Convert bitmap from 24 bit to monochrome.

Hi,

Is there an "easy" way of converting a 24 bit bitmap to a monochrome image (the same as "save as - monochrome" in mspaint for example).

Thanks.

James.
JAMESAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

AlexFMCommented:
This is pure .NET way:

using System.Drawing.Imaging;
using System.Runtime.InteropServices;


        Bitmap ConvertRGB24ToMonochrome(Bitmap source)
        {
            if ( source.PixelFormat != PixelFormat.Format24bppRgb )
            {
                return null;
            }

            Byte[] colorBytes = BitmapToBytesRGB24(source);

            if ( colorBytes == null )
            {
                 return null;
            }

            Byte[] monoBytes = new Byte[source.Width * source.Height];

            int j = 0;

            for ( int i = 0; i < source.Width * source.Height; i++ )
            {
                monoBytes[i] = (Byte)(0.3f * (float)colorBytes[j + 2] + 0.59f * (float)colorBytes[j + 1] + 0.11f * (float)colorBytes[j]);

                j += 3;
            }

            return BitsToBitmapMonochrome(monoBytes, source.Width, source.Height);
        }

        // Create monochrome bitmap from Byte array
        Bitmap BitsToBitmapMonochrome(Byte[] bytes, int width, int height)
        {
            if (bytes.GetLength(0) < width * height)
            {
                return null;
            }

            Bitmap bmp = new Bitmap(width, height, PixelFormat.Format8bppIndexed);
            int i;

            bmp.Palette = GetGrayScalePalette();
           
            //for (i = 0; i < 256; i++)
            //{
            //    bmp.Palette.Entries[i] = Color.FromArgb(i, i, i);
            //}
           

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


            if (data.Stride == width * 3)
            {
                Marshal.Copy(bytes, 0, data.Scan0, width * height);
            }
            else
            {
                for (i = 0; i < bmp.Height; i++)
                {
                    IntPtr p = new IntPtr(data.Scan0.ToInt32() + data.Stride * i);
                    Marshal.Copy(bytes, i * bmp.Width, p, bmp.Width);
                }
            }

            bmp.UnlockBits(data);

            return bmp;
        }


        // Create Byte array from RGB24 bitmap
        Byte[] BitmapToBytesRGB24(Bitmap bmp)
        {
            if ( bmp.PixelFormat != PixelFormat.Format24bppRgb )
            {
                return null;
            }

            int i;
            int length = bmp.Width * bmp.Height * 3;

            Byte[] bytes = new Byte[length];

            BitmapData data = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height),
                ImageLockMode.ReadOnly, bmp.PixelFormat);

            if (data.Stride == bmp.Width * 3)
            {
                Marshal.Copy(data.Scan0, bytes, 0, length);
            }
            else
            {
                for ( i = 0; i < bmp.Height; i++ )
                {
                    IntPtr p = new IntPtr(data.Scan0.ToInt32() + data.Stride * i);
                    Marshal.Copy(p, bytes, i * bmp.Width * 3, bmp.Width * 3);
                }
            }

            bmp.UnlockBits(data);

            return bytes;
        }


        ColorPalette GetGrayScalePalette()
        {
            Bitmap bmp = new Bitmap(1, 1, PixelFormat.Format8bppIndexed);

            ColorPalette monoPalette = bmp.Palette;

            Color[] entries = monoPalette.Entries;

            for ( int i = 0; i < 256; i++ )
            {
                entries[i] = Color.FromArgb(i, i, i);
            }

            return monoPalette;
        }
    }
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
JAMESAuthor Commented:
Cool - many thanks.

James.
0
Cloud Class® Course: C++ 11 Fundamentals

This course will introduce you to C++ 11 and teach you about syntax fundamentals.

AlexFMCommented:
Correction in BitsToBitmapMonochrome function:

if (data.Stride == width * 3)

should be

if (data.Stride == width)
0
JAMESAuthor Commented:
Thanks.
0
JAMESAuthor Commented:
Alex,

Not sure if you still see any messages posted here now this one is closed but after using the above method I have discovered the PixelFormat of captured bitmaps is PixelFormat.Format32bppArgb.

Should I be able to use the same routine anyway (after altering the initial check which returns null) ?

Thanks.

James.
0
AlexFMCommented:
You can create RGB24 bitmap, explicitly providing PixelFormat parameter to Bitmap constructor, for capturing code. Try this, if it doesn't work, I will post code for 32 bpp bitmap.

0
JAMESAuthor Commented:
I *think* it works but the result looks different to when I "save as" to Monochrome in MS Paint.
0
AlexFMCommented:
Changed without test, hope it will work:

        Bitmap ConvertRGB32ToMonochrome(Bitmap source)
        {
            if ( source.PixelFormat != PixelFormat.Format32bppRgb )
            {
                return null;
            }

            Byte[] colorBytes = BitmapToBytesRGB32(source);

            if ( colorBytes == null )
            {
                 return null;
            }

            Byte[] monoBytes = new Byte[source.Width * source.Height];

            int j = 0;

            for ( int i = 0; i < source.Width * source.Height; i++ )
            {
                monoBytes[i] = (Byte)(0.3f * (float)colorBytes[j + 2] + 0.59f * (float)colorBytes[j + 1] + 0.11f * (float)colorBytes[j]);

                j += 4;
            }

            return BitsToBitmapMonochrome(monoBytes, source.Width, source.Height);
        }

        // Create monochrome bitmap from Byte array
        Bitmap BitsToBitmapMonochrome(Byte[] bytes, int width, int height)
        {
            if (bytes.GetLength(0) < width * height)
            {
                return null;
            }

            Bitmap bmp = new Bitmap(width, height, PixelFormat.Format8bppIndexed);
            int i;

            bmp.Palette = GetGrayScalePalette();
           
            BitmapData data = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height),
                ImageLockMode.WriteOnly, bmp.PixelFormat);


            if (data.Stride == width)
            {
                Marshal.Copy(bytes, 0, data.Scan0, width * height);
            }
            else
            {
                for (i = 0; i < bmp.Height; i++)
                {
                    IntPtr p = new IntPtr(data.Scan0.ToInt32() + data.Stride * i);
                    Marshal.Copy(bytes, i * bmp.Width, p, bmp.Width);
                }
            }

            bmp.UnlockBits(data);

            return bmp;
        }


        // Create Byte array from RGB32 bitmap
        Byte[] BitmapToBytesRGB32(Bitmap bmp)
        {
            if ( bmp.PixelFormat != PixelFormat.Format32bppRgb )
            {
                return null;
            }

            int i;
            int length = bmp.Width * bmp.Height * 4;

            Byte[] bytes = new Byte[length];

            BitmapData data = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height),
                ImageLockMode.ReadOnly, bmp.PixelFormat);

            if (data.Stride == bmp.Width * 4)
            {
                Marshal.Copy(data.Scan0, bytes, 0, length);
            }
            else
            {
                for ( i = 0; i < bmp.Height; i++ )
                {
                    IntPtr p = new IntPtr(data.Scan0.ToInt32() + data.Stride * i);
                    Marshal.Copy(p, bytes, i * bmp.Width * 4, bmp.Width * 4);
                }
            }

            bmp.UnlockBits(data);

            return bytes;
        }


        ColorPalette GetGrayScalePalette()
        {
            Bitmap bmp = new Bitmap(1, 1, PixelFormat.Format8bppIndexed);

            ColorPalette monoPalette = bmp.Palette;

            Color[] entries = monoPalette.Entries;

            for ( int i = 0; i < 256; i++ )
            {
                entries[i] = Color.FromArgb(i, i, i);
            }

            return monoPalette;
        }
    }
0
JAMESAuthor Commented:
Does it matter you are using Format32bppRBG but my pixelformat is Format32bppArgb ?

Sorry to possibly be asking dumb questions but this level of image manipulation is new to me.

Many thanks.

james.
0
AlexFMCommented:
It is just result of my "online" correction, Format32bppArgb is correct.
0
vikasparashar320Commented:
But i want to change the bitmap image to 1 Bpp Monochrome.  as like in MS paint
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C#

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.