[cairo] Reducing PNG Image Size

Mohit Sindhwani ml3p at onghu.com
Wed Sep 24 13:02:25 PDT 2008

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 :)

9/25/2008 | 4:00 AM.

[1] http://www.xdp.it/cximage.htm

More information about the cairo mailing list