Mega Code Archive

 
Categories / Java / 2D Graphics GUI
 

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;   } }