Saturday, January 16, 2010

ColdFusion + iText 5.0.0 (Good things come in *new* packages)

In case you were unaware, iText 5.0.0 was released a short while ago, and a new iText book scheduled for release in June. The new version of iText contains some significant changes, including a new license. But to ColdFusion users, the most signficant change may be the new package name.


Most everyone knows ColdFusion uses an older version of iText internally. So upgrading to a newer version (without breaking ColdFusion) requires a little fancy foot-work, such as using a custom class loader like JavaLoader.cfc. But with the new package name, that has all changed.

In previous versions, iText classes were packaged under com.lowagie.* . As of version 5.0.0, the classes are now packaged under a new name: com.itextpdf.*. This change is a huge benefit to ColdFusion users because it eliminates class path compatibility issues with MX7, CF8 and CF9. The new iText version should happily co-exist with the older iText versions shipped with MX7, CF8 and CF9.

Now obviously using version 5.0.0 means changing code to use the new package name, and being careful not to mix old and new. But it is now easier than ever before to use the latest version of iText under ColdFusion.

15 comments:

Henry Ho January 17, 2010 at 1:57 PM  

So.. how do you make CF9 use the new iText lib? Would CFPDF tag still work?

cfSearching January 17, 2010 at 2:44 PM  

@Henry,

Yes. Just throw it into the CF classpath, like any other jar. Since v5.0.0 uses a totally different package name, there is no conflict with CF's version of iText. (Obviously, if you are using the {cf_root}/lib directory do not overwrite the existing jar. Use a unique file name)

-Leigh

cfSearching January 17, 2010 at 9:37 PM  

BTW: In case there is any confusion, this entry is about having the two versions of iText coexist, not about replacing the version iText used by ColdFusion. That almost certainly would break cfpdf and other CF tags.

TJ January 18, 2010 at 8:08 AM  

It should be factored in that eventually Adobe will likely end up using these libraries, in which case it will end up breaking code you wrote. As such, the old methods of loading iText should probably still be considered.

cfSearching January 18, 2010 at 9:36 PM  

@TJ,

True. There are also other reasons to use the JavaLoader regardless of version (ie features like the JavaProxy).

-Leigh

I_learn_from_my_mistakes July 28, 2010 at 1:50 PM  

I have a question and I wanted to ask before going down this road.
I have a project in which I need to
add two different images to a PDF file. I can't do this with CFPDF as the only way to do it is to make it a watermark. When I add the 2nd image as a watermark the other image is replaced. Could I insert these images using itext or even the new version of itext?

Thanks!

cfSearching July 29, 2010 at 2:42 AM  

Yes it is possible with both the old and new versions of iText. Just determine the coordinates and you can add an image at that location.

Though depending on your needs, another option might be to combine the images into one and add a single watermark with cfpdf.

-Leigh

I_learn_from_my_mistakes July 29, 2010 at 6:16 AM  

Thanks,

I will be working on that for now. However, its interesting what you mentioned about combining two images into one. The best way I could see this happening is to create a newer image with cfimage, and paste the other two into that. I think thats possible but I have not seen any examples online that have done so. I will be trying the itext way first with may be a little frustrating as I'm no Java expert. I think I have seen enough examples that I might be able to fumble my way through. However, I might be posting. Thanks for taking the time to reply. If you have any suggestions or code examples I would be more than happy to try them.

cfSearching July 29, 2010 at 6:33 AM  

I would probably try the single image method first, if only because it is simpler and more familiar being CF. Just create a image of the desired dimensions. Then paste each of your two images at the desired coordinates. Then watermark as usual.

It is not difficult to add images with iText. But getting used to the coordinate system and java syntax can be confusing at first. If you run into any problems, feel free to email me at cfsearching / gmail.

-Leigh

Anonymous,  January 21, 2011 at 4:06 PM  

I am having problems with iText 5. It seems that some of the methods like "HTMLParser" have been deprecated.
I am copying my code below. I would appreciate any help i can get.

Thanks Art.

===================================









paths = arrayNew(1);
paths[1] = expandPath("itext/iText-5.0.5.jar");
javaloader = createObject("component", "javaloader.JavaLoader").init( paths );

sbis = javaloader.create("java.io.StringBufferInputStream").init(_html);
htmlparser = javaloader.create("com.itextpdf.text.html.HtmlParser");
document = javaloader.create("com.itextpdf.text.Document").init();
writer = javaloader.create("com.itextpdf.text.pdf.PdfWriter");

// this writes the pdf out to a file
outstream = javaloader.create("java.io.FileOutputStream").init(pdf_file);
// or this keeps tthe pdf in memory as a binary object
//outstream = javaloader.create("java.io.ByteArrayOutputStream").init();

writer = writer.getInstance(document, outstream);
document.open();
htmlparser.go(document, sbis);
outstream.close();

cfSearching January 21, 2011 at 5:39 PM  

@Art,

Yes, it was removed. Unfortunately, the only option for version 5 is HTMLWorker (lower level). Or you could use a different library like Flying Saucer, which uses iText internally.

-Leigh

Anonymous,  January 22, 2011 at 8:58 AM  

Do you happen to have an example of how to use HTMLWorker to convert entire html page to pdf?

I think i have been battling this for a while now without any successful resolution.

PS: flying saurcer uses iText 2 i believe and has not been updated in a more than 2 years. :(

Thanks,
Art

cfSearching January 24, 2011 at 8:03 AM  

@Art - Yes it does use 2.x, but you could use a separate classloader. Btw: Apparently the project moved here

There is more to it, but a very basic example of HTMLWorker:

<cfscript>
//...
doc = loader.create("com.itextpdf.text.Document").init();
out = loader.create("java.io.FileOutputStream").init(outPath);
PdfWriter = loader.create("com.itextpdf.text.pdf.PdfWriter");
writer = PdfWriter.getInstance(doc, out);
reader = loader.create("java.io.StringReader").init(_html);
worker = loader.create("com.itextpdf.text.html.simpleparser.HTMLWorker").init(doc);
document = loader.create("com.itextpdf.text.Document").init();
doc.open();
worker.parse( reader );
doc.close();
out.close();
</cfscript>

HTH
-Leigh

Anonymous,  January 24, 2011 at 5:11 PM  

Hi Leigh,
your example actually worked. Thanks.

But now i am facing another problem. It does not apply any of my style sheets.

Do you happen to know how to make the rendering engine recognize the styles?

Thanks
Art

cfSearching January 25, 2011 at 8:37 AM  

@Art,

Yes, like I said HTMLWorker is lower level. You can create a StyleSheet and add your styles to that object. Then pass it to HTMLWorker.setStyleSheet. See the second example the HTMLWorker link above.

But the basic HTMLWorker really is not designed for handling arbitrary pages of html. Not unless they are extremely well formed and avoid anything exotic. The worker was designed to handle html fragments. If you need to parse whole pages, with arbitrary content, you are probably better off with a more specialized tool like Flying Saucer (or even cfdocument with all its flaws).

-Leigh

  © Blogger templates The Professional Template by Ourblogtemplates.com 2008

Header image adapted from atomicjeep