ColdFusion makes it relatively trivial to create a PDF and password protect it. But how do you edit a PDF to remove that password? Let me begin this blog entry by saying that I am convinced that the solution I am about to provide is the wrong way to solve the problem. I truly can't believe that the awesome CFPDF tag, which does so much, doesn't provide for this simple functionality. I'll be happy to be proved right when someone posts the one line solution. Until then, here is how I solved it using DDX and the power of magical unicorns.
Let's begin with a simple example of creating a PDF with password protection. This is documented of course, but I just wanted to show a quick reminder of how easy ColdFusion makes it.2 <img src="http://www.magicunicorns.us/Index3/aunirainbow.jpg" align="left">
3 This is the PDF that I'll protect. My bank atm is 5318008.
4 </cfdocument>
5
6 <cfheader name="Content-Disposition" value="inline; filename=foo.pdf">
7 <cfcontent type="application/pdf" variable="#toBinary(secret)#">
After the password...
Alright, so that's how we can create the password protected PDF, but how do we remove the password? Well I began by trying to use various combinations of cfpdf attributes. I tried to set newUserPassword to a blank string, but that returned an error. I tried setting encrypt to None, which is documented, but was told I didn't have permission. (This was after opening the PDF using the password option which worked just fine.) I spent a good hour just playing around and no combination worked for me.
I was about to give up when I looked to DDX. I've blogged on DDX a few times now (my first entry may be found here) and it is truly a very powerful tool. It can be a bit hard to use at times though. You have to be sure you read the docs carefully and make use of isDDX() to verify your XML is valid. Using DDX to solve this problem involves two steps really.
The first thing we need to do is find out how to simply even work with a password protected PDF. Who cares about removing a password - we just want to be sure we can even use a password protected document to do other tasks. I did some searching in the DDX Reference and discovered that you can provide a PasswordAccessProfile element. This element lets you do a few things, one of which is a password for opening the document. Consider:
2 <cfdocument format="pdf" name="secret" userpassword="paris" encryption="128-bit">
3 <img src="http://www.magicunicorns.us/Index3/aunirainbow.jpg" align="left">
4 This is the PDF that I'll protect. My bank atm is 5318008.
5 </cfdocument>
6
7 <cfset fileWrite(expandPath('private.pdf'),secret)>
8
9 <cfset pdfpath = expandPath('./private.pdf')>
10 <cfset outfile = expandPath('./notprivate.pdf')>
11
12 <cfsavecontent variable="myddx">
13 <?xml version="1.0" encoding="UTF-8"?>
14 <DDX xmlns="http://ns.adobe.com/DDX/1.0/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://ns.adobe.com/DDX/1.0/ coldfusion_ddx.xsd">
15 <PDF result="Out1">
16 <PDF source="In1" access="mainP"/>
17 </PDF>
18 <PasswordAccessProfile name="mainP">
19 <Password>paris</Password>
20 </PasswordAccessProfile>
21 </DDX>
22 </cfsavecontent>
23 <cfset myddx = trim(myddx)>
24
25 <cfset inputStruct = {In1="#pdfpath#"}>
26 <cfset outputStruct = {Out1="#outfile#"}>
27
28 <cfpdf action="processddx" ddxfile="#myddx#" inputfiles="#inputStruct#" outputfiles="#outputStruct#" name="ddxVar">
29 <cfdump var="#ddxVar#">
2 <DDX xmlns="http://ns.adobe.com/DDX/1.0/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://ns.adobe.com/DDX/1.0/ coldfusion_ddx.xsd">
3 <PDF result="Out1" encryption="None">
4 <PDF source="In1" access="mainP"/>
5 </PDF>
6 <PasswordAccessProfile name="mainP">
7 <Password>paris</Password>
8 </PasswordAccessProfile>
9 </DDX>


Comment 1 written by Jochem van Dieten on 23 January 2009, at 10:57 AM
<cfpdf action="protect" source="protected.pdf"
newUserPassword = "test"
newOwnerPassword = "test"
permissions = "All"
destination = "unprotected.pdf"
encrypt = "none"
overwrite = "yes"
password = "user" />
Comment 2 written by Raymond Camden on 23 January 2009, at 11:00 AM
Comment 3 written by JC on 23 January 2009, at 11:01 AM
Comment 4 written by Raymond Camden on 23 January 2009, at 11:04 AM
Comment 5 written by Andrew Scott on 24 January 2009, at 6:40 AM
If DDX is ignoring those two options then the problem is in DDX and not ColdFusion, in my eyes.
Comment 6 written by Raymond Camden on 24 January 2009, at 8:43 AM
Who knew we would spend so much time on such a small detail in PDF files? ;)
[Add Comment] [Subscribe to Comments]