Чертежи В Ms Excel С Использованием Apache Poi

Некоторое время назад появился на хабе статья о художнике , который рисует картинки в MS Excel, используя свои векторные возможности.

Но задолго до этого я наткнулся на истории о феноменальных растровых рисунках в Excel, идея которых основана на пиксель-арте.

Те.

некоторые просто уменьшают размер ячеек и используют цветовую заливку, чтобы создать своеобразную мозаику.

Выглядит довольно эффектно, хотя до качества векторных рисунков, конечно, не дотягивает. Увидев такие картинки, я, конечно, засомневался, что кому-то хватит упорства создавать их вручную, и решил поискать способ автоматизации «офисного творчества».

Задачу оказалось легко реализовать на Java при условии, что Библиотеки POI Apache , предназначенный для работы с собственными форматами Microsoft Office. Подробности под катом.

Итак, что мы имеем? Я поставил перед собой задачу создать приложение для конвертации самого обычного изображения JPG (или в принципе любого другого распространенного формата) в документ Excel. Стоит сразу упомянуть о существующих ограничениях: Ширина «картинки» не должна превышать 255 пикселей (максимальное количество столбцов на листе) максимальное количество стилей оформления (в нашем случае это количество цветов) — 4000 Таким образом, вам придется либо сначала найти и подготовить изображение (уменьшить размер и глубину цвета), либо сделать это программно.

Мы пойдём вторым путём :)

Чертежи в MS Excel с использованием Apache POI

Сначала давайте набросаем класс Main нашей программы, содержащий единственный метод:

  
  
  
  
  
   

public class Main { public static void main(String[] args) { IMGRead ir = new IMGRead(); Map<String, Object[]> data = ir.read("C:\\picture.jpg"); POIWrite pw = new POIWrite(); pw.write(data); } }

Хардкод, конечно, убогий, но для демонстрации вполне подойдет. Рассмотрим класс для чтения картинки из файла.

Он содержит метод собственно чтения картинки и возвращает результат в виде карты, содержащей объекты типа RGBColor, хранящие информацию о трёх компонентах цвета точки:

public Map<String, Object[]> read(String fileName) { File file = new File(fileName); BufferedImage source, image;//source and resized images Map<String, Object[]> data = new TreeMap<String, Object[]>(); try { source = ImageIO.read(file);//read picture from file int type = source.getType() == 0? BufferedImage.TYPE_INT_ARGB : source.getType();//get type image = resizeImage(source, type);//resize source = convert8(image); image = source; // :) // Getting pixel color for every pixel for (Integer y = 0; y < image.getHeight(); y++) { Object[] line = new Object[image.getWidth()]; for (int x = 0; x < image.getWidth(); x++) { int clr = image.getRGB(x, y); int red = (clr & 0x00ff0000) >> 16; int green = (clr & 0x0000ff00) >> 8; int blue = clr & 0x000000ff; line[x] = new RGBColor(red, green, blue); } data.put(String.format("d", y), line); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return data; }

У нас также есть метод изменения размера изображения:

private static BufferedImage resizeImage(BufferedImage originalImage, int type) { BufferedImage resizedImage = new BufferedImage(IMG_WIDTH, IMG_HEIGHT, type); Graphics2D g = resizedImage.createGraphics(); g.drawImage(originalImage, 0, 0, IMG_WIDTH, IMG_HEIGHT, null); g.dispose(); return resizedImage; }

И метод уменьшения цвета (я использую восьмибитный цвет, для других вариантов см.

источник ):

public static BufferedImage convert8(BufferedImage src) { BufferedImage dest = new BufferedImage(src.getWidth(), src.getHeight(), BufferedImage.TYPE_BYTE_INDEXED); ColorConvertOp cco = new ColorConvertOp(src.getColorModel() .

getColorSpace(), dest.getColorModel().

getColorSpace(), null); cco.filter(src, dest); return dest; }

Перейдем к классу, реализующему запись «картинки» в документ Excel. Здесь у нас есть 2 метода, первый из которых записывает в файл:

public void write(Map<String, Object[]> data) { HSSFWorkbook workbook = new HSSFWorkbook(); HSSFSheet sheet = workbook.createSheet("Picture"); 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(); } }

Карта colorToStyle используется для хранения стилей оформления ячеек.

При создании нового стиля мы связываем его с определенным цветом и каждый раз, когда закрашиваем новую ячейку, проверяем, существует ли готовый стиль для нужного цвета или его нужно создать.

И, наконец, метод преобразования цветов RGB в формат HSSFColor, используемый в Apache POI. Обратите внимание, что используется метод findSimilarColor(), который пытается автоматически найти похожий цвет в палитре.



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) { System.err.println("null " + r + " " + g + " " + b); palette.setColorAtIndex(HSSFColor.RED.index, r, g, b); hssfColor = palette.getColor(HSSFColor.RED.index); } } catch (Exception e) { e.printStackTrace(); } return hssfColor; }

Результаты «творчества»:

Конечно, такая мозаика далеко не шедевр, но при правильном подборе цветов изображения и его размера можно получить вполне симпатичные «рисунки».

Я не знаю, может ли Apache POI (или любая другая библиотека) работать с векторной графикой в офисных документах :( Теги: #java #apache poi #Excel #программирование #java

Вместе с данным постом часто просматривают: