我正在使用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);
答案 0 :(得分:7)
与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时,我认为属于CLibPNGImageWriter
或jai-imageio.jar
的{{1}}支持设置压缩。您只需要查看jai-imageio-tools.jar
迭代器,看看是否安装了它:
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 ;-)
}
}
,您的代码应按预期工作。
答案 1 :(得分:0)
请检查此代码是否适合您。
ImageWriteParam writeParam = writer.getDefaultWriteParam();
writeParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
writeParam.setCompressionType("PackBits");
writeParam.setCompressionQuality(0.5f);
感谢。