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