Как контролировать размер пикселя цветовой модели ErrorDiffusionDescriptor?

Я пытаюсь преобразовать изображение прямой цветовой модели в индексированное битовое изображение (1 бит на пиксель) и сохранить индексированное изображение как BMP.

Как указано на домашней странице Java Advanced Imaging API:

Глубина в битах кодированного вывода определяется глубиной исходного изображения.

Просматривая исходный кодBMPImageWriterМеханизм этого - возвращаемое значение ColorModel # getPixelSize ().

Используя уменьшенную копию изображения из Wikimedia Commons, я сначала выполняю квантование цветов, чтобы получить таблицу соответствия цветов, а затем распространяю ошибки, чтобы применить дизеринг Флойда-Стейнберга:

PlanarImage surrogateImage = PlanarImage.wrapRenderedImage(image);

PlanarImage op = ColorQuantizerDescriptor.create(surrogateImage, ColorQuantizerDescriptor.OCTTREE, 2, null, null, null, null, null);
LookupTableJAI lut = (LookupTableJAI)op.getProperty("LUT");
IndexColorModel cm = new IndexColorModel(1, lut.getByteData()[0].length, lut.getByteData()[0], lut.getByteData()[1], lut.getByteData()[2]);

op = ErrorDiffusionDescriptor.create(surrogateImage, lut, KernelJAI.ERROR_FILTER_FLOYD_STEINBERG, null);

image = op.getAsBufferedImage();

Проблема в, image.getColorModel().getPixelSize() возвращает 8, поэтому изображение сохраняется как растровое изображение 8bpp:

Результат квантования цвета и диффузии ошибок на образце изображения

Размер этого изображения 167 КиБ.

Я где-то видел, что одним из способов передачи цветовой модели к распространению ошибок является установка подсказки рендеринга JAI.KEY_IMAGE_LAYOUT:

ImageLayout layout = new ImageLayout();
layout.setTileWidth(image.getWidth());
layout.setTileHeight(image.getHeight());
layout.setColorModel(cm);
layout.setSampleModel(op.getSampleModel());
RenderingHints rh = new RenderingHints(JAI.KEY_IMAGE_LAYOUT, layout);
op = ErrorDiffusionDescriptor.create(surrogateImage, lut, KernelJAI.ERROR_FILTER_FLOYD_STEINBERG, rh);

image.getColorModel().getPixelSize() теперь возвращает 1, но результирующее изображение значительно изменяется:

Результат квантования цвета и диффузии ошибок на образце изображения, передающем ImageLayout

Тем не менее, размер этого изображения составляет 21 КиБ, примерно то же самое, когда я использую MS Paint для преобразования образца изображения в монохромное растровое изображение. Итак, похоже, что JAI BMPImageWriter использует правильную кодировку, но если вы внимательно посмотрите на второе изображение, смежные столбцы пикселей разделены на восемь пикселей. Фактически, вы можете видеть первое изображение, только каждый столбец пикселей из первого изображения расширяется до 8 столбцов пикселей.

Это ошибка в JAI? Есть ли что-то, что я могу сделать, чтобы свернуть эти столбцы шириной 8 пикселей в пиксели одного столбца?

1 ответ

Решение

Это должно работать с 24 BPP PNG:

    String filename = "jEEDL.png";

    PlanarImage image = PlanarImage.wrapRenderedImage(JAI.create("fileload", filename));

    LookupTableJAI lut = new LookupTableJAI(new byte[][] {{(byte)0x00, (byte)0xff}, {(byte)0x00, (byte)0xff}, {(byte)0x00, (byte)0xff}});
    ImageLayout layout = new ImageLayout();
    byte[] map = new byte[] {(byte)0x00, (byte)0xff};
    ColorModel cm = new IndexColorModel(1, 2, map, map, map);
    layout.setColorModel(cm);
    SampleModel sm = new MultiPixelPackedSampleModel(DataBuffer.TYPE_BYTE,
            image.getWidth(),
            image.getHeight(),
            1);
    layout.setSampleModel(sm);
    RenderingHints hints = new RenderingHints(JAI.KEY_IMAGE_LAYOUT, layout);
    PlanarImage op = ErrorDiffusionDescriptor.create(image, lut, KernelJAI.ERROR_FILTER_FLOYD_STEINBERG, hints);

    BufferedImage dst  = op.getAsBufferedImage();

    JAI.create("filestore", dst, "jEEDL.bmp", "BMP");
Другие вопросы по тегам