Skip to main content
April 28, 2010
Question

Why does AddWatermark make file so big?

  • April 28, 2010
  • 1 reply
  • 4205 views

I have created a 600 x 253 72 dpi gif file.  It is only 36kb in size.  When I take a 7 page 220kb PDF file and do a cfpdf action="addwatermark" to the file, it grows from 220kb to a whopping 1.3 MB!

Strangely enough, if I open the same file in Adobe Acrobat Professional and manually add the exact same gif file as a watermark to the exact same PDF file, the result file actually got SMALLER!?!?!

You don't believe me?  Try it yourself.

Image file: https://www.calcerts.com/images/logo_main_watermark_color.gif

Original PDF: https://www.calcerts.com/BB4031.pdf

PDF File after doing a simple addwatermark: https://www.calcerts.com/BB4031_WTF.pdf

PDF File if I add the image as a watermark in Adobe Acrobat Professional 8: https://www.calcerts.com/BB4031_AdobeWatermarked.pdf

The code I used was this:

<cfpdf action="addwatermark"
  source="d:\BB4031.pdf"
  destination="d:\BB4031_WTF.pdf"
  image="D:\images\logo_main_watermark_color.gif"
  opacity = 2
  foreground = "yes"
  rotation = 0
  showonprint = "yes"
  overwrite="yes"
  position = "0,250"
  >

This topic has been closed for replies.

1 reply

Inspiring
April 29, 2010

My guess would be it is how the watermark image is added internally. From the size increase, it seems like the image bytes are added to the pdf multiple times. ie Once per page. As opposed to adding them once, and then reusing some sort of reference.  But that is just a guess. You might also submit a bug report on this behavior.

If you have createObject("java") access, you could always use iText to add the watermark. It is not as simple as cfpdf. But done correctly, it does not increase the file size so drastically.  If you are looking for an iText example, see the entry below. I wrote it for another problem. But you could easily adapt it.

http://cfsearching.blogspot.com/2009/06/cfpdf-issues-when-using-transparent.html

Message was edited by: -==cfSearching==-

April 29, 2010

Awesome.  It does not answer the why problem, but it did offer an alternative thing for me to do.  The iText worked great.  I think I am going to be doing some iText learning, because the file is significantly smaller.

As you said, it's not as easy, but it works nicely.

Also, FYI - you need to fix your sample code. On line 30, it says:

ii = i + 1;

I think you need only one i.  The while loop goes to infinity. 

Inspiring
April 30, 2010

I can't thank you enough for all the help you are giving me, but I just hit a brick wall.  I am not really a "coder" by any stretch of the imagination.  I am more of a cut 'n paste sort of guy that tweaks the code a bit to make it work.  So I read your article (light hearted and easy to read) but very difficult for me to understand exactly what to do.  So I will tell you what I did and you can tell me what I did wrong.

1) downloaded the CFCDyamicProxy from the website link you provided.  I created a mapping in CFAdministrator to the folder.  I ran a couple of the "Sample" files and got no errors, so I assume it installed properly.

2) Downloaded iText JAVA-PDF library 5.02 and put it in the same folder so I could use the mapping.

3) I then copied and pasted your example (and changed the reference of the iText to the 5.02 version instead of your 2.17).

4) Ran the CFM file and got this error:

Could not find the ColdFusion Component or Interface PdfPageEventHandler.

so obviously I am missing something, but don't know what.

btw, should I be e-mailing you on the side or should we keep this on the Forum?  also, if you can't be bothered with this, I totally understand just let me know.

Here is the CFM file I created:


<cffunction name="onEndPage" access="public" returntype="void" output="true"
    hint="Called when a page is finished, just before being written to the document.">
<cfargument name="writer" type="any" required="true" hint="Writer for the target pdf. Instance of com.lowagie.text.pdf.PdfWriter" />
<cfargument name="document" type="any" required="true" hint="Document for target pdf. Instance of com.lowagie.text.Document" />
<cfset var Local = {} />

<cfscript>
if (len(variables.instance.footerText))
{
     Local.cb = arguments.writer.getDirectContent();
     Local.cb.saveState();

     Local.cb.beginText();
     Local.cb.setColorFill( variables.instance.textColor );
     Local.cb.setFontAndSize( variables.instance.font, javacast("float", variables.instance.fontSize) );
     Local.cb.setTextMatrix( arguments.document.left(), arguments.document.bottom() - 10);
     Local.text = variables.instance.footerText &" page ["& arguments.writer.getPageNumber() &"]";
     Local.cb.showText( Local.text );
     Local.cb.endText();

     Local.cb.restoreState();
}
</cfscript>

</cffunction>

<cfscript>
//add the javaloader dynamic proxy library (and the iText jar) to the javaloader
libpaths = [];
arrayAppend(libpaths, expandPath("/javaLoader/support/cfcdynamicproxy/lib/cfcdynamicproxy.jar"));
arrayAppend(libpaths, expandPath("/javaLoader/itext/iText-5.0.2.jar") );

//we HAVE to load the ColdFusion class path to use the dynamic proxy, as it uses ColdFusion's classes
loader = createObject("component", "javaLoader.JavaLoader").init(loadPaths=libpaths, loadColdFusionClassPath=true);
</cfscript>

<cfscript>
//intialize the page event handler component
eventHandler = createObject("component", "PdfPageEventHandler").init( font=textFont, fontSize=10, textColor=textColor);
//add a custom footer
eventHandler.setFooterText( "www.clueless.corp * 85 anywhere blvd * lost city" );

//we can pass in an array of strings which name all the interfaces we want out dynamic proxy to implement
interfaces = ["com.lowagie.text.pdf.PdfPageEvent"];

//get a reference to the dynamic proxy class
CFCDynamicProxy = loader.create("com.compoundtheory.coldfusion.cfc.CFCDynamicProxy");

// create a proxy that we will pass to the iText writer
eventHandlerProxy = CFCDynamicProxy.createInstance(eventHandler, interfaces);
</cfscript>
<CFABORT>


<cfscript>
fullPathToOutputFile =  "d:\20833P2_After.pdf";

  document = loader.create("com.lowagie.text.Document").init();
  outStream = createObject("java", "java.io.FileOutputStream").init(fullPathToOutputFile);
  writer = loader.create("com.lowagie.text.pdf.PdfWriter").getInstance(document, outStream);

  // ** register the PROXY as the page event handler **
  writer.setPageEvent( eventHandlerProxy );
     
  document.open();
  Paragraph = loader.create("com.lowagie.text.Paragraph");
  document.add( Paragraph.init("Paragraph Text....") );
  document.newPage(); 
  document.add( Paragraph.init("Paragraph Text....") );
  document.newPage();
  document.close();
  outStream.close();

  WriteOutput("Done!");
</cfscript>


so I assume it installed properly.

Yes, if you can run the JavaLoader examples it is installed properly

2) Downloaded iText JAVA-PDF library 5.02 and put it in the

same folder so I could use the mapping.

Download 2.1.7 instead. (The code will not work with 5.x "as is"). So your jar path would be: /javaLoader/itext/iText-2.1.7.jar

4) Ran the CFM file and got this error:

The example requires two files: a .CFM script to run the code and a .CFC containing the cffunctions (like onPageEnd). If you follow the example, the component must be named: PdfPageEventHandler.cfc.  You can download a working example using the box.net widget on the right menu of the blog. Extract the .zip and copy the entire "betterPdfPageEventHandler" directory anywhere in your webroot.

         Example:

         C:\ColdFusion8\wwwroot\betterPdfPageEventHandler

Then open up index.cfm, fix the jar paths, and run the script. It  creates a sample pdf (with footers) in the same directory.

BTW: If you are using the javaLoader, be sure to see this article on avoiding memory leaks:

http://www.compoundtheory.com/?action=displayPost&ID=212

HTH

-Leigh