Styling The ColdFusion 8 WriteToBrowser CFImage Output

Posted July 20, 2007 at 4:22 PM

Tags: ColdFusion

The ColdFusion 8 has some amazing functionality, one feature of which is being able to write an image to the browser as an inline IMG tag:

 Launch code in new window » Download code as text file »

  • <cfimage
  • action="writetobrowser"
  • source="./mud_monster.jpg"
  • />

The problem with this is that it writes the IMG tag to the browser and doesn't give you any ability to add your own IMG attributes, including CSS or STYLE. This may or may not be a problem for people, but it would be nice to have access to the tag data.

This dilemma is actually fairly easy to overcome. The CFImage tag, in addition to creating the image object and saving to the file system, is really just writing to the page's content buffer, which is then flushed to the client along with everythign else. As such, we can intercept the content buffer write, modify it in any way we want, and then write the new IMG tag to the page's content buffer.

I have created ImageWriteToBrowserCustom(), a ColdFusion user defined function that takes your ColdFusion 8 image object and additional attribute values and writes the IMG tag for you. Here's what it might look like:

 Launch code in new window » Download code as text file »

  • <html>
  • <head>
  • <title>ColdFusion 8 WriteToBrowser() Modification</title>
  • <style type="text/css">
  •  
  • img.frame {
  • border: 2px solid #660000 ;
  • }
  •  
  • </style>
  • </head>
  • <body>
  •  
  • <!--- Read image into memory. --->
  • <cfimage
  • action="read"
  • source="./mud_monster.jpg"
  • name="objImage"
  • />
  •  
  • <!--- Write to browser with custom attributes. --->
  • <cfset ImageWriteToBrowserCustom(
  • Image = objImage,
  • Alt = "Mud Monster - She So Crazy!",
  • Class = "frame",
  • Style = "border-width: 10px ;"
  • ) />
  •  
  • </body>
  • </html>

Notice that ImageWriteToBrowserCustom() is taking the image that we read in via CFImage as well as the ALT, CLASS, and STYLE attributes. If we now look at the source code of the rendered page, we will get the following image tag (I have wrapped it for easy viewing):

 Launch code in new window » Download code as text file »

  • <img
  • src="/CFFileServlet/_cf_image/_cfimg527766746223564434.PNG"
  • alt="Mud Monster - She So Crazy!"
  • class="frame"
  • style="border-width: 10px ;"
  • />

The image itself looks like this:


 
 
 

 
ColdFusion 8 - Modifying The CFImage WriteToBrowser Action  
 
 
 

The user defined function that accomplishes this is actually fairly simple and just traps the IMG tag output using ColdFusion's CFSaveContent tag:

 Launch code in new window » Download code as text file »

  • <cffunction
  • name="ImageWriteToBrowserCustom"
  • access="public"
  • returntype="void"
  • output="true"
  • hint="Writes the image to the browser with additional attributes.">
  •  
  • <!--- Define arguments. --->
  • <cfargument
  • name="Image"
  • type="any"
  • required="true"
  • hint="The ColdFusion image object that you are writing to browser."
  • />
  •  
  • <cfargument
  • name="Alt"
  • type="string"
  • required="false"
  • default=""
  • hint="The ALT attribute value to apply to the image."
  • />
  •  
  • <cfargument
  • name="Class"
  • type="string"
  • required="false"
  • default=""
  • hint="The CSS class to apply to the image."
  • />
  •  
  • <cfargument
  • name="Style"
  • type="string"
  • required="false"
  • default=""
  • hint="The STYLE attribute value to apply to the image."
  • />
  •  
  • <cfargument
  • name="Height"
  • type="string"
  • required="false"
  • default=""
  • hint="The HEIGHT attribute value to apply to the image."
  • />
  •  
  • <cfargument
  • name="Width"
  • type="string"
  • required="false"
  • default=""
  • hint="The WIDTH attribute value to apply to the image."
  • />
  •  
  • <cfargument
  • name="Border"
  • type="string"
  • required="false"
  • default=""
  • hint="The BORDER attribute value to apply to the image."
  • />
  •  
  •  
  • <!--- Define the local scope. --->
  • <cfset var LOCAL = {} />
  •  
  •  
  • <!---
  • Write the image to the browser. This is really just
  • creating the image and then writing to the buffer.
  • All we have to do is intercept the buffer write.
  • --->
  • <cfsavecontent variable="LOCAL.Output">
  • <cfoutput>
  •  
  • <!--- Write image tag. --->
  • <cfimage
  • action="writetobrowser"
  • source="#ARGUMENTS.Image#"
  • />
  •  
  • </cfoutput>
  • </cfsavecontent>
  •  
  • <!---
  • First, delete any existing attributes that we might
  • be using (so that we can just add new ones).
  • --->
  • <cfset LOCAL.Output = LOCAL.Output.ReplaceAll(
  • "(?i) (alt|class|style|height|width|border)=""[^""]*""",
  • ""
  • ) />
  •  
  • <!---
  • Now that we have an image with Just the SRC
  • attribute, we can go about adding our attributes.
  • First, chop off the trailing slash.
  • --->
  • <cfset LOCAL.Output = LOCAL.Output.ReplaceFirst(
  • "\s*/?>\s*$",
  • ""
  • ) />
  •  
  • <!---
  • Loop over the arguments to see if we need to
  • add them to the tag.
  • --->
  • <cfloop
  • index="LOCAL.Key"
  • list="alt,class,style,height,width,border"
  • delimiters=",">
  •  
  • <!--- Check for a passed-in value. --->
  • <cfif Len( ARGUMENTS[ LOCAL.Key ] )>
  •  
  • <!---
  • Append this argument to the output and a
  • key-value attribute.
  • --->
  • <cfset LOCAL.Output &= (
  • " " &
  • LOCAL.Key &
  • "=""" &
  • ARGUMENTS[ LOCAL.Key ] &
  • """"
  • ) />
  •  
  • </cfif>
  •  
  • </cfloop>
  •  
  • <!--- Write the image tag to the output. --->
  • <cfset WriteOutput( LOCAL.Output & " />" ) />
  •  
  • <!--- Return out. --->
  • <cfreturn />
  • </cffunction>

I am sure (*hoping*) that eventually ColdFusion 8 will give us the ability to control the attributes of the rendered IMG tag, but for now, this seems like a decent solution. The one thing I don't like about it is that it requires the Output attribute of the CFFunction tag to be true; I really don't like having output in a function call, but I also didn't want to return a value since CFImage / WriteToBrowser doesn't return any values (and I wanted to keep in sync with that style.

Download Code Snippet ZIP File

Post Comment  |  Ask Ben  |  Other Searches  |  Print Page




Learning ColdFusion 9 - ColdFusion 9 tutorials, samples, examples, demos

Reader Comments

Jul 20, 2007 at 4:46 PM // reply »
7,212 Comments

While I didn't do this in the demo, this could probably be made more flexible by not actually defining the argument tags, but rather looping over the arguments and created name-value attributes for anything NOT named "Image". This way, you could just about add any attribute you wanted to (ex. onclick, onload).


Jul 21, 2007 at 2:58 AM // reply »
25 Comments

Thats a nice idea and solution Ben. We can not make any change in this function now. but certainly in future.


Jul 21, 2007 at 10:44 AM // reply »
7,212 Comments

@Rupesh,

Yeah, not a huge deal, but down the road, it would definitely be cool. Especially since I think I remember saying Ben Forta saying that all the AJAX stuff produces XHTML compliant code, and I think technically, all images need height/width attributes to be "standards compliant" (maybe).... not that that really matters to me so much, but just another selling point.


Aug 18, 2007 at 3:44 AM // reply »
5 Comments

Don't forget that there are often many more attributes that could be used (like id="uniqueVal"). A simple solution might be to offer an attribute called xcode (or whatever) where it just adds the entire value to the resulting img tag as attribute=value pairs.

example:

xcode='alt="My IMage" id="myImage" class="imgRight"'

Just a thought.


Aug 18, 2007 at 4:56 PM // reply »
7,212 Comments

Yes, definitely a good idea.


Jan 8, 2009 at 7:10 AM // reply »
4 Comments

Once again great work Ben. But I have the problem to add attributes to a CF generated captcha image. With captcha u can not use the name attribute to cfimage tag. So I thought about using cfsavecontent, which returns one of the most weird errors:

The png" alt="" height="40" width="140" /> image format is not supported on this operating system. Use GetReadableImageFormats() and GetWriteableImageFormats() to see which image formats are supported.

I created a function for this:

<cffunction
name="writeCaptcha"
displayname="writeCaptcha"
hint="I will output the captcha image"
returntype="any">

<cfargument name="strCaptcha" type="string" required="false">

<cfset var ret = "">

<cfsavecontent variable="ret">

<cfoutput>

<cflock name="captcha" type="exclusive" timeout="20">

<cfimage
action="captcha"
height="40"
width="140"
text="#arguments.strCaptcha#"
difficulty="medium"
fonts="verdana,arial,times new roman,courier"
fontsize="20"
/>

</cflock>

</cfoutput>

</cfsavecontent>

<cfreturn ret/>
</cffunction>

Do you have any other suggestion, or a workaround so I can use your ImageWriteToBrowserCustom() function on captcha images?


Jan 14, 2009 at 10:32 PM // reply »
7,212 Comments

@Alexander,

That's a funky error. I don't believe I tried to use this with CAPTCHA. If I can get some time, I'll take a looksee.


Feb 20, 2009 at 10:01 AM // reply »
2 Comments

Just wanted to let you know that this code greatly helped me. On many occasions I have gotten frustrated with my non-functioning code, turned to Google for help and your site has always had an answer. Thank you!


Feb 20, 2009 at 10:37 AM // reply »
4 Comments

Hi Ben, hi Matt,

now that I received your message, Matt, I was wondering why the hell is that code not working for me. So I tried this code once again on my personal machine at home and...well..it is working here perfectly. Strange, because both machines (company and at home are same). I guess I will look out for some hotfixes, that may be applied on my machine, already.

Thank you for getting me back on this.

Kind regards
Alex


Feb 20, 2009 at 10:58 AM // reply »
2 Comments

I did install a ColdFusion patch on my server to fix another issue. Perhaps that would help?

More info here:
http://kb.adobe.com/selfservice/viewContent.do?externalId=kb403411


Feb 20, 2009 at 11:12 AM // reply »
7,212 Comments

@Alexander,

Yeah, definitely look into the hot fixes. I know there were some that helped several image funkiness.


Nov 21, 2009 at 4:49 PM // reply »
9 Comments

Great work yet again Ben! Whilst I didn't use this whole code, I copied some of your regex code for a similar problem with the lack of an alt attribute and unescaped ampersands in CFIMAGE for Railo 3.1.

Thanks!

:)


cu
Dec 7, 2009 at 4:40 PM // reply »
1 Comments

Great work! I use a jQuery solution that has worked quite well. The example uses a real image file and a CF-created one.

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js" type="text/javascript"></script>
<style>
.myImage { border:4px solid red; };
</style>
<cfimage name="cImg1" source="pic.jpg">
<cfset cImg2 = ImageNew("","100","100","grayscale")>
<span class="imgAddClass"><cfimage action="writeToBrowser" source="#cImg1#" format="jpg" quality="1"></span>
<span class="imgAddClass"><cfimage action="writeToBrowser" source="#cImg2#" format="jpg" quality="1"></span>
<script>$(".imgAddClass img").addClass("myImage").attr("alt","This is my image");</script>


Post Comment  |  Ask Ben

Recent Blog Comments
Feb 9, 2010 at 8:09 AM
Creating A "Remember Me" Login System In ColdFusion
@Nikos, Heck yeah! Glad you got things working smoothly. ... read »
Feb 9, 2010 at 8:05 AM
Creating A "Remember Me" Login System In ColdFusion
No probs :) anyway , Im good now :) ... read »
Feb 9, 2010 at 8:02 AM
Creating A "Remember Me" Login System In ColdFusion
@Nikos, I've seen people use the J2EE sessions, but I have not used them myself... yet. ... read »
Feb 9, 2010 at 7:57 AM
Ask Ben: Converting a Query to an Array
@Stju, Did you actually test this? I ask because there is a fatal flaw in it - you are using the same Row struct for every row. Since Structs are passed by reference, every subsequent update you ma ... read »
Feb 9, 2010 at 7:50 AM
Using jQuery's SlideUp() and SlideDown() Methods With Bottom-Positioned Elements
@Thomas, Not bad. I suppose you could do the same with Top as well as margin. ... read »
Feb 9, 2010 at 7:47 AM
Ask Ben: Creating A PDF And Attaching It To An Email Using ColdFusion
@Johan, I don't think I have one off hand. Basically, you'd just want to use the File attribute of CFDocument to save the PDF to disk. Then, you'd want to use the File attribute of CFMailParam to a ... read »
Feb 9, 2010 at 5:34 AM
Creating A "Remember Me" Login System In ColdFusion
Any change you could show how to take advantage how the J2ee session stuff in your code? http://kb2.adobe.com/cps/182/tn_18232.html ... read »
Feb 9, 2010 at 5:32 AM
Creating A "Remember Me" Login System In ColdFusion
This may help: http://bugs.farcrycms.org/browse/FC-79 Its the session variables' option being selected in the CF Admin ... read »