views:

531

answers:

3

I am currently using javax.imageio.ImageIO to write a PNG file. I would like to include a tEXt chunk (and indeed any of the chunks listed here), but can see no means of doing so.

By the looks of com.sun.imageio.plugins.png.PNGMetadata it should be possible.

I should be most grateful for any clues or answers.

M.

A: 

Try the Sixlegs Java PNG library (http://sixlegs.com/software/png/). It claims to have support for all chunk types and does private chunk handling.

lothar
+1  A: 

The solution I struck upon after some decompilation, goes as follows ...

RenderedImage image = getMyImage();   
Iterator<ImageWriter> iterator = ImageIO.getImageWritersBySuffix( "png" );

if(!iterator.hasNext()) throw new Error( "No image writer for PNG" );

ImageWriter imagewriter = iterator.next();
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
imagewriter.setOutput( ImageIO.createImageOutputStream( bytes ) );

// Create & populate metadata
PNGMetadata metadata = new PNGMetadata();
metadata.tEXt_keyword.add( "MandelbrotCoords" );
metadata.tEXt_text.add( fractal.getCoords().toString() );//   

// Render the PNG to memory
IIOImage iioImage = new IIOImage( image, null, null );
iioImage.setMetadata( metadata ); // Attach the metadata
imagewriter.write( null, iioImage, null );
Martin Cowie
A: 

We do this in the JGraphX project. Download the source code and have a look in the com.mxgraph.util.png package, there you'll find three classes for encoding that we copied from the Apache Batik sources. An example of usage is in com.mxgraph.examples.swing.editor.EditorActions in the saveXmlPng method. Slightly edited the code looks like:

mxPngEncodeParam param = mxPngEncodeParam
  .getDefaultEncodeParam(image);
param.setCompressedText(new String[] { "mxGraphModel", xml });

// Saves as a PNG file
FileOutputStream outputStream = new FileOutputStream(new File(
  filename));
try
{
 mxPngImageEncoder encoder = new mxPngImageEncoder(outputStream,
   param);

 if (image != null)
 {
  encoder.encode(image);
 }
}
finally
{
 outputStream.close();
}

Where image is the BufferedImage that will form the .PNG and xml is the string we wish to place in the iTxt section. "mxGraphModel" is the key for that xml string (the section comprises some number of key/value pairs), obviously you replace that with your key.

Also under com.mxgraph.util.png we've written a really simple class that extracts the iTxt without processing the whole image. You could apply the same idea for the tEXt chunk using mxPngEncodeParam.setText instead of setCompressedText(), but the compressed text section does allow for considerable larger text sections.

David