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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/582766/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 09:10:39  来源:igfitidea点击:

Cannot render image to HttpContext.Response.OutputStream

c#asp.netgdi+system.drawing

提问by Serguei

Basically I am trying to render a simple image in an ASP.NET handler:

基本上我试图在 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);
}

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:

解决方案是使用它而不是将图像写入 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".

编辑:HRESULT 是 80004005,它只是“通用”。

采纳答案by Jerome Laban

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.

但是在您的最后一个源代码中,请确保您确实使用 MemoryStream.ToArray() 来获取正确的数据,或者,如果您不想复制数据,请使用 MemoryStream.GetBuffer() 和 MemoryStream.Length 而不是长度返回的数组。

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.

GetBuffer 将返回 MemoryStream 使用的内部缓冲区,其长度一般大于已写入流的数据长度。

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

这将避免您在流的末尾发送垃圾,并且不会弄乱一些不能容忍尾随垃圾的严格图像解码器。(并传输更少的数据......)

回答by David

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.

我认为问题在于 Response.OutputStream 不支持搜索。为了保存 PNG(或 JPEG),图像对象需要能够非顺序地写入输出。如果我没记错的话,如果您将图像保存为 BMP,它会起作用,因为可以在不寻找流的情况下写入该图像格式。

回答by Serguei

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.

好的,我使用了 Stream 的包装器(实现 Stream 并将调用传递给底层流)来确定 Image.Save() 调用 Position 和 Length 属性,而不检查返回 false 的 CanSeek。它还尝试将 Position 设置为 0。

So it seems an intermediate buffer is required.

所以似乎需要一个中间缓冲区。

回答by Jason Carter

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:

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

A fully functional code sample is available here:

这里提供了一个功能齐全的代码示例:

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

使用 ASP.NET 自动生成抗锯齿文本图像