1 31 package org.pdfbox.pdmodel.graphics.xobject; 32 33 import java.awt.image.BufferedImage ; 34 import java.io.InputStream ; 35 import java.io.IOException ; 36 import java.io.OutputStream ; 37 38 import java.util.ArrayList ; 39 import java.util.List ; 40 41 import javax.imageio.ImageIO ; 42 43 import org.pdfbox.cos.COSDictionary; 44 import org.pdfbox.cos.COSName; 45 import org.pdfbox.io.RandomAccess; 46 47 import org.pdfbox.pdmodel.PDDocument; 48 import org.pdfbox.pdmodel.common.PDStream; 49 import org.pdfbox.pdmodel.graphics.color.PDDeviceGray; 50 51 58 public class PDCcitt extends PDXObjectImage 59 { 60 private static final List FAX_FILTERS = new ArrayList (); 61 62 static 63 { 64 FAX_FILTERS.add( COSName.CCITTFAX_DECODE.getName() ); 65 FAX_FILTERS.add( COSName.CCITTFAX_DECODE_ABBREVIATION.getName() ); 66 } 67 68 73 public PDCcitt(PDStream ccitt) 74 { 75 super(ccitt, "tiff"); 76 77 } 78 79 86 87 public PDCcitt( PDDocument doc, RandomAccess raf ) throws IOException 88 { 89 super( new PDStream(doc),"tiff"); 90 92 COSDictionary decodeParms = new COSDictionary(); 93 94 COSDictionary dic = getCOSStream(); 95 96 extractFromTiff(raf, getCOSStream().createFilteredStream(),decodeParms); 97 98 dic.setItem( COSName.FILTER, COSName.CCITTFAX_DECODE); 99 dic.setItem( COSName.SUBTYPE, COSName.IMAGE); 100 dic.setItem( COSName.TYPE, COSName.getPDFName( "XObject" ) ); 101 dic.setItem( "DecodeParms", decodeParms); 102 103 setBitsPerComponent( 1 ); 104 setColorSpace( new PDDeviceGray() ); 105 setWidth( decodeParms.getInt("Columns") ); 106 setHeight( decodeParms.getInt("Rows") ); 107 108 } 109 110 115 public BufferedImage getRGBImage() throws IOException 116 { 117 return ImageIO.read(new TiffWrapper(getPDStream().getPartiallyFilteredStream( FAX_FILTERS ),getCOSStream())); 119 } 120 121 126 public void write2OutputStream(OutputStream out) throws IOException 127 { 128 InputStream data = new TiffWrapper(getPDStream().getPartiallyFilteredStream( FAX_FILTERS ),getCOSStream()); 129 byte[] buf = new byte[1024]; 130 int amountRead = -1; 131 while( (amountRead = data.read( buf )) != -1 ) 132 { 133 out.write( buf, 0, amountRead ); 134 } 135 } 136 137 145 private void extractFromTiff(RandomAccess raf, OutputStream os, COSDictionary parms) throws IOException 146 { 147 try 148 { 149 150 raf.seek(0); 152 char endianess = (char) raf.read(); 153 if ((char) raf.read() != endianess) 154 { 155 throw new IOException ("Not a valid tiff file"); 156 } 157 if (endianess != 'M' && endianess != 'I') 159 { 160 throw new IOException ("Not a valid tiff file"); 161 } 162 int magicNumber = readshort(endianess, raf); 163 if( magicNumber != 42) 164 { 165 throw new IOException ("Not a valid tiff file"); 166 } 167 168 raf.seek(readlong(endianess, raf)); 170 171 int numtags = readshort(endianess, raf); 172 173 if (numtags > 50) 175 { 176 throw new IOException ("Not a valid tiff file"); 177 } 178 179 184 int k=-1000; int dataoffset=0; 186 int datalength=0; 187 188 for (int i=0; i < numtags; i++) 189 { 190 int tag = readshort(endianess, raf); 191 int type = readshort(endianess, raf); 192 int count = readlong(endianess, raf); 193 int val = readlong(endianess, raf); 195 if (endianess == 'M') 199 { 200 switch (type) 201 { 202 case 1: 203 { 204 val = val >> 24; 205 break; } 207 case 3: 208 { 209 val = val >> 16; 210 break; } 212 case 4: 213 { 214 break; } 216 default: 217 { 218 } 220 } 221 } 222 switch (tag) 223 { 224 case 256: 225 { 226 parms.setInt("Columns",val); 227 break; 228 } 229 case 257: 230 { 231 parms.setInt("Rows",val); 232 break; 233 } 234 case 259: 235 { 236 if (val == 4) 237 { 238 k=-1; 239 } 240 if (val == 3) 241 { 242 k=0; 243 } 244 break; } 246 case 262: 247 { 248 if (val == 1) 249 { 250 parms.setBoolean("BlackIs1", true); 251 } 252 break; 253 } 254 case 273: 255 { 256 if (count == 1) 257 { 258 dataoffset=val; 259 } 260 break; 261 } 262 case 279: 263 { 264 if (count == 1) 265 { 266 datalength=val; 267 } 268 break; 269 } 270 case 292: 271 { 272 if (val == 1) 273 { 274 k=50; } 276 break; 277 } 278 case 324: 279 { 280 if (count == 1) 281 { 282 dataoffset=val; 283 } 284 break; 285 } 286 case 325: 287 { 288 if (count == 1) 289 { 290 datalength=val; 291 } 292 break; 293 } 294 default: 295 { 296 } 298 } 299 } 300 301 if (k == -1000) 302 { 303 throw new IOException ("First image in tiff is not CCITT T4 or T6 compressed"); 304 } 305 if (dataoffset == 0) 306 { 307 throw new IOException ("First image in tiff is not a single tile/strip"); 308 } 309 310 parms.setInt("K",k); 311 312 raf.seek(dataoffset); 313 314 byte[] buf = new byte[8192]; 315 int amountRead = -1; 316 while( (amountRead = raf.read( buf,0, Math.min(8192,datalength) )) > 0 ) 317 { 318 datalength -= amountRead; 319 os.write( buf, 0, amountRead ); 320 } 321 322 } 323 finally 324 { 325 os.close(); 326 } 327 } 328 329 private int readshort(char endianess, RandomAccess raf) throws IOException 330 { 331 if (endianess == 'I') 332 { 333 return raf.read() | (raf.read() << 8); 334 } 335 return (raf.read() << 8) | raf.read(); 336 } 337 338 private int readlong(char endianess, RandomAccess raf) throws IOException 339 { 340 if (endianess == 'I') 341 { 342 return raf.read() | (raf.read() << 8) | (raf.read() << 16) | (raf.read() << 24); 343 } 344 return (raf.read() << 24) | (raf.read() << 16) | (raf.read() << 8) | raf.read(); 345 } 346 347 348 354 private class TiffWrapper extends InputStream 355 { 356 357 private int currentOffset; private byte[] tiffheader; private InputStream datastream; 361 private TiffWrapper(InputStream rawstream, COSDictionary options) 362 { 363 buildHeader(options); 364 currentOffset=0; 365 datastream = rawstream; 366 } 367 368 372 public boolean markSupported() 373 { 374 return false; 375 } 376 379 public void reset() throws IOException 380 { 381 throw new IOException ("reset not supported"); 382 } 383 384 389 public int read() throws IOException 390 { 391 if (currentOffset < tiffheader.length) 392 { 393 return tiffheader[currentOffset++]; 394 } 395 return datastream.read(); 396 } 397 398 404 public int read(byte[] data) throws IOException 405 { 406 if (currentOffset < tiffheader.length) 407 { 408 int length = java.lang.Math.min(tiffheader.length - currentOffset, data.length); 409 if (length > 0) 410 { 411 System.arraycopy(tiffheader, currentOffset, data, 0, length); 412 } 413 currentOffset += length; 414 return length; 415 } 416 else 417 { 418 return datastream.read(data); 419 } 420 } 421 422 428 public int read(byte[] data, int off, int len) throws IOException 429 { 430 if (currentOffset < tiffheader.length) 431 { 432 int length = java.lang.Math.min(tiffheader.length - currentOffset, len); 433 if (length > 0) 434 { 435 System.arraycopy(tiffheader, currentOffset, data, off, length); 436 } 437 currentOffset += length; 438 return length; 439 } 440 else 441 { 442 return datastream.read(data,off,len); 443 } 444 } 445 446 452 public long skip(long n) throws IOException 453 { 454 if (currentOffset < tiffheader.length) 455 { 456 long length = Math.min(tiffheader.length - currentOffset, n); 457 currentOffset += length; 458 return length; 459 } 460 else 461 { 462 return datastream.skip(n); 463 } 464 } 465 466 private final byte[] basicHeader = { 468 'I','I',42,0,8,0,0,0, 0,0}; 471 472 private int additionalOffset; 474 private void buildHeader(COSDictionary options) 476 { 477 478 final int numOfTags = 10; final int maxAdditionalData = 24; 482 486 tiffheader = new byte[10 + (12 * numOfTags ) + 4 + maxAdditionalData]; 487 java.util.Arrays.fill(tiffheader,(byte)0); 488 System.arraycopy(basicHeader,0,tiffheader,0,basicHeader.length); 489 490 additionalOffset = 10 + (12 * numOfTags ) + 4; 492 493 short cols = 1728; 496 short rows = 0; 497 short blackis1 = 0; 498 short comptype = 3; long t4options = 0; 501 COSDictionary decodeParms = (COSDictionary) options.getDictionaryObject("DecodeParms"); 502 503 if (decodeParms != null) 504 { 505 cols = (short) decodeParms.getInt("Columns", cols); 506 rows = (short) decodeParms.getInt("Rows", rows); 507 if (decodeParms.getBoolean("BlackIs1", false)) 508 { 509 blackis1 = 1; 510 } 511 int k = decodeParms.getInt("K"); if (k < 0) 513 { 514 comptype = 4; 516 } 517 if (k > 0) 518 { 519 comptype = 3; 521 t4options = 1; 522 } 523 } 525 526 if (rows == 0) 528 { 529 rows = (short) options.getInt("Height", rows); 530 } 531 532 536 addTag(256, cols); addTag(257, rows); addTag(259, comptype); addTag(262, blackis1); addTag(273, tiffheader.length); addTag(279, options.getInt("Length")); addTag(282, 300, 1); addTag(283, 300, 1); if (comptype == 3) 545 { 546 addTag(292, t4options); 547 } 548 addTag(305, "PDFBOX"); } 550 551 552 553 private void addTag(int tag,long value) 554 { 555 int count = ++tiffheader[8]; 557 int offset = (count-1)*12 + 10; 558 tiffheader[offset]=(byte)(tag & 0xff); 559 tiffheader[offset+1]=(byte)((tag>>8) & 0xff); 560 tiffheader[offset+2]=4; tiffheader[offset+4]=1; tiffheader[offset+8]=(byte)(value & 0xff); 563 tiffheader[offset+9]=(byte)((value>>8) & 0xff); 564 tiffheader[offset+10]=(byte)((value>>16) & 0xff); 565 tiffheader[offset+11]=(byte)((value>>24) & 0xff); 566 } 567 568 private void addTag(int tag, short value) 569 { 570 int count = ++tiffheader[8]; 572 int offset = (count-1)*12 + 10; 573 tiffheader[offset]=(byte)(tag & 0xff); 574 tiffheader[offset+1]=(byte)((tag>>8) & 0xff); 575 tiffheader[offset+2]=3; tiffheader[offset+4]=1; tiffheader[offset+8]=(byte)(value & 0xff); 578 tiffheader[offset+9]=(byte)((value>>8) & 0xff); 579 } 580 581 private void addTag(int tag, String value) 582 { 583 int count = ++tiffheader[8]; 585 int offset = (count-1)*12 + 10; 586 tiffheader[offset]=(byte)(tag & 0xff); 587 tiffheader[offset+1]=(byte)((tag>>8) & 0xff); 588 tiffheader[offset+2]=2; tiffheader[offset+4]=1; tiffheader[offset+8]=(byte)(additionalOffset & 0xff); 591 tiffheader[offset+9]=(byte)((additionalOffset>>8) & 0xff); 592 tiffheader[offset+10]=(byte)((additionalOffset>>16) & 0xff); 593 tiffheader[offset+11]=(byte)((additionalOffset>>24) & 0xff); 594 System.arraycopy(value.getBytes(), 0, tiffheader, additionalOffset, value.length()); 595 additionalOffset += value.length() + 1; 596 } 597 598 private void addTag(int tag, long numerator, long denominator) 599 { 600 int count = ++tiffheader[8]; 602 int offset = (count-1)*12 + 10; 603 tiffheader[offset]=(byte)(tag & 0xff); 604 tiffheader[offset+1]=(byte)((tag>>8) & 0xff); 605 tiffheader[offset+2]=5; tiffheader[offset+4]=1; tiffheader[offset+8]=(byte)(additionalOffset & 0xff); 608 tiffheader[offset+9]=(byte)((additionalOffset>>8) & 0xff); 609 tiffheader[offset+10]=(byte)((additionalOffset>>16) & 0xff); 610 tiffheader[offset+11]=(byte)((additionalOffset>>24) & 0xff); 611 tiffheader[additionalOffset++]=(byte) ((numerator) & 0xFF); 612 tiffheader[additionalOffset++]=(byte) ((numerator>>8) & 0xFF); 613 tiffheader[additionalOffset++]=(byte) ((numerator>>16) & 0xFF); 614 tiffheader[additionalOffset++]=(byte) ((numerator>>24) & 0xFF); 615 tiffheader[additionalOffset++]=(byte) ((denominator) & 0xFF); 616 tiffheader[additionalOffset++]=(byte) ((denominator>>8) & 0xFF); 617 tiffheader[additionalOffset++]=(byte) ((denominator>>16) & 0xFF); 618 tiffheader[additionalOffset++]=(byte) ((denominator>>24) & 0xFF); 619 } 620 } 621 } | Popular Tags |