我正在使用 javax.imageio API 和 JAI 来压缩不同类型的图像。它适用于使用 JPEGImageWriter
的 JPEG 和使用 GIFImageWriter
的 GIF。但它不支持使用 PNGImageWriter
进行 PNG 压缩,这会引发异常,例如未设置压缩类型或“无有效压缩”等。所以我在下面使用了 ImageWriter
PNG。它可以工作,但图像质量太差了。
谁能建议如何使用 PNGImageWriter
进行 PNG 压缩以及哪个 JAR 包含它?
File input = new File("test.png");
InputStream is = new FileInputStream(input);
BufferedImage image = ImageIO.read(is);
File compressedImageFile = new File(input.getName());
OutputStream os =new FileOutputStream(compressedImageFile);
Iterator<ImageWriter>writers =
ImageIO.getImageWritersByFormatName("jpg"); // here "png" does not work
ImageWriter writer = (ImageWriter) writers.next();
ImageOutputStream ios = ImageIO.createImageOutputStream(os);
writer.setOutput(ios);
ImageWriteParam param = writer.getDefaultWriteParam();
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionQuality(0.5f);
writer.write(null, new IIOImage(image, null, null), param);
最佳答案
似乎与 JRE 捆绑在一起的默认 com.sun.imageio.plugins.png.PNGImageWriter
不支持设置 压缩。这有点令人惊讶,因为该格式显然支持压缩。但是,PNGImageWriter
总是 写入压缩。
从源码可以看出它使用的是:
Deflater def = new Deflater(Deflater.BEST_COMPRESSION);
这会给你很好但很慢的压缩。这对您来说可能已经足够了,但在某些情况下,使用更快的压缩和更大的文件可能会更好。
要修复您的代码,使其适用于任何格式名称,请更改以下行:
ImageWriteParam param = writer.getDefaultWriteParam();
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionQuality(0.5f);
到:
ImageWriteParam param = writer.getDefaultWriteParam();
if (param.canWriteCompressed()) {
// NOTE: Any method named [set|get]Compression.* throws UnsupportedOperationException if false
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionQuality(0.5f);
}
它仍然会写入压缩的 PNG。
如果您需要对 PNG 压缩进行更多控制,例如设置压缩或使用的过滤器,您需要找到支持它的 ImageWriter
。正如您提到的 JAI,我认为 jai-imageio.jar
或 jai-imageio-tools.jar
的一部分的 CLibPNGImageWriter
支持设置压缩.您只需要查看 ImageWriter
的迭代器,看看您是否安装了它:
Iterator<ImageWriter>writers = ImageIO.getImageWritersByFormatName("png");
ImageWriter writer = null;
while (writers.hasNext()) {
ImageWriter candidate = writers.next();
if (candidate.getClass().getSimpleName().equals("CLibPNGImageWriter")) {
writer = candidate; // This is the one we want
break;
}
else if (writer == null) {
writer = candidate; // Any writer is better than no writer ;-)
}
}
使用正确的 ImageWriter
,您的代码应该可以按预期工作。
关于java - 使用 JAI(Java 高级成像)压缩 PNG,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24538455/