Every now and then I can't find a good solution for a reader so I take to the "airways" and ask my good readers for help. This is one of those days. Rick emailed me a few days ago with an interesting issue.
He had a query that he used to create a set of PDFs. In each PDF, he included a bit of dynamic data, like name, age, etc. It worked, but something odd happened. Consider the following sample code.
<cfset getStudents = queryNew("fname,lname,email", "cf_sql_varchar,cf_sql_varchar,cf_sql_varchar", [
{fname:"Ray",lname:"Camden",email:"raymondcamden@gmail.com"},
{fname:"Joe",lname:"Blow",email:"jblow@gmail.com"},
{fname:"Scott",lname:"Stroz",email:"boyzoid@gmail.com"}]
)>
<cfoutput>
<cfloop query="getStudents">
<cfdocument format="pdf" orientation="landscape" name="certificate">
<p style="background-image:url(cert.jpg);background-repeat:no-repeat;height:680px;width:900px">
<font size="+2">#fname# #lname#</font>
</p>
</cfdocument>
<cfmail from="no_reply@monoc.org" to="#email#" subject="Your Course Completion Certificate" type="html">
<cfmailparam file="certificate.pdf" type="application/pdf" content="#certificate#" />
</cfmail>
</cfloop>
</cfoutput>
Pretty straightforward, right? Each PDF is stored in memory and then attached to an email. When executed, emails go out, the text is dynamic per the code specified, but only the first PDF has the background attachment as defined in CSS.
As an FYI, when you create emails with attachments, you can find the attachments pretty easily. Open the mail file first, and then make note of the file line. Here is a sample from one of my tests: file: /Applications/ColdFusion10/cfusion/runtime/work/Catalina/localhost/tmp/cftmp1249913661563960132.tmp
The file is named .tmp, but I found the file, renamed it .pdf, and was able to view it just fine.
Anyway, I did some digging into this and immediately found some interesting tips:
- Use localurl="true"
- Use a file:/// path
But none of these worked. I also tried adding a bit of randomness to the URL, thinking it was something in ColdFusion's request handling, but that didn't work either. I then made the variable used for PDF data dynamic. Why? Who the heck knows. I was trying everything. Here is the final version of the script, and one you can run yourself, to see the bug in action.
<cfset getStudents = queryNew("fname,lname,email", "cf_sql_varchar,cf_sql_varchar,cf_sql_varchar", [
{fname:"Ray",lname:"Camden",email:"raymondcamden@gmail.com"},
{fname:"Joe",lname:"Blow",email:"jblow@gmail.com"},
{fname:"Scott",lname:"Stroz",email:"boyzoid@gmail.com"}]
)>
<cfoutput>
<cfloop query="getStudents">
<cfdocument format="pdf" orientation="landscape" name="certificate#currentRow#" localurl="true">
<p style="background-image:url(cert.jpg);background-repeat:no-repeat;height:680px;width:900px">
<font size="+2">#fname# #lname#</font>
</p>
<hr/>
<p style="background-image:url(file:///Users/ray/Dropbox/websites/testingzone/cert.jpg);background-repeat:no-repeat;height:680px;width:900px">
<font size="+2">#fname# #lname#</font>
</p>
<hr/>
<p style="background-image:url(cert.jpg?x=#createUUID()#);background-repeat:no-repeat;height:680px;width:900px">
<font size="+2">#fname# #lname#</font>
</p>
</cfdocument>
<cfset content = variables["certificate#currentRow#"]>
<cfmail from="no_reply@monoc.org" to="#email#" subject="Your Course Completion Certificate" type="html">
<cfmailparam file="certificate.pdf" type="application/pdf" content="#content#" />
</cfmail>
</cfloop>
</cfoutput>
So... any ideas?
Archived Comments
I have not tried any of this....and I am not a CSS expert by any means, but had these sudden thoughts...
Put a <div> around the <p></p> block , and put the 'style' for the image inside the <div> statement. So, roughly, <div style:stuff-including-image><p>the text goes here </p></div>
Also, in your test code between the divs (or the <p>'s), you might need a <div> with a style:position:relative</div>, otherwise the next certificate image is placed on top of the previous one. You might also need a clear:left between each certificate image.
I encountered something similar when using small GIF images that were all different. Even though the filenames were different, CF8 CFDocument would display all images using the same source image. (I need to find the test code that I was using so I can see if this issue still exists in ColdFusion 9, 10 or 11.)
I wrote scripts to generate finisher certificates (name, age, finish time, rank, etc). To work around multiple CSS layout limitations and eliminate possible performance issues, we started using pre-generated PDF templates with form fields. We'd use cfpdfform to populate a PDF that has named fields (the fields would be styled with embedded fonts that weren't installed on the server). After saving the updated PDF, we'd re-read it and flatten it. Here's
<cfpdfform action="POPULATE" source="C;\originalPDF.pdf" destination="C:\PopulatedPDF.pdf" overwrite="yes" overwritedata="yes">
<cfpdfformparam name="Name1" value="#Name1#">
<cfpdfformparam name="Name2" value="#Name2#">
<cfpdfformparam name="Name3" value="#Name3#">
</cfpdfform>
<cfpdf action="write" source="C:\PopulatedPDF.pdf" destination="C:\FinalPDF.pdf" overwrite="yes" flatten="yes">
In addition, if we want to have multiple certificates in a single PDF, we use CFPDF to merge them. To bring the bloated filesize down to something tolerable, we use CFExecute & ghostscript. For complex placement/population, we gave up back in ColdFusion 8 and started using iText directly.
Another command line option we just started using is wkhtmltopdf. It's PDF generation is vastly superior to the 2008 engine that CFDocument currently uses for ColdFUsion 9-11beta. Check it out. http://wkhtmltopdf.org/
I just verified that the CFDocument bug I encountered exists in ColdFusion 8, 9, 10 & 11 installations.
Small PNG images with transparency are duplicated. (It may work with larger PNG images too, but I never tried.) I created multiple unique PNG, JPG & GIF images using CFImage. Transparent PNG images were created using ImageNew("", 19, 9, 'argb'). The transparent GIF & regular JPG images work fine, but all PNG images end up displaying the first image that is used in the CFDocument.
(I can't test the code & images on CFLive.net or TryCF.com either due to the CFDocument tag being disabled.)
Came across a similar problem.
I ended up creating the content inside cfsavecontent and then calling the variable inside the cfdocument.
I tried using the cfsavecontent method for a pdf document created with the cfdocument tag but when it came time to output the message and attach the pdf it had difficulty doing it. The only way I could make it work was to use the name="invcontent" attribute in the cfdocument tag and then set the file name and content with a cfmailparam tag.
Which is essentially what Ray has done in this example. But I directly hard coded the images in the tables or with image tag's vs. using any kind of cfimage resolution. I may have to take a look at James's way of doing it via cfimage and the cfpdf action. Interesting option.
I reported the ColdFusion 8, 9, 10 & 11 bug here and posted sample code:
#3725010 "CFDocument duplicates transparent PNG images of equal dimensions"
https://bugbase.adobe.com/i...
Transparent PNG images look pretty amazing on PDFs (especially compared to a transparent GIF), but use any with the same dimensions and you'll encounter this bug.
I know this is old but this worked great for a certificate with a name, issue date, and expiration date.
CF 2016 Pro.
Win 2018 server
<cfheader name="Content-Disposition" value="attachment;filename=#pdfFileName#-certificate.pdf">
<cfcontent type="application/pdf">
<cfdocument format="pdf" pagetype="custom" orientation="landscape" fontembed="true" unit="in" localurl="true" marginleft="0" margintop="0" marginright="0" marginbottom="0" backgroundvisible="true" pageheight="8.5" pagewidth="8.5">
<cfinclude template="stylepage.cfm">
<div style="position:absolute; top:318px; left:38px;font-size:20px;width:360px;height:198px;">
<div style="text-align:center;margin-top:78px;font-size:20px;"><cfoutput>#name#</cfoutput></div>
<div style="position:absolute;margin-left:13px;margin-top:143px;font-size:14px;"><cfoutput>#cert-date#</cfoutput></div>
<div style="position:relative;margin-left:106px;margin-top:44px;font-size:14px;"><cfoutput>#exp-date#</cfoutput></div>
</cfdocument>
style include contained: (this is the blank certificate in the background)
<style type="“text/css”">
body {
background-image: url("https://www.yourimage.com/c...");
background-repeat: no-repeat;
background-attachment: fixed;
}
</style>