C#将32bpp图像转换为8bpp

时间:2011-06-15 08:45:06

标签: c# .net windows image

我正在尝试使用C#将32bpp屏幕截图图像转换为8bpp(或4bpp或1bpp)格式。我已经查看了类似主题的几个stackoverflow答案,大多数使用以下代码建议变体:

public static Bitmap Convert(Bitmap oldbmp) 
{
    Bitmap newbmp = new Bitmap(oldbmp.Width, oldbmp.Height, PixelFormat.Format8bppIndexed);

    Graphics gr = Graphics.FromImage(newbmp);

    gr.PageUnit = GraphicsUnit.Pixel;
    gr.DrawImageUnscaled(oldbmp, 0, 0);

    return newbmp;
}

然而,当执行此操作时,我得到一个例外:A graphics object cannot be created from an image that has an indexed pixel format。据我所知,8,4和1bpp图像有颜色表映射而不是实际颜色像素本身(如32或16bpp图像),所以我假设我在某个地方缺少一些转换步骤,但我对C#相当新(即将到来)从C ++背景而言,并希望能够使用本机C#调用而不是诉诸PInvoking BitBltGetDIBits等。任何人都能帮我解决这个问题吗?感谢。

编辑:我应该指出,我需要它向后兼容.NET framework 2.0

4 个答案:

答案 0 :(得分:16)

GDI +通常对索引像素格式的支持非常差。没有简单的方法可以将65536或1600万种颜色的图像转换为只有2种,16种或256种颜色的图像。必须从源图像中删除颜色,这是一种可能导致非常差的结果的有损转换。有多种算法可以实现这一点,它们都不适用于各种图像。这是图形编辑器的工作。

我找到了一个技巧。 GDI +有一个用于GIF文件的图像编码器。这是一种只有256种颜色的图形格式,编码器必须限制颜色数量。它使用适合照片的抖动算法。它确实具有生成网格图案的诀窍,当它发生时你会感到非常激动。像这样使用它:

public static Image Convert(Bitmap oldbmp) {
    using (var ms = new MemoryStream()) {
        oldbmp.Save(ms, ImageFormat.Gif);
        ms.Position = 0;
        return Image.FromStream(ms);
    }
}

返回的图像具有8bpp像素格式,其中Palette条目由编码器计算。如有必要,您可以将其强制转换为位图。到目前为止,最好的办法是不要轻易使用索引格式。当记忆严重受限时,它们可以追溯到计算的石器时代。或使用专业的图形编辑器。

答案 1 :(得分:7)

AForge库使用Grayscale完美地完成了这项工作。

var bmp8bpp = Grayscale.CommonAlgorithms.BT709.Apply(bmp);
  

此类是图像灰度的基类[...]   过滤器接受24,32,48和64 bpp彩色图像,并产生8   (如果源是24或32 bpp图像)或16(如果源是48或64 bpp   image)bpp灰度图像。

答案 2 :(得分:1)

负步幅表示图像是自下而上(倒置)。如果你不在乎,只要使用步幅的绝对。我知道这适用于24bpp图像,如果它适用于其他人,则不知道。

答案 3 :(得分:-1)

您可以在PresentationCore程序集中使用System.Windows.Media.Imaging查看here以获取更多信息