cfhtmltopdf and cfdocument generate a new PDF from HTML/CFML. cfpdf does the opposite job: operating on a PDF that already exists, merging several into one, adding a watermark, password-protecting it, or pulling text and images back out.
Learning Objectives
After completing this lesson, you'll be able to:
- Merge multiple PDFs into one with cfpdf.
- Add a watermark and password-protect a PDF.
- Recognize a real migration gotcha: actions Lucee's cfpdf doesn't implement at all.
How cfpdf Fits In
Existing PDF(s)
cfpdf action="..."
Merged / Watermarked / Protected Output
Some of cfpdf's 23+ Actions
| action | Does |
|---|---|
| merge | Combines multiple PDFs into one |
| deletePages | Removes specific pages |
| addWatermark / removeWatermark | Overlays or removes a watermark |
| protect | Encrypts and password-protects the document |
| thumbnail | Generates an image preview of a page |
| extractText / extractImage | Pulls text or embedded images out of the PDF |
| getInfo / setInfo | Reads or writes document metadata |
| addHeader / addFooter | Adds page numbering or text to every page |
| read / write | Loads a PDF into a variable, or saves one to a file |
The full Adobe reference documents over 20 actions in total, including sign, unsign, validateSignature, archive, and sanitize, worth checking the reference directly for anything beyond this core set.
A Real Example: Merging PDFs
<cfpdf action="merge" source="cover.pdf,report.pdf,appendix.pdf" destination="final.pdf" overwrite="yes">
keepBookmark (default false) preserves each source document's bookmarks in the merged output. merge also accepts a directory (merge every PDF in a folder instead of listing them individually) and order/ascending to control what sequence they're combined in.
A Real Example: Adding a Watermark
<cfpdf
action="addwatermark"
source="report.pdf"
destination="report-draft.pdf"
overwrite="yes"
text="DRAFT"
rotation="45"
opacity="3"
foreground="no">opacity is on a 0–10 scale, not 0–100. foreground="no" (the default) places the watermark behind the existing content rather than on top of it.
A Real Example: Password-Protecting the Output
<cfpdf action="protect" source="report.pdf" destination="report-protected.pdf" overwrite="yes" newOwnerPassword="ownerSecret" newUserPassword="viewerSecret">
protect's password attributes are newOwnerPassword and newUserPassword, not ownerpassword/userpassword, those names belong to cfhtmltopdf and cfdocument instead.
A Real Migration Gotcha: Lucee's Narrower Action List
Lucee's cfpdf documents merge, read, write, protect, removePassword, deletePages, thumbnail, extractText, extractImage, extractBookmarks, addWatermark, removeWatermark, addHeader, addFooter, getInfo, and setInfo. It does not document sign, unsign, validateSignature, readSignatureFields, archive, addAttachments, addStamp, processddx, sanitize, transform, optimize, or import.
Digital signing (sign/unsign/validateSignature) is the most consequential gap for a real migration, code that signs or validates a signed PDF on Adobe ColdFusion has no direct equivalent on Lucee's cfpdf.
Common Beginner Mistakes
Using ownerpassword/userpassword with cfpdf's protect action
protect's actual attributes are newOwnerPassword and newUserPassword, ownerpassword/userpassword are cfhtmltopdf's and cfdocument's naming instead, an easy mix-up across the PDF tags.
Assuming every Adobe cfpdf action exists on Lucee
It doesn't, digital signing (sign/unsign/validateSignature) in particular has no equivalent on Lucee's cfpdf. Check the actual supported action list before porting code that relies on one of the gaps.
Setting opacity as if it were a 0–100 percentage
It's a 0–10 scale, a value like 75 is not what it looks like.
Merging PDFs without setting keepbookmark, then expecting bookmarks to survive
It defaults to false, set it explicitly when each source document's bookmarks matter in the merged result.
Forgetting overwrite when writing to a destination that already exists
Without it, running the same operation again against an existing file can fail rather than replace it.
Best Practices
- Check Lucee's actual supported action list before porting Adobe cfpdf-based signing, sanitizing, or archiving code.
- Use getInfo before deciding how to process an unfamiliar or user-uploaded PDF.
- Use explicit page ranges (like "1,6-9,56-89") rather than assuming a default range applies.
- Set keepbookmark explicitly on a merge when the source documents' bookmarks need to survive.
Interview Questions
What's the difference between what cfdocument and cfpdf are each used for?
cfdocument generates a new PDF from CFML/HTML content. cfpdf manipulates a PDF that already exists, merging, watermarking, protecting, or extracting content from it.
What's a real, concrete gap in Lucee's cfpdf compared to Adobe's?
Digital signing and signature validation (sign, unsign, validateSignature, readSignatureFields) aren't documented on Lucee's cfpdf at all, code relying on those actions has no direct equivalent there.
What scale is cfpdf's opacity attribute on for addWatermark?
0 to 10, not a 0–100 percentage.
Summary
In this lesson, you merged multiple PDFs, added a watermark, and password-protected a document with cfpdf, and covered a real migration gotcha: Lucee's cfpdf doesn't implement digital signing or several other actions that Adobe's does.
What's Next?
The next lesson covers cfchart, generating charts and graphs directly from a query.