001: /*
002: * Copyright 2003-2005 by Paulo Soares.
003: *
004: * The contents of this file are subject to the Mozilla Public License Version 1.1
005: * (the "License"); you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at http://www.mozilla.org/MPL/
007: *
008: * Software distributed under the License is distributed on an "AS IS" basis,
009: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
010: * for the specific language governing rights and limitations under the License.
011: *
012: * The Original Code is 'iText, a free JAVA-PDF library'.
013: *
014: * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by
015: * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie.
016: * All Rights Reserved.
017: * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer
018: * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved.
019: *
020: * Contributor(s): all the names of the contributors are added in the source code
021: * where applicable.
022: *
023: * Alternatively, the contents of this file may be used under the terms of the
024: * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the
025: * provisions of LGPL are applicable instead of those above. If you wish to
026: * allow use of your version of this file only under the terms of the LGPL
027: * License and not to allow others to use your version of this file under
028: * the MPL, indicate your decision by deleting the provisions above and
029: * replace them with the notice and other provisions required by the LGPL.
030: * If you do not delete the provisions above, a recipient may use your version
031: * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE.
032: *
033: * This library is free software; you can redistribute it and/or modify it
034: * under the terms of the MPL as stated above or under the terms of the GNU
035: * Library General Public License as published by the Free Software Foundation;
036: * either version 2 of the License, or any later version.
037: *
038: * This library is distributed in the hope that it will be useful, but WITHOUT
039: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
040: * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more
041: * details.
042: *
043: * If you didn't download this code from the following link, you should check if
044: * you aren't using an obsolete version:
045: * http://www.lowagie.com/iText/
046: */
047: package com.lowagie.text.pdf.codec;
048:
049: import java.awt.color.ICC_Profile;
050: import java.io.ByteArrayOutputStream;
051: import java.io.IOException;
052: import java.util.zip.DataFormatException;
053: import java.util.zip.DeflaterOutputStream;
054: import java.util.zip.Inflater;
055:
056: import com.lowagie.text.ExceptionConverter;
057: import com.lowagie.text.Image;
058: import com.lowagie.text.Jpeg;
059: import com.lowagie.text.pdf.PdfArray;
060: import com.lowagie.text.pdf.PdfDictionary;
061: import com.lowagie.text.pdf.PdfName;
062: import com.lowagie.text.pdf.PdfNumber;
063: import com.lowagie.text.pdf.PdfString;
064: import com.lowagie.text.pdf.RandomAccessFileOrArray;
065:
066: /** Reads TIFF images
067: * @author Paulo Soares (psoares@consiste.pt)
068: */
069: public class TiffImage {
070:
071: /** Gets the number of pages the TIFF document has.
072: * @param s the file source
073: * @return the number of pages
074: */
075: public static int getNumberOfPages(RandomAccessFileOrArray s) {
076: try {
077: return TIFFDirectory.getNumDirectories(s);
078: } catch (Exception e) {
079: throw new ExceptionConverter(e);
080: }
081: }
082:
083: static int getDpi(TIFFField fd, int resolutionUnit) {
084: if (fd == null)
085: return 0;
086: long res[] = fd.getAsRational(0);
087: float frac = (float) res[0] / (float) res[1];
088: int dpi = 0;
089: switch (resolutionUnit) {
090: case TIFFConstants.RESUNIT_INCH:
091: case TIFFConstants.RESUNIT_NONE:
092: dpi = (int) (frac + 0.5);
093: break;
094: case TIFFConstants.RESUNIT_CENTIMETER:
095: dpi = (int) (frac * 2.54 + 0.5);
096: break;
097: }
098: return dpi;
099: }
100:
101: /** Reads a page from a TIFF image. Direct mode is not used.
102: * @param s the file source
103: * @param page the page to get. The first page is 1
104: * @return the <CODE>Image</CODE>
105: */
106: public static Image getTiffImage(RandomAccessFileOrArray s, int page) {
107: return getTiffImage(s, page, false);
108: }
109:
110: /** Reads a page from a TIFF image.
111: * @param s the file source
112: * @param page the page to get. The first page is 1
113: * @param direct for single strip, CCITT images, generate the image
114: * by direct byte copying. It's faster but may not work
115: * every time
116: * @return the <CODE>Image</CODE>
117: */
118: public static Image getTiffImage(RandomAccessFileOrArray s,
119: int page, boolean direct) {
120: if (page < 1)
121: throw new IllegalArgumentException(
122: "The page number must be >= 1.");
123: try {
124: TIFFDirectory dir = new TIFFDirectory(s, page - 1);
125: if (dir.isTagPresent(TIFFConstants.TIFFTAG_TILEWIDTH))
126: throw new IllegalArgumentException(
127: "Tiles are not supported.");
128: int compression = (int) dir
129: .getFieldAsLong(TIFFConstants.TIFFTAG_COMPRESSION);
130: switch (compression) {
131: case TIFFConstants.COMPRESSION_CCITTRLEW:
132: case TIFFConstants.COMPRESSION_CCITTRLE:
133: case TIFFConstants.COMPRESSION_CCITTFAX3:
134: case TIFFConstants.COMPRESSION_CCITTFAX4:
135: break;
136: default:
137: return getTiffImageColor(dir, s);
138: }
139: float rotation = 0;
140: if (dir.isTagPresent(TIFFConstants.TIFFTAG_ORIENTATION)) {
141: int rot = (int) dir
142: .getFieldAsLong(TIFFConstants.TIFFTAG_ORIENTATION);
143: if (rot == TIFFConstants.ORIENTATION_BOTRIGHT
144: || rot == TIFFConstants.ORIENTATION_BOTLEFT)
145: rotation = (float) Math.PI;
146: else if (rot == TIFFConstants.ORIENTATION_LEFTTOP
147: || rot == TIFFConstants.ORIENTATION_LEFTBOT)
148: rotation = (float) (Math.PI / 2.0);
149: else if (rot == TIFFConstants.ORIENTATION_RIGHTTOP
150: || rot == TIFFConstants.ORIENTATION_RIGHTBOT)
151: rotation = -(float) (Math.PI / 2.0);
152: }
153:
154: Image img = null;
155: long tiffT4Options = 0;
156: long tiffT6Options = 0;
157: int fillOrder = 1;
158: int h = (int) dir
159: .getFieldAsLong(TIFFConstants.TIFFTAG_IMAGELENGTH);
160: int w = (int) dir
161: .getFieldAsLong(TIFFConstants.TIFFTAG_IMAGEWIDTH);
162: int dpiX = 0;
163: int dpiY = 0;
164: float XYRatio = 0;
165: int resolutionUnit = TIFFConstants.RESUNIT_INCH;
166: if (dir.isTagPresent(TIFFConstants.TIFFTAG_RESOLUTIONUNIT))
167: resolutionUnit = (int) dir
168: .getFieldAsLong(TIFFConstants.TIFFTAG_RESOLUTIONUNIT);
169: dpiX = getDpi(dir
170: .getField(TIFFConstants.TIFFTAG_XRESOLUTION),
171: resolutionUnit);
172: dpiY = getDpi(dir
173: .getField(TIFFConstants.TIFFTAG_YRESOLUTION),
174: resolutionUnit);
175: if (resolutionUnit == TIFFConstants.RESUNIT_NONE) {
176: if (dpiY != 0)
177: XYRatio = (float) dpiX / (float) dpiY;
178: dpiX = 0;
179: dpiY = 0;
180: }
181: long tstrip = 0xFFFFFFFFL;
182: if (dir.isTagPresent(TIFFConstants.TIFFTAG_ROWSPERSTRIP))
183: tstrip = dir
184: .getFieldAsLong(TIFFConstants.TIFFTAG_ROWSPERSTRIP);
185: int rowsStrip = (int) Math.min(h, tstrip);
186: long offset[] = getArrayLongShort(dir,
187: TIFFConstants.TIFFTAG_STRIPOFFSETS);
188: long size[] = getArrayLongShort(dir,
189: TIFFConstants.TIFFTAG_STRIPBYTECOUNTS);
190: if ((size == null || (size.length == 1 && size[0] == 0))
191: && h == rowsStrip) { // some TIFF producers are really lousy, so...
192: size = new long[] { s.length() - (int) offset[0] };
193: }
194: boolean reverse = false;
195: TIFFField fillOrderField = dir
196: .getField(TIFFConstants.TIFFTAG_FILLORDER);
197: if (fillOrderField != null)
198: fillOrder = fillOrderField.getAsInt(0);
199: reverse = (fillOrder == TIFFConstants.FILLORDER_LSB2MSB);
200: int params = 0;
201: if (dir.isTagPresent(TIFFConstants.TIFFTAG_PHOTOMETRIC)) {
202: long photo = dir
203: .getFieldAsLong(TIFFConstants.TIFFTAG_PHOTOMETRIC);
204: if (photo == TIFFConstants.PHOTOMETRIC_MINISBLACK)
205: params |= Image.CCITT_BLACKIS1;
206: }
207: int imagecomp = 0;
208: switch (compression) {
209: case TIFFConstants.COMPRESSION_CCITTRLEW:
210: case TIFFConstants.COMPRESSION_CCITTRLE:
211: imagecomp = Image.CCITTG3_1D;
212: params |= Image.CCITT_ENCODEDBYTEALIGN
213: | Image.CCITT_ENDOFBLOCK;
214: break;
215: case TIFFConstants.COMPRESSION_CCITTFAX3:
216: imagecomp = Image.CCITTG3_1D;
217: params |= Image.CCITT_ENDOFLINE
218: | Image.CCITT_ENDOFBLOCK;
219: TIFFField t4OptionsField = dir
220: .getField(TIFFConstants.TIFFTAG_GROUP3OPTIONS);
221: if (t4OptionsField != null) {
222: tiffT4Options = t4OptionsField.getAsLong(0);
223: if ((tiffT4Options & TIFFConstants.GROUP3OPT_2DENCODING) != 0)
224: imagecomp = Image.CCITTG3_2D;
225: if ((tiffT4Options & TIFFConstants.GROUP3OPT_FILLBITS) != 0)
226: params |= Image.CCITT_ENCODEDBYTEALIGN;
227: }
228: break;
229: case TIFFConstants.COMPRESSION_CCITTFAX4:
230: imagecomp = Image.CCITTG4;
231: TIFFField t6OptionsField = dir
232: .getField(TIFFConstants.TIFFTAG_GROUP4OPTIONS);
233: if (t6OptionsField != null)
234: tiffT6Options = t6OptionsField.getAsLong(0);
235: break;
236: }
237: if (direct && rowsStrip == h) { //single strip, direct
238: byte im[] = new byte[(int) size[0]];
239: s.seek(offset[0]);
240: s.readFully(im);
241: img = Image.getInstance(w, h, reverse, imagecomp,
242: params, im);
243: img.setInverted(true);
244: } else {
245: int rowsLeft = h;
246: CCITTG4Encoder g4 = new CCITTG4Encoder(w);
247: for (int k = 0; k < offset.length; ++k) {
248: byte im[] = new byte[(int) size[k]];
249: s.seek(offset[k]);
250: s.readFully(im);
251: int height = Math.min(rowsStrip, rowsLeft);
252: TIFFFaxDecoder decoder = new TIFFFaxDecoder(
253: fillOrder, w, height);
254: byte outBuf[] = new byte[(w + 7) / 8 * height];
255: switch (compression) {
256: case TIFFConstants.COMPRESSION_CCITTRLEW:
257: case TIFFConstants.COMPRESSION_CCITTRLE:
258: decoder.decode1D(outBuf, im, 0, height);
259: g4.fax4Encode(outBuf, height);
260: break;
261: case TIFFConstants.COMPRESSION_CCITTFAX3:
262: try {
263: decoder.decode2D(outBuf, im, 0, height,
264: tiffT4Options);
265: } catch (RuntimeException e) {
266: // let's flip the fill bits and try again...
267: tiffT4Options ^= TIFFConstants.GROUP3OPT_FILLBITS;
268: try {
269: decoder.decode2D(outBuf, im, 0, height,
270: tiffT4Options);
271: } catch (RuntimeException e2) {
272: throw e;
273: }
274: }
275: g4.fax4Encode(outBuf, height);
276: break;
277: case TIFFConstants.COMPRESSION_CCITTFAX4:
278: decoder.decodeT6(outBuf, im, 0, height,
279: tiffT6Options);
280: g4.fax4Encode(outBuf, height);
281: break;
282: }
283: rowsLeft -= rowsStrip;
284: }
285: byte g4pic[] = g4.close();
286: img = Image.getInstance(w, h, false, Image.CCITTG4,
287: params & Image.CCITT_BLACKIS1, g4pic);
288: }
289: img.setDpi(dpiX, dpiY);
290: img.setXYRatio(XYRatio);
291: if (dir.isTagPresent(TIFFConstants.TIFFTAG_ICCPROFILE)) {
292: try {
293: TIFFField fd = dir
294: .getField(TIFFConstants.TIFFTAG_ICCPROFILE);
295: ICC_Profile icc_prof = ICC_Profile.getInstance(fd
296: .getAsBytes());
297: if (icc_prof.getNumComponents() == 1)
298: img.tagICC(icc_prof);
299: } catch (RuntimeException e) {
300: //empty
301: }
302: }
303: img.setOriginalType(Image.ORIGINAL_TIFF);
304: if (rotation != 0)
305: img.setInitialRotation(rotation);
306: return img;
307: } catch (Exception e) {
308: throw new ExceptionConverter(e);
309: }
310: }
311:
312: protected static Image getTiffImageColor(TIFFDirectory dir,
313: RandomAccessFileOrArray s) {
314: try {
315: int compression = (int) dir
316: .getFieldAsLong(TIFFConstants.TIFFTAG_COMPRESSION);
317: int predictor = 1;
318: TIFFLZWDecoder lzwDecoder = null;
319: switch (compression) {
320: case TIFFConstants.COMPRESSION_NONE:
321: case TIFFConstants.COMPRESSION_LZW:
322: case TIFFConstants.COMPRESSION_PACKBITS:
323: case TIFFConstants.COMPRESSION_DEFLATE:
324: case TIFFConstants.COMPRESSION_OJPEG:
325: case TIFFConstants.COMPRESSION_JPEG:
326: break;
327: default:
328: throw new IllegalArgumentException("The compression "
329: + compression + " is not supported.");
330: }
331: int photometric = (int) dir
332: .getFieldAsLong(TIFFConstants.TIFFTAG_PHOTOMETRIC);
333: switch (photometric) {
334: case TIFFConstants.PHOTOMETRIC_MINISWHITE:
335: case TIFFConstants.PHOTOMETRIC_MINISBLACK:
336: case TIFFConstants.PHOTOMETRIC_RGB:
337: case TIFFConstants.PHOTOMETRIC_SEPARATED:
338: case TIFFConstants.PHOTOMETRIC_PALETTE:
339: break;
340: default:
341: if (compression != TIFFConstants.COMPRESSION_OJPEG
342: && compression != TIFFConstants.COMPRESSION_JPEG)
343: throw new IllegalArgumentException(
344: "The photometric " + photometric
345: + " is not supported.");
346: }
347: float rotation = 0;
348: if (dir.isTagPresent(TIFFConstants.TIFFTAG_ORIENTATION)) {
349: int rot = (int) dir
350: .getFieldAsLong(TIFFConstants.TIFFTAG_ORIENTATION);
351: if (rot == TIFFConstants.ORIENTATION_BOTRIGHT
352: || rot == TIFFConstants.ORIENTATION_BOTLEFT)
353: rotation = (float) Math.PI;
354: else if (rot == TIFFConstants.ORIENTATION_LEFTTOP
355: || rot == TIFFConstants.ORIENTATION_LEFTBOT)
356: rotation = (float) (Math.PI / 2.0);
357: else if (rot == TIFFConstants.ORIENTATION_RIGHTTOP
358: || rot == TIFFConstants.ORIENTATION_RIGHTBOT)
359: rotation = -(float) (Math.PI / 2.0);
360: }
361: if (dir.isTagPresent(TIFFConstants.TIFFTAG_PLANARCONFIG)
362: && dir
363: .getFieldAsLong(TIFFConstants.TIFFTAG_PLANARCONFIG) == TIFFConstants.PLANARCONFIG_SEPARATE)
364: throw new IllegalArgumentException(
365: "Planar images are not supported.");
366: if (dir.isTagPresent(TIFFConstants.TIFFTAG_EXTRASAMPLES))
367: throw new IllegalArgumentException(
368: "Extra samples are not supported.");
369: int samplePerPixel = 1;
370: if (dir.isTagPresent(TIFFConstants.TIFFTAG_SAMPLESPERPIXEL)) // 1,3,4
371: samplePerPixel = (int) dir
372: .getFieldAsLong(TIFFConstants.TIFFTAG_SAMPLESPERPIXEL);
373: int bitsPerSample = 1;
374: if (dir.isTagPresent(TIFFConstants.TIFFTAG_BITSPERSAMPLE))
375: bitsPerSample = (int) dir
376: .getFieldAsLong(TIFFConstants.TIFFTAG_BITSPERSAMPLE);
377: switch (bitsPerSample) {
378: case 1:
379: case 2:
380: case 4:
381: case 8:
382: break;
383: default:
384: throw new IllegalArgumentException("Bits per sample "
385: + bitsPerSample + " is not supported.");
386: }
387: Image img = null;
388:
389: int h = (int) dir
390: .getFieldAsLong(TIFFConstants.TIFFTAG_IMAGELENGTH);
391: int w = (int) dir
392: .getFieldAsLong(TIFFConstants.TIFFTAG_IMAGEWIDTH);
393: int dpiX = 0;
394: int dpiY = 0;
395: int resolutionUnit = TIFFConstants.RESUNIT_INCH;
396: if (dir.isTagPresent(TIFFConstants.TIFFTAG_RESOLUTIONUNIT))
397: resolutionUnit = (int) dir
398: .getFieldAsLong(TIFFConstants.TIFFTAG_RESOLUTIONUNIT);
399: dpiX = getDpi(dir
400: .getField(TIFFConstants.TIFFTAG_XRESOLUTION),
401: resolutionUnit);
402: dpiY = getDpi(dir
403: .getField(TIFFConstants.TIFFTAG_YRESOLUTION),
404: resolutionUnit);
405: int rowsStrip = h;
406: if (dir.isTagPresent(TIFFConstants.TIFFTAG_ROWSPERSTRIP)) //another hack for broken tiffs
407: rowsStrip = (int) dir
408: .getFieldAsLong(TIFFConstants.TIFFTAG_ROWSPERSTRIP);
409: long offset[] = getArrayLongShort(dir,
410: TIFFConstants.TIFFTAG_STRIPOFFSETS);
411: long size[] = getArrayLongShort(dir,
412: TIFFConstants.TIFFTAG_STRIPBYTECOUNTS);
413: if ((size == null || (size.length == 1 && size[0] == 0))
414: && h == rowsStrip) { // some TIFF producers are really lousy, so...
415: size = new long[] { s.length() - (int) offset[0] };
416: }
417: if (compression == TIFFConstants.COMPRESSION_LZW) {
418: TIFFField predictorField = dir
419: .getField(TIFFConstants.TIFFTAG_PREDICTOR);
420: if (predictorField != null) {
421: predictor = predictorField.getAsInt(0);
422: if (predictor != 1 && predictor != 2) {
423: throw new RuntimeException(
424: "Illegal value for Predictor in TIFF file.");
425: }
426: if (predictor == 2 && bitsPerSample != 8) {
427: throw new RuntimeException(
428: bitsPerSample
429: + "-bit samples are not supported for Horizontal differencing Predictor.");
430: }
431: }
432: lzwDecoder = new TIFFLZWDecoder(w, predictor,
433: samplePerPixel);
434: }
435: int rowsLeft = h;
436: ByteArrayOutputStream stream = null;
437: DeflaterOutputStream zip = null;
438: CCITTG4Encoder g4 = null;
439: if (bitsPerSample == 1 && samplePerPixel == 1) {
440: g4 = new CCITTG4Encoder(w);
441: } else {
442: stream = new ByteArrayOutputStream();
443: if (compression != TIFFConstants.COMPRESSION_OJPEG
444: && compression != TIFFConstants.COMPRESSION_JPEG)
445: zip = new DeflaterOutputStream(stream);
446: }
447: if (compression == TIFFConstants.COMPRESSION_OJPEG) {
448:
449: // Assume that the TIFFTAG_JPEGIFBYTECOUNT tag is optional, since it's obsolete and
450: // is often missing
451:
452: if ((!dir
453: .isTagPresent(TIFFConstants.TIFFTAG_JPEGIFOFFSET))) {
454: throw new IOException(
455: "Missing tag(s) for OJPEG compression.");
456: }
457: int jpegOffset = (int) dir
458: .getFieldAsLong(TIFFConstants.TIFFTAG_JPEGIFOFFSET);
459: int jpegLength = s.length() - jpegOffset;
460:
461: if (dir
462: .isTagPresent(TIFFConstants.TIFFTAG_JPEGIFBYTECOUNT)) {
463: jpegLength = (int) dir
464: .getFieldAsLong(TIFFConstants.TIFFTAG_JPEGIFBYTECOUNT)
465: + (int) size[0];
466: }
467:
468: byte[] jpeg = new byte[Math.min(jpegLength, s.length()
469: - jpegOffset)];
470:
471: int posFilePointer = s.getFilePointer();
472: posFilePointer += jpegOffset;
473: s.seek(posFilePointer);
474: s.readFully(jpeg);
475: img = new Jpeg(jpeg);
476: } else if (compression == TIFFConstants.COMPRESSION_JPEG) {
477: if (size.length > 1)
478: throw new IOException(
479: "Compression JPEG is only supported with a single strip. This image has "
480: + size.length + " strips.");
481: byte[] jpeg = new byte[(int) size[0]];
482: s.seek(offset[0]);
483: s.readFully(jpeg);
484: img = new Jpeg(jpeg);
485: } else {
486: for (int k = 0; k < offset.length; ++k) {
487: byte im[] = new byte[(int) size[k]];
488: s.seek(offset[k]);
489: s.readFully(im);
490: int height = Math.min(rowsStrip, rowsLeft);
491: byte outBuf[] = null;
492: if (compression != TIFFConstants.COMPRESSION_NONE)
493: outBuf = new byte[(w * bitsPerSample
494: * samplePerPixel + 7)
495: / 8 * height];
496: switch (compression) {
497: case TIFFConstants.COMPRESSION_DEFLATE:
498: inflate(im, outBuf);
499: break;
500: case TIFFConstants.COMPRESSION_NONE:
501: outBuf = im;
502: break;
503: case TIFFConstants.COMPRESSION_PACKBITS:
504: decodePackbits(im, outBuf);
505: break;
506: case TIFFConstants.COMPRESSION_LZW:
507: lzwDecoder.decode(im, outBuf, height);
508: break;
509: }
510: if (bitsPerSample == 1 && samplePerPixel == 1) {
511: g4.fax4Encode(outBuf, height);
512: } else {
513: zip.write(outBuf);
514: }
515: rowsLeft -= rowsStrip;
516: }
517: if (bitsPerSample == 1 && samplePerPixel == 1) {
518: img = Image
519: .getInstance(
520: w,
521: h,
522: false,
523: Image.CCITTG4,
524: photometric == TIFFConstants.PHOTOMETRIC_MINISBLACK ? Image.CCITT_BLACKIS1
525: : 0, g4.close());
526: } else {
527: zip.close();
528: img = Image.getInstance(w, h, samplePerPixel,
529: bitsPerSample, stream.toByteArray());
530: img.setDeflated(true);
531: }
532: }
533: img.setDpi(dpiX, dpiY);
534: if (compression != TIFFConstants.COMPRESSION_OJPEG
535: && compression != TIFFConstants.COMPRESSION_JPEG) {
536: if (dir.isTagPresent(TIFFConstants.TIFFTAG_ICCPROFILE)) {
537: try {
538: TIFFField fd = dir
539: .getField(TIFFConstants.TIFFTAG_ICCPROFILE);
540: ICC_Profile icc_prof = ICC_Profile
541: .getInstance(fd.getAsBytes());
542: if (samplePerPixel == icc_prof
543: .getNumComponents())
544: img.tagICC(icc_prof);
545: } catch (RuntimeException e) {
546: //empty
547: }
548: }
549: if (dir.isTagPresent(TIFFConstants.TIFFTAG_COLORMAP)) {
550: TIFFField fd = dir
551: .getField(TIFFConstants.TIFFTAG_COLORMAP);
552: char rgb[] = fd.getAsChars();
553: byte palette[] = new byte[rgb.length];
554: int gColor = rgb.length / 3;
555: int bColor = gColor * 2;
556: for (int k = 0; k < gColor; ++k) {
557: palette[k * 3] = (byte) (rgb[k] >>> 8);
558: palette[k * 3 + 1] = (byte) (rgb[k + gColor] >>> 8);
559: palette[k * 3 + 2] = (byte) (rgb[k + bColor] >>> 8);
560: }
561: PdfArray indexed = new PdfArray();
562: indexed.add(PdfName.INDEXED);
563: indexed.add(PdfName.DEVICERGB);
564: indexed.add(new PdfNumber(gColor - 1));
565: indexed.add(new PdfString(palette));
566: PdfDictionary additional = new PdfDictionary();
567: additional.put(PdfName.COLORSPACE, indexed);
568: img.setAdditional(additional);
569: }
570: img.setOriginalType(Image.ORIGINAL_TIFF);
571: }
572: if (photometric == TIFFConstants.PHOTOMETRIC_MINISWHITE)
573: img.setInverted(true);
574: if (rotation != 0)
575: img.setInitialRotation(rotation);
576: return img;
577: } catch (Exception e) {
578: throw new ExceptionConverter(e);
579: }
580: }
581:
582: static long[] getArrayLongShort(TIFFDirectory dir, int tag) {
583: TIFFField field = dir.getField(tag);
584: if (field == null)
585: return null;
586: long offset[];
587: if (field.getType() == TIFFField.TIFF_LONG)
588: offset = field.getAsLongs();
589: else { // must be short
590: char temp[] = field.getAsChars();
591: offset = new long[temp.length];
592: for (int k = 0; k < temp.length; ++k)
593: offset[k] = temp[k];
594: }
595: return offset;
596: }
597:
598: // Uncompress packbits compressed image data.
599: public static void decodePackbits(byte data[], byte[] dst) {
600: int srcCount = 0, dstCount = 0;
601: byte repeat, b;
602:
603: while (dstCount < dst.length) {
604: b = data[srcCount++];
605: if (b >= 0 && b <= 127) {
606: // literal run packet
607: for (int i = 0; i < (b + 1); i++) {
608: dst[dstCount++] = data[srcCount++];
609: }
610:
611: } else if (b <= -1 && b >= -127) {
612: // 2 byte encoded run packet
613: repeat = data[srcCount++];
614: for (int i = 0; i < (-b + 1); i++) {
615: dst[dstCount++] = repeat;
616: }
617: } else {
618: // no-op packet. Do nothing
619: srcCount++;
620: }
621: }
622: }
623:
624: public static void inflate(byte[] deflated, byte[] inflated) {
625: Inflater inflater = new Inflater();
626: inflater.setInput(deflated);
627: try {
628: inflater.inflate(inflated);
629: } catch (DataFormatException dfe) {
630: throw new ExceptionConverter(dfe);
631: }
632: }
633:
634: }
|