Issue
I am using the code given below for image compression of jpeg image.
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);
But when I tried for for PNG format by changing ImageIO.getImageWritersByFormatName("png"); It is giving me error that compression not supported.
So how should i modify the above code so as to support all image format compression
Solution
The problem with your code is that you used ImageWriter.getDefaultWriteParam(). From the following quote from ImageWriter.java:
public ImageWriteParam getDefaultWriteParam()
Returns a new ImageWriteParam object of the appropriate type for this file format containing default values, that is, those values that would be used if no ImageWriteParam object were specified. This is useful as a starting point for tweaking just a few parameters and otherwise leaving the default settings alone.
The default implementation constructs and returns a new ImageWriteParam object that does not allow tiling, progressive encoding, or compression, and that will be localized for the current Locale (i.e., what you would get by calling new ImageWriteParam(getLocale()).
Individual plug-ins may return an instance of ImageWriteParam with additional optional features enabled, or they may return an instance of a plug-in specific subclass of ImageWriteParam.
The actual behavior depends on individual implementation of specific ImageWriteParam. I believe the reason JPG image works is that the ImageWriteParam for JPG set the canWriteCompressed
protected field for the default ImageWriteParam but for PNG image, for some reason it doesn't do that.
If you look at the com.sun.imageio.plugins.png.PNGImageWriteParam.java, you will find it indeed doesn't set it.
In order to make your code work generally, you can do like this:
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);
Update: I was trying to find out a way for you to fine-tune PNG image compression within the framework of ImageIO. But unfortunately, given the current implementation, it seems next to impossible. Java PNG writer plugin has fixed filtering - adaptive filtering and fixed deflater level - 9 which is the best thing it could do.
Answered By - dragon66
Answer Checked By - Gilberto Lyons (JavaFixing Admin)