< prev index next >

src/java.desktop/share/classes/javax/imageio/ImageTypeSpecifier.java

Print this page




  29 import java.awt.Transparency;
  30 import java.awt.image.BandedSampleModel;
  31 import java.awt.image.BufferedImage;
  32 import java.awt.image.ColorModel;
  33 import java.awt.color.ColorSpace;
  34 import java.awt.image.IndexColorModel;
  35 import java.awt.image.ComponentColorModel;
  36 import java.awt.image.DataBuffer;
  37 import java.awt.image.DirectColorModel;
  38 import java.awt.image.MultiPixelPackedSampleModel;
  39 import java.awt.image.PixelInterleavedSampleModel;
  40 import java.awt.image.SinglePixelPackedSampleModel;
  41 import java.awt.image.Raster;
  42 import java.awt.image.RenderedImage;
  43 import java.awt.image.SampleModel;
  44 import java.awt.image.WritableRaster;
  45 import java.util.Hashtable;
  46 
  47 /**
  48  * A class that allows the format of an image (in particular, its
  49  * <code>SampleModel</code> and <code>ColorModel</code>) to be
  50  * specified in a convenient manner.
  51  *
  52  */
  53 public class ImageTypeSpecifier {
  54 
  55     /**
  56      * The <code>ColorModel</code> to be used as a prototype.
  57      */
  58     protected ColorModel colorModel;
  59 
  60     /**
  61      * A <code>SampleModel</code> to be used as a prototype.
  62      */
  63     protected SampleModel sampleModel;
  64 
  65     /**
  66      * Cached specifiers for all of the standard
  67      * <code>BufferedImage</code> types.
  68      */
  69     private static ImageTypeSpecifier[] BISpecifier;
  70     private static ColorSpace sRGB;
  71     // Initialize the standard specifiers
  72     static {
  73         sRGB = ColorSpace.getInstance(ColorSpace.CS_sRGB);
  74 
  75         BISpecifier =
  76             new ImageTypeSpecifier[BufferedImage.TYPE_BYTE_INDEXED + 1];
  77     }
  78 
  79     /**
  80      * A constructor to be used by inner subclasses only.
  81      */
  82     private ImageTypeSpecifier() {}
  83 
  84     /**
  85      * Constructs an <code>ImageTypeSpecifier</code> directly
  86      * from a <code>ColorModel</code> and a <code>SampleModel</code>.
  87      * It is the caller's responsibility to supply compatible
  88      * parameters.
  89      *
  90      * @param colorModel a <code>ColorModel</code>.
  91      * @param sampleModel a <code>SampleModel</code>.
  92      *
  93      * @exception IllegalArgumentException if either parameter is
  94      * <code>null</code>.
  95      * @exception IllegalArgumentException if <code>sampleModel</code>
  96      * is not compatible with <code>colorModel</code>.
  97      */
  98     public ImageTypeSpecifier(ColorModel colorModel, SampleModel sampleModel) {
  99         if (colorModel == null) {
 100             throw new IllegalArgumentException("colorModel == null!");
 101         }
 102         if (sampleModel == null) {
 103             throw new IllegalArgumentException("sampleModel == null!");
 104         }
 105         if (!colorModel.isCompatibleSampleModel(sampleModel)) {
 106             throw new IllegalArgumentException
 107                 ("sampleModel is incompatible with colorModel!");
 108         }
 109         this.colorModel = colorModel;
 110         this.sampleModel = sampleModel;
 111     }
 112 
 113     /**
 114      * Constructs an <code>ImageTypeSpecifier</code> from a
 115      * <code>RenderedImage</code>.  If a <code>BufferedImage</code> is
 116      * being used, one of the factory methods
 117      * <code>createFromRenderedImage</code> or
 118      * <code>createFromBufferedImageType</code> should be used instead in
 119      * order to get a more accurate result.
 120      *
 121      * @param image a <code>RenderedImage</code>.
 122      *
 123      * @exception IllegalArgumentException if the argument is
 124      * <code>null</code>.
 125      */
 126     public ImageTypeSpecifier(RenderedImage image) {
 127         if (image == null) {
 128             throw new IllegalArgumentException("image == null!");
 129         }
 130         colorModel = image.getColorModel();
 131         sampleModel = image.getSampleModel();
 132     }
 133 
 134     // Packed
 135 
 136     static class Packed extends ImageTypeSpecifier {
 137         ColorSpace colorSpace;
 138         int redMask;
 139         int greenMask;
 140         int blueMask;
 141         int alphaMask;
 142         int transferType;
 143         boolean isAlphaPremultiplied;
 144 


 171             this.redMask = redMask;
 172             this.greenMask = greenMask;
 173             this.blueMask = blueMask;
 174             this.alphaMask = alphaMask;
 175             this.transferType = transferType;
 176             this.isAlphaPremultiplied = isAlphaPremultiplied;
 177 
 178             int bits = 32;
 179             this.colorModel =
 180                 new DirectColorModel(colorSpace,
 181                                      bits,
 182                                      redMask, greenMask, blueMask,
 183                                      alphaMask, isAlphaPremultiplied,
 184                                      transferType);
 185             this.sampleModel = colorModel.createCompatibleSampleModel(1, 1);
 186         }
 187     }
 188 
 189     /**
 190      * Returns a specifier for a packed image format that will use a
 191      * <code>DirectColorModel</code> and a packed
 192      * <code>SampleModel</code> to store each pixel packed into in a
 193      * single byte, short, or int.
 194      *
 195      * @param colorSpace the desired <code>ColorSpace</code>.
 196      * @param redMask a contiguous mask indicated the position of the
 197      * red channel.
 198      * @param greenMask a contiguous mask indicated the position of the
 199      * green channel.
 200      * @param blueMask a contiguous mask indicated the position of the
 201      * blue channel.
 202      * @param alphaMask a contiguous mask indicated the position of the
 203      * alpha channel.
 204      * @param transferType the desired <code>SampleModel</code> transfer type.
 205      * @param isAlphaPremultiplied <code>true</code> if the color channels
 206      * will be premultipled by the alpha channel.
 207      *
 208      * @return an <code>ImageTypeSpecifier</code> with the desired
 209      * characteristics.
 210      *
 211      * @exception IllegalArgumentException if <code>colorSpace</code>
 212      * is <code>null</code>.
 213      * @exception IllegalArgumentException if <code>colorSpace</code>
 214      * is not of type <code>TYPE_RGB</code>.
 215      * @exception IllegalArgumentException if no mask has at least 1
 216      * bit set.
 217      * @exception IllegalArgumentException if
 218      * <code>transferType</code> if not one of
 219      * <code>DataBuffer.TYPE_BYTE</code>,
 220      * <code>DataBuffer.TYPE_USHORT</code>, or
 221      * <code>DataBuffer.TYPE_INT</code>.
 222      */
 223     public static ImageTypeSpecifier
 224         createPacked(ColorSpace colorSpace,
 225                      int redMask,
 226                      int greenMask,
 227                      int blueMask,
 228                      int alphaMask, // 0 if no alpha
 229                      int transferType,
 230                      boolean isAlphaPremultiplied) {
 231         return new ImageTypeSpecifier.Packed(colorSpace,
 232                                              redMask,
 233                                              greenMask,
 234                                              blueMask,
 235                                              alphaMask, // 0 if no alpha
 236                                              transferType,
 237                                              isAlphaPremultiplied);
 238     }
 239 
 240     static ColorModel createComponentCM(ColorSpace colorSpace,
 241                                         int numBands,


 346 
 347             for (int i = 0; i < bandOffsets.length; i++) {
 348                 if (this.bandOffsets[i] != that.bandOffsets[i]) {
 349                     return false;
 350                 }
 351             }
 352 
 353             return true;
 354         }
 355 
 356         public int hashCode() {
 357             return (super.hashCode() +
 358                     (4 * bandOffsets.length) +
 359                     (25 * dataType) +
 360                     (hasAlpha ? 17 : 18));
 361         }
 362     }
 363 
 364     /**
 365      * Returns a specifier for an interleaved image format that will
 366      * use a <code>ComponentColorModel</code> and a
 367      * <code>PixelInterleavedSampleModel</code> to store each pixel
 368      * component in a separate byte, short, or int.
 369      *
 370      * @param colorSpace the desired <code>ColorSpace</code>.
 371      * @param bandOffsets an array of <code>int</code>s indicating the
 372      * offsets for each band.
 373      * @param dataType the desired data type, as one of the enumerations
 374      * from the <code>DataBuffer</code> class.
 375      * @param hasAlpha <code>true</code> if an alpha channel is desired.
 376      * @param isAlphaPremultiplied <code>true</code> if the color channels
 377      * will be premultipled by the alpha channel.
 378      *
 379      * @return an <code>ImageTypeSpecifier</code> with the desired
 380      * characteristics.
 381      *
 382      * @exception IllegalArgumentException if <code>colorSpace</code>
 383      * is <code>null</code>.
 384      * @exception IllegalArgumentException if <code>bandOffsets</code>
 385      * is <code>null</code>.
 386      * @exception IllegalArgumentException if <code>dataType</code> is
 387      * not one of the legal <code>DataBuffer.TYPE_*</code> constants.
 388      * @exception IllegalArgumentException if
 389      * <code>bandOffsets.length</code> does not equal the number of
 390      * color space components, plus 1 if <code>hasAlpha</code> is
 391      * <code>true</code>.
 392      */
 393     public static ImageTypeSpecifier
 394         createInterleaved(ColorSpace colorSpace,
 395                           int[] bandOffsets,
 396                           int dataType,
 397                           boolean hasAlpha,
 398                           boolean isAlphaPremultiplied) {
 399         return new ImageTypeSpecifier.Interleaved(colorSpace,
 400                                                   bandOffsets,
 401                                                   dataType,
 402                                                   hasAlpha,
 403                                                   isAlphaPremultiplied);
 404     }
 405 
 406     // Banded
 407 
 408     static class Banded extends ImageTypeSpecifier {
 409         ColorSpace colorSpace;
 410         int[] bankIndices;
 411         int[] bandOffsets;


 498             for (int i = 0; i < bandOffsets.length; i++) {
 499                 if (this.bandOffsets[i] != that.bandOffsets[i]) {
 500                     return false;
 501                 }
 502             }
 503 
 504             return true;
 505         }
 506 
 507         public int hashCode() {
 508             return (super.hashCode() +
 509                     (3 * bandOffsets.length) +
 510                     (7 * bankIndices.length) +
 511                     (21 * dataType) +
 512                     (hasAlpha ? 19 : 29));
 513         }
 514     }
 515 
 516     /**
 517      * Returns a specifier for a banded image format that will use a
 518      * <code>ComponentColorModel</code> and a
 519      * <code>BandedSampleModel</code> to store each channel in a
 520      * separate array.
 521      *
 522      * @param colorSpace the desired <code>ColorSpace</code>.
 523      * @param bankIndices an array of <code>int</code>s indicating the
 524      * bank in which each band will be stored.
 525      * @param bandOffsets an array of <code>int</code>s indicating the
 526      * starting offset of each band within its bank.
 527      * @param dataType the desired data type, as one of the enumerations
 528      * from the <code>DataBuffer</code> class.
 529      * @param hasAlpha <code>true</code> if an alpha channel is desired.
 530      * @param isAlphaPremultiplied <code>true</code> if the color channels
 531      * will be premultipled by the alpha channel.
 532      *
 533      * @return an <code>ImageTypeSpecifier</code> with the desired
 534      * characteristics.
 535      *
 536      * @exception IllegalArgumentException if <code>colorSpace</code>
 537      * is <code>null</code>.
 538      * @exception IllegalArgumentException if <code>bankIndices</code>
 539      * is <code>null</code>.
 540      * @exception IllegalArgumentException if <code>bandOffsets</code>
 541      * is <code>null</code>.
 542      * @exception IllegalArgumentException if the lengths of
 543      * <code>bankIndices</code> and <code>bandOffsets</code> differ.
 544      * @exception IllegalArgumentException if
 545      * <code>bandOffsets.length</code> does not equal the number of
 546      * color space components, plus 1 if <code>hasAlpha</code> is
 547      * <code>true</code>.
 548      * @exception IllegalArgumentException if <code>dataType</code> is
 549      * not one of the legal <code>DataBuffer.TYPE_*</code> constants.
 550      */
 551     public static ImageTypeSpecifier
 552         createBanded(ColorSpace colorSpace,
 553                      int[] bankIndices,
 554                      int[] bandOffsets,
 555                      int dataType,
 556                      boolean hasAlpha,
 557                      boolean isAlphaPremultiplied) {
 558         return new ImageTypeSpecifier.Banded(colorSpace,
 559                                              bankIndices,
 560                                              bandOffsets,
 561                                              dataType,
 562                                              hasAlpha,
 563                                              isAlphaPremultiplied);
 564     }
 565 
 566     // Grayscale
 567 
 568     static class Grayscale extends ImageTypeSpecifier {
 569         int bits;


 645                 byte[] arr = new byte[numEntries];
 646                 for (int i = 0; i < numEntries; i++) {
 647                     arr[i] = (byte)(i*255/(numEntries - 1));
 648                 }
 649                 this.colorModel =
 650                     new IndexColorModel(bits, numEntries, arr, arr, arr);
 651 
 652                 this.sampleModel =
 653                     new MultiPixelPackedSampleModel(dataType, 1, 1, bits);
 654             }
 655         }
 656     }
 657 
 658     /**
 659      * Returns a specifier for a grayscale image format that will pack
 660      * pixels of the given bit depth into array elements of
 661      * the specified data type.
 662      *
 663      * @param bits the number of bits per gray value (1, 2, 4, 8, or 16).
 664      * @param dataType the desired data type, as one of the enumerations
 665      * from the <code>DataBuffer</code> class.
 666      * @param isSigned <code>true</code> if negative values are to
 667      * be represented.
 668      *
 669      * @return an <code>ImageTypeSpecifier</code> with the desired
 670      * characteristics.
 671      *
 672      * @exception IllegalArgumentException if <code>bits</code> is
 673      * not one of 1, 2, 4, 8, or 16.
 674      * @exception IllegalArgumentException if <code>dataType</code> is
 675      * not one of <code>DataBuffer.TYPE_BYTE</code>,
 676      * <code>DataBuffer.TYPE_SHORT</code>, or
 677      * <code>DataBuffer.TYPE_USHORT</code>.
 678      * @exception IllegalArgumentException if <code>bits</code> is
 679      * larger than the bit size of the given <code>dataType</code>.
 680      */
 681     public static ImageTypeSpecifier
 682         createGrayscale(int bits,
 683                         int dataType,
 684                         boolean isSigned) {
 685         return new ImageTypeSpecifier.Grayscale(bits,
 686                                                 dataType,
 687                                                 isSigned,
 688                                                 false,
 689                                                 false);
 690     }
 691 
 692     /**
 693      * Returns a specifier for a grayscale plus alpha image format
 694      * that will pack pixels of the given bit depth into array
 695      * elements of the specified data type.
 696      *
 697      * @param bits the number of bits per gray value (1, 2, 4, 8, or 16).
 698      * @param dataType the desired data type, as one of the enumerations
 699      * from the <code>DataBuffer</code> class.
 700      * @param isSigned <code>true</code> if negative values are to
 701      * be represented.
 702      * @param isAlphaPremultiplied <code>true</code> if the luminance channel
 703      * will be premultipled by the alpha channel.
 704      *
 705      * @return an <code>ImageTypeSpecifier</code> with the desired
 706      * characteristics.
 707      *
 708      * @exception IllegalArgumentException if <code>bits</code> is
 709      * not one of 1, 2, 4, 8, or 16.
 710      * @exception IllegalArgumentException if <code>dataType</code> is
 711      * not one of <code>DataBuffer.TYPE_BYTE</code>,
 712      * <code>DataBuffer.TYPE_SHORT</code>, or
 713      * <code>DataBuffer.TYPE_USHORT</code>.
 714      * @exception IllegalArgumentException if <code>bits</code> is
 715      * larger than the bit size of the given <code>dataType</code>.
 716      */
 717     public static ImageTypeSpecifier
 718         createGrayscale(int bits,
 719                         int dataType,
 720                         boolean isSigned,
 721                         boolean isAlphaPremultiplied) {
 722         return new ImageTypeSpecifier.Grayscale(bits,
 723                                                 dataType,
 724                                                 isSigned,
 725                                                 true,
 726                                                 isAlphaPremultiplied);
 727     }
 728 
 729     // Indexed
 730 
 731     static class Indexed extends ImageTypeSpecifier {
 732         byte[] redLUT;
 733         byte[] greenLUT;
 734         byte[] blueLUT;
 735         byte[] alphaLUT = null;


 797                 (bits == 16 &&
 798                  (dataType == DataBuffer.TYPE_SHORT ||
 799                   dataType == DataBuffer.TYPE_USHORT))) {
 800                 int[] bandOffsets = { 0 };
 801                 this.sampleModel =
 802                     new PixelInterleavedSampleModel(dataType,
 803                                                     1, 1, 1, 1,
 804                                                     bandOffsets);
 805             } else {
 806                 this.sampleModel =
 807                     new MultiPixelPackedSampleModel(dataType, 1, 1, bits);
 808             }
 809         }
 810     }
 811 
 812     /**
 813      * Returns a specifier for an indexed-color image format that will pack
 814      * index values of the given bit depth into array elements of
 815      * the specified data type.
 816      *
 817      * @param redLUT an array of <code>byte</code>s containing
 818      * the red values for each index.
 819      * @param greenLUT an array of <code>byte</code>s containing * the
 820      *  green values for each index.
 821      * @param blueLUT an array of <code>byte</code>s containing the
 822      * blue values for each index.
 823      * @param alphaLUT an array of <code>byte</code>s containing the
 824      * alpha values for each index, or <code>null</code> to create a
 825      * fully opaque LUT.
 826      * @param bits the number of bits in each index.
 827      * @param dataType the desired output type, as one of the enumerations
 828      * from the <code>DataBuffer</code> class.
 829      *
 830      * @return an <code>ImageTypeSpecifier</code> with the desired
 831      * characteristics.
 832      *
 833      * @exception IllegalArgumentException if <code>redLUT</code> is
 834      * <code>null</code>.
 835      * @exception IllegalArgumentException if <code>greenLUT</code> is
 836      * <code>null</code>.
 837      * @exception IllegalArgumentException if <code>blueLUT</code> is
 838      * <code>null</code>.
 839      * @exception IllegalArgumentException if <code>bits</code> is
 840      * not one of 1, 2, 4, 8, or 16.
 841      * @exception IllegalArgumentException if the
 842      * non-<code>null</code> LUT parameters do not have lengths of
 843      * exactly {@code 1 << bits}.
 844      * @exception IllegalArgumentException if <code>dataType</code> is
 845      * not one of <code>DataBuffer.TYPE_BYTE</code>,
 846      * <code>DataBuffer.TYPE_SHORT</code>,
 847      * <code>DataBuffer.TYPE_USHORT</code>,
 848      * or <code>DataBuffer.TYPE_INT</code>.
 849      * @exception IllegalArgumentException if <code>bits</code> is
 850      * larger than the bit size of the given <code>dataType</code>.
 851      */
 852     public static ImageTypeSpecifier
 853         createIndexed(byte[] redLUT,
 854                       byte[] greenLUT,
 855                       byte[] blueLUT,
 856                       byte[] alphaLUT,
 857                       int bits,
 858                       int dataType) {
 859         return new ImageTypeSpecifier.Indexed(redLUT,
 860                                               greenLUT,
 861                                               blueLUT,
 862                                               alphaLUT,
 863                                               bits,
 864                                               dataType);
 865     }
 866 
 867     /**
 868      * Returns an <code>ImageTypeSpecifier</code> that encodes
 869      * one of the standard <code>BufferedImage</code> types
 870      * (other than <code>TYPE_CUSTOM</code>).
 871      *
 872      * @param bufferedImageType an int representing one of the standard
 873      * <code>BufferedImage</code> types.
 874      *
 875      * @return an <code>ImageTypeSpecifier</code> with the desired
 876      * characteristics.
 877      *
 878      * @exception IllegalArgumentException if
 879      * <code>bufferedImageType</code> is not one of the standard
 880      * types, or is equal to <code>TYPE_CUSTOM</code>.
 881      *
 882      * @see java.awt.image.BufferedImage
 883      * @see java.awt.image.BufferedImage#TYPE_INT_RGB
 884      * @see java.awt.image.BufferedImage#TYPE_INT_ARGB
 885      * @see java.awt.image.BufferedImage#TYPE_INT_ARGB_PRE
 886      * @see java.awt.image.BufferedImage#TYPE_INT_BGR
 887      * @see java.awt.image.BufferedImage#TYPE_3BYTE_BGR
 888      * @see java.awt.image.BufferedImage#TYPE_4BYTE_ABGR
 889      * @see java.awt.image.BufferedImage#TYPE_4BYTE_ABGR_PRE
 890      * @see java.awt.image.BufferedImage#TYPE_USHORT_565_RGB
 891      * @see java.awt.image.BufferedImage#TYPE_USHORT_555_RGB
 892      * @see java.awt.image.BufferedImage#TYPE_BYTE_GRAY
 893      * @see java.awt.image.BufferedImage#TYPE_USHORT_GRAY
 894      * @see java.awt.image.BufferedImage#TYPE_BYTE_BINARY
 895      * @see java.awt.image.BufferedImage#TYPE_BYTE_INDEXED
 896      */
 897     public static
 898         ImageTypeSpecifier createFromBufferedImageType(int bufferedImageType) {
 899         if (bufferedImageType >= BufferedImage.TYPE_INT_RGB &&
 900             bufferedImageType <= BufferedImage.TYPE_BYTE_INDEXED) {
 901             return getSpecifier(bufferedImageType);
 902         } else if (bufferedImageType == BufferedImage.TYPE_CUSTOM) {
 903             throw new IllegalArgumentException("Cannot create from TYPE_CUSTOM!");
 904         } else {
 905             throw new IllegalArgumentException("Invalid BufferedImage type!");
 906         }
 907     }
 908 
 909     /**
 910      * Returns an <code>ImageTypeSpecifier</code> that encodes the
 911      * layout of a <code>RenderedImage</code> (which may be a
 912      * <code>BufferedImage</code>).
 913      *
 914      * @param image a <code>RenderedImage</code>.
 915      *
 916      * @return an <code>ImageTypeSpecifier</code> with the desired
 917      * characteristics.
 918      *
 919      * @exception IllegalArgumentException if <code>image</code> is
 920      * <code>null</code>.
 921      */
 922     public static
 923         ImageTypeSpecifier createFromRenderedImage(RenderedImage image) {
 924         if (image == null) {
 925             throw new IllegalArgumentException("image == null!");
 926         }
 927 
 928         if (image instanceof BufferedImage) {
 929             int bufferedImageType = ((BufferedImage)image).getType();
 930             if (bufferedImageType != BufferedImage.TYPE_CUSTOM) {
 931                 return getSpecifier(bufferedImageType);
 932             }
 933         }
 934 
 935         return new ImageTypeSpecifier(image);
 936     }
 937 
 938     /**
 939      * Returns an int containing one of the enumerated constant values
 940      * describing image formats from <code>BufferedImage</code>.
 941      *
 942      * @return an <code>int</code> representing a
 943      * <code>BufferedImage</code> type.
 944      *
 945      * @see java.awt.image.BufferedImage
 946      * @see java.awt.image.BufferedImage#TYPE_CUSTOM
 947      * @see java.awt.image.BufferedImage#TYPE_INT_RGB
 948      * @see java.awt.image.BufferedImage#TYPE_INT_ARGB
 949      * @see java.awt.image.BufferedImage#TYPE_INT_ARGB_PRE
 950      * @see java.awt.image.BufferedImage#TYPE_INT_BGR
 951      * @see java.awt.image.BufferedImage#TYPE_3BYTE_BGR
 952      * @see java.awt.image.BufferedImage#TYPE_4BYTE_ABGR
 953      * @see java.awt.image.BufferedImage#TYPE_4BYTE_ABGR_PRE
 954      * @see java.awt.image.BufferedImage#TYPE_USHORT_565_RGB
 955      * @see java.awt.image.BufferedImage#TYPE_USHORT_555_RGB
 956      * @see java.awt.image.BufferedImage#TYPE_BYTE_GRAY
 957      * @see java.awt.image.BufferedImage#TYPE_USHORT_GRAY
 958      * @see java.awt.image.BufferedImage#TYPE_BYTE_BINARY
 959      * @see java.awt.image.BufferedImage#TYPE_BYTE_INDEXED
 960      */
 961     public int getBufferedImageType() {
 962         BufferedImage bi = createBufferedImage(1, 1);
 963         return bi.getType();
 964     }
 965 
 966     /**
 967      * Return the number of color components
 968      * specified by this object.  This is the same value as returned by
 969      * <code>ColorModel.getNumComponents</code>
 970      *
 971      * @return the number of components in the image.
 972      */
 973     public int getNumComponents() {
 974         return colorModel.getNumComponents();
 975     }
 976 
 977     /**
 978      * Return the number of bands
 979      * specified by this object.  This is the same value as returned by
 980      * <code>SampleModel.getNumBands</code>
 981      *
 982      * @return the number of bands in the image.
 983      */
 984     public int getNumBands() {
 985         return sampleModel.getNumBands();
 986     }
 987 
 988     /**
 989      * Return the number of bits used to represent samples of the given band.
 990      *
 991      * @param band the index of the band to be queried, as an
 992      * int.
 993      *
 994      * @return an int specifying a number of bits.
 995      *
 996      * @exception IllegalArgumentException if <code>band</code> is
 997      * negative or greater than the largest band index.
 998      */
 999     public int getBitsPerBand(int band) {
1000         if (band < 0 | band >= getNumBands()) {
1001             throw new IllegalArgumentException("band out of range!");
1002         }
1003         return sampleModel.getSampleSize(band);
1004     }
1005 
1006     /**
1007      * Returns a <code>SampleModel</code> based on the settings
1008      * encapsulated within this object.  The width and height of the
1009      * <code>SampleModel</code> will be set to arbitrary values.
1010      *
1011      * @return a <code>SampleModel</code> with arbitrary dimensions.
1012      */
1013     public SampleModel getSampleModel() {
1014         return sampleModel;
1015     }
1016 
1017     /**
1018      * Returns a <code>SampleModel</code> based on the settings
1019      * encapsulated within this object.  The width and height of the
1020      * <code>SampleModel</code> will be set to the supplied values.
1021      *
1022      * @param width the desired width of the returned <code>SampleModel</code>.
1023      * @param height the desired height of the returned
1024      * <code>SampleModel</code>.
1025      *
1026      * @return a <code>SampleModel</code> with the given dimensions.
1027      *
1028      * @exception IllegalArgumentException if either <code>width</code> or
1029      * <code>height</code> are negative or zero.
1030      * @exception IllegalArgumentException if the product of
1031      * <code>width</code> and <code>height</code> is greater than
1032      * <code>Integer.MAX_VALUE</code>
1033      */
1034     public SampleModel getSampleModel(int width, int height) {
1035         if ((long)width*height > Integer.MAX_VALUE) {
1036             throw new IllegalArgumentException
1037                 ("width*height > Integer.MAX_VALUE!");
1038         }
1039         return sampleModel.createCompatibleSampleModel(width, height);
1040     }
1041 
1042     /**
1043      * Returns the <code>ColorModel</code> specified by this object.
1044      *
1045      * @return a <code>ColorModel</code>.
1046      */
1047     public ColorModel getColorModel() {
1048         return colorModel;
1049     }
1050 
1051     /**
1052      * Creates a <code>BufferedImage</code> with a given width and
1053      * height according to the specification embodied in this object.
1054      *
1055      * @param width the desired width of the returned
1056      * <code>BufferedImage</code>.
1057      * @param height the desired height of the returned
1058      * <code>BufferedImage</code>.
1059      *
1060      * @return a new <code>BufferedImage</code>
1061      *
1062      * @exception IllegalArgumentException if either <code>width</code> or
1063      * <code>height</code> are negative or zero.
1064      * @exception IllegalArgumentException if the product of
1065      * <code>width</code> and <code>height</code> is greater than
1066      * <code>Integer.MAX_VALUE</code>, or if the number of array
1067      * elements needed to store the image is greater than
1068      * <code>Integer.MAX_VALUE</code>.
1069      */
1070     public BufferedImage createBufferedImage(int width, int height) {
1071         try {
1072             SampleModel sampleModel = getSampleModel(width, height);
1073             WritableRaster raster =
1074                 Raster.createWritableRaster(sampleModel,
1075                                             new Point(0, 0));
1076             return new BufferedImage(colorModel, raster,
1077                                      colorModel.isAlphaPremultiplied(),
1078                                      new Hashtable<>());
1079         } catch (NegativeArraySizeException e) {
1080             // Exception most likely thrown from a DataBuffer constructor
1081             throw new IllegalArgumentException
1082                 ("Array size > Integer.MAX_VALUE!");
1083         }
1084     }
1085 
1086     /**
1087      * Returns <code>true</code> if the given <code>Object</code> is
1088      * an <code>ImageTypeSpecifier</code> and has a
1089      * <code>SampleModel</code> and <code>ColorModel</code> that are
1090      * equal to those of this object.
1091      *
1092      * @param o the <code>Object</code> to be compared for equality.
1093      *
1094      * @return <code>true</code> if the given object is an equivalent
1095      * <code>ImageTypeSpecifier</code>.
1096      */
1097     public boolean equals(Object o) {
1098         if ((o == null) || !(o instanceof ImageTypeSpecifier)) {
1099             return false;
1100         }
1101 
1102         ImageTypeSpecifier that = (ImageTypeSpecifier)o;
1103         return (colorModel.equals(that.colorModel)) &&
1104             (sampleModel.equals(that.sampleModel));
1105     }
1106 
1107     /**
1108      * Returns the hash code for this ImageTypeSpecifier.
1109      *
1110      * @return a hash code for this ImageTypeSpecifier
1111      */
1112     public int hashCode() {
1113         return (9 * colorModel.hashCode()) + (14 * sampleModel.hashCode());
1114     }
1115 




  29 import java.awt.Transparency;
  30 import java.awt.image.BandedSampleModel;
  31 import java.awt.image.BufferedImage;
  32 import java.awt.image.ColorModel;
  33 import java.awt.color.ColorSpace;
  34 import java.awt.image.IndexColorModel;
  35 import java.awt.image.ComponentColorModel;
  36 import java.awt.image.DataBuffer;
  37 import java.awt.image.DirectColorModel;
  38 import java.awt.image.MultiPixelPackedSampleModel;
  39 import java.awt.image.PixelInterleavedSampleModel;
  40 import java.awt.image.SinglePixelPackedSampleModel;
  41 import java.awt.image.Raster;
  42 import java.awt.image.RenderedImage;
  43 import java.awt.image.SampleModel;
  44 import java.awt.image.WritableRaster;
  45 import java.util.Hashtable;
  46 
  47 /**
  48  * A class that allows the format of an image (in particular, its
  49  * {@code SampleModel} and {@code ColorModel}) to be
  50  * specified in a convenient manner.
  51  *
  52  */
  53 public class ImageTypeSpecifier {
  54 
  55     /**
  56      * The {@code ColorModel} to be used as a prototype.
  57      */
  58     protected ColorModel colorModel;
  59 
  60     /**
  61      * A {@code SampleModel} to be used as a prototype.
  62      */
  63     protected SampleModel sampleModel;
  64 
  65     /**
  66      * Cached specifiers for all of the standard
  67      * {@code BufferedImage} types.
  68      */
  69     private static ImageTypeSpecifier[] BISpecifier;
  70     private static ColorSpace sRGB;
  71     // Initialize the standard specifiers
  72     static {
  73         sRGB = ColorSpace.getInstance(ColorSpace.CS_sRGB);
  74 
  75         BISpecifier =
  76             new ImageTypeSpecifier[BufferedImage.TYPE_BYTE_INDEXED + 1];
  77     }
  78 
  79     /**
  80      * A constructor to be used by inner subclasses only.
  81      */
  82     private ImageTypeSpecifier() {}
  83 
  84     /**
  85      * Constructs an {@code ImageTypeSpecifier} directly
  86      * from a {@code ColorModel} and a {@code SampleModel}.
  87      * It is the caller's responsibility to supply compatible
  88      * parameters.
  89      *
  90      * @param colorModel a {@code ColorModel}.
  91      * @param sampleModel a {@code SampleModel}.
  92      *
  93      * @exception IllegalArgumentException if either parameter is
  94      * {@code null}.
  95      * @exception IllegalArgumentException if {@code sampleModel}
  96      * is not compatible with {@code colorModel}.
  97      */
  98     public ImageTypeSpecifier(ColorModel colorModel, SampleModel sampleModel) {
  99         if (colorModel == null) {
 100             throw new IllegalArgumentException("colorModel == null!");
 101         }
 102         if (sampleModel == null) {
 103             throw new IllegalArgumentException("sampleModel == null!");
 104         }
 105         if (!colorModel.isCompatibleSampleModel(sampleModel)) {
 106             throw new IllegalArgumentException
 107                 ("sampleModel is incompatible with colorModel!");
 108         }
 109         this.colorModel = colorModel;
 110         this.sampleModel = sampleModel;
 111     }
 112 
 113     /**
 114      * Constructs an {@code ImageTypeSpecifier} from a
 115      * {@code RenderedImage}.  If a {@code BufferedImage} is
 116      * being used, one of the factory methods
 117      * {@code createFromRenderedImage} or
 118      * {@code createFromBufferedImageType} should be used instead in
 119      * order to get a more accurate result.
 120      *
 121      * @param image a {@code RenderedImage}.
 122      *
 123      * @exception IllegalArgumentException if the argument is
 124      * {@code null}.
 125      */
 126     public ImageTypeSpecifier(RenderedImage image) {
 127         if (image == null) {
 128             throw new IllegalArgumentException("image == null!");
 129         }
 130         colorModel = image.getColorModel();
 131         sampleModel = image.getSampleModel();
 132     }
 133 
 134     // Packed
 135 
 136     static class Packed extends ImageTypeSpecifier {
 137         ColorSpace colorSpace;
 138         int redMask;
 139         int greenMask;
 140         int blueMask;
 141         int alphaMask;
 142         int transferType;
 143         boolean isAlphaPremultiplied;
 144 


 171             this.redMask = redMask;
 172             this.greenMask = greenMask;
 173             this.blueMask = blueMask;
 174             this.alphaMask = alphaMask;
 175             this.transferType = transferType;
 176             this.isAlphaPremultiplied = isAlphaPremultiplied;
 177 
 178             int bits = 32;
 179             this.colorModel =
 180                 new DirectColorModel(colorSpace,
 181                                      bits,
 182                                      redMask, greenMask, blueMask,
 183                                      alphaMask, isAlphaPremultiplied,
 184                                      transferType);
 185             this.sampleModel = colorModel.createCompatibleSampleModel(1, 1);
 186         }
 187     }
 188 
 189     /**
 190      * Returns a specifier for a packed image format that will use a
 191      * {@code DirectColorModel} and a packed
 192      * {@code SampleModel} to store each pixel packed into in a
 193      * single byte, short, or int.
 194      *
 195      * @param colorSpace the desired {@code ColorSpace}.
 196      * @param redMask a contiguous mask indicated the position of the
 197      * red channel.
 198      * @param greenMask a contiguous mask indicated the position of the
 199      * green channel.
 200      * @param blueMask a contiguous mask indicated the position of the
 201      * blue channel.
 202      * @param alphaMask a contiguous mask indicated the position of the
 203      * alpha channel.
 204      * @param transferType the desired {@code SampleModel} transfer type.
 205      * @param isAlphaPremultiplied {@code true} if the color channels
 206      * will be premultipled by the alpha channel.
 207      *
 208      * @return an {@code ImageTypeSpecifier} with the desired
 209      * characteristics.
 210      *
 211      * @exception IllegalArgumentException if {@code colorSpace}
 212      * is {@code null}.
 213      * @exception IllegalArgumentException if {@code colorSpace}
 214      * is not of type {@code TYPE_RGB}.
 215      * @exception IllegalArgumentException if no mask has at least 1
 216      * bit set.
 217      * @exception IllegalArgumentException if
 218      * {@code transferType} if not one of
 219      * {@code DataBuffer.TYPE_BYTE},
 220      * {@code DataBuffer.TYPE_USHORT}, or
 221      * {@code DataBuffer.TYPE_INT}.
 222      */
 223     public static ImageTypeSpecifier
 224         createPacked(ColorSpace colorSpace,
 225                      int redMask,
 226                      int greenMask,
 227                      int blueMask,
 228                      int alphaMask, // 0 if no alpha
 229                      int transferType,
 230                      boolean isAlphaPremultiplied) {
 231         return new ImageTypeSpecifier.Packed(colorSpace,
 232                                              redMask,
 233                                              greenMask,
 234                                              blueMask,
 235                                              alphaMask, // 0 if no alpha
 236                                              transferType,
 237                                              isAlphaPremultiplied);
 238     }
 239 
 240     static ColorModel createComponentCM(ColorSpace colorSpace,
 241                                         int numBands,


 346 
 347             for (int i = 0; i < bandOffsets.length; i++) {
 348                 if (this.bandOffsets[i] != that.bandOffsets[i]) {
 349                     return false;
 350                 }
 351             }
 352 
 353             return true;
 354         }
 355 
 356         public int hashCode() {
 357             return (super.hashCode() +
 358                     (4 * bandOffsets.length) +
 359                     (25 * dataType) +
 360                     (hasAlpha ? 17 : 18));
 361         }
 362     }
 363 
 364     /**
 365      * Returns a specifier for an interleaved image format that will
 366      * use a {@code ComponentColorModel} and a
 367      * {@code PixelInterleavedSampleModel} to store each pixel
 368      * component in a separate byte, short, or int.
 369      *
 370      * @param colorSpace the desired {@code ColorSpace}.
 371      * @param bandOffsets an array of {@code int}s indicating the
 372      * offsets for each band.
 373      * @param dataType the desired data type, as one of the enumerations
 374      * from the {@code DataBuffer} class.
 375      * @param hasAlpha {@code true} if an alpha channel is desired.
 376      * @param isAlphaPremultiplied {@code true} if the color channels
 377      * will be premultipled by the alpha channel.
 378      *
 379      * @return an {@code ImageTypeSpecifier} with the desired
 380      * characteristics.
 381      *
 382      * @exception IllegalArgumentException if {@code colorSpace}
 383      * is {@code null}.
 384      * @exception IllegalArgumentException if {@code bandOffsets}
 385      * is {@code null}.
 386      * @exception IllegalArgumentException if {@code dataType} is
 387      * not one of the legal {@code DataBuffer.TYPE_*} constants.
 388      * @exception IllegalArgumentException if
 389      * {@code bandOffsets.length} does not equal the number of
 390      * color space components, plus 1 if {@code hasAlpha} is
 391      * {@code true}.
 392      */
 393     public static ImageTypeSpecifier
 394         createInterleaved(ColorSpace colorSpace,
 395                           int[] bandOffsets,
 396                           int dataType,
 397                           boolean hasAlpha,
 398                           boolean isAlphaPremultiplied) {
 399         return new ImageTypeSpecifier.Interleaved(colorSpace,
 400                                                   bandOffsets,
 401                                                   dataType,
 402                                                   hasAlpha,
 403                                                   isAlphaPremultiplied);
 404     }
 405 
 406     // Banded
 407 
 408     static class Banded extends ImageTypeSpecifier {
 409         ColorSpace colorSpace;
 410         int[] bankIndices;
 411         int[] bandOffsets;


 498             for (int i = 0; i < bandOffsets.length; i++) {
 499                 if (this.bandOffsets[i] != that.bandOffsets[i]) {
 500                     return false;
 501                 }
 502             }
 503 
 504             return true;
 505         }
 506 
 507         public int hashCode() {
 508             return (super.hashCode() +
 509                     (3 * bandOffsets.length) +
 510                     (7 * bankIndices.length) +
 511                     (21 * dataType) +
 512                     (hasAlpha ? 19 : 29));
 513         }
 514     }
 515 
 516     /**
 517      * Returns a specifier for a banded image format that will use a
 518      * {@code ComponentColorModel} and a
 519      * {@code BandedSampleModel} to store each channel in a
 520      * separate array.
 521      *
 522      * @param colorSpace the desired {@code ColorSpace}.
 523      * @param bankIndices an array of {@code int}s indicating the
 524      * bank in which each band will be stored.
 525      * @param bandOffsets an array of {@code int}s indicating the
 526      * starting offset of each band within its bank.
 527      * @param dataType the desired data type, as one of the enumerations
 528      * from the {@code DataBuffer} class.
 529      * @param hasAlpha {@code true} if an alpha channel is desired.
 530      * @param isAlphaPremultiplied {@code true} if the color channels
 531      * will be premultipled by the alpha channel.
 532      *
 533      * @return an {@code ImageTypeSpecifier} with the desired
 534      * characteristics.
 535      *
 536      * @exception IllegalArgumentException if {@code colorSpace}
 537      * is {@code null}.
 538      * @exception IllegalArgumentException if {@code bankIndices}
 539      * is {@code null}.
 540      * @exception IllegalArgumentException if {@code bandOffsets}
 541      * is {@code null}.
 542      * @exception IllegalArgumentException if the lengths of
 543      * {@code bankIndices} and {@code bandOffsets} differ.
 544      * @exception IllegalArgumentException if
 545      * {@code bandOffsets.length} does not equal the number of
 546      * color space components, plus 1 if {@code hasAlpha} is
 547      * {@code true}.
 548      * @exception IllegalArgumentException if {@code dataType} is
 549      * not one of the legal {@code DataBuffer.TYPE_*} constants.
 550      */
 551     public static ImageTypeSpecifier
 552         createBanded(ColorSpace colorSpace,
 553                      int[] bankIndices,
 554                      int[] bandOffsets,
 555                      int dataType,
 556                      boolean hasAlpha,
 557                      boolean isAlphaPremultiplied) {
 558         return new ImageTypeSpecifier.Banded(colorSpace,
 559                                              bankIndices,
 560                                              bandOffsets,
 561                                              dataType,
 562                                              hasAlpha,
 563                                              isAlphaPremultiplied);
 564     }
 565 
 566     // Grayscale
 567 
 568     static class Grayscale extends ImageTypeSpecifier {
 569         int bits;


 645                 byte[] arr = new byte[numEntries];
 646                 for (int i = 0; i < numEntries; i++) {
 647                     arr[i] = (byte)(i*255/(numEntries - 1));
 648                 }
 649                 this.colorModel =
 650                     new IndexColorModel(bits, numEntries, arr, arr, arr);
 651 
 652                 this.sampleModel =
 653                     new MultiPixelPackedSampleModel(dataType, 1, 1, bits);
 654             }
 655         }
 656     }
 657 
 658     /**
 659      * Returns a specifier for a grayscale image format that will pack
 660      * pixels of the given bit depth into array elements of
 661      * the specified data type.
 662      *
 663      * @param bits the number of bits per gray value (1, 2, 4, 8, or 16).
 664      * @param dataType the desired data type, as one of the enumerations
 665      * from the {@code DataBuffer} class.
 666      * @param isSigned {@code true} if negative values are to
 667      * be represented.
 668      *
 669      * @return an {@code ImageTypeSpecifier} with the desired
 670      * characteristics.
 671      *
 672      * @exception IllegalArgumentException if {@code bits} is
 673      * not one of 1, 2, 4, 8, or 16.
 674      * @exception IllegalArgumentException if {@code dataType} is
 675      * not one of {@code DataBuffer.TYPE_BYTE},
 676      * {@code DataBuffer.TYPE_SHORT}, or
 677      * {@code DataBuffer.TYPE_USHORT}.
 678      * @exception IllegalArgumentException if {@code bits} is
 679      * larger than the bit size of the given {@code dataType}.
 680      */
 681     public static ImageTypeSpecifier
 682         createGrayscale(int bits,
 683                         int dataType,
 684                         boolean isSigned) {
 685         return new ImageTypeSpecifier.Grayscale(bits,
 686                                                 dataType,
 687                                                 isSigned,
 688                                                 false,
 689                                                 false);
 690     }
 691 
 692     /**
 693      * Returns a specifier for a grayscale plus alpha image format
 694      * that will pack pixels of the given bit depth into array
 695      * elements of the specified data type.
 696      *
 697      * @param bits the number of bits per gray value (1, 2, 4, 8, or 16).
 698      * @param dataType the desired data type, as one of the enumerations
 699      * from the {@code DataBuffer} class.
 700      * @param isSigned {@code true} if negative values are to
 701      * be represented.
 702      * @param isAlphaPremultiplied {@code true} if the luminance channel
 703      * will be premultipled by the alpha channel.
 704      *
 705      * @return an {@code ImageTypeSpecifier} with the desired
 706      * characteristics.
 707      *
 708      * @exception IllegalArgumentException if {@code bits} is
 709      * not one of 1, 2, 4, 8, or 16.
 710      * @exception IllegalArgumentException if {@code dataType} is
 711      * not one of {@code DataBuffer.TYPE_BYTE},
 712      * {@code DataBuffer.TYPE_SHORT}, or
 713      * {@code DataBuffer.TYPE_USHORT}.
 714      * @exception IllegalArgumentException if {@code bits} is
 715      * larger than the bit size of the given {@code dataType}.
 716      */
 717     public static ImageTypeSpecifier
 718         createGrayscale(int bits,
 719                         int dataType,
 720                         boolean isSigned,
 721                         boolean isAlphaPremultiplied) {
 722         return new ImageTypeSpecifier.Grayscale(bits,
 723                                                 dataType,
 724                                                 isSigned,
 725                                                 true,
 726                                                 isAlphaPremultiplied);
 727     }
 728 
 729     // Indexed
 730 
 731     static class Indexed extends ImageTypeSpecifier {
 732         byte[] redLUT;
 733         byte[] greenLUT;
 734         byte[] blueLUT;
 735         byte[] alphaLUT = null;


 797                 (bits == 16 &&
 798                  (dataType == DataBuffer.TYPE_SHORT ||
 799                   dataType == DataBuffer.TYPE_USHORT))) {
 800                 int[] bandOffsets = { 0 };
 801                 this.sampleModel =
 802                     new PixelInterleavedSampleModel(dataType,
 803                                                     1, 1, 1, 1,
 804                                                     bandOffsets);
 805             } else {
 806                 this.sampleModel =
 807                     new MultiPixelPackedSampleModel(dataType, 1, 1, bits);
 808             }
 809         }
 810     }
 811 
 812     /**
 813      * Returns a specifier for an indexed-color image format that will pack
 814      * index values of the given bit depth into array elements of
 815      * the specified data type.
 816      *
 817      * @param redLUT an array of {@code byte}s containing
 818      * the red values for each index.
 819      * @param greenLUT an array of {@code byte}s containing * the
 820      *  green values for each index.
 821      * @param blueLUT an array of {@code byte}s containing the
 822      * blue values for each index.
 823      * @param alphaLUT an array of {@code byte}s containing the
 824      * alpha values for each index, or {@code null} to create a
 825      * fully opaque LUT.
 826      * @param bits the number of bits in each index.
 827      * @param dataType the desired output type, as one of the enumerations
 828      * from the {@code DataBuffer} class.
 829      *
 830      * @return an {@code ImageTypeSpecifier} with the desired
 831      * characteristics.
 832      *
 833      * @exception IllegalArgumentException if {@code redLUT} is
 834      * {@code null}.
 835      * @exception IllegalArgumentException if {@code greenLUT} is
 836      * {@code null}.
 837      * @exception IllegalArgumentException if {@code blueLUT} is
 838      * {@code null}.
 839      * @exception IllegalArgumentException if {@code bits} is
 840      * not one of 1, 2, 4, 8, or 16.
 841      * @exception IllegalArgumentException if the
 842      * non-{@code null} LUT parameters do not have lengths of
 843      * exactly {@code 1 << bits}.
 844      * @exception IllegalArgumentException if {@code dataType} is
 845      * not one of {@code DataBuffer.TYPE_BYTE},
 846      * {@code DataBuffer.TYPE_SHORT},
 847      * {@code DataBuffer.TYPE_USHORT},
 848      * or {@code DataBuffer.TYPE_INT}.
 849      * @exception IllegalArgumentException if {@code bits} is
 850      * larger than the bit size of the given {@code dataType}.
 851      */
 852     public static ImageTypeSpecifier
 853         createIndexed(byte[] redLUT,
 854                       byte[] greenLUT,
 855                       byte[] blueLUT,
 856                       byte[] alphaLUT,
 857                       int bits,
 858                       int dataType) {
 859         return new ImageTypeSpecifier.Indexed(redLUT,
 860                                               greenLUT,
 861                                               blueLUT,
 862                                               alphaLUT,
 863                                               bits,
 864                                               dataType);
 865     }
 866 
 867     /**
 868      * Returns an {@code ImageTypeSpecifier} that encodes
 869      * one of the standard {@code BufferedImage} types
 870      * (other than {@code TYPE_CUSTOM}).
 871      *
 872      * @param bufferedImageType an int representing one of the standard
 873      * {@code BufferedImage} types.
 874      *
 875      * @return an {@code ImageTypeSpecifier} with the desired
 876      * characteristics.
 877      *
 878      * @exception IllegalArgumentException if
 879      * {@code bufferedImageType} is not one of the standard
 880      * types, or is equal to {@code TYPE_CUSTOM}.
 881      *
 882      * @see java.awt.image.BufferedImage
 883      * @see java.awt.image.BufferedImage#TYPE_INT_RGB
 884      * @see java.awt.image.BufferedImage#TYPE_INT_ARGB
 885      * @see java.awt.image.BufferedImage#TYPE_INT_ARGB_PRE
 886      * @see java.awt.image.BufferedImage#TYPE_INT_BGR
 887      * @see java.awt.image.BufferedImage#TYPE_3BYTE_BGR
 888      * @see java.awt.image.BufferedImage#TYPE_4BYTE_ABGR
 889      * @see java.awt.image.BufferedImage#TYPE_4BYTE_ABGR_PRE
 890      * @see java.awt.image.BufferedImage#TYPE_USHORT_565_RGB
 891      * @see java.awt.image.BufferedImage#TYPE_USHORT_555_RGB
 892      * @see java.awt.image.BufferedImage#TYPE_BYTE_GRAY
 893      * @see java.awt.image.BufferedImage#TYPE_USHORT_GRAY
 894      * @see java.awt.image.BufferedImage#TYPE_BYTE_BINARY
 895      * @see java.awt.image.BufferedImage#TYPE_BYTE_INDEXED
 896      */
 897     public static
 898         ImageTypeSpecifier createFromBufferedImageType(int bufferedImageType) {
 899         if (bufferedImageType >= BufferedImage.TYPE_INT_RGB &&
 900             bufferedImageType <= BufferedImage.TYPE_BYTE_INDEXED) {
 901             return getSpecifier(bufferedImageType);
 902         } else if (bufferedImageType == BufferedImage.TYPE_CUSTOM) {
 903             throw new IllegalArgumentException("Cannot create from TYPE_CUSTOM!");
 904         } else {
 905             throw new IllegalArgumentException("Invalid BufferedImage type!");
 906         }
 907     }
 908 
 909     /**
 910      * Returns an {@code ImageTypeSpecifier} that encodes the
 911      * layout of a {@code RenderedImage} (which may be a
 912      * {@code BufferedImage}).
 913      *
 914      * @param image a {@code RenderedImage}.
 915      *
 916      * @return an {@code ImageTypeSpecifier} with the desired
 917      * characteristics.
 918      *
 919      * @exception IllegalArgumentException if {@code image} is
 920      * {@code null}.
 921      */
 922     public static
 923         ImageTypeSpecifier createFromRenderedImage(RenderedImage image) {
 924         if (image == null) {
 925             throw new IllegalArgumentException("image == null!");
 926         }
 927 
 928         if (image instanceof BufferedImage) {
 929             int bufferedImageType = ((BufferedImage)image).getType();
 930             if (bufferedImageType != BufferedImage.TYPE_CUSTOM) {
 931                 return getSpecifier(bufferedImageType);
 932             }
 933         }
 934 
 935         return new ImageTypeSpecifier(image);
 936     }
 937 
 938     /**
 939      * Returns an int containing one of the enumerated constant values
 940      * describing image formats from {@code BufferedImage}.
 941      *
 942      * @return an {@code int} representing a
 943      * {@code BufferedImage} type.
 944      *
 945      * @see java.awt.image.BufferedImage
 946      * @see java.awt.image.BufferedImage#TYPE_CUSTOM
 947      * @see java.awt.image.BufferedImage#TYPE_INT_RGB
 948      * @see java.awt.image.BufferedImage#TYPE_INT_ARGB
 949      * @see java.awt.image.BufferedImage#TYPE_INT_ARGB_PRE
 950      * @see java.awt.image.BufferedImage#TYPE_INT_BGR
 951      * @see java.awt.image.BufferedImage#TYPE_3BYTE_BGR
 952      * @see java.awt.image.BufferedImage#TYPE_4BYTE_ABGR
 953      * @see java.awt.image.BufferedImage#TYPE_4BYTE_ABGR_PRE
 954      * @see java.awt.image.BufferedImage#TYPE_USHORT_565_RGB
 955      * @see java.awt.image.BufferedImage#TYPE_USHORT_555_RGB
 956      * @see java.awt.image.BufferedImage#TYPE_BYTE_GRAY
 957      * @see java.awt.image.BufferedImage#TYPE_USHORT_GRAY
 958      * @see java.awt.image.BufferedImage#TYPE_BYTE_BINARY
 959      * @see java.awt.image.BufferedImage#TYPE_BYTE_INDEXED
 960      */
 961     public int getBufferedImageType() {
 962         BufferedImage bi = createBufferedImage(1, 1);
 963         return bi.getType();
 964     }
 965 
 966     /**
 967      * Return the number of color components
 968      * specified by this object.  This is the same value as returned by
 969      * {@code ColorModel.getNumComponents}
 970      *
 971      * @return the number of components in the image.
 972      */
 973     public int getNumComponents() {
 974         return colorModel.getNumComponents();
 975     }
 976 
 977     /**
 978      * Return the number of bands
 979      * specified by this object.  This is the same value as returned by
 980      * {@code SampleModel.getNumBands}
 981      *
 982      * @return the number of bands in the image.
 983      */
 984     public int getNumBands() {
 985         return sampleModel.getNumBands();
 986     }
 987 
 988     /**
 989      * Return the number of bits used to represent samples of the given band.
 990      *
 991      * @param band the index of the band to be queried, as an
 992      * int.
 993      *
 994      * @return an int specifying a number of bits.
 995      *
 996      * @exception IllegalArgumentException if {@code band} is
 997      * negative or greater than the largest band index.
 998      */
 999     public int getBitsPerBand(int band) {
1000         if (band < 0 | band >= getNumBands()) {
1001             throw new IllegalArgumentException("band out of range!");
1002         }
1003         return sampleModel.getSampleSize(band);
1004     }
1005 
1006     /**
1007      * Returns a {@code SampleModel} based on the settings
1008      * encapsulated within this object.  The width and height of the
1009      * {@code SampleModel} will be set to arbitrary values.
1010      *
1011      * @return a {@code SampleModel} with arbitrary dimensions.
1012      */
1013     public SampleModel getSampleModel() {
1014         return sampleModel;
1015     }
1016 
1017     /**
1018      * Returns a {@code SampleModel} based on the settings
1019      * encapsulated within this object.  The width and height of the
1020      * {@code SampleModel} will be set to the supplied values.
1021      *
1022      * @param width the desired width of the returned {@code SampleModel}.
1023      * @param height the desired height of the returned
1024      * {@code SampleModel}.
1025      *
1026      * @return a {@code SampleModel} with the given dimensions.
1027      *
1028      * @exception IllegalArgumentException if either {@code width} or
1029      * {@code height} are negative or zero.
1030      * @exception IllegalArgumentException if the product of
1031      * {@code width} and {@code height} is greater than
1032      * {@code Integer.MAX_VALUE}
1033      */
1034     public SampleModel getSampleModel(int width, int height) {
1035         if ((long)width*height > Integer.MAX_VALUE) {
1036             throw new IllegalArgumentException
1037                 ("width*height > Integer.MAX_VALUE!");
1038         }
1039         return sampleModel.createCompatibleSampleModel(width, height);
1040     }
1041 
1042     /**
1043      * Returns the {@code ColorModel} specified by this object.
1044      *
1045      * @return a {@code ColorModel}.
1046      */
1047     public ColorModel getColorModel() {
1048         return colorModel;
1049     }
1050 
1051     /**
1052      * Creates a {@code BufferedImage} with a given width and
1053      * height according to the specification embodied in this object.
1054      *
1055      * @param width the desired width of the returned
1056      * {@code BufferedImage}.
1057      * @param height the desired height of the returned
1058      * {@code BufferedImage}.
1059      *
1060      * @return a new {@code BufferedImage}
1061      *
1062      * @exception IllegalArgumentException if either {@code width} or
1063      * {@code height} are negative or zero.
1064      * @exception IllegalArgumentException if the product of
1065      * {@code width} and {@code height} is greater than
1066      * {@code Integer.MAX_VALUE}, or if the number of array
1067      * elements needed to store the image is greater than
1068      * {@code Integer.MAX_VALUE}.
1069      */
1070     public BufferedImage createBufferedImage(int width, int height) {
1071         try {
1072             SampleModel sampleModel = getSampleModel(width, height);
1073             WritableRaster raster =
1074                 Raster.createWritableRaster(sampleModel,
1075                                             new Point(0, 0));
1076             return new BufferedImage(colorModel, raster,
1077                                      colorModel.isAlphaPremultiplied(),
1078                                      new Hashtable<>());
1079         } catch (NegativeArraySizeException e) {
1080             // Exception most likely thrown from a DataBuffer constructor
1081             throw new IllegalArgumentException
1082                 ("Array size > Integer.MAX_VALUE!");
1083         }
1084     }
1085 
1086     /**
1087      * Returns {@code true} if the given {@code Object} is
1088      * an {@code ImageTypeSpecifier} and has a
1089      * {@code SampleModel} and {@code ColorModel} that are
1090      * equal to those of this object.
1091      *
1092      * @param o the {@code Object} to be compared for equality.
1093      *
1094      * @return {@code true} if the given object is an equivalent
1095      * {@code ImageTypeSpecifier}.
1096      */
1097     public boolean equals(Object o) {
1098         if ((o == null) || !(o instanceof ImageTypeSpecifier)) {
1099             return false;
1100         }
1101 
1102         ImageTypeSpecifier that = (ImageTypeSpecifier)o;
1103         return (colorModel.equals(that.colorModel)) &&
1104             (sampleModel.equals(that.sampleModel));
1105     }
1106 
1107     /**
1108      * Returns the hash code for this ImageTypeSpecifier.
1109      *
1110      * @return a hash code for this ImageTypeSpecifier
1111      */
1112     public int hashCode() {
1113         return (9 * colorModel.hashCode()) + (14 * sampleModel.hashCode());
1114     }
1115 


< prev index next >