【问题标题】:Why does Bitmap.LockBits fail on VM's为什么 Bitmap.LockBits 在 VM 上失败
【发布时间】:2014-01-16 16:12:48
【问题描述】:

在部署应用程序之前,我使用 XP VM 和 Vista VM 进行冒烟测试。这两个 VM 都使用 32 位颜色。不确定它是否有任何区别,但我正在使用 VirtualBox。每台机器还分配了 2GB 的内存,2 个处理器。 XP 有 128MB 的视频内存,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

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

我的下一个假设是 VM 的视频硬件受到限制,但归根结底,它是位图而不是 3D 场景......我很确定我应该能够使用它。

谁能解释一下这个问题?我真的很希望能够正确测试其中的一些代码,而不是仅仅依靠“它在我的机器上工作”,而且我宁愿不必在 VM 上安装 VS(我什至不确定它'将安装在 XP 上(我更喜欢 Vista 上的那个,因为它使用起来明显更快))。

希望其他人遇到过这个问题并有解决方案 - Google 搜索让我失望了。

【问题讨论】:

  • 视频硬件不起作用。查看进程使用的私有字节,最好使用 SysInternals 的 VMMap,当您使用大位图时,使用此代码可能会耗尽 VM 地址空间。当 GDI+ 无法在地址空间中找到足以容纳像素数据的空洞时,可能会引发“参数无效”。如果您确定在应该处理位图时,除了使用较小的位图或切换到 64 位代码之外,没有简单的解决方法。
  • 感谢您的评论。我用来测试的位图已经很小了——最大大约 100x100 像素。我认为我很擅长释放资源,所以我不会认为这是内存问题。不过,我会看看你所说的这个 VMMap 工具。仅仅因为两个虚拟机都安装了 32 位操作系统,所以不能选择 64 位。再次感谢您的评论!

标签: c# graphics bitmap gdi+ lockbits


【解决方案1】:

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

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-07-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-21
    相关资源
    最近更新 更多