GDI+ 将位图保存到 MemoryStream 时发生异常

发布于 2024-07-13 11:14:21 字数 1875 浏览 4 评论 0原文

我在 Windows 窗体应用程序中遇到问题,当我保存到 MemoryStream 时 Bitmap.Save 失败。 该问题似乎只间歇性地发生在一台机器上(到目前为止),而坏消息是在客户站点上。 我无法在机器上进行调试,但我得到了堆栈跟踪,将问题范围缩小到一行代码。

这是我的代码的精简版本:

byte[] ConvertPixelsToBytes()
{
    // imagine a picture class that creates a 24 bbp image, and has
    // a method to get an unmanaged pixel buffer.
    // imagine it also has methods for getting the width,
    // height, pitch 

    // I suppose this line could return a bad address, but 
    // I would have expected that the Bitmap constructor would have 
    // failed if it was
    System.IntPtr pPixels = picture.GetPixelData();

    System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(
            picture.width(),
            picture.height(),
            picture.pitch(),
            System.Drawing.Imaging.PixelFormat.Format24bppRgb,
            pPixels );

    // This line doesn't actually free the memory, but it could be freed in a 
    // background thread
    // (2)
    picture.releasePixelData(pPixels);

    System.IO.MemoryStream memStream = new System.IO.MemoryStream();
    try
    {
        // I don't see how this line could fail, but it does
        // (3)
        bmp.Save(memStream, System.Drawing.Imaging.ImageFormat.Bmp);
        return memStream.ToArray();
    }
   catch(System.Runtime.InteropServices.ExternalException e)
   {
       // e.Message is the very helpful " A generic error occurred in GDI+."
   }
   finally
   {
       memStream.Dispose();
   }
   return new byte[0];
}

知道会发生什么吗? 我很确定我的像素缓冲区是正确的,它始终适用于我们的开发/测试机器和其他客户站点。

我对失败的可能原因的看法是

: 位图构造函数不复制像素数据,但保留对其的引用,并且保存失败,因为内存被释放。 我没有找到 MSDN 文档明确说明这一点,但我假设位图复制像素数据而不是假设它被锁定。

b. 像素数据无效,导致 Save 方法失败。 我对此表示怀疑,因为我的像素数据是每像素 24 位,所以据我所知它不应该是无效的。

C。 .NET 框架有问题。

我将不胜感激对其他可能的失败原因的任何想法,以便我可以向我的应用程序添加额外的检查和日志信息,以便我可以将一些内容发送到现场。

I have a problem in a Windows Forms application with Bitmap.Save failing when I save to a MemoryStream. The problem only seems to occur intermittently on one machine (so far) and the bad news it is at a customer site. I can't debug on the machine, but I got a stack trace that narrowed the problem down to a single line of code.

Here's a condensed version of my code:

byte[] ConvertPixelsToBytes()
{
    // imagine a picture class that creates a 24 bbp image, and has
    // a method to get an unmanaged pixel buffer.
    // imagine it also has methods for getting the width,
    // height, pitch 

    // I suppose this line could return a bad address, but 
    // I would have expected that the Bitmap constructor would have 
    // failed if it was
    System.IntPtr pPixels = picture.GetPixelData();

    System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(
            picture.width(),
            picture.height(),
            picture.pitch(),
            System.Drawing.Imaging.PixelFormat.Format24bppRgb,
            pPixels );

    // This line doesn't actually free the memory, but it could be freed in a 
    // background thread
    // (2)
    picture.releasePixelData(pPixels);

    System.IO.MemoryStream memStream = new System.IO.MemoryStream();
    try
    {
        // I don't see how this line could fail, but it does
        // (3)
        bmp.Save(memStream, System.Drawing.Imaging.ImageFormat.Bmp);
        return memStream.ToArray();
    }
   catch(System.Runtime.InteropServices.ExternalException e)
   {
       // e.Message is the very helpful " A generic error occurred in GDI+."
   }
   finally
   {
       memStream.Dispose();
   }
   return new byte[0];
}

Any idea what might be going on? I'm pretty sure my pixel buffer is right, it always works on our dev/test machines and at other customer sites.

My thoughts on possible reasons for failure are

a. The bitmap constructor doesn't copy the pixel data, but keeps a reference to it, and the Save fails because the memory is released. I don't find the MSDN docs clear on this point, but I assume that the Bitmap copies the pixel data rather than assume it is locked.

b. The pixel data is invalid, and causes the Save method to fail. I doubt this since my pixel data is 24 Bits per pixel, so as far as I know it should not be invalid.

c. There's a problem with the .NET framework.

I would appreciate any thoughts on other possible failure reasons so I can add extra checks and logging information to my app so I can send something out into the field.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

ぃ弥猫深巷。 2024-07-20 11:14:22

该 Bitmap 构造函数的 MSDN 文档毫无疑问:

备注
调用者负责分配和释放由 scan0 参数指定的内存块,但是,在释放相关 Bitmap 之前不应释放内存。

The MSDN docs for that Bitmap constructor leave no doubt whatsoever:

Remarks
The caller is responsible for allocating and freeing the block of memory specified by the scan0 parameter, however, the memory should not be released until the related Bitmap is released.

过潦 2024-07-20 11:14:22

您是否尝试过转向

   picture.releasePixelData(pPixels);

   finally
   {
       memStream.Dispose();
       picture.releasePixelData(pPixels);
   }

,这听起来确实像是一个线程问题(特别是因为您声明releasePixelData可能发生在后台线程上)。 线程问题总是只发生在一台机器上,并且总是在客户端机器上(可能是因为它们只有 256Meg 内存或一些荒谬的东西,垃圾收集器提前启动,或者机器有四核)并且您的开发机器是双核之类的)。

Have you tried moving

   picture.releasePixelData(pPixels);

to

   finally
   {
       memStream.Dispose();
       picture.releasePixelData(pPixels);
   }

it definitely sounds like a threading issue (especially since you state that the releasePixelData could happen on a background thread). Threading issues are always the ones that only happen on one machine, and it is always on the clients machine (probably due to the fact they only have 256Megs of memory or something ridiculous and garbage collector is kicking in early, or the machine has quad core and your developer machine is dual core or something).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文