Ben Nadel
On User Experience (UX) Design, JavaScript, ColdFusion, Node.js, Life, and Love.
I am the chief technical officer at InVision App, Inc - a prototyping and collaboration platform for designers, built by designers. I also rock out in JavaScript and ColdFusion 24x7.
Meanwhile on Twitter
Loading latest tweet...
Ben Nadel at Scotch On The Rock (SOTR) 2010 (Amsterdam) with:

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

By Ben Nadel on
Tags: ColdFusion

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="girlsFighting"
  • action="read"
  • source="http://farm5.static.flickr.com/4037/4443876086_fa59a4fa52_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="#girlsFighting#"
  • />
  •  
  • </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.




Reader 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.

Reply to this Comment

@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.

Reply to this Comment

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.

Reply to this Comment

I also recommend copying and pasting the w3.org URL I just gave, because the ".25" got chopped off of the hotlink.

Reply to this Comment

Wow. This should come with a NSFW warning. I definitely just checked out the URL at work.

Reply to this Comment

@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 :(

Reply to this Comment

... or even a damper. But it wouldn't be the first time I threw a feature into the laundry bin because of MSIE. :)

Reply to this Comment

@Steve,

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

Reply to this Comment

@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.

Reply to this Comment

@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.

Reply to this Comment

Post A Comment

You — Get Out Of My Dreams, Get Into My Comments
Live in the Now
Oops!
Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.