Dlaczego mapa bitowa nie jest równa sobie?

To trochę zagadkowe. Poniższy kod jest częścią niewielkiej aplikacji testowej, aby sprawdzić, czy zmiany kodu nie wprowadziły regresji. Użyliśmy go szybkomemcmp którywydaje się być najszybszym sposobem porównywania dwóch obrazów o jednakowym rozmiarze (nic dziwnego).

Mamy jednak kilka obrazów testowych, które wykazują dość zaskakujący problem:memcmp na danych bitmapowych mówi się, że nie są równe, jednak porównanie piksel po pikselu wcale nie znajduje żadnej różnicy. Miałem wrażenie, że podczas używaniaLockBits naBitmap otrzymasz rzeczywiste surowe bajty obrazu. Dla bitmapy 24 bpp trudno sobie wyobrazić warunek, w którym piksele są takie same, ale piksel leżący u ich podstawdane nie jest.

Kilka zaskakujących rzeczy:

Różnice sązawsze pojedyncze bajty, które są00 na jednym obrazie iFF w innym.Jeśli zmieniszPixelFormat dlaLockBits doFormat32bppRgb lubFormat32bppArgb, porównanie się powiedzie.Jeśli minieBitmapData zwrócone przez pierwszegoLockBits wywołać jako czwarty argument do drugiego, porównanie się powiedzie.Jak wspomniano powyżej, porównanie piksel po pikselu również się powiedzie.

Jestem tu trochę zakłopotany, bo szczerze mówiąc nie mogę sobie tego wyobrazićczemu to się stało.

Kod (obniżony) poniżej. Po prostu skompiluj zcsc /unsafe i przekazać 24-bitowy obraz PNG jako pierwszy argument.

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 < bmp.Width; x++)
            for (var y = 0; y < 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);
}

questionAnswers(2)

yourAnswerToTheQuestion