GDI +,JPEG图像到MemoryStream中发生一般错误


326

这似乎是整个网络上的一个臭名昭著的错误。如此之多,以致于我的情况不适合我,因此无法找到解决问题的答案。当我将图像保存到流中时,将引发异常。

奇怪的是,这与png完美兼容,但是对于jpg和gif却给出了上述错误,这非常令人困惑。

那里最类似的问题与未经许可将图像保存到文件有关。具有讽刺意味的是,解决方案是在执行操作时使用内存流。

public static byte[] ConvertImageToByteArray(Image imageToConvert)
{
    using (var ms = new MemoryStream())
    {
        ImageFormat format;
        switch (imageToConvert.MimeType())
        {
            case "image/png":
                format = ImageFormat.Png;
                break;
            case "image/gif":
                format = ImageFormat.Gif;
                break;
            default:
                format = ImageFormat.Jpeg;
                break;
        }

        imageToConvert.Save(ms, format);
        return ms.ToArray();
    }
}

有关异常的更多详细信息。造成如此多问题的原因是缺乏解释:(

System.Runtime.InteropServices.ExternalException was unhandled by user code
Message="A generic error occurred in GDI+."
Source="System.Drawing"
ErrorCode=-2147467259
StackTrace:
   at System.Drawing.Image.Save(Stream stream, ImageCodecInfo encoder, EncoderParameters    encoderParams)
   at System.Drawing.Image.Save(Stream stream, ImageFormat format)
   at Caldoo.Infrastructure.PhotoEditor.ConvertImageToByteArray(Image imageToConvert) in C:\Users\Ian\SVN\Caldoo\Caldoo.Coordinator\PhotoEditor.cs:line 139
   at Caldoo.Web.Controllers.PictureController.Croppable() in C:\Users\Ian\SVN\Caldoo\Caldoo.Web\Controllers\PictureController.cs:line 132
   at lambda_method(ExecutionScope , ControllerBase , Object[] )
   at System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters)
   at System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters)
   at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters)
   at System.Web.Mvc.ControllerActionInvoker.<>c__DisplayClassa.<InvokeActionMethodWithFilters>b__7()
   at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func`1 continuation)
 InnerException: 

好的,我到目前为止已经尝试过。

  1. 克隆图像并进行处理。
  2. 检索该MIME的编码器,并将其与jpeg质量设置一起传递。



3
对我来说,问题在于该文件夹不存在。通过仅创建文件夹来修复。
hazjack

对我来说,这是一个超出范围的指标。
比利·杰克·奥康纳

Answers:


189

好的,我似乎只是由于运气而找到了原因,而该特定方法没有任何问题,它进一步备份了调用堆栈。

之前,我调整了图像的大小,并作为该方法的一部分,按如下所示返回了调整大小的对象。我已经插入了对上述方法的两个调用,并直接保存到文件中。

// At this point the new bitmap has no MimeType
// Need to output to memory stream
using (var m = new MemoryStream())
{
       dst.Save(m, format);

       var img = Image.FromStream(m);

       //TEST
       img.Save("C:\\test.jpg");
       var bytes = PhotoEditor.ConvertImageToByteArray(img);


       return img;
 }

似乎在其上创建对象的内存流具有是在保存对象时打开。我不确定为什么会这样。有谁能启发我以及如何解决这个问题。

我只从流返回,因为在使用类似于 ,目标文件具有未知的mime类型(img.RawFormat.Guid),并且Id希望Mime类型在所有图像对象上都是正确的,因为它使很难写通用否则处理代码。

编辑

这不是我最初的搜索时出现的,但这乔恩·斯凯特(Jon Skeet)的回答


4
我没有意识到,当您从内存流中获取位图时,您不应关闭该流。非常有帮助,谢谢
mcdon

38
谢谢。这可能节省了我的头发。
NotMe 2010年

6
谢谢!这为我节省了很多时间,但有一件事情,您能介意在答案的开头强调错误的原因,因为我(而且我想大多数人都这么说)在答案中遗漏了原始内容,例如如果您打算再次使用该图像,请不要关闭存储空间”,这是很好的选择; D
DorD 2012年

6
什么是您的“ dst”变量?
WEFX

1
@madcapnmckay请说明“ dst”变量是什么及其含义
Mike T

131

如果出现该错误,那么我可以说您的应用程序对某个目录没有写许可权。

例如,如果您尝试将映像从内存流保存到文件系统,则可能会收到该错误。

如果您使用的是XP,请确保在该文件夹上为aspnet帐户添加写权限。

如果使用Windows Server(2003,2008)或Vista,请确保为网络服务帐户添加写权限。

希望它能帮助一些人。


7
你没有!我被该死的写许可权浪费了2个小时...来到这里发表。希望您能获得更多的支持。:)
Gleno

2
这是我的解决方案。总共+1!
Grandizer

5
保存位图之前,可以先执行File.WriteAllText(“ filename.jpg”,“”),然后执行File.DeleteFile(“ filename.jpg”)。在我的Benmark中,这只需要0.01秒,您会得到一个不错的“您无权在其中保存filename.jpg”
Despertar 2012年

@Despertar您的意思是File.Delete(),但这是一个非常方便的技巧!绝对要在保存位图时使用它。
D Coetzee

2
就我而言,该目录不存在。
静默消息2015年

54

我还将添加此错误原因,希望它对将来的互联网旅行者有所帮助。:)

GDI +将图片的最大高度限制为65500

我们进行一些基本的图像大小调整,但是在调整大小时,我们尝试保持宽高比。我们有一个QA专家,他在这项工作上有点太出色了;他决定用一张480像素高的1像素宽的照片进行测试。当图像按比例缩放到适合我们的尺寸时,高度在68,000像素以北,并且我们的应用爆炸了A generic error occurred in GDI+

您可以通过测试自己验证:

  int width = 480;
  var height = UInt16.MaxValue - 36; //succeeds at 65499, 65500
  try
  {
    while(true)
    {
      var image = new Bitmap(width, height);
      using(MemoryStream ms = new MemoryStream())
      {
        //error will throw from here
        image.Save(ms, ImageFormat.Jpeg);
      }
      height += 1;
    }
  }
  catch(Exception ex)
  {
    //explodes at 65501 with "A generic error occurred in GDI+."
  }

太糟糕了,ArgumentException在的构造函数中没有抛出友好的.net Bitmap


17
谢谢-这位互联网时间旅行者非常感谢您留下此信息。
汤姆·韦斯特

根据我的测试,65535实际上是最大值。在65536,我开始看到一般错误。
ChaseMedallion

只需再试一次:Win10 .net 4.5和.net 4.6.1,它以65501爆炸,似乎更加随机。代码也充满语法错误,将会更新:)
Fred

37

本文详细解释了实际发生的情况:位图和图像构造函数的依赖关系

简而言之,在Image构造的生命周期中,不得破坏该流。

所以,代替

using (var strm = new ... )  {
    myImage = Image.FromStream(strm);
}

尝试这个

Stream imageStream;
...

    imageStream = new ...;
    myImage = Image.FromStream(strm);

并在窗体关闭或网页关闭时关闭imageStream


是的,这个救了我。我一直很谨慎,将流包装在中using,然后尝试将图像复制到内存流中,并收到了可怕的“ GDI +中的通用错误”消息。
阿普尔比

您的链接给了我无限的重定向;这个作品。我在存钱方面遇到了问题,PixelFormat.Format32bppArgb但没有PixelFormat.Format1bppIndexed。您链接的文章解释了原因:GDI +可能选择重新解码源流中的位图数据,而不是将所有内容保留在内存中。我的猜测是它不会重新解码1bpp图像。
labreuer17年

即使是新的链接也不再起作用。一个简单的Google搜索似乎并未显示正确的页面。但是我很高兴找到这个答案!由于这个问题,
Katjoek

28

如果您尝试保存到无效路径或存在权限问题,也会收到此异常。

如果您不是100%确定文件路径可用且权限正确,请尝试将a写入文本文件。只需几秒钟即可排除掉什么是非常简单的修复程序。

var img = System.Drawing.Image.FromStream(incomingStream);

// img.Save(path);
System.IO.File.WriteAllText(path, "Testing valid path & permissions.");

并且不要忘记清理文件。


这对我来说是个问题...我希望错误不那么模糊,可以为我节省很多时间。
Oofpez,2012年

是! 保存到的文件夹必须存在。现在,在尝试保存图像之前,我先对此进行检查。(仍然,该错误使我大约每年一次。)
Magnus Smith,

我的路径是目录,而不是文件。
阿森·卡西莫夫

20

将图像保存到位图变量

using (var ms = new MemoryStream())
{
    Bitmap bmp = new Bitmap(imageToConvert);
    bmp.Save(ms, format);
    return ms.ToArray();
}

这解决了我的问题。您能解释一下为什么将图像保存到位图会吓跑异常吗?
jmc 2015年

拯救了我的一天..不知道是什么原因引起的,但是位图保存有效。.System.Drawing.Image不会保存到内存流,但是位图可以保存!

这对我来说是最好的解决方案。创建新的位图并进行转换。
uzay95 '18

17

以防万一有人像我一样愚蠢。1.确保路径确实存在。2.确保您具有写权限。3.确保您的路径正确,在我的情况下,我在TargetPath中缺少文件名:(

应该说,您的路径比“ GDI +中发生一般错误”糟透了


16

保存JPEG时也会出现此错误,但仅适用于某些图像。

我的最终代码:

  try
  {
    img.SaveJpeg(tmpFile, quality); // This is always successful for say image1.jpg, but always throws the GDI+ exception for image2.jpg
  }
  catch (Exception ex)
  {
    // Try HU's method: Convert it to a Bitmap first
    img = new Bitmap(img); 
    img.SaveJpeg(tmpFile, quality); // This is always successful
  }

我没有创建图像,所以我不知道有什么区别。
如果有人可以解释,我将不胜感激。

这是我的SaveJpeg函数,仅供参考:

private static void SaveJpeg(this Image img, string filename, int quality)
{
  EncoderParameter qualityParam = new EncoderParameter(Encoder.Quality, (long)quality);
  ImageCodecInfo jpegCodec = GetEncoderInfo("image/jpeg");
  EncoderParameters encoderParams = new EncoderParameters(1);
  encoderParams.Param[0] = qualityParam;
  img.Save(filename, jpegCodec, encoderParams);
}

private static ImageCodecInfo GetEncoderInfo(string mimeType)
{
    var encoders = ImageCodecInfo.GetImageEncoders();
    var encoder = encoders.SingleOrDefault(c => string.Equals(c.MimeType, mimeType, StringComparison.InvariantCultureIgnoreCase));
    if (encoder == null) throw new Exception($"Encoder not found for mime type {mimeType}");
    return encoder;
}

1
这解决了头发拉扯的日子。这是我认为我写过的最多的wtf代码:)
杰夫·邓洛普

13

我发现,如果我要保存文件的父文件夹之一具有尾随空格,则GDI +会抛出通用异常。

换句话说,如果我尝试保存到“ C:\ Documents and Settings \ myusername \ Local Settings \ Temp \ ABC DEF M1 Trended Values \ Images \ picture.png”,则会引发一般异常。

我的文件夹名称是由恰好具有尾随空格的文件名生成的,因此.Trim()可以轻松继续。


3
太棒了-我从没想过要仔细看一下目录路径
jharr100 2014年

11

如果您的代码如下,则也会发生此错误

private Image GetImage(byte[] byteArray)
{
   using (var stream = new MemoryStream(byteArray))
   {
       return Image.FromStream(stream);
    }
}

正确的是

private Image GetImage(byte[] byteArray)
{
   var stream = new MemoryStream(byteArray))
   return Image.FromStream(stream);        
}

这可能是因为我们正在从using块返回


对我来说,这是using块中的返回。我仍然使用using,但我在块外返回了值。谢谢!
Dragouf,2010年

1
我发现“困难的方式”是,如果您再次将Image保存到新的Stream(例如HttpContext.Response.OutputStream)中,则还需要执行stream.Flush(),否则将发生错误。再次。
Lucian

11

这是对Fred的回应的扩展/限定,其中指出:“ GDI将图片的高度限制为65534”。我们在其中一个.NET应用程序中遇到了这个问题,看到这个帖子后,我们的外包团队举起了手,说如果没有重大更改,他们将无法解决问题。

根据我的测试,可以创建/处理高度大于65534的图像,但是在将其保存到“ 某些格式”中的流或文件时会出现问题。在以下代码中,当我的像素高度为65501时,t.Save()方法调用将向我们的朋友抛出通用异常。出于好奇的原因,我重复测试宽度,并对保存使用相同的限制。

    for (int i = 65498; i <= 100000; i++)
    {
        using (Bitmap t = new Bitmap(800, i))
        using (Graphics gBmp = Graphics.FromImage(t))
        {
            Color green = Color.FromArgb(0x40, 0, 0xff, 0);
            using (Brush greenBrush = new SolidBrush(green))
            {
                // draw a green rectangle to the bitmap in memory
                gBmp.FillRectangle(greenBrush, 0, 0, 799, i);
                if (File.Exists("c:\\temp\\i.jpg"))
                {
                    File.Delete("c:\\temp\\i.jpg");
                }
                t.Save("c:\\temp\\i.jpg", ImageFormat.Jpeg);
            }
        }
        GC.Collect();
    }

如果写入内存流,也会发生相同的错误。

为了解决这个问题,您可以重复上面的代码,并用ImageFormat.Tiff或ImageFormat.Bmp代替ImageFormat.Jpeg。

对我来说,这高达100,000的高度/宽度-我没有测试极限。碰巧。Tiff对我们来说是一个可行的选择。

被警告

内存中TIFF流/文件比JPG对应文件消耗更多的内存。


10

遇到了非常类似的问题,还尝试了克隆不起作用的映像。我发现最好的解决方案是根据从内存流中加载的图像创建一个新的Bitmap对象。这样,流可以被处理掉,例如

using (var m = new MemoryStream())
{
    var img = new Bitmap(Image.FromStream(m));
    return img;
}

希望这可以帮助。


6

由于权限而发生错误。确保文件夹具有“所有权限”。

public Image Base64ToImage(string base64String)
    {
        // Convert Base64 String to byte[]
        byte[] imageBytes = Convert.FromBase64String(base64String);
        MemoryStream ms = new MemoryStream(imageBytes, 0,
          imageBytes.Length);

        // Convert byte[] to Image
        ms.Write(imageBytes, 0, imageBytes.Length);
        Image image = Image.FromStream(ms, true);
        return image;
    }

 img.Save("YOUR PATH TO SAVE IMAGE")

我同意你。我用PERMISSION解决了这个问题
-praguan

5

已解决-我遇到了这个确切的问题。对我来说,解决方法是增加IIS服务器上IUSR的磁盘配额。在这种情况下,我们有一个包含项目图像等的目录应用程序。“匿名Web用户”的上传配额设置为100MB,这是该特定托管公司的IIS服务器的默认配额。我将其增加到400MB,并能够无误上传图像。

这可能不是您的问题,但是如果是这样,这很容易解决。


4

就我而言,问题出在我要保存的路径(root C:\)中。对其进行更改以D:\111\使异常消失。


4

导致此错误的另一个原因-您在位图实例的Save方法中指定的路径不存在,或者您没有提供完整/有效的路径。

发生此错误是因为我传递的是文件名而不是完整路径!

它发生了!


4

轮到我了!

using (System.Drawing.Image img = Bitmap.FromFile(fileName))
{
      ... do some manipulation of img ...
      img.Save(fileName, System.Drawing.Imaging.ImageFormat.Jpeg);
}

将其放在.Save ...上,因为using()使文件保持打开状态,所以我无法覆盖它。也许这会在将来对某人有所帮助。


4

我面临着同样的问题。但就我而言,我试图将文件保存在C驱动器中,并且无法访问。因此,我尝试将其保存在完全可访问的D驱动器中,并成功了。

因此,首先检查您要保存在其中的文件夹。您必须具有该特定文件夹的所有(读取和写入)权限。


原因通常c未经管理员许可是不允许的。
Aneeq Azam Khan

2

我注意到您的“ jpeg”案实际上是:

            default:
                format = ImageFormat.Jpeg;
                break;

您确定格式为jpeg而不是其他格式吗?

我会尝试:

            case "image/jpg": // or "image/jpeg" !
                format = ImageFormat.Jpeg;
                break;

或检查imageToConvert.MimeType()实际返回的内容。

更新

您还需要对MemoryStream对象进行其他初始化吗?


谢谢。绝对是用正确的格式调用它。我加载jpg,进行调试并确认mime被识别为image / jpeg,格式为JPG。
madcapnmckay

3
哦,好吧-我总是尽力消除明显的缺点。我数不完的次数不多,后来又回来咬我。
ChrisF

2
  • 我在测试服务器上遇到了这个问题,但在实时服务器上却没有。
  • 我正在将图像写入流,因此这不是权限问题。
  • 我一直在直接将某些.dll部署到测试服务器。
  • 部署整个解决方案解决了该问题,因此可能是奇怪的编译不匹配

2

只是为了提出另一种可能的解决方案,我将提到遇到此错误消息的情况。Bitmap.Save保存已转换并显示的位图时,该方法将引发此异常。我发现如果语句上有一个断点,它不会引发异常,如果该语句前面有一个断点,也不会引发异常Bitmap.SaveThread.Sleep(500)因此,我认为正在进行某种资源争用。

只需将图像复制到新的Bitmap对象就足以防止出现此异常:

new Bitmap(oldbitmap).Save(filename);

2

PDF在生产服务器上使用ImageProcessor lib 生成图像或调整图像大小时,我们遇到了类似的问题。

回收应用程序池可解决此问题。


1

如果尝试将图像保存到远程位置,请确保将NETWORK_SERVICE用户帐户添加到安全设置中,并授予该用户读写权限。否则它将无法正常工作。


1
byte[] bts = (byte[])page1.EnhMetaFileBits; 
using (var ms = new MemoryStream(bts)) 
{ 
    var image = System.Drawing.Image.FromStream(ms); 
    System.Drawing.Image img = image.GetThumbnailImage(200, 260, null, IntPtr.Zero);      
    img.Save(NewPath, System.Drawing.Imaging.ImageFormat.Png);
}


1

简单,创建一个新的Bitmap实例即可解决该问题。

string imagePath = Path.Combine(Environment.CurrentDirectory, $"Bhatti{i}.png");
Bitmap bitmap = new Bitmap(image);
bitmap.Save(imagePath);

0

对我来说,我在使用Image.Save(Stream, ImageCodecInfo, EncoderParameters),显然这是导致臭名昭著的A generic error occurred in GDI+错误。

我试图用来EncoderParameter以100%的质量保存jpeg。这在“我的机器”(doh!)上完美运行,而不在生产上。

当我使用Image.Save(Stream, ImageFormat)代替时,错误消失了!因此,像白痴一样,我继续使用后者,尽管它可以将它们保存为默认质量(我认为仅为50%)。

希望此信息对某人有帮助。


0

我也遇到了问题。问题是由于处理了装载流。但是我没有处理它,它在.Net框架内。我所要做的就是使用:

image_instance = Image.FromFile(file_name);

代替

image_instance.Load(file_name);

image_instance是System.Windows.Forms.PictureBox类型!PictureBox的Load()处理从中加载图像的流,但我不知道。


0

根据@savindra的回答,如果您在应用程序上进行RHM并尝试以管理员身份运行,那么它应该可以解决您的问题。

我的似乎是一个许可问题。


0

导致这种错误的可能问题是:

  1. 目录不存在(您调用的方法不会自动为您创建此目录)
  2. 写入输出目录的安全权限不允许运行该应用程序的用户写入

我希望这会有所帮助,这是解决我的问题的方法,我只是在保存输出图像之前确保输出目录存在!

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.