Skip to main content
Ben Nadel at cf.Objective() 2010 (Minneapolis, MN) with: Anne Porosoff
Ben Nadel at cf.Objective() 2010 (Minneapolis, MN) with: Anne Porosoff

CFDocument Intelligently Reuses Repeated Image Objects In Lucee CFML 5.3.4.80

By
Published in

The other day, I experimented with saving InVision prototypes as interactive PDFs in Lucee CFML. And, while very few people will have an interest in such a technique, it's gotten me thinking a lot about how I might use PDFs more effectively. One thing I started to wonder about is how CFDocument handles repeated Image URLs. The answer to this would certainly influence how I would implement different types of PDF content: whether I crop images in a pre-processing step, generating unique image URLs per cropping; or, whether I should just use overflow:hidden in order to simulate cropping on a repeated image URL. To explore this, I created a simple demo in which I can dynamically repeat an image in a CFDocument tag using Lucee CFML 5.3.4.80.

This demo is super simple. All I'm doing is passing in a URL parameter, pageCount, and then using CFLoop to generate N-number of pages all with the same img tag and src attribute:

<!--- We can use the URL to drive the number of pages generated in the PDF. --->
<cfparam name="url.pageCount" type="numeric" default="1" />

<cfdocument
	format="pdf"
	filename="./images.pdf"
	overwrite="true"
	localurl="true"
	orientation="portrait"
	pagetype="a4"
	margintop="0.5"
	marginright="0.5"
	marginbottom="0.5"
	marginleft="0.5">

	<!doctype html>
	<html lang="en">
	<head>
		<meta charset="utf-8" />
		<style type="text/css">

			p img {
				border: 3px solid #ff3366 ;
				width: 600px ;
			}

		</style>
	</head>
	<body>

		<cfoutput>
			<cfloop index="i" from="1" to="#url.pageCount#" step="1">

				<p>
					<!---
						This IMAGE file is going to be used on N-number of pages. We can
						look at the size (bytes on disk) of the generated file to see if
						the repeated image is "reused" intelligently.
					--->
					<img src="file:///#expandPath( "./goose-duck.jpg" )#" />
				</p>

				<cfdocumentitem type="pagebreak" />

			</cfloop>
		</cfoutput>

	</body>
	</html>

</cfdocument>

<!--- Now that the file has been generated, let's look at the file-size. --->
<cfoutput>
	
	Page Count: #url.pageCount#
	<br />
	File Size: #numberFormat( getFileInfo( "./images.pdf" ).size )#

</cfoutput>

As you can see, there's almost nothing going on in this ColdFusion code. Just a repeated image and set of page-breaks. Then, once the CFDocument tag is done generating the PDF, I output the number of pages and the resultant file-size (in bytes).

If we run this with one-page as our Control, we get the following output:

A 1-page PDF that is 95Kb.

Ok, so 1-page, 1-image is only about 95kb on disk. Now, let's try to increase the page-count / image-count by one oreder-of-magnitude:

A 10-page PDF that is 100Kb.

Despite the 10x increase in image count, the file-size of the PDF has only gone up a mere 5kb. Clearly, the number of times that an image is repeated is not directly proportional to the size of the PDF.

And, let's try increasing it by one more order-of-magnitude:

A 100-page PDF that is 161Kb.

This time, we get a slightly larger jump in file-size; however, even at two orders-of-magnitude in page-count and image-count, we're still only 40% larger in file-size than the 1-page version. Clearly, the CFDocument tag is being very intelligent in how it embeds and then reuses images objects within a single PDF document.

This is important to understand, especially for InVision where we repeat the same image multiple times in a PDF when outputting comments. Instead of attempting to externally crop each conversation image prior to embedding it, we should use the same image whenever possible and then "mimic" cropping by using CSS.

Epilogue On External Image URLs

In this demo, I'm using the localUrl attribute for CFDocument. But, I should point out that the same repeated-image efficiency exists for external, HTTP-URL images. That is, as long as the URL for the image doesn't change, it will be embedded and reused intelligently. However, if the URL is different for each image, then the CFDocument tag will view each instance of the image as a unique binary.

Want to use code from this post? Check out the license.

Reader Comments

I believe in love. I believe in compassion. I believe in human rights. I believe that we can afford to give more of these gifts to the world around us because it costs us nothing to be decent and kind and understanding. And, I want you to know that when you land on this site, you are accepted for who you are, no matter how you identify, what truths you live, or whatever kind of goofy shit makes you feel alive! Rock on with your bad self!
Ben Nadel