2009-02-24 9 views
7

Zasadniczo próbuję uczynić prostego obrazu w ASP.NET obsługi:nie może renderować obraz do HttpContext.Response.OutputStream

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

Ale pojawia się następujący wyjątek:

System.Runtime.InteropServices.ExternalException: A generic error 
occurred in GDI+. 
    at System.Drawing.Image.Save(Stream stream, ImageCodecInfo encoder, 
    EncoderParameters encoderParams) 

rozwiązaniem jest użycie tego zamiast zapisu obrazu do OutputStream:

MemoryStream temp = new MemoryStream(); 
image.Save(temp, ImageFormat.Png); 
byte[] buffer = temp.GetBuffer(); 
context.Response.OutputStream.Write(buffer, 0, buffer.Length); 

Więc jestem ciekawy jak dlaczego pierwszy wariant jest problematyczny?

Edytuj: HRESULT to 80004005, który jest po prostu "ogólny".

+0

na rozwiązanie używając GetBuffer() musi po "Response.OutputStream.Write" usuwasz obiekty 'Image' i' MemoryStream'? – Pingpong

Odpowiedz

6

Pisarz rzeczywiście musi starać się poprawnie pisać w strumieniu.

Ale w swoim ostatnim kodzie źródłowym, upewnij się, że użyłeś albo MemoryStream.ToArray(), aby uzyskać prawidłowe dane, albo, jeśli nie chcesz kopiować danych, użyj MemoryStream.GetBuffer() z MemoryStream.Length a nie długość zwróconej tablicy.

GetBuffer zwróci wewnętrzny bufor używany przez obiekt MemoryStream, a jego długość będzie większa niż długość danych zapisanych w strumieniu.

Pozwoli to uniknąć wysyłania śmieci na końcu strumienia i nie zepsuć jakiegoś ścisłego dekodera obrazu, który nie będzie tolerował zbierania śmieci. (I przenieś mniej danych ...)

+0

Dobry połów, dzięki! MSDN mówi tak samo o GetBuffer(): http://msdn.microsoft.com/en-us/library/system.io.memorystream.getbuffer.aspx – Serguei

1

Uważam, że problem polega na tym, że Response.OutputStream nie obsługuje wyszukiwania. Aby zapisać PNG (lub JPEG), obiekt obrazu musi mieć możliwość zapisu danych wyjściowych niesekwencyjnie. Jeśli dobrze pamiętam, działałoby, gdybyś zapisał obraz jako BMP, ponieważ ten format obrazu można zapisać bez szukania strumienia.

+0

Próbowałem tego, ale wynik okazał się taki sam. – Serguei

0

Ok Użyłem opakowania dla Stream (implementuje Stream i przekazuje połączenia do strumienia bazowego), aby określić, że Image.Save() wywołuje właściwości Position i Length bez sprawdzania CanSeek, który zwraca false. Próbuje również ustawić pozycję na 0.

Wygląda na to, że wymagany jest bufor pośredni.

3

Image.Save (strumień MemoryStream) wymaga obiektu MemoryStream, który można wyszukać. Obiekt context.Response.OutputStream jest przeznaczony tylko do przekazywania i nie obsługuje wyszukiwania, więc potrzebny jest strumień pośredni. Jednak nie potrzebujesz bufora tablic bajtowych. Można pisać bezpośrednio z tymczasowej pamięci do strumienia 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); 
     } 
    } 
} 

Kod pełni funkcjonalny Próbka jest dostępna tutaj:

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

Powiązane problemy