I have a service on a Coldfusion 9 server that creates image banners on the fly for us. A separate machine has to save these files with something like:
wget http://myserver.com/services/local/bannerCreator/250x250-v3.cfm?prodID=3&percentSaving=19
The problem is that I can't think of how to get coldfusion to write out binary data without using a temporary file. At the minute the image is just displayed as an image tag like this:
<cfimage action = "writeToBrowser" source="#banner#" width="#banner.width#" height="#banner.height#" />
Any ideas? Or should I just use a temporary file?
I can't test because you're not giving any example code for how your images are generated, but have you tried something along this line?
<cfcontent reset="true" variable="#imageData#" type="image/jpg" />
Update: So I went ahead and created my own image; I'll assume you're doing something similar. This works perfectly for me:
<cfset img = imageNew("",200,200,"rgb","red") />
<cfcontent variable="#toBinary(toBase64(img))#" type="image/png" reset="true" />
This works without writing to file, and without using a virtual file system ("ramdisk")
If you have the binary bytes of an file/image, you can replace the output buffer with it's contents like so:
<cfscript>
// eg. this is how you get a file as a binary stream
// var fileBytes = fileReadBinary( '/path/to/your/file.jpg' );
// get the http response
var response = getPageContext().getFusionContext().getResponse();
// set the appropriate mime type
response.setHeader( 'Content-Type', 'image/jpg' );
// replace the output stream contents with the binary
response.getOutputStream().writeThrough( fileBytes );
// leave immediately to ensure no whitespace is added
abort;
</cfscript>
Pretty much what <cfcontent>
does when you use reset="true"
The advantage of this method over <cfcontent>
is that we can write it inside our cfscript based cfcs.
I found the solution above
<cfcontent variable="#toBinary(toBase64(img))#" type="image/png" reset="true" />
to not quite work for me.
Setting type="image/png" is just setting the mime type of the response. I don't think it's necessarily encoding the image as PNG. As such, generating a transparent png (image type "argb") was giving me odd colours, when compared to the <cfimage action = "writeToBrowser"...>
method.
I figured that somehow I needed to explicitly encode the image data as PNG and output the binary data directly.
With some digging around in the underlying java, I came up with this, which so far seems to work for me.
This example draws a transparent png with a black circle.
<!--- create the image and draw it --->
<cfset img = ImageNew("", 23, 23, "argb")>
<cfset ImageSetDrawingColor(img, "black")>
<cfset ImageDrawOval(img, 0, 0, 21, 21, true)>
<!--- get the response object --->
<cfset response = getPageContext().getFusionContext().getResponse()>
<!--- set the response mime type --->
<cfset response.setHeader('Content-Type', 'image/png')>
<!--- get the underlying image data --->
<cfset bImage = ImageGetBufferedImage(img)>
<!--- get the magical object to do the png encoding --->
<cfset ImageIO = createObject("java", "javax.imageio.ImageIO")>
<!--- encode the image data as png and write it directly to the response stream --->
<cfset ImageIO.write(bImage, "png", response.getResponse().getOutputStream())>
I hope that helps someone!
Take out the height and width attributes and add the format attribute:
<cfimage action = "writeToBrowser" source="#banner#" format="png" />
wget should honor the redirection to the physical file CF creates in the CFFileServlet folder but if it doesn't there is a flag you can set to make it --max-redirect=10
.
And as you suggest, a temporary file would work too. Just write the file and use cfheader and cfcontent to write it out. Just make sure to make the temp file name more unique.
<cfimage action="write" destination="tempfile.png" source="#banner#" format="png" />
<cfheader name="content-disposition" value="attachment; filename=banner.png" />
<cfcontent file="tempfile.png" deletefile="true" type="image/png" />
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With