Mark Stephens Mark has been working with Java and PDF since 1999 and is a big NetBeans fan. He enjoys speaking at conferences. He has an MA in Medieval History and a passion for reading.

Replacing the deprecated Java JPEG classes for Java 7

1 min read

In the early days of Java, Sun produced a really handy set of classes to handle JPEG images. These included some really nifty little features like the ability to easily set the amount of compression and the resolution. When ImageIO came along, the class was deprecated. This means that it is still in Java but not guaranteed to be in any later releases. ImageIO was more complicated to use for JPEG images and we felt the earlier code produced better results so we continued to use it.

I have been checking our code against the new Java 7 (release 4) build for the Mac and it now appears that the old JPEG classes have finally been removed. So I have updated my code to use ImageIO. Here is my updated version with both old and new versions so you can see the changes if you are still using these classes.

public static void saveAsJPEG(String jpgFlag,BufferedImage image_to_save, float JPEGcompression, FileOutputStream fos) throws IOException {
 
    //useful documentation at http://docs.oracle.com/javase/7/docs/api/javax/imageio/metadata/doc-files/jpeg_metadata.html
    //useful example program at http://johnbokma.com/java/obtaining-image-metadata.html to output JPEG data
 
    //old jpeg class
    //com.sun.image.codec.jpeg.JPEGImageEncoder jpegEncoder = com.sun.image.codec.jpeg.JPEGCodec.createJPEGEncoder(fos);
    //com.sun.image.codec.jpeg.JPEGEncodeParam jpegEncodeParam = jpegEncoder.getDefaultJPEGEncodeParam(image_to_save);
 
    // Image writer
    JPEGImageWriter imageWriter = (JPEGImageWriter) ImageIO.getImageWritersBySuffix(“jpeg”).next();
    ImageOutputStream ios = ImageIO.createImageOutputStream(fos);
    imageWriter.setOutput(ios);
 
    //and metadata
    IIOMetadata imageMetaData = imageWriter.getDefaultImageMetadata(new ImageTypeSpecifier(image_to_save), null);
 
    if (jpgFlag != null){
 
        int dpi = 96;
 
        try {
            dpi = Integer.parseInt(jpgFlag);
        } catch (Exception e) {
            e.printStackTrace();
        }
 
        //old metadata
        //jpegEncodeParam.setDensityUnit(com.sun.image.codec.jpeg.JPEGEncodeParam.DENSITY_UNIT_DOTS_INCH);
        //jpegEncodeParam.setXDensity(dpi);
        //jpegEncodeParam.setYDensity(dpi);
 
        //new metadata
        Element tree = (Element) imageMetaData.getAsTree(“javax_imageio_jpeg_image_1.0?);
        Element jfif = (Element)tree.getElementsByTagName(“app0JFIF”).item(0);
        jfif.setAttribute(“Xdensity”, Integer.toString(dpi));
        jfif.setAttribute(“Ydensity”, Integer.toString(dpi));
 
    }
 
    if(JPEGcompression>=0 && JPEGcompression<=1f){
 
        //old compression
        //jpegEncodeParam.setQuality(JPEGcompression,false);
 
        // new Compression
        JPEGImageWriteParam jpegParams = (JPEGImageWriteParam) imageWriter.getDefaultWriteParam();
        jpegParams.setCompressionMode(JPEGImageWriteParam.MODE_EXPLICIT);
        jpegParams.setCompressionQuality(JPEGcompression);
 
    }
 
    //old write and clean
    //jpegEncoder.encode(image_to_save, jpegEncodeParam);
 
    //new Write and clean up
    imageWriter.write(imageMetaData, new IIOImage(image_to_save, null, null), null);
    ios.close();
    imageWriter.dispose();
 
}

Otherwise, Java 7 looks to be a definite progression over Java 6. What do you think of it?

Update
In the end we gave up with trying to patch ImageIO and wrote our own ImageIO replacement from scratch. Lots of other developers seemed to have the problems so we made this commercially available as the JDeli Image library. JDeli can be used as a complete JPG Converter as it can read and write JPG files as well as being able to read a wide range of Image File formats. You can find out more on the JDeli page.

IDRsolutions develop a Java PDF Viewer and SDK, an Adobe forms to HTML5 forms converter, a PDF to HTML5 converter and a Java ImageIO replacement. On the blog our team post anything interesting they learn about.

Mark Stephens Mark has been working with Java and PDF since 1999 and is a big NetBeans fan. He enjoys speaking at conferences. He has an MA in Medieval History and a passion for reading.

11 Replies to “Replacing the deprecated Java JPEG classes for Java 7”

  1. Thank you very much for this post. This was very helpful!

    There is an error in the line with
    “imageWriter.write(imageMetaData, new IIOImage(image_to_save, null, null), null);”

    At the last argument you must provide “jpegParams” or otherwise the
    compression quality will not be applied and all resulting images will have
    the same file size (in my case @ Java 7u76).

  2. Thanks a lot for your code!
    I used it to set dpi of a jpg image but i had to make some changes to make it work.
    You get metadata as tree and modify dpi values, but you need to set the modified tree as metadata after changes. So i had to add this line after setting Xdensity and Ydensity attributes:
    imageMetaData.setFromTree(“javax_imageio_jpeg_image_1.0”, tree);

    Then, i had to modify one of the last lines in this way:
    imageWriter.write(imageMetaData, new IIOImage(image_to_save, null, imageMetaData), jpegParams);

    1. Thanks a lot for your code!But DPI settings are not valid.
      JPEGImageWriter imageWriter = (JPEGImageWriter) ImageIO.getImageWritersBySuffix(“jpg”).next();
      ImageOutputStream ios = ImageIO.createImageOutputStream(fos);
      imageWriter.setOutput(ios);
      IIOMetadata imageMetaData = imageWriter.getDefaultImageMetadata(new ImageTypeSpecifier(image), null);
      Element tree = (Element) imageMetaData.getAsTree(“javax_imageio_jpeg_image_1.0”);
      Element jfif = (Element) tree.getElementsByTagName(“app0JFIF”).item(0);
      for (int i = 0; i < jfif.getAttributes().getLength(); i++) {
      Node attribute = jfif.getAttributes().item(i);
      System.out.println(attribute.getNodeName() + "="
      + attribute.getNodeValue());
      }
      jfif.setAttribute("Xdensity", Integer.toString(dpi));
      jfif.setAttribute("Ydensity", Integer.toString(dpi));
      imageMetaData.setFromTree("javax_imageio_jpeg_image_1.0", tree);

      JPEGImageWriteParam jpegParams = (JPEGImageWriteParam) imageWriter.getDefaultWriteParam();
      jpegParams.setCompressionMode(JPEGImageWriteParam.MODE_EXPLICIT);
      jpegParams.setCompressionQuality(1f);

      //imageWriter.write(imageMetaData, new IIOImage(image, null, null), null);
      imageWriter.write(imageMetaData, new IIOImage(image, null, imageMetaData), jpegParams);
      ios.close();
      imageWriter.dispose();

      1. // This is OK!!!!
        //JPEGImageEncoder jpegEncoder = com.sun.image.codec.jpeg.JPEGCodec.createJPEGEncoder(fos);
        //JPEGEncodeParam jpegEncodeParam = jpegEncoder.getDefaultJPEGEncodeParam(image);
        //jpegEncodeParam.setDensityUnit(JPEGEncodeParam.DENSITY_UNIT_DOTS_INCH);
        //jpegEncodeParam.setXDensity(dpi);
        //jpegEncodeParam.setYDensity(dpi);
        //jpegEncoder.encode(image, jpegEncodeParam);

        // Invalid DPI settings! Why???
        JPEGImageWriter imageWriter = (JPEGImageWriter) ImageIO.getImageWritersBySuffix(“jpg”).next();
        ImageOutputStream ios = ImageIO.createImageOutputStream(fos);
        imageWriter.setOutput(ios);
        IIOMetadata imageMetaData = imageWriter.getDefaultImageMetadata(new ImageTypeSpecifier(image), null);
        Element tree = (Element) imageMetaData.getAsTree(“javax_imageio_jpeg_image_1.0”);
        Element jfif = (Element) tree.getElementsByTagName(“app0JFIF”).item(0);
        for (int i = 0; i < jfif.getAttributes().getLength(); i++) {
        Node attribute = jfif.getAttributes().item(i);
        System.out.println(attribute.getNodeName() + "="
        + attribute.getNodeValue());
        }
        jfif.setAttribute("Xdensity", Integer.toString(dpi));
        jfif.setAttribute("Ydensity", Integer.toString(dpi));
        imageMetaData.setFromTree("javax_imageio_jpeg_image_1.0", tree);

        JPEGImageWriteParam jpegParams = (JPEGImageWriteParam) imageWriter.getDefaultWriteParam();
        jpegParams.setCompressionMode(JPEGImageWriteParam.MODE_EXPLICIT);
        jpegParams.setCompressionQuality(1f);

        //imageWriter.write(imageMetaData, new IIOImage(image, null, null), null);
        imageWriter.write(imageMetaData, new IIOImage(image, null, imageMetaData), jpegParams);
        ios.close();
        imageWriter.dispose();

  3. Thanks for the post. Very helpful. I tried the same in my application and the image is getting written. My only concern is, in my existing code I have a line – jpegEncoder.setJPEGEncodeParam(jpegEncodeParam);

    Will this too be handled by the current code or do I have to write any additional code for the same?

      1. Thanks Mark for your time.
        It will be great if a sample (like the current blog) can be shared for the JDeli library.

      2. Thanks Mark, I would also like to know if the code jpegEncoder.setJPEGEncodeParam(jpegEncodeParam);
        gets handled as per the ImageIO code given in the current blog as we currently wish to continue with ImageIO

Leave a Reply

Your email address will not be published. Required fields are marked *

IDRsolutions Ltd 2019. All rights reserved.