Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/apache/batik/ext/awt/image/codec/tiff/TIFFImage.java


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;
21  import java.awt.Transparency;
22  import java.awt.color.ColorSpace;
23  import java.awt.image.ColorModel;
24  import java.awt.image.ComponentColorModel;
25  import java.awt.image.DataBuffer;
26  import java.awt.image.DataBufferByte;
27  import java.awt.image.DataBufferInt;
28  import java.awt.image.DataBufferShort;
29  import java.awt.image.DataBufferUShort;
30  import java.awt.image.IndexColorModel;
31  import java.awt.image.MultiPixelPackedSampleModel;
32  import java.awt.image.PixelInterleavedSampleModel;
33  import java.awt.image.Raster;
34  import java.awt.image.SampleModel;
35  import java.awt.image.WritableRaster;
36  import java.io.ByteArrayInputStream;
37  import java.io.IOException;
38  import java.util.HashMap;
39  import java.util.Map;
40  import java.util.zip.DataFormatException;
41  import java.util.zip.Inflater;
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 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 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 jpegStream = new ByteArrayInputStream(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 jpegRaster;
151         try {
152             jpegRaster = colorConvert ?
153                 decoder.decodeAsBufferedImage().getWritableTile(0, 0) :
154                 decoder.decodeAsRaster();
155         } catch (IOException ioe) {
156             throw new RuntimeException("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 dfe) {
172             throw new RuntimeException("TIFFImage17"+": "+
173                                        dfe.getMessage());
174         }
175         inflater.reset();
176     }
177 
178     private static SampleModel 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
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();
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 {
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("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("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("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("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("TIFFImage4");
406             }
407 
408             // Set basic image layout
409             Rectangle bounds = new Rectangle
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("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("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();
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("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("TIFFImage8"); 
557                     }
558         
559                     if (predictor == 2 && sampleSize != 8) {
560                         throw new RuntimeException(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("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("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 tableStream =
585                         new ByteArrayInputStream(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("TIFFImage10");
595             }
596 
597             ColorModel  colorModel  = null;
598             SampleModel sampleModel = null;
599             switch(imageType) {
600             case TYPE_BILEVEL:
601             case TYPE_GRAY_4BIT:
602                 sampleModel = 
603                     new MultiPixelPackedSampleModel(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(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(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
635                     (dataType, tileWidth, tileHeight,
636                      numBands, numBands*tileWidth, reverseOffsets);
637 
638                 if(imageType == TYPE_GRAY) {
639                   colorModel = new ComponentColorModel
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
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                                                        extraSamples == 1,
664                                                        transparency);
665                 }
666                 break;
667 
668             case TYPE_GENERIC:
669             case TYPE_YCBCR_SUB:
670                 // For this case we can't display the image, so we create a
671                 // SampleModel with increasing bandOffsets, and keep the
672                 // ColorModel as null, as there is no appropriate ColorModel.
673 
674                 int[] bandOffsets = new int[numBands];
675                 for (int i=0; i<numBands; i++) {
676                     bandOffsets[i] = i;
677                 }
678     
679                 sampleModel = new PixelInterleavedSampleModel
680                     (dataType, tileWidth, tileHeight,
681                      numBands, numBands * tileWidth, bandOffsets);
682                 colorModel = null;
683                 break;
684 
685             case TYPE_PALETTE:
686                 // Get the colormap
687                 TIFFField cfield = dir.getField(TIFFImageDecoder.TIFF_COLORMAP);
688                 if (cfield == null) {
689                     throw new RuntimeException("TIFFImage11");
690                 } else {
691                     colormap = cfield.getAsChars();
692                 }
693 
694                 // Could be either 1 or 3 bands depending on whether we use
695                 // IndexColorModel or not.
696                 if (decodePaletteAsShorts) {
697                     numBands = 3;
698 
699                     // If no SampleFormat tag was specified and if the 
700                     // sampleSize is less than or equal to 8, then the 
701                     // dataType was initially set to byte, but now we want to 
702                     // expand the palette as shorts, so the dataType should 
703                     // be ushort.
704                     if (dataType == DataBuffer.TYPE_BYTE) {
705                         dataType = DataBuffer.TYPE_USHORT;
706                     }
707 
708                     // Data will have to be unpacked into a 3 band short image
709                     // as we do not have a IndexColorModel that can deal with
710                     // a colormodel whose entries are of short data type.
711                     sampleModel = createPixelInterleavedSampleModel
712                         (dataType, tileWidth, tileHeight, numBands);
713 
714                   colorModel = new ComponentColorModel
715                     (ColorSpace.getInstance(ColorSpace.CS_sRGB),
716                      new int[] { 16, 16, 16 }, false, false, 
717                      Transparency.OPAQUE, dataType);
718 
719                 } else {
720 
721                     numBands = 1;
722     
723                     if (sampleSize == 4) {
724                         // Pixel data will not be unpacked, will use
725                         // MPPSM to store packed data and
726                         // IndexColorModel to do the unpacking.
727                         sampleModel = new MultiPixelPackedSampleModel
728                             (DataBuffer.TYPE_BYTE, tileWidth, tileHeight, 
729                              sampleSize);
730                     } else if (sampleSize == 8) {
731                         
732                         sampleModel = createPixelInterleavedSampleModel
733                             (DataBuffer.TYPE_BYTE, tileWidth, tileHeight,
734                              numBands);
735                     } else if (sampleSize == 16) {
736 
737                         // Here datatype has to be unsigned since we
738                         // are storing indices into the
739                         // IndexColorModel palette. Ofcourse the
740                         // actual palette entries are allowed to be
741                         // negative.
742                         dataType = DataBuffer.TYPE_USHORT;
743                         sampleModel = createPixelInterleavedSampleModel
744                             (DataBuffer.TYPE_USHORT, tileWidth, tileHeight,
745                              numBands);
746                     }
747     
748                     int bandLength = colormap.length/3;
749                     byte r[] = new byte[bandLength];
750                     byte g[] = new byte[bandLength];
751                     byte b[] = new byte[bandLength];
752     
753                     int gIndex = bandLength;
754                     int bIndex = bandLength * 2;
755 
756                     if (dataType == DataBuffer.TYPE_SHORT) {
757 
758                         for (int i=0; i<bandLength; i++) {
759                             r[i] = param.decodeSigned16BitsTo8Bits
760                                 ((short)colormap[i]);
761                             g[i] = param.decodeSigned16BitsTo8Bits
762                                 ((short)colormap[gIndex+i]);
763                             b[i] = param.decodeSigned16BitsTo8Bits
764                                 ((short)colormap[bIndex+i]);
765                         }
766 
767                     } else {
768 
769                         for (int i=0; i<bandLength; i++) {
770                             r[i] = param.decode16BitsTo8Bits
771                                 (colormap[i] & 0xffff);
772                             g[i] = param.decode16BitsTo8Bits
773                                 (colormap[gIndex+i] & 0xffff);
774                             b[i] = param.decode16BitsTo8Bits
775                                 (colormap[bIndex+i] & 0xffff);
776                         }
777         
778                     }
779 
780                     colorModel = new IndexColorModel(sampleSize, 
781                                                      bandLength, r, g, b);
782                 }
783                 break;
784 
785             default:
786                 throw new RuntimeException("TIFFImage4");
787             }
788 
789         Map properties = new HashMap();
790         // Set a property "tiff_directory".
791         properties.put("tiff_directory", dir);
792 
793         // System.out.println("Constructed TIFF");
794 
795         init((CachableRed)null, bounds, colorModel, sampleModel, 
796              0, 0, properties);
797     }
798 
799     /**
800      * Reads a private IFD from a given offset in the stream.  This
801      * method may be used to obtain IFDs that are referenced
802      * only by private tag values.
803      */
804     public TIFFDirectory getPrivateIFD(long offset) throws IOException {
805         return new TIFFDirectory(stream, offset, 0);
806     }
807 
808 
809     public WritableRaster copyData(WritableRaster wr) {
810         copyToRaster(wr);
811         return wr;
812     }
813 
814 
815     /**
816      * Returns tile (tileX, tileY) as a Raster.
817      */
818     public synchronized Raster getTile(int tileX, int tileY) {
819         if ((tileX < 0) || (tileX >= tilesX) ||
820             (tileY < 0) || (tileY >= tilesY)) {
821             throw new IllegalArgumentException("TIFFImage12");
822         }
823 
824         // System.out.println("Called TIFF getTile:" + tileX + "," + tileY);
825 
826 
827         // Get the data array out of the DataBuffer
828         byte bdata[] = null;
829         short sdata[] = null;
830         int idata[] = null;
831 
832         SampleModel sampleModel = getSampleModel();
833         WritableRaster tile = makeTile(tileX,tileY);
834 
835         DataBuffer buffer = tile.getDataBuffer();
836 
837         int dataType = sampleModel.getDataType();
838         if (dataType == DataBuffer.TYPE_BYTE) {
839             bdata = ((DataBufferByte)buffer).getData();
840         } else if (dataType == DataBuffer.TYPE_USHORT) {
841             sdata = ((DataBufferUShort)buffer).getData();
842         } else if (dataType == DataBuffer.TYPE_SHORT) {
843             sdata = ((DataBufferShort)buffer).getData();
844         } else if (dataType == DataBuffer.TYPE_INT) {
845             idata = ((DataBufferInt)buffer).getData();
846         }
847 
848         // Variables used for swapping when converting from RGB to BGR
849         byte bswap;
850         short sswap;
851         int iswap;
852 
853         // Save original file pointer position and seek to tile data location.
854         long save_offset = 0;
855         try {
856             save_offset = stream.getFilePointer();
857             stream.seek(tileOffsets[tileY*tilesX + tileX]);
858         } catch (IOException ioe) {
859             throw new RuntimeException("TIFFImage13");
860         }
861 
862         // Number of bytes in this tile (strip) after compression.
863         int byteCount = (int)tileByteCounts[tileY*tilesX + tileX];
864 
865         // Find out the number of bytes in the current tile
866         Rectangle newRect;
867         if (!tiled)
868             newRect = tile.getBounds();
869         else
870             newRect = new Rectangle(tile.getMinX(), tile.getMinY(),
871                                     tileWidth, tileHeight);
872             
873         int unitsInThisTile = newRect.width * newRect.height * numBands;
874 
875         // Allocate read buffer if needed.
876         byte data[] = compression != COMP_NONE || imageType == TYPE_PALETTE ?
877             new byte[byteCount] : null;
878 
879         // Read the data, uncompressing as needed. There are four cases:
880         // bilevel, palette-RGB, 4-bit grayscale, and everything else.
881         if(imageType == TYPE_BILEVEL) { // bilevel
882             try {
883                 if (compression == COMP_PACKBITS) {
884                     stream.readFully(data, 0, byteCount);
885 
886                     // Since the decompressed data will still be packed 
887                     // 8 pixels into 1 byte, calculate bytesInThisTile
888                     int bytesInThisTile;
889                     if ((newRect.width % 8) == 0) {
890                         bytesInThisTile = (newRect.width/8) * newRect.height;
891                     } else {
892                         bytesInThisTile =
893                             (newRect.width/8 + 1) * newRect.height;
894                     }
895                     decodePackbits(data, bytesInThisTile, bdata);
896                 } else if (compression == COMP_LZW) {
897                     stream.readFully(data, 0, byteCount);
898                     lzwDecoder.decode(data, bdata, newRect.height);
899                 } else if (compression == COMP_FAX_G3_1D) {
900                     stream.readFully(data, 0, byteCount);
901                     decoder.decode1D(bdata, data, 0, newRect.height);
902                 } else if (compression == COMP_FAX_G3_2D) {
903                     stream.readFully(data, 0, byteCount);
904                     decoder.decode2D(bdata, data, 0, newRect.height,
905                                      tiffT4Options);
906                 } else if (compression == COMP_FAX_G4_2D) {
907                     stream.readFully(data, 0, byteCount);
908                     decoder.decodeT6(bdata, data, 0, newRect.height,
909                                      tiffT6Options);
910                 } else if (compression == COMP_DEFLATE) {
911                     stream.readFully(data, 0, byteCount);
912                     inflate(data, bdata);
913                 } else if (compression == COMP_NONE) {
914                     stream.readFully(bdata, 0, byteCount);
915                 }
916 
917                 stream.seek(save_offset);
918             } catch (IOException ioe) {
919                 throw new RuntimeException("TIFFImage13");
920             }
921         } else if(imageType == TYPE_PALETTE) { // palette-RGB
922             if (sampleSize == 16) {
923 
924                 if (decodePaletteAsShorts) {
925         
926                     short tempData[]= null;
927                 
928                     // At this point the data is 1 banded and will
929                     // become 3 banded only after we've done the palette
930                     // lookup, since unitsInThisTile was calculated with
931                     // 3 bands, we need to divide this by 3.
932                     int unitsBeforeLookup = unitsInThisTile / 3;
933         
934                     // Since unitsBeforeLookup is the number of shorts, 
935                     // but we do our decompression in terms of bytes, we 
936                     // need to multiply it by 2 in order to figure out
937                     // how many bytes we'll get after decompression.
938                     int entries = unitsBeforeLookup * 2;
939         
940                     // Read the data, if compressed, decode it, reset the pointer
941                     try {
942       
943                         if (compression == COMP_PACKBITS) {
944 
945                             stream.readFully(data, 0, byteCount);
946           
947                             byte byteArray[] = new byte[entries];
948                             decodePackbits(data, entries, byteArray);
949                             tempData = new short[unitsBeforeLookup];
950                             interpretBytesAsShorts(byteArray, tempData,
951                                                    unitsBeforeLookup);
952           
953                         }  else if (compression == COMP_LZW) {
954 
955                             // Read in all the compressed data for this tile
956                             stream.readFully(data, 0, byteCount);
957 
958                             byte byteArray[] = new byte[entries];
959                             lzwDecoder.decode(data, byteArray, newRect.height);
960                             tempData = new short[unitsBeforeLookup];
961                             interpretBytesAsShorts(byteArray, tempData,
962                                                    unitsBeforeLookup);
963 
964                         }  else if (compression == COMP_DEFLATE) {
965 
966                             stream.readFully(data, 0, byteCount);
967                             byte byteArray[] = new byte[entries];
968                             inflate(data, byteArray);
969                             tempData = new short[unitsBeforeLookup];
970                             interpretBytesAsShorts(byteArray, tempData,
971                                                    unitsBeforeLookup);
972 
973                         } else if (compression == COMP_NONE) {
974 
975                             // byteCount tells us how many bytes are there
976                             // in this tile, but we need to read in shorts, 
977                             // which will take half the space, so while
978                             // allocating we divide byteCount by 2.
979                             tempData = new short[byteCount/2];
980                             readShorts(byteCount/2, tempData);
981                         }      
982 
983                         stream.seek(save_offset);
984 
985                     } catch (IOException ioe) {
986                         throw new RuntimeException("TIFFImage13");
987                     }
988 
989                     if (dataType == DataBuffer.TYPE_USHORT) {
990       
991                         // Expand the palette image into an rgb image with ushort
992                         // data type.
993                         int cmapValue; 
994                         int count = 0, lookup, len = colormap.length/3;
995                         int len2 = len * 2;
996                         for (int i=0; i<unitsBeforeLookup; i++) {
997                             // Get the index into the colormap
998                             lookup = tempData[i] & 0xffff;
999                             // Get the blue value 
1000                            cmapValue = colormap[lookup+len2];
1001                            sdata[count++] = (short)(cmapValue & 0xffff);
1002                            // Get the green value
1003                            cmapValue = colormap[lookup+len];
1004                            sdata[count++] = (short)(cmapValue & 0xffff);
1005                            // Get the red value
1006                            cmapValue = colormap[lookup];
1007                            sdata[count++] = (short)(cmapValue & 0xffff);
1008                        }
1009
1010                    } else if (dataType == DataBuffer.TYPE_SHORT) {
1011
1012                        // Expand the palette image into an rgb image with 
1013                        // short data type.
1014                        int cmapValue; 
1015                        int count = 0, lookup, len = colormap.length/3;
1016                        int len2 = len * 2;
1017                        for (int i=0; i<unitsBeforeLookup; i++) {
1018                            // Get the index into the colormap
1019                            lookup = tempData[i] & 0xffff;
1020                            // Get the blue value 
1021                            cmapValue = colormap[lookup+len2];
1022                            sdata[count++] = (short)cmapValue;
1023                            // Get the green value
1024                            cmapValue = colormap[lookup+len];
1025                            sdata[count++] = (short)cmapValue;
1026                            // Get the red value
1027                            cmapValue = colormap[lookup];
1028                            sdata[count++] = (short)cmapValue;
1029                        }
1030                    }
1031
1032                } else {
1033        
1034                    // No lookup being done here, when RGB values are needed,
1035                    // the associated IndexColorModel can be used to get them.
1036        
1037                    try {
1038
1039                        if (compression == COMP_PACKBITS) {
1040
1041                            stream.readFully(data, 0, byteCount);
1042
1043                            // Since unitsInThisTile is the number of shorts, 
1044                            // but we do our decompression in terms of bytes, we 
1045                            // need to multiply unitsInThisTile by 2 in order to 
1046                            // figure out how many bytes we'll get after 
1047                            // decompression.
1048                            int bytesInThisTile = unitsInThisTile * 2;
1049
1050                            byte byteArray[] = new byte[bytesInThisTile];
1051                            decodePackbits(data, bytesInThisTile, byteArray);
1052                            interpretBytesAsShorts(byteArray, sdata,
1053                                                   unitsInThisTile);
1054          
1055                        } else if (compression == COMP_LZW) {
1056          
1057                            stream.readFully(data, 0, byteCount);
1058
1059                            // Since unitsInThisTile is the number of shorts, 
1060                            // but we do our decompression in terms of bytes, we 
1061                            // need to multiply unitsInThisTile by 2 in order to 
1062                            // figure out how many bytes we'll get after 
1063                            // decompression.
1064                            byte byteArray[] = new byte[unitsInThisTile * 2];
1065                            lzwDecoder.decode(data, byteArray, newRect.height);
1066                            interpretBytesAsShorts(byteArray, sdata, 
1067                                                   unitsInThisTile);
1068
1069                        }  else if (compression == COMP_DEFLATE) {
1070
1071                            stream.readFully(data, 0, byteCount);
1072                            byte byteArray[] = new byte[unitsInThisTile * 2];
1073                            inflate(data, byteArray);
1074                            interpretBytesAsShorts(byteArray, sdata, 
1075                                                   unitsInThisTile);
1076
1077                        } else if (compression == COMP_NONE) {
1078
1079                            readShorts(byteCount/2, sdata);
1080                        }
1081      
1082                        stream.seek(save_offset);
1083
1084                    } catch (IOException ioe) {
1085                        throw new RuntimeException("TIFFImage13");
1086                    }        
1087                }
1088    
1089            } else if (sampleSize == 8) {
1090
1091                if (decodePaletteAsShorts) {
1092        
1093                    byte tempData[]= null;
1094
1095                    // At this point the data is 1 banded and will
1096                    // become 3 banded only after we've done the palette
1097                    // lookup, since unitsInThisTile was calculated with
1098                    // 3 bands, we need to divide this by 3.
1099                    int unitsBeforeLookup = unitsInThisTile / 3;
1100        
1101                    // Read the data, if compressed, decode it, reset the pointer
1102                    try {
1103      
1104                        if (compression == COMP_PACKBITS) {
1105          
1106                            stream.readFully(data, 0, byteCount);
1107                            tempData = new byte[unitsBeforeLookup];
1108                            decodePackbits(data, unitsBeforeLookup, tempData);
1109          
1110                        }  else if (compression == COMP_LZW) {
1111          
1112                            stream.readFully(data, 0, byteCount);
1113                            tempData = new byte[unitsBeforeLookup];
1114                            lzwDecoder.decode(data, tempData, newRect.height);
1115          
1116                        } else if (compression == COMP_JPEG_TTN2) {
1117
1118                            stream.readFully(data, 0, byteCount);
1119                            Raster tempTile = decodeJPEG(data,
1120                                                         decodeParam,
1121                                                         colorConvertJPEG,
1122                                                         tile.getMinX(),
1123                                                         tile.getMinY());
1124                            int[] tempPixels = new int[unitsBeforeLookup];
1125                            tempTile.getPixels(tile.getMinX(),
1126                                               tile.getMinY(),
1127                                               tile.getWidth(),
1128                                               tile.getHeight(),
1129                                               tempPixels);
1130                            tempData = new byte[unitsBeforeLookup];
1131                            for(int i = 0; i < unitsBeforeLookup; i++) {
1132                                tempData[i] = (byte)tempPixels[i];
1133                            }
1134
1135                        }  else if (compression == COMP_DEFLATE) {
1136
1137                            stream.readFully(data, 0, byteCount);
1138                            tempData = new byte[unitsBeforeLookup];
1139                            inflate(data, tempData);
1140
1141                        } else if (compression == COMP_NONE) {
1142
1143                            tempData = new byte[byteCount];
1144                            stream.readFully(tempData, 0, byteCount);
1145                        }      
1146
1147                        stream.seek(save_offset);
1148
1149                    } catch (IOException ioe) {
1150                        throw new RuntimeException("TIFFImage13");
1151                    }
1152
1153                    // Expand the palette image into an rgb image with ushort
1154                    // data type.
1155                    int cmapValue; 
1156                    int count = 0, lookup, len = colormap.length/3;
1157                    int len2 = len * 2;
1158                    for (int i=0; i<unitsBeforeLookup; i++) {
1159                        // Get the index into the colormap
1160                        lookup = tempData[i] & 0xff;
1161                        // Get the blue value 
1162                        cmapValue = colormap[lookup+len2];
1163                        sdata[count++] = (short)(cmapValue & 0xffff);
1164                        // Get the green value
1165                        cmapValue = colormap[lookup+len];
1166                        sdata[count++] = (short)(cmapValue & 0xffff);
1167                        // Get the red value
1168                        cmapValue = colormap[lookup];
1169                        sdata[count++] = (short)(cmapValue & 0xffff);
1170                    }
1171                } else {
1172        
1173                    // No lookup being done here, when RGB values are needed,
1174                    // the associated IndexColorModel can be used to get them.
1175        
1176                    try {
1177
1178                        if (compression == COMP_PACKBITS) {
1179          
1180                            stream.readFully(data, 0, byteCount);
1181                            decodePackbits(data, unitsInThisTile, bdata);
1182          
1183                        } else if (compression == COMP_LZW) {
1184          
1185                            stream.readFully(data, 0, byteCount);
1186                            lzwDecoder.decode(data, bdata, newRect.height);
1187          
1188                        } else if (compression == COMP_JPEG_TTN2) {
1189
1190                            stream.readFully(data, 0, byteCount);
1191                            tile.setRect(decodeJPEG(data,
1192                                                    decodeParam,
1193                                                    colorConvertJPEG,
1194                                                    tile.getMinX(),
1195                                                    tile.getMinY()));
1196
1197                        }  else if (compression == COMP_DEFLATE) {
1198                            
1199                            stream.readFully(data, 0, byteCount);
1200                            inflate(data, bdata);
1201
1202                        } else if (compression == COMP_NONE) {
1203
1204                            stream.readFully(bdata, 0, byteCount);
1205                        }
1206      
1207                        stream.seek(save_offset);
1208
1209                    } catch (IOException ioe) {
1210                        throw new RuntimeException("TIFFImage13");
1211                    }        
1212                }
1213    
1214            } else if (sampleSize == 4) {
1215    
1216                int padding = (newRect.width % 2 == 0) ? 0 : 1;
1217                int bytesPostDecoding = ((newRect.width/2 + padding) *
1218                                         newRect.height);
1219    
1220                // Output short images
1221                if (decodePaletteAsShorts) {    
1222        
1223                    byte tempData[] = null;
1224
1225                    try {
1226                        stream.readFully(data, 0, byteCount);
1227                        stream.seek(save_offset);
1228                    } catch (IOException ioe) {
1229                        throw new