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 */ ImageTypeSpecifier(ColorModel colorModel, SampleModel sampleModel)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 */ ImageTypeSpecifier(RenderedImage image)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 */ createBanded(ColorSpace colorSpace, int[] bankIndices, int[] bankOffsets, int dataType, boolean hasAlpha, boolean isAlphaPremultiplied)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 */ createBufferedImage(int width, int height)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 */ createFromBufferedImageType(int bufferedImageType)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 */ createFromRenderedImage(RenderedImage image)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 */ createGrayscale(int bits, int dataType, boolean isSigned)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 */ createGrayscale(int bits, int dataType, boolean isSigned, boolean isAlphaPremultiplied)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 */ createIndexed(byte[] redLUT, byte[] greenLUT, byte[] blueLUT, byte[] alphaLUT, int bits, int dataType)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 */ createInterleaved(ColorSpace colorSpace, int[] bandOffsets, int dataType, boolean hasAlpha, boolean isAlphaPremultiplied)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 */ createPacked(ColorSpace colorSpace, int redMask, int greenMask, int blueMask, int alphaMask, int transferType, boolean isAlphaPremultiplied)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 */ getBitsPerBand(int band)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 */ getBufferedImageType()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 */ getSampleModel(int width, int height)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 */ getColorModel()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 */ getNumBands()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 */ getNumComponents()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 */ getSampleModel()557 public SampleModel getSampleModel() 558 { 559 return sampleModel; 560 } 561 } 562