WinForms 位图区域已被锁定

WinForms Bitmap region is already locked

我想滑过几张图片,基本上你有 2 个向前和向后的按钮。它们的功能是滚动列表图像。一旦其中一个到达末尾,它必须返回列表的另一侧。这是我的

private List<Bitmap> RotatePacks = new List<Bitmap> { new Bitmap(@"Assets\All_Cards\All_Royal\All_Royal.png"),
                                                        new Bitmap(@"Assets\All_Cards\All_Classic\All_Classic.jpg")};

private void bNext_Click(object sender, EventArgs e)
{
    Bitmap currentImage = (Bitmap)pickCards.Image;
    for (int i = 0; i < RotatePacks.Count; i++)
    {
        if (AreEqual(currentImage, RotatePacks[i]))
        {
            try
            {
                pickCards.Image = RotatePacks[i + 1];
            }
            catch (Exception)
            {
                bPrevious_Click(sender, e);
                pickCards.Image = RotatePacks[i - 1];
            }
        }
    }
}
private void bPrevious_Click(object sender, EventArgs e)
{
    Bitmap currentImage = (Bitmap)pickCards.Image;
    for (int i = 0; i < RotatePacks.Count; i++)
    {
        if (AreEqual(currentImage, RotatePacks[i]))
        {
            try
            {
                pickCards.Image = RotatePacks[i - 1];
            }
            catch (Exception)
            {
                bNext_Click(sender, e);
            }
        }
    }
}

这是 2 个按钮。在这里,我试图将保存图像的 pictureBox 的图像与列表 RotatePacks 进行比较。就像这样,我正在获取正在显示的当前图像。这是 AreEqual 方法:

public unsafe static bool AreEqual(Bitmap b1, Bitmap b2) // copy pasted
{
    if (b1.Size != b2.Size)
    {
        return false;
    }

    if (b1.PixelFormat != b2.PixelFormat)
    {
        return false;
    }

    /*if (b1.PixelFormat != PixelFormat.Format32bppArgb)
    {
        return false;
    }*/
    Rectangle rect = new Rectangle(0, 0, b1.Width, b1.Height);
    BitmapData data1
        = b1.LockBits(rect, ImageLockMode.ReadOnly, b1.PixelFormat);
    BitmapData data2
        = b2.LockBits(rect, ImageLockMode.ReadOnly, b1.PixelFormat);
    int* p1 = (int*)data1.Scan0;
    int* p2 = (int*)data2.Scan0;
    int byteCount = b1.Height * data1.Stride / 4; //only Format32bppArgb 

    bool result = true;
    for (int i = 0; i < byteCount; ++i)
    {
        if (*p1++ != *p2++)
        {
            result = false;
            break;
        }
    }

    b1.UnlockBits(data1);
    b2.UnlockBits(data2);

    return result;
}

所以现在回到我的问题,按钮按照我想要的方式工作,但它们只工作一次。如果我按下一个按钮而不是上一个按钮,或者我按两次下一个按钮,程序将崩溃。它在这里给了我例外

            BitmapData data2
            = b2.LockBits(rect, ImageLockMode.ReadOnly, b1.PixelFormat);

下面是实际异常的一些屏幕截图:

http://prntscr.com/9ug3nl

http://prntscr.com/9ug3vv

这里似乎有几个问题:

  1. 值得早点检查

    if (b1 == b2) //put this
        return true; 
    //do something else
    Rectangle rect = new Rectangle(0, 0, b1.Width, b1.Height);
    //and so on
    

    可能 b1 == b2 会导致该问题

  2. 您的 LockBits 似乎指的是完全相同的项目(相同 rect、相同大小、某些模式、相同像素格式):

    Rectangle rect = new Rectangle(0, 0, b1.Width, b1.Height);
    BitmapData data1
        = b1.LockBits(rect, ImageLockMode.ReadOnly, b1.PixelFormat);
    BitmapData data2
        = b2.LockBits(rect, ImageLockMode.ReadOnly, b1.PixelFormat);
    

    这可能是问题的另一个原因...

就像 Ian 指出的那样,您必须检查您在 AreEqual() 方法中尝试比较的图像(current imageRotatepacks[i] 中的图像是否相同并且属于是否相同的实例?如果它们属于同一个实例,它显然会生成该异常。使用 .Equals() 方法检查图像是否属于同一实例。

考虑一个图像实例

Bitmap img;

img 中的图像与 RotatePacks 中的一样被加载到图片框中。在您的代码中,您试图两次锁定同一个实例,因此它会生成异常 Ian 指出的位图线没问题,但 2 个不同的图像可以具有相同的大小和像素格式。

此外,如果确实如此,我认为您不需要逐个像素地进行比较。我想您在 Rotatepacks 中有 Bitmap 个实例。只需使用 .Equals()

将图片框中的图片实例与 Rotatepacks 中的图片实例进行比较