无法将图像渲染到 HttpContext.Response.OutputStream
基本上,我试图在 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,这只是“通用”。
Basically I am trying to render a simple image in an ASP.NET handler:
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);
}
But I get the following exception:
System.Runtime.InteropServices.ExternalException: A generic error
occurred in GDI+.
at System.Drawing.Image.Save(Stream stream, ImageCodecInfo encoder,
EncoderParameters encoderParams)
The solution is to use this instead of having image write to OutputStream:
MemoryStream temp = new MemoryStream();
image.Save(temp, ImageFormat.Png);
byte[] buffer = temp.GetBuffer();
context.Response.OutputStream.Write(buffer, 0, buffer.Length);
So I'm just curious as to why the first variant is problematic?
Edit: The HRESULT is 80004005 which is just "generic".
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
作者确实需要寻求正确地在流中写入。
但在您的最后一个源代码中,请确保您确实使用 MemoryStream.ToArray() 来获取正确的数据,或者,如果您不想复制数据,请使用 MemoryStream.GetBuffer() 和 MemoryStream.Length 而不是长度返回的数组。
GetBuffer会返回MemoryStream使用的内部缓冲区,其长度一般大于已写入流的数据长度。
这将避免您在流末尾发送垃圾,并且不会弄乱某些不能容忍尾随垃圾的严格图像解码器。 (并且传输更少的数据......)
The writer indeed needs to seek to write in the stream properly.
But in your last source code, make sure that you do use either MemoryStream.ToArray() to get the proper data or, if you do not want to copy the data, use MemoryStream.GetBuffer() with MemoryStream.Length and not the length of the returned array.
GetBuffer will return the internal buffer used by the MemoryStream, and its length generally greater than the length of the data that has been written to the stream.
This will avoid you to send garbage at the end of the stream, and not mess up some strict image decoder that would not tolerate trailing garbage. (And transfer less data...)
Image.Save(MemoryStream stream) 确实需要一个可以查找的 MemoryStream 对象。 context.Response.OutputStream 是仅向前的,不支持查找,因此您需要一个中间流。 但是,您不需要字节数组缓冲区。 您可以直接从临时内存流写入 context.Response.OutputStream:
此处提供了功能齐全的代码示例:
使用 ASP.NET 自动生成抗锯齿文本图像
Image.Save(MemoryStream stream) does require a MemoryStream object that can be seeked upon. The context.Response.OutputStream is forward-only and doesn't support seeking, so you need an intermediate stream. However, you don't need the byte array buffer. You can write directly from the temporary memory stream into the context.Response.OutputStream:
A fully functional code sample is available here:
Auto-Generate Anti-Aliased Text Images with ASP.NET
我相信问题是 Response.OutputStream 不支持查找。 为了保存 PNG(或 JPEG),图像对象需要能够非顺序写入输出。 如果我没记错的话,如果将图像保存为 BMP,就会起作用,因为可以在不查找流的情况下写入该图像格式。
I believe the problem is that the Response.OutputStream does not support seeking. In order to save a PNG (or JPEG), the image object needs to be able to write the output non-sequentially. If I remember correctly, it would have worked if you saved the image as a BMP since that image format can be written without seeking the stream.
好的,我使用了 Stream 的包装器(实现 Stream 并将调用传递给底层流)来确定 Image.Save() 调用 Position 和 Length 属性,而不检查返回 false 的 CanSeek。 它还尝试将 Position 设置为 0。
所以看来需要一个中间缓冲区。
Ok I used a wrapper for Stream (implements Stream and passes calls to an underlying stream) to determine that Image.Save() calls Position and Length properties without checking CanSeek which returns false. It also tries to set Position to 0.
So it seems an intermediate buffer is required.