Skip to main content
Ben Nadel at cf.Objective() 2014 (Bloomington, MN) with: Jonathan Dowdle
Ben Nadel at cf.Objective() 2014 (Bloomington, MN) with: Jonathan Dowdle

Getting The Image SRC Of ColdFusion's CFImage WriteToBrowser Temporary Image With CFXML

By
Published in Comments (11)

ColdFusion 8 comes with a file servlet that can be used to serve up temporary image files. This is great because it allows us to do on-the-fly image creation without having to worry about the physical image file I/O (input/output). Furthermore, the images stored in the file servlet get deleted automatically after a brief amount of time so that we don't have to worry about file clean-up either. Unfortunately, there's no real API for accessing this file servlet; it's usage is a byproduct of some of ColdFusion's other features. Specifically, ColdFusion's CFImage "WriteToBrowser" action will write an image to the file servlet and then output an XHTML IMG tag with the temporary image path as the IMG SRC attribute.

Sometimes, it would be nice to be able to create these temporary image files without having to write an IMG tag to the output. Fortunately, there is a really easy way to leverage the existing CFImage behavior to accomplish such a goal. As I demonstrated a few years ago, the CFIMage "WriteToBrowser" action doesn't necessarily write an IMG tag to the response buffer; rather, it writes the IMG tag to the current output buffer. In most cases, the response buffer is the current output buffer; but, when we use ColdFusion tags like CFSaveContent and CFXML, the output buffer within those tags is not the response buffer but rather the content buffer of the given tag.

A while back, I used a CFSaveContent approach to extract the SRC attribute of the temporary IMG tag. But, there's an even easier approach. When CFImage writes the IMG tag to the current output buffer, it uses strict XHTML standards. That means it also uses XML standards. And, if it uses XML standards, we can treat it as XML and parse it into an XML document object. This turns out to be super easy way to access the temporary image source path without having to output the IMG tag to the response:

<!--- Load the remote image. --->
<cfimage
	name="kittenYawning"
	action="read"
	source="http://some-image-domain.com/38sdf52_o.jpg"
	/>


<!---
	Write the image to the output. Except, rather than writing it
	to the screen, write it to an XML data buffer.
--->
<cfxml variable="imageXml">

	<!--- Let IMG be the only tag in this XML document. --->
	<cfimage
		action="writetobrowser"
		source="#kittenYawning#"
		/>

</cfxml>


<!---
	At this point, our XML object should have one tag - IMG - from
	which we can extract the SRC attribute as the temporary image
	path on the CFImage file servlet.
--->
<cfset imageSrc = imageXml.xmlRoot.xmlAttributes.src />


<!--- Output the temporary image src: --->
<cfoutput>

	SRC: #imageSrc#

</cfoutput>

As you can see here, after we load the remote image, we use CFImage's "WriteToBrowser" action to output the XHTML IMG tag to a CFXML buffer. This will parse the IMG tag into a single-node XML document from which we can easily extract the XML attribute, "Src." In doing so, we can find the URL of the temporary image without having to send an IMG tag to the client or deal with any complex Regular Expression pattern matching. And, in fact, when we run the above code, we get the following output:

SRC: /CFFileServlet/_cf_image/_cfimg3659208981406976772.PNG

This SRC attribute can then be served up to the client as some sort of AJAX or Web Service response. In either case, I have found this to be the easiest way to create temporary images without having direct access to the response buffer.

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

Reader Comments

198 Comments

It's important to remember that there's a pretty short timeout for these temporary files, so the URLs become invalid pretty quickly (I can't recall what the initial timeout is, but it can be changed in one of the XML files.) Just keep this in mind depending on how you're planning on implementing this.

15,848 Comments

@Dan,

Good point. I think by default it is somewhat high (the timeout); from what I can remember, I've had situations where the URL is still valid like 20 minutes later.

But that said, yes, you can definitely not depend on this for any kind of long-term persistence. Typically what I use this for is AJAX / web services responses where the URL is needed immediately, but an IMG tag is not really fitting to the situation.

290 Comments

I'm writing to recommend exploring the "Data URL" syntax:

http://en.wikipedia.org/wiki/Data_URI_scheme

The advantage of using a true file for an image is caching. On page refreshes or requests of new pages with the same URL, the browser detects that the file is in cache and sends the request with the HTTP header If-Modified-Since:

http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.25

If the file hasn't changed since the date/time given in the header, the server can respond with a 304 Not Modified response, and the web is all the better off for the minimization of unnecessary traffic.

But if the file is going to reside on the hard drive on the server only temporarily, you lose that benefit. So why have it reside there at all? You're incurring an I/O to write it, the web server incurs an I/O to read it, and the network traffic is the same or worse, compared to using a Data URL.

I've only used the CF image tags/functions to create CAPTCHA files, which are an ideal example of intentionally one-time-only files. But I couldn't explore the Data URL option further at that time, because I had to abandon CAPTCHA. (I work at a US Federal Government site and all of our pages have to be Section 508 compliant. It denies access to the blind to use CAPTCHA to control access.)

Given the ease with which we can base64-encode data in ColdFusion, Data URLs seem like a perfect fit for generated-only-once-on-the-fly images.

15,848 Comments

@Anon,

Shhh, that's an "Easter egg".

@Steve,

Data URIs are definitely interesting. As you are probably aware, ColdFusion can easily read in data URIs with the imageReadBase64() method. I've briefly played around with that; but, I have not played around very much with actually creating base64 encoded images as part of a data URI.

It is definitely very cool. Unfortunately, I don't think image data URIs are not supported in Internet Explorer until version 8. That's puts a bit of hamper on its use :(

15,848 Comments

@Steve,

Something like this, however, would be awesome for a closed application, like an internal app on the company intranet.

81 Comments

@Ben,

When you said you didn't think that data URIs were supported by MSIE until version 8, it was news to me. I assumed that you had run one of your many experiments.

But just now, on Wikipedia, I noticed that MSIE does in fact support data URIs for images. Have a look:

http://en.wikipedia.org/wiki/Comparison_of_web_browsers#cite_note-IEdataprotocol-132

So I'm back to recommending that approach as a way to avoid 2 I/Os when you're serving up generated-only-once-on-the-fly images.

15,848 Comments

@Steve,

I am not sure if I have run it. I have definitely looked it up, though not on any official docs - mostly on some other people's web sites. I'll do some testing with my IE Collection app.

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