基本上我试图在ASP.NET处理程序中渲染一个简单的图像:
public void ProcessRequest (HttpContext context)
{
Bitmap image = new Bitmap(16, 16);
Graphics graph = Graphics.FromImage(image);
graph.FillEllipse(Brushes.Green, 0, 0, 16, 16);
context.Response.ContentType = "image/png";
image.Save(context.Response.OutputStream, ImageFormat.Png);
}
但我得到以下例外:
System.Runtime.InteropServices.ExternalException: A generic error
occurred in GDI+.
at System.Drawing.Image.Save(Stream stream, ImageCodecInfo encoder,
EncoderParameters encoderParams)
解决方案是使用它而不是将图像写入OutputStream:
MemoryStream temp = new MemoryStream();
image.Save(temp, ImageFormat.Png);
byte[] buffer = temp.GetBuffer();
context.Response.OutputStream.Write(buffer, 0, buffer.Length);
所以我只是好奇为什么第一个变种有问题?
编辑:HRESULT是80004005,只是“通用”。
答案 0 :(得分:6)
作者确实需要设法正确地写入流。
但是在上一个源代码中,请确保使用MemoryStream.ToArray()来获取正确的数据,或者,如果您不想复制数据,请使用MemoryStream.GetBuffer()和MemoryStream.Length以及不是返回数组的长度。
GetBuffer将返回MemoryStream使用的内部缓冲区,其长度通常大于已写入流的数据的长度。
这将避免你在流的末尾发送垃圾,而不是搞乱一些不能容忍尾随垃圾的严格图像解码器。 (并传输较少的数据......)
答案 1 :(得分:4)
Image.Save(MemoryStream流)确实需要一个可以寻找的MemoryStream对象。 context.Response.OutputStream是仅向前的,不支持搜索,因此您需要一个中间流。但是,您不需要字节数组缓冲区。您可以直接从临时内存流写入context.Response.OutputStream:
/// <summary>
/// Sends a given image to the client browser as a PNG encoded image.
/// </summary>
/// <param name="image">The image object to send.</param>
private void SendImage(Image image)
{
// Get the PNG image codec
ImageCodecInfo codec = GetCodec("image/png");
// Configure to encode at high quality
using (EncoderParameters ep = new EncoderParameters())
{
ep.Param[0] = new EncoderParameter(Encoder.Quality, 100L);
// Encode the image
using (MemoryStream ms = new MemoryStream())
{
image.Save(ms, codec, ep);
// Send the encoded image to the browser
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.ContentType = "image/png";
ms.WriteTo(HttpContext.Current.Response.OutputStream);
}
}
}
这里有一个功能齐全的代码示例:
答案 2 :(得分:1)
我认为问题在于Response.OutputStream不支持搜索。为了保存PNG(或JPEG),图像对象需要能够非顺序地写入输出。如果我没记错的话,如果您将图像保存为BMP,那将会有效,因为可以在不搜索流的情况下编写图像格式。
答案 3 :(得分:0)
好的我使用Stream的包装器(实现Stream并将调用传递给底层流)来确定Image.Save()调用Position和Length属性而不检查返回false的CanSeek。它还尝试将Position设置为0。
所以似乎需要一个中间缓冲区。