Pergunta

I use an XP VM and a Vista VM for smoke testing my applications before I deploy them. Both of these VM's are using 32bit color. Not sure if it makes any difference but I'm using VirtualBox. Each machine is also allocated 2GB of ram, 2 processors. XP has 128MB of video ram, Vista 256 (in each case the max I can set them to). The desktop running the machines has 6cores and 16GB of ram. Again, not sure if this information is relevant but who knows.

The following is an extension method I use in order to convert a Bitmap into a bunch of pixels that I can work with directly. Because, after all we need speed. Speed's what we need. Greasy, fast speed! And Bitmap.GetPixel is the antithesis of that.

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;
}

This code works perfectly on my Windows 8.1 "real" machine, as it did when I was using Windows 8 and Windows 7 previously.

But on the VM's, it fails with a "Parameter is not valid." 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)

According to the docs this is because either PixelFormat value is not a specific bits-per-pixel value or The incorrect PixelFormat is passed in for a bitmap.

I haven't got VS installed on these VM's but I did drop a test program on that opened an image and printed it's format... which was the expected PixelFormat.Format32bppArgb. I'm using the same set of test images on all 3 systems.

My next assumption is it's limitation of the video hardware of the VM, but at the end of the day it's a bitmap not a 3D scene... I'm pretty sure I should be able to work with it.

Can anyone shed some light on this issue? I'd really like to be able to test some of this code properly instead of just relying on "it works on my machine" and I'd rather not have to install VS on a VM anyway (not that I'm even sure it'll install on XP (I prefer that one over the Vista as it's visibly faster to work with)).

Hopefully someone else has come across this issue and has a solution - Google searching has let me down.

Foi útil?

Solução

Sigh... well, I can answer this question now, user error.

I had played around with VMMap but it wasn't really helping, so I decided I'd try adding some extra checks to the code as a precursor to installing VS on the VM for full debugging. I added an ArgumentException check for if the passed image was not 32bit ARGB. As it turned out though, the exception was thrown on my development machine which was somewhat unexpected. Evidently one of the images I was using for testing wasn't 32bit ARGB, but yet was happily being locked to 32bit ARGB. Just as evidently the right pixel data was being returned, as I think even I would have noticed a garbled image after manipulating bits!

Seems newer versions of Windows can in fact lock bits to a completely different format - a quick test program which simply opened a PNG then attempted to call Bitmap.LockBits on all values in the PixelFormat worked for every single format, bar the weird ones (that aren't prefixed with Format). Well, at the very least it doesn't thrown an exception, and in my case an image that had the format Format8bppIndexed was locked to Format32bppArgb and returned the correct pixel data. Whereas XP and Vista can't seem to do that and just throw an exception. Not sure if I prefer the former behaviour or the latter actually, almost leaning towards the latter although obviously the former is more convenient.

I stuck in a ugly hack where if the source image wasn't 32bit ARGB then a new temp image was generated from the source and used that to get the pixels. Now my code works in the VM without any noticeable problems, bar the speed of the method will have taken a hit. So there's one problem solved, now I just need to get rid of that hack.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top