无法将图像渲染到 HttpContext.Response.OutputStream

发布于 2024-07-14 21:09:49 字数 915 浏览 9 评论 0原文

基本上,我试图在 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

歌枕肩 2024-07-21 21:09:49

作者确实需要寻求正确地在流中写入。

但在您的最后一个源代码中,请确保您确实使用 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...)

我不是你的备胎 2024-07-21 21:09:49

Image.Save(MemoryStream stream) 确实需要一个可以查找的 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);
        }
    }
}

此处提供了功能齐全的代码示例:

使用 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:

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

A fully functional code sample is available here:

Auto-Generate Anti-Aliased Text Images with ASP.NET

平定天下 2024-07-21 21:09:49

我相信问题是 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.

遮云壑 2024-07-21 21:09:49

好的,我使用了 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文