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

C#将32bpp图像转换为8bpp,c#,.net,windows,image,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 = G

我正在尝试使用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;
}
但是,当执行此操作时,我得到一个异常:
无法从具有索引像素格式的图像创建图形对象
。我知道8, 4和1BPP图像有颜色表映射而不是实际的彩色像素本身(如32或16BPP图像),所以我假设我在某些地方缺少一些转换步骤,但是对于C(来自C++背景),我是相当新的。并且更愿意使用本机C#调用来实现这一点,而不是求助于PInvoking
BitBlt
GetDIBits
等。有人能帮我解决这个问题吗?谢谢


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

一般来说,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像素格式,其中调色板条目由编码器计算。如有必要,可以将其转换为位图。到目前为止,最好的办法就是不要麻烦使用索引格式。它们可以追溯到石器时代的计算机时代,当时内存受到严重限制。或者使用专业的图形编辑器。

您可以在PresentationCore Assembly中使用System.Windows.Media.Imaging查看更多信息

负跨距表示图像为自下而上(倒置)。如果你不在乎,就用绝对的步幅。我知道它适用于24bpp图像,但不知道它是否适用于其他图像。

库使用它做得非常完美

此类是图像灰度缩放的基类[…] 该过滤器接受24、32、48和64 bpp彩色图像,并生成8个bpp (如果源为24或32 bpp映像)或16(如果源为48或64 bpp映像) 图像)bpp灰度图像


谢谢,我应该指出解决方案需要与.NETFramework2.0向后兼容-我编辑了我的问题以反映这一点this@Don您可以始终使用
web.archive.org
搜索旧链接。太好了,谢谢。顺便说一句,的代码还描述了一种实现我想要的东西的方法,尽管有一定程度的PInvoke。我认为最好的解决方案是使用EmguCV(opencv包装器)。“到目前为止,最好的办法就是不去麻烦索引格式。它们可以追溯到石器时代的计算时代,当时内存受到严重限制。”这一切都很好,但当您编写一个程序来处理目标(如手持控制台或智能手表)的图形时,如果视频内存仍然很高,该怎么办?您不必担心,GDI+在此类设备上不可用。谢谢!无论如何,我需要为一个精明的边缘检测器做这件事;不知道它是内置的:)
var bmp8bpp = Grayscale.CommonAlgorithms.BT709.Apply(bmp);