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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6355135/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 17:03:46  来源:igfitidea点击:

C# Converting 32bpp image to 8bpp

c#.netwindowsimage

提问by binarybob

I'm trying to convert a 32bpp screenshot image to an 8bpp (or 4bpp, or 1bpp) format using C#. I've already looked at several stackoverflow answers on similar subjects and most suggest variations using the following code:

我正在尝试使用 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;
}

However, when this executes, I get a the exception: A graphics object cannot be created from an image that has an indexed pixel format. I understand that 8, 4 and 1bpp images have colour table mappings rather than the actual colour pixels themselves (as in 32 or 16bpp images) so I assume I'm missing some conversion step somewhere, but I'm fairly new to C# (coming from a C++ background) and would prefer to be able do this using native C# calls rather than resorting to PInvoking BitBltand GetDIBitsetc. Anybody able to help me solve this? Thanks.

但是,当它执行时,我得到一个异常:A graphics object cannot be created from an image that has an indexed pixel format. 我知道 8、4 和 1bpp 图像具有颜色表映射而不是实际颜色像素本身(如在 32 或 16bpp 图像中)所以我假设我在某处缺少一些转换步骤,但我对 C# 相当陌生(即将从C ++背景),并希望能够做到这一点使用原生C#调用,而不是诉诸PInvokingBitBltGetDIBits等任何人能帮助我解决这个问题?谢谢。

EDIT: I should point out that I need this to be backwardly compatible to .NET framework 2.0

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

采纳答案by Hans Passant

GDI+ in general has very poor support for indexed pixel formats. There is no simple way to convert an image with 65536 or 16 million colors into one that only has 2, 16 or 256. Colors have to be removed from the source image and that is a lossy conversion that can have very poor results. There are multiple algorithms available to accomplish this, none of them are perfect for every kind of image. This is a job for a graphics editor.

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

There is one trick I found. GDI+ has an image encoder for GIF files. That's a graphics format that has only 256 colors, the encoder mustlimit the number of colors. It uses a dithering algorithm that's suitable for photos. It does have a knack for generating a grid pattern, you'll be less than thrilled when it does. Use it like this:

我发现了一个技巧。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);
    }
}

The returned image has a 8bpp pixel format with the Palette entries calculated by the encoder. You can cast it to Bitmap if necessary. By far the best thing to do is to simply not bother with indexed formats. They date from the stone age of computing back when memory was severely constrained. Or use a professional graphics editor.

返回的图像具有 8bpp 像素格式,其中包含由编码器计算的调色板条目。如有必要,您可以将其转换为位图。到目前为止,最好的办法就是不要理会索引格式。它们可以追溯到计算的石器时代,当时内存受到严重限制。或者使用专业的图形编辑器。

回答by Larry

AForgelibrary is doing it perfectly using Grayscale.

AForge库使用Grayscale完美地做到了这一点。

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

This class is the base class for image grayscaling [...] The filter accepts 24, 32, 48 and 64 bpp color images and produces 8 (if source is 24 or 32 bpp image) or 16 (if source is 48 or 64 bpp image) bpp grayscale image.

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

回答by Genzzry

Negative stride signifies the image is bottom-up (inverted). Just use the absolute of the stride if you dont care. I know that works for 24bpp images, unaware if it works for others.

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

回答by Navid Rahmani

You can use System.Windows.Media.Imaging in PresentationCore Assembly take a look at herefor more information

您可以在 PresentationCore 程序集中使用 System.Windows.Media.Imaging 查看此处了解更多信息