0

I'm trying to make color picker using LockBits so when I move the cursor over picturebox it shows color located at cursor position. Approach with GetPixel works however I'm interested how to do this using LockBits.

My try, unfortunately shows white all the time:

void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
    Bitmap bmp = new Bitmap(pictureBox1.Image);
    // we will try to get the pixel using raw data and make color from it
    BitmapData data = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, bmp.PixelFormat);

    // default format is 32bpp argb ( 4 bytes per pixel)
    unsafe
    {
        byte* scanline = (byte*)data.Scan0;
        for(int y = 0; y < data.Height; y++)
        {
            // row
            for (int x = 0; x < data.Width; x+=4)
            {
                 int r = scanline[x];
                 int g = scanline[x+1];
                 int b = scanline[x+2];
                 //int a = scanline[x+3];
                 Color color = Color.FromArgb(255, r, g, b);

                 pictureBox2.BackColor = color;

             }
         }
    }

    bmp.UnlockBits(data);

    //Color color = bmp.GetPixel(e.X, e.Y);

}
meJustAndrew
  • 6,011
  • 8
  • 50
  • 76
Konrad
  • 6,385
  • 12
  • 53
  • 96
  • Not only are you getting the channels in reverse (physically they are BGRA) ) and ignoring the true pixelformat and the stride; the whole idea seems moot as there can't be a performance reason the use lockbits over getPixel when picking one single pixel, let alone when a humnan slo-mo user does the picking. There are many [working examples](http://stackoverflow.com/questions/24411114/c-sharp-copy-bitmaps-pixels-in-the-alpha-channel-on-another-bitmap/24411925#24411925) here.. – TaW Aug 02 '16 at 20:41
  • Yes but I would like to learn how to do this using this method. – Konrad Aug 02 '16 at 20:42
  • 1
    In addition, it seems strange to loop through the entire bitmap each time the mouse moves. I would think at least you would use the X, Y coordinates provided in the `MouseEventArgs` parameters and use lockbits to select that single pixel. – Chris Dunaway Aug 02 '16 at 20:43
  • @ChrisDunaway could you provide an example ? Please. – Konrad Aug 02 '16 at 20:44
  • See [here](http://stackoverflow.com/questions/38654285/c-sharp-draw-on-image-using-unsafe-pointers/38655459#38655459) for an example. Simply double drop the loop and use the x and y values form the e.location directly. (Assuming the picturebox is not zoomed, of course) - Also add `alpha = p[px + 3] = 255; //alpha` - As you can see from the comments in the link this is actually slower than using getpixel ;-) But of course well worth studying it. Try to correct the code and report back! – TaW Aug 02 '16 at 20:45
  • ((make 'double drop the loop' 'drop the double loop ;-'))- As it is your code always reports only the very last pixel and in reverse, ie (R=255, G=R, B=G).. If this comes out as White the last pixel is Yellow. – TaW Aug 02 '16 at 20:51
  • You are writing pointless code. Not only is it very buggy, it will never be faster than GetPixel(). Which is "slow" because it calls LockBits(). So do you of course. You just made it a lot slower. GetPixel() is not slow enough for a human hand. – Hans Passant Aug 02 '16 at 21:04
  • It's for educational purposes not for performance. I tried but I can't get it working. This stride stuff it's confusing me. I get wrong colors all the time. – Konrad Aug 02 '16 at 21:07
  • Folow the 2nd link I gave you and my comments on it. – TaW Aug 02 '16 at 21:13
  • What is x0 y0 x1 y1 – Konrad Aug 02 '16 at 21:22
  • Ignore, delete with the loops and replace by your actual x coordinate! (the op draws a rectangle from x0,y0 to -x1,y1) – TaW Aug 02 '16 at 21:26
  • Okay... I give up.. I do something wrong tried to do it for the past few hours. – Konrad Aug 02 '16 at 21:35
  • OK, since you tried so hard.. – TaW Aug 02 '16 at 21:36
  • @shad0wk well I felt offended so I deleted it okay. If you know the answer thats nice. I don't know it. – Konrad Aug 04 '16 at 08:39

1 Answers1

1

Here is the solution..:

unsafe Color getPixel(Bitmap bmp, int x, int y)
{
    BitmapData bmData = bmp.LockBits( new Rectangle(0, 0, bmp.Width, bmp.Height),
                        System.Drawing.Imaging.ImageLockMode.ReadWrite, bmp.PixelFormat);

    // not a complete check, but a start on how to use different pixelformats
    int pixWidth = bmp.PixelFormat == PixelFormat.Format24bppRgb ? 3 :
                   bmp.PixelFormat == PixelFormat.Format32bppArgb ? 4 : 4;

    IntPtr scan0 = bmData.Scan0;
    int stride = bmData.Stride;
    byte* p = (byte*)scan0.ToPointer() + y * stride;
    int px = x * pixWidth;
    byte alpha = (byte) (pixWidth == 4 ? p[px + 3] : 255);
    Color color  = Color.FromArgb(alpha , p[px + 2], p[px + 1], p[px + 0]);
    bmp.UnlockBits(bmData);
    return color;
}

This is how you could call it:

private void panel1_MouseClick(object sender, MouseEventArgs e)
{
    panel2.BackColor = getPixel((Bitmap)panel1.BackgroundImage, e.X, e.Y);
}

Of course you can use any sort of Bitmap source, like Label.Image ot PictureBox.Image...

The color channels are called ARGB but actually ordered BGRA.

Note that stride is the physical width of a bitmap pixel row, including possible etra bytes to fill to a multiple of 4 bytes.

Also note that other solutions using lockbit work without pointers..

As noted in the comments above this is actually slower than using GetPixel, since setting up the unsafe access vector eats up any gain, even when reading out several pixels.

TaW
  • 53,122
  • 8
  • 69
  • 111
  • Thank you. What's the other solution without pointer using lockbit ? – Konrad Aug 02 '16 at 21:43
  • 1
    Note the correction! I forgot to test before using the alpha component! - The lower part of [my answer here](http://stackoverflow.com/questions/24411114/c-sharp-copy-bitmaps-pixels-in-the-alpha-channel-on-another-bitmap/24411925#24411925) works without pointers and without unsafe code. It is also not aiming at single pixels but at looping over a block. Similar changes apply.. – TaW Aug 02 '16 at 21:46
  • Great ! I still have a lot to learn. Thank you so much for help. – Konrad Aug 02 '16 at 21:50