ImageCodec.java
上传用户:btjssb159
上传日期:2018-01-04
资源大小:241k
文件大小:29k
源码类别:

DNA

开发平台:

Java

  1. /*
  2.  * Copyright (c) 2001 Sun Microsystems, Inc. All Rights Reserved.
  3.  *
  4.  * Redistribution and use in source and binary forms, with or without 
  5.  * modification, are permitted provided that the following conditions are met:
  6.  * 
  7.  * -Redistributions of source code must retain the above copyright notice, this 
  8.  * list of conditions and the following disclaimer.
  9.  *
  10.  * -Redistribution in binary form must reproduct the above copyright notice,
  11.  * this list of conditions and the following disclaimer in the documentation
  12.  * and/or other materials provided with the distribution.
  13.  * 
  14.  * Neither the name of Sun Microsystems, Inc. or the names of contributors may
  15.  * be used to endorse or promote products derived from this software without
  16.  * specific prior written permission.
  17.  * 
  18.  * This software is provided "AS IS," without a warranty of any kind. ALL
  19.  * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
  20.  * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
  21.  * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE
  22.  * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
  23.  * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS
  24.  * LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
  25.  * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
  26.  * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
  27.  * OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
  28.  * POSSIBILITY OF SUCH DAMAGES.
  29.  * 
  30.  * You acknowledge that Software is not designed,licensed or intended for use in 
  31.  * the design, construction, operation or maintenance of any nuclear facility.
  32.  */
  33. import java.awt.Transparency;
  34. import java.awt.color.ColorSpace;
  35. import java.awt.image.ColorModel;
  36. import java.awt.image.DataBuffer;
  37. import java.awt.image.ComponentColorModel;
  38. import java.awt.image.IndexColorModel;
  39. import java.awt.image.RenderedImage;
  40. import java.awt.image.SampleModel;
  41. import java.io.File;
  42. import java.io.InputStream;
  43. import java.io.IOException;
  44. import java.io.OutputStream;
  45. import java.util.Enumeration;
  46. import java.util.Hashtable;
  47. import java.util.Vector;
  48. /**
  49.  * An abstract class allowing the creation of image decoders and
  50.  * encoders.  Instances of <code>ImageCodec</code> may be registered.
  51.  * Once a codec has been registered, the format name associated with
  52.  * it may be used as the <code>name</code> parameter in the
  53.  * <code>createImageEncoder()</code> and <code>createImageDecoder()</code>
  54.  * methods.
  55.  *
  56.  * <p> Additionally, subclasses of <code>ImageCodec</code> 
  57.  * are able to perform recognition of their particular format,
  58.  * wither by inspection of a fixed-length file header or by
  59.  * arbitrary access to the source data stream.
  60.  *
  61.  * <p> Format recognition is performed by two variants of the
  62.  * <code>isFormatRecognized()</code> method.  Which variant should be
  63.  * called is determined by the output of the codec's
  64.  * <codec>getNumHeaderBytes()</code> method, which returns 0 if
  65.  * arbitrary access to the stream is required, and otherwise returns
  66.  * the number of header bytes required to recognize the format.
  67.  * Each subclass of <code>ImageCodec</code> needs to implement only
  68.  * one of the two variants.
  69.  *
  70.  * <p><b> This class is not a committed part of the JAI API.  It may
  71.  * be removed or changed in future releases of JAI.</b>
  72.  */
  73. public abstract class ImageCodec {
  74.     private static Hashtable codecs = new Hashtable();
  75.     /** Allow only subclasses to instantiate this class. */
  76.     protected ImageCodec() {}
  77.     /**
  78.      * Load the JPEG and PNM codecs.
  79.      */
  80.     static {
  81.         registerCodec(new BMPCodec());
  82.         registerCodec(new GIFCodec());
  83.         registerCodec(new FPXCodec());
  84.         registerCodec(new JPEGCodec());
  85.         registerCodec(new PNGCodec());
  86.         registerCodec(new PNMCodec());
  87.         registerCodec(new TIFFCodec());
  88.     }
  89.     /**
  90.      * Returns the <code>ImageCodec</code> associated with the given
  91.      * name.  <code>null</code> is returned if no codec is registered
  92.      * with the given name.  Case is not significant.
  93.      *
  94.      * @param name The name associated with the codec.
  95.      * @return The associated <code>ImageCodec</code>, or <code>null</code>.
  96.      */
  97.     public static ImageCodec getCodec(String name) {
  98.         return (ImageCodec)codecs.get(name.toLowerCase());
  99.     }
  100.     /**
  101.      * Associates an <code>ImageCodec</code> with its format name, as
  102.      * determined by its <code>getFormatName()</code> method.  Case is
  103.      * not significant.  Any codec previously associated with the name
  104.      * is discarded.
  105.      *
  106.      * @param codec The <code>ImageCodec</code> object to be registered.
  107.      */
  108.     public static void registerCodec(ImageCodec codec) {
  109.         codecs.put(codec.getFormatName().toLowerCase(), codec);
  110.     }
  111.     /**
  112.      * Unregisters the <code>ImageCodec</code> object currently
  113.      * responsible for handling the named format.  Case is not
  114.      * significant.
  115.      *
  116.      * @param name The name associated with the codec to be removed.
  117.      */
  118.     public static void unregisterCodec(String name) {
  119.         codecs.remove(name.toLowerCase());
  120.     }
  121.     /**
  122.      * Returns an <code>Enumeration</code> of all regstered 
  123.      * <code>ImageCodec</code> objects.
  124.      */
  125.     public static Enumeration getCodecs() {
  126.         return codecs.elements();
  127.     }
  128.     /**
  129.      * Returns an <code>ImageEncoder</code> object suitable for
  130.      * encoding to the supplied <code>OutputStream</code>, using the
  131.      * supplied <code>ImageEncoderParam</code> object.
  132.      *
  133.      * @param name The name associated with the codec.
  134.      * @param dst An <code>OutputStream</code> to write to.
  135.      * @param param An instance of <code>ImageEncoderParam</code> suitable
  136.      *        for use with the named codec, or <code>null</code>.
  137.      * @return An instance of <code>ImageEncoder</code>, or <code>null</code>.
  138.      */
  139.     public static ImageEncoder createImageEncoder(String name,
  140.                                                   OutputStream dst,
  141.                                                   ImageEncodeParam param) {
  142.         ImageCodec codec = getCodec(name);
  143.         if (codec == null) {
  144.             return null;
  145.         }
  146.         return codec.createImageEncoder(dst, param);
  147.     }
  148.     /**
  149.      * Returns an <code>ImageDecoder</code> object suitable for
  150.      * decoding from the supplied <code>InputStream</code>, using the
  151.      * supplied <code>ImageDecodeParam</code> object.
  152.      *
  153.      * @param name The name associated with the codec.
  154.      * @param src An <code>InputStream</code> to read from.
  155.      * @param param An instance of <code>ImageDecodeParam</code> suitable
  156.      *        for use with the named codec, or <code>null</code>.
  157.      * @return An instance of <code>ImageDecoder</code>, or <code>null</code>.
  158.      */
  159.     public static ImageDecoder createImageDecoder(String name,
  160.                                                   InputStream src,
  161.                                                   ImageDecodeParam param) {
  162.         ImageCodec codec = getCodec(name);
  163.         if (codec == null) {
  164.             return null;
  165.         }
  166.         return codec.createImageDecoder(src, param);
  167.     }
  168.     /**
  169.      * Returns an <code>ImageDecoder</code> object suitable for
  170.      * decoding from the supplied <code>File</code>, using the
  171.      * supplied <code>ImageDecodeParam</code> object.
  172.      *
  173.      * @param name The name associated with the codec.
  174.      * @param src A <code>File</code> to read from.
  175.      * @param param An instance of <code>ImageDecodeParam</code> suitable
  176.      *        for use with the named codec, or <code>null</code>.
  177.      * @return An instance of <code>ImageDecoder</code>, or <code>null</code>.
  178.      */
  179.     public static ImageDecoder createImageDecoder(String name,
  180.                                                   File src,
  181.                                                   ImageDecodeParam param)
  182.         throws IOException {
  183.         ImageCodec codec = getCodec(name);
  184.         if (codec == null) {
  185.             return null;
  186.         }
  187.         return codec.createImageDecoder(src, param);
  188.     }
  189.     /**
  190.      * Returns an <code>ImageDecoder</code> object suitable for
  191.      * decoding from the supplied <code>SeekableStream</code>, using the
  192.      * supplied <code>ImageDecodeParam</code> object.
  193.      *
  194.      * @param name The name associated with the codec.
  195.      * @param src A <code>SeekableStream</code> to read from.
  196.      * @param param An instance of <code>ImageDecodeParam</code> suitable
  197.      *        for use with the named codec, or <code>null</code>.
  198.      * @return An instance of <code>ImageDecoder</code>, or <code>null</code>.
  199.      */
  200.     public static ImageDecoder createImageDecoder(String name,
  201.                                                   SeekableStream src,
  202.                                                   ImageDecodeParam param) {
  203.         ImageCodec codec = getCodec(name);
  204.         if (codec == null) {
  205.             return null;
  206.         }
  207.         return codec.createImageDecoder(src, param);
  208.     }
  209.     private static String[] vectorToStrings(Vector nameVec) {
  210.         int count = nameVec.size();
  211.         String[] names = new String[count];
  212.         for (int i = 0; i < count; i++) {
  213.             names[i] = (String)nameVec.elementAt(i);
  214.         }
  215.         return names;
  216.     }
  217.     /**
  218.      * Returns an array of <code>String</code>s indicating the names
  219.      * of registered <code>ImageCodec</code>s that may be appropriate
  220.      * for reading the given <code>SeekableStream</code>.
  221.      *
  222.      * <p> If the <code>src</code> <code>SeekableStream</code> does
  223.      * not support seeking backwards (that is, its
  224.      * <code>canSeekBackwards()</code> method returns
  225.      * <code>false</code>) then only <code>FormatRecognizer</code>s
  226.      * that require only a fixed-length header will be checked.
  227.      *
  228.      * <p> If the <code>src</code> stream does not support seeking
  229.      * backwards, it must support marking, as determined by its 
  230.      * <code>markSupported()</code> method.
  231.      *
  232.      * @param src A <code>SeekableStream</code> which optionally supports
  233.      *        seeking backwards.
  234.      * @return An array of <code>String</code>s.
  235.      *
  236.      * @throws IllegalArgumentException if <code>src</code> supports
  237.      *         neither seeking backwards nor marking.
  238.      */
  239.     public static String[] getDecoderNames(SeekableStream src) {
  240.         if (!src.canSeekBackwards() && !src.markSupported()) {
  241.             throw new IllegalArgumentException(JaiI18N.getString("ImageCodec2"));
  242.         }
  243.         
  244.         Enumeration enum = codecs.elements();
  245.         Vector nameVec = new Vector();
  246.         String opName = null;
  247.         while (enum.hasMoreElements()) {
  248.             ImageCodec codec = (ImageCodec)enum.nextElement();
  249.             int bytesNeeded = codec.getNumHeaderBytes();
  250.             if ((bytesNeeded == 0) && !src.canSeekBackwards()) {
  251.                 continue;
  252.             }
  253.             try {
  254.                 if (bytesNeeded > 0) {
  255.                     src.mark(bytesNeeded);
  256.                     byte[] header = new byte[bytesNeeded];
  257.                     src.readFully(header);
  258.                     src.reset();
  259.                     if (codec.isFormatRecognized(header)) {
  260.                         nameVec.add(codec.getFormatName());
  261.                     }
  262.                 } else {
  263.                     long pointer = src.getFilePointer();
  264.                     src.seek(0L);
  265.                     if (codec.isFormatRecognized(src)) {
  266.                         nameVec.add(codec.getFormatName());
  267.                     }
  268.                     src.seek(pointer);
  269.                 }
  270.             } catch (IOException e) {
  271.                 e.printStackTrace();
  272.             }
  273.         }
  274.         return vectorToStrings(nameVec);
  275.     }
  276.     /**
  277.      * Returns an array of <code>String</code>s indicating the names
  278.      * of registered <code>ImageCodec</code>s that may be appropriate
  279.      * for writing the given <code>RenderedImage</code>, using the
  280.      * optional <code>ImageEncodeParam</code>, which may be
  281.      * <code>null</code>.
  282.      *
  283.      * @param im A <code>RenderedImage</code> to be encodec.
  284.      * @param param An <code>ImageEncodeParam</code>, or null.
  285.      * @return An array of <code>String</code>s.
  286.      */
  287.     public static String[] getEncoderNames(RenderedImage im,
  288.                                            ImageEncodeParam param) {
  289.         Enumeration enum = codecs.elements();
  290.         Vector nameVec = new Vector();
  291.         String opName = null;
  292.         while (enum.hasMoreElements()) {
  293.             ImageCodec codec = (ImageCodec)enum.nextElement();
  294.             if (codec.canEncodeImage(im, param)) {
  295.                 nameVec.add(codec.getFormatName());
  296.             }
  297.         }
  298.         return vectorToStrings(nameVec);
  299.     }
  300.     /**
  301.      * Returns the name of this image format.
  302.      *
  303.      * @return A <code>String</code> containing the name of the
  304.      *         image format supported by this codec.
  305.      */
  306.     public abstract String getFormatName();
  307.     /** 
  308.      * Returns the number of bytes of header needed to recognize the
  309.      * format, or 0 if an arbitrary number of bytes may be needed.
  310.      * The default implementation returns 0.
  311.      *
  312.      * <p> The return value must be a constant for all instances of
  313.      * each particular subclass of <code>ImageCodec</code>.
  314.      *
  315.      * <p> Although it is legal to always return 0, in some cases
  316.      * processing may be more efficient if the number of bytes needed
  317.      * is known in advance.
  318.      */
  319.     public int getNumHeaderBytes() {
  320.         return 0;
  321.     }
  322.     /**
  323.      * Returns <code>true</code> if the format is recognized in the
  324.      * initial portion of a stream.  The header will be passed in as a
  325.      * <code>byte</code> array of length <code>getNumHeaderBytes()</code>.
  326.      * This method should be called only if <code>getNumHeaderBytes()</code>
  327.      * returns a value greater than 0.
  328.      *
  329.      * <p> The default implementation throws an exception to indicate
  330.      * that it should never be called.
  331.      *
  332.      * @param header An array of <code>byte</code>s containing the input
  333.      *        stream header.
  334.      * @return <code>true</code> if the format is recognized.
  335.      */
  336.     public boolean isFormatRecognized(byte[] header) {
  337.         throw new RuntimeException(JaiI18N.getString("ImageCodec0"));
  338.     }
  339.     /**
  340.      * Returns <code>true</code> if the format is recognized in the
  341.      * input data stream.  This method should be called only if
  342.      * <code>getNumHeaderBytesNeeded()</code> returns 0.
  343.      *
  344.      * <p> The source <code>SeekableStream</code> is guaranteed to
  345.      * support seeking backwards, and should be seeked to 0 prior
  346.      * to calling this method.
  347.      *
  348.      * <p> The default implementation throws an exception to indicate
  349.      * that it should never be called.
  350.      *
  351.      * @param src A <code>SeekableStream</code> containing the input
  352.      *        data.
  353.      * @return <code>true</code> if the format is recognized.
  354.      */
  355.     public boolean isFormatRecognized(SeekableStream src) throws IOException {
  356.         throw new RuntimeException(JaiI18N.getString("ImageCodec1"));
  357.     }
  358.     /**
  359.      * Returns a <code>Class</code> object indicating the proper
  360.      * subclass of <code>ImageEncodeParam</code> to be used with this
  361.      * <code>ImageCodec</code>.  If encoding is not supported by this
  362.      * codec, <code>null</code> is returned.  If encoding is
  363.      * supported, but a parameter object is not used during encoding,
  364.      * Object.class is returned to signal this fact.
  365.      */
  366.     protected abstract Class getEncodeParamClass();
  367.     /**
  368.      * Returns a <code>Class</code> object indicating the proper
  369.      * subclass of <code>ImageDecodeParam</code> to be used with this
  370.      * <code>ImageCodec</code>.  If encoding is not supported by this
  371.      * codec, <code>null</code> is returned.  If decoding is
  372.      * supported, but a parameter object is not used during decoding,
  373.      * Object.class is returned to signal this fact.
  374.      */
  375.     protected abstract Class getDecodeParamClass();
  376.     /**
  377.      * In a concrete subclass of <code>ImageCodec</code>, returns an
  378.      * implementation of the <code>ImageEncoder</code> interface
  379.      * appropriate for that codec.
  380.      *
  381.      * @param dst An <code>OutputStream</code> to write to.
  382.      * @param param An instance of <code>ImageEncoderParam</code>
  383.      *        suitable for use with the <code>ImageCodec</code>
  384.      *        subclass, or <code>null</code>.
  385.      * @return An instance of <code>ImageEncoder</code>.
  386.      */
  387.     protected abstract ImageEncoder createImageEncoder(OutputStream dst,
  388.                                                        ImageEncodeParam param);
  389.     
  390.     /**
  391.      * Returns <code>true</code> if the given image and encoder param
  392.      * object are suitable for encoding by this <code>ImageCodec</code>.
  393.      * For example, some codecs may only deal with images with a certain
  394.      * number of bands; an attempt to encode an image with an unsupported
  395.      * number of bands will fail.
  396.      *
  397.      * @param im a RenderedImage whose ability to be encoded is to be
  398.      *        determined.
  399.      * @param param a suitable <code>ImageEncodeParam</code> object,
  400.      *        or <code>null</code>.
  401.      */
  402.     public abstract boolean canEncodeImage(RenderedImage im,
  403.                                            ImageEncodeParam param);
  404.     /**
  405.      * Returns an implementation of the <code>ImageDecoder</code>
  406.      * interface appropriate for that codec.  Subclasses of
  407.      * <code>ImageCodec</code> may override this method if they wish
  408.      * to accept data directly from an <code>InputStream</code>;
  409.      * otherwise, this method will convert the source into a
  410.      * backwards-seekable <code>SeekableStream</code> and call the
  411.      * appropriate version of <code>createImageDecoder</code> for that
  412.      * data type.
  413.      *
  414.      * <p> Instances of <code>ImageCodec</code> that do not require
  415.      * the ability to seek backwards in their source
  416.      * <code>SeekableStream</code> should override this method in
  417.      * order to avoid the default call to
  418.      * <code>SeekableStream.wrapInputStream(src, true)</code>.
  419.      *
  420.      * @param dst An <code>InputStream</code> to read from.
  421.      * @param param An instance of <code>ImageDecodeParam</code>
  422.      *        suitable for use with the <code>ImageCodec</code>
  423.      *        subclass, or <code>null</code>.
  424.      * @return An instance of <code>ImageDecoder</code>.
  425.      */
  426.     protected ImageDecoder createImageDecoder(InputStream src,
  427.                                               ImageDecodeParam param) {
  428.         SeekableStream stream = SeekableStream.wrapInputStream(src, true);
  429.         return createImageDecoder(stream, param);
  430.     }
  431.     /**
  432.      * Returns an implementation of the <code>ImageDecoder</code>
  433.      * interface appropriate for that codec.  Subclasses of 
  434.      * <code>ImageCodec</code> may override this method if they wish
  435.      * to accept data directly from a <code>File</code>;
  436.      * otherwise, this method will convert the source into a
  437.      * <code>SeekableStream</code> and call the appropriate
  438.      * version of <code>createImageDecoder</code> for that data type.
  439.      *
  440.      * @param dst A <code>File</code> to read from.
  441.      * @param param An instance of <code>ImageDecodeParam</code>
  442.      *        suitable for use with the <code>ImageCodec</code>
  443.      *        subclass, or <code>null</code>.
  444.      * @return An instance of <code>ImageDecoder</code>.
  445.      */
  446.     protected ImageDecoder createImageDecoder(File src,
  447.                                               ImageDecodeParam param) 
  448.         throws IOException {
  449.         return createImageDecoder(new FileSeekableStream(src), param);
  450.     }
  451.     /**
  452.      * In a concrete subclass of <code>ImageCodec</code>, returns an
  453.      * implementation of the <code>ImageDecoder</code> interface
  454.      * appropriate for that codec.
  455.      *
  456.      * @param dst A <code>SeekableStream</code> to read from.
  457.      * @param param An instance of <code>ImageDecodeParam</code>
  458.      *        suitable for use with the <code>ImageCodec</code>
  459.      *        subclass, or <code>null</code>.
  460.      * @return An instance of <code>ImageDecoder</code>.
  461.      */
  462.     protected abstract ImageDecoder createImageDecoder(SeekableStream src,
  463.                                                        ImageDecodeParam param);
  464.     // ColorModel utility functions
  465.     private static final byte[][] grayIndexCmaps = {
  466.         null,
  467.         // 1 bit
  468.         { (byte)0x00, (byte)0xff },
  469.         // 2 bits
  470.         { (byte)0x00, (byte)0x55, (byte)0xaa, (byte)0xff },
  471.         null,
  472.         // 4 bits
  473.         { (byte)0x00, (byte)0x11, (byte)0x22, (byte)0x33,
  474.           (byte)0x44, (byte)0x55, (byte)0x66, (byte)0x77,
  475.           (byte)0x88, (byte)0x99, (byte)0xaa, (byte)0xbb,
  476.           (byte)0xcc, (byte)0xdd, (byte)0xee, (byte)0xff }
  477.     };
  478.     /**
  479.      * A convenience methods to create an instance of
  480.      * <code>IndexColorModel</code> suitable for the given 1-banded
  481.      * <code>SampleModel</code>.
  482.      *
  483.      * @param sm a 1-banded <code>SampleModel</code>.
  484.      * @param blackIsZero <code>true</code> if the gray ramp should
  485.      *        go from black to white, <code>false</code>otherwise.
  486.      */
  487.     public static ColorModel createGrayIndexColorModel(SampleModel sm,
  488.                                                        boolean blackIsZero) {
  489.         if (sm.getNumBands() != 1) {
  490.             throw new IllegalArgumentException();
  491.         }
  492.         int sampleSize = sm.getSampleSize(0);
  493.         byte[] cmap = null;
  494.         if (sampleSize < 8) {
  495.             cmap = grayIndexCmaps[sampleSize];
  496.             if (!blackIsZero) {
  497.                 int length = cmap.length;
  498.                 byte[] newCmap = new byte[length];
  499.                 for (int i = 0; i < length; i++) {
  500.                     newCmap[i] = cmap[length - i - 1];
  501.                 }
  502.                 cmap = newCmap;
  503.             }
  504.         } else {
  505.             cmap = new byte[256];
  506.             if (blackIsZero) {
  507.                 for (int i = 0; i < 256; i++) {
  508.                     cmap[i] = (byte)i;
  509.                 }
  510.             } else {
  511.                 for (int i = 0; i < 256; i++) {
  512.                     cmap[i] = (byte)(255 - i);
  513.                 }
  514.             }
  515.         }
  516.         return new IndexColorModel(sampleSize, cmap.length,
  517.                                    cmap, cmap, cmap);
  518.     }
  519.     private static final int[] GrayBits8 = { 8 };
  520.     private static final ComponentColorModel colorModelGray8 =
  521.         new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_GRAY),
  522.                                 GrayBits8, false, false,
  523.                                 Transparency.OPAQUE,
  524.                                 DataBuffer.TYPE_BYTE);
  525.     private static final int[] GrayAlphaBits8 = { 8, 8 };
  526.     private static final ComponentColorModel colorModelGrayAlpha8 =
  527.         new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_GRAY),
  528.                                 GrayAlphaBits8, true, false,
  529.                                 Transparency.TRANSLUCENT,
  530.                                 DataBuffer.TYPE_BYTE);
  531.     private static final int[] GrayBits16 = { 16 };
  532.     private static final ComponentColorModel colorModelGray16 =
  533.         new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_GRAY),
  534.                                 GrayBits16, false, false,
  535.                                 Transparency.OPAQUE,
  536.                                 DataBuffer.TYPE_USHORT);
  537.     private static final int[] GrayAlphaBits16 = { 16, 16 };
  538.     private static final ComponentColorModel colorModelGrayAlpha16 =
  539.         new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_GRAY),
  540.                                 GrayAlphaBits16, true, false,
  541.                                 Transparency.TRANSLUCENT,
  542.                                 DataBuffer.TYPE_USHORT);
  543.     private static final int[] GrayBits32 = { 32 };
  544.     private static final ComponentColorModel colorModelGray32 =
  545.         new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_GRAY),
  546.                                 GrayBits32, false, false,
  547.                                 Transparency.OPAQUE,
  548.                                 DataBuffer.TYPE_INT);
  549.     private static final int[] GrayAlphaBits32 = { 32, 32 };
  550.     private static final ComponentColorModel colorModelGrayAlpha32 =
  551.         new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_GRAY),
  552.                                 GrayAlphaBits32, true, false,
  553.                                 Transparency.TRANSLUCENT,
  554.                                 DataBuffer.TYPE_INT);
  555.     private static final int[] RGBBits8 = { 8, 8, 8 };
  556.     private static final ComponentColorModel colorModelRGB8 =
  557.       new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB),
  558.                               RGBBits8, false, false,
  559.                               Transparency.OPAQUE,
  560.                               DataBuffer.TYPE_BYTE);
  561.     private static final int[] RGBABits8 = { 8, 8, 8, 8 };
  562.     private static final ComponentColorModel colorModelRGBA8 =
  563.       new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB),
  564.                               RGBABits8, true, false,
  565.                               Transparency.TRANSLUCENT,
  566.                               DataBuffer.TYPE_BYTE);
  567.     private static final int[] RGBBits16 = { 16, 16, 16 };
  568.     private static final ComponentColorModel colorModelRGB16 =
  569.       new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB),
  570.                               RGBBits16, false, false,
  571.                               Transparency.OPAQUE,
  572.                               DataBuffer.TYPE_USHORT);
  573.     private static final int[] RGBABits16 = { 16, 16, 16, 16 };
  574.     private static final ComponentColorModel colorModelRGBA16 =
  575.       new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB),
  576.                               RGBABits16, true, false,
  577.                               Transparency.TRANSLUCENT,
  578.                               DataBuffer.TYPE_USHORT);
  579.     private static final int[] RGBBits32 = { 32, 32, 32 };
  580.     private static final ComponentColorModel colorModelRGB32 =
  581.       new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB),
  582.                               RGBBits32, false, false,
  583.                               Transparency.OPAQUE,
  584.                               DataBuffer.TYPE_INT);
  585.     private static final int[] RGBABits32 = { 32, 32, 32, 32 };
  586.     private static final ComponentColorModel colorModelRGBA32 =
  587.       new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB),
  588.                               RGBABits32, true, false,
  589.                               Transparency.TRANSLUCENT,
  590.                               DataBuffer.TYPE_INT);
  591.     /**
  592.      * A convenience method to create an instance of
  593.      * <code>ComponentColorModel</code> suitable for use with the
  594.      * given <code>SampleModel</code>.  The <code>SampleModel</code>
  595.      * should have a data type of <code>DataBuffer.TYPE_BYTE</code>,
  596.      * <code>TYPE_USHORT</code>, or <code>TYPE_INT</code> and between
  597.      * 1 and 4 bands.  Depending on the number of bands of the
  598.      * <code>SampleModel</code>, either a gray, gray+alpha, rgb, or
  599.      * rgb+alpha <code>ColorModel</code> is returned.
  600.      */
  601.     public static ColorModel createComponentColorModel(SampleModel sm) {
  602.         int type = sm.getDataType();
  603.         int bands = sm.getNumBands();
  604.         ComponentColorModel cm = null;
  605.         if (type == DataBuffer.TYPE_BYTE) {
  606.             switch (bands) {
  607.             case 1:
  608.                 cm = colorModelGray8;
  609.                 break;
  610.             case 2:
  611.                 cm = colorModelGrayAlpha8;
  612.                 break;
  613.             case 3:
  614.                 cm = colorModelRGB8;
  615.                 break;
  616.             case 4:
  617.                 cm = colorModelRGBA8;
  618.                 break;
  619.             }
  620.         } else if (type == DataBuffer.TYPE_USHORT) {
  621.             switch (bands) {
  622.             case 1:
  623.                 cm = colorModelGray16;
  624.                 break;
  625.             case 2:
  626.                 cm = colorModelGrayAlpha16;
  627.                 break;
  628.             case 3:
  629.                 cm = colorModelRGB16;
  630.                 break;
  631.             case 4:
  632.                 cm = colorModelRGBA16;
  633.                 break;
  634.             }
  635.         } else if (type == DataBuffer.TYPE_INT) {
  636.             switch (bands) {
  637.             case 1:
  638.                 cm = colorModelGray32;
  639.                 break;
  640.             case 2:
  641.                 cm = colorModelGrayAlpha32;
  642.                 break;
  643.             case 3:
  644.                 cm = colorModelRGB32;
  645.                 break;
  646.             case 4:
  647.                 cm = colorModelRGBA32;
  648.                 break;
  649.             }
  650.         } else if (type == DataBuffer.TYPE_FLOAT &&
  651.                    bands >= 1 && bands <= 4) {
  652.             ColorSpace cs = bands <= 2 ?
  653.                 ColorSpace.getInstance(ColorSpace.CS_GRAY) :
  654.                 ColorSpace.getInstance(ColorSpace.CS_sRGB);
  655.             boolean hasAlpha = bands % 2 == 0;
  656.             cm = new FloatDoubleColorModel(cs, hasAlpha, false,
  657.                                            hasAlpha ?
  658.                                            Transparency.TRANSLUCENT :
  659.                                            Transparency.OPAQUE,
  660.                                            DataBuffer.TYPE_FLOAT);
  661.         }
  662.         return cm;
  663.     }
  664. }