views:

954

answers:

2

I have an image that I have created in memory as Format24bppRgb.

I save this as a PNG and it is 24kb.

If I save the same image with photoshop as a 24bit PNG it comes to about the same size, but if i save it as an 8bit PNG with only 32 colors it goes down to 5kb.

How can I create an indexed version of a PNG file using C# / GDI+ / System.Drawing ?

I'm having a hard time finding any answers to this question that don't just apply to grayscale images or require an external library. is it not possible within GDI+ as is?

A: 

You're trying to convert 16777216 colors down to 32. This is a non-trivial problem, and there are many ways to do it, all of which have their plusses and minuses. It's not something you often need to do, especially since full color displays became ubiquitous.

This Microsoft article has some information about GIF files that should be relevant to PNG also.

http://support.microsoft.com/default.aspx?scid=kb;EN-US;Q319061

Mark Ransom
but Photoshop makes it look so easy :-) i'm looking at FreeImage.NET right now
Simon_Weaver
+2  A: 

I ended up using the FreeImageAPI DLL, with a C# wrapper. I try to avoid 3rd party libraries but I don't think there is any other choice. It seems a pretty standard and well used library.

In my case I have an System.Drawing.Image object 'image' that was dynamically created - which I want to save to the HttpContext output stream as a compressed image. Note that Image does not have the needed GetHbitmap() method, but Bitmap does.

// convert image to a 'FreeImageAPI' image
var fiBitmap = FreeImageAPI.FreeImageBitmap.FromHbitmap((image as Bitmap).GetHbitmap());
fiBitmap.ConvertColorDepth(FreeImageAPI.FREE_IMAGE_COLOR_DEPTH.FICD_08_BPP);

// see http://stackoverflow.com/questions/582766
MemoryStream ms = new MemoryStream();
fiBitmap.Save(ms, FreeImageAPI.FREE_IMAGE_FORMAT.FIF_PNG, FreeImageAPI.FREE_IMAGE_SAVE_FLAGS.PNG_Z_BEST_COMPRESSION);
context.HttpContext.Response.OutputStream.Write(ms.ToArray(), 0, (int)ms.Length);

My 24kb bitmap is now only 9kb :-)

Tip: Be sure to have both 'FreeImageNET' AND 'FreeImage' dlls available in your bin when you run it. At the current time the C# sample projects contain a reference to 'Library.DLL' which doesn't seem to exist in their zip file. Using FreeImageNET.dll and FreeImage.dll works though. You'll get an annoying file not found error if you don't realize that FreeImageNet != FreeImage !

Simon_Weaver