Advanced Imaging Image I/O API RC 1.0

   
   

Articles Index


Interested in manipulating images but need to use formats other than GIF, JPEG, and PNG? Looking for better performance when working with JPEG images and don't know where to look? Need to manipulate images through geometric operations, including non-linear transformations? Fret no more; the answers are here in the form of the Java Advanced Imaging (JAI) API and the Java Advanced Imaging Image I/O API 1.0 RC from Sun.

The JAI API is part of the Java Media APIs, along with the Java 2D API, Java 3D API, Java Speech API, and several others. Developed as part of the Java Specification Request (JSR) 34, the Java Advanced Imaging API offers an extension to the Java 2 Platform, Standard Edition (J2SE) version 1.3+ releases for manipulating images. Originally available in a 1.0 release, the Java Developer Connection (JDC) offers an early access to the 1.1.2 beta of the Java Advanced Imaging API. (See the README.html file for what's new there.) What the API offers beyond the AWT and Java 2D functionality is a richer API set for image manipulation including built in support for many common imaging operations.

This article isn't about the JAI API though. Instead, it is about a set of image reader/writer (codec) classes that comes with the API but has been separated into its own installable library, the Java Advanced Imaging Image I/O Tools 1.0 RC. The RC release provides functionality that plugs into the Image I/O framework specific to the J2SE 1.4 release. Developed as part of JSR-15, the Image I/O API offers a pluggable framework working with different image formats. Available as part of the standard 1.4 release with support for GIF, JPEG, and PNG formats, the JAI Image I/O RC provides readers and writers for additional popular image formats. By just adding the platform-specific native version of the tool, previously developed applications can work with additional image formats.

To understand the usage of the JAI Image I/O Tools, you need to understand the Image I/O library. We'll take a look at that first before installing and demonstrating the tools.

Image I/O Library

The Image I/O library is one of the standard APIs of the J2SE 1.4 release in the javax.imageio package. While the package offers two interfaces and nine classes, the whole of the API is really just the ImageIO class. From there, you can find out what image formats are supported for reading and writing, and then read or write them. That is really the whole of the API.

As the Image I/O library is a pluggable framework, the set of supported image formats is not fixed. Yes, there are standard formats supported with the J2SE 1.4 release, and anyone can add additional formats. To find out what formats are available, you just ask.

import javax.imageio.*;
import java.util.Arrays;

public class GetFormats {
  public static void main(String args[]) {
    String readFormats[] = ImageIO.getReaderMIMETypes();
    String writeFormats[] = ImageIO.getWriterMIMETypes();
    System.out.println("Readers: " + 
        Arrays.asList(readFormats));
    System.out.println("Writers: " + 
        Arrays.asList(writeFormats));
  }
}

Running the program, you'll find out that there is support for reading GIF, JPEG, and PNG images and support for writing JPEG and PNG images. There is no write support for writing GIF files.

Besides working with MIME types like image/jpeg, the ImageIO class also allows you to work with informal names like JPEG through the getReaderFormatNames and getWriterFormatNames methods. You can also find out if a reader/writer exists for a specific filename extension with getImageReadersBySuffix and getImageWritersBySuffix.

With the ImageIO class, all you have to do is read the javax.imageio.stream.ImageInputStream, java.io.InputStream, java.io.File, or java.net.URL. In turn, this gives you a java.awt.image.BufferedImage. Once you have a BufferedImage, you can write the image back out by providing the format name of the desired output. (You can write any class that implements the RenderedImage interface, not just a BufferedImage.) This could either be the same format as what was read in or some other format to convert the format. If no writer is available for the given format, then write returns false, otherwise true is returned for success in finding a writer.

String inputFilename = ...;
BufferedImage image = ImageIO.read(inputFilename);
...
String formatName = "jpg"; // desired format
String outputFilename = ...;
File outputFile = new File(outputFilename);
boolean writerExists = ImageIO.write(image,
formatName, outputFile);

To demonstrate the use of the Image I/O libraries, the following program prompts for an input file with the help of a JFileChooser. After selecting the file, you select the desired output format and press Save. Upon saving the image, the image is re-read to be displayed in a new window.

import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import javax.swing.*;
import java.io.*;
import java.net.*;
import javax.imageio.*;

public class Converting extends JFrame {
  JLabel promptLabel;
  JTextField prompt;
  JButton promptButton;
  JFileChooser fileChooser;
  JComboBox comboBox;
  JButton saveButton;
  public Converting() {
    super("Image Conversion");
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    Container contentPane = getContentPane();
    JPanel inputPanel = new JPanel();
    promptLabel = new JLabel("Filename:");
    inputPanel.add(promptLabel);
    prompt = new JTextField(20);
    inputPanel.add(prompt);
    promptButton = new JButton("Browse");
    inputPanel.add(promptButton);
    contentPane.add(inputPanel, BorderLayout.NORTH);

    fileChooser = new JFileChooser();
    promptButton.addActionListener(
      new ActionListener() {
        public void actionPerformed(ActionEvent e) {
          int returnValue = 
              fileChooser.showOpenDialog(null);
          if (returnValue == 
              JFileChooser.APPROVE_OPTION) {
            File selectedFile = 
                fileChooser.getSelectedFile();
            if (selectedFile != null) {
              prompt.setText(selectedFile.getAbsolutePath());
            }
          }
        }
      }
    );

    JPanel outputPanel = new JPanel();
    String writerFormats[] = 
        ImageIO.getWriterFormatNames();
    ComboBoxModel comboBoxModel = new 
        DefaultComboBoxModel(writerFormats);
    comboBox = new JComboBox(comboBoxModel);
    outputPanel.add(comboBox);
    saveButton = new JButton("Save");
    outputPanel.add(saveButton);
    saveButton.addActionListener(
      new ActionListener() {
        public void actionPerformed(ActionEvent e) {
          try {
            String name = prompt.getText();
            File file = new File(name);
            if (file.exists()) {
              BufferedImage image = 
                  ImageIO.read(file.toURL());
              if (image == null) {
                  System.err.println("Invalid input 
                      file format");
              } else {
                String selection = 
                    (String)comboBox.getSelectedItem();
                String outputFilename = name + 
                    "." + selection;
                File outputFile = new File(outputFilename);
                boolean found = ImageIO.write(image, 
                    selection, outputFile);
                if (found) {
                  JDialog window = new JDialog();
                  Container windowContent = 
                      window.getContentPane();
                  BufferedImage newImage = 
                      ImageIO.read(outputFile);
                  JLabel label = new JLabel(new 
                      ImageIcon(newImage));
                  JScrollPane pane = new 
                      JScrollPane(label);
                  windowContent.add(pane, 
                      BorderLayout.CENTER);
                  window.setSize(300, 300);
                  window.show();
                } else {
                  System.err.println("Error saving");
                }
              }
            } else {
              System.err.println("Bad filename");
            }
          } catch (MalformedURLException mur) {
            System.err.println("Bad filename");
          } catch (IOException ioe) {
            System.err.println("Error reading file");
          }
        }
      }
    );

    contentPane.add(outputPanel, BorderLayout.SOUTH);

  }
  public static void main(String args[]) {
    JFrame frame = new Converting();
    frame.pack();
    frame.show();
  }
}

Notice that the program doesn't hardcode any filetypes. Instead, it asks the Image I/O framework what formats are supported. Once you install the Java Advanced Imaging Image I/O Tools RC, you'll be able to rerun the same program and the program will offer different formats for saving. Reading other formats will essentially just work without any code changes, too, as a user can just pick a different file type.

Note: There is more to the Image I/O library than what is shown here. For instance, you can set parameters for writing to set options like compression level or listen for events with perhaps a read or write progress listener. For more information on Image I/O usage, see the Java Image I/O API Guide.

Java Advanced Imaging Image I/O Tools 1.0 Overview

That brings us to the actual purpose of this article, the Java Advanced Imaging Image I/O Tools 1.0 (RC). The JAI Image I/O Tools essential purpose is to provide additional image readers/writers (codecs) for use with the Image I/O libraries of J2SE 1.4. Once made available for your runtime platform, your programs will then support these additional codecs.

The new codecs available with the JAI Image I/O Tools are as follows:

  • Bitmap (BMP) reader and writer support (MIME type image/bmp)
  • Accelerated JPEG reader and writer support through native code (MIME type image/jpeg). Lossless JPEG (ISO 10918-1) and JPEG-LS (ISO 14495-1) are also supported and 12-bit depth is handled for all supported JPEG variants.
  • JPEG 2000 reader and writer support (MIME type image/jpeg2000)
  • Accelerated PNG reader and writer support through native code (MIME type image/png)
  • Portable anymap (PNM) reader and writer support for portable bitmap (PBM), portable graymap (PGM), and portable pixmap (PPM) (MIME types image/x-portable-anymap, image/x-portable-bitmap, image/x-portable-graymap, image/x-portable-pixmap)
  • Raw format (no MIME type)
  • Tag(ged) Image File Format (TIFF) reader and writer support (MIME type image/tiff)
  • Wireless Bitmap (WBMP) reader and writer support (MIME type image/vnd.wap.wbmp)

The library also makes available stream plug-ins for use with the NIO libraries. See the com.sun.media.imageio.stream package for the FileChannelImageInputStream, FileChannelImageOutputStream, and RawImageInputStream. The first two work with java.nio.channels.FileChannel as the source or destination, respectively, while the latter is used by the raw format javax.imageio.ImageReader, to permit reading raw data. There is also support for the JAI operations "ImageRead" and "ImageWrite" which are included with the package set. These are analogous to the extant JAI operation sets {"Stream", "FileLoad", "URL"} and {"Encode", "FileStore"}, respectively.

Java Advanced Imaging Image I/O Tools 1.0 Installation

To use the Java Advanced Imaging Image I/O Tools, you must download the version specific to your platform from the Early Access page for the RC. Versions are available for Solaris SPARC, Solaris x86, Linux, and Windows and range in size from 5 MB for the Solaris SPARC version to 1 MB for the others. The README-jai_imageio.html file that comes with the download provides information about the download, including installation instructions. In addition, the file provides information on the supported versions of the reader and writer plugins, like the BMP codec can read version 3-5 but only write version 3 images.

There are three JAR files that come with the installation along with the native libraries. These native libraries will not be used if security settings do not permit them, reverting back to the built-in Pure Java versions for JPG and PNG formats.

To install the libraries on a Unix machine, you'll need to install the three JAR files into the jre/lib/ext directory. For Solaris-SPARC users, you get to copy the six .so files to jre/lib/sparc. For Solaris-x86 and Linux users, you get to copy the libclib_jiio.so file to jre/lib/i386.

For installation on Microsoft Windows-based machines, the three JAR files also get copied into the jre\lib\ext directory. The remaining clib_jiio.dll file goes into jre\bin.

Note: In all cases, the installation directories are relative to the root level for your JRE.

Once the files are copied to the necessary location, the JAI Image I/O Tools are installed.

Java Advanced Imaging Image I/O Tools 1.0 Usage

Usage of the Image I/O libraries with the Java Advanced Imaging Image I/O Tools installed changes nothing. Properly programmed code will work unchanged. About the only thing you might want to change is which file extension to use for the new formats. You can either use the names returned by something like getWriterFormatNames or hardcode your own for each format.

To demonstrate that the same code works unchanged, first run the GetFormats example. This should now report support for the new MIME types:

Readers: [image/png, image/x-portable-graymap, 
 image/jpeg, image/jpeg2000, image/x-png, 
 image/tiff, image/vnd.wap.wbmp, image/x-portable-pixmap, 
 image/x-portable-bitmap, image/bmp, image/gif, 
 image/x-portable-anymap, ]
Writers: [image/png, image/x-portable-graymap, image/jpeg, 
 image/jpeg2000, image/x-png, image/tiff, 
 image/vnd.wap.wbmp, image/x-portable-pixmap, 
 image/x-portable-bitmap, image/bmp, 
 image/x-portable-anymap, ]

Running the Converting program next will then allow you to convert images to and from more formats.

While the default reading and writing settings are typically sufficient for the default set of readers and writers, with some of the new codecs you might want to change these settings. To change the settings, you'll need to not call the read and write methods of ImageIO. Instead, you'll need to get an ImageReader or ImageWriter from ImageIO, typically for a specific MIME type. Then, with that ImageReader or ImageWriter, you can then customize its settings. If you customize the default ImageReadParam or ImageWriteParam, you'll be able to go back and use the read and write methods of ImageIO. Otherwise, you'll need to do the read or write operation in the ImageReader or ImageWriter. For instance, the JPEG ImageWriter lets you tell the writer to generate optimized Huffman tables for the image. Other codecs may offer their own appropriate settings.

Conclusion

The Java Advanced Imaging Image I/O Tools 1.0 RC is a welcome addition to the extensions available for the Java platform. Once out of RC, the additional image formats supported will be a welcome improvement to the standard runtime. The guts of the libraries are hidden away in several com.sun.media.imageio packages, some even as native libraries. However, the usage of all the libraries is done through the standard Image I/O framework, introduced with the J2SE 1.4 release. Just adding the libraries to the JRE is sufficient to make them available to the user.

Resources


Have a question about programming? Use Java Online Support.