You may have noticed that my pet-peeve du jour is the sorry state of PNG metadata. Right now I'm working in Actionscript 3, and the current crop of PNG encoders doesn't allow metadata.
These all require that the keys and values are in Latin1 (ISO-8859-1) as according to the PNG spec. The spec also requires that the key is 1-79 characters.
AS3CoreLib
The AS3CoreLibs project has a nice PNGEncoder. Here's the drop in replacement that supports metadata.
To use, you do something like this
var meta:Object = {Title: "A big cow", Copyright: "Oh yes"};
var enc:PngEncoder = new PngEncoder();
var bytes:ByteArray = enc.encode(data, meta);
Line by Line
For this patch I'll give a brief explanation on how it works. The other patches are very similar.
This writes out a tEXt chunk
/**
* write out metadata using Latin1, uncompressed
*
* @param png The output bytearray
* @param key the metadata key. Must be in latin1, between 1-79 characters
* @param value the metadata value. Must be in latin1.
*
* the key or value is null or violates some contraints, the metadata
* is silently not added
*/
private static function writeChunk_tEXt(png:ByteArray,
key:String, value:String):void
{
if (key == null || key.length == 0 || key.length > 79) {
return;
}
if (value == null) {
value = "";
}
// the spec says this should be latin1,
// but UTF8 is probably ok, but be care of overflows
var tEXt:ByteArray = new ByteArray();
tEXt.writeMultiByte(key, "iso-8859-1");
tEXt.writeByte(0x0);
tEXt.writeMultiByte(value, "iso-8859-1");
writeChunk(png, 0x74455874, tEXt);
}
Change the encode function to take an optional metadata object (a hash table of key, values)
public function encode(img:BitmapData, meta:Object = null):ByteArray {
Write the tEXt chunks between the IHDR and IDAT chunks
writeChunk(png,0x49484452,IHDR);
// should be before IDAT so ImageMagick can read it
for (var k:String in meta) {
writeChunk_tEXt(png, k, meta[k]);
}
// Build IDAT chunk
var IDAT:ByteArray= new ByteArray();
Ta - Da!
Better, Faster, PNGEncoder
Hey, it's a better, faster implementation. Besides being faster, it supports RBG or RGBA PNG formats which can save space as well. There is a rumour the improvements will be merged into AS3CoreLib.
The drop in replacement that supports metadata is here. It also cleaned up some warnings/errors spotted by the Flex3-Beta1 compiler and some other tidbits.
AsPngEncoder
There is one other PNG encoder, AsPngEncoder. It's notable since it support palete based PNG files, which can result in dramatic space savings. I got lazy and didn't hack this one. I'll leave it as an exercise for you to add meta data.
License
Hey kids, go nuts. These changes are in the public domain, so the original authors can integrate this without hassle. It would be swell if you gave me some credit (e.g. Thanks to: Nick Galbreath or so), but not required.
WARNING
Always save the best for last. I'm not a flash expert, really. Always check your application before deploying this to production. It's possible quite a few "check for nulls" can be rid of. I'm coming from C++ background and I'm paranoid. ha! Any tips are welcome.