Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you write a image to browser as a binary stream in coldfusion?

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?

like image 629
boodle Avatar asked Apr 12 '11 14:04

boodle


4 Answers

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")

like image 199
Adam Tuttle Avatar answered Nov 07 '22 06:11

Adam Tuttle


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.

like image 6
Mike Causer Avatar answered Nov 07 '22 06:11

Mike Causer


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!

like image 4
Ross Taylor Avatar answered Nov 07 '22 07:11

Ross Taylor


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" />
like image 3
Matt Shooks Avatar answered Nov 07 '22 06:11

Matt Shooks