Loading...
вівторок, 7 травня 2013 р.

Apache POI - малюємо в екселі

Колись бачив у якійсь ЖЖшечці казочку про японця, який малює картини в екселі методом піксель-арту. Там ще всі дивувалися з того як у японців багато вільного часу і яка це важка та непосильна праця "офісного художника".
А сьогодні випадково прочитав статтю про Apache POI - Java API, призначену для роботи з документами Microsoft Office.  Apache POI дозволяє як просто читати чи записувати дані, так і, скажімо, вводити в екселі формули і обчислювати результат, використовувати готові формули, змінювати розміри та колір клітинок... Непоганий варіант для автоматизації діяльності альтернативних художників типу того японця. Фактично, будь-яку картинку можна запросто "конвертувати" таблицю екселя.

Одна біда, Apache POI має якийсь власний спосіб роботи з кольорами, а не просто юзає звичайний RGB (не факт, звісно, що це не взялося з майкрософтівських розробок). Тому для задання кольору спочатку доведеться заюзати якийсь конвертор. Типу отакого методу:

public HSSFColor setColor(HSSFWorkbook workbook, byte r, byte g, byte b) {
HSSFPalette palette = workbook.getCustomPalette();
HSSFColor hssfColor = null;
try {
// Пробуємо знайти схожий колір у палітрі екселя
// він може відрізнятися трохи від того, що треба,
// але це навіть краще - більше схоже на кустарну роботу :)
hssfColor = palette.findSimilarColor(r, g, b);
if (hssfColor == null) {
   // Не знайшли, можна щось придумати
}} catch (Exception e) {
  // Так само можна щось придумувати
}
// Але переважно все працює ;)
return hssfColor;
}

На вхід подаємо три компоненти RGBі отримуємо той таємничий  HSSFColor, який уже можна юзати для задання кольору; workbook - це поточна "книга" екселя. 
А вже оцей код юзає наш метод для записування екселівського файлу з кольоровими клітинками:

public void write(Map<String, Object[]> data) {
// На вхід треба дати мапу, у якій  Object[] - набір кольорів по кожному рядку зображення
// у вигляді public class RGBColor {private byte r, g, b;} 
HSSFWorkbook workbook = new HSSFWorkbook();
HSSFSheet sheet = workbook.createSheet("Picture");
// ХешМапа для зберігання співвідношення колір-стиль. Справа у тому, що максимальна
// кількість стилів у екселі - 4000, тобто якщо просто генерити стилі, то
// більше як на 4к пікселів картинку не намалюєш, а так стилі
// можна використовувати повторно
Map<String, HSSFCellStyle> colorToStyle = new HashMap<String, HSSFCellStyle>();
HSSFCellStyle style;
Set<String> keyset = data.keySet();
int rownum = 0;
// Перебираємо всі клітинки на аркуші
// Насправді фактично створюємо їх для наших пікселів
for (String key : keyset) {
Row row = sheet.createRow(rownum++);
// Встановлюємо висоту всіх клітинок
row.setHeight((short) 50);
Object[] objArr = data.get(key);
int cellnum = 0;
for (Object obj : objArr) {
// Зменшуємо ширину всіх клітинок
sheet.setColumnWidth(cellnum, 100);
Cell cell = row.createCell(cellnum++);
RGBColor rgb = (RGBColor) obj;
try {
// Пробуємо дістати стиль з мапи
style = colorToStyle.get(rgb.toString());
cell.setCellStyle(style);
} catch (Exception e) {
// Якщо стилю у мапі нема, то створюємо новий
style = workbook.createCellStyle();
// Вказуємо, що будем заливати суцільним кольором
style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
style.setFillForegroundColor(setColor(workbook, rgb.getR(), rgb.getG(), rgb.getB()).getIndex());
// Запихаємо стиль у мапу
colorToStyle.put(rgb.toString(), style);
cell.setCellStyle(style);
}}}
try {
// Це просто записує файл, нічого особливого
FileOutputStream out =
new FileOutputStream(new File("C:\\picture.xls"));
workbook.write(out);
out.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}}

Ну і нарешті результат :)
Початкова картинка
Результат обробки (зменшено)

   

0 коментарі:

 
TOP