Todd Sharp recently pinged me about an interesting problem. He was working with Images generated in ColdFusion 8 and was trying to use this imaga via the HTML IMG tag, like so:
The code in foo.cfm generated the graphic and he couldn't quite figure out how to display it. One thing he tried was the WriteToBrowser action:
This didn't work - and if you view source on a file using this action you will see why. The WriteToBrowser action actually generates HTML that points to a 'magic' URL to serve the image.
He also tried cfcontent:
2 <cfcontent type="image/jpg" variable="#paris#">
This also failed as well. Why? The cfcontent tag doesn't like the Image variable. ColdFusion will throw the following error:
coldfusion.image.Image is not a supported variable type. The variable is expected to contain binary data.
If you think about it - this makes sense. Image variables aren't binary data in ColdFusion. While they may store binary data, ColdFusion wraps up the data in a new "Image" variable type. Now personally I think cfcontent should be smart enough to recognize a image variable and deal with it - but what do you in the meantime?
ColdFusion provides a ImageGetBlob function. This returns the binary data of the image and can be safely used with cfcontent like so:
2 <cfcontent type="image/jpg" variable="#imageGetBlob(paris)#">
But wait - there is a catch! This works ok as long as you begin your image with a real image. Notice above I have a image file I'm beginning with. If I use a 100% virtual image then it doesn't work. Consider:
If you run imageGetBlob on this, you get:
The source file should contain an extension,so that ColdFusion can determine the image format.
So I'm not 100% sure - but this is how I read this. I had created an image of a certain type of image type. But there was no file type for the image. Obviously I could write the variable out to a file, but there is no way to go directly from an "pure" Image variable to a blob. I'm going to file an enhancement request to add support for this. In the meantime if you needed to do something like this, I'd recommend creating a "canvas" graphic in your desired format and seed your dynamic image with that.
Ok - so now for the contest part. I whipped up a quick demo to show the code described above in action. I call it the Paris-Talkometer. Let me show you the code and then I'll link to the application.
2
3 <cfajaxproxy bind="javascript:updImage({caption})">
4
5 <script>
6 function updImage(str) {
7 if(str != '') document.getElementById('myimg').src = 'imgs3.cfm?caption='+escape(str);
8 }
9 </script>
10
11 <h2>Paris-Talkometer</h2>
12
13 <cfform name="form">
14 <cfinput type="text" name="caption" value="#url.caption#" > <cfinput name="mybutton" type="button" value="Update"><br />
15 <cfinput type="image" name="myimage" src="imgs3.cfm?caption=#url.caption#" id="myimg">
16 </cfform>
What we have is is a basic form. There is a text box for a caption, and a cfinput image type that points to imgs3.cfm. Notice though that it passes a URL variable. Go back up to the top of the file and see how I use cfajaxproxy to bind to the caption. Whenever the caption changes, I use a bit of JavaScript to the change the SRC of the image. Here is the code behind imgs3.cfm:
2
3 <cfimage action="read" source="paris.jpg" name="paris">
4
5 <cfif len(trim(url.caption))>
6
7 <cfset imageSetDrawingColor(paris, "black")>
8 <cfset imageDrawRect(paris, 1, 1, paris.width, 40, true)>
9
10 <cfset imageSetAntialiasing(paris, "on")>
11 <cfset imageSetDrawingColor(paris, "white")>
12 <cfset text = { style='bold', size=12, font='verdana' }>
13 <cfset imageDrawText(paris, url.caption, 10, 25, text)>
14
15 </cfif>
16
17 <cfcontent type="image/jpg" variable="#imageGetBlob(paris)#">
All I'm really doing here is looking for a URL.caption value. If it exists, I draw some text over the picture. The last thing I do is serve up the image using cfcontent and imageGetBlob.
You can see this in action here:
http://www.coldfusionjedi.com/demos/imagecfcontent/test3.cfm
Now for the contest. If you look at the code for test3.cfm, you will notice that you can seed the caption value via the URL. Here is an example.
Your content is to make Paris intelligent - or at least witty. While this is a somewhat herculean task - I'm sure some of you can do it. Just post your URL as a comment (and of course, you can comment on the main part of this blog post as well). Please keep your captions work safe. Work safe doesn't mean boring - just keep it safe please.


Comment 1 written by Hem on 14 September 2007, at 8:11 AM
If you save the image file to the HDD and use a server side redirect or a cflocation redirect to the image file I believe it should work.
Cheers!
Comment 2 written by Raymond Camden on 14 September 2007, at 8:16 AM
Actually, I mentioned if you _start_ with a real file you are good. So yes - this is an alternative as well.
Comment 3 written by Lola LB on 14 September 2007, at 8:51 AM
http://www.coldfusionjedi.com/demos/imagecfcontent...!
Anyone who's been to a sheep & wool festival will see the absurdity and irony in that comment, considering who Paris Hilton is. ;-)
Comment 4 written by Lola LB on 14 September 2007, at 8:54 AM
Comment 5 written by Pablo Vos on 14 September 2007, at 8:56 AM
Comment 6 written by Pablo Vos on 14 September 2007, at 9:01 AM
Comment 7 written by Pablo Vos on 14 September 2007, at 9:03 AM
Comment 8 written by Gary Gilbert on 14 September 2007, at 9:26 AM
"Did you know they named a city after me" LMFAO awesome!
Comment 9 written by Pablo Vos on 14 September 2007, at 10:15 AM
Comment 10 written by Jeff on 14 September 2007, at 10:34 AM
Comment 11 written by Raymond Camden on 14 September 2007, at 10:38 AM
As far as I know, the no way to "measure" your text. Let me kick some people around and see if I can get any info on that.
Comment 12 written by Jeff on 14 September 2007, at 10:47 AM
Comment 13 written by Mat Evans on 14 September 2007, at 10:53 AM
http://www.coldfusionjedi.com/demos/imagecfcontent... me! I'm trapped in your computer!
http://www.coldfusionjedi.com/demos/imagecfcontent... I do look pretty fine in here
(to be viewed one after the other) ;)
enjoy..
Comment 14 written by Mat Evans on 14 September 2007, at 10:54 AM
i feel silly now :)
Comment 15 written by Pablo Vos on 14 September 2007, at 11:00 AM
Comment 16 written by Pablo Vos on 14 September 2007, at 11:02 AM
Let's try again: http://www.coldfusionjedi.com/demos/imagecfcontent......?
Comment 17 written by Pablo Vos on 14 September 2007, at 11:04 AM
Comment 18 written by Pablo Vos on 14 September 2007, at 11:04 AM
http://www.coldfusionjedi.com/demos/imagecfcontent...
Comment 19 written by Raymond Camden on 14 September 2007, at 11:08 AM
Comment 20 written by Rupesh kumar on 14 September 2007, at 11:10 AM
I know you don't like using undocumented features :-)
But here is something very simple you can use which will work in all the cases. You can use getImageBytes() method on image object.
<cfset canvas = imageNew("", 100, 100, "rgb", "red")>
<cfset bytes = canvas.getImageBytes("jpg")>
<cfcontent type="image/jpg" variable="#bytes#">
Cheers !
Rupesh.
Comment 21 written by Raymond Camden on 14 September 2007, at 11:13 AM
Rupesh - I didn't get a chance to file a ER. I'll do so now.
Comment 22 written by JC on 14 September 2007, at 11:44 AM
Comment 23 written by Chris on 14 September 2007, at 12:07 PM
Comment 24 written by CeeVee on 14 September 2007, at 12:48 PM
Comment 25 written by CeeVee on 14 September 2007, at 12:49 PM
Comment 26 written by West on 14 September 2007, at 3:36 PM
Comment 27 written by TJ Downes on 16 September 2007, at 8:01 AM
Comment 28 written by Dan Wilson on 16 September 2007, at 8:18 AM
www.coldfusionjedi.com/demos/imagecfcontent/test3....
Comment 29 written by Dan Wilson on 16 September 2007, at 8:37 AM
Here is the above link in tiny form.
http://tinyurl.com/34qs3u
Comment 30 written by Raymond Camden on 16 September 2007, at 10:19 AM
Comment 31 written by George Bridgeman on 17 September 2007, at 4:42 AM
Regarding the text measuring... there's no way in CF8 to do it natively but you can write a few lines of Java code to do it for you and call that from your CF code. I wrote a Font CFC to do this, as well as determining whether or not text will fit in a given rect size, etc. It doesn't reformat the text to fit inside a rect (it's on the TODO list) but it's quite accurate and supports different font families, sizes and styles.
Once I get home this evening I can upload it someplace and give the URL here if you're interested. The code is still pretty dirty as it's still in development, but it works.
George.
Comment 32 written by Raymond Camden on 17 September 2007, at 8:45 AM
Comment 33 written by George Bridgeman on 17 September 2007, at 2:31 PM
http://homepage.mac.com/georgebridgeman/FontUtil.c...
I'll finish it off if I get some time. You should be able to get the jist of it though, even though it's quite mucky.
Comment 34 written by Phil on 19 July 2008, at 5:10 AM
<cfcontent type="image/jpg" variable="#imageGetBlob(myimage)#">
the quality of the rendered image is quite bad. Is there any way on how to render a image with a better quality?
Comment 35 written by TJ Downes on 28 March 2009, at 12:36 PM
[Add Comment] [Subscribe to Comments]