More Batik Goodness

Last October I posted about using ColdFusion and Batik together to convert dynamically generated SVG content into PNGs for easier consumption. Well thanks to a little more digging and a post by Christian Cantrell, I've improved upon it further.

<cfscript>
  context = getPageContext();
  context.setFlushOutput(false);
  response = context.getResponse().getResponse();
  response.setContentType("image/png");
  transcoder = createObject("java", "org.apache.batik.transcoder.image.PNGTranscoder").init();
  inputStream = createObject("java", "java.io.StringBufferInputStream").init(svg);
  input = createObject("java", "org.apache.batik.transcoder.TranscoderInput").init(inputStream);
  outputStream = response.getOutputStream();
  output = createObject("java", "org.apache.batik.transcoder.TranscoderOutput").init(outputStream);
  transcoder.transcode(input, output);
  output.close();
</cfscript>

The primary difference here is that your SVG content comes from a string (rather than a file), and the PNG content will be sent directly to the browser, rather than stored in a file. If you're operating on files, not much benefit, but if you're generating your SVG on-the-fly every request and sending it directly out, cutting out all the filesystem access (four separate trips) can be a nice benefit.

As before, you need a full installation of Batik (WEB-INF/lib is a good place for it), and if you're on CF7, you'll need to remove the partial install in WEB-INF/cfform/jars as well.

3 Responses to “More Batik Goodness”


  1. 1 Jim Collins

    Nice work Barney. I'm assuming that that output method could be used to send anything to the browser not just a PNG image?

  2. 2 Barney

    Jim,

    Absolutely. With a file you just use CFCONTENT, but if your data is anywhere else (memory, database) you can use the response's OutputStream to write it directly. You could even use it to send back a string of HTML if you wanted, but CF provides much nicer ways for doing that (like CFOUTPUT).

    Note that in my example, I'm not actually writing to the OutputStream (as Christian's example showed), I'm just wrapping it up and letting the PNGTranscoder write to it for me. I could have used a ByteArrayOutputStream for the PNGTranscoder's destination, and then extracted the byte array and passed it to the response's OutputStream to achieve the same effect, but doing it as I did saves an extra buffering.

  3. 3 Jim Collins

    I'm doing something similar with SAX but your solution is much more elegant that the kludge I hacked together :)

Leave a Reply