Source for javax.imageio.ImageTypeSpecifier

   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 bandOffsets 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 the width of the buffered image, in pixels
 172:    * @param 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: }