Note that there are some explanatory texts on larger screens.

plurals
  1. POWhy does a bitmap compare not equal to itself?
    text
    copied!<p>This is a bit puzzling here. The following code is part of a little testing application to verify that code changes didn't introduce a regression. To make it fast we used <code>memcmp</code> which <a href="https://stackoverflow.com/q/2031217/73070">appears to be the fastest way of comparing two images of equal size</a> (unsurprisingly).</p> <p>However, we have a few test images that exhibit a rather surprising problem: <code>memcmp</code> on the bitmap data tells us that they are not equal, however, a pixel-by-pixel comparison doesn't find any difference at all. I was under the impression that when using <code>LockBits</code> on a <code>Bitmap</code> you get the actual raw bytes of the image. For a 24 bpp bitmap it's a bit hard to imagine a condition where the pixels are the same but the underlying pixel <em>data</em> isn't.</p> <p>A few surprising things:</p> <ol> <li>The differences are <em>always</em> single bytes that are <code>00</code> in one image and <code>FF</code> in the other.</li> <li>If one changes the <code>PixelFormat</code> for <code>LockBits</code> to <code>Format32bppRgb</code> or <code>Format32bppArgb</code>, the comparison succeeds.</li> <li>If one passes the <code>BitmapData</code> returned by the first <code>LockBits</code> call as 4th argument to the second one, the comparison succeeds.</li> <li>As noted above, the pixel-by-pixel comparison succeeds as well.</li> </ol> <p>I'm a bit stumped here because frankly I cannot imagine <em>why</em> this happens.</p> <p>(Reduced) Code below. Just compile with <code>csc /unsafe</code> and pass a 24bpp PNG image as first argument.</p> <pre><code>using System; using System.Drawing; using System.Drawing.Imaging; using System.Runtime.InteropServices; class Program { public static void Main(string[] args) { Bitmap title = new Bitmap(args[0]); Console.WriteLine(CompareImageResult(title, new Bitmap(title))); } private static string CompareImageResult(Bitmap bmp, Bitmap expected) { string retval = ""; unsafe { var rect = new Rectangle(0, 0, bmp.Width, bmp.Height); var resultData = bmp.LockBits(rect, ImageLockMode.ReadOnly, bmp.PixelFormat); var expectedData = expected.LockBits(rect, ImageLockMode.ReadOnly, expected.PixelFormat); try { if (memcmp(resultData.Scan0, expectedData.Scan0, resultData.Stride * resultData.Height) != 0) retval += "Bitmap data did not match\n"; } finally { bmp.UnlockBits(resultData); expected.UnlockBits(expectedData); } } for (var x = 0; x &lt; bmp.Width; x++) for (var y = 0; y &lt; bmp.Height; y++) if (bmp.GetPixel(x, y) != expected.GetPixel(x, y)) { Console.WriteLine("Pixel diff at {0}, {1}: {2} - {3}", x, y, bmp.GetPixel(x, y), expected.GetPixel(x, y)); retval += "pixel fail"; } return retval != "" ? retval : "success"; } [DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)] static extern int memcmp(IntPtr b1, IntPtr b2, long count); } </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload