Coldfusion + JPEGCodec + response.getOutputStream() = BAD

Time for me to admit I was wrong…

All the time I’ve been getting ColdFusion errors stating that the server cannot support any more connections… it wasn’t the server, it was some code I had written.

I’m still not sure of the why it caused the problems that it did, but it certainly did.

The issue at hand was my Captcha images that i was generating on the fly.

The idea was I would generate a BufferedImage , draw all my stuff on it,  grab the HttpServletResponse OutputStream from the getPageContext() and then use the com.sun.image.codec.jpeg.JPEGCodec to encode said OutputStream to my captcha.

In theory this should all work like a charm.

Except for one very irritating thing. It doesn’t. 

Occasionally when multiple requests go for the JpegEncoder, ColdFusion decides to go totally belly up. Not even in a nice error message way, nope, in a ‘Oh my G-d, I’ve totally dropped my &%$#’ way.

It even got to the point where it was dropping out the whole server.

The way I have gotten around it now, is by writing the image to a file, and every so often replacing it with a new Captcha image and text.  It seems to be working very nicely, and with some locking, ensures that it should only get hit one at a time.

So, in the future, I highly recommend not encoding the OutputStream of the HttpServletResponse – write it to a file, and access it that way.

Leave a Comment

Comments

  • Mike Kelp | January 12, 2006

    Is there a reason you do not simply output the jpeg image data with cfcontent and the necessary header values?

    If you have already been through this solution I would like to know of any issues you had.

    Glad you got your problems fixed though.

    Mike.

  • Mark | January 12, 2006

    Mike –
    Woah.
    I totally didn’t think of that.

    I just tested it out, and pushing the image out to a java.io.ByteArrayOutputputStream, and then passing the resulting .toByteArray to the ‘variable’ attribute in cfcontent works perfectly.

    Now I’m debating whether or not I want to change my code back, (the image is less processor intensive) but regardless, that is really good to know.

    *blushes as he feels a little silly now*

  • Mike Kelp | January 12, 2006

    I think you have come up with a good solution with the file write. Doesn’t need to be updated every request for your particular purpose. The benefit cfcontent sometimes offers in this case is you could make changing the URL of the image dynamically while keeping the same actual file name that cf reads and returns.

    Good work though. I have been wanting to play with some of the Java imaging stuff myself lately or make an extension for CF that can use the ImageMagick (C++ library) to process images on linux.

  • Java Newbie | May 19, 2006

    Mark – Thanks for the great info. How exactly do you "push the image out to a java.io.ByteArrayOutputputStream"?

    I am trying:
    imgObj = CreateObject("java", "java.awt.image.BufferedImage");
    baos = CreateObject("java", "java.io.ByteArrayOutputStream");
    imgio=CreateObject("java", "javax.imageio.ImageIO");
    imgio.write(imgObj, "JPG", baos);

    the last line of that is giving me errors: "The selected method write was not found."

    Any ideas?

  • Java Newbie | May 19, 2006

    I got it!
    the second line above should read:
    baos = CreateObject("java", "java.io.ByteArrayOutputStream").init();

    forgot to initialize the stream!

  • Denny | August 28, 2006

    Hey Mark, no need to blush, I did the same thing (tried using the http response to dump an outStream) but was having some trouble calling it from a cfc… when I switched to a "normal" outStream and used cfdocument’s variable attribute, it worked like a charm.

    Just wanted to say thanks to Mike for offering the suggestion, since if I hadn’t randomly come across it I might still be struggling.

    Woot! Thanks guys!