Watermarking PDFs In Lucee 5.3.7 Without Using CFPDF

Why Load Test ColdFusion Apps (4 Reasons)
Samsung vs Huawei vs Apple Battle for Top Smartphone Maker in 2021

Watermarking PDFs In Lucee 5.3.7 Without using CFPDF

Recently, I’ve needed to add a watermark to PDFs but struggled with Lucee’s current implementation in 5.3.x..  Watermarking PDFs In Lucee 5.3.7 without using CFPDF is usually pretty straightforward, via

<code>
<cfpdf action="addwatermark" source="#source#" image="#image#" destination="#destination#" overwrite="yes">
</code>

However, there appear to be a fair few issues with cfpdf() at the time of writing:

Thankfully, there is a workaround by directly calling the iText Java libs which are already in Lucee 5.x. You can use the function below as a bit of a hacky fix in the meantime! Note, this is only tested in Lucee 5.3.7 so your mileage may vary.

<cfscript>

  /**

* Add a image as a watermark to a PDF using iText in Lucee 5.3

*

* @source string, i.e Full path to Input File: expandPath("myFile.pdf")

* @destination string i.e Full path to Output File: expandPath("myFile_Watermarked.pdf")

* @image string i.e Full path to Watermark Image: expandPath("watermark.png")

* @x Watermark image x offset, defaults to 0

* @y Watermark image y offset, defaults to 0

* @foreground Whether to add watermark on top or behind content

*/

function watermarkPDF(

required string source,

required string destination,

required string image,

numeric x = 0,

numeric y = 0,

boolean foreground = true

){

// Create PDF reader

local.pdfReader = createObject("java", "com.lowagie.text.pdf.PdfReader").init(arguments.source);

// Fill form fields

local.outputStream = createObject("java", "java.io.FileOutputStream").init(arguments.destination);

local.pdfStamper = createObject("java", "com.lowagie.text.pdf.PdfStamper").init(local.pdfReader, local.outputStream);

// Create image object for watermark image

local.imageObj = createobject("java", "com.lowagie.text.Image");

//  Read watermark image

local.img = local.imageObj.getInstance(arguments.image);

// Add watermark image to every page

local.i = 0;

// Loop PDF pages

while (local.i LT local.pdfReader.getNumberOfPages()) {

local.i = local.i + 1;

local.pdfContentByte = arguments.foreground?

local.pdfStamper.getOverContent( javacast("int", local.i) )

: local.pdfStamper.getUnderContent( javacast("int", local.i) );

// Set position of image

local.img.setAbsolutePosition(javacast("float", arguments.x),javacast("float", arguments.y));

// Add watermark image to looped page

local.pdfContentByte.addImage(local.img);

}

// flattern form

local.pdfStamper.setFormFlattening(true);

// Close and create destination pdf file

local.pdfStamper.close();

local.outputStream.close();

}

</cfscript>

```

Example Usage:

```
<cfscript>
watermarkPDF(
    expandPath("/files/A1_MyDocument.pdf"),
    expandPath("/files/A1_MyDocument_Watermarked.pdf"),
    expandPath("/files/watermark.png")
);
</cfscript>
```

Bear in mind, watermarking PDFs won’t stop a user from easily removing the watermark in Acrobat Pro unless you add an owner password to restrict editing (and, arguably, even then there are ‘unethical’ ways around that).

Thankfully that functionality currently works in Lucee 5.3.7, so we use cfpdf to restrict access:

```
<cfpdf action="protect"
    encrypt="AES_128"
    source="#FullPathToOutputFile#"
    newOwnerPassword="myAwesomePassword"
    permissions="none">
```