Image::Pngslimmer - slims (dynamically created) PNGs
$ping = ispng($blob) #is this a PNG? $ping == 1 if it is $newblob = discard_noncritical($blob) #discard non critcal chunks and return a new PNG my @chunklist = analyze($blob) #get the chunklist as an array $newblob = zlibshrink($blob) #attempt to better compress the PNG $newblob = filter($blob) #apply adaptive filtering and then compress $newblob = indexcolours($blob) #attempt to replace RGB IDAT with palette (usually losslessly) $newblob = palettize($blob[, $colourlimit [, $dither]]) #replace RGB IDAT with colour index palette (usually lossy) \%colourhash = reportcolours($blob) #return details of the colours in the PNG
Image::Pngslimmer aims to cut down the size of PNGs. Users pass a PNG to various functions and a slimmer version is returned. Image::Pngslimmer was designed for use where PNGs are being generated on the fly and where size matters more than speed- eg for J2ME use or any similiar low speed or high latency environment. There are other options - probably better ones - for handling static PNGs, though you may still find the fuctions useful.
Filtering and recompressing an image is not fast - for example on a 4300 BogoMIPS box with 1G of memory the author processes PNGs at about 30KB per second.
Call Image::Pngslimmer::discard_noncritical($blob) on a stream of bytes (eg as created by Perl Magick's Image::Magick package) to remove sections of the PNG that are not essential for display.
Do not expect this to result in a big saving - the author suggests maybe 200 bytes is typical - but in an environment such as the backend of J2ME applications that may still be a worthwhile reduction.
Image::Pngslimmer::discard_noncritical($blob) will call ispng($blob) before attempting to manipulate the supplied stream of bytes - hopefully, therefore, avoiding the accidental mangling of JPEGs or other files. ispng checks for PNG definition conformity - it looks for a correct signature, an image header (IHDR) chunk in the right place, looks for (but does not check beyond the CRC) an image data (IDAT) chunk and checks there is an end (IEND) chunk in the right place. CRCs are also checked throughout.
Image::Pngslimmer::analyze($blob) is supplied for completeness and to aid debugging. It is not called by discard_noncritical but may be used to show 'before-and-after' to demonstrate the savings delivered by discard_noncritical.
Image::Pngslimmer::zlibshrink($blob) will attempt to better compress the supplied PNG and will achieve good results with poorly compressed PNGs.
Image::Pngsimmer::filter($blob) will attempt to apply adaptive filtering to the PNG - filtering should deliver better compression results (though the results can be mixed). Please note that filter() will compress the image with Z_BEST_SPEED and so the blob returned from the function may even be larger than the blob passed in. You must call zlibshrink if you want to recompress the blob at maximum level. All PNG compression and filtering is lossless.
Image::Pngslimmer::indexcolours($blob) will attempt to replace an RGB image with a colourmapped image. NB This is not the same as quantization - this process is lossless, but also only works if there are less than 256 colours in the image.
(indexcolours now supports PNGs with alpha channels but all alpha information is lost in the indexed PNG.)
Image::Pngslimmer::palettize($blob[, $colourlimit[, $dither]]) will replace a 24 bit RGB image with a colourmapped (256 or less colours) image. If the original image has less than $colourlimit colours it will do this by calling indexcolours and so losslessly (except for any alpha channel)process the image. More generally it will process the image using the lossy median cut algorithm. Currently this only works for 24 bit images, though now also supports the alpha channel (ie the alpha channel is accounted for in quantization - there is no alpha in the quantized image). Again this process is relatively slow - the author can process images at about 30 - 50KB per second - meaning it can be used for J2ME in "real time" but is likely to be too slow for many other dynamic uses. Setting $colourlimit between 1 and 255 allows control over the size of the generated palette (the default is 0 which generates a 256 colour palette). Setting $dither to 1 will turn on the much slower dithering. It is not recommended for anything that requires quick image display.
$hashref = Image::Pngslimmer::reportcolours($blob) will return a reference to a hash with a frequency table of the colours in the image.
This is free software and is licensed under the same terms as Perl itself ie Artistic and GPL
It is copyright (c) Adrian McMenamin, 2006, 2007, 2008
POSIX Compress::Zlib Compress::Raw::Zlib
To make Pngslimmer really useful it needs to handle a broader range of bit map depths etc. The work goes on and the range of PNG types supported is growing. But at the moment it really only works well with 24 bit images (though discard_noncritical will work with all PNGs).
Adrian McMenamin <adrian AT mcmen DOT demon DOT co DOT uk>