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:
<img src="foo.cfm">
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:
<cfimage action="writeToBrowser" ...>
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:
<cfimage action="read" source="paris.jpg" name="paris">
<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:
<cfimage action="read" source="paris.jpg" name="paris">
<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:
<cfset canvas = imageNew("", 100, 100, "rgb", "white")>
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.
<cfparam name="url.caption" default="">
<cfajaxproxy bind="javascript:updImage({caption})">
<script>
function updImage(str) {
if(str != '') document.getElementById('myimg').src = 'imgs3.cfm?caption='+escape(str);
}
</script>
<h2>Paris-Talkometer</h2>
<cfform name="form">
<cfinput type="text" name="caption" value="#url.caption#" > <cfinput name="mybutton" type="button" value="Update"><br />
<cfinput type="image" name="myimage" src="imgs3.cfm?caption=#url.caption#" id="myimg">
</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:
<cfparam name="url.caption" default="">
<cfimage action="read" source="paris.jpg" name="paris">
<cfif len(trim(url.caption))>
<cfset imageSetDrawingColor(paris, "black")>
<cfset imageDrawRect(paris, 1, 1, paris.width, 40, true)>
<cfset imageSetAntialiasing(paris, "on")>
<cfset imageSetDrawingColor(paris, "white")>
<cfset text = { style='bold', size=12, font='verdana' }>
<cfset imageDrawText(paris, url.caption, 10, 25, text)>
</cfif>
<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.
Archived Comments
Ray,
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!
Hem - I believe I mentioned that - if you make it a real file, then it definitely works - but I was trying to be 100% virtual.
Actually, I mentioned if you _start_ with a real file you are good. So yes - this is an alternative as well.
Okay . . . here's my comment:
http://www.coldfusionjedi.c...
Anyone who's been to a sheep & wool festival will see the absurdity and irony in that comment, considering who Paris Hilton is. ;-)
Hmm . . . that exclamation mark _is_ supposed to be part of the comment . . .
http://www.coldfusionjedi.c...
http://www.coldfusionjedi.c...
I hope the last one is SFW... where I work it is ;-)
@Pablo
"Did you know they named a city after me" LMFAO awesome!
Thx, can't wait to see other posts...
Is there anything in the CFIMAGE arsenal of tools that will allow for a nice wrap when having LOOOooooong text??
No. I asked Adobe about this - but didn't get a response. (It was towards the endof the beta.)
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.
Thanks for looking into. As you can tell, I have paragraphs and paragraphs of information to write about regarding my hero, Paris :)
hehe, good competition..
http://www.coldfusionjedi.c... me! I'm trapped in your computer!
http://www.coldfusionjedi.c... I do look pretty fine in here
(to be viewed one after the other) ;)
enjoy..
grr.. sorry my bad.. assumed it would code the URLs
i feel silly now :)
http://www.coldfusionjedi.c...
@Raymond: your url parser sucks kinda...
Let's try again: http://www.coldfusionjedi.c...
http://www.coldfusionjedi.c...
@this url parser: GRRR!
http://www.coldfusionjedi.c...
If you want to avoid the URL Parser, remove the http from your url.
Ray,
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.
Nice!
Rupesh - I didn't get a chance to file a ER. I'll do so now.
http://www.coldfusionjedi.c... read two books in jail...the bible and CFWACK...and I found God
http://www.coldfusionjedi.c...
http://www.coldfusionjedi.c......
Ugh. Supposed to read, "That's Hot..."
http://www.coldfusionjedi.c...
http://tinyurl.com/2ltaxx
Heh
www.coldfusionjedi.com/demo...
As usual, TJ schools me:
Here is the above link in tiny form.
http://tinyurl.com/34qs3u
Tj - you know me too well. ;)
Ray,
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.
Sure - post the code. It does sound interesting.
I've put the code up here:
http://homepage.mac.com/geo...
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.
When serving the image with your code:
<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?
Ray, thanks for this. I know it's been a while since you posted it, but I had remember you posted it and easily found it via Google when I needed it. I was able to create a proof of concept in about 30 minutes, for a client, using the Flex-AJAX bridge to dynamic generate images based upon user feedback in my Flex app. thanks!