java - ClassCastException converting TIF to PDF using iText -


i'm using itext version 5.5.6 (tested 5.3.4) java 7 (1.7.0_71) 64bit on windows 7

here's example code

@test public void testconvert() throws exception {         try{             //read tiff file             randomaccessfileorarray mytifffile=new randomaccessfileorarray("c:\\local\\docs\\test.01.tif");             //find number of images in tiff file             int numberofpages= tiffimage.getnumberofpages(mytifffile);             system.out.println("number of images in tiff file: " + numberofpages);             document tifftopdf=new document();             pdfwriter.getinstance(tifftopdf, new fileoutputstream("c:\\local\\docs\\test.01.pdf"));             tifftopdf.open();             //run loop extract images tiff file             //into image object , add pdf recursively             for(int i=1;i<=numberofpages;i++){                 //*******                            //******* next line generating error                 //*******                 image tempimage=tiffimage.gettiffimage(mytifffile, i);                 tifftopdf.add(tempimage);             }             tifftopdf.close();             system.out.println("tiff pdf conversion in java completed" );         }         catch (exception i1){             i1.printstacktrace();         } } 

generates following error

java.lang.classcastexception     @ com.itextpdf.text.pdf.codec.tifffield.getasint(tifffield.java:315)     @ com.itextpdf.text.pdf.codec.tiffimage.gettiffimage(tiffimage.java:163)     @ com.itextpdf.text.pdf.codec.tiffimage.gettiffimage(tiffimage.java:315)     @ com.itextpdf.text.pdf.codec.tiffimage.gettiffimage(tiffimage.java:303)     @ com.pdf.imageconverterimplit.testconvert(imageconverterimplit.java:116) 

i'm going go deep dive of hex surgery on file, cause of exception in itext , cause of bug. go on screed describing why happens.

your file structured primary ifd @ end of file. here file header:

49 49 2a 00 96 6c 00 00  intel magic offset----- 

which says "i'm tiff in intel (little endian) byte order , primary ifd starts @ offset 0x6c9c.

if skip ahead spot see this:

0f 00 <- total number of tags, each tag 12 bytes  #  |  id |type | count     | value     | 01. 00 01 04 00 01 00 00 00 a2 06 00 00 width = 6a2 02. 01 01 04 00 01 00 00 00 4a 04 00 00 height = 44a 03. 02 01 03 00 01 00 00 00 01 00 00 00 bits per sample = 1 04. 03 01 03 00 01 00 00 00 04 00 00 00 compression = ccitt g4 05. 06 01 03 00 01 00 00 00 00 00 00 00 photometric = min white 06. 0a 01 04 00 01 00 00 00 01 00 00 00 fill order = msb lsb 07. 11 01 04 00 01 00 00 00 08 00 00 00 offset of strips = 8 08. 15 01 03 00 01 00 00 00 01 00 00 00 samples per pixel = 4 09. 16 01 04 00 01 00 00 00 4a 04 00 00 rows per strip = 448 0a. 17 01 04 00 01 00 00 00 5b 6c 00 00 strip byte counts = 6c5b 0b. 1a 01 05 00 01 00 00 00 63 6c 00 00 offset x resolution = 6c63 0c. 1b 01 05 00 01 00 00 00 6b 6c 00 00 offset y resolution = 6c6b 0d. 1c 01 03 00 01 00 00 00 01 00 00 00 planar config = contiguous 0e. 28 01 03 00 01 00 00 00 02 00 00 00 resolution unit = inches 0f. 31 01 02 00 23 00 00 00 73 6c 00 00 software string offset = 6c73 location of next ifd, 0 means no more 00 00 00 00  

now, looking @ call stack , tracing source, see call being made fill order. fill order 1 bit files describes whether high order bit or low order bit in byte leftmost in display.

tifffield fillorderfield =  dir.getfield(tiffconstants.tifftag_fillorder); if (fillorderfield != null)     fillorder = fillorderfield.getasint(0); 

we know called since there fill order tag in ifd, 4 byte integer value 1.

unfortunately you, call tifffield.getasint(0) causing failure.

if @ code:

public int getasint(int index) {     switch (type) {     case tiff_byte: case tiff_undefined:         return ((byte[])data)[index] & 0xff;     case tiff_sbyte:         return ((byte[])data)[index];     case tiff_short:         return ((char[])data)[index] & 0xffff;     case tiff_sshort:         return ((short[])data)[index];     case tiff_slong:         return ((int[])data)[index];     default:         throw new classcastexception();     } } 

you can see can throw classcastexception if type doesn't match, , in case since type constants in cases 1, 7, 6, 3, 8 , 9 respectively , tag's type 4.

so why code wrong?

the problem tiff tags though spec pretty clear fact fillorder tag (10a) should unsigned short (type 3), tag in file unsigned 4 byte int (type 4), switch statement there doesn't account (no case tiff_long).

why there no case this? looking @ surrounding code, library treats 4 byte unsigned integers java type 'long' , trying treat 4 byte unsigned int 4 byte signed int cause overflow sign bit (even though none of legal values tag trigger that) since cast might cause error, treated 1 always.

ultimately cause of bug 2 things:

  1. java has precisely 1 unsigned integer type (char, of playing along @ home) , library chose use long represent unsigned 4 byte int.
  2. this particular file out of spec , used unsigned int tag

or more specifically, there impedance mismatch between chosen java types , tiff file. field code attempting type-strong. calling code is attempting accept wide variety of types. missed 1 case.

i looked @ own tag code grins see if suffer particular problem. answer no version of getintvalue() let overflow sign bit if that's want do.

so real fix change code to:

tifffield fillorderfield =  dir.getfield(tiffconstants.tifftag_fillorder); if (fillorderfield != null)     fillorder = (int)fillorderfield.getaslong(0); 

or alternately perform hex surgery on file , change data type of fill order tag unsigned short. poor solution consuming code still susceptible bad tiff files.


gratuitous screed

one thing i've learned in past 10 years of working tiff files there no shortage of broken tiff files , no shortage of engineers either didn't read spec or failed implement correctly making new broken files (and once in while, have been engineer). number of these grad students need tiff output right , write quick , dirty (broken) encoder consider correct when irfanview can open output (which invalid test since irfanview, , tiff codec well, open wide variety of fundamentally broken tiffs).

the tiff specification deceptively straight forward. because format feels should relatively easy generate. tags logical, ifds simple collections of tags, pointer tags can tricky, manageable. happens code gets written lacks level of abstraction prevent classes of error otherwise slip through.

this particular file not written grad student. @ least don't think so.

in case, problem caused fcoder. know because put software string created fcoder graphics processor. i'm calling them out because put software string identify themselves. bug (an incorrect type, due copy-paste error in source), while minor bug, causing problems , maybe they'll fix that. in world, #1 top-priority-drop-everything bug "generates bad file." , if had done this, sure hell want know fix code. meantime, itext should update code able accept class of file.

lessons learned:

  1. the specification answer question "is file correct."
  2. it's hard write decent tiff encoder or decoder. consider commercial library before writing own (although in example, found bugs in not 1 2 commercial libraries).
  3. put in software string when generate file can contact when there issue.

here endeth lesson.


Comments

Popular posts from this blog

android - MPAndroidChart - How to add Annotations or images to the chart -

javascript - Add class to another page attribute using URL id - Jquery -

firefox - Where is 'webgl.osmesalib' parameter? -