繁体   English   中英

任何图像格式(jpg、PNG、gif)的java图像压缩

[英]java image compression for any image format(jpg, PNG, gif)

我正在使用下面给出的代码对 jpeg 图像进行图像压缩。

File input = new File("digital_image_processing.jpg");
BufferedImage image = ImageIO.read(input);

File compressedImageFile = new File("compress.jpg");  
OutputStream os = new FileOutputStream(compressedImageFile);

 Iterator<ImageWriter>writers = ImageIO.getImageWritersByFormatName("jpg");
 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.05f);

 writer.write(null, new IIOImage(image, null, null), param);

但是当我通过更改 ImageIO.getImageWritersByFormatName("png"); 尝试使用 PNG 格式时它给了我不支持压缩的错误。

那么我应该如何修改上面的代码以支持所有图像格式压缩

您的代码的问题是您使用了 ImageWriter.getDefaultWriteParam()。 来自 ImageWriter.java 的以下引用:

公共 ImageWriteParam getDefaultWriteParam()

返回此文件格式的适当类型的新 ImageWriteParam 对象,其中包含默认值,即在未指定 ImageWriteParam 对象时将使用的那些值。 这对于仅调整几个参数并保留默认设置非常有用。

默认实现构造并返回一个新的 ImageWriteParam 对象,该对象不允许平铺、渐进式编码或压缩,并将针对当前的 Locale 进行本地化(即,您将通过调用 new ImageWriteParam(getLocale()) 获得什么)。

各个插件可能会返回启用了附加可选功能的 ImageWriteParam 实例,或者它们可能会返回 ImageWriteParam 的插件特定子类的实例。

实际行为取决于特定 ImageWriteParam 的单独实现。 我相信 JPG 图像起作用的原因是 JPG 的 ImageWriteParam 为默认的 ImageWriteParam 设置了canWriteCompressed保护字段,但对于 PNG 图像,由于某种原因它没有这样做。

如果您查看 com.sun.imageio.plugins.png.PNGImageWriteParam.java,您会发现它确实没有设置它。

为了使您的代码能够正常工作,您可以这样做:

  File input = new File("digital_image_processing.jpg");
  BufferedImage image = ImageIO.read(input);

  File compressedImageFile = new File("compress.jpg");  
  OutputStream os = new FileOutputStream(compressedImageFile);

  Iterator<ImageWriter>writers = ImageIO.getImageWritersByFormatName("jpg");
  ImageWriter writer = (ImageWriter) writers.next();

  ImageOutputStream ios = ImageIO.createImageOutputStream(os);
  writer.setOutput(ios);

  ImageWriteParam param = writer.getDefaultWriteParam();
  // Check if canWriteCompressed is true
  if(param.canWriteCompressed()) {
     param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
     param.setCompressionQuality(0.05f);
  }
  // End of check
  writer.write(null, new IIOImage(image, null, null), param);

更新:我试图为您找到一种在 ImageIO 框架内微调 PNG 图像压缩的方法。 但不幸的是,鉴于目前的实施,这似乎几乎是不可能的。 Java PNG writer 插件具有固定过滤 - 自适应过滤和固定 deflater 级别 - 9,这是它可以做的最好的事情。

我尝试了建议的解决方案,但 png 的图像并没有减小尺寸。 下面是我的代码之一,可以将图像 jpg 和 png 压缩到更小的尺寸。

示例图像

  1. 原图(png): https ://imgur.com/a/wSfD5yH(大小:923kb)
  2. 压缩图像(PNG): https ://imgur.com/a/M56zPAp(大小:48.9kb,压缩质量:0.35f)

public ByteArrayOutputStreamcompressedImage(BufferedImage originalImage,Float compressValue, String fileType) 抛出 IOException {

ByteArrayOutputStream compressed = new ByteArrayOutputStream();

try (ImageOutputStream outputStream = ImageIO.createImageOutputStream(compressed)) {
        
    ImageWriter jpgWriter = ImageIO.getImageWritersByFormatName("JPEG").next();
        
    ImageWriteParam jpgWriteParam = jpgWriter.getDefaultWriteParam();

    //to handle image png to get same output as original file with smaller size
    if(fileType.equals("jpg")){
    
        jpgWriteParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
        jpgWriteParam.setCompressionQuality(compressValue);
        jpgWriter.setOutput(outputStream);
        jpgWriter.write(null, new IIOImage(originalImage, null, null), jpgWriteParam);
        jpgWriter.dispose();

    }
    else{

        BufferedImage newBufferedImage = new BufferedImage(
        originalImage.getWidth(),
        originalImage.getHeight(),
        BufferedImage.TYPE_INT_BGR);

        newBufferedImage.createGraphics()
        .drawImage(newBufferedImage, 0, 0, Color.white, null);

        Graphics2D g2d = newBufferedImage.createGraphics();
        g2d.setColor(Color.WHITE);
        g2d.fillRect(0, 0, newBufferedImage.getWidth(), newBufferedImage.getHeight());
        g2d.drawImage(originalImage, 0, 0, null);
        g2d.dispose();

        //fix colour  
        // int[] rgb = originalImage.getRGB(0, 0, originalImage.getWidth(), originalImage.getHeight(), null, 0, originalImage.getWidth());
        // newBufferedImage.setRGB(0, 0, originalImage.getWidth(), originalImage.getHeight(), rgb, 0, originalImage.getWidth());

        //fix colour 
        // newBufferedImage = this.fixBadImageJPEG(newBufferedImage);
        
        newBufferedImage.flush();

        jpgWriteParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
        jpgWriteParam.setCompressionQuality(compressValue);

        jpgWriter.setOutput(outputStream);
        jpgWriter.write(null, new IIOImage(newBufferedImage, null, null), jpgWriteParam);
        jpgWriter.dispose();

    }

}


return compressed;

}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM