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

将位图保存到内存流时发生gdi+异常

  •  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.像素数据无效,导致保存方法失败。我对此表示怀疑,因为我的像素数据是每像素24位,据我所知,它不应该是无效的。

    C..NET框架有问题。

    我会很感激对其他可能的失败原因有任何想法,这样我就可以在我的应用程序中添加额外的检查和记录信息,这样我就可以向该领域发送一些信息。

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

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

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

        2
  •  2
  •   Kris Erickson    16 年前

    你试过搬家吗

       picture.releasePixelData(pPixels);
    

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

    这听起来绝对像是线程问题(特别是当您声明ReleasePixelData可能发生在后台线程上时)。线程问题总是只在一台机器上发生的,并且总是在客户机上(可能是因为它们只有256meg的内存或者一些荒谬的东西,垃圾收集器很早就开始工作了,或者机器有四核,而您的开发人员机器是双核的或者其他的)。