Simple, functional ImageReaderSpi used to understand how information : Image IO « 2D Graphics GUI « Java






Simple, functional ImageReaderSpi used to understand how information

      
/*

Java Media APIs: Cross-Platform Imaging, Media and Visualization
Alejandro Terrazas
Sams, Published November 2002, 
ISBN 0672320940
*/


import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.awt.image.DataBuffer;
import java.awt.image.WritableRaster;
import java.io.IOException;
import java.util.Iterator;
import java.util.Locale;

import javax.imageio.IIOException;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.imageio.ImageTypeSpecifier;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.metadata.IIOMetadataFormat;
import javax.imageio.metadata.IIOMetadataNode;
import javax.imageio.spi.ImageReaderSpi;
import javax.imageio.stream.ImageInputStream;

import org.w3c.dom.Node;

/**
 * Simple, functional ImageReaderSpi used to understand how information
 * regarding format name, suffices and mime types get passed to ImageIO static
 * methods
 */
public class ch5ImageReaderSpi extends ImageReaderSpi {

  static final String[] suffixes = { "ch5", "CH5" };

  static final String[] names = { "ch5" };

  static final String[] MIMETypes = { "image/ch5" };

  static final String version = "1.00";

  static final String readerCN = "ch5.imageio.plugins.ch5ImageReader";

  static final String vendorName = "CompanyName";

  //writerSpiNames
  static final String[] wSN = { "ch5.imageio.plugins.ch5ImageWriterSpi" };

  //StreamMetadataFormatNames and StreamMetadataFormatClassNames
  static final boolean supportedStandardStreamMetadataFormat = false;

  static final String nativeStreamMFN = "ch5.imageio.ch5stream_1.00";

  static final String nativeStreamMFCN = "ch5.imageio.ch5stream";

  static final String[] extraStreamMFN = null;

  static final String[] extraStreamMFCN = null;

  //ImageMetadataFormatNames and ImageMetadataFormatClassNames
  static final boolean supportedStandardImageMetadataFormat = false;

  static final String nativeImageMFN = "ch5.imageio.ch5image1.00";

  static final String nativeImageMFCN = "ch5.imageio.ch5image";

  static final String[] extraImageMFN = null;

  static final String[] extraImageMFCN = null;

  public ch5ImageReaderSpi() {
    super(vendorName, version, names, suffixes, MIMETypes, readerCN, //readerClassName
        STANDARD_INPUT_TYPE, wSN, //writerSpiNames
        false, nativeStreamMFN, nativeStreamMFCN, extraStreamMFN,
        extraStreamMFCN, false, nativeImageMFN, nativeImageMFCN,
        extraImageMFN, extraImageMFCN);
  }

  public String getDescription(Locale locale) {
    return "Demo ch5 image reader, version " + version;
  }

  public ImageReader createReaderInstance(Object extension) {
    return new ch5ImageReader(this);
  }

  /**
   * This method gets called when an application wants to see if the input
   * image's format can be decoded by this ImageReader. In this case, we'll
   * simply check the first byte of data to see if its a 5 which is the format
   * type's magic number
   */
  public boolean canDecodeInput(Object input) {
    boolean reply = false;

    ImageInputStream iis = (ImageInputStream) input;
    iis.mark(); // mark where we are in ImageInputStream
    try {
      String magicNumber = iis.readLine().trim();
      iis.reset(); // reset stream back to marked location
      if (magicNumber.equals("5"))
        reply = true;
    } catch (IOException exception) {
    }
    return reply;
  }
}

class ch5ImageReader extends ImageReader {
  private ImageInputStream iis;

  private ch5ImageMetadata[] imagemd;

  private ch5StreamMetadata streammd;

  public ch5ImageReader(ImageReaderSpi originatingProvider) {
    super(originatingProvider);
  }

  /**
   * return the ch5StreamMetadata object instantiated in the setStreamMetadata
   * method
   */
  public IIOMetadata getStreamMetadata() {
    return streammd;
  }

  /**
   * return the ch5ImageMetadata object instantiated in the setImageMetadata
   * method
   */
  public IIOMetadata getImageMetadata(int imageIndex) {
    return imagemd[imageIndex];
  }

  /**
   * this method sets the input for this ImageReader and also calls the
   * setStreamMetadata method so that the numberImages field is available
   */
  public void setInput(Object object, boolean seekForwardOnly) {
    super.setInput(object, seekForwardOnly);
    if (object == null)
      throw new IllegalArgumentException("input is null");

    if (!(object instanceof ImageInputStream)) {
      String argString = "input not an ImageInputStream";
      throw new IllegalArgumentException(argString);
    }
    iis = (ImageInputStream) object;
    setStreamMetadata(iis);
  }

  /**
   * this method provides suggestions for possible image types that will be
   * used to decode the image specified by index imageIndex. By default, the
   * first image type returned by this method will be the image type of the
   * BufferedImage returned by the ImageReader's getDestination method. In
   * this case, we are suggesting using an 8 bit grayscale image with no alpha
   * component.
   */
  public Iterator getImageTypes(int imageIndex) {
    java.util.List l = new java.util.ArrayList();
    ;
    int bits = 8;

    /*
     * can convert ch5 format into 8 bit grayscale image with no alpha
     */
    l.add(ImageTypeSpecifier.createGrayscale(bits, DataBuffer.TYPE_BYTE,
        false));
    return l.iterator();
  }

  /**
   * read in the input image specified by index imageIndex using the
   * parameters specified by the ImageReadParam object param
   */
  public BufferedImage read(int imageIndex, ImageReadParam param) {

    checkIndex(imageIndex);

    if (isSeekForwardOnly())
      minIndex = imageIndex;
    else
      minIndex = 0;

    BufferedImage bimage = null;
    WritableRaster raster = null;

    /*
     * this method sets the image metadata so that we can use the getWidth
     * and getHeight methods
     */
    setImageMetadata(iis, imageIndex);

    int srcWidth = getWidth(imageIndex);
    int srcHeight = getHeight(imageIndex);

    // initialize values to -1
    int dstWidth = -1;
    int dstHeight = -1;
    int srcRegionWidth = -1;
    int srcRegionHeight = -1;
    int srcRegionXOffset = -1;
    int srcRegionYOffset = -1;
    int xSubsamplingFactor = -1;
    int ySubsamplingFactor = -1;
    if (param == null)
      param = getDefaultReadParam();

    Iterator imageTypes = getImageTypes(imageIndex);
    try {
      /*
       * get the destination BufferedImage which will be filled using the
       * input image's pixel data
       */
      bimage = getDestination(param, imageTypes, srcWidth, srcHeight);

      /*
       * get Rectangle object which will be used to clip the source
       * image's dimensions.
       */
      Rectangle srcRegion = param.getSourceRegion();
      if (srcRegion != null) {
        srcRegionWidth = (int) srcRegion.getWidth();
        srcRegionHeight = (int) srcRegion.getHeight();
        srcRegionXOffset = (int) srcRegion.getX();
        srcRegionYOffset = (int) srcRegion.getY();

        /*
         * correct for overextended source regions
         */
        if (srcRegionXOffset + srcRegionWidth > srcWidth)
          dstWidth = srcWidth - srcRegionXOffset;
        else
          dstWidth = srcRegionWidth;

        if (srcRegionYOffset + srcRegionHeight > srcHeight)
          dstHeight = srcHeight - srcRegionYOffset;
        else
          dstHeight = srcRegionHeight;
      } else {
        dstWidth = srcWidth;
        dstHeight = srcHeight;
        srcRegionXOffset = srcRegionYOffset = 0;
      }
      /*
       * get subsampling factors
       */
      xSubsamplingFactor = param.getSourceXSubsampling();
      ySubsamplingFactor = param.getSourceYSubsampling();

      /**
       * dstWidth and dstHeight should be equal to bimage.getWidth() and
       * bimage.getHeight() after these next two instructions
       */
      dstWidth = (dstWidth - 1) / xSubsamplingFactor + 1;
      dstHeight = (dstHeight - 1) / ySubsamplingFactor + 1;
    } catch (IIOException e) {
      System.err.println("Can't create destination BufferedImage");
    }
    raster = bimage.getWritableTile(0, 0);

    /*
     * using the parameters specified by the ImageReadParam object, read the
     * image image data into the destination BufferedImage
     */
    byte[] srcBuffer = new byte[srcWidth];
    byte[] dstBuffer = new byte[dstWidth];
    int jj;
    int index;
    try {
      for (int j = 0; j < srcHeight; j++) {
        iis.readFully(srcBuffer, 0, srcWidth);

        jj = j - srcRegionYOffset;
        if (jj % ySubsamplingFactor == 0) {
          jj /= ySubsamplingFactor;
          if ((jj >= 0) && (jj < dstHeight)) {
            for (int i = 0; i < dstWidth; i++) {
              index = srcRegionXOffset + i * xSubsamplingFactor;
              dstBuffer[i] = srcBuffer[index];
            }
            raster.setDataElements(0, jj, dstWidth, 1, dstBuffer);
          }
        }
      }
    } catch (IOException e) {
      bimage = null;
    }
    return bimage;
  }

  /**
   * this method sets the image metadata for the image indexed by index
   * imageIndex. This method is specific for the ch5 format and thus only sets
   * the image width and image height
   */
  private void setImageMetadata(ImageInputStream iis, int imageIndex) {
    imagemd[imageIndex] = new ch5ImageMetadata();
    try {
      String s;
      s = iis.readLine();
      while (s.length() == 0)
        s = iis.readLine();
      imagemd[imageIndex].imageWidth = Integer.parseInt(s.trim());
      s = iis.readLine();
      imagemd[imageIndex].imageHeight = Integer.parseInt(s.trim());
    } catch (IOException exception) {
    }
  }

  /**
   * this method sets the stream metadata for the images represented by the
   * ImageInputStream iis. This method is specific for the ch5 format and thus
   * only sets the numberImages field.
   */
  private void setStreamMetadata(ImageInputStream iis) {
    streammd = new ch5StreamMetadata();
    try {
      String magicNumber = iis.readLine();
      int numImages = Integer.parseInt(iis.readLine().trim());
      streammd.numberImages = numImages;
      imagemd = new ch5ImageMetadata[streammd.numberImages];
    } catch (IOException exception) {
    }
  }

  /**
   * This method can only be used after the stream metadata has been set
   * (which occurs in the setInput method). Else it will return a -1
   */
  public int getNumImages(boolean allowSearch) {
    return streammd.numberImages;
  }

  /**
   * This method can only be used after the stream metadata has been set
   * (which occurs in the setInput method). Else it will return a -1
   */
  public int getHeight(int imageIndex) {
    if (imagemd == null)
      return -1;
    checkIndex(imageIndex);

    return imagemd[imageIndex].imageHeight;
  }

  /**
   * This method can only be used after the stream metadata has been set
   * (which occurs in the setInput method). Else it will return a -1
   */
  public int getWidth(int imageIndex) {
    if (imagemd == null)
      return -1;
    checkIndex(imageIndex);

    return imagemd[imageIndex].imageWidth;
  }

  private void checkIndex(int imageIndex) {
    if (imageIndex >= streammd.numberImages) {
      String argString = "imageIndex >= number of images";
      throw new IndexOutOfBoundsException(argString);
    }
    if (imageIndex < minIndex) {
      String argString = "imageIndex < minIndex";
      throw new IndexOutOfBoundsException(argString);
    }
  }
}


/**
 * ch5ImageMetadata.java -- holds image metadata for the ch5 format. The
 * internal tree for holding this metadata is read only
 */

class ch5ImageMetadata extends IIOMetadata {
  static final String nativeMetadataFormatName = "ch5.imageio.ch5image_1.00";

  static final String nativeMetadataFormatClassName = "ch5.imageio.ch5image";

  static final String[] extraMetadataFormatNames = null;

  static final String[] extraMetadataFormatClassNames = null;

  static final boolean standardMetadataFormatSupported = false;

  public int imageWidth;

  public int imageHeight;

  public ch5ImageMetadata() {
    super(standardMetadataFormatSupported, nativeMetadataFormatName,
        nativeMetadataFormatClassName, extraMetadataFormatNames,
        extraMetadataFormatClassNames);
    imageWidth = -1;
    imageHeight = -1;
  }

  public boolean isReadOnly() {
    return true;
  }

  /**
   * IIOMetadataFormat objects are meant to describe the structure of metadata
   * returned from the getAsTree method. In this case, no such description is
   * available
   */
  public IIOMetadataFormat getMetadataFormat(String formatName) {
    if (formatName.equals(nativeMetadataFormatName)) {
      return null;
    } else {
      throw new IllegalArgumentException("Unrecognized format!");
    }
  }

  /**
   * returns the image metadata in a tree corresponding to the provided
   * formatName
   */
  public Node getAsTree(String formatName) {
    if (formatName.equals(nativeMetadataFormatName)) {
      return getNativeTree();
    } else {
      throw new IllegalArgumentException("Unrecognized format!");
    }
  }

  /**
   * returns the image metadata in a tree using the following format <!ELEMENT
   * ch5.imageio.ch5image_1.00 (imageDimensions)> <!ATTLIST imageDimensions
   * imageWidth CDATA #REQUIRED imageHeight CDATA #REQUIRED
   */
  private Node getNativeTree() {
    IIOMetadataNode root = new IIOMetadataNode(nativeMetadataFormatName);

    IIOMetadataNode node = new IIOMetadataNode("imageDimensions");
    node.setAttribute("imageWidth", Integer.toString(imageWidth));
    node.setAttribute("imageHeight", Integer.toString(imageHeight));
    root.appendChild(node);

    return root;
  }

  public void setFromTree(String formatName, Node root) {
    throw new IllegalStateException("Metadata is read-only!");
  }

  public void mergeTree(String formatName, Node root) {
    throw new IllegalStateException("Metadata is read-only!");
  }

  public void reset() {
    throw new IllegalStateException("Metadata is read-only!");
  }

  /**
   * initialize the image metadata elements width and height
   */
  public void initialize(int width, int height) {
    imageWidth = width;
    imageHeight = height;
  }
}


/**
 * ch5StreamMetadata.java -- holds stream metadata for the ch5 format. The
 * internal tree for holding this metadata is read only
 */

class ch5StreamMetadata extends IIOMetadata {
  static final String nativeMetadataFormatName = "ch5.imageio.ch5stream_1.00";

  static final String nativeMetadataFormatClassName = "ch5.imageio.ch5stream";

  static final String[] extraMetadataFormatNames = null;

  static final String[] extraMetadataFormatClassNames = null;

  static final boolean standardMetadataFormatSupported = false;

  public int numberImages;

  public ch5StreamMetadata() {
    super(standardMetadataFormatSupported, nativeMetadataFormatName,
        nativeMetadataFormatClassName, extraMetadataFormatNames,
        extraMetadataFormatClassNames);
    numberImages = -1;
  }

  public boolean isReadOnly() {
    return true;
  }

  /**
   * IIOMetadataFormat objects are meant to describe the structure of metadata
   * returned from the getAsTree method. In this case, no such description is
   * available
   */
  public IIOMetadataFormat getMetadataFormat(String formatName) {
    if (formatName.equals(nativeMetadataFormatName)) {
      return null;
    } else {
      throw new IllegalArgumentException("Unrecognized format!");
    }
  }

  /**
   * returns the stream metadata in a tree corresponding to the provided
   * formatName
   */
  public Node getAsTree(String formatName) {
    if (formatName.equals(nativeMetadataFormatName)) {
      return getNativeTree();
    } else {
      throw new IllegalArgumentException("Unrecognized format!");
    }
  }

  /**
   * returns the stream metadata in a tree using the following format
   * <!ELEMENT ch5.imageio.ch5stream_1.00 (imageDimensions)> <!ATTLIST
   * imageDimensions numberImages CDATA #REQUIRED
   */
  private Node getNativeTree() {
    IIOMetadataNode node; // scratch node

    IIOMetadataNode root = new IIOMetadataNode(nativeMetadataFormatName);

    // Image descriptor
    node = new IIOMetadataNode("imageDimensions");
    node.setAttribute("numberImages", Integer.toString(numberImages));
    root.appendChild(node);

    return root;
  }

  public void setFromTree(String formatName, Node root) {
    throw new IllegalStateException("Metadata is read-only!");
  }

  public void mergeTree(String formatName, Node root) {
    throw new IllegalStateException("Metadata is read-only!");
  }

  public void reset() {
    throw new IllegalStateException("Metadata is read-only!");
  }

  /**
   * initialize the stream metadata element numberImages
   */
  public void initialize(int numberImages) {
    this.numberImages = numberImages;
  }
}

           
         
    
    
    
    
    
  








Related examples in the same category

1.Display image supported by ImageIO
2.Print an Image to print directly
3.List All reader and writer formats supported by ImageIO
4.Display available ImageReaders and ImageWriters by image format and MIME typeDisplay available ImageReaders and ImageWriters by image format and MIME type
5.Write an image of a given format
6.Read an image
7.Simple, functional ImageWriterSpi used to understand how information
8.Example showing how to reset the ordering of ImageReaderSpis in Image I/OExample showing how to reset the ordering of ImageReaderSpis in Image I/O
9.Using mediatracker to pre-load images
10.Get list of unique supported read formats
11.Get list of unique supported write formats
12.Get list of unique MIME types that can be read
13.Get list of unique MIME types that can be written
14.Returns true if the specified format name can be read
15.Returns true if the specified format name can be written
16.Returns true if the specified file extension can be read
17.Returns true if the specified file extension can be written
18.Returns true if the specified mime type can be read
19.Returns true if the specified mime type can be written
20.Show ImageIO Info
21.Write Image with different types
22.Load the image file from a folder or a jar file: use javax.imageio.ImageIO class to read the image file
23.Compress and save an image to the disk
24.Creates a new raster copy
25.Resizes an image
26.Creates an image compatible with the current display
27.Produces a copy of the supplied image
28.Produces a resized image that is of the given dimensions
29.Loads an image in a format compatible with the current display
30.Thumbnail Generator
31.Saves an image to the disk
32.Helper class for debugging stuff in Image I/O.
33.Reading a gif image with ImageIO.read and display it on screenReading a gif image with ImageIO.read and display it on screen
34.Read and write image files in the formats that the JDK supports. Multi-file images are supported.
35.A program for viewing imagesA program for viewing images
36.Thumbnail Tools