Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
606 views
in Technique[技术] by (71.8m points)

.net - C# Converting 32bpp image to 8bpp

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:

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 BitBlt and GetDIBits etc. Anybody able to help me solve this? Thanks.

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

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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.

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 must limit 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:

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...