3

I am new in working with Bitmap and using 16 bits per pixel Format16bppRgb555;

I want to Extract RGB Values from Bitmap Data. Here is my code

static void Main(string[] args)
    {

        BitmapRGBValues();
        Console.ReadKey();
    }


 static unsafe void BitmapRGBValues()
    {

        Bitmap cur = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, PixelFormat.Format16bppRgb555);
        //Capture Screen
        var screenBounds = Screen.PrimaryScreen.Bounds;
        using (var gfxScreenshot = Graphics.FromImage(cur))
        {
            gfxScreenshot.CopyFromScreen(screenBounds.X, screenBounds.Y, 0, 0, screenBounds.Size, CopyPixelOperation.SourceCopy);
        }

        var curBitmapData = cur.LockBits(new Rectangle(0, 0, cur.Width, cur.Height),
                                 ImageLockMode.ReadWrite, PixelFormat.Format16bppRgb555);


        try
        {
            byte* scan0 = (byte*)curBitmapData.Scan0.ToPointer();

            for (int y = 0; y < cur.Height; ++y)
            {
                ulong* curRow = (ulong*)(scan0 + curBitmapData.Stride * y);

                for (int x = 0; x < curBitmapData.Stride / 8; ++x)
                {

                    ulong pixel = curRow[x];

                    //How to get RGB Values  from pixel;







                }

            }


        }
        catch
        {

        }
        finally
        {
            cur.UnlockBits(curBitmapData);

        }


    }
Azar Shaikh
  • 445
  • 9
  • 26
  • Look up bit operations in c#! – TaW Mar 09 '18 at 09:36
  • The blocks in a 16bpp image are UInt16 (ushort), not ulong. Once you got that, bit-shift the values out. That aside... what do you mean with "extract", here? Your return type is `void`. – Nyerguds Mar 11 '18 at 22:07

1 Answers1

7

LockBits can actually convert your image to a desired pixel format, meaning no further conversion should be needed. Just lock the image as Format32bppArgb and you can simply take your colour values from single bytes.

BitmapData curBitmapData = cur.LockBits(new Rectangle(0, 0, cur.Width, cur.Height),
    ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
Int32 stride = curBitmapData.Stride;
Byte[] data = new Byte[stride * cur.Height];
Marshal.Copy(curBitmapData.Scan0, data, 0, data.Length);
cur.UnlockBits(curBitmapData);

With this code, you end up with the byte array data, which is filled with your image data in ARGB format, meaning the colour component bytes will be in there in the order [B, G, R, A]. Note that the stride is the amount of bytes to skip to get to a next line on the image, and since this is not always equal to "width * bytes per pixel", it should always be taken into account.

Now you got that, you can do whatever you want with it...

Int32 curRowOffs = 0;
for (Int32 y = 0; y < cur.Height; y++)
{
    // Set offset to start of current row
    Int32 curOffs = curRowOffs;
    for (Int32 x = 0; x < cur.Width; x++)
    {
        // ARGB = bytes [B,G,R,A]
        Byte b = data[curOffs];
        Byte g = data[curOffs + 1];
        Byte r = data[curOffs + 2];
        Byte a = data[curOffs + 3];
        Color col = Color.FromArgb(a, r, g, b);

        // Do whatever you want with your colour here
        // ...

        // Increase offset to next colour
        curOffs += 4;
    }
    // Increase row offset
    curRowOffs += stride;
}

You can even edit the bytes, and then build a new image from them if you want.

Nyerguds
  • 5,360
  • 1
  • 31
  • 63
  • How can the order be like [B, G, R, A] and not [A, R, G, B]..... according to documentation {The format also defines the order of the color components within a single pixel of data} ..... The format in PixelFormat is ARGB so what i am asking why did you reverse to BGRA??????? – user1477332 May 14 '20 at 00:35
  • 2
    @user1477332 Look up the concept of "endianness". PC CPUs are little-endian, meaning bytes are stored in reverse order. So a byte sequence "AA BB CC DD", interpreted as little-endian `UInt32`, becomes the _value_ 0xDDCCBBAA. Since the `System.Drawing` classes use data that way, and an ARGB colour refers to the colour as `UInt32`, not as byte array, you need to reverse that order to handle the colours as bare bytes. – Nyerguds May 14 '20 at 16:32
  • Yes you are right, thanks for clarification, it helped me alot – user1477332 May 14 '20 at 20:20