Mega Code Archive

 
Categories / Java / 2D Graphics GUI
 

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