GDI+、JPEG 图像到 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:
到目前为止我已经尝试过的事情。
- 克隆图像并进行处理。
- 检索该 MIME 的编码器,通过 jpeg 质量设置传递该编码器。
This seems to be a bit of an infamous error all over the web. So much so that I have been unable to find an answer to my problem as my scenario doesn't fit. An exception gets thrown when I save the image to the stream.
Weirdly this works perfectly with a png but gives the above error with jpg and gif which is rather confusing.
Most similar problem out there relate to saving images to files without permissions. Ironically the solution is to use a memory stream as I am doing....
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();
}
}
More detail to the exception. The reason this causes so many issues is the lack of explanation :(
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:
OK things I have tried so far.
- Cloning the image and working on that.
- Retrieving the encoder for that MIME passing that with jpeg quality setting.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(30)
好吧,我似乎纯粹是靠运气找到了原因,并且该特定方法没有任何问题,它进一步备份了调用堆栈。
早些时候,我调整了图像的大小,作为该方法的一部分,我返回调整大小的对象,如下所示。 我已插入对上述方法的两次调用并直接保存到文件。
看来在保存对象时必须打开创建该对象的内存流。 我不知道这是为什么。 有谁能够启发我以及我如何解决这个问题。
我只从流返回,因为使用类似于 this 的调整大小代码后目标文件有一个未知的 mime 类型 (img.RawFormat.Guid),并且我希望所有图像对象上的 Mime 类型都是正确的,因为否则很难编写通用处理代码。
编辑
这在我最初的搜索中没有出现,但是这是乔恩·斯基特的回答
OK I seem to have found the cause just by sheer luck and its nothing wrong with that particular method, it's further back up the call stack.
Earlier I resize the image and as part of that method I return the resized object as follows. I have inserted two calls to the above method and a direct save to a file.
It appears that the memory stream that the object was created on has to be open at the time the object is saved. I am not sure why this is. Is anyone able to enlighten me and how I can get around this.
I only return from a stream because after using the resize code similar to this the destination file has an unknown mime type (img.RawFormat.Guid) and Id like the Mime type to be correct on all image objects as it makes it hard write generic handling code otherwise.
EDIT
This didn't come up in my initial search but here's the answer from Jon Skeet
如果您收到该错误,那么我可以说您的应用程序没有对某些目录的写入权限。
例如,如果您尝试将图像从内存流保存到文件系统,您可能会收到该错误。
如果您使用的是 XP,请确保为该文件夹的 aspnet 帐户添加写权限。
如果您使用的是 Windows Server (2003、2008) 或 Vista,请确保为网络服务帐户添加写入权限。
希望它对某人有所帮助。
If you are getting that error , then I can say that your application doesn't have a write permission on some directory.
For example, if you are trying to save the Image from the memory stream to the file system , you may get that error.
Please if you are using XP, make sure to add write permission for the aspnet account on that folder.
If you are using windows server (2003,2008) or Vista, make sure that add write permission for the Network service account.
Hope it help some one.
我也会添加这个错误原因,希望它能帮助一些未来的互联网旅行者。 :)
GDI+ 将图像的最大高度限制为 65500
我们进行了一些基本的图像大小调整,但在调整大小时我们尝试保持宽高比。 我们有一个 QA 人员,他对这项工作有点太擅长了; 他决定用一张 1 像素宽、480 像素高的照片来测试这一点。 当图像缩放以满足我们的尺寸时,高度超出了 68,000 像素,我们的应用程序崩溃了,并显示
GDI+ 中发生一般错误
。您可以通过测试自行验证这一点:
遗憾的是,
Bitmap
的构造函数中没有抛出友好的 .netArgumentException
异常。I'll add this cause of the error as well in hopes it helps some future internet traveler. :)
GDI+ limits the maximum height of an image to 65500
We do some basic image resizing, but in resizing we try to maintain aspect ratio. We have a QA guy who's a little too good at this job; he decided to test this with a ONE pixel wide photo that was 480 pixels tall. When the image was scaled to meet our dimensions, the height was north of 68,000 pixels and our app exploded with
A generic error occurred in GDI+
.You can verify this yourself with test:
It's too bad there's not a friendly .net
ArgumentException
thrown in the constructor ofBitmap
.本文详细解释了到底发生了什么:位图和图像构造函数依赖项
简而言之,一生对于从流构造的
Image
,该流不得被销毁。因此,不要
尝试此操作
并在表单关闭或网页关闭时关闭imageStream。
This article explains in detail what exactly happens: Bitmap and Image constructor dependencies
In short, for a lifetime of an
Image
constructed from a stream, the stream must not be destroyed.So, instead of
try this
and close imageStream at the form close or web page close.
如果您尝试保存到无效路径或存在权限问题,您也会收到此异常。
如果您不能 100% 确定文件路径可用且权限正确,请尝试将 a 写入文本文件。 只需几秒钟就可以排除一个非常简单的修复。
并且不要忘记清理您的文件。
You'll also get this exception if you try to save to an invalid path or if there's a permissions issue.
If you're not 100% sure that the file path is available and permissions are correct then try writing a to a text file. This takes just a few seconds to rule out what would be a very simple fix.
And don't forget to clean up your file.
将图像保存到位图变量
Save image to bitmap variable
以防万一有人做像我一样愚蠢的事情。
1.确保路径确实存在。
2.确保您有写入权限。
3.确保你的路径是正确的,在我的例子中,我在TargetPath中丢失了文件名:(
应该说,你的路径比“GDI+中发生一般错误”更糟糕
Just in case if someone is doing as stupid stuff as I was.
1. make sure path does exist.
2. make sure you have permissions to write.
3. make sure your path is correct, in my case I was missing file name in the TargetPath :(
it should have said, your path sucks than "A generic error occurred in GDI+"
我在保存 JPEG 时也遇到此错误,但仅限于某些图像。
我的最终代码:
我没有创建图像,所以我不知道有什么区别。
如果有人能解释一下,我将不胜感激。
这是我的 SaveJpeg 函数,仅供参考:
I also got this error when saving JPEGs, but only for certain images.
My final code:
I didn't create the images so I can't tell what the difference is.
I'd appreciate if anyone could explain that.
This is my SaveJpeg function just FYI:
如果您的代码如下,那么也会发生此错误
正确的错误是
这可能是因为我们从 using 块返回
if your code is as follows then also this error occurs
The correct one is
This may be because we are returning from the using block
我发现如果我保存文件的父文件夹之一有尾随空格,那么 GDI+ 将抛出通用异常。
换句话说,如果我尝试保存到“C:\Documents and Settings\myusername\Local Settings\Temp\ABC DEF M1 Trended Values \Images\picture.png”,则会引发通用异常。
我的文件夹名称是从恰好有尾随空格的文件名生成的,因此很容易对其进行 .Trim() 并继续。
I found that if one of the parent folders where I was saving the file had a trailing space then GDI+ would throw the generic exception.
In other words, if I tried to save to "C:\Documents and Settings\myusername\Local Settings\Temp\ABC DEF M1 Trended Values \Images\picture.png" then it threw the generic exception.
My folder name was being generated from a file name that happened to have a trailing space so it was easy to .Trim() that and move on.
有一个非常相似的问题,也尝试克隆图像,但不起作用。 我发现最好的解决方案是从内存流加载的图像创建一个新的 Bitmap 对象。 这样就可以处理流,例如
希望这有帮助。
Had a very similar problem and also tried cloning the image which doesn't work. I found that the best solution was to create a new Bitmap object from the image that was loaded from the memory stream. That way the stream can be disposed of e.g.
Hope this helps.
这是 Fred 回应的扩展/限定,其中指出:“GDI 将图像的高度限制为 65534”。 我们的一个 .NET 应用程序遇到了这个问题,看到这篇文章后,我们的外包团队举起了手,表示如果不进行重大更改,他们无法解决该问题。
根据我的测试,可以创建/操作高度大于 65534 的图像,但在以某些格式保存到流或文件时会出现问题。 在下面的代码中,当我的像素高度为 65501 时,t.Save() 方法调用向我们的朋友抛出一般异常。 出于好奇,我重复了宽度测试,并将相同的限制应用于保存。
如果写入内存流,也会发生相同的错误。
要解决这个问题,您可以重复上面的代码,并用 ImageFormat.Tiff 或 ImageFormat.Bmp 替换 ImageFormat.Jpeg。
对我来说,这最高/宽度为 100,000 - 我没有测试限制。 碰巧 .Tiff 对我们来说是一个可行的选择。
警告
内存中的 TIFF 流/文件比 JPG 流/文件消耗更多的内存。
This is an expansion / qualification of Fred's response which stated: "GDI limits the height of an image to 65534". We ran into this issue with one of our .NET applications, and having seen the post, our outsourcing team raised their hands in the air and said they couldn't fix the problem without major changes.
Based on my testing, it's possible to create / manipulate images with a height larger than 65534, but the issue arises when saving to a stream or file IN CERTAIN FORMATS. In the following code, the t.Save() method call throws our friend the generic exception when the pixel height is 65501 for me. For reasons of curiosity, I repeated the test for width, and the same limit applied to saving.
The same error also occurs if you write to a memory stream.
To get round it, you can repeat the above code and substitute ImageFormat.Tiff or ImageFormat.Bmp for ImageFormat.Jpeg.
This runs up to heights / widths of 100,000 for me - I didn't test the limits. As it happens .Tiff was a viable option for us.
BE WARNED
The in memory TIFF streams / files consume more memory than their JPG counterparts.
由于权限而发生错误。 确保文件夹具有所有权限。
Error occurring because of Permission. make sure folder have ALL THE PERMISSION.
已解决 - 我遇到了这个确切的问题。 对我来说,修复方法是增加 IIS 服务器上 IUSR 的磁盘配额。 在本例中,我们有一个包含商品图像等的目录应用程序。 “匿名 Web 用户”的上传配额设置为 100MB,这是该特定托管公司的 IIS 服务器的默认设置。 我将其提高到 400MB,并且能够毫无错误地上传图像。
这可能不是您的问题,但如果是,则很容易解决。
SOLVED - I had this exact problem. The fix, for me, was to up the disk quota for IUSR on the IIS server. In this instance, we have a catalog app with images of items and such. The upload quota for the "Anonymous Web User" was set to 100MB, which is the default for this particular hosting company's IIS servers. I upped it to 400MB and was able to upload images without error.
This might not be your issue, but if it is, it's an easy fix.
就我而言,问题出在我保存的路径中(根
C:\
)。 将其更改为D:\111\
使异常消失。In my case the problem was in the path I was saving (the root
C:\
). Changing it toD:\111\
made the exception go away.很简单,创建一个新的 Bitmap 实例就可以解决问题。
Simple, create a new instance of Bitmap solves the problem.
导致此错误的另一个原因 - 您在 Bitmap 实例的 Save 方法中指定的路径不存在,或者您没有提供完整/有效的路径。
刚刚出现此错误,因为我传递的是文件名而不是完整路径!
它发生了!
Another cause for this error - the path you indicate in the Save method of the Bitmap instance doesn't exist or you haven't supplied a full / valid path.
Just had this error because I was passing in a filename and not a full path!
It happens!
轮到我了!
在 .Save... 上得到它,因为 using() 使文件保持打开状态,所以我无法覆盖它。 也许这会对将来的某人有所帮助。
My turn!
Got it on the .Save... because the using() is holding the file open, so I can't overwrite it. Maybe this will help someone in the future.
我面临同样的问题。 但就我而言,我试图将文件保存在 C 盘中,但无法访问。 于是我尝试将其保存在完全可访问的D盘中,并且成功了。
因此,首先检查您要保存的文件夹。 您必须拥有该特定文件夹的所有(读取和写入)权限。
Same problem I was facing. But in my case, I was trying to save file in C drive and it was not accessible. So I tried it to save in D drive which was fully accessible and I succeeded.
So first check your folders in which you are trying to save. You must have all (read and write) rights for that particular folder.
我们在生产服务器上使用 ImageProcessor lib 生成 PDF 或调整图像大小时遇到了类似的问题。
回收应用程序池解决问题。
We had a similar problem on generating a
PDF
or resize image using ImageProcessor lib on production server.Recycle the application pool fix the issue.
我注意到你的“jpeg”情况实际上是:
你确定格式是jpeg而不是其他格式吗?
我会尝试:
或者检查 imageToConvert.MimeType() 实际返回的内容。
更新
您还需要对 MemoryStream 对象进行其他初始化吗?
I notice that your "jpeg" case is actually:
Are you sure that the format is jpeg and not something else?
I'd try:
Or check what
imageToConvert.MimeType()
is actually returning.UPDATE
Is there any other initialisation you need to do to the MemoryStream object?
只是为了抛出另一个可能的解决方案,我将提到我遇到的带有此错误消息的情况。 当保存我已经转换并正在显示的位图时,
Bitmap.Save
方法会抛出此异常。 我发现如果语句上有断点,它不会抛出异常,如果Bitmap.Save
前面是Thread.Sleep(500)
也不会抛出异常,所以我假设正在发生某种资源争用。只需将图像复制到新的 Bitmap 对象就足以防止出现此异常:
Just to throw another possible solution on the pile, I'll mention the case I ran into with this error message. The method
Bitmap.Save
would throw this exception when saving an bitmap I had transformed and was displaying. I discovered it would not throw the exception if the statement had a breakpoint on it, nor would it if theBitmap.Save
was preceeded byThread.Sleep(500)
so I suppose there is some sort of resource contention going on.Simply copying the image to a new Bitmap object was enough to prevent this exception from appearing:
导致此错误并解决我的问题的另一个原因是您的应用程序没有对某些目录的写入权限。
因此,要完成萨文德拉的回答:https://stackoverflow.com/a/7426516/6444829。
以下是向 IIS_IUSERS 授予文件访问权限的方法。
要提供对 ASP.NET 应用程序的访问权限,必须向 IIs_IUSERS 授予访问权限。
授予对特定文件或文件夹的读取、写入和修改权限
在 Windows 资源管理器中,找到并选择所需的文件。
右键单击该文件,然后单击“属性”。
在“属性”对话框中,单击“安全”选项卡。
在“安全”选项卡上,检查用户列表。
(如果您的应用程序作为网络服务运行,请在列表中添加网络服务帐户并授予其权限。
在“属性”对话框中,单击“IIs_IUSERS”,然后在“网络服务的权限”部分中,选择“读取”、写入和修改权限。
单击“应用”,然后单击“确定”。< /p>
这对我的 Windows Server 2016 的 IIS 和本地 IIS Windows 10 有效。
One other cause of this error and that solve my problème is that your application doesn't have a write permission on some directory.
so to complete the answer of savindra : https://stackoverflow.com/a/7426516/6444829.
Here is how you Grant File Access to IIS_IUSERS
To provide access to an ASP.NET application, you must grant access to the IIs_IUSERS.
To grant read, write, and modify permissions to a specific File or Folder
In Windows Explorer, locate and select the required file.
Right click the file, and then click Properties.
In the Properties dialog box, click the Security tab.
On the Security tab, examine the list of users.
(If your application is running as a Network Service, add the network service account in the list and grant it the permission.
In the Properties dialog box, click IIs_IUSERS, and in the Permissions for NETWORK SERVICE section, select the Read, Write, and Modify permissions.
Click Apply, and then click OK.
this worked for me in my IIS of windows server 2016 and local IIS windows 10.
如果您尝试将图像保存到远程位置,请务必将
NETWORK_SERVICE
用户帐户添加到安全设置中,并授予该用户读写权限。 否则它不会起作用。If you are trying to save an image to a remote location be sure to add the
NETWORK_SERVICE
user account into the security settings and give that user read and write permissions. Otherwise it is not going to work.我也收到此错误,因为我尝试使用与以前保存的图像相同的名称保存图像。
确保您不保存具有重复名称的图像。
例如,使用“随机”函数(C# 的随机数生成器如何工作?)
或者例如生成一个 Guid (http://betterexplained.com/articles/指南快速指南/)
I also get this error because i'm trying to save images with the same name of previous saved images.
Make sure that you don't save images with duplicate name.
Use for thar for example a 'Random' function (How does C#'s random number generator work?)
or for example generate a Guid (http://betterexplained.com/articles/the-quick-guide-to-guids/)
导致此类错误的可能问题有:
我希望这样有帮助,这是我的问题的解决方案,我只是在保存输出图像之前确保输出目录存在!
Possible problems that cause such an error are:
I hope this helps, this was the fix for my issue, I simply made sure that the output directory exists before saving the output image!
就我而言,路径错误,
只需使用这个
in my case, path was wrong
just use this
对我来说,我使用的是
Image.Save(Stream, ImageCodecInfo, EncoderParameters)
,显然这导致了臭名昭著的GDI+ 中发生一般错误
错误。我试图使用
EncoderParameter
以 100% 质量保存 jpeg。 这在“我的机器”上完美运行(doh!),而不是在生产中。当我使用
Image.Save(Stream, ImageFormat)
时,错误消失了! 所以像个白痴一样,我继续使用后者,尽管它以默认质量保存它们,我认为只有 50%。希望此信息对某人有所帮助。
For me I was using the
Image.Save(Stream, ImageCodecInfo, EncoderParameters)
and apparently this was causing the infamousA generic error occurred in GDI+
error.I was trying to use
EncoderParameter
to save the jpegs in 100% quality. This was working perfectly on "my machine" (doh!) and not on production.When I used the
Image.Save(Stream, ImageFormat)
instead, the error disappeared! So like an idiot I continued to use the latter although it saves them in default quality which I assume is just 50%.Hope this info helps someone.