代码之家  ›  专栏  ›  技术社区  ›  Peter Tate

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

  •  3
  • Peter Tate  · 技术社区  · 16 年前

    我在Windows窗体应用程序中遇到了位图问题。保存到MemoryStream时保存失败。到目前为止,问题似乎只在一台机器上间歇性出现,坏消息是在客户现场。我无法在机器上调试,但我得到了一个堆栈跟踪,将问题缩小到一行代码。

    这是我的代码的压缩版本:

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

    你知道可能发生了什么吗?我非常确定我的像素缓冲区是正确的,它总是在我们的开发/测试机器和其他客户站点上工作。

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

    a.位图构造函数不复制像素数据,但保留对像素数据的引用,由于内存被释放,保存失败。我觉得MSDN文档在这一点上并不清楚,但我假设位图复制了像素数据,而不是假设它被锁定了。

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

    c.有个问题。NET框架。

    如果您对其他可能的失败原因有任何想法,我将不胜感激,这样我就可以在我的应用程序中添加额外的检查和日志信息,以便我可以向现场发送一些东西。

    2 回复  |  直到 16 年前
        1
  •  5
  •   Hans Passant    9 年前

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

    言论 调用者负责分配和释放由scan0参数指定的内存块, 在释放相关位图之前,不应释放内存。

        2
  •  2
  •   Kris Erickson    16 年前

    你试过搬家吗

       picture.releasePixelData(pPixels);
    

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

    这听起来确实像是一个线程问题(尤其是因为你声明releasePixelData可能发生在后台线程上)。线程问题总是只发生在一台机器上的问题,而且它总是发生在客户端机器上(可能是因为它们只有256Meg的内存或一些荒谬的事情,垃圾收集器很早就启动了,或者机器有四核,而你的开发人员机器是双核或其他什么)。