1 /*
2  * Copyright 2003-2005 by Paulo Soares.
3  *
4  * The contents of this file are subject to the Mozilla Public License Version 1.1
5  * (the "License"); you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at http://www.mozilla.org/MPL/
7  *
8  * Software distributed under the License is distributed on an "AS IS" basis,
9  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
10  * for the specific language governing rights and limitations under the License.
11  *
12  * The Original Code is 'iText, a free JAVA-PDF library'.
13  *
14  * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by
15  * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie.
16  * All Rights Reserved.
17  * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer
18  * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved.
19  *
20  * Contributor(s): all the names of the contributors are added in the source code
21  * where applicable.
22  *
23  * Alternatively, the contents of this file may be used under the terms of the
24  * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the
25  * provisions of LGPL are applicable instead of those above.  If you wish to
26  * allow use of your version of this file only under the terms of the LGPL
27  * License and not to allow others to use your version of this file under
28  * the MPL, indicate your decision by deleting the provisions above and
29  * replace them with the notice and other provisions required by the LGPL.
30  * If you do not delete the provisions above, a recipient may use your version
31  * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE.
32  *
33  * This library is free software; you can redistribute it and/or modify it
34  * under the terms of the MPL as stated above or under the terms of the GNU
35  * Library General Public License as published by the Free Software Foundation;
36  * either version 2 of the License, or any later version.
37  *
38  * This library is distributed in the hope that it will be useful, but WITHOUT
39  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
40  * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more
41  * details.
42  *
43  * If you didn't download this code from the following link, you should check if
44  * you aren't using an obsolete version:
45  * http://www.lowagie.com/iText/
46  */
47 package com.lowagie.text.pdf.codec;
48 import java.awt.color.ICC_Profile;
49 import java.io.ByteArrayOutputStream;
50 import java.io.IOException;
51 import java.util.zip.DataFormatException;
52 import java.util.zip.DeflaterOutputStream;
53 import java.util.zip.Inflater;
54 import com.lowagie.text.error_messages.MessageLocalization;
55 
56 import com.lowagie.text.ExceptionConverter;
57 import com.lowagie.text.Image;
58 import com.lowagie.text.Jpeg;
59 import com.lowagie.text.pdf.PdfArray;
60 import com.lowagie.text.pdf.PdfDictionary;
61 import com.lowagie.text.pdf.PdfName;
62 import com.lowagie.text.pdf.PdfNumber;
63 import com.lowagie.text.pdf.PdfString;
64 import com.lowagie.text.pdf.RandomAccessFileOrArray;
65 
66 /** Reads TIFF images
67  * @author Paulo Soares (psoares@consiste.pt)
68  */
69 public class TiffImage {
70 
71     /** Gets the number of pages the TIFF document has.
72      * @param s the file source
73      * @return the number of pages
74      */
getNumberOfPages(RandomAccessFileOrArray s)75     public static int getNumberOfPages(RandomAccessFileOrArray s) {
76         try {
77             return TIFFDirectory.getNumDirectories(s);
78         }
79         catch (Exception e) {
80             throw new ExceptionConverter(e);
81         }
82     }
83 
getDpi(TIFFField fd, int resolutionUnit)84     static int getDpi(TIFFField fd, int resolutionUnit) {
85         if (fd == null)
86             return 0;
87         long res[] = fd.getAsRational(0);
88         float frac = (float)res[0] / (float)res[1];
89         int dpi = 0;
90         switch (resolutionUnit) {
91             case TIFFConstants.RESUNIT_INCH:
92             case TIFFConstants.RESUNIT_NONE:
93                 dpi = (int)(frac + 0.5);
94                 break;
95             case TIFFConstants.RESUNIT_CENTIMETER:
96                 dpi = (int)(frac * 2.54 + 0.5);
97                 break;
98         }
99         return dpi;
100     }
101 
102     /** Reads a page from a TIFF image. Direct mode is not used.
103      * @param s the file source
104      * @param page the page to get. The first page is 1
105      * @return the <CODE>Image</CODE>
106      */
getTiffImage(RandomAccessFileOrArray s, int page)107     public static Image getTiffImage(RandomAccessFileOrArray s, int page) {
108         return getTiffImage(s, page, false);
109     }
110 
111     /** Reads a page from a TIFF image.
112      * @param s the file source
113      * @param page the page to get. The first page is 1
114      * @param direct for single strip, CCITT images, generate the image
115      * by direct byte copying. It's faster but may not work
116      * every time
117      * @return the <CODE>Image</CODE>
118      */
getTiffImage(RandomAccessFileOrArray s, int page, boolean direct)119     public static Image getTiffImage(RandomAccessFileOrArray s, int page, boolean direct) {
120         if (page < 1)
121             throw new IllegalArgumentException(MessageLocalization.getComposedMessage("the.page.number.must.be.gt.eq.1"));
122         try {
123             TIFFDirectory dir = new TIFFDirectory(s, page - 1);
124             if (dir.isTagPresent(TIFFConstants.TIFFTAG_TILEWIDTH))
125                 throw new IllegalArgumentException(MessageLocalization.getComposedMessage("tiles.are.not.supported"));
126             int compression = (int)dir.getFieldAsLong(TIFFConstants.TIFFTAG_COMPRESSION);
127             switch (compression) {
128                 case TIFFConstants.COMPRESSION_CCITTRLEW:
129                 case TIFFConstants.COMPRESSION_CCITTRLE:
130                 case TIFFConstants.COMPRESSION_CCITTFAX3:
131                 case TIFFConstants.COMPRESSION_CCITTFAX4:
132                     break;
133                 default:
134                     return getTiffImageColor(dir, s);
135             }
136             float rotation = 0;
137             if (dir.isTagPresent(TIFFConstants.TIFFTAG_ORIENTATION)) {
138                 int rot = (int)dir.getFieldAsLong(TIFFConstants.TIFFTAG_ORIENTATION);
139                 if (rot == TIFFConstants.ORIENTATION_BOTRIGHT || rot == TIFFConstants.ORIENTATION_BOTLEFT)
140                     rotation = (float)Math.PI;
141                 else if (rot == TIFFConstants.ORIENTATION_LEFTTOP || rot == TIFFConstants.ORIENTATION_LEFTBOT)
142                     rotation = (float)(Math.PI / 2.0);
143                 else if (rot == TIFFConstants.ORIENTATION_RIGHTTOP || rot == TIFFConstants.ORIENTATION_RIGHTBOT)
144                     rotation = -(float)(Math.PI / 2.0);
145             }
146 
147             Image img = null;
148             long tiffT4Options = 0;
149             long tiffT6Options = 0;
150             int fillOrder = 1;
151             int h = (int)dir.getFieldAsLong(TIFFConstants.TIFFTAG_IMAGELENGTH);
152             int w = (int)dir.getFieldAsLong(TIFFConstants.TIFFTAG_IMAGEWIDTH);
153             int dpiX = 0;
154             int dpiY = 0;
155             float XYRatio = 0;
156             int resolutionUnit = TIFFConstants.RESUNIT_INCH;
157             if (dir.isTagPresent(TIFFConstants.TIFFTAG_RESOLUTIONUNIT))
158                 resolutionUnit = (int)dir.getFieldAsLong(TIFFConstants.TIFFTAG_RESOLUTIONUNIT);
159             dpiX = getDpi(dir.getField(TIFFConstants.TIFFTAG_XRESOLUTION), resolutionUnit);
160             dpiY = getDpi(dir.getField(TIFFConstants.TIFFTAG_YRESOLUTION), resolutionUnit);
161             if (resolutionUnit == TIFFConstants.RESUNIT_NONE) {
162                 if (dpiY != 0)
163                     XYRatio = (float)dpiX / (float)dpiY;
164                 dpiX = 0;
165                 dpiY = 0;
166             }
167             int rowsStrip = h;
168             if (dir.isTagPresent(TIFFConstants.TIFFTAG_ROWSPERSTRIP))
169                 rowsStrip = (int)dir.getFieldAsLong(TIFFConstants.TIFFTAG_ROWSPERSTRIP);
170             if (rowsStrip <= 0 || rowsStrip > h)
171                 rowsStrip = h;
172             long offset[] = getArrayLongShort(dir, TIFFConstants.TIFFTAG_STRIPOFFSETS);
173             long size[] = getArrayLongShort(dir, TIFFConstants.TIFFTAG_STRIPBYTECOUNTS);
174             if ((size == null || (size.length == 1 && (size[0] == 0 || size[0] + offset[0] > s.length()))) && h == rowsStrip) { // some TIFF producers are really lousy, so...
175                 size = new long[]{s.length() - (int)offset[0]};
176             }
177             boolean reverse = false;
178             TIFFField fillOrderField =  dir.getField(TIFFConstants.TIFFTAG_FILLORDER);
179             if (fillOrderField != null)
180                 fillOrder = fillOrderField.getAsInt(0);
181             reverse = (fillOrder == TIFFConstants.FILLORDER_LSB2MSB);
182             int params = 0;
183             if (dir.isTagPresent(TIFFConstants.TIFFTAG_PHOTOMETRIC)) {
184                 long photo = dir.getFieldAsLong(TIFFConstants.TIFFTAG_PHOTOMETRIC);
185                 if (photo == TIFFConstants.PHOTOMETRIC_MINISBLACK)
186                     params |= Image.CCITT_BLACKIS1;
187             }
188             int imagecomp = 0;
189             switch (compression) {
190                 case TIFFConstants.COMPRESSION_CCITTRLEW:
191                 case TIFFConstants.COMPRESSION_CCITTRLE:
192                     imagecomp = Image.CCITTG3_1D;
193                     params |= Image.CCITT_ENCODEDBYTEALIGN | Image.CCITT_ENDOFBLOCK;
194                     break;
195                 case TIFFConstants.COMPRESSION_CCITTFAX3:
196                     imagecomp = Image.CCITTG3_1D;
197                     params |= Image.CCITT_ENDOFLINE | Image.CCITT_ENDOFBLOCK;
198                     TIFFField t4OptionsField = dir.getField(TIFFConstants.TIFFTAG_GROUP3OPTIONS);
199                     if (t4OptionsField != null) {
200                         tiffT4Options = t4OptionsField.getAsLong(0);
201                     if ((tiffT4Options & TIFFConstants.GROUP3OPT_2DENCODING) != 0)
202                         imagecomp = Image.CCITTG3_2D;
203                     if ((tiffT4Options & TIFFConstants.GROUP3OPT_FILLBITS) != 0)
204                         params |= Image.CCITT_ENCODEDBYTEALIGN;
205                     }
206                     break;
207                 case TIFFConstants.COMPRESSION_CCITTFAX4:
208                     imagecomp = Image.CCITTG4;
209                     TIFFField t6OptionsField = dir.getField(TIFFConstants.TIFFTAG_GROUP4OPTIONS);
210                     if (t6OptionsField != null)
211                         tiffT6Options = t6OptionsField.getAsLong(0);
212                     break;
213             }
214             if (direct && rowsStrip == h) { //single strip, direct
215                 byte im[] = new byte[(int)size[0]];
216                 s.seek(offset[0]);
217                 s.readFully(im);
218                 img = Image.getInstance(w, h, false, imagecomp, params, im);
219                 img.setInverted(true);
220             }
221             else {
222                 int rowsLeft = h;
223                 CCITTG4Encoder g4 = new CCITTG4Encoder(w);
224                 for (int k = 0; k < offset.length; ++k) {
225                     byte im[] = new byte[(int)size[k]];
226                     s.seek(offset[k]);
227                     s.readFully(im);
228                     int height = Math.min(rowsStrip, rowsLeft);
229                     TIFFFaxDecoder decoder = new TIFFFaxDecoder(fillOrder, w, height);
230                     byte outBuf[] = new byte[(w + 7) / 8 * height];
231                     switch (compression) {
232                         case TIFFConstants.COMPRESSION_CCITTRLEW:
233                         case TIFFConstants.COMPRESSION_CCITTRLE:
234                             decoder.decode1D(outBuf, im, 0, height);
235                             g4.fax4Encode(outBuf,height);
236                             break;
237                         case TIFFConstants.COMPRESSION_CCITTFAX3:
238                             try {
239                                 decoder.decode2D(outBuf, im, 0, height, tiffT4Options);
240                             }
241                             catch (RuntimeException e) {
242                                 // let's flip the fill bits and try again...
243                                 tiffT4Options ^= TIFFConstants.GROUP3OPT_FILLBITS;
244                                 try {
245                                     decoder.decode2D(outBuf, im, 0, height, tiffT4Options);
246                                 }
247                                 catch (RuntimeException e2) {
248                                     throw e;
249                                 }
250                             }
251                             g4.fax4Encode(outBuf, height);
252                             break;
253                         case TIFFConstants.COMPRESSION_CCITTFAX4:
254                             decoder.decodeT6(outBuf, im, 0, height, tiffT6Options);
255                             g4.fax4Encode(outBuf, height);
256                             break;
257                     }
258                     rowsLeft -= rowsStrip;
259                 }
260                 byte g4pic[] = g4.close();
261                 img = Image.getInstance(w, h, false, Image.CCITTG4, params & Image.CCITT_BLACKIS1, g4pic);
262             }
263             img.setDpi(dpiX, dpiY);
264             img.setXYRatio(XYRatio);
265             if (dir.isTagPresent(TIFFConstants.TIFFTAG_ICCPROFILE)) {
266                 try {
267                     TIFFField fd = dir.getField(TIFFConstants.TIFFTAG_ICCPROFILE);
268                     ICC_Profile icc_prof = ICC_Profile.getInstance(fd.getAsBytes());
269                     if (icc_prof.getNumComponents() == 1)
270                         img.tagICC(icc_prof);
271                 }
272                 catch (RuntimeException e) {
273                     //empty
274                 }
275             }
276             img.setOriginalType(Image.ORIGINAL_TIFF);
277             if (rotation != 0)
278                 img.setInitialRotation(rotation);
279             return img;
280         }
281         catch (Exception e) {
282             throw new ExceptionConverter(e);
283         }
284     }
285 
getTiffImageColor(TIFFDirectory dir, RandomAccessFileOrArray s)286     protected static Image getTiffImageColor(TIFFDirectory dir, RandomAccessFileOrArray s) {
287         try {
288             int compression = (int)dir.getFieldAsLong(TIFFConstants.TIFFTAG_COMPRESSION);
289             int predictor = 1;
290             TIFFLZWDecoder lzwDecoder = null;
291             switch (compression) {
292                 case TIFFConstants.COMPRESSION_NONE:
293                 case TIFFConstants.COMPRESSION_LZW:
294                 case TIFFConstants.COMPRESSION_PACKBITS:
295                 case TIFFConstants.COMPRESSION_DEFLATE:
296                 case TIFFConstants.COMPRESSION_ADOBE_DEFLATE:
297                 case TIFFConstants.COMPRESSION_OJPEG:
298                 case TIFFConstants.COMPRESSION_JPEG:
299                     break;
300                 default:
301                     throw new IllegalArgumentException(MessageLocalization.getComposedMessage("the.compression.1.is.not.supported", compression));
302             }
303             int photometric = (int)dir.getFieldAsLong(TIFFConstants.TIFFTAG_PHOTOMETRIC);
304             switch (photometric) {
305                 case TIFFConstants.PHOTOMETRIC_MINISWHITE:
306                 case TIFFConstants.PHOTOMETRIC_MINISBLACK:
307                 case TIFFConstants.PHOTOMETRIC_RGB:
308                 case TIFFConstants.PHOTOMETRIC_SEPARATED:
309                 case TIFFConstants.PHOTOMETRIC_PALETTE:
310                     break;
311                 default:
312                     if (compression != TIFFConstants.COMPRESSION_OJPEG && compression != TIFFConstants.COMPRESSION_JPEG)
313                         throw new IllegalArgumentException(MessageLocalization.getComposedMessage("the.photometric.1.is.not.supported", photometric));
314             }
315             float rotation = 0;
316             if (dir.isTagPresent(TIFFConstants.TIFFTAG_ORIENTATION)) {
317                 int rot = (int)dir.getFieldAsLong(TIFFConstants.TIFFTAG_ORIENTATION);
318                 if (rot == TIFFConstants.ORIENTATION_BOTRIGHT || rot == TIFFConstants.ORIENTATION_BOTLEFT)
319                     rotation = (float)Math.PI;
320                 else if (rot == TIFFConstants.ORIENTATION_LEFTTOP || rot == TIFFConstants.ORIENTATION_LEFTBOT)
321                     rotation = (float)(Math.PI / 2.0);
322                 else if (rot == TIFFConstants.ORIENTATION_RIGHTTOP || rot == TIFFConstants.ORIENTATION_RIGHTBOT)
323                     rotation = -(float)(Math.PI / 2.0);
324             }
325             if (dir.isTagPresent(TIFFConstants.TIFFTAG_PLANARCONFIG)
326                 && dir.getFieldAsLong(TIFFConstants.TIFFTAG_PLANARCONFIG) == TIFFConstants.PLANARCONFIG_SEPARATE)
327                 throw new IllegalArgumentException(MessageLocalization.getComposedMessage("planar.images.are.not.supported"));
328             if (dir.isTagPresent(TIFFConstants.TIFFTAG_EXTRASAMPLES))
329                 throw new IllegalArgumentException(MessageLocalization.getComposedMessage("extra.samples.are.not.supported"));
330             int samplePerPixel = 1;
331             if (dir.isTagPresent(TIFFConstants.TIFFTAG_SAMPLESPERPIXEL)) // 1,3,4
332                 samplePerPixel = (int)dir.getFieldAsLong(TIFFConstants.TIFFTAG_SAMPLESPERPIXEL);
333             int bitsPerSample = 1;
334             if (dir.isTagPresent(TIFFConstants.TIFFTAG_BITSPERSAMPLE))
335                 bitsPerSample = (int)dir.getFieldAsLong(TIFFConstants.TIFFTAG_BITSPERSAMPLE);
336             switch (bitsPerSample) {
337                 case 1:
338                 case 2:
339                 case 4:
340                 case 8:
341                     break;
342                 default:
343                     throw new IllegalArgumentException(MessageLocalization.getComposedMessage("bits.per.sample.1.is.not.supported", bitsPerSample));
344             }
345             Image img = null;
346 
347             int h = (int)dir.getFieldAsLong(TIFFConstants.TIFFTAG_IMAGELENGTH);
348             int w = (int)dir.getFieldAsLong(TIFFConstants.TIFFTAG_IMAGEWIDTH);
349             int dpiX = 0;
350             int dpiY = 0;
351             int resolutionUnit = TIFFConstants.RESUNIT_INCH;
352             if (dir.isTagPresent(TIFFConstants.TIFFTAG_RESOLUTIONUNIT))
353                 resolutionUnit = (int)dir.getFieldAsLong(TIFFConstants.TIFFTAG_RESOLUTIONUNIT);
354             dpiX = getDpi(dir.getField(TIFFConstants.TIFFTAG_XRESOLUTION), resolutionUnit);
355             dpiY = getDpi(dir.getField(TIFFConstants.TIFFTAG_YRESOLUTION), resolutionUnit);
356             int fillOrder = 1;
357             boolean reverse = false;
358             TIFFField fillOrderField =  dir.getField(TIFFConstants.TIFFTAG_FILLORDER);
359             if (fillOrderField != null)
360                 fillOrder = fillOrderField.getAsInt(0);
361             reverse = (fillOrder == TIFFConstants.FILLORDER_LSB2MSB);
362             int rowsStrip = h;
363             if (dir.isTagPresent(TIFFConstants.TIFFTAG_ROWSPERSTRIP)) //another hack for broken tiffs
364                 rowsStrip = (int)dir.getFieldAsLong(TIFFConstants.TIFFTAG_ROWSPERSTRIP);
365             if (rowsStrip <= 0 || rowsStrip > h)
366                 rowsStrip = h;
367             long offset[] = getArrayLongShort(dir, TIFFConstants.TIFFTAG_STRIPOFFSETS);
368             long size[] = getArrayLongShort(dir, TIFFConstants.TIFFTAG_STRIPBYTECOUNTS);
369             if ((size == null || (size.length == 1 && (size[0] == 0 || size[0] + offset[0] > s.length()))) && h == rowsStrip) { // some TIFF producers are really lousy, so...
370                 size = new long[]{s.length() - (int)offset[0]};
371             }
372             if (compression == TIFFConstants.COMPRESSION_LZW) {
373                 TIFFField predictorField = dir.getField(TIFFConstants.TIFFTAG_PREDICTOR);
374                 if (predictorField != null) {
375                     predictor = predictorField.getAsInt(0);
376                     if (predictor != 1 && predictor != 2) {
377                         throw new RuntimeException(MessageLocalization.getComposedMessage("illegal.value.for.predictor.in.tiff.file"));
378                     }
379                     if (predictor == 2 && bitsPerSample != 8) {
380                         throw new RuntimeException(MessageLocalization.getComposedMessage("1.bit.samples.are.not.supported.for.horizontal.differencing.predictor", bitsPerSample));
381                     }
382                 }
383                 lzwDecoder = new TIFFLZWDecoder(w, predictor,
384                                                 samplePerPixel);
385             }
386             int rowsLeft = h;
387             ByteArrayOutputStream stream = null;
388             DeflaterOutputStream zip = null;
389             CCITTG4Encoder g4 = null;
390             if (bitsPerSample == 1 && samplePerPixel == 1) {
391                 g4 = new CCITTG4Encoder(w);
392             }
393             else {
394                 stream = new ByteArrayOutputStream();
395                 if (compression != TIFFConstants.COMPRESSION_OJPEG && compression != TIFFConstants.COMPRESSION_JPEG)
396                     zip = new DeflaterOutputStream(stream);
397             }
398             if (compression == TIFFConstants.COMPRESSION_OJPEG) {
399 
400                 // Assume that the TIFFTAG_JPEGIFBYTECOUNT tag is optional, since it's obsolete and
401                 // is often missing
402 
403                 if ((!dir.isTagPresent(TIFFConstants.TIFFTAG_JPEGIFOFFSET))) {
404                     throw new IOException(MessageLocalization.getComposedMessage("missing.tag.s.for.ojpeg.compression"));
405                 }
406                 int jpegOffset = (int)dir.getFieldAsLong(TIFFConstants.TIFFTAG_JPEGIFOFFSET);
407                 int jpegLength = s.length() - jpegOffset;
408 
409                 if (dir.isTagPresent(TIFFConstants.TIFFTAG_JPEGIFBYTECOUNT)) {
410                     jpegLength = (int)dir.getFieldAsLong(TIFFConstants.TIFFTAG_JPEGIFBYTECOUNT) +
411                         (int)size[0];
412                 }
413 
414                 byte[] jpeg = new byte[Math.min(jpegLength, s.length() - jpegOffset)];
415 
416                 int posFilePointer = s.getFilePointer();
417                 posFilePointer += jpegOffset;
418                 s.seek(posFilePointer);
419                 s.readFully(jpeg);
420                 img = new Jpeg(jpeg);
421             }
422             else if (compression == TIFFConstants.COMPRESSION_JPEG) {
423                 if (size.length > 1)
424                     throw new IOException(MessageLocalization.getComposedMessage("compression.jpeg.is.only.supported.with.a.single.strip.this.image.has.1.strips", size.length));
425                 byte[] jpeg = new byte[(int)size[0]];
426                 s.seek(offset[0]);
427                 s.readFully(jpeg);
428                 img = new Jpeg(jpeg);
429             }
430             else {
431                 for (int k = 0; k < offset.length; ++k) {
432                     byte im[] = new byte[(int)size[k]];
433                     s.seek(offset[k]);
434                     s.readFully(im);
435                     int height = Math.min(rowsStrip, rowsLeft);
436                     byte outBuf[] = null;
437                     if (compression != TIFFConstants.COMPRESSION_NONE)
438                         outBuf = new byte[(w * bitsPerSample * samplePerPixel + 7) / 8 * height];
439                     if (reverse)
440                         TIFFFaxDecoder.reverseBits(im);
441                     switch (compression) {
442                         case TIFFConstants.COMPRESSION_DEFLATE:
443                         case TIFFConstants.COMPRESSION_ADOBE_DEFLATE:
444                             inflate(im, outBuf);
445                             break;
446                         case TIFFConstants.COMPRESSION_NONE:
447                             outBuf = im;
448                             break;
449                         case TIFFConstants.COMPRESSION_PACKBITS:
450                             decodePackbits(im,  outBuf);
451                             break;
452                         case TIFFConstants.COMPRESSION_LZW:
453                             lzwDecoder.decode(im, outBuf, height);
454                             break;
455                     }
456                     if (bitsPerSample == 1 && samplePerPixel == 1) {
457                         g4.fax4Encode(outBuf, height);
458                     }
459                     else {
460                         zip.write(outBuf);
461                     }
462                     rowsLeft -= rowsStrip;
463                 }
464                 if (bitsPerSample == 1 && samplePerPixel == 1) {
465                     img = Image.getInstance(w, h, false, Image.CCITTG4,
466                         photometric == TIFFConstants.PHOTOMETRIC_MINISBLACK ? Image.CCITT_BLACKIS1 : 0, g4.close());
467                 }
468                 else {
469                     zip.close();
470                     img = Image.getInstance(w, h, samplePerPixel, bitsPerSample, stream.toByteArray());
471                     img.setDeflated(true);
472                 }
473             }
474             img.setDpi(dpiX, dpiY);
475             if (compression != TIFFConstants.COMPRESSION_OJPEG && compression != TIFFConstants.COMPRESSION_JPEG) {
476                 if (dir.isTagPresent(TIFFConstants.TIFFTAG_ICCPROFILE)) {
477                     try {
478                         TIFFField fd = dir.getField(TIFFConstants.TIFFTAG_ICCPROFILE);
479                         ICC_Profile icc_prof = ICC_Profile.getInstance(fd.getAsBytes());
480                         if (samplePerPixel == icc_prof.getNumComponents())
481                             img.tagICC(icc_prof);
482                     }
483                     catch (RuntimeException e) {
484                         //empty
485                     }
486                 }
487                 if (dir.isTagPresent(TIFFConstants.TIFFTAG_COLORMAP)) {
488                     TIFFField fd = dir.getField(TIFFConstants.TIFFTAG_COLORMAP);
489                     char rgb[] = fd.getAsChars();
490                     byte palette[] = new byte[rgb.length];
491                     int gColor = rgb.length / 3;
492                     int bColor = gColor * 2;
493                     for (int k = 0; k < gColor; ++k) {
494                         palette[k * 3] = (byte)(rgb[k] >>> 8);
495                         palette[k * 3 + 1] = (byte)(rgb[k + gColor] >>> 8);
496                         palette[k * 3 + 2] = (byte)(rgb[k + bColor] >>> 8);
497                     }
498                     PdfArray indexed = new PdfArray();
499                     indexed.add(PdfName.INDEXED);
500                     indexed.add(PdfName.DEVICERGB);
501                     indexed.add(new PdfNumber(gColor - 1));
502                     indexed.add(new PdfString(palette));
503                     PdfDictionary additional = new PdfDictionary();
504                     additional.put(PdfName.COLORSPACE, indexed);
505                     img.setAdditional(additional);
506                 }
507                 img.setOriginalType(Image.ORIGINAL_TIFF);
508             }
509             if (photometric == TIFFConstants.PHOTOMETRIC_MINISWHITE)
510                 img.setInverted(true);
511             if (rotation != 0)
512                 img.setInitialRotation(rotation);
513             return img;
514         }
515         catch (Exception e) {
516             throw new ExceptionConverter(e);
517         }
518     }
519 
getArrayLongShort(TIFFDirectory dir, int tag)520     static long[] getArrayLongShort(TIFFDirectory dir, int tag) {
521         TIFFField field = dir.getField(tag);
522         if (field == null)
523             return null;
524         long offset[];
525         if (field.getType() == TIFFField.TIFF_LONG)
526             offset = field.getAsLongs();
527         else { // must be short
528             char temp[] = field.getAsChars();
529             offset = new long[temp.length];
530             for (int k = 0; k < temp.length; ++k)
531                 offset[k] = temp[k];
532         }
533         return offset;
534     }
535 
536     // Uncompress packbits compressed image data.
decodePackbits(byte data[], byte[] dst)537     public static void decodePackbits(byte data[], byte[] dst) {
538         int srcCount = 0, dstCount = 0;
539         byte repeat, b;
540 
541         try {
542             while (dstCount < dst.length) {
543                 b = data[srcCount++];
544                 if (b >= 0 && b <= 127) {
545                     // literal run packet
546                     for (int i=0; i<(b + 1); i++) {
547                         dst[dstCount++] = data[srcCount++];
548                     }
549 
550                 } else if (b <= -1 && b >= -127) {
551                     // 2 byte encoded run packet
552                     repeat = data[srcCount++];
553                     for (int i=0; i<(-b + 1); i++) {
554                         dst[dstCount++] = repeat;
555                     }
556                 } else {
557                     // no-op packet. Do nothing
558                     srcCount++;
559                 }
560             }
561         }
562         catch (Exception e) {
563             // do nothing
564         }
565     }
566 
inflate(byte[] deflated, byte[] inflated)567     public static void inflate(byte[] deflated, byte[] inflated) {
568         Inflater inflater = new Inflater();
569         inflater.setInput(deflated);
570         try {
571             inflater.inflate(inflated);
572         }
573         catch(DataFormatException dfe) {
574             throw new ExceptionConverter(dfe);
575         }
576     }
577 
578 }
579