在GDI +,JPEG Image到MemoryStream中发生一般性错误

这似乎是一个臭名昭着的错误在整个网络上。 因为我的情况不适合,所以我一直无法找到我的问题的答案。 将图像保存到流中时引发异常。

奇怪的是,这与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. 为jpeg质量设置传回那个MIME的编码器。

好吧,我似乎已经找到了原因,只是运气好,它没有错,特定的方法,它进一步支持调用堆栈。

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

 // 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类型一样对所有图像对象都是正确的,因为它使得它难以写入通用否则处理代码。

编辑

这并没有出现在我最初的搜索,但这是 Jon Skeet的答案

如果你得到这个错误,那么我可以说你的应用程序在某个目录上没有写权限。

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

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

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

希望它有助于一个人。

我会添加这个错误的原因,希望它可以帮助一些未来的互联网旅行者。 🙂

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

我们做一些基本的图像调整大小,但在调整大小,我们尝试保持高宽比。 我们有一个质量保证人员,在这项工作上有点太棒了。 他决定用480像素高的ONE像素宽的照片来测试。 当图像缩放以符合我们的尺寸时,高度为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+." } 

这太糟糕了,没有一个友好的.net ArgumentException引发的Bitmap的构造函数。

本文详细解释了究竟发生了什么: 位图和图像构造函数的依赖关系

简而言之,对于从流中构建的Image的生命周期,流必须不被销毁。

所以,而不是

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

尝试这个

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

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

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

如果您不能100%确定文件路径可用并且权限正确,那么请尝试写入文本文件。 这只需要几秒钟就可以排除什么是一个非常简单的修复。

 var img = System.Drawing.Image.FromStream(incomingStream); // img.Save(path); System.IO.File.WriteAllText(path, "Testing valid path & permissions."); 

不要忘记清理你的文件。

这是弗雷德答复的扩展/限定:“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。

这对我来说高达10万的宽度 – 我没有测试极限。 事实上,蒂芙对我们来说是一个可行的选择。

被警告

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

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

换句话说,如果我试图保存到“C:\ Documents and Settings \ myusername \ Local Settings \ Temp \ ABC DEF M1 Trended Values \ Images \ picture.png”,那么它会抛出一般异常。

我的文件夹名是从一个文件名产生的,碰巧有一个尾随的空间,所以很容易.Trim(),并继续前进。

将图像保存到位图变量

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

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

这可能是因为我们从使用块返回

有一个非常类似的问题,也试图克隆不起作用的图像。 我发现最好的解决方案是从内存流中加载的图像创建一个新的Bitmap对象。 这样的流可以被丢弃,例如

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

希望这可以帮助。

解决 – 我有这个确切的问题。 对我来说,修正是为IIS服务器上的IUSR增加磁盘配额。 在这种情况下,我们有一个目录应用程序与项目等图像。 “匿名网络用户”的上传限额设置为100MB,这是此特定托管公司的IIS服务器的默认值。 我把它升高到400MB,并能够无误地上传图像。

这可能不是你的问题,但如果是这样,这是一个简单的修复。

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

应该说,你的路径比“GDI +中发生的一般错误”

在我的情况下,问题是在我保存的路径(根C:\ )。 将其更改为D:\111\使例外消失。

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

只是有这个错误,因为我传入一个文件名,而不是一个完整的路径!

发生了!

轮到我了!

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

在.Save上得到它,因为using()是打开文件,所以我不能覆盖它。 也许这将有助于未来的人。

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

 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") 

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

  default: format = ImageFormat.Jpeg; break; 

你确定这个格式是jpeg而不是别的吗?

我会尝试:

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

或者检查imageToConvert.MimeType()实际上是否返回。

UPDATE

是否有任何其他初始化你需要做的MemoryStream对象?

为了抛出另一个可能的解决方案,我会提到遇到这个错误消息的情况。 方法Bitmap.Save会通过这个例外保存一个位图,我已经转换,并正在显示。 我发现它不会抛出异常,如果语句有一个断点,也不是如果Bitmap.SaveThread.Sleep(500)所以我认为是有某种资源争夺进行。

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

 new Bitmap(oldbitmap).Save(filename); 

如果您尝试将图像保存到远程位置,请确保将NETWORK_SERVICE用户帐户添加到安全设置中,并为该用户提供读取和写入权限。 否则,它不会工作。

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

我也得到这个错误,因为我试图保存与以前保存的图像相同的名称的图像。

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

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

  • 我在测试服务器上遇到了这个问题,但不在活动服务器上。
  • 我正在写图像到一个流,所以这不是一个权限问题。
  • 我一直在直接部署一些.dll的测试服务器。
  • 部署整个解决方案解决了这个问题,所以这可能是一个奇怪的编译不匹配

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

我试图使用EncoderParameter保存在100%质量的JPEG。 这是完美的“我的机器”(doh!),而不是生产。

当我使用Image.Save(Stream, ImageFormat)代替时,错误消失了! 所以就像一个白痴,我继续使用后者,尽管它保存在默认的质量,我认为只是50%。

希望这个信息有助于某人。

我也遇到了这个问题。 问题是由于装载流被处置。 但是我没有把它放置在.Net框架里面。 我所要做的就是使用:

 image_instance = Image.FromFile(file_name); 

代替

 image_instance.Load(file_name); 

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

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

我似乎是一个权限问题。

我面对同样的问题。 但在我的情况下,我试图保存在C盘中的文件,它不可访问。 所以我试图保存在D盘,这是完全可以访问,我成功了。

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