Невозможно отобразить изображение в 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, который является просто «общим».
Ответов (4)4
Писателю действительно нужно стремиться к правильной записи в потоке.
Но в вашем последнем исходном коде убедитесь, что вы используете либо MemoryStream.ToArray () для получения правильных данных, либо, если вы не хотите копировать данные, используйте MemoryStream.GetBuffer () с MemoryStream.Length, а не длину возвращенного массива.
GetBuffer вернет внутренний буфер, используемый MemoryStream, и его длина обычно превышает длину данных, которые были записаны в поток.
Это предотвратит отправку мусора в конце потока и не испортит какой-то строгий декодер изображений, который не допускает замыкающего мусора. (И передавать меньше данных ...)
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);
}
}
}
Полнофункциональный образец кода доступен здесь:
Автоматическое создание текстовых изображений со сглаживанием с помощью ASP.NET
Я считаю, что проблема в том, что Response.OutputStream не поддерживает поиск. Чтобы сохранить PNG (или JPEG), объект изображения должен иметь возможность записывать выходные данные непоследовательно. Если я правильно помню, это сработало бы, если бы вы сохранили изображение как BMP, поскольку этот формат изображения можно записать без поиска потока.
Хорошо, я использовал оболочку для Stream (реализует Stream и передает вызовы базовому потоку), чтобы определить, что Image.Save () вызывает свойства Position и Length без проверки CanSeek, который возвращает false. Он также пытается установить для Position значение 0.
Таким образом, кажется, требуется промежуточный буфер.