GDI+发生了通用错误,位于System.Drawing.Image.Save。

33

异常:

GDI+ 中发生了一般错误。 在 System.Drawing.Image.Save(String filename, ImageCodecInfo encoder, EncoderParameters encoderParams) 中 在 System.Drawing.Image.Save(String filename, ImageFormat format) 中 在 System.Drawing.Image.Save(String filename) 中

代码:

byte[] bitmapData = new byte[imageText.Length];
MemoryStream streamBitmap;
bitmapData = Convert.FromBase64String(imageText);
streamBitmap = new MemoryStream(bitmapData);
System.Drawing.Image img = Image.FromStream(streamBitmap);
img.Save(path);

我们将base64字符串转换为MemoryStream,然后创建一个System.Drawing.Image(Image.FromStream(streamBitmap))。 最后,图像保存在临时文件中。

奇怪的是,在Web服务器上活动(并发用户数量)高时似乎会出现问题,而在进行IISRESET或应用程序池回收后问题暂时得到解决...

==> 垃圾收集器问题?

我已经检查了TEMP文件夹的权限...

7个回答

32

当您从流中加载图像时,必须在图像的生命周期内保持该流处于打开状态。请参阅此MSDN Image.FromStream

我认为异常是因为内存流在图像被处理之前被关闭了。您可以将代码更改为:

byte[] bitmapData = new byte[imageText.Length];
bitmapData = Convert.FromBase64String(imageText);

  using (var streamBitmap = new MemoryStream(bitmapData))
  {
      using (img = Image.FromStream(streamBitmap))
      { 
         img.Save(path);
      }
  }

以下是一些讨论类似问题的主题链接:

gdi+ 保存网页图像错误

绘制图像时出现 System.Runtime.InteropServices.ExternalException: A generic error occurred in GDI 错误


好的,谢谢!我会实现这个更改并进行进一步的测试。 - Razor
3
因为有人删除了我与这个被接受答案相关的补充回答,所以我要补充一下。 如果你发现GDI错误在一段时间后会被抛出,以下是如何确认它是由于泄漏GDI内存而引起异常。 当程序泄漏10,000个句柄时,Windows将不再提供更多。你可以使用TaskMgr.exe来诊断这些类型的泄漏。单击进程选项卡,在列上右键单击并选择添加GDI对象列。如果GDI对象持续增加,那么你就有一个GDI内存泄漏。 - rboy

18

确保您指定的路径是有效的。使用先前的答案(在内存流上使用)仍然可能会出现此精确错误“GDI+中的通用错误”,如果文件路径不存在。文件将被创建,目录路径必须存在。


2
这个真的帮了我很多。在我的情况下,同样的错误是因为路径错误引起的。谢谢。 - Mathew Markose

3

当我保存图片时,遇到了同样的异常消息。结果发现我的代码没有问题,正在执行它应该做的事情。

问题是硬盘已满,因此无法创建新图像。只有在尝试保存我正在工作的项目时才注意到这一点,因为它没有足够的空间来保存。


1
在我的情况下,事实证明我的IIS应用程序池用户没有对该目录的写入权限。只是想在这里添加一条注释,因为这个答案是一个类似的问题。 - Brent Keller
2015年如何让硬盘充满? - Rafael Ventura
@RafaelVentura,我的朋友,在虚拟机中很容易。 - Bart Vanseer

2
我之所以遇到错误,是因为我要保存图像的文件夹不存在。而且image.Save(string path)不会自动创建文件夹。因此,您需要在程序中创建该文件夹。
if (Directory.Exists(folderToUpload) == false)
{
    Directory.CreateDirectory(folderToUpload);
}

然后您应该能够将图像保存到所需位置。

2
在我的情况下,以下代码片段有效,其中ConvertedImageString是从API接收到的Base64Image字符串,我将其转换为相关格式的图像,并将其保存到服务器上的物理文件夹中。 编辑:以上错误可能是因为您尝试保存图像的文件路径不正确。
string converted = ConvertedImageString.Replace('-', '+');
converted = converted.Replace('_', '/');
using (MemoryStream ms = new MemoryStream(Convert.FromBase64String(ConvertedImageString)))
{
    using (Bitmap bm1 = new Bitmap(ms))
    {
        newFileName =  id + ".jpg";
        newFileName = CleanFileName(newFileName);
        newFileName = newFileName.Replace(" ", "_");

        Path = Path + newFileName;

        bm1.Save(Path, ImageFormat.Jpeg);
    }
}

在上面的代码中,变量 i 接收图像的 BASE64 转换后的字符串,并将其以“联合摄影专家组”格式存储在 IIS 目录或网站目录中。就是这样。 - Prashant Pimpale
1
把这个放在你的答案里! - Sanket Makani

1

当调用 "Image.FromFile" 或 "Image.Save" 时,图像对象将锁定文件,直到其被显式释放。如果对同一文件名执行另一个 "Image.Save" 或 "Image.FromFile" 操作,则可能会出现 "通用错误" 异常。这取决于垃圾收集器是否已释放了该图像,因此结果是不一致的。

如果在 "Save" 操作后不需要该图像,则应立即释放它。如果确实需要该图像,则 Image.Clone 将创建一个不锁定源文件的副本。

我在一个图像库编辑应用程序中遇到过这个问题,而这就是解决方案。


0

这个错误是由于图像已经在使用中。无论您在哪里使用图像,都将图像转换为字符串 base 64 格式并使用它。这将解决该错误。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接