1

I'm trying to compare screenshots and write only the differences.

This is my code

public Bitmap Difference(Bitmap bmp0, Bitmap bmp1)
{
        Bitmap bmp2;
        int Bpp = bmp0.PixelFormat == PixelFormat.Format24bppRgb ? 3 : 4;

        bmp2 = new Bitmap(bmp0.Width, bmp0.Height, bmp0.PixelFormat);

        var bmpData0 = bmp0.LockBits(
                        new Rectangle(0, 0, bmp0.Width, bmp0.Height),
                        ImageLockMode.ReadOnly, bmp0.PixelFormat);
        var bmpData1 = bmp1.LockBits(
                        new Rectangle(0, 0, bmp1.Width, bmp1.Height),
                        ImageLockMode.ReadOnly, bmp1.PixelFormat);
        var bmpData2 = bmp2.LockBits(
                        new Rectangle(0, 0, bmp2.Width, bmp2.Height),
                        ImageLockMode.ReadWrite, bmp2.PixelFormat);

       // MessageBox.Show(bmpData0.Stride.ToString());
       int len = bmpData0.Height * bmpData0.Stride;

       //   MessageBox.Show(bmpData0.Stride.ToString());
       bool changed = false;

       byte[] data0 = new byte[len];
       byte[] data1 = new byte[len];
       byte[] data2 = new byte[len];

       Marshal.Copy(bmpData0.Scan0, data0, 0, len);
       Marshal.Copy(bmpData1.Scan0, data1, 0, len);
       Marshal.Copy(bmpData2.Scan0, data2, 0, len);

       for (int i = 0; i < len; i += Bpp)
       {
            changed = ((data0[i] != data1[i])
                          || (data0[i + 1] != data1[i + 1])
                          || (data0[i + 2] != data1[i + 2]));

            // this.Invoke(new Action(() => this.Text = changed.ToString()));

            data2[i] = changed ? data1[i] : (byte)2;   // special markers
            data2[i + 1] = changed ? data1[i + 1] : (byte)3;   // special markers
            data2[i + 2] = changed ? data1[i + 2] : (byte)7;   // special markers

            if (Bpp == 4) 
               data2[i + 3] = changed ? (byte)255 : (byte)42;  // special markers
    }

    //  this.Invoke(new Action(() => this.Text = changed.ToString()));
    Marshal.Copy(data2, 0, bmpData2.Scan0, len);
    bmp0.UnlockBits(bmpData0);
    bmp1.UnlockBits(bmpData1);
    bmp2.UnlockBits(bmpData2);

    return bmp2;
}


    Bitmap shot = new Bitmap(SystemInformation.VirtualScreen.Width,
                    SystemInformation.VirtualScreen.Height,
                    PixelFormat.Format24bppRgb);

    public Bitmap screenshot()
    {


        Graphics screenGraph = Graphics.FromImage(shot);
        screenGraph.CopyFromScreen(Screen.PrimaryScreen.Bounds.X,
                                   Screen.PrimaryScreen.Bounds.Y,
                                   0,
                                   0,
                                   SystemInformation.VirtualScreen.Size,
                                   CopyPixelOperation.SourceCopy);

        return shot;

    }

And my call:

private void Form1_Load(object sender, EventArgs e)
{
        Bitmap prev = screenshot();

        Thread.Sleep(1000);
        Bitmap  curr = screenshot();

        pictureBox1.Image=Difference(prev,curr);
}

im getting an Bitmap region is already locked. Error in this line

   var bmpData1 = bmp1.LockBits(
                        new Rectangle(0, 0, bmp1.Width, bmp1.Height),
                        ImageLockMode.ReadOnly, bmp1.PixelFormat);

this is my screenshot code, a simple .net screen capture method:

it's realy weird because i dont even used LockBits in the screenshot method so i have no idea why it's throwing this error...

  • 1
    One problem (though maybe not the main problem) is that you've called `UnlockBits` for all the images before you try to access their data via the `BitmapData` objects. You have to do all your reading/writing from/to the `BitmapData` objects *before* calling `UnlockBits`, which essentially invalidates the `BitmapData` objects. – adv12 Jul 01 '15 at 13:34
  • @adv12 allright thanks but it's not the problem i edited and unlockbits in the end but still same error –  Jul 01 '15 at 13:40

1 Answers1

1

If your bitmap is 'bottom up' as opposed to 'top down', the Stride property will be a negative value.

See here: https://msdn.microsoft.com/en-us/library/system.drawing.imaging.bitmapdata.stride%28v=vs.110%29.aspx

From this article:
"The stride is the width of a single row of pixels (a scan line), rounded up to a four-byte boundary. If the stride is positive, the bitmap is top-down. If the stride is negative, the bitmap is bottom-up."

Use

int len = bmpData0.Height * Math.Abs(bmpData0.Stride);

If you are using a bottom-up bitmap you will need to use a different mechanism for copying the bitmap to your buffer. There are some different suggestions for how to handle this in this question, see the first three answers:

How can I copy the pixel data from a Bitmap with negative stride?



From the latest edit to your question, your problem is now that you are using the same Bitmap instance for both your screenshots. Move the 'shot' declaration inside the screenshot() method so a different instance is used for each screenshot:

public Bitmap screenshot()
{

     Bitmap shot = new Bitmap(SystemInformation.VirtualScreen.Width,
                SystemInformation.VirtualScreen.Height,
                PixelFormat.Format24bppRgb);
    Graphics screenGraph = Graphics.FromImage(shot);
    screenGraph.CopyFromScreen(Screen.PrimaryScreen.Bounds.X,
                               Screen.PrimaryScreen.Bounds.Y,
                               0,
                               0,
                               SystemInformation.VirtualScreen.Size,
                               CopyPixelOperation.SourceCopy);

    return shot;
}
Community
  • 1
  • 1
user469104
  • 1,206
  • 12
  • 15
  • now im getting another error in this line `Marshal.Copy(bmpData0.Scan0, data0, 0, len);` `Attempted to read or write protected memory. This is often an indication that other memory is corrupt.` @user469104 –  Jul 01 '15 at 13:41
  • Did you move the UnlockBits to the end as per adv12's comment? – user469104 Jul 01 '15 at 13:45
  • yeah look also in the question i edited these lines –  Jul 01 '15 at 13:45
  • @itapi if you are getting a different exception with the edited code please update your question to show new error you get, you are still saying you are getting the OverflowException in your question. – Scott Chamberlain Jul 01 '15 at 13:48
  • @itapi, the error is related to you using a bottom-up bitmap. I will update the answer with additional information. – user469104 Jul 01 '15 at 13:50
  • @user469104 allright notify me if you can so i would know you edited –  Jul 01 '15 at 13:56
  • @user469104 i didnt really understand what is wrriten there... the best solution i could think about is using `Clone` Method.. but it works slow... –  Jul 01 '15 at 14:01
  • @user469104 please see the updated question. i decided to use regular c# screen capture –  Jul 01 '15 at 14:19