[英]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 压缩到更小的尺寸。
示例图像
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.