Using Both SrcFile And CFDocumentItem In The Same CFDocument Tag In Lucee CFML 5.3.7.47
At InVision, we generate a surprising number of PDF documents. For the most part, the CFDocument
tag in Lucee CFML just works. But, sometimes, PDF generation eats-up all the RAM and an OOM (Out of Memory) error is thrown. As such, I'm always on the lookout for ways to tweak the PDF generation process to see if I can consume fewer resources. One idea that I had was to pre-generate the HTML file instead of just rendering the HTML content within the CFDocument
tag-body. But, I wasn't sure if I could combine the concept of the srcfile
attribute with the child-tag, CFDocumentItem
. As such, I wanted to try it out in Lucee CFML 5.3.7.47.
CAUTION: My goal here is to try and find ways to consume fewer resources while generating a PDF. That said, I am not saying that this technique uses fewer resources. This post is simply an exploration of the mechanics of this technique, not the performance of this technique.
Historically, when I've gone to generate a PDF document with the CFDocument
tag, I just jam a whole bunch of CFML right into the body of the tag:
<cfscript>
document
format = "pdf"
filename = "my-doc.pdf"
overwrite = true
{
```
<p>
I can haz PDF?!
</p>
```
}
</cfscript>
This example is obviously trivial - in a real-world PDF, the content of the document would be significantly more complex and would (likely) include CFDocumentSection
and CFDocumentItem
tags. But, part of me wonders if all of that "child logic" is contributing to the memory consumption. As such, I'm curious to see if using an external file via the SrcFile
attribute would:
Force me to simply the mechanics of the document.
Allow the PDF-generation engine to keep less "stuff" in memory.
Of course, I still need to define a document header (in some cases); and, I can't find a way to do this with just HTML/CSS; so, I'll still need the CFDocumentItem
tag to be a child of the CFDocument
tag.
Here's my test to see if this works - the following code pre-generates an HTML file by rendering a CFML file to a string-buffer and then writing that buffer to disk. This generated-file is then consumed by the CFDocument
tag as the SrcFile
attribute:
<cfscript>
stub = "./out/doc-#createUniqueId()#";
// Evaluate the CFML body that we're going to use for the PDF generation.
savecontent variable = "bodyContent" {
include "./render-body.cfm";
}
// Save the CFML document as a static HTML document. This is what we're going to use
// as the "srcfile" for the CFDocument tag.
fileWrite( "#stub#-body.html", bodyContent );
document
format = "pdf"
filename = "#stub#.pdf"
srcfile = "#stub#-body.html"
overwrite = true
localurl = true
{
// Note that we can mix both "srcfile" and CFDocumentItem techniques.
documentItem type = "header" {
```
<table width="100%" cellpadding="0" cellspacing="0" class="page-header">
<tr>
<td class="page-header__left">
Testing CFDocument
</td>
<td class="page-header__right">
SrcFile & DocumentItem(s)
</td>
</tr>
</table>
```
}
}
</cfscript>
As you can see, the only child content of the CFDocument
tag is the one CFDocumentItem
tag for the header - the rest of the body content is taken from the srcfile
attribute. And, when we run this ColdFusion code, we are able to successfully generate a PDF document using both sources of content:
Again, I have no idea if this actually has any impact on resource consumption. But, now that I know that this approach is possible, it gives me something more to play with. Generating PDFs in ColdFusion isn't always "great"; but, by gosh, they make it easy.
Want to use code from this post? Check out the license.
Reader Comments
@All,
After writing this, it occurred to me that I wasn't sure how to create page-breaks when using an external source file. Normally, I would use
CFDocumentItem[type=pagebreak]
. But, I don't have that opportunity with an external file. Luckily, page-breaks are possible with pure CSS:www.bennadel.com/blog/4045-creating-page-breaks-in-cfdocument-without-using-cfdocumentitem-in-lucee-cfml-5-3-7-47.htm