Frames | No Frames |
1: /* ImageTypeSpecifier.java -- 2: Copyright (C) 2004 Free Software Foundation, Inc. 3: 4: This file is part of GNU Classpath. 5: 6: GNU Classpath is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2, or (at your option) 9: any later version. 10: 11: GNU Classpath is distributed in the hope that it will be useful, but 12: WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14: General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU Classpath; see the file COPYING. If not, write to the 18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 USA. 20: 21: Linking this library statically or dynamically with other modules is 22: making a combined work based on this library. Thus, the terms and 23: conditions of the GNU General Public License cover the whole 24: combination. 25: 26: As a special exception, the copyright holders of this library give you 27: permission to link this library with independent modules to produce an 28: executable, regardless of the license terms of these independent 29: modules, and to copy and distribute the resulting executable under 30: terms of your choice, provided that you also meet, for each linked 31: independent module, the terms and conditions of the license of that 32: module. An independent module is a module which is not derived from 33: or based on this library. If you modify this library, you may extend 34: this exception to your version of the library, but you are not 35: obligated to do so. If you do not wish to do so, delete this 36: exception statement from your version. */ 37: 38: 39: package javax.imageio; 40: 41: import java.awt.Transparency; 42: import java.awt.color.ColorSpace; 43: import java.awt.image.DataBuffer; 44: import java.awt.image.BandedSampleModel; 45: import java.awt.image.BufferedImage; 46: import java.awt.image.ColorModel; 47: import java.awt.image.ComponentColorModel; 48: import java.awt.image.DirectColorModel; 49: import java.awt.image.IndexColorModel; 50: import java.awt.image.MultiPixelPackedSampleModel; 51: import java.awt.image.PixelInterleavedSampleModel; 52: import java.awt.image.RenderedImage; 53: import java.awt.image.SampleModel; 54: 55: /** 56: * ImageTypeSpecifier store the color and sample models associated 57: * with an IIOImage. 58: */ 59: public class ImageTypeSpecifier 60: { 61: /** 62: * The image's color model. 63: */ 64: protected ColorModel colorModel; 65: 66: /** 67: * The image's sample model. 68: */ 69: protected SampleModel sampleModel; 70: 71: /** 72: * Construct an image type specifier with the given models. 73: * 74: * @param colorModel the color model 75: * @param sampleModel the sample model 76: * 77: * @exception IllegalArgumentException if either model argument is 78: * null 79: * @exception IllegalArgumentException if the models are 80: * incompatible with one another 81: */ 82: public ImageTypeSpecifier(ColorModel colorModel, SampleModel sampleModel) 83: { 84: if (colorModel == null) 85: throw new IllegalArgumentException("colorModel may not be null"); 86: 87: if (sampleModel == null) 88: throw new IllegalArgumentException("sampleModel may not be null"); 89: 90: if (!colorModel.isCompatibleSampleModel(sampleModel)) 91: throw new IllegalArgumentException 92: ("sample Model not compatible with colorModel"); 93: 94: this.colorModel = colorModel; 95: this.sampleModel = sampleModel; 96: } 97: 98: /** 99: * Construct an image type specifier that describes the given 100: * rendered image. 101: * 102: * @param image a rendered image 103: * 104: * @exception IllegalArgumentException if image is null 105: */ 106: public ImageTypeSpecifier(RenderedImage image) 107: { 108: if (image == null) 109: throw new IllegalArgumentException("image may not be null"); 110: 111: this.colorModel = image.getColorModel(); 112: this.sampleModel = image.getSampleModel(); 113: } 114: 115: /** 116: * Create an image type specifier for a banded image using a 117: * component color model and a banded sample model. 118: * 119: * @param colorSpace the color space 120: * @param bankIndices the bank indices at which each band will be 121: * stored 122: * @param bankOffsets the starting band offset for each band within 123: * its bank 124: * @param dataType the data type, a DataBuffer constant 125: * @param hasAlpha true if this image type specifier should have an 126: * alpha component, false otherwise 127: * @param isAlphaPremultiplied true if other color components should 128: * be premultiplied by the alpha component, false otherwise 129: * 130: * @return a banded image type specifier 131: * 132: * @exception IllegalArgumentException if any of colorSpace, 133: * bankIndices or bankOffsets is null 134: * @exception IllegalArgumentException if bankIndices and 135: * bankOffsets differ in length 136: * @excpetion IllegalArgumentException if the number of color space 137: * components, including the alpha component if requested, is 138: * different from bandOffsets.length 139: * @exception if dataType is not a valid DataBuffer constant 140: */ 141: public static ImageTypeSpecifier createBanded (ColorSpace colorSpace, 142: int[] bankIndices, 143: int[] bankOffsets, 144: int dataType, 145: boolean hasAlpha, 146: boolean isAlphaPremultiplied) 147: { 148: if (colorSpace == null || bankIndices == null || bankOffsets == null) 149: throw new IllegalArgumentException ("null argument"); 150: 151: if (bankIndices.length != bankOffsets.length) 152: throw new IllegalArgumentException ("array lengths differ"); 153: 154: if (bankOffsets.length != (colorSpace.getNumComponents() + (hasAlpha ? 1 : 0))) 155: throw new IllegalArgumentException ("invalid bankOffsets length"); 156: 157: return new ImageTypeSpecifier (new ComponentColorModel (colorSpace, 158: hasAlpha, 159: isAlphaPremultiplied, 160: hasAlpha ? Transparency.TRANSLUCENT : Transparency.OPAQUE, 161: dataType), 162: new BandedSampleModel (dataType, 1, 1, 1, 163: bankIndices, 164: bankOffsets)); 165: } 166: 167: /** 168: * Create a buffered image with the given dimensions using that has 169: * the characteristics specified by this image type specifier. 170: * 171: * @param width width of the buffered image, in pixels 172: * @param height the height of the buffered image, in pixels 173: * 174: * @return a buffered image 175: * 176: * @exception IllegalArgumentException if either width or height is 177: * less than or equal to zero 178: * @exception IllegalArgumentException if width * height is greater 179: * than Integer.MAX_VALUE or if the storage required is greater than 180: * Integer.MAX_VALUE 181: */ 182: public BufferedImage createBufferedImage (int width, int height) 183: { 184: if (width <= 0 || height <= 0) 185: throw new IllegalArgumentException ("dimension <= 0"); 186: 187: // test for overflow 188: if (width * height < Math.min (width, height)) 189: throw new IllegalArgumentException ("width * height > Integer.MAX_VALUE"); 190: 191: if (width * height * sampleModel.getNumBands() < Math.min (width, height)) 192: throw new IllegalArgumentException ("storage required >" 193: + " Integer.MAX_VALUE"); 194: 195: // FIXME: this is probably wrong: 196: return new BufferedImage (width, height, BufferedImage.TYPE_INT_RGB); 197: } 198: 199: /** 200: * Create an image type specifier that describes the given buffered 201: * image type. 202: * 203: * @param bufferedImageType the buffered image type to represent 204: * with the returned image type specifier 205: * 206: * @return a new image type specifier 207: * 208: * @exception IllegalArgumentException if bufferedImageType is not a 209: * BufferedImage constant or is BufferedImage.TYPE_CUSTOM 210: */ 211: public static ImageTypeSpecifier createFromBufferedImageType (int bufferedImageType) 212: { 213: if (bufferedImageType <= BufferedImage.TYPE_CUSTOM 214: || bufferedImageType > BufferedImage.TYPE_BYTE_INDEXED) 215: throw new IllegalArgumentException ("invalid buffered image type"); 216: 217: return new ImageTypeSpecifier (new BufferedImage (1, 1, bufferedImageType)); 218: } 219: 220: /** 221: * Create an image type specifier that describes the given rendered 222: * image's type. 223: * 224: * @param image the rendered image 225: * 226: * @return a new image type specifier 227: * 228: * @exception IllegalArgumentException if image is null 229: */ 230: public static ImageTypeSpecifier createFromRenderedImage (RenderedImage image) 231: { 232: if (image == null) 233: throw new IllegalArgumentException ("image null"); 234: 235: return new ImageTypeSpecifier (image); 236: } 237: 238: /** 239: * Create a grayscale image type specifier, given the number of 240: * bits, data type and whether or not the data is signed. 241: * 242: * @param bits the number of bits used to specify a greyscale value 243: * @param dataType a DataBuffer type constant 244: * @param isSigned true if this type specifier should support 245: * negative values, false otherwise 246: * 247: * @return a greyscal image type specifier 248: * 249: * @exception IllegalArgumentException if bits is not 1, 2, 4, 8 or 16 250: * @exception IllegalArgumentException if dataType is not 251: * DataBuffer.TYPE_BYTE, DataBuffer.TYPE_SHORT or 252: * DataBuffer.TYPE_USHORT 253: * @exception if bits is larger than the number of bits in the given 254: * data type 255: */ 256: public static ImageTypeSpecifier createGrayscale (int bits, int dataType, boolean isSigned) 257: { 258: return createGrayscale (bits, dataType, isSigned, false); 259: } 260: 261: /** 262: * Create a grayscale image type specifier, given the number of 263: * bits, data type and whether or not the data is signed. 264: * 265: * @param bits the number of bits used to specify a greyscale value 266: * @param dataType a DataBuffer type constant 267: * @param isSigned true if this type specifier should support 268: * negative values, false otherwise 269: * 270: * @return a greyscal image type specifier 271: * 272: * @exception IllegalArgumentException if bits is not 1, 2, 4, 8 or 273: * 16 274: * @exception IllegalArgumentException if dataType is not 275: * DataBuffer.TYPE_BYTE, DataBuffer.TYPE_SHORT or 276: * DataBuffer.TYPE_USHORT 277: * @exception if bits is larger than the number of bits in the given 278: * data type 279: */ 280: public static ImageTypeSpecifier createGrayscale (int bits, int dataType, 281: boolean isSigned, 282: boolean isAlphaPremultiplied) 283: { 284: if (bits != 1 && bits != 2 && bits != 4 && bits != 8 && bits != 16) 285: throw new IllegalArgumentException ("invalid bit size"); 286: 287: if (dataType != DataBuffer.TYPE_BYTE && dataType != DataBuffer.TYPE_SHORT 288: && dataType != DataBuffer.TYPE_USHORT) 289: throw new IllegalArgumentException ("invalid data type"); 290: 291: if (dataType == DataBuffer.TYPE_BYTE && bits > 8) 292: throw new IllegalArgumentException ("number of bits too large for data type"); 293: 294: // FIXME: this is probably wrong: 295: return new ImageTypeSpecifier (new DirectColorModel (bits, 0xff, 0x0, 296: 0x0, 0xff), 297: new MultiPixelPackedSampleModel (dataType, 298: 1, 1, 299: bits)); 300: } 301: 302: /** 303: * Return an image type specifier for an image that uses an indexed 304: * colour model where each colour value has the specified number of 305: * bits and type and where the colour tables are those given. 306: * 307: * @param redLUT the red index values 308: * @param greenLUT the green index values 309: * @param blueLUT the blue index values 310: * @param alphaLUT the alpha index values 311: * @param bits the number of bits per index value 312: * @param dataType the type of each index value 313: * 314: * @return an indexed image type specifier 315: * 316: * @exception IllegalArgumentException if any of the colour arrays, 317: * not including alphaLUT, is null 318: * @exception IllegalArgumentException if bits is not 1, 2, 4, 8 or 319: * 16 320: * @exception IllegalArgumentException if dataType is not 321: * DataBuffer.TYPE_BYTE, DataBuffer.TYPE_SHORT or 322: * DataBuffer.TYPE_USHORT 323: * @exception if bits is larger than the number of bits in the given 324: * data type 325: */ 326: public static ImageTypeSpecifier createIndexed (byte[] redLUT, 327: byte[] greenLUT, 328: byte[] blueLUT, 329: byte[] alphaLUT, 330: int bits, 331: int dataType) 332: { 333: if (redLUT == null || greenLUT == null || blueLUT == null) 334: throw new IllegalArgumentException ("null colour table"); 335: 336: if (bits != 1 && bits != 2 && bits != 4 && bits != 8 && bits != 16) 337: throw new IllegalArgumentException ("invalid bit size"); 338: 339: if (dataType != DataBuffer.TYPE_BYTE && dataType != DataBuffer.TYPE_SHORT 340: && dataType != DataBuffer.TYPE_USHORT) 341: throw new IllegalArgumentException ("invalid data type"); 342: 343: if (dataType == DataBuffer.TYPE_BYTE && bits > 8) 344: throw new IllegalArgumentException ("number of bits too large for data type"); 345: 346: // FIXME: this is probably wrong: 347: return new ImageTypeSpecifier (new IndexColorModel (bits, redLUT.length, 348: redLUT, greenLUT, blueLUT, 349: alphaLUT), 350: new MultiPixelPackedSampleModel (dataType, 351: 1, 1, 352: bits)); 353: } 354: 355: /** 356: * Create an image type specifier that uses a component colour model 357: * and a pixel interleaved sample model. Each pixel component will 358: * be stored in a separate value of the given data type. 359: * 360: * @param colorSpace the colour space used by the colour model 361: * @param bandOffsets the starting band offset for each band within 362: * its bank 363: * @param dataType the type of each pixel value 364: * @param hasAlpha true if an alpha channel should be specified, 365: * false otherwise 366: * @param isAlphaPremultiplied true if other colour channels should 367: * be premultiplied by the alpha value, false otherwise 368: * 369: * @return an interleaved image type specifier 370: * 371: * @exception IllegalArgumentException if either colorSpace or 372: * bandOffsets is null 373: * @excpetion IllegalArgumentException if the number of color space 374: * components, including the alpha component if requested, is 375: * different from bandOffsets.length 376: * @exception if dataType is not a valid DataBuffer constant 377: */ 378: public static ImageTypeSpecifier createInterleaved (ColorSpace colorSpace, 379: int[] bandOffsets, 380: int dataType, 381: boolean hasAlpha, 382: boolean isAlphaPremultiplied) 383: { 384: if (colorSpace == null || bandOffsets == null) 385: throw new IllegalArgumentException ("null argument"); 386: 387: if (bandOffsets.length != (colorSpace.getNumComponents() + (hasAlpha ? 1 : 0))) 388: throw new IllegalArgumentException ("invalid bankOffsets length"); 389: 390: return new ImageTypeSpecifier (new ComponentColorModel (colorSpace, 391: hasAlpha, 392: isAlphaPremultiplied, 393: hasAlpha ? Transparency.TRANSLUCENT : Transparency.OPAQUE, 394: dataType), 395: new PixelInterleavedSampleModel (dataType, 1, 1, 1, 1, 396: bandOffsets)); 397: } 398: 399: /** 400: * Create an image type specifier using a direct color model and a 401: * packed sample model. All pixel components will be packed into 402: * one value of the given data type. 403: * 404: * @param colorSpace the color space to use in the color model 405: * @param redMask the bitmask for the red bits 406: * @param greenMask the bitmask for the green bits 407: * @param blueMask the bitmask for the blue bits 408: * @param alphaMask the bitmask for the alpha bits 409: * @param transferType the data type used to store pixel values 410: * @param isAlphaPremultiplied true if other colour channels should 411: * be premultiplied by the alpha value, false otherwise 412: * 413: * @return a packed image type specifier 414: * 415: * @exception IllegalArgumentException if colorSpace is null 416: * @exception IllegalArgumentException if colorSpace does not have 417: * type ColorSpace.TYPE_RGB 418: * @exception IllegalArgumentException if all masks are 0 419: * @exception IllegalArgumentException if dataType is not 420: * DataBuffer.TYPE_BYTE, DataBuffer.TYPE_SHORT or 421: * DataBuffer.TYPE_INT 422: */ 423: public static ImageTypeSpecifier createPacked (ColorSpace colorSpace, 424: int redMask, 425: int greenMask, 426: int blueMask, 427: int alphaMask, 428: int transferType, 429: boolean isAlphaPremultiplied) 430: { 431: if (colorSpace == null) 432: throw new IllegalArgumentException ("null color space"); 433: 434: if (colorSpace.getType() != ColorSpace.TYPE_RGB) 435: throw new IllegalArgumentException ("invalid color space type"); 436: 437: if (redMask == 0 && greenMask == 0 && blueMask == 0 && alphaMask == 0) 438: throw new IllegalArgumentException ("no non-zero mask"); 439: 440: if (transferType != DataBuffer.TYPE_BYTE && transferType != DataBuffer.TYPE_USHORT 441: && transferType != DataBuffer.TYPE_INT) 442: throw new IllegalArgumentException ("invalid data type"); 443: 444: // Assume DataBuffer.TYPE_BYTE. 445: int numBits = 8; 446: 447: if (transferType == DataBuffer.TYPE_SHORT) 448: numBits = 16; 449: else if (transferType == DataBuffer.TYPE_INT) 450: numBits = 32; 451: 452: return new ImageTypeSpecifier (new DirectColorModel (colorSpace, 453: numBits, 454: redMask, 455: greenMask, 456: blueMask, 457: alphaMask, 458: isAlphaPremultiplied, 459: transferType), 460: new MultiPixelPackedSampleModel (transferType, 461: 1, 1, numBits)); 462: } 463: 464: /** 465: * Get the number of bits per sample in the given band. 466: * 467: * @param band the band from which to get the number of bits 468: * 469: * @return the number of bits in the given band 470: * 471: * @exception IllegalArgumentException if band is out-of-bounds 472: */ 473: public int getBitsPerBand (int band) 474: { 475: if (band < 0 || band > sampleModel.getNumBands()) 476: throw new IllegalArgumentException ("band out-of-bounds"); 477: 478: return sampleModel.getSampleSize (band); 479: } 480: 481: /** 482: * Get the buffered image constant specified by this image type 483: * specifier. 484: * 485: * @return a buffered image constant 486: */ 487: public int getBufferedImageType () 488: { 489: // FIXME: 490: return BufferedImage.TYPE_INT_RGB; 491: } 492: 493: /** 494: * Create a sample model that is compatible with the one specified 495: * by this image type specifier, with the given dimensions. 496: * 497: * @param width the width of the returned sample model 498: * @param height the height of the returned sample model 499: * 500: * @return a sample model compatible with the one in this image type 501: * specifier, with the given dimensions 502: * 503: * @exception IllegalArgumentException if either width or height is 504: * less than or equal to 0 505: * @exception IllegalArgumentException if width * height is greater 506: * than Intere.MAX_VALUE 507: */ 508: public SampleModel getSampleModel (int width, int height) 509: { 510: if (width <= 0 || height <= 0) 511: throw new IllegalArgumentException ("invalid dimension"); 512: 513: // test for overflow 514: if (width * height < Math.min (width, height)) 515: throw new IllegalArgumentException ("width * height > Integer.MAX_VALUE"); 516: 517: return sampleModel.createCompatibleSampleModel (width, height); 518: } 519: 520: /** 521: * Get the color model specified by this image type specifier. 522: * 523: * @return the color model 524: */ 525: public ColorModel getColorModel() 526: { 527: return colorModel; 528: } 529: 530: /** 531: * Get the number of bands specified by this image type specifier's 532: * sample model. 533: * 534: * @return the number of bands in the sample model 535: */ 536: public int getNumBands() 537: { 538: return sampleModel.getNumBands(); 539: } 540: 541: /** 542: * Get the number of components specified by this image type 543: * specifier's color model. 544: * 545: * @return the number of color components per pixel 546: */ 547: public int getNumComponents() 548: { 549: return colorModel.getNumComponents(); 550: } 551: 552: /** 553: * Get the sample model specified by this image type specifier. 554: * 555: * @return the sample model 556: */ 557: public SampleModel getSampleModel() 558: { 559: return sampleModel; 560: } 561: }