Невозможно отобразить изображение в HttpContext.Response.OutputStream - PullRequest
7 голосов
/ 24 февраля 2009

В основном я пытаюсь сделать простое изображение в обработчике 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, который просто "универсальный".

Ответы [ 4 ]

6 голосов
/ 25 февраля 2009

Писателю действительно нужно правильно искать запись в потоке.

Но в вашем последнем исходном коде убедитесь, что вы используете либо MemoryStream.ToArray () для получения правильных данных, либо, если вы не хотите копировать данные, используйте MemoryStream.GetBuffer () с MemoryStream.Length и не длина возвращаемого массива.

GetBuffer возвращает внутренний буфер, используемый MemoryStream, и его длина обычно больше длины данных, записанных в поток.

Это позволит вам не отправлять мусор в конце потока и не испортить какой-либо строгий декодер изображений, который не допустит конечного мусора. (И передавать меньше данных ...)

4 голосов
/ 16 мая 2010

Image.Save (поток MemoryStream) действительно требует объект MemoryStream, который может быть найден. Context.Response.OutputStream предназначен только для пересылки и не поддерживает поиск, поэтому вам необходим промежуточный поток. Однако вам не нужен буфер байтового массива. Вы можете записать непосредственно из потока временной памяти в контекст. 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

1 голос
/ 24 февраля 2009

Я считаю, что проблема в том, что Response.OutputStream не поддерживает поиск. Чтобы сохранить PNG (или JPEG), объект изображения должен иметь возможность записывать выходные данные не последовательно. Если я правильно помню, это сработало бы, если бы вы сохранили изображение как BMP, поскольку этот формат изображения можно записать без поиска потока.

0 голосов
/ 25 февраля 2009

Хорошо. Я использовал оболочку для Stream (реализует Stream и передает вызовы в базовый поток), чтобы определить, что Image.Save () вызывает свойства Position и Length без проверки CanSeek, которая возвращает false. Он также пытается установить Position в 0.

Так что, кажется, необходим промежуточный буфер.

...