3

我正在尝试将直接颜色模型图像转换为双色调索引图像(每像素 1 位)并将索引图像保存为 BMP。

Java Advanced Imaging API Home Page所述:

编码输出的位深度由源图像的位深度决定。

源码BMPImageWriter看,这个的机制就是ColorModel#getPixelSize()的返回值。

使用来自 Wikimedia Commons 的图像的缩小副本,我首先执行颜色量化以获得颜色查找表,然后进行误差扩散以应用 Floyd–Steinberg 抖动:

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 KiB。

我在某处看到将颜色模型传递给错误扩散的一种方法是设置 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 KiB,大约是我使用 MS Paint 将示例图像转换为单色位图时的大小。因此,看起来 JAIBMPImageWriter使用了正确的编码,但如果您仔细查看第二张图像,相邻的像素列相距 8 个像素。事实上,你可以看到第一张图像,只有第一张图像的每一列像素被扩展为 8 列像素。

这是 JAI 中的错误吗?我可以做些什么来将这些 8 宽的像素列折叠为单列像素吗?

4

1 回答 1

2

这应该适用于 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");
于 2013-03-19T20:45:55.027 回答