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                                                        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 JavaDoc
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 JavaDoc("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 JavaDoc
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 JavaDoc
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 JavaDoc(sampleSize,
781                                                      bandLength, r, g, b);
782                 }
783                 break;
784
785             default:
786                 throw new RuntimeException JavaDoc("TIFFImage4");
787             }
788
789         Map JavaDoc properties = new HashMap JavaDoc();
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 JavaDoc {
805         return new TIFFDirectory(stream, offset, 0);
806     }
807
808
809     public WritableRaster JavaDoc copyData(WritableRaster JavaDoc wr) {
810         copyToRaster(wr);
811         return wr;
812     }
813
814
815     /**
816      * Returns tile (tileX, tileY) as a Raster.
817      */

818     public synchronized Raster JavaDoc getTile(int tileX, int tileY) {
819         if ((tileX < 0) || (tileX >= tilesX) ||
820             (tileY < 0) || (tileY >= tilesY)) {
821             throw new IllegalArgumentException JavaDoc("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 JavaDoc sampleModel = getSampleModel();
833         WritableRaster JavaDoc tile = makeTile(tileX,tileY);
834
835         DataBuffer JavaDoc buffer = tile.getDataBuffer();
836
837         int dataType = sampleModel.getDataType();
838         if (dataType == DataBuffer.TYPE_BYTE) {
839             bdata = ((DataBufferByte JavaDoc)buffer).getData();
840         } else if (dataType == DataBuffer.TYPE_USHORT) {
841             sdata = ((DataBufferUShort JavaDoc)buffer).getData();
842         } else if (dataType == DataBuffer.TYPE_SHORT) {
843             sdata = ((DataBufferShort JavaDoc)buffer).getData();
844         } else if (dataType == DataBuffer.TYPE_INT) {
845             idata = ((DataBufferInt JavaDoc)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 JavaDoc ioe) {
859             throw new RuntimeException JavaDoc("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 JavaDoc newRect;
867         if (!tiled)
868             newRect = tile.getBounds();
869         else
870             newRect = new Rectangle JavaDoc(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 JavaDoc ioe) {
919                 throw new RuntimeException JavaDoc("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 JavaDoc ioe) {
986                         throw new RuntimeException JavaDoc("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 JavaDoc ioe) {
1085                        throw new RuntimeException JavaDoc("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 JavaDoc 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 JavaDoc ioe) {
1150                        throw new RuntimeException JavaDoc("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 JavaDoc ioe) {
1210                        throw new RuntimeException JavaDoc("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 JavaDoc ioe) {
1229                        throw new RuntimeException JavaDoc("TIFFImage13");
1230                    }
1231            
1232                    // If compressed, decode the data.
1233
if (compression == COMP_PACKBITS) {
1234            
1235                        tempData = new byte[bytesPostDecoding];
1236                        decodePackbits(data, bytesPostDecoding, tempData);
1237            
1238                    } else if (compression == COMP_LZW) {
1239            
1240                        tempData = new byte[bytesPostDecoding];
1241                        lzwDecoder.decode(data, tempData, newRect.height);
1242            
1243                    } else if (compression == COMP_DEFLATE) {
1244
1245                        tempData = new byte[bytesPostDecoding];
1246                        inflate(data, tempData);
1247            
1248                    } else if (compression == COMP_NONE) {
1249            
1250                        tempData = data;
1251                    }
1252            
1253                    int bytes = unitsInThisTile / 3;
1254            
1255                    // Unpack the 2 pixels packed into each byte.
1256
data = new byte[bytes];
1257            
1258                    int srcCount = 0, dstCount = 0;
1259                    for (int j=0; j<newRect.height; j++) {
1260                        for (int i=0; i<newRect.width/2; i++) {
1261                            data[dstCount++] =
1262                                (byte)((tempData[srcCount] & 0xf0) >> 4);
1263                            data[dstCount++] =
1264                                (byte)(tempData[srcCount++] & 0x0f);
1265                        }
1266               
1267                        if (padding == 1) {
1268                            data[dstCount++] =
1269                                (byte)((tempData[srcCount++] & 0xf0) >> 4);
1270                        }
1271                    }
1272            
1273                    int len = colormap.length/3;
1274                    int len2 = len*2;
1275                    int cmapValue, lookup;
1276                    int count = 0;
1277                    for (int i=0; i<bytes; i++) {
1278                        lookup = data[i] & 0xff;
1279                        cmapValue = colormap[lookup+len2];
1280                        sdata[count++] = (short)(cmapValue & 0xffff);
1281                        cmapValue = colormap[lookup+len];
1282                        sdata[count++] = (short)(cmapValue & 0xffff);
1283                        cmapValue = colormap[lookup];
1284                        sdata[count++] = (short)(cmapValue & 0xffff);
1285                    }
1286                } else {
1287            
1288                    // Output byte values, use IndexColorModel for unpacking
1289
try {
1290            
1291                        // If compressed, decode the data.
1292
if (compression == COMP_PACKBITS) {
1293                
1294                            stream.readFully(data, 0, byteCount);
1295                            decodePackbits(data, bytesPostDecoding, bdata);
1296                
1297                        } else if (compression == COMP_LZW) {
1298                
1299                            stream.readFully(data, 0, byteCount);
1300                            lzwDecoder.decode(data, bdata, newRect.height);
1301                
1302                        } else if (compression == COMP_DEFLATE) {
1303
1304                            stream.readFully(data, 0, byteCount);
1305                            inflate(data, bdata);
1306
1307                        } else if (compression == COMP_NONE) {
1308                
1309                            stream.readFully(bdata, 0, byteCount);
1310                        }
1311            
1312                        stream.seek(save_offset);
1313
1314                    } catch (IOException JavaDoc ioe) {
1315                        throw new RuntimeException JavaDoc("TIFFImage13");
1316                    }
1317                }
1318            }
1319        } else if(imageType == TYPE_GRAY_4BIT) { // 4-bit gray
1320
try {
1321                if (compression == COMP_PACKBITS) {
1322            
1323                    stream.readFully(data, 0, byteCount);
1324            
1325                    // Since the decompressed data will still be packed
1326
// 2 pixels into 1 byte, calculate bytesInThisTile
1327
int bytesInThisTile;
1328                    if ((newRect.width % 8) == 0) {
1329                        bytesInThisTile = (newRect.width/2) * newRect.height;
1330                    } else {
1331                        bytesInThisTile = (newRect.width/2 + 1) *
1332                            newRect.height;
1333                    }
1334            
1335                    decodePackbits(data, bytesInThisTile, bdata);
1336            
1337                } else if (compression == COMP_LZW) {
1338            
1339                    stream.readFully(data, 0, byteCount);
1340                    lzwDecoder.decode(data, bdata, newRect.height);
1341            
1342                } else if (compression == COMP_DEFLATE) {
1343            
1344                    stream.readFully(data, 0, byteCount);
1345                    inflate(data, bdata);
1346            
1347                } else {
1348
1349                    stream.readFully(bdata, 0, byteCount);
1350                }
1351        
1352                stream.seek(save_offset);
1353            } catch (IOException JavaDoc ioe) {
1354                throw new RuntimeException JavaDoc("TIFFImage13");
1355            }
1356        } else { // everything else
1357
try {
1358        
1359                if (sampleSize == 8) {
1360            
1361                    if (compression == COMP_NONE) {
1362                        stream.readFully(bdata, 0, byteCount);
1363            
1364                    } else if (compression == COMP_LZW) {
1365            
1366                        stream.readFully(data, 0, byteCount);
1367                        lzwDecoder.decode(data, bdata, newRect.height);
1368            
1369                    } else if (compression == COMP_PACKBITS) {
1370            
1371                        stream.readFully(data, 0, byteCount);
1372                        decodePackbits(data, unitsInThisTile, bdata);
1373            
1374                    } else if (compression == COMP_JPEG_TTN2) {
1375
1376                        stream.readFully(data, 0, byteCount);
1377                        tile.setRect(decodeJPEG(data,
1378                                                decodeParam,
1379                                                colorConvertJPEG,
1380                                                tile.getMinX(),
1381                                                tile.getMinY()));
1382                    } else if (compression == COMP_DEFLATE) {
1383
1384                        stream.readFully(data, 0, byteCount);
1385                        inflate(data, bdata);
1386                    }
1387            
1388                } else if (sampleSize == 16) {
1389            
1390                    if (compression == COMP_NONE) {
1391            
1392                        readShorts(byteCount/2, sdata);
1393            
1394                    } else if (compression == COMP_LZW) {
1395            
1396                        stream.readFully(data, 0, byteCount);
1397
1398                        // Since unitsInThisTile is the number of shorts,
1399
// but we do our decompression in terms of bytes, we
1400
// need to multiply unitsInThisTile by 2 in order to
1401
// figure out how many bytes we'll get after
1402
// decompression.
1403
byte byteArray[] = new byte[unitsInThisTile * 2];
1404                        lzwDecoder.decode(data, byteArray, newRect.height);
1405                        interpretBytesAsShorts(byteArray, sdata,
1406                                               unitsInThisTile);
1407            
1408                    } else if (compression == COMP_PACKBITS) {
1409            
1410                        stream.readFully(data, 0, byteCount);
1411
1412                        // Since unitsInThisTile is the number of shorts,
1413
// but we do our decompression in terms of bytes, we
1414
// need to multiply unitsInThisTile by 2 in order to
1415
// figure out how many bytes we'll get after
1416
// decompression.
1417
int bytesInThisTile = unitsInThisTile * 2;
1418
1419                        byte byteArray[] = new byte[bytesInThisTile];
1420                        decodePackbits(data, bytesInThisTile, byteArray);
1421                        interpretBytesAsShorts(byteArray, sdata,
1422                                               unitsInThisTile);
1423                    } else if (compression == COMP_DEFLATE) {
1424
1425                        stream.readFully(data, 0, byteCount);
1426                        byte byteArray[] = new byte[unitsInThisTile * 2];
1427                        inflate(data, byteArray);
1428                        interpretBytesAsShorts(byteArray, sdata,
1429                                               unitsInThisTile);
1430
1431                    }
1432                } else if (sampleSize == 32 &&
1433                           dataType == DataBuffer.TYPE_INT) { // redundant
1434
if (compression == COMP_NONE) {
1435            
1436                        readInts(byteCount/4, idata);
1437
1438                    } else if (compression == COMP_LZW) {
1439            
1440                        stream.readFully(data, 0, byteCount);
1441
1442                        // Since unitsInThisTile is the number of ints,
1443
// but we do our decompression in terms of bytes, we
1444
// need to multiply unitsInThisTile by 4 in order to
1445
// figure out how many bytes we'll get after
1446
// decompression.
1447
byte byteArray[] = new byte[unitsInThisTile * 4];
1448                        lzwDecoder.decode(data, byteArray, newRect.height);
1449                        interpretBytesAsInts(byteArray, idata,
1450                                             unitsInThisTile);
1451            
1452                    } else if (compression == COMP_PACKBITS) {
1453            
1454                        stream.readFully(data, 0, byteCount);
1455
1456                        // Since unitsInThisTile is the number of ints,
1457
// but we do our decompression in terms of bytes, we
1458
// need to multiply unitsInThisTile by 4 in order to
1459
// figure out how many bytes we'll get after
1460
// decompression.
1461
int bytesInThisTile = unitsInThisTile * 4;
1462
1463                        byte byteArray[] = new byte[bytesInThisTile];
1464                        decodePackbits(data, bytesInThisTile, byteArray);
1465                        interpretBytesAsInts(byteArray, idata,
1466                                             unitsInThisTile);
1467                    } else if (compression == COMP_DEFLATE) {
1468
1469                        stream.readFully(data, 0, byteCount);
1470                        byte byteArray[] = new byte[unitsInThisTile * 4];
1471                        inflate(data, byteArray);
1472                        interpretBytesAsInts(byteArray, idata,
1473                                             unitsInThisTile);
1474
1475                    }
1476                }
1477
1478                stream.seek(save_offset);
1479
1480            } catch (IOException JavaDoc ioe) {
1481                throw new RuntimeException JavaDoc("TIFFImage13");
1482            }
1483
1484            // Modify the data for certain special cases.
1485
switch(imageType) {
1486            case TYPE_GRAY:
1487            case TYPE_GRAY_ALPHA:
1488                if(isWhiteZero) {
1489                    // Since we are using a ComponentColorModel with this
1490
// image, we need to change the WhiteIsZero data to
1491
// BlackIsZero data so it will display properly.
1492
if (dataType == DataBuffer.TYPE_BYTE &&
1493                        !(getColorModel() instanceof IndexColorModel JavaDoc)) {
1494
1495                        for (int l = 0; l < bdata.length; l += numBands) {
1496                            bdata[l] = (byte)(255 - bdata[l]);
1497                        }
1498                    } else if (dataType == DataBuffer.TYPE_USHORT) {
1499
1500                        int ushortMax = Short.MAX_VALUE - Short.MIN_VALUE;
1501                        for (int l = 0; l < sdata.length; l += numBands) {
1502                            sdata[l] = (short)(ushortMax - sdata[l]);
1503                        }
1504
1505                    } else if (dataType == DataBuffer.TYPE_SHORT) {
1506
1507                        for (int l = 0; l < sdata.length; l += numBands) {
1508                            sdata[l] = (short)(~sdata[l]);
1509                        }
1510                    } else if (dataType == DataBuffer.TYPE_INT) {
1511
1512                        long uintMax = ((long)Integer.MAX_VALUE -
1513                                        (long)Integer.MIN_VALUE);
1514                        for (int l = 0; l < idata.length; l += numBands) {
1515                            idata[l] = (int)(uintMax - idata[l]);
1516                        }
1517                    }
1518                }
1519                break;
1520            case TYPE_RGB:
1521                // Change RGB to BGR order, as Java2D displays that faster.
1522
// Unnecessary for JPEG-in-TIFF as the decoder handles it.
1523
if (sampleSize == 8 && compression != COMP_JPEG_TTN2) {
1524                    for (int i=0; i<unitsInThisTile; i+=3) {
1525                        bswap = bdata[i];
1526                        bdata[i] = bdata[i+2];
1527                        bdata[i+2] = bswap;
1528                    }
1529                } else if (sampleSize == 16) {
1530                    for (int i=0; i<unitsInThisTile; i+=3) {
1531                        sswap = sdata[i];
1532                        sdata[i] = sdata[i+2];
1533                        sdata[i+2] = sswap;
1534                    }
1535                } else if (sampleSize == 32) {
1536                    if(dataType == DataBuffer.TYPE_INT) {
1537                        for (int i=0; i<unitsInThisTile; i+=3) {
1538                            iswap = idata[i];
1539                            idata[i] = idata[i+2];
1540                            idata[i+2] = iswap;
1541                        }
1542                    }
1543                }
1544                break;
1545            case TYPE_RGB_ALPHA:
1546                // Convert from RGBA to ABGR for Java2D
1547
if (sampleSize == 8) {
1548                    for (int i=0; i<unitsInThisTile; i+=4) {
1549                        // Swap R and A
1550
bswap = bdata[i];
1551                        bdata[i] = bdata[i+3];
1552                        bdata[i+3] = bswap;
1553            
1554                        // Swap G and B
1555
bswap = bdata[i+1];
1556                        bdata[i+1] = bdata[i+2];
1557                        bdata[i+2] = bswap;
1558                    }
1559                } else if (sampleSize == 16) {
1560                    for (int i=0; i<unitsInThisTile; i+=4) {
1561                        // Swap R and A
1562
sswap = sdata[i];
1563                        sdata[i] = sdata[i+3];
1564                        sdata[i+3] = sswap;
1565
1566                        // Swap G and B
1567
sswap = sdata[i+1];
1568                        sdata[i+1] = sdata[i+2];
1569                        sdata[i+2] = sswap;
1570                    }
1571                } else if (sampleSize == 32) {
1572                    if(dataType == DataBuffer.TYPE_INT) {
1573                        for (int i=0; i<unitsInThisTile; i+=4) {
1574                            // Swap R and A
1575
iswap = idata[i];
1576                            idata[i] = idata[i+3];
1577                            idata[i+3] = iswap;
1578
1579                            // Swap G and B
1580
iswap = idata[i+1];
1581                            idata[i+1] = idata[i+2];
1582                            idata[i+2] = iswap;
1583                        }
1584                    }
1585                }
1586                break;
1587            case TYPE_YCBCR_SUB:
1588                // Post-processing for YCbCr with subsampled chrominance:
1589
// simply replicate the chroma channels for displayability.
1590
int pixelsPerDataUnit = chromaSubH*chromaSubV;
1591
1592                int numH = newRect.width/chromaSubH;
1593                int numV = newRect.height/chromaSubV;
1594
1595                byte[] tempData = new byte[numH*numV*(pixelsPerDataUnit + 2)];
1596                System.arraycopy(bdata, 0, tempData, 0, tempData.length);
1597
1598                int samplesPerDataUnit = pixelsPerDataUnit*3;
1599                int[] pixels = new int[samplesPerDataUnit];
1600
1601                int bOffset = 0;
1602                int offsetCb = pixelsPerDataUnit;
1603                int offsetCr = offsetCb + 1;
1604
1605                int y = newRect.y;
1606                for(int j = 0; j < numV; j++) {
1607                    int x = newRect.x;
1608                    for(int i = 0; i < numH; i++) {
1609                        int Cb = tempData[bOffset + offsetCb];
1610                        int Cr = tempData[bOffset + offsetCr];
1611                        int k = 0;
1612                        while(k < samplesPerDataUnit) {
1613                            pixels[k++] = tempData[bOffset++];
1614                            pixels[k++] = Cb;
1615                            pixels[k++] = Cr;
1616                        }
1617                        bOffset += 2;
1618                        tile.setPixels(x, y, chromaSubH, chromaSubV, pixels);
1619                        x += chromaSubH;
1620                    }
1621                    y += chromaSubV;
1622                }
1623
1624                break;
1625            }
1626        }
1627        
1628        return tile;
1629    }
1630
1631    private void readShorts(int shortCount, short shortArray[]) {
1632    
1633        // Since each short consists of 2 bytes, we need a
1634
// byte array of double size
1635
int byteCount = 2 * shortCount;
1636        byte byteArray[] = new byte[byteCount];
1637
1638        try {
1639            stream.readFully(byteArray, 0, byteCount);
1640        } catch (IOException JavaDoc ioe) {
1641            throw new RuntimeException JavaDoc("TIFFImage13");
1642        }
1643
1644        interpretBytesAsShorts(byteArray, shortArray, shortCount);
1645    }
1646
1647    private void readInts(int intCount, int intArray[]) {
1648    
1649        // Since each int consists of 4 bytes, we need a
1650
// byte array of quadruple size
1651
int byteCount = 4 * intCount;
1652        byte byteArray[] = new byte[byteCount];
1653
1654        try {
1655            stream.readFully(byteArray, 0, byteCount);
1656        } catch (IOException JavaDoc ioe) {
1657            throw new RuntimeException JavaDoc("TIFFImage13");
1658        }
1659
1660        interpretBytesAsInts(byteArray, intArray, intCount);
1661    }
1662
1663    // Method to interpret a byte array to a short array, depending on
1664
// whether the bytes are stored in a big endian or little endian format.
1665
private void interpretBytesAsShorts(byte byteArray[],
1666                                        short shortArray[],
1667                                        int shortCount) {
1668
1669        int j = 0;
1670        int firstByte, secondByte;
1671
1672        if (isBigEndian) {
1673
1674            for (int i=0; i<shortCount; i++) {
1675                firstByte = byteArray[j++] & 0xff;
1676                secondByte = byteArray[j++] & 0xff;
1677                shortArray[i] = (short)((firstByte << 8) + secondByte);
1678            }
1679        
1680        } else {
1681        
1682            for (int i=0; i<shortCount; i++) {
1683                firstByte = byteArray[j++] & 0xff;
1684                secondByte = byteArray[j++] & 0xff;
1685                shortArray[i] = (short)((secondByte << 8) + firstByte);
1686            }
1687        }
1688    }
1689
1690    // Method to interpret a byte array to a int array, depending on
1691
// whether the bytes are stored in a big endian or little endian format.
1692
private void interpretBytesAsInts(byte byteArray[],
1693                                      int intArray[],
1694                                      int intCount) {
1695
1696        int j = 0;
1697
1698        if (isBigEndian) {
1699        
1700            for (int i=0; i<intCount; i++) {
1701                intArray[i] = (((byteArray[j++] & 0xff) << 24) |
1702                               ((byteArray[j++] & 0xff) << 16) |
1703                               ((byteArray[j++] & 0xff) << 8) |
1704                               ( byteArray[j++] & 0xff));
1705            }
1706        
1707        } else {
1708        
1709            for (int i=0; i<intCount; i++) {
1710                intArray[i] = ((byteArray[j++] & 0xff) |
1711                              ((byteArray[j++] & 0xff) << 8) |
1712                              ((byteArray[j++] & 0xff) << 16) |
1713                              ((byteArray[j++] & 0xff) << 24));
1714            }
1715        }
1716    }
1717
1718    // Uncompress packbits compressed image data.
1719
private byte[] decodePackbits(byte data[], int arraySize, byte[] dst) {
1720
1721        if (dst == null) {
1722            dst = new byte[arraySize];
1723        }
1724
1725        int srcCount = 0, dstCount = 0;
1726        byte repeat, b;
1727
1728        try {
1729        
1730            while (dstCount < arraySize) {
1731        
1732                b = data[srcCount++];
1733        
1734                if (b >= 0 && b <= 127) {
1735            
1736                    // literal run packet
1737
for (int i=0; i<(b + 1); i++) {
1738                        dst[dstCount++] = data[srcCount++];
1739                    }
1740                        
1741                } else if (b <= -1 && b >= -127) {
1742            
1743                    // 2 byte encoded run packet
1744
repeat = data[srcCount++];
1745                    for (int i=0; i<(-b + 1); i++) {
1746                        dst[dstCount++] = repeat;
1747                    }
1748            
1749                } else {
1750                    // no-op packet. Do nothing
1751
srcCount++;
1752                }
1753            }
1754        } catch (java.lang.ArrayIndexOutOfBoundsException JavaDoc ae) {
1755            throw new RuntimeException JavaDoc("TIFFImage14");
1756        }
1757
1758        return dst;
1759    }
1760
1761    // Need a createColorModel().
1762
// Create ComponentColorModel for TYPE_RGB images
1763
private ComponentColorModel JavaDoc createAlphaComponentColorModel
1764    (int dataType, int numBands,
1765     boolean isAlphaPremultiplied, int transparency) {
1766    
1767        ComponentColorModel JavaDoc ccm = null;
1768        int RGBBits[] = null;
1769        ColorSpace JavaDoc cs = null;
1770        switch(numBands) {
1771            case 2: // gray+alpha
1772
cs = ColorSpace.getInstance(ColorSpace.CS_GRAY);
1773                break;
1774            case 4: // RGB+alpha
1775
cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
1776                break;
1777            default:
1778                throw new IllegalArgumentException JavaDoc();
1779        }
1780        
1781        int componentSize = 0;
1782        switch(dataType) {
1783            case DataBuffer.TYPE_BYTE:
1784                componentSize = 8;
1785                break;
1786            case DataBuffer.TYPE_USHORT:
1787            case DataBuffer.TYPE_SHORT:
1788                componentSize = 16;
1789                break;
1790            case DataBuffer.TYPE_INT:
1791                componentSize = 32;
1792                break;
1793            default:
1794                throw new IllegalArgumentException JavaDoc();
1795        }
1796
1797        RGBBits = new int[numBands];
1798        for(int i = 0; i < numBands; i++) {
1799            RGBBits[i] = componentSize;
1800        }
1801
1802        ccm = new ComponentColorModel JavaDoc(cs,
1803                                      RGBBits,
1804                                      true,
1805                                      isAlphaPremultiplied,
1806                                      transparency,
1807                                      dataType);
1808
1809
1810        return ccm;
1811    }
1812        
1813}
1814
Popular Tags