Convert a 24 bit in memory image to indexed color

空扰寡人 提交于 2019-12-14 02:12:42

问题


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?


回答1:


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 !




回答2:


You can do this with nQuant (which you can install with nuget, or see references below). The following example converts an image on disk and would be readily adapted to meet your needs.

    public static bool TryNQuantify(string inputFilename, string outputFilename)
    {
        var quantizer = new nQuant.WuQuantizer();
        var bitmap = new Bitmap(inputFilename);
        if (bitmap.PixelFormat != System.Drawing.Imaging.PixelFormat.Format32bppArgb)
        {
            ConvertTo32bppAndDisposeOriginal(ref bitmap);
        }

        try
        {
            using (var quantized = quantizer.QuantizeImage(bitmap))
            {
                quantized.Save(outputFilename, System.Drawing.Imaging.ImageFormat.Png);
            }
        }
        catch
        {
            return false;
        }
        finally
        {
            bitmap.Dispose();
        }
        return true;
    }

    private static void ConvertTo32bppAndDisposeOriginal(ref Bitmap img)
    {
        var bmp = new Bitmap(img.Width, img.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
        using (var gr = Graphics.FromImage(bmp))
            gr.DrawImage(img, new Rectangle(0, 0, img.Width, img.Height));
        img.Dispose();
        img = bmp;
    }

For more information see:

  • http://nquant.codeplex.com/
  • https://code.msdn.microsoft.com/windowsdesktop/Convert-32-bit-PNGs-to-81ef8c81



回答3:


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



来源:https://stackoverflow.com/questions/727987/convert-a-24-bit-in-memory-image-to-indexed-color

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!