Skip to main content
Inspiring
April 10, 2008
Answered

iText Watermark position issue

  • April 10, 2008
  • 2 replies
  • 7104 views
Coders,

Please forgive me in advance as my java kung foo is not that strong. I have a site which allows users to merge multiple pdf documents they choose via a checklist, and then it will apply a small watermark to the top left (xposition 158, yposition 743). The problem is that there are some pdfs in which the watermark gets set in the middle of the page instead of the top left. I believe I have read in some forums where it may be a size issue of sorts, but I'm still confused. I do know that I have found a weird work around, which involves saving the pdf documents that don't work right, then rescanning via copy machine and having my copy machine send it back to me via email. It will then apply the watermark to the upper left corner. I will attach my code below (note: code is written in coldfusion and java):


I hope this isn't confusing. Thanks in advance for everyone's assistance.
This topic has been closed for replies.
Correct answer -__cfSearching__-
Well, you certainly could set both but I am still wondering whether you need to actually set the values or just read them. In other words, are you trying to read the existing values so you know where to position the image, or do you always want to overwrite the existing settings? If all of the pdf's are a known and fixed size overwriting should be okay. However, if the code just arbitrarily sets the media/cropbox sizes without knowledge of any existing settings, the results might be unexpected.

I believe I am just trying to read the existing values so I my site will know where to position the image; as all the pdf's are not a fixed size. I must be missing/not understanding something as I have incorporated your code (Thanks), but it did not make a change. I've been over the iText documentation many times now, but can't seem to find my error. I also used re-modified my code so that the cropbox and mediabox adjust for a 8.5" X 11" page (per this site: http://itext.ugent.be/library/question.php?id=588) but the watermark still stays in the center. Perhaps this what you were referring to when you said results might be unexpected.

I've attached my (full) altered code so hopefully you or someone may find the flaws. Note that the first part of the code actually merges documents, and the 2nd part applies the watermark. Thanks again.


Lumpia wrote:
I must be missing/not understanding something as I have incorporated your code (Thanks)

Yes, I think so. The code was just a straight translation of your java snippet. As mentioned, you would need to make additional changes if you were to try using a PdfWriter (instead of a stamper) to add the watermarks. However, to just read the existing dimensions, you should not need a writer at all.

Obtain the media/crop box sizes from the reader (like in my original example). Then use the box values to calculate the desired x and y coordinates of the watermark.

for (ii = 1; ii LT n; ii = ii + 1) {
box = pdfReader.getCropBox( javacast("int", ii) );
under = pdfStamper.getUnderContent( javaCast("int", ii) );
// xOffset and yOffset being the desired left an top margin
// ie start drawing the image x points from the left of the crop box and y points from the top
xPos = box.getLeft() + xOffset;
yPos = box.getTop() - yOffset - img.getHeight();
img.setAbsolutePosition( xPos, yPos );
....
under.addImage(img);

}

However, IIRC those methods do not take into account rotation. So that is something you will have to look into yourself. Disclaimer: It has been a long day. The mind is tired. Take this all with a grain of salt ;-)

2 replies

BKBK
Community Expert
May 1, 2008
Lumpia, if you're on CF8 you can use the cfpdf tag to merge PDFs in one line of code.

LumpiaAuthor
Inspiring
May 1, 2008
BKBK,

True. Unfortunately, my company is still using CFMX7 until next year. If only...
LumpiaAuthor
Inspiring
May 3, 2008
Lumpia wrote:

<cfif form.image1 neq "">
<cfoutput>#insertWatermarkPDF("concatenation.pdf"
,"#form.image1#.gif"
,"concatenation2.pdf"
,158
,743
,1)#
</cfoutput>
</cfif>


Can you post your latest function code for adding the watermark? Because I do not think my previous code snippet would work with those xPos, yPos values (158, 743). They look like absolute positions.

The idea with my previous example was to pass in the desired offsets and let the function determine what the x and y coordinates should be. In other words, you tell the function the watermark should be positioned 1/2 inch from the left (xOffset) and 3/4 of an inch from the top (yOffset) of the crop box. The function then uses that information to calculate the x and y coordinates needed to achieve this.

By using offset values, instead of coordinates, you should be able to position the images correctly simply by changing the x/yOffset parameters. But I would have to see the actual code to know why it is not behaving as you expect.





cfSearching,

You are correct. The way I originally coding this site was with absolute positions, but obviously, my method did not take into account the mediabox and cropbox sizes and adjust accordingly. You are definitely on the right track, and I'm not opposed to taking the absolute postions out and just using the java offsets instead, I really just need it to work with 2 images/coordinates at this point (instead of overlapping each other). Thanks again for your help.

Here is the entire Watermark function code:

LumpiaAuthor
Inspiring
April 22, 2008
Ok, it appears that what I need to do is implement the use of iText's mediabox and cropbox. Has anyone successfully used mediabox and cropbox within a cfscript tag? Thanks.
Inspiring
April 24, 2008
What issue are you having with it? Using your code as a base, this simple example displays the cropbox information for each page.

<cfscript>
pdfReader = loader2.create("com.lowagie.text.pdf.PdfReader");
pdfReader.init(arguments.pdfFileIn);
n = pdfReader.getNumberOfPages();

for (ii = 1; ii LTE n; ii = ii + 1)
{
// display crop box for each page
box = pdfReader.getCropBox(ii);
WriteOutput(" PAGE "& ii &" (crop box): ");
WriteOutput(" Top="& box.getTop());
WriteOutput(" Right="& box.getRight());
WriteOutput(" Bottom="& box.getBottom());
WriteOutput(" Left="& box.getLeft());
WriteOutput(" Width="& box.getWidth());
WriteOutput(" Height="& box.getHeight() &"<br>");
}
</cfscript>


Having nothing to do with watermarks, I did notice two things that might cause other problems.

Lumpia wrote:
//create the loader
loader2 = createObject("component", "javaloader.JavaLoader").init(paths);


There is a bug in ColdFusion that can cause a memory leak when using java.net.URLClassLoader. So it is recommended that you store the javaLoader in the server scope rather than instantiating it each time it is used.
http://www.transfer-orm.com/?action=displayPost&ID=212


document = loader2.create("com.lowagie.text.Document");
streamOut.init(arguments.pdfFileOut);

...
pdfStamper.close();


Consider structuring your try/catch code so it always closes document, outputstream and stamper objects. Even if an error occurs. Sort of like a try/catch/finally clause. IMO it is a good practice that can prevent locked files and other io related problems.
LumpiaAuthor
Inspiring
April 24, 2008
Cfsearching,

Thanks for your many advices. Regarding the memory leak issue, I am going to incorporate that now. I figure the way to add it to server scope with UUID would be like so:

server.uuid.loader = createObject("component", "javaloader.JavaLoader").init(paths);

However, for each referencing object, would I also add server.uuid on them, like so:

pdfCopy=server.uuid.loader.create("com.lowagie.text.pdf.PdfCopy");
pdfReader=server.uuid.loader.create("com.lowagie.text.pdf.PdfReader");
pageSize=server.uuid.loader.create("com.lowagie.text.PageSize").init();
bookMark=server.uuid.loader.create("com.lowagie.text.pdf.SimpleBookmark");
pdfDocument=server.uuid.loader.create("com.lowagie.text.Document");

In reference to media & crop box, I've been reading 'iText In Action' manual and it has this example:

Document document = new Document(new Rectangle(432, 792));
PdfWriter writer = PdfWriter.getInstance(document,
new FileOutputStream("page_boundaries.pdf"));
writer.setCropBoxSize(new Rectangle(5, 5, 427, 787));

which is written in java, of course, so I'm having troubles converting it to use in cfscript and also knowing where to place it in my current code.

Thanks again for your help.