KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > batik > ext > awt > image > codec > tiff > TIFFImage


1 /*
2
3    Copyright 2001,2003 The Apache Software Foundation
4
5    Licensed under the Apache License, Version 2.0 (the "License");
6    you may not use this file except in compliance with the License.
7    You may obtain a copy of the License at
8
9        http://www.apache.org/licenses/LICENSE-2.0
10
11    Unless required by applicable law or agreed to in writing, software
12    distributed under the License is distributed on an "AS IS" BASIS,
13    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14    See the License for the specific language governing permissions and
15    limitations under the License.
16
17  */

18 package org.apache.batik.ext.awt.image.codec.tiff;
19
20 import java.awt.Rectangle JavaDoc;
21 import java.awt.Transparency JavaDoc;
22 import java.awt.color.ColorSpace JavaDoc;
23 import java.awt.image.ColorModel JavaDoc;
24 import java.awt.image.ComponentColorModel JavaDoc;
25 import java.awt.image.DataBuffer JavaDoc;
26 import java.awt.image.DataBufferByte JavaDoc;
27 import java.awt.image.DataBufferInt JavaDoc;
28 import java.awt.image.DataBufferShort JavaDoc;
29 import java.awt.image.DataBufferUShort JavaDoc;
30 import java.awt.image.IndexColorModel JavaDoc;
31 import java.awt.image.MultiPixelPackedSampleModel JavaDoc;
32 import java.awt.image.PixelInterleavedSampleModel JavaDoc;
33 import java.awt.image.Raster JavaDoc;
34 import java.awt.image.SampleModel JavaDoc;
35 import java.awt.image.WritableRaster JavaDoc;
36 import java.io.ByteArrayInputStream JavaDoc;
37 import java.io.IOException JavaDoc;
38 import java.util.HashMap JavaDoc;
39 import java.util.Map JavaDoc;
40 import java.util.zip.DataFormatException JavaDoc;
41 import java.util.zip.Inflater JavaDoc;
42
43 import org.apache.batik.ext.awt.image.codec.SeekableStream;
44 import org.apache.batik.ext.awt.image.rendered.AbstractRed;
45 import org.apache.batik.ext.awt.image.rendered.CachableRed;
46
47 import com.sun.image.codec.jpeg.JPEGCodec;
48 import com.sun.image.codec.jpeg.JPEGDecodeParam;
49 import com.sun.image.codec.jpeg.JPEGImageDecoder;
50
51 public class TIFFImage extends AbstractRed {
52
53     // Compression types
54
public static final int COMP_NONE = 1;
55     public static final int COMP_FAX_G3_1D = 2;
56     public static final int COMP_FAX_G3_2D = 3;
57     public static final int COMP_FAX_G4_2D = 4;
58     public static final int COMP_LZW = 5;
59     public static final int COMP_JPEG_OLD = 6;
60     public static final int COMP_JPEG_TTN2 = 7;
61     public static final int COMP_PACKBITS = 32773;
62     public static final int COMP_DEFLATE = 32946;
63
64     // Image types
65
private static final int TYPE_UNSUPPORTED = -1;
66     private static final int TYPE_BILEVEL = 0;
67     private static final int TYPE_GRAY_4BIT = 1;
68     private static final int TYPE_GRAY = 2;
69     private static final int TYPE_GRAY_ALPHA = 3;
70     private static final int TYPE_PALETTE = 4;
71     private static final int TYPE_RGB = 5;
72     private static final int TYPE_RGB_ALPHA = 6;
73     private static final int TYPE_YCBCR_SUB = 7;
74     private static final int TYPE_GENERIC = 8;
75
76     // Incidental tags
77
private static final int TIFF_JPEG_TABLES = 347;
78     private static final int TIFF_YCBCR_SUBSAMPLING = 530;
79
80     SeekableStream stream;
81     int tileSize;
82     int tilesX, tilesY;
83     long[] tileOffsets;
84     long[] tileByteCounts;
85     char[] colormap;
86     int sampleSize;
87     int compression;
88     byte[] palette;
89     int numBands;
90
91     int chromaSubH;
92     int chromaSubV;
93
94     // Fax compression related variables
95
long tiffT4Options;
96     long tiffT6Options;
97     int fillOrder;
98
99     // LZW compression related variable
100
int predictor;
101
102     // TTN2 JPEG related variables
103
JPEGDecodeParam decodeParam = null;
104     boolean colorConvertJPEG = false;
105
106     // DEFLATE variables
107
Inflater JavaDoc inflater = null;
108
109     // Endian-ness indicator
110
boolean isBigEndian;
111     
112     int imageType;
113     boolean isWhiteZero = false;
114     int dataType;
115
116     boolean decodePaletteAsShorts;
117     boolean tiled;
118
119     // Decoders
120
private TIFFFaxDecoder decoder = null;
121     private TIFFLZWDecoder lzwDecoder = null;
122
123     /**
124      * Decode a buffer of data into a Raster with the specified location.
125      *
126      * @param data buffer contain an interchange or abbreviated datastream.
127      * @param decodeParam decoding parameters; may be null unless the
128      * data buffer contains an abbreviated datastream in which case
129      * it may not be null or an error will occur.
130      * @param colorConvert whether to perform color conversion; in this
131      * case that would be limited to YCbCr-to-RGB.
132      * @param minX the X position of the returned Raster.
133      * @param minY the Y position of the returned Raster.
134      */

135     private static final Raster JavaDoc decodeJPEG(byte[] data,
136                                            JPEGDecodeParam decodeParam,
137                                            boolean colorConvert,
138                                            int minX,
139                                            int minY) {
140         // Create an InputStream from the compressed data array.
141
ByteArrayInputStream JavaDoc jpegStream = new ByteArrayInputStream JavaDoc(data);
142
143         // Create a decoder.
144
JPEGImageDecoder decoder = decodeParam == null ?
145             JPEGCodec.createJPEGDecoder(jpegStream) :
146             JPEGCodec.createJPEGDecoder(jpegStream,
147                                         decodeParam);
148
149         // Decode the compressed data into a Raster.
150
Raster JavaDoc jpegRaster;
151         try {
152             jpegRaster = colorConvert ?
153                 decoder.decodeAsBufferedImage().getWritableTile(0, 0) :
154                 decoder.decodeAsRaster();
155         } catch (IOException JavaDoc ioe) {
156             throw new RuntimeException JavaDoc("TIFFImage13");
157         }
158
159         // Translate the decoded Raster to the specified location and return.
160
return jpegRaster.createTranslatedChild(minX, minY);
161     }
162
163     /**
164      * Inflates <code>deflated</code> into <code>inflated</code> using the
165      * <code>Inflater</code> constructed during class instantiation.
166      */

167     private final void inflate(byte[] deflated, byte[] inflated) {
168         inflater.setInput(deflated);
169         try {
170             inflater.inflate(inflated);
171         } catch(DataFormatException JavaDoc dfe) {
172             throw new RuntimeException JavaDoc("TIFFImage17"+": "+
173                                        dfe.getMessage());
174         }
175         inflater.reset();
176     }
177
178     private static SampleModel JavaDoc createPixelInterleavedSampleModel
179         (int dataType, int tileWidth, int tileHeight, int bands) {
180         int [] bandOffsets = new int[bands];
181         for (int i=0; i<bands; i++)
182             bandOffsets[i] = i;
183         return new PixelInterleavedSampleModel JavaDoc
184             (dataType, tileWidth, tileHeight, bands,
185              tileWidth*bands, bandOffsets);
186     }
187
188     /**
189      * Return as a long[] the value of a TIFF_LONG or TIFF_SHORT field.
190      */

191     private final long[] getFieldAsLongs(TIFFField field) {
192         long[] value = null;
193
194         if(field.getType() == TIFFField.TIFF_SHORT) {
195             char[] charValue = field.getAsChars();
196             value = new long[charValue.length];
197             for(int i = 0; i < charValue.length; i++) {
198                 value[i] = charValue[i] & 0xffff;
199             }
200         } else if(field.getType() == TIFFField.TIFF_LONG) {
201             value = field.getAsLongs();
202         } else {
203             throw new RuntimeException JavaDoc();
204         }
205
206         return value;
207     }
208
209     /**
210      * Constructs a TIFFImage that acquires its data from a given
211      * SeekableStream and reads from a particular IFD of the stream.
212      * The index of the first IFD is 0.
213      *
214      * @param stream the SeekableStream to read from.
215      * @param param an instance of TIFFDecodeParam, or null.
216      * @param directory the index of the IFD to read from.
217      */

218     public TIFFImage(SeekableStream stream,
219                      TIFFDecodeParam param,
220                      int directory)
221         throws IOException JavaDoc {
222
223         this.stream = stream;
224         if (param == null) {
225             param = new TIFFDecodeParam();
226         }
227
228         decodePaletteAsShorts = param.getDecodePaletteAsShorts();
229
230         // Read the specified directory.
231
TIFFDirectory dir = param.getIFDOffset() == null ?
232             new TIFFDirectory(stream, directory) :
233             new TIFFDirectory(stream, param.getIFDOffset().longValue(),
234                               directory);
235
236         // Get the number of samples per pixel
237
TIFFField sfield = dir.getField(TIFFImageDecoder.TIFF_SAMPLES_PER_PIXEL);
238         int samplesPerPixel = sfield == null ? 1 : (int)sfield.getAsLong(0);
239
240         // Read the TIFF_PLANAR_CONFIGURATION field
241
TIFFField planarConfigurationField =
242             dir.getField(TIFFImageDecoder.TIFF_PLANAR_CONFIGURATION);
243         char[] planarConfiguration = planarConfigurationField == null ?
244             new char[] {1} :
245             planarConfigurationField.getAsChars();
246
247             // Support planar format (band sequential) only for 1 sample/pixel.
248
if (planarConfiguration[0] != 1 && samplesPerPixel != 1) {
249                 throw new RuntimeException JavaDoc("TIFFImage0");
250             }
251
252             // Read the TIFF_BITS_PER_SAMPLE field
253
TIFFField bitsField =
254                 dir.getField(TIFFImageDecoder.TIFF_BITS_PER_SAMPLE);
255             char[] bitsPerSample = null;
256             if(bitsField != null) {
257                 bitsPerSample = bitsField.getAsChars();
258             } else {
259                 bitsPerSample = new char[] {1};
260
261                 // Ensure that all samples have the same bit depth.
262
for (int i = 1; i < bitsPerSample.length; i++) {
263                     if (bitsPerSample[i] != bitsPerSample[0]) {
264                         throw new RuntimeException JavaDoc("TIFFImage1");
265                     }
266                 }
267             }
268             sampleSize = bitsPerSample[0];
269
270             // Read the TIFF_SAMPLE_FORMAT tag to see whether the data might be
271
// signed or floating point
272
TIFFField sampleFormatField =
273                 dir.getField(TIFFImageDecoder.TIFF_SAMPLE_FORMAT);
274
275             char[] sampleFormat = null;
276             if (sampleFormatField != null) {
277                 sampleFormat = sampleFormatField.getAsChars();
278
279                 // Check that all the samples have the same format
280
for (int l=1; l<sampleFormat.length; l++) {
281                     if (sampleFormat[l] != sampleFormat[0]) {
282                         throw new RuntimeException JavaDoc("TIFFImage2");
283                     }
284                 }
285
286             } else {
287                 sampleFormat = new char[] {1};
288             }
289
290             // Set the data type based on the sample size and format.
291
boolean isValidDataFormat = false;
292             switch(sampleSize) {
293             case 1:
294             case 4:
295             case 8:
296                 if(sampleFormat[0] != 3) {
297                     // Ignore whether signed or unsigned: treat all as unsigned.
298
dataType = DataBuffer.TYPE_BYTE;
299                     isValidDataFormat = true;
300                 }
301                 break;
302             case 16:
303                 if(sampleFormat[0] != 3) {
304                     dataType = sampleFormat[0] == 2 ?
305                         DataBuffer.TYPE_SHORT : DataBuffer.TYPE_USHORT;
306                     isValidDataFormat = true;
307                 }
308                 break;
309             case 32:
310               if (sampleFormat[0] == 3)
311                 isValidDataFormat = false;
312               else {
313                 dataType = DataBuffer.TYPE_INT;
314                 isValidDataFormat = true;
315               }
316               break;
317             }
318
319             if(!isValidDataFormat) {
320                 throw new RuntimeException JavaDoc("TIFFImage3");
321             }
322
323             // Figure out what compression if any, is being used.
324
TIFFField compField = dir.getField(TIFFImageDecoder.TIFF_COMPRESSION);
325             compression = compField == null ? COMP_NONE : compField.getAsInt(0);
326
327             // Get the photometric interpretation.
328
int photometricType = (int)dir.getFieldAsLong(
329                                                           TIFFImageDecoder.TIFF_PHOTOMETRIC_INTERPRETATION);
330
331             // Determine which kind of image we are dealing with.
332
imageType = TYPE_UNSUPPORTED;
333             switch(photometricType) {
334             case 0: // WhiteIsZero
335
isWhiteZero = true;
336             case 1: // BlackIsZero
337
if(sampleSize == 1 && samplesPerPixel == 1) {
338                     imageType = TYPE_BILEVEL;
339                 } else if(sampleSize == 4 && samplesPerPixel == 1) {
340                     imageType = TYPE_GRAY_4BIT;
341                 } else if(sampleSize % 8 == 0) {
342                     if(samplesPerPixel == 1) {
343                         imageType = TYPE_GRAY;
344                     } else if(samplesPerPixel == 2) {
345                         imageType = TYPE_GRAY_ALPHA;
346                     } else {
347                         imageType = TYPE_GENERIC;
348                     }
349                 }
350                 break;
351             case 2: // RGB
352
if(sampleSize % 8 == 0) {
353                     if(samplesPerPixel == 3) {
354                         imageType = TYPE_RGB;
355                     } else if(samplesPerPixel == 4) {
356                         imageType = TYPE_RGB_ALPHA;
357                     } else {
358                         imageType = TYPE_GENERIC;
359                     }
360                 }
361                 break;
362             case 3: // RGB Palette
363
if(samplesPerPixel == 1 &&
364                    (sampleSize == 4 || sampleSize == 8 || sampleSize == 16)) {
365                     imageType = TYPE_PALETTE;
366                 }
367                 break;
368             case 4: // Transparency mask
369
if(sampleSize == 1 && samplesPerPixel == 1) {
370                     imageType = TYPE_BILEVEL;
371                 }
372                 break;
373             case 6: // YCbCr
374
if(compression == COMP_JPEG_TTN2 &&
375                    sampleSize == 8 && samplesPerPixel == 3) {
376                     // Set color conversion flag.
377
colorConvertJPEG = param.getJPEGDecompressYCbCrToRGB();
378
379                     // Set type to RGB if color converting.
380
imageType = colorConvertJPEG ? TYPE_RGB : TYPE_GENERIC;
381                 } else {
382                     TIFFField chromaField = dir.getField(TIFF_YCBCR_SUBSAMPLING);
383                     if(chromaField != null) {
384                         chromaSubH = chromaField.getAsInt(0);
385                         chromaSubV = chromaField.getAsInt(1);
386                     } else {
387                         chromaSubH = chromaSubV = 2;
388                     }
389
390                     if(chromaSubH*chromaSubV == 1) {
391                         imageType = TYPE_GENERIC;
392                     } else if(sampleSize == 8 && samplesPerPixel == 3) {
393                         imageType = TYPE_YCBCR_SUB;
394                     }
395                 }
396                 break;
397             default: // Other including CMYK, CIE L*a*b*, unknown.
398
if(sampleSize % 8 == 0) {
399                     imageType = TYPE_GENERIC;
400                 }
401             }
402
403             // Bail out if not one of the supported types.
404
if(imageType == TYPE_UNSUPPORTED) {
405                 throw new RuntimeException JavaDoc("TIFFImage4");
406             }
407
408             // Set basic image layout
409
Rectangle JavaDoc bounds = new Rectangle JavaDoc
410                 (0, 0,
411                  (int)dir.getFieldAsLong(TIFFImageDecoder.TIFF_IMAGE_WIDTH),
412                  (int)dir.getFieldAsLong(TIFFImageDecoder.TIFF_IMAGE_LENGTH));
413
414             // Set a preliminary band count. This may be changed later as needed.
415
numBands = samplesPerPixel;
416
417             // Figure out if any extra samples are present.
418
TIFFField efield = dir.getField(TIFFImageDecoder.TIFF_EXTRA_SAMPLES);
419             int extraSamples = efield == null ? 0 : (int)efield.getAsLong(0);
420
421             int tileWidth, tileHeight;
422             if (dir.getField(TIFFImageDecoder.TIFF_TILE_OFFSETS) != null) {
423                 tiled = true;
424                 // Image is in tiled format
425
tileWidth =
426                     (int)dir.getFieldAsLong(TIFFImageDecoder.TIFF_TILE_WIDTH);
427                 tileHeight =
428                     (int)dir.getFieldAsLong(TIFFImageDecoder.TIFF_TILE_LENGTH);
429                 tileOffsets =
430                     (dir.getField(TIFFImageDecoder.TIFF_TILE_OFFSETS)).getAsLongs();
431                 tileByteCounts =
432                     getFieldAsLongs(dir.getField(TIFFImageDecoder.TIFF_TILE_BYTE_COUNTS));
433
434             } else {
435                 tiled = false;
436
437                 // Image is in stripped format, looks like tiles to us
438
// Note: Some legacy files may have tile width and height
439
// written but use the strip offsets and byte counts fields
440
// instead of the tile offsets and byte counts. Therefore
441
// we default here to the tile dimensions if they are written.
442
tileWidth =
443                     dir.getField(TIFFImageDecoder.TIFF_TILE_WIDTH) != null ?
444                     (int)dir.getFieldAsLong(TIFFImageDecoder.TIFF_TILE_WIDTH) :
445                     bounds.width;
446                 TIFFField field =
447                     dir.getField(TIFFImageDecoder.TIFF_ROWS_PER_STRIP);
448                 if (field == null) {
449                     // Default is infinity (2^32 -1), basically the entire image
450

451                     tileHeight =
452                         dir.getField(TIFFImageDecoder.TIFF_TILE_LENGTH) != null ?
453                         (int)dir.getFieldAsLong(TIFFImageDecoder.TIFF_TILE_LENGTH):
454                         bounds.height;
455                 } else {
456                     long l = field.getAsLong(0);
457                     long infinity = 1;
458                     infinity = (infinity << 32) - 1;
459                     if (l == infinity) {
460                         // 2^32 - 1 (effectively infinity, entire image is 1 strip)
461
tileHeight = bounds.height;
462                     } else {
463                         tileHeight = (int)l;
464                     }
465                 }
466
467                 TIFFField tileOffsetsField =
468                     dir.getField(TIFFImageDecoder.TIFF_STRIP_OFFSETS);
469                 if (tileOffsetsField == null) {
470                     throw new RuntimeException JavaDoc("TIFFImage5");
471                 } else {
472                     tileOffsets = getFieldAsLongs(tileOffsetsField);
473                 }
474
475                 TIFFField tileByteCountsField =
476                     dir.getField(TIFFImageDecoder.TIFF_STRIP_BYTE_COUNTS);
477                 if (tileByteCountsField == null) {
478                     throw new RuntimeException JavaDoc("TIFFImage6");
479                 } else {
480                     tileByteCounts = getFieldAsLongs(tileByteCountsField);
481                 }
482             }
483
484             // Calculate number of tiles and the tileSize in bytes
485
tilesX = (bounds.width + tileWidth - 1)/tileWidth;
486             tilesY = (bounds.height + tileHeight - 1)/tileHeight;
487             tileSize = tileWidth * tileHeight * numBands;
488
489             // Check whether big endian or little endian format is used.
490
isBigEndian = dir.isBigEndian();
491
492             TIFFField fillOrderField =
493                 dir.getField(TIFFImageDecoder.TIFF_FILL_ORDER);
494             if (fillOrderField != null) {
495                 fillOrder = fillOrderField.getAsInt(0);
496             } else {
497                 // Default Fill Order
498
fillOrder = 1;
499             }
500
501             switch(compression) {
502             case COMP_NONE:
503             case COMP_PACKBITS:
504                 // Do nothing.
505
break;
506             case COMP_DEFLATE:
507                 inflater = new Inflater JavaDoc();
508                 break;
509             case COMP_FAX_G3_1D:
510             case COMP_FAX_G3_2D:
511             case COMP_FAX_G4_2D:
512                 if(sampleSize != 1) {
513                     throw new RuntimeException JavaDoc("TIFFImage7");
514                 }
515
516                 // Fax T.4 compression options
517
if (compression == 3) {
518                     TIFFField t4OptionsField =
519                         dir.getField(TIFFImageDecoder.TIFF_T4_OPTIONS);
520                     if (t4OptionsField != null) {
521                         tiffT4Options = t4OptionsField.getAsLong(0);
522                     } else {
523                         // Use default value
524
tiffT4Options = 0;
525                     }
526                 }
527
528                 // Fax T.6 compression options
529
if (compression == 4) {
530                     TIFFField t6OptionsField =
531                         dir.getField(TIFFImageDecoder.TIFF_T6_OPTIONS);
532                     if (t6OptionsField != null) {
533                         tiffT6Options = t6OptionsField.getAsLong(0);
534                     } else {
535                         // Use default value
536
tiffT6Options = 0;
537                     }
538                 }
539
540                 // Fax encoding, need to create the Fax decoder.
541
decoder = new TIFFFaxDecoder(fillOrder,
542                                              tileWidth, tileHeight);
543                 break;
544
545             case COMP_LZW:
546                 // LZW compression used, need to create the LZW decoder.
547
TIFFField predictorField =
548                     dir.getField(TIFFImageDecoder.TIFF_PREDICTOR);
549
550                 if (predictorField == null) {
551                     predictor = 1;
552                 } else {
553                     predictor = predictorField.getAsInt(0);
554             
555                     if (predictor != 1 && predictor != 2) {
556                         throw new RuntimeException JavaDoc("TIFFImage8");
557                     }
558             
559                     if (predictor == 2 && sampleSize != 8) {
560                         throw new RuntimeException JavaDoc(sampleSize +
561                                                    "TIFFImage9");
562                     }
563                 }
564         
565                 lzwDecoder = new TIFFLZWDecoder(tileWidth, predictor,
566                                                 samplesPerPixel);
567                 break;
568
569             case COMP_JPEG_OLD:
570                 throw new RuntimeException JavaDoc("TIFFImage15");
571
572             case COMP_JPEG_TTN2:
573                 if(!(sampleSize == 8 &&
574                      ((imageType == TYPE_GRAY && samplesPerPixel == 1) ||
575                       (imageType == TYPE_PALETTE && samplesPerPixel == 1) ||
576                       (imageType == TYPE_RGB && samplesPerPixel == 3)))) {
577                     throw new RuntimeException JavaDoc("TIFFImage16");
578                 }
579
580                 // Create decodeParam from JPEGTables field if present.
581
if(dir.isTagPresent(TIFF_JPEG_TABLES)) {
582                     TIFFField jpegTableField = dir.getField(TIFF_JPEG_TABLES);
583                     byte[] jpegTable = jpegTableField.getAsBytes();
584                     ByteArrayInputStream JavaDoc tableStream =
585                         new ByteArrayInputStream JavaDoc(jpegTable);
586                     JPEGImageDecoder decoder =
587                         JPEGCodec.createJPEGDecoder(tableStream);
588                     decoder.decodeAsRaster();
589                     decodeParam = decoder.getJPEGDecodeParam();
590                 }
591
592                 break;
593             default:
594                 throw new RuntimeException JavaDoc("TIFFImage10");
595             }
596
597             ColorModel JavaDoc colorModel = null;
598             SampleModel JavaDoc sampleModel = null;
599             switch(imageType) {
600             case TYPE_BILEVEL:
601             case TYPE_GRAY_4BIT:
602                 sampleModel =
603                     new MultiPixelPackedSampleModel JavaDoc(dataType,
604                                                     tileWidth,
605                                                     tileHeight,
606                                                     sampleSize);
607                 if(imageType == TYPE_BILEVEL) {
608                     byte[] map = new byte[] {(byte)(isWhiteZero ? 255 : 0),
609                                              (byte)(isWhiteZero ? 0 : 255)};
610                     colorModel = new IndexColorModel JavaDoc(1, 2, map, map, map);
611                 } else {
612                     byte [] map = new byte[16];
613                     if (isWhiteZero) {
614                         for (int i=0; i<map.length; i++)
615                             map[i] = (byte)(255-(16*i));
616                     } else {
617                         for (int i=0; i<map.length; i++)
618                             map[i] = (byte)(16*i);
619                     }
620                     colorModel = new IndexColorModel JavaDoc(4, 16, map, map, map);
621                 }
622                 break;
623
624             case TYPE_GRAY:
625             case TYPE_GRAY_ALPHA:
626             case TYPE_RGB:
627             case TYPE_RGB_ALPHA:
628                 // Create a pixel interleaved SampleModel with decreasing
629
// band offsets.
630
int[] reverseOffsets = new int[numBands];
631                 for (int i=0; i<numBands; i++) {
632                     reverseOffsets[i] = numBands - 1 - i;
633                 }
634                 sampleModel = new PixelInterleavedSampleModel JavaDoc
635                     (dataType, tileWidth, tileHeight,
636                      numBands, numBands*tileWidth, reverseOffsets);
637
638                 if(imageType == TYPE_GRAY) {
639                   colorModel = new ComponentColorModel JavaDoc
640                     (ColorSpace.getInstance(ColorSpace.CS_GRAY),
641                      new int[] { sampleSize }, false, false,
642                      Transparency.OPAQUE, dataType);
643                 } else if (imageType == TYPE_RGB) {
644                   colorModel = new ComponentColorModel JavaDoc
645                     (ColorSpace.getInstance(ColorSpace.CS_sRGB),
646                      new int[] { sampleSize, sampleSize, sampleSize },
647                      false, false, Transparency.OPAQUE, dataType);
648                 } else { // hasAlpha
649
// Transparency.OPAQUE signifies image data that is
650
// completely opaque, meaning that all pixels have an alpha
651
// value of 1.0. So the extra band gets ignored, which is
652
// what we want.
653
int transparency = Transparency.OPAQUE;
654                     if(extraSamples == 1) { // associated (premultiplied) alpha
655
transparency = Transparency.TRANSLUCENT;
656                     } else if(extraSamples == 2) { // unassociated alpha
657
transparency = Transparency.BITMASK;
658                     }
659
660                     colorModel =
661                         createAlphaComponentColorModel(dataType,
662                                                        numBands,
663