将位图保存到MemoryStream时,GDI+中出现一般错误

本文关键字:错误 GDI+ 保存 位图 MemoryStream | 更新日期: 2023-09-27 18:25:49

我有一些代码可以在几台机器上完美运行(开发、QA、UAT)。不幸的是,在生产过程中,我在bmp.Save(ms, ImageFormat.Png);上收到了"GDI+中发生了一个通用错误"。因此,我认为你将无法重现这个问题,但也许有人可以发现我的错误。

注意,我已经搜索了很多常见的解决方案,注意这是保存到MemoryStream,所以大多数人建议的文件权限问题不适用,"打开时bmp被锁定"的解决方案也不适用,因为我在其他地方写。最后,这并不是因为png需要一个可查找的流,因为MemoryStream是可查找的。

注意,如果我将其更改为ImageFormat.Jpeg,它会正常工作。我只是对PNG有问题。我发现提到的注册表项HKEY_CLASSES_ROOT'CLSID'{FAE3D380-FEA4-4623-8C75-C6B61110B681}可能是由于权限而导致的问题。因此,我将密钥设置为允许Everyone对该密钥进行读取访问,没有任何更改。

public static MemoryStream GenerateImage(string text)
{
    MemoryStream ms = new MemoryStream();
    using (Bitmap bmp = new Bitmap(400,400))
    {
        bmp.Save(ms, ImageFormat.Png);
        ms.Position = 0;
    }
    return ms;
}

这是完整的堆栈跟踪:

[ExternalException(0x80004005):GDI+中发生一般错误。]
System.Drawing.Image.Save(流流,ImageCodecInfo编码器,编码器参数编码器参数)+616457
WP.Tools.Img.GenerateImage(字符串文本)+383

注:我的问题已经列举了拟议副本中的解决方案。没有问题。如果是这样的话,JPEG也会失败。

将位图保存到MemoryStream时,GDI+中出现一般错误

这里的.NET引用源代码,在保存到流的情况下,从对本机方法GdipSaveImageToStream的调用中获取状态值:

public void Save(Stream stream, ImageCodecInfo encoder, EncoderParameters encoderParams) {
    ...
    if (!saved)
    {
        status = SafeNativeMethods.Gdip.GdipSaveImageToStream(new HandleRef(this,nativeImage),new UnsafeNativeMethods.ComStreamFromDataStream(stream),ref g,new HandleRef(encoderParams, encoderParamsMemory));
    }
    ...
}

此状态值是用于从该方法引发异常的唯一API返回值。当我们进一步研究StatusException函数时,它根据状态代码决定抛出哪种异常,我们只发现一个可能的状态值会导致您得到的ExternalException(来自Gdiplus.cs,第3167行):

switch (status)
{
    case GenericError:
        return new ExternalException(SR.GetString(SR.GdiplusGenericError), E_FAIL);
    ...
}

0x80004005是"未指定的错误",而SR.GdiplsGenericError是您得到的文本"在GDI+中发生了一个通用错误"。这排除了我们可能怀疑的其他几种可能性(这将导致不同的例外),即:

  • 内存不足
  • 对象正忙
  • 缓冲区不足
  • win32错误
  • 值溢出
  • unknownimageformat
  • 找不到/不支持属性
  • 不支持的双重版本

本机方法位于gdiplus.dll中。长话短说,请修补生产服务器,修复.NET框架。更多详细信息:

  1. 比较%windir%''system32中已知良好机器和生产机器之间的dll版本。dll有数百个依赖项,因此即使文件本身的版本匹配,请参阅以修补您的操作系统
  2. PNG格式的内置编解码器是windows的WIC组件的一部分,位于WindowsCodecs.dllWindowsCodecsExt.dll-同时检查这些库的版本。您提到的注册表项也应该指向WindowsCodecsExt.dll
  3. 不是基于研究,只是想法:您是否通过虚拟化/远程桌面连接访问生产服务器?如果可以的话,请尝试控制台会话。尝试不同的屏幕分辨率和颜色深度。尝试调试/发布版本。确保您确实已经清除了发布版本配置中的DEBUG检查。尝试生成x64和MSIL。如果您在生产中使用NGEN,请尝试不使用