[cairo] Reducing PNG Image Size

Aron Rubin aron.rubin at lmco.com
Thu Sep 25 10:10:28 PDT 2008

Mohit Sindhwani wrote:
> Hi Carl & Vlad,
> Thanks for your replies!  I've spent the whole day looking around for 
> solutions to this and to see what can be done (learnt a lot about PNG 
> today!) and here is where I'm at right now.
> Carl Worth wrote:
>> On Wed, 2008-09-24 at 12:36 -0700, Vladimir Vukicevic wrote:
>>> pngcrush essentially runs the compression algorithm with different  
>>> settings for the various knobs (window size, etc., iirc), and then  
>>> picks whatever the best results are.  It does a really good job, but  
>>> it's an expensive process... you essentially end up recompressing the  
>>> image around a dozen times.
>> Ah, cool.
>> So games like that wouldn't make sense in cairo_surface_write_to_png at
>> all. But an application making its own calls into libpng could easily do
>> things like that.
>> And as Vlad would say, all applications *should* be doing their own
>> calls rather than using cairo_surface_write_to_png.
> Yes, PNGCrush can be used, but it would be a bit slow for the task that 
> I have in mind.
> Actually, the whole thing started with the fact that I didn't want to go 
> to pnglib directly and was wondering if PNG support in Cairo went beyond 
> just writing out the image surface to the file.  I've seen the source 
> and it seemed that it wouldn't do what I wanted, so just wanted to check.
> As it turns out, here is what I've learned and got to:
> [1] There are ways to compress PNG - the best way, as you mentioned, is 
> to quantize the colors.  What I had read was that at the same color 
> depth (8 bits), PNG does a better job than GIF.
> [2] Naturally, the image surface is a 24-bit or 32-bit surface.  As a 
> result, cairo_surface_write_to_png doesn't consider writing it as an 
> 8-bit color depth file even if there are less than 256 colors in the 
> image.  The files that it writes are grayscale or 32-bit.
> [3] It seems that the files produced by cairo_surface_write_to_png are, 
> however, larger (30%) than a PNG file with the same data and same number 
> of colors.  I saved the file to a PNG, opened it up in Microsoft Paint 
> and saved it as PNG.  The file size is smaller (1.7MB against 2.2MB).  I 
> found that using PNG crush in all its entirety cuts the file size by up 
> to 30% (in my case), using pngcrush with just "-m 1" is very fast and 
> cuts the size by about 25%.  I think there is still some extra data in 
> the default file.
> [4] To produce smaller size PNG files, quantization is necessary - if 
> your image data type supports it.  Currently, there is nothing in Cairo 
> that supports this.  After a lot of looking around, it seems that 
> CxImage [1] is quite a nice library - it looks like a fantastic add-on 
> to what Cairo does.  So far, we've been able to use the image_surface to 
> create a CxImage object and then quantize that down to 256 colors and 
> save the reduced image to BMP (PNG tomorrow, I hope).
> So, that's what I've learnt today.
> Just one question: in Cairo, is it easy to know how many unique colors 
> are used in an image?  If it's easy, it might be sensible to try 
> extending cairo_surface_write_to_png to check if the number of unique 
> colors in the image is below 256 and write it as a palette based image 
> that would be much smaller (about 25% of the size of the original).
> Thanks for all the help.  The time difference between my day (Singapore) 
> and yours (US) has given me enough time to look around at other things 
> and I think it's been useful.
> I'm enjoying Cairo, thanks :)

Just to add a couple of important points here. Current versions of PNG
uses the same compression as gzip which is not at all optimized for
image data. The strategy is to leverage a general purpose compression by
first transforming image data to something that compresses well with
that compression. The filters are that preprocessing (and post
processing after decompression). For example quantizing (without
dithering) the color values will be rather lossy for most photographic
image data, but quantizing adjacent pixel differences may not be very
lossy at all. Unfortunately the filters offered with current PNG are
lossless but they do a decent job of feeding gzip with a compressible form.

The other important note is I don't think cairo exposes the
unpremultiply alpha routine yet so you will want to grab that before you
start using libpng directly yourself.


More information about the cairo mailing list