如何将java中的图像保存为java.awt.image.IndexColorModel
PNG?我正在使用 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 下降了。如何正确转换回索引颜色模式而不造成质量损失和失真?
最佳答案
假设我对 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 block 来减小文件大小。您应该能够通过传递原始数据中的元数据以及图像像素数据来解决此问题,以指示编写器保留 IndexColorModel
(即写入 PLTE block ):
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:对于生产代码,您还需要对上面的 reader
和 writer
进行 dispose()
,但我将其遗漏了保持焦点并避免对 try/finally
进行进一步讨论。 ;-)
关于java - 如何在java中保存索引颜色PNG,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41958769/