C# – Convert 32-bit Bitmap to 8-bit (both color and grayscale)

cnetsystem.drawing

I have a System.Drawing.Bitmap with PixelFormat of Format32bppRgb.
I want this image to be converted to a bitmap of 8bit.

The following is the code to convert a 32-bit image to an 8-bit grayscale image:

        public static Bitmap ToGrayscale(Bitmap bmp)
        {
            int rgb;
            System.Drawing.Color c;

            for (int y = 0; y < bmp.Height; y++)
                for (int x = 0; x < bmp.Width; x++)
                {
                    c = bmp.GetPixel(x, y);
                    rgb = (int)((c.R + c.G + c.B) / 3);
                    bmp.SetPixel(x, y, System.Drawing.Color.FromArgb(rgb, rgb, rgb));
                }
            return bmp;
        }

However, the Bitmap I end up with still has the PixelFormat Property of Format32bppRgb.

Also,

  • How can I convert a 32-bit color image into an 8-bit color image?

Thanks for any input!

Related.
Convert RGB image to RGB 16-bit and 8-bit
C# – How to convert an Image into an 8-bit color Image?
C# Convert Bitmap to indexed colour format
Color Image Quantization in .NET
quantization (Reduction of colors of image)
The best way to reduce quantity of colors in bitmap palette

Best Answer

You must create (and return) new instance of Bitmap.

PixelFormat is specified in constructor of Bitmap and can not be changed.

EDIT: Sample code based on this answer on MSDN:

    public static Bitmap ToGrayscale(Bitmap bmp) {
        var result = new Bitmap(bmp.Width, bmp.Height, PixelFormat.Format8bppIndexed);

        BitmapData data = result.LockBits(new Rectangle(0, 0, result.Width, result.Height), ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);

        // Copy the bytes from the image into a byte array
        byte[] bytes = new byte[data.Height * data.Stride];
        Marshal.Copy(data.Scan0, bytes, 0, bytes.Length);

        for (int y = 0; y < bmp.Height; y++) {
            for (int x = 0; x < bmp.Width; x++) {
                var c = bmp.GetPixel(x, y);
                var rgb = (byte)((c.R + c.G + c.B) / 3);

                bytes[x * data.Stride + y] = rgb;
            }
        }

        // Copy the bytes from the byte array into the image
        Marshal.Copy(bytes, 0, data.Scan0, bytes.Length);

        result.UnlockBits(data);

        return result;
    }
Related Topic