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 |