使用JAI(Java高级成像)压缩PNG

问题描述 投票:0回答:2

我使用 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);
java compression javax.imageio jai image-compression
2个回答
12
投票

更新:与 JDK 捆绑在一起的默认

com.sun.imageio.plugins.png.PNGImageWriter
现在支持设置和指定压缩级别,至少从 Java 9 开始。

如果您仍在使用 Java 8 或更早版本,还可以使用 back port

本答案的其余部分假设您使用的是旧版本的 Java。


与 JRE 捆绑的默认

com.sun.imageio.plugins.png.PNGImageWriter
似乎不支持 setting 压缩。这有点令人惊讶,因为该格式显然支持压缩。但是,
PNGImageWriter
always 会进行压缩写入。

从源码中可以看到它使用的是:

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
jai-imageio-tools.jar
的一部分,支持设置压缩。你只需要查看
ImageWriter
s 迭代器,看看你是否安装了它:

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
,您的代码应该按预期工作。


0
投票

请检查此代码是否适合您。

ImageWriteParam writeParam = writer.getDefaultWriteParam();

writeParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);

writeParam.setCompressionType("PackBits");

writeParam.setCompressionQuality(0.5f);

谢谢。

© www.soinside.com 2019 - 2024. All rights reserved.