如何在java.awt.image.IndexColorModel
PNG中将图像保存在java中?我正在使用ImageIO加载索引颜色png,使用 Catalino 库进行操作,遗憾的是将颜色空间转换为java.awt.image.DirectColorModel
。
现在我想以与原始图像完全相同的格式保存结果。我尝试了以下代码片段。
private static void testIndexedColor() throws IOException {
FastBitmap input = new FastBitmap("test.png");
BufferedImage bi = new BufferedImage(input.getWidth(), input.getHeight(), BufferedImage.TYPE_BYTE_INDEXED);
bi.getGraphics().drawImage(input.toBufferedImage(), 0, 0, null);
ImageIO.write(bi, "PNG", new File("test_result.png"));
}
但结果在白色背景中出现了奇怪的浅灰色像素伪影,PPI减少了。如何在没有质量损失和失真的情况下正确转换回索引颜色模式?
答案 0 :(得分:1)
假设我对Catalano框架是正确的,你应该能够重新编写你的方法:
private static void testIndexedColor() throws IOException {
BufferedImage bi = ImageIO.read(new File("test.png"));
FastBitmap input = new FastBitmap(bi);
Graphics2D g = bi.createGraphics();
try {
g.drawImage(input.toBufferedImage(), 0, 0, null);
}
finally {
g.dispose(); // Good practice ;-)
}
ImageIO.write(bi, "PNG", new File("test_result.png"));
}
至少你应该使用固定的调色板和工件。
然而,这可能仍然修改PPI(但这不会影响像素)。即使在某些情况下,图像也可能被写回非调色板PNG。
更新:似乎PNGImageWriter
(通过PNGMetadata
)实际上会将包含完美灰度的IndexColorModel
重写为默认的灰度PNG。这通常是一个好主意,因为您不通过编写PLTE块来减小文件大小。您应该能够通过传递原始元数据和图像像素数据来解决这个问题,以指示编写者保留IndexColorModel
(即写入PLTE块):
private static void testIndexedColor() throws IOException {
File in = new File("test.png");
File out new File("test_result.png");
try (ImageInputStream input = ImageIO.createImageInputStream(in);
ImageOutputStream output = ImageIO.createImageOutputStream(out)) {
ImageReader reader = ImageIO.getImageReaders(input).next(); // Will fail if no reader
reader.setInput(input);
ImageWriter writer = ImageIO.getImageWriter(reader); // Will obtain a writer that understands the metadata from the reader
writer.setOutput(output); // Will fail if no writer
// Now, the important part, we'll read the pixel AND metadata all in one go
IIOImage image = reader.readAll(0, null); // PNGs only have a single image, so index 0 is safe
// You can now access and modify the image data using:
BufferedImage bi = (BufferedImage) image.getRenderedImage();
FastBitmap fb = new FastBitmap(bi);
// ...do stuff...
Graphics2D g = bi.createGraphics();
try {
g.drawImage(fb.toBufferedImage(), 0, 0, null);
}
finally {
g.dispose();
}
// Write pixel and metadata back
writer.write(null, image, writer.getDefaultWriteParam());
}
}
此应该(作为奖励)也保持您的PPI原样。
PS:对于生产代码,您还想要dispose()
和reader
上面的writer
,但我将其留下来保持专注并避免进一步讨论{{1} }。 ; - )