如何使用Java压缩PNG图像

如何使用Java压缩PNG图像,java,compression,png,Java,Compression,Png,您好,我想知道Java中是否有任何方法可以减小作为BuffereImage加载并将保存为PNG的图像的大小(使用任何类型的压缩) 也许是某种png图像写入内存?我没有发现任何有用的东西,所以我被卡住了 下面是如何加载和保存图像的示例 public static BufferedImage load(String imageUrl) { Image image = new ImageIcon(imageUrl).getImage(); bufferedImage

您好,我想知道Java中是否有任何方法可以减小作为BuffereImage加载并将保存为PNG的图像的大小(使用任何类型的压缩)

也许是某种png图像写入内存?我没有发现任何有用的东西,所以我被卡住了

下面是如何加载和保存图像的示例

public static BufferedImage load(String imageUrl) {         
    Image image = new ImageIcon(imageUrl).getImage();
    bufferedImage = new BufferedImage(image.getWidth(null),
                                                    image.getHeight(null),
                                                    BufferedImage.TYPE_INT_ARGB);
    Graphics2D g2D = bufferedImage.createGraphics();
    g2D.drawImage(image, 0, 0, null);
    return bufferedImage;
}

public static void storeImageAsPng(BufferedImage image, String imageUrl) throws IOException {
    ImageIO.write(image, "png", new File(imageUrl));
}

请查看与
ImageIO
类位于同一软件包中的
ImageWriterParam
类。它提到了压缩


另请看上的示例,看看它是否能很好地转换为PNG文件。

如果
将其保存为PNG
,则将在该阶段进行压缩。PNG有一个无损压缩算法(基本上是预测,然后是lempel-ziv压缩),具有很少的可调整参数(类型为“”),并且对压缩量没有太大影响-通常默认值是最佳的。

您可能想尝试一下。这是一个纯java png图像优化器,可以将png图像缩小到一定程度。

通过调用
ImageIO.write
可以使用png的默认压缩质量。您可以选择显式压缩模式,这将大大减少文件大小

String inputPath = "a.png";
String outputPath = "b.png";

BufferedImage image;
IIOMetadata metadata;

try (ImageInputStream in = ImageIO.createImageInputStream(Files.newInputStream(Paths.get(inputPath)))) {
    ImageReader reader = ImageIO.getImageReadersByFormatName("png").next();
    reader.setInput(in, true, false);
    image = reader.read(0);
    metadata = reader.getImageMetadata(0);
    reader.dispose();
}

try (ImageOutputStream out = ImageIO.createImageOutputStream(Files.newOutputStream(Paths.get(outputPath)))) {
    ImageTypeSpecifier type = ImageTypeSpecifier.createFromRenderedImage(image);
    ImageWriter writer = ImageIO.getImageWriters(type, "png").next();

    ImageWriteParam param = writer.getDefaultWriteParam();
    if (param.canWriteCompressed()) {
        param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
        param.setCompressionQuality(0.0f);
    }

    writer.setOutput(out);
    writer.write(null, new IIOImage(image, null, metadata), param);
    writer.dispose();
}

“任何类型的压缩”是否包括有损压缩?因为将图像存储为JPEG格式可能会节省大量空间。PNG是一种无损压缩格式(只要源图像每通道使用不超过8位:如果将48位RGB图片转换为PNG,PNG将变得有损),因此无法获得太多收益。然而,有很多工具可以生成比平常小得多的PNG,如果你需要将PNG用于内存受限的设备,它们特别有用:PNGOUT就是这样一个工具,由史上最好的程序员之一编写:对,就像Joachim问的,没有有损压缩,只需减小图像文件的大小,如zip和so所使用的图像文件,并且不应涉及诸如PNGOUT之类的外部工具,因此它可以是某种支持PNG的ImageWriteParam和ImageWriteParam的库,如JPEGImageWriteParam,查看xmlgraphics commons 1.3.1 atm。对不起,如果我在某些方面感到困惑,我仍然是一个新手,只是觉得这些答案可以帮助我或者启发其他有类似问题的人。感谢到目前为止的建议。从我读到的有关gimps png保存选项的内容来看,压缩级别(从1到9的设置)决定了压缩(编码器的工作),尽管无论您设置什么,它的损失都较小。是的,这只是选择四个“过滤器”(实际上是预测器,请参见上面的链接)之一的问题,可能对不同的行使用不同的过滤器。它始终是无损的。如果您想对PNG使用显式压缩模式,它将抛出一个异常,通知您此格式不支持此模式。所以应用于JpegWriter的参数不适用于PNG。你真的尝试过这个吗?Java 7和8中的默认
com.sun.imageio.plugins.png.PNGImageWriteParam
抛出
Java.lang.UnsupportedOperationException:不支持压缩。
是,它在Java 9上工作。Java8和更早版本始终使用最大压缩。您可以将setCompression…语句放在if(param.isCompressionSupported)或类似的东西中,以实现Java 8兼容性。这是可行的,但在我的实验中,我只能将文件大小减少很小的一部分,即问题中使用的默认值的99.86%。可以使用更好的PNG压缩,但似乎它们没有在imageio中实现。