Wednesday, January 2, 2008

Getting started with iText - Part 19 (Convert TIFF to PDF)

In Part 19 we translate the Tiff2Pdf.java example. It demonstrates how to convert TIFF files to PDF.

How does it work?

At first glance the java example looks a bit more complicated than it is. In summary it uses the RandomAccessFileOrArray and TiffImage classes to read each input file and calculate the number of pages in the image
ra = RandomAccessFileOrArray.init(tiff_file);
totalPages = TiffImage.getNumberOfPages(ra);


Then inside a loop, it obtains an image of each page in the TIFF file. If needed, the image is scaled to fit the new document. Finally each image, and a page header, are added to the PDF file using the document's direct content. See, that was not so complicated was it?

img = TiffImage.getTiffImage( ra, javacast("int", page) );
..
if (img.getScaledWidth() GT 500 OR img.getScaledHeight() GT 700) {
img.scaleToFit( javacast("float", 500), javacast("float", 700) );
}
..
img.setAbsolutePosition( javacast("float", 20), javacast("float", 20) );
document.add( Paragraph.init(tiff_file &" - page "& page) );
directContent.addImage( img );

What you will need for this example

1. To run the first example, you will need a recent version of iText like 2.0.7. For instructions, see How to use a newer version of iText . If you do not want to install a newer version, skip this step and use the MX7/CF8 example below. Note, the MX7/CF8 example uses deprecated methods.

2. Four(4) input files from the iText site. Download the sample files and place them in the same directory as your .cfm script:
12.tif 338814-00.tif odd.tif even.tif

Documentation: Selected examples: TIFF, Barcodes
Source: Tiff2PDF.java

iText 2.0.7+ Example

<h1>Convert Tiff files to PDF example (iText 2.0.7+)</h1>


<cfscript>
savedErrorMessage = arrayNew(1);

// cfSearching: All file paths are relative to the current directory
arrayOfInputFiles = arrayNew(1);
arrayAppend(arrayOfInputFiles, ExpandPath("12.tif"));
arrayAppend(arrayOfInputFiles, ExpandPath("338814-00.tif"));
arrayAppend(arrayOfInputFiles, ExpandPath("odd.tif"));
arrayAppend(arrayOfInputFiles, ExpandPath("even.tif"));

// cfSearching: Get reference to javaLoader stored in server scope
javaLoader = server[MyUniqueKeyForJavaLoader];

// cfSearching: Create objects for reuse
RandomAccessFileOrArray = javaLoader.create("com.lowagie.text.pdf.RandomAccessFileOrArray");
TiffImage = javaLoader.create("com.lowagie.text.pdf.codec.TiffImage");
FileOutputStream = createObject("java", "java.io.FileOutputStream");
PdfWriter = javaLoader.create("com.lowagie.text.pdf.PdfWriter");
Document = javaLoader.create("com.lowagie.text.Document");
Paragraph = javaLoader.create("com.lowagie.text.Paragraph");

for ( fileIndex = 1; fileIndex LTE arrayLen(arrayOfInputFiles); fileIndex = fileIndex + 1) {
// cfSearching: get the input file (TIFF)
tiff_file = arrayOfInputFiles[fileIndex];
// cfSearching: generate the output file name with a PDF extension
pdf_file = listDeleteAt(tiff_file, listLen(tiff_file, "."), ".") & ".pdf";
newDocument = Document.init();

try {
// cfSearching: create a writer to generate the new pdf
outStream = FileOutputStream.init(pdf_file);
writer = PdfWriter.getInstance(newDocument, outStream);

// cfSearching: open the document and get the direct content for writing
document.open();
directContent = writer.getDirectContent();

try {
// cfSearching: calculate the total number of pages in the tiff file
ra = RandomAccessFileOrArray.init(tiff_file);
totalPages = TiffImage.getNumberOfPages(ra);
}
catch (java.lang.Throwable e) {
// cfSearching: if an error occurs, skip this file and go to the next one
WriteOutput("Exception in "& tiff_file &" "& e.getMessage());
continue;
}

WriteOutput("Processing: "& tiff_file &"<br>");

// cfSearching: for each page in the file
for (page = 1; page LTE totalPages; page = page + 1) {
try {
// cfSearching: get an image of the current page
img = TiffImage.getTiffImage( ra, javacast("int", page) );
if ( IsDefined("img") ) {
// cfSearching: reduce the image size if needed
if (img.getScaledWidth() GT 500 OR img.getScaledHeight() GT 700) {
img.scaleToFit( javacast("float", 500), javacast("float", 700) );
}

// cfSearching: add the current page to the output file
img.setAbsolutePosition( javacast("float", 20), javacast("float", 20) );
// cfSearching: add a header containing the file path and current page number
document.add( Paragraph.init(tiff_file &" - page "& page) );
directContent.addImage( img );
document.newPage();

WriteOutput("page "& page &"<br>");
}
}
catch (java.lang.Throwable e) {
WriteOutput("Exception "& tiff_file &" page "& page &" "& e.getMessage());
}
}
ra.close();
document.close();
}
catch (java.lang.Throwable e) {
arrayAppend(savedErrorMessage, duplicate(e));
}
}

WriteOutput("<hr>Finished!");
</cfscript>


<!--- show any errors --->
<cfif arrayLen(savedErrorMessage) gt 0>
Error creating documents
<cfdump var="#savedErrorMessage#">
</cfif>



MX7/CF8 Example (Uses deprecated methods)

<h1>Convert Tiff files to PDF example (MX7/CF8)</h1>

<cfscript>
savedErrorMessage = arrayNew(1);

// cfSearching: All file paths are relative to the current directory
arrayOfInputFiles = arrayNew(1);
arrayAppend(arrayOfInputFiles, ExpandPath("12.tif"));
arrayAppend(arrayOfInputFiles, ExpandPath("338814-00.tif"));
arrayAppend(arrayOfInputFiles, ExpandPath("odd.tif"));
arrayAppend(arrayOfInputFiles, ExpandPath("even.tif"));

// cfSearching: Create objects for reuse
RandomAccessFileOrArray = createObject("java", "com.lowagie.text.pdf.RandomAccessFileOrArray");
TiffImage = createObject("java", "com.lowagie.text.pdf.codec.TiffImage");
FileOutputStream = createObject("java", "java.io.FileOutputStream");
PdfWriter = createObject("java", "com.lowagie.text.pdf.PdfWriter");
Document = createObject("java", "com.lowagie.text.Document");
Paragraph = createObject("java", "com.lowagie.text.Paragraph");

for ( fileIndex = 1; fileIndex LTE arrayLen(arrayOfInputFiles); fileIndex = fileIndex + 1) {
// cfSearching: get the input file (TIFF)
tiff_file = arrayOfInputFiles[fileIndex];
// cfSearching: generate the output file name with a PDF extension
pdf_file = listDeleteAt(tiff_file, listLen(tiff_file, "."), ".") & ".pdf";
newDocument = Document.init();

try {
// cfSearching: create a writer to generate the new pdf
outStream = FileOutputStream.init(pdf_file);
writer = PdfWriter.getInstance(newDocument, outStream);

// cfSearching: open the document and get the direct content for writing
document.open();
directContent = writer.getDirectContent();

try {
// cfSearching: calculate the total number of pages in the tiff file
ra = RandomAccessFileOrArray.init(tiff_file);
totalPages = TiffImage.getNumberOfPages(ra);
}
catch (java.lang.Throwable e) {
// cfSearching: if an error occurs, skip this file and go to the next one
WriteOutput("Exception in "& tiff_file &" "& e.getMessage());
continue;
}

WriteOutput("Processing: "& tiff_file &"<br>");

// cfSearching: for each page in the file
for (page = 1; page LTE totalPages; page = page + 1) {
try {
// cfSearching: get an image of the current page
img = TiffImage.getTiffImage( ra, javacast("int", page) );
if ( IsDefined("img") ) {
// cfSearching: reduce the image size if needed
// cfSearching: scaledWidth() and scaledHeight() are deprecated. As of iText 2.0.3,
// cfSearching: replaced by getScaledHeight(), scheduled for removal at 2.1.0
if (img.scaledWidth() GT 500 OR img.scaledHeight() GT 700) {
img.scaleToFit( javacast("float", 500), javacast("float", 700) );
}

// cfSearching: add the current page to the output file
img.setAbsolutePosition( javacast("float", 20), javacast("float", 20) );
// cfSearching: add a header containing the file path and current page number
document.add( Paragraph.init(tiff_file &" - page "& page) );
directContent.addImage( img );
document.newPage();

WriteOutput("page "& page &"<br>");
}
}
catch (java.lang.Throwable e) {
WriteOutput("Exception "& tiff_file &" page "& page &" "& e.getMessage());
}
}
ra.close();
document.close();
}
catch (java.lang.Throwable e) {
arrayAppend(savedErrorMessage, duplicate(e));
}
}

WriteOutput("<hr>Finished!");
</cfscript>


<!--- show any errors --->
<cfif arrayLen(savedErrorMessage) gt 0>
Error creating documents
<cfdump var="#savedErrorMessage#">
</cfif>

15 comments:

Anonymous,  March 4, 2008 at 2:39 PM  

Did you realize that all of the ColdFusion server's PDF capabilities are based on iText? Adobe, the makers of PDF, couldn't even write their own PDF library for Java. That's just sad. But what's sadder, is that after wasting a couple thou on the ColdFusion server that's supposed to give you all these cool PDF creation options, you are now having to go back to iText yourself and redo all the work that Adobe still failed to get right!

cfSearching March 4, 2008 at 9:10 PM  

ColdFusion has used iText since long before Adobe ever entered the picture. Since iText was already built into CF, before Adobe acquired Macromedia, it hardly seems feasible that they would completely rip it all out, start from scratch, and ignore backward compatibility.

However CF8 includes some functionality for LiveCycle forms. Since those are not as well supported under iText, I would guess that portion is implemented with Adobe libraries.

cfSearching March 4, 2008 at 9:18 PM  

Also, bear in mind many of the examples here are deliberately geared towards the older MX7 version, which does not have access to many of the newer pdf features.

Jason July 2, 2008 at 8:21 PM  

I tried both versions of the code but both returned the following:-


Exception in D:\Websites\iText\12.tif Object Instantiation Exception.Exception in D:\Websites\iText\338814-00.tif Object Instantiation Exception.Exception in D:\Websites\iText\odd.tif Object Instantiation Exception.Exception in D:\Websites\iText\even.tif Object Instantiation Exception.

Help please. Thanks in advance.

cfSearching July 3, 2008 at 4:44 AM  

@Jason,

"Object Instantiation Exception" is a general exception. It is hard to say anything more without seeing the full error message and the full stack trace.

1. Verify the TIF files were saved to the same directory as your CFM script. In your case:

D:\Websites\iText\

2. Verify you have the correct permissions to use createObject and access the files.

3. Post the full error message + full stack trace

Jason July 3, 2008 at 5:17 AM  

Thanks for the quick response.

1) The TIF files are saved into the right directory as the cfm file.

2) I'm using CFMX 8 and I can't seem to find the permission for CreateObject. The files are definitely not readonly.

3) Btw, how do I find the full error message + full stack trace?

cfSearching July 3, 2008 at 5:55 AM  

@Jason

You can view/change permissions in the ColdFusion Administrator, assuming you have access to it.

IF debugging output is enabled, you should see a more detailed error message. The stack trace should be at the bottom. However, if debugging is not enabled this will not be visible.


======================
The value blah cannot be converted to a number.

The error occurred in C:\ColdFusion8\wwwroot\test.cfm: line 2

1 : <cfset a = "blah">
2 : <cfoutput>#a+2#</cfoutput>


.... (other messages)

Stack Trace
at cfcheckBox2ecfm1652629358.runPage(C:\ColdFusion8\wwwroot\test.cfm:2) at cfApplication2ecfc1471333263$funcONREQUEST.runFunction(C:\ColdFusion8\wwwroot\Application.cfc:47)

coldfusion.runtime.Cast$NumberConversionException: The value blah cannot be converted to a number.
at coldfusion.runtime.Cast._double(Cast.java:762)
at coldfusion.runtime.Cast._double(Cast.java:632)
at coldfusion.runtime.Cast._double(Cast.java:786)
......
======================


1. Do you have Administrator access or are you on a shared server?

2. Have you ever successfully used createObject("java", ...) before?

Jason July 3, 2008 at 6:14 AM  

Yes, I do have access to the CF Administrator and I believe I have successfully been using CreateObject as I went through all the tutorials in the series :)

Removing the catch section of the coding produces the following error. The error list is a bit long, so I have it printscreen-ed:

http://img359.imageshack.us/img359/699/error1hy0.jpg

http://img68.imageshack.us/img68/7708/error2oe3.jpg

cfSearching July 3, 2008 at 6:45 AM  

@Jason,

LOL. Well if you have run the other tutorials, you definitely have access to createObject ;-)

The error seems to be saying it cannot find or access the TIF files.

Caused by: java.io.IOException: D:\Websites\iText\12.tif not found as file or resource

Can you do a FileExists?

FileExists("D:\Websites\iText\12.tif") check?

cfSearching July 3, 2008 at 6:49 AM  

.. or possibly the file exists but cannot be accessed. Example, maybe it is locked by another process.

Jason July 3, 2008 at 7:15 AM  

The tif(f) files downloaded from iText somehow got the extension of tiff instead of tif.

I tried downloading from another PC and it is saved as TIF.

Hope this serves as a note to others.

Thanks a lot for your help.

cfSearching July 3, 2008 at 7:30 AM  

@Jason,

You are welcome. Thanks for posting the resolution!

Edward Gioja,  April 24, 2010 at 12:21 AM  

I know I've said this to you before, but I can't thank you enough for the examples that you post on your site. Between iText and your examples, I save uncountable hours of work.

Thank you.

cfSearching April 25, 2010 at 5:56 PM  

You are very welcome. I feel the way about the iText examples. They are probably some of the best I have seen for any java library .. and fortunately, there are tons of them ;)

-Leigh

Anonymous,  August 3, 2010 at 3:53 PM  

For anyone using CF9, you can use the MX7/CF8 example. But as noted in the code comments, img.scaledWidth() and img.scaledHeight() are deprecated. So you need to change them to img.getScaledWidth() and img.getScaledHeight().

  © Blogger templates The Professional Template by Ourblogtemplates.com 2008

Header image adapted from atomicjeep