我正在尝试将直接颜色模型图像转换为双色索引图像(每像素1位),并将索引图像保存为BMP。
正如Java Advanced Imaging API Home Page所述:
编码输出的位深度由源图像的位深决定。
从浏览the source code of BMPImageWriter
开始,其机制就是ColorModel#getPixelSize()的返回值。
使用an image from 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,但生成的图像会发生显着变化:
但是,此图像的大小为21 KiB,大约是使用MS Paint将样本图像转换为单色位图时的大小。因此,看起来JAI的BMPImageWriter
正在使用正确的编码,但如果仔细观察第二个图像,则相邻的像素列相隔八个像素。事实上,您可以看到第一张图像,只有第一张图像中的每列像素都扩展为8列像素。
这是JAI中的错误吗?我可以做些什么来将这8个像素的像素列折叠成单列像素吗?
答案 0 :(得分: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");