This isn't as cool as perhaps it sounds, but it's kind of neat! For project Skin Spider, I had to add an age verification page. This is ONLY for the demo - I don't plan on using it in the final application. Because of this, I don't want images on it to have to be stored in the standard file system. This makes the page extremely modular so that I can just drop it in and not worry about taking it out later.
To make this happen, all you have to do is put a test on the page to see WHY you are hitting the page. If you are hitting it for the HTML, then return the HTML. If, however, you are hitting it for an image, return the binary image data. Once you have this set up, all you have to do is point any image source values right back at the page.
<!--- Param the URL variables. ---> <cfparam name="URL.image" type="string" default="" /> <!--- Check to see if we have an image to return. ---> <cfif NOT CompareNoCase( URL.image, "background" )> <!--- Set the image data. We have stored the image data as Base64 encoded binary data. We did this by sending the binary data to BinaryEncode() passing in Base64 as the encoding. ---> <cfset strImageData = ( "R0lGODlhBAAEAIAAADMzMwAAACH5BAAHAP8ALAAA" & "AAAEAAQAAAIFRI4WqgUAOw==" ) /> <!--- Set the content. Since we need to be very carefule about returning proper data, be sure to RESET the content buffer (reset="true"). Since we stored the data in Base64 format, when we write it to the content stream, we have to decode it first. ---> <cfcontent type="image/gif" variable="#BinaryDecode( strImageData, 'Base64' )#" reset="true" /> <cfelse> <!--- We are hitting the page to get the HTML. ---> <cfoutput> <html> <head> <title>Embedded Images Using ColdFusion</title> </head> <body <!--- Notice the URL for the background image. It's calling itself (index.cfm). ---> background="#CGI.script_name#?image=background" > Isn't ColdFusion The Coolest?!? </body> </html> </cfoutput> </cfif>
Notice the URL for the background image? It points right back at the CGI.script_name value; right back at itself. The only difference is that it is sending a request for an image (image=background). This forces the page to return an image, not the HTML content.
Now, we are using the CFContent tag attribute "variable" to write the binary data. This is only available in ColdFusion MX 7. If you are using ColdFusion MX 6, it gets a bit more tricky. Now, I am not 100% sure on this, but I think you need to write the binary data to the page's byte output stream. You can get this buried under the page context. So, if you are running MX 6, you can replace the CFContent tag above with this code:
<!--- Get the Page Context. ---> <cfset objPageContext = GetPageContext() /> <!--- Get the page output stream. We want the BYTE output stream, not the character output stream. Therefore we need to call GetResponse() TWICE from the page context. This will give us the byte stream???? ---> <cfset objResponse = objPageContext.GetResponse( ).GetResponse() /> <!--- From the page response, we need to get the output stream. This will give us the Byte output stream to which we can write binary data. ---> <cfset objPageOutputStream = objResponse.GetOutputStream() /> <!--- Set the content type and reset the buffer. Then, without any white space, we have to write the binary data to the output stream. This WRITE method is a bit tricky. The first argument is the binary data itself. The second argument is the offset of the output buffer to read from. Since we want to get ALL the binary data, start at the begining of the buffer (offset zero). Then, the third argument is the length of the binary byte array. In this case, we want all of it, so return the LEN() of the array. Not 100% sure why Len() works... but it seems to. ---> <cfcontent type="image/gif" reset="true" /><cfset objPageOutputStream.Write( BinaryDecode( strImageData, 'Base64' ), JavaCast( "int", 0 ), JavaCast( "int", Len( BinaryDecode( strImageData, 'Base64' ) ) ) ) /> <!--- Flush the output stream buffer. ---> <cfset objPageOutputStream.Flush() /> <!--- Close the output stream. ---> <cfset objPageOutputStream.Close() />
So, that's the MX 6 way of doing it. Not 100% how it all works. I kind of pieced it together until it worked. I don't want to give too much MISinformation, so I am not going to try an explain it too thoroughly.
Want to use code from this post? Check out the license.