【问题标题】:Convert a 24 bit in memory image to indexed color将内存图像中的 24 位转换为索引颜色
【发布时间】:2009-04-07 23:28:34
【问题描述】:

我在内存中创建了一个图像,格式为 Format24bppRgb。

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

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

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

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

【问题讨论】:

    标签: .net gdi+ system.drawing


    【解决方案1】:

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

    就我而言,我有一个动态创建的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 !

    【讨论】:

    • 如何在windows 7 64位上安装?
    • 小心使用 bitmap.GetHbitmap()。您必须手动释放该内存,否则它会泄漏。 1. [DllImport("gdi32.dll")] private static extern bool DeleteObject(IntPtr hObject); 2. IntPtr hBitmap = bitmap.GetHbitmap(); 3. FreeImageBitmap freeImageBitmap = FreeImageBitmap.FromHbitmap(hBitmap); 4.(做事) 5. DeleteObject(hBitmap);
    【解决方案2】:

    您可以使用 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;
        }
    

    欲了解更多信息,请参阅:

    【讨论】:

    • 如果您想要一个不是 1 位通道的 Alpha 通道,这很好。你会得到一个类似于 tinypng.com 给你的带有 alpha 的 8 位图像。但请注意,它很慢
    • 这对我来说效果很好,但重要的是要注意,当我处理高度大于 4550 像素的图像时,它无法生成图像并且输出是一个空的灰色图像。
    【解决方案3】:

    您正在尝试将 16777216 种颜色转换为 32 种颜色。这是一个非常重要的问题,并且有很多方法可以做到这一点,所有这些方法都有其优点和缺点。这不是您经常需要做的事情,尤其是在全彩色显示器变得无处不在的情况下。

    这篇 Microsoft 文章包含一些关于 GIF 文件的信息,这些信息也应该与 PNG 相关。

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

    【讨论】:

    • 但是 Photoshop 让它看起来很简单 :-) 我现在正在看 FreeImage.NET
    • 或者图像可能有 32 种颜色,在这种情况下你不会丢失任何东西。
    猜你喜欢
    • 2016-01-25
    • 2022-11-25
    • 1970-01-01
    • 2014-12-01
    • 1970-01-01
    • 2020-09-09
    • 2012-07-17
    • 2011-07-10
    • 1970-01-01
    相关资源
    最近更新 更多