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






Simple, functional ImageWriterSpi 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.Raster;
import java.io.IOException;
import java.util.Locale;

import javax.imageio.IIOImage;
import javax.imageio.ImageTypeSpecifier;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.metadata.IIOMetadataFormat;
import javax.imageio.metadata.IIOMetadataNode;
import javax.imageio.spi.ImageWriterSpi;
import javax.imageio.stream.ImageOutputStream;

import org.w3c.dom.Node;

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

  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 writerClassName = "ch5.imageio.plugins.ch5ImageWriter";

  static final String vendorName = "Company Name";

  static final String[] readerSpiNames = { "ch5.imagio.plugins.ch5ImageReaderSpi" };

  /*
   * static final String nativeStreamMetadataFormatName =
   * "ch5.imageio.ch5stream_1.0"; static final String[]
   * streamMetadataFormatNames = {nativeStreamMetadataFormatName}; static
   * final String nativeImageMetadataFormatName = "ch5.imageio.ch5image_1.0";
   * static final String[] imageMetadataFormatNames =
   * {nativeImageMetadataFormatName};
   */

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

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

  static final String[] extraStreamMetadataFormatNames = { null };

  static final String[] extraStreamMetadataFormatClassNames = { null };

  static final String nativeImageMetadataFormatName = "ch5.imageio.ch5image_1.00";

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

  static final String[] extraImageMetadataFormatNames = { null };

  static final String[] extraImageMetadataFormatClassNames = { null };

  public ch5ImageWriterSpi() {
    super(vendorName, version, names, suffixes, MIMETypes, writerClassName,
        STANDARD_OUTPUT_TYPE, readerSpiNames, false,
        nativeStreamMetadataFormatName,
        nativeStreamMetadataFormatClassName,
        extraStreamMetadataFormatNames,
        extraStreamMetadataFormatClassNames, false,
        nativeImageMetadataFormatName,
        nativeImageMetadataFormatClassName,
        extraImageMetadataFormatNames,
        extraImageMetadataFormatClassNames);

  }

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

  public ImageWriter createWriterInstance(Object extension) {
    return new ch5ImageWriter(this);
  }

  /**
   * This method gets called when an application wants to see if the
   * corresponding ImageWriter can encode an image with a ColorModel and
   * SampleModel specified by the ImageTypeSpecifier
   */
  public boolean canEncodeImage(ImageTypeSpecifier its) {
    if (its.getBufferedImageType() == BufferedImage.TYPE_BYTE_GRAY)
      return true;
    else
      return false;
  }
}

class ch5v1ImageWriter extends ImageWriter {

  public ch5v1ImageWriter(ImageWriterSpi originatingProvider) {
    super(originatingProvider);
    streamMetadataWritten = false;
  }

  /**
   * this method returns null for now. We will revisit it at the end of this
   * chapter after metadata has been discussed.
   */
  public IIOMetadata convertImageMetadata(IIOMetadata metadata,
      ImageTypeSpecifier its, ImageWriteParam param) {
    return null;
  }

  /**
   * this method returns null for now. We will revisit it at the end of this
   * chapter after metadata has been discussed.
   */
  public IIOMetadata convertStreamMetadata(IIOMetadata metadata,
      ImageWriteParam param) {
    return null;
  }

  /**
   * this method returns null for now. We will revisit it at the end of this
   * chapter after metadata has been discussed.
   */
  public IIOMetadata getDefaultImageMetadata(ImageTypeSpecifier its,
      ImageWriteParam param) {
    return null;
  }

  /**
   * this method returns null for now. We will revisit it at the end of this
   * chapter after metadata has been discussed.
   */
  public IIOMetadata getDefaultStreamMetadata(ImageWriteParam param) {
    return null;
  }

  /**
   * write out the output image specified by index imageIndex using the
   * parameters specified by the ImageWriteParam object param
   */
  public void write(IIOMetadata metadata, IIOImage iioimage,
      ImageWriteParam param) {
    Node root = null;
    Node dimensionsElementNode = null;

    if (iioimage.getRenderedImage() != null)
      raster = iioimage.getRenderedImage().getData();
    else
      raster = iioimage.getRaster();

    /*
     * since this format allows you to write multiple images, the
     * streamMetadataWritten variable makes sure the stream metadata is
     * written only once. Not using metadata in this version, so using
     * default value of 1 image per output stream.
     */
    if (streamMetadataWritten == false) {
      try {
        ios.writeBytes("5\n");
        ios.writeBytes("1");
        ios.flush();
      } catch (IOException ioe) {
        System.err.println("IOException " + ioe.getMessage());
      }
      streamMetadataWritten = true;
    }

    int sourceWidth = raster.getWidth();
    int sourceHeight = raster.getHeight();
    int destinationWidth = -1;
    int destinationHeight = -1;
    int sourceRegionWidth = -1;
    int sourceRegionHeight = -1;
    int sourceRegionXOffset = -1;
    int sourceRegionYOffset = -1;
    int xSubsamplingFactor = -1;
    int ySubsamplingFactor = -1;

    if (param == null)
      param = getDefaultWriteParam();

    /*
     * get Rectangle object which will be used to clip the source image's
     * dimensions.
     */
    Rectangle sourceRegion = param.getSourceRegion();
    if (sourceRegion != null) {
      sourceRegionWidth = (int) sourceRegion.getWidth();
      sourceRegionHeight = (int) sourceRegion.getHeight();
      sourceRegionXOffset = (int) sourceRegion.getX();
      sourceRegionYOffset = (int) sourceRegion.getY();

      /*
       * correct for overextended source regions
       */
      if (sourceRegionXOffset + sourceRegionWidth > sourceWidth)
        destinationWidth = sourceWidth - sourceRegionXOffset;
      else
        destinationWidth = sourceRegionWidth;

      if (sourceRegionYOffset + sourceRegionHeight > sourceHeight)
        destinationHeight = sourceHeight - sourceRegionYOffset;
      else
        destinationHeight = sourceRegionHeight;
    } else {
      destinationWidth = sourceWidth;
      destinationHeight = sourceHeight;
      sourceRegionXOffset = sourceRegionYOffset = 0;
    }
    /*
     * get subsampling factors
     */
    xSubsamplingFactor = param.getSourceXSubsampling();
    ySubsamplingFactor = param.getSourceYSubsampling();

    destinationWidth = (destinationWidth - 1) / xSubsamplingFactor + 1;
    destinationHeight = (destinationHeight - 1) / ySubsamplingFactor + 1;

    byte[] sourceBuffer;
    byte[] destinationBuffer = new byte[destinationWidth];

    try {
      ios.writeBytes(new String("\n"));
      ios.writeBytes(new String(destinationWidth + "\n"));
      ios.writeBytes(new String(destinationHeight + "\n"));

      int jj;
      int index;
      for (int j = 0; j < sourceWidth; j++) {
        sourceBuffer = (byte[]) raster.getDataElements(0, j,
            sourceWidth, 1, null);
        jj = j - sourceRegionYOffset;
        if (jj % ySubsamplingFactor == 0) {
          jj /= ySubsamplingFactor;
          if ((jj >= 0) && (jj < destinationHeight)) {
            for (int i = 0; i < destinationWidth; i++) {
              index = sourceRegionXOffset + i
                  * xSubsamplingFactor;
              destinationBuffer[i] = sourceBuffer[index];
            }
            ios.write(destinationBuffer, 0, destinationWidth);
            ios.flush();
          }
        }
      }
    } catch (IOException e) {
      System.err.println("IOException: " + e.getMessage());
    }
  }

  public void setOutput(Object output) {
    super.setOutput(output);

    if (output == null)
      throw new IllegalArgumentException("output is null");

    if (!(output instanceof ImageOutputStream))
      throw new IllegalArgumentException(
          "output not an ImageOutputStream");

    ios = (ImageOutputStream) output;
    streamMetadataWritten = false;
  }

  private ImageOutputStream ios;

  private boolean streamMetadataWritten;

  private Raster raster;
}

class ch5ImageWriter extends ImageWriter {

  public ch5ImageWriter(ImageWriterSpi originatingProvider) {
    super(originatingProvider);
    streamMetadataWritten = false;
  }

  /**
   * this method is used to convert an ImageReader's image metadata which is
   * in a particular format into image metadata that can be used for this
   * ImageWriter. Primarily this is used for transcoding (format conversion).
   * This ImageWriter does not support such conversions
   */
  public IIOMetadata convertImageMetadata(IIOMetadata metadata,
      ImageTypeSpecifier specifier, ImageWriteParam param) {
    return null;
  }

  /**
   * this method is used to convert an ImageReader's stream metadata which is
   * in a particular format into stream metadata that can be used for this
   * ImageWriter. Primarily this is used for transcoding (format conversion).
   * This ImageWriter does not support such conversions
   */
  public IIOMetadata convertStreamMetadata(IIOMetadata metadata,
      ImageWriteParam param) {
    return null;
  }

  /**
   * provide default values for the image metadata
   */
  public IIOMetadata getDefaultImageMetadata(ImageTypeSpecifier specifier,
      ImageWriteParam param) {
    ch5ImageMetadata imagemd = new ch5ImageMetadata();
    int width = raster.getWidth();
    int height = raster.getHeight();
    imagemd.initialize(width, height); // default image size
    return imagemd;
  }

  /**
   * provide default values for the stream metadata
   */
  public IIOMetadata getDefaultStreamMetadata(ImageWriteParam param) {
    ch5StreamMetadata streammd = new ch5StreamMetadata();
    streammd.initialize(1); // default number of images
    return streammd;
  }

  /**
   * write out the output image specified by index imageIndex using the
   * parameters specified by the ImageWriteParam object param
   */
  public void write(IIOMetadata metadata, IIOImage iioimage,
      ImageWriteParam param) {
    Node root = null;
    Node dimensionsElementNode = null;

    if (iioimage.getRenderedImage() != null)
      raster = iioimage.getRenderedImage().getData();
    else
      raster = iioimage.getRaster();

    /*
     * since this format allows you to write multiple images, the
     * streamMetadataWritten variable makes sure the stream metadata is
     * written only once
     */
    if (streamMetadataWritten == false) {
      if (metadata == null)
        metadata = getDefaultStreamMetadata(param);
      root = metadata.getAsTree("ch5.imageio.ch5stream_1.00");
      dimensionsElementNode = root.getFirstChild();
      Node numberImagesAttributeNode = dimensionsElementNode
          .getAttributes().getNamedItem("numberImages");
      String numberImages = numberImagesAttributeNode.getNodeValue();
      try {
        ios.writeBytes("5\n");
        ios.writeBytes(numberImages);
        ios.flush();
      } catch (IOException ioe) {
        System.err.println("IOException " + ioe.getMessage());
      }
      streamMetadataWritten = true;
    }

    String widthString;
    String heightString;
    IIOMetadata imageMetadata = (ch5ImageMetadata) iioimage.getMetadata();
    /*
     * don't really need image metadata object here since raster knows
     * necessary information
     */
    if (imageMetadata == null)
      imageMetadata = getDefaultImageMetadata(null, param);

    root = imageMetadata.getAsTree("ch5.imageio.ch5image_1.00");
    dimensionsElementNode = root.getFirstChild();

    Node widthAttributeNode = dimensionsElementNode.getAttributes()
        .getNamedItem("imageWidth");
    widthString = widthAttributeNode.getNodeValue();

    Node heightAttributeNode = dimensionsElementNode.getAttributes()
        .getNamedItem("imageHeight");
    heightString = heightAttributeNode.getNodeValue();

    int sourceWidth = Integer.parseInt(widthString);
    int sourceHeight = Integer.parseInt(heightString);
    int destinationWidth = -1;
    int destinationHeight = -1;
    int sourceRegionWidth = -1;
    int sourceRegionHeight = -1;
    int sourceRegionXOffset = -1;
    int sourceRegionYOffset = -1;
    int xSubsamplingFactor = -1;
    int ySubsamplingFactor = -1;

    if (param == null)
      param = getDefaultWriteParam();

    /*
     * get Rectangle object which will be used to clip the source image's
     * dimensions.
     */
    Rectangle sourceRegion = param.getSourceRegion();
    if (sourceRegion != null) {
      sourceRegionWidth = (int) sourceRegion.getWidth();
      sourceRegionHeight = (int) sourceRegion.getHeight();
      sourceRegionXOffset = (int) sourceRegion.getX();
      sourceRegionYOffset = (int) sourceRegion.getY();

      /*
       * correct for overextended source regions
       */
      if (sourceRegionXOffset + sourceRegionWidth > sourceWidth)
        destinationWidth = sourceWidth - sourceRegionXOffset;
      else
        destinationWidth = sourceRegionWidth;

      if (sourceRegionYOffset + sourceRegionHeight > sourceHeight)
        destinationHeight = sourceHeight - sourceRegionYOffset;
      else
        destinationHeight = sourceRegionHeight;
    } else {
      destinationWidth = sourceWidth;
      destinationHeight = sourceHeight;
      sourceRegionXOffset = sourceRegionYOffset = 0;
    }
    /*
     * get subsampling factors
     */
    xSubsamplingFactor = param.getSourceXSubsampling();
    ySubsamplingFactor = param.getSourceYSubsampling();

    destinationWidth = (destinationWidth - 1) / xSubsamplingFactor + 1;
    destinationHeight = (destinationHeight - 1) / ySubsamplingFactor + 1;

    byte[] sourceBuffer;
    byte[] destinationBuffer = new byte[destinationWidth];

    try {
      ios.writeBytes(new String("\n"));
      ios.writeBytes(new String(destinationWidth + "\n"));
      ios.writeBytes(new String(destinationHeight + "\n"));

      int jj;
      int index;
      for (int j = 0; j < sourceWidth; j++) {
        sourceBuffer = (byte[]) raster.getDataElements(0, j,
            sourceWidth, 1, null);
        jj = j - sourceRegionYOffset;
        if (jj % ySubsamplingFactor == 0) {
          jj /= ySubsamplingFactor;
          if ((jj >= 0) && (jj < destinationHeight)) {
            for (int i = 0; i < destinationWidth; i++) {
              index = sourceRegionXOffset + i
                  * xSubsamplingFactor;
              destinationBuffer[i] = sourceBuffer[index];
            }
            ios.write(destinationBuffer, 0, destinationWidth);
            ios.flush();
          }
        }
      }
    } catch (IOException e) {
      System.err.println("IOException: " + e.getMessage());
    }
  }

  public void setOutput(Object output) {
    super.setOutput(output);

    if (output == null)
      throw new IllegalArgumentException("output is null");

    if (!(output instanceof ImageOutputStream))
      throw new IllegalArgumentException(
          "output not an ImageOutputStream");

    ios = (ImageOutputStream) output;
    streamMetadataWritten = false;
  }

  private ImageOutputStream ios;

  private boolean streamMetadataWritten;

  private Raster raster;
}


/**
 * 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 ImageReaderSpi 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