I have been trying to get ColdFusion to write binary data (image bytes) out to my browser on and off for the last couple of weeks using several different techniques. Thanks to some internal help, this morning, I finally got it.
The idea is that I want to take a byte array and write it directly to the output stream between the server and client and have the image render properly in the browser. That means the data and the output stream can’t be at all corrupted by whitespace, new lines or line returns like it can be if you are only sending back text. The following code illustrates how to get this to work:
<cffile action="readbinary" file="/home/cantrell/Pictures/Corrs2.jpg" variable="pic"/><cfscript>context = getPageContext();context.setFlushOutput(false);response = context.getResponse().getResponse();out = response.getOutputStream();response.setContentType("image/jpeg");response.setContentLength(arrayLen(pic));out.write(pic);out.flush();out.close();</cfscript>
It wasn’t the process of writing a byte array to the output stream that had me stumped for so long. My problem was that I wasn’t getting my hands on the right output stream, or more specifically, the right response. Notice this line:
response = context.getResponse().getResponse();
I was only calling getResponse() once, which returned a response object with an output stream that would always corrupt binary data because it was always expecting character data. By calling getResponse() twice, I am able to get to the underlying output stream which I can use to write bytes with no problems.
So why do something like this? If all I wanted to do is essentially move a binary file from disk to the client, I would use the cfcontent tag, but what if the file doesn’t exist on disk? What if the image is in the database, or you got the bytes from a URL? The only way (as far as I know) to send the bytes to a client without creating a temporary file is using the technique above.
I should point out that this is not an officially supported technique. Use it at your own risk, and encapsulate it well so that if it doesn’t work in future versions of CFMX, you can fix it easily.