1

im trying to compare 2 smalls blocks of image using the memcmp method. i saw this answer What is the fastest way I can compare two equal-size bitmaps to determine whether they are identical? and i tried to implement this in my project:

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

    prev = (Bitmap) Image.FromFile(@"C:\Users\Public\Desktop\b.png");



    curr = (Bitmap)Image.FromFile(@"C:\Users\Public\Desktop\b.png");
    MessageBox.Show(CompareMemCmp(prev, curr).ToString());
}

this is the method-

[DllImport("msvcrt.dll")]
private static extern int memcmp(IntPtr b1, IntPtr b2, long count);

public static bool CompareMemCmp(Bitmap b1, Bitmap b2)
{
    if ((b1 == null) != (b2 == null)) return false;
    if (b1.Size != b2.Size) return false;

    var bd1 = b1.LockBits(new Rectangle(new Point(0, 0), b1.Size), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
    var bd2 = b2.LockBits(new Rectangle(new Point(0, 0), b2.Size), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);

    try
    {
        IntPtr bd1scan0 = bd1.Scan0;
        IntPtr bd2scan0 = bd2.Scan0;

        int stride = bd1.Stride;
        int len = stride * b1.Height;

        return memcmp(bd1scan0, bd2scan0, len) == 0;
    }
    finally
    {
        b1.UnlockBits(bd1);
        b2.UnlockBits(bd2);
    }
}

and im getting this error when calling memcmp function

A call to PInvoke function 'WindowsFormsApplication1!WindowsFormsApplication1.Form1::memcmp' has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature.

any idea why is that happening? i did all based on that answer.

Community
  • 1
  • 1

1 Answers1

2

The correct signature is:

[DllImport("msvcrt.dll", CallingConvention=CallingConvention.Cdecl)]
static extern int memcmp(IntPtr b1, IntPtr b2, IntPtr count);

because in C, count is size_t, so it can be 32 or 64 bits depending if the program is running at 32 or 64 bits.

Then to use it:

return memcmp(bd1scan0, bd2scan0, (IntPtr)len) == 0;
xanatos
  • 109,618
  • 12
  • 197
  • 280
  • wait! but bd1scan0 and bd2scan0 are **Intptr**! i dont want to to compare byte array! @xanatos –  Jul 23 '15 at 14:10
  • @itapi There are various correct signature... In one revision I changed from one to another... Restored the one you saw in the beginning. Note that I've added the `CallingConvention=CallingConvention.Cdecl)]` – xanatos Jul 23 '15 at 14:12
  • allright thank you man. one last question, a little consultation-i created a screen sharing app and i want to send only the differences part over a socket to make it faster and more efficient. Will it be a good idea to split the screenshot into small blocks,compare each block using this method and only if there's a change-to send it? because actually this method does indicates about the change-i mean how big is the change,if theres a small or massive change. thank you very much i apperciate you're help :) @xanatos –  Jul 23 '15 at 14:15
  • @itapi You can't do it in that way... `LockBits` doesn't really give you "nice" rectangular crops of the image. See http://stackoverflow.com/q/10771300/613130 for an explanation of what it does. What I would do would be do (for example) a binary diff of the two images and then compress with `DeflateStream` it. Equal bytes would be diffed to 0, and long sequences of 0 would be "removed" by `DeflateStream` – xanatos Jul 23 '15 at 14:25
  • @itapi With binary diff I mean that you create a `byte[] diff = new byte[len]`, then you put there the `for (int i = 0; i < len; i++) diff[i] = Marshal.ReadByte(bd1scan0, i) - Marshal.ReadByte(bd2scan0, i)` – xanatos Jul 23 '15 at 14:27
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/84086/discussion-between-itapi-and-xanatos). –  Jul 23 '15 at 14:28