Search code examples
javajpegimage-compressionjavax.imageio

Setting jpg compression level with ImageIO in Java


I'm using javax.imageio.ImageIO to save a BufferedImage as a jpeg file. In particular, I created the following Java function:

public static void getScreenShot(BufferedImage capture, Path folder, String filename) {
        try {
            ImageIO.write(capture, "jpeg", new File(folder.toString()+"/"+filename+".jpg"));
        } catch (AWTException | IOException ex) {
            Logger.getLogger(ScreenShotMaker.class.getName()).log(Level.SEVERE, null, ex);
        }
}

Likewise any image manipulation software, I wish to change the compression level of the jpeg file. However, I'm searching for this option that seems to be missing in ImageIO.

Can I set the compression level and how?


Solution

  • You have to use JPEGImageWriteParam and then save the image with ImageWriter.write(). Before to write, set the output via ImageWriter.setOutput.

    Set the compression level as follows:

    JPEGImageWriteParam jpegParams = new JPEGImageWriteParam(null);
    jpegParams.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
    jpegParams.setCompressionQuality(1f);
    

    Where 1f is a float number that stands for 100% quality. Default value is around 70% if I don't remember wrong.

    EDIT

    Then, you have to do as follows to get an instance of an ImageWriter. There are two ways, a short and a long one (I keep both, just in case).

    The short way (suggested by lapo in one comment) is:

    final ImageWriter writer = ImageIO.getImageWritersByFormatName("jpg").next();
    // specifies where the jpg image has to be written
    writer.setOutput(new FileImageOutputStream(
      new File(folder.toString() + "/" + filename + ".jpg")));
    
    // writes the file with given compression level 
    // from your JPEGImageWriteParam instance
    writer.write(null, new IIOImage(capture, null, null), jpegParams);
    

    or longer way

    // use IIORegistry to get the available services
    IIORegistry registry = IIORegistry.getDefaultInstance();
    // return an iterator for the available ImageWriterSpi for jpeg images
    Iterator<ImageWriterSpi> services = registry.getServiceProviders(ImageWriterSpi.class,
                                                     new ServiceRegistry.Filter() {   
            @Override
            public boolean filter(Object provider) {
                if (!(provider instanceof ImageWriterSpi)) return false;
    
                ImageWriterSpi writerSPI = (ImageWriterSpi) provider;
                String[] formatNames = writerSPI.getFormatNames();
                for (int i = 0; i < formatNames.length; i++) {
                    if (formatNames[i].equalsIgnoreCase("JPEG")) {
                        return true;
                    }
                }
    
                return false;
            }
        },
       true);
    //...assuming that servies.hasNext() == true, I get the first available service.
    ImageWriterSpi writerSpi = services.next();
    ImageWriter writer = writerSpi.createWriterInstance();
    
    // specifies where the jpg image has to be written
    writer.setOutput(new FileImageOutputStream(
      new File(folder.toString() + "/" + filename + ".jpg")));
    
    // writes the file with given compression level 
    // from your JPEGImageWriteParam instance
    writer.write(null, new IIOImage(capture, null, null), jpegParams);