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

奇怪的是,此样式与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: 


到目前为止我已经尝试过的事情。


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


评论

相关:stackoverflow.com/questions/4671449/…

stackoverflow.com/questions/1053052/…

对我来说,问题在于该文件夹不存在。只需创建文件夹即可修复。

对我来说,这是一个超出范围的指标。

#1 楼

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

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

// 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),并且像Mime类型的ID在所有图像上都是正确的对象,因为否则很难编写通用处理代码。

编辑

这不是我最初的搜索所想的,但这是Jon Skeet的回答

评论


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

– mcdon
2010-09-24 23:04

谢谢。这可能节省了我的头发。

–NotMe
10-10-8在21:26

谢谢!这虽然节省了我很多时间,但有一件事情,您能介意在答案的开头强调错误的原因,因为我(而且我想大多数人都这么说)在答案的原始内容中错过了它,例如“如果您打算再次使用该图像,请不要关闭内存流”;

–DorD
2012年8月27日在6:46

您的“ dst”变量是什么?

– WEFX
15年5月14日在21:05

@madcapnmckay请解释“ dst”变量是什么及其含义

– Mike T
2015年12月8日,2:14

#2 楼

如果遇到该错误,那么我可以说您的应用程序对某个目录没有写权限。例如,如果您尝试将图像从内存流保存到文件系统,则可能会出现该错误。

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

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

希望对您有所帮助。

评论


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

–Gleno
2012年7月23日在23:22

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

–增白剂
2012年9月19日15:09

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

– Despertar
2012年10月6日,0:45

就我而言,该目录不存在。

–silencedmessage
2015年9月13日20:30在

当我发现它就像@Jonathan一样在使用中时,我正在更改权限。创建映像的程序尚未释放锁定。我最终保存到一个新文件,而不是重写原始文件。

– astrosteve
10月27日19:41

#3 楼

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

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

我们进行一些基本的图像大小调整,但是在调整大小时,我们尝试保持宽高比。我们有一个质量检查人员,在这项工作上有点太出色了;他决定用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

评论


谢谢-这位互联网时间旅行者非常感谢您留下此信息。

–汤姆·韦斯特
2011-11-30 17:16

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

–ChaseMedallion
17年1月13日在13:46



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

–弗雷德
17年1月18日在18:01

#4 楼

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

简而言之,对于从流中构造的Image的生命周期,必须不破坏该流。

所以,而不是

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


试试这个

Stream imageStream;
...

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


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

评论


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

–爱普比会
17年1月1日于20:32

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

– labreuer
17年3月3日在4:20

即使是新的链接也不再起作用。一个简单的Google搜索似乎并未显示正确的页面。但是我很高兴找到这个答案!由于此问题,我通过复制到新位图的解决方法失败

– Katjoek
19 Mar 1 '19 at 15:58



#5 楼

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

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

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

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


不要忘了清理文件。

评论


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

– Oofpez
2012年8月22日上午9:33

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

– Magnus Smith
18年1月12日在8:16

我的路径是目录,而不是文件。

–阿森·卡西莫夫(Asen Kasimov)
19年1月30日14:27



很棒的把戏,对我有帮助

– Mohd Faizan
12月2日22:09

#6 楼

将图像保存到位图变量

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


评论


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

– jmc
2015年4月1日下午5:53

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

–圣
17年4月3日在16:33



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

– uzay95
18 Mar 22 '18 at 19:31

我知道这篇文章很旧,但是我想让您知道这使我免于扯掉所有头发!大声笑

–纤细的Fuchsbau
7月22日20:36

#7 楼

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

它应该说,您的路径比“ GDI +中发生一般错误”更糟糕。

#8 楼

保存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;
}


评论


这解决了头发拉扯的日子。这是我认为我写过的最多的wtf代码:)

–杰夫·邓洛普(Jeff Dunlop)
16-10-17在12:35

#9 楼

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

换句话说,如果我尝试保存到“ C:\ Documents和Settings \ myusername \ Local Settings \ Temp \ ABC DEF M1趋势值\ Images \ picture.png”,则引发了一般性异常。

我的文件夹名称是由碰巧出现的文件名生成的有一个尾随空格,因此很容易.Trim()继续前进。

评论


太棒了-我再也没想过要仔细查看目录路径

– jharr100
2014年5月23日20:05

#10 楼

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

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
10-11-18在10:43

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

– Lucian
2011年3月18日在14:51

#11 楼

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

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


希望有帮助。

#12 楼

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

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

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

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

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

被警告

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

#13 楼

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

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
18年5月5日23:08

#14 楼

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

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

#15 楼

就我而言,问题出在我要保存的路径(根目录C:\)中。将其更改为D:1\使异常消失。

#16 楼

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

因为我正在传递而出现了此错误在文件名而不是完整路径中!

发生了!

#17 楼

轮到我了!

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


将其保存在.Save ...上,因为using()使文件保持打开状态,所以我不能覆盖它。也许这会对以后的人有所帮助。

#18 楼

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

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

评论


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

–Aneeq Azam Khan
18年6月9日在8:23

#19 楼

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

            default:
                format = ImageFormat.Jpeg;
                break;


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

我尝试:

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


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

UPDATE

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

评论


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

– madcapnmckay
2009年6月27日15:58

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

–ChrisF♦
09-6-27 at 16:02

#20 楼


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


#21 楼

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

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

new Bitmap(oldbitmap).Save(filename);


#22 楼

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

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


#23 楼

导致此错误并解决我的问题的另一个原因是您的应用程序对某个目录没有写权限。

因此,请完成savindra的答案:https://stackoverflow.com/ a / 7426516/6444829。

这里是向IIS_IUSERS授予文件访问权限的方式

要提供对ASP.NET应用程序的访问,必须授予对IIs_IUSERS的访问权限。 br />
要授予对特定文件或文件夹的读取,写入和修改权限,请执行以下操作:在Windows资源管理器中,找到并选择所需的文件。
右单击文件,然后单击属性。
在“属性”对话框中,单击“安全性”选项卡。
在“安全性”选项卡上,检查用户列表。
(如果您的应用程序作为网络服务运行,请在列表中添加网络服务帐户并为其授予权限。
在“属性”对话框中,单击“ IIs_IUSERS”,然后在“网络服务的权限”部分中,选择“读取”,“写入”和“修改”权限。
单击“应用”,然后单击“确定”。 />

#24 楼

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

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

#25 楼

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

#26 楼

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


#27 楼

我也收到此错误,因为我正在尝试使用与以前保存的图像相同的名称保存图像。

请确保您不保存具有重复名称的图像。

例如用于“随机”函数(C#的随机数生成器如何工作?)
,例如用于生成Guid(http://betterexplained.com/articles/the-quick-guide-to- guids /)

#28 楼

在我的情况下,路径错误
只需使用此
String path = Server.MapPath("~/last_img.png");//Path


#29 楼

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

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

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

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

#30 楼

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

image_instance = Image.FromFile(file_name);


而不是

image_instance.Load(file_name);


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