为什么Bitmap.LockBits在VM上失败

时间:2013-12-29 17:55:17

标签: c# graphics bitmap gdi+ lockbits

在部署之前,我使用XP VM和Vista VM对我的应用程序进行烟雾测试。这两款VM都使用32位色。不确定它是否有任何区别,但我正在使用VirtualBox。每台机器还分配2GB内存,2个处理器。 XP有128MB的视频RAM,Vista 256(在每种情况下我可以设置它们的最大值)。运行机器的桌面有6个内核和16GB内存。同样,不确定这些信息是否相关但谁知道。

以下是我使用的扩展方法,用于将Bitmap转换为可以直接使用的一堆像素。因为,毕竟我们需要速度。速度是我们所需要的。油腻,速度快!而Bitmap.GetPixel就是其中的对立面。

public static ArgbColor[] GetPixels(this Bitmap bitmap)
{
  ArgbColor[] results;
  int width;
  int height;
  BitmapData bitmapData;

  width = bitmap.Width;
  height = bitmap.Height;
  results = new ArgbColor[width * height];
  bitmapData = bitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);

  unsafe
  {
    ArgbColor* pixelPtr;

    pixelPtr = (ArgbColor*)(void*)bitmapData.Scan0;

    for (int row = 0; row < height; row++)
    {
      for (int col = 0; col < width; col++)
      {
        results[row * width + col] = *pixelPtr;

        pixelPtr++;
      }
    }
  }

  bitmap.UnlockBits(bitmapData);

  return results;
}

此代码在我的Windows 8.1“真实”机器上运行良好,就像我之前使用Windows 8和Windows 7时一样。

但是在VM上,它失败并显示“参数无效”。 ArgumentException

System.Drawing.Bitmap.LockBits(Rectangle rect, ImageLockMode flags, PixelFormat format, BitmapData bitmapData)
System.Drawing.Bitmap.LockBits(Rectangle rect, ImageLockMode flags, PixelFormat format)
Cyotek.Drawing.ImageExtensions.GetPixels(Bitmap bitmap)

根据docs,这是因为 PixelFormat值不是特定的每像素位值为位图传递了错误的PixelFormat

我没有在这些VM上安装VS但是我确实放了一个测试程序,打开了一个图像并打印了它的格式......这是预期的PixelFormat.Format32bppArgb。我在所有3个系统上使用相同的测试图像集。

我的下一个假设是它限制了VM的视频硬件,但在一天结束时它是一个位图而不是3D场景......我很确定我应该能够使用它。

有人能解释一下这个问题吗?我真的希望能够正确地测试这些代码,而不仅仅依赖于“它在我的机器上工作”而且我宁愿不必在VM上安装VS(不是我甚至不确定它)将在XP上安装(我更喜欢在Vista上使用它,因为它的使用速度明显更快))。

希望其他人遇到此问题并提供解决方案 - Google搜索让我失望。

1 个答案:

答案 0 :(得分:6)

叹息......好吧,我现在可以回答这个问题,用户错误。

我曾经玩过VMMap,但它并没有真正起作用,所以我决定尝试在代码中添加一些额外的检查,作为在VM上安装VS进行全面调试的前提。我添加ArgumentException检查传递的图像是否不是32位ARGB。事实证明,我的开发机器上抛出了异常,这有些出乎意料。显然我用于测试的图像之一不是32位ARGB,但很高兴被锁定到32位ARGB。就像显然返回正确的像素数据一样,我认为即使在操作位之后我也会发现一个乱码图像!

似乎较新版本的Windows实际上可以将位锁定为完全不同的格式 - 一个快速测试程序,它只是打开一个PNG,然后试图调用Bitmap.LockBits PixelFormat为每个值工作的所有值单一格式,禁止奇怪的(不带格式前缀)。好吧,至少它没有抛出异常,在我的情况下,格式为Format8bppIndexed的图像被锁定到Format32bppArgb并返回正确的像素数据。而XP和Vista似乎无法做到这一点而只是抛出异常。不确定我是否更喜欢以前的行为或后者,实际上几乎倾向于后者,尽管前者显然更方便。

我陷入了一个丑陋的黑客,如果源图像不是32位ARGB,那么从源生成一个新的临时图像并用它来获取像素。现在我的代码在VM中运行时没有任何明显的问题,条件的速度会受到影响。所以有一个问题解决了,现在我只需要摆脱那个黑客。