将24位内存映像转换为索引颜色

时间:2009-04-07 23:28:35

标签: .net gdi+ system.drawing

我在内存中创建的图像为Format24bppRgb。

我将其保存为PNG,它是24kb。

如果我用photoshop将相同的图像保存为24位PNG,它的大小大致相同,但如果我将其保存为只有32种颜色的8位PNG,则会降至5kb。

如何使用C#/ GDI + / System.Drawing创建PNG文件的索引版本?

我很难找到这个问题的任何答案,这些答案不仅适用于灰度图像或需要外部库。在GDI +中是不可能的呢?

3 个答案:

答案 0 :(得分:2)

我最终使用了FreeImageAPI DLL和一个C#包装器。我尽量避免使用第三方库,但我认为没有其他选择。它似乎是一个非常标准和使用良好的库。

在我的情况下,我有一个动态创建的System.Drawing.Image对象'image' - 我希望将其作为压缩图像保存到HttpContext输出流中。请注意,Image没有所需的GetHbitmap()方法,但Bitmap有。

// 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);

我的24kb位图现在只有9kb: - )

提示:运行时,请务必在bin中同时提供“FreeImageNET”和“FreeImage”dll。目前,C#示例项目包含对“Library.DLL”的引用,它们的zip文件似乎不存在。使用FreeImageNET.dllFreeImage.dll可以正常工作。如果你没有意识到FreeImageNet!= FreeImage,你会得到一个恼人的文件找不到错误!

答案 1 :(得分:1)

您可以使用 nQuant (您可以使用nuget安装,或参阅下面的参考资料)执行此操作。以下示例转换磁盘上的图像,并且可以很容易地进行调整以满足您的需求。

    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;
    }

有关详细信息,请参阅:

答案 2 :(得分:0)

你试图将16777216种颜色转换为32.这是一个非常重要的问题,有许多方法可以做到,所有这些都有其优点和缺点。这不是你经常需要做的事情,特别是因为全彩显示器无处不在。

这篇Microsoft文章提供了一些与PNG相关的GIF文件信息。

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