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