2009-02-24 6 views
7

Fondamentalmente sto cercando di rendere una semplice immagine in un gestore ASP.NET:non può rendere un'immagine per 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); 
} 

Ma ho la seguente eccezione:

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

Il la soluzione è di usare questo invece di avere la scrittura dell'immagine su OutputStream:

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

Quindi sono solo curioso come a perché la prima variante è problematica?

Modifica: HRESULT è 80004005 che è solo "generico".

+0

Sul soluzione che utilizza GetBuffer(), deve Disponi gli oggetti 'Image' e' MemoryStream' dopo 'Response.OutputStream.Write'? – Pingpong

risposta

6

Lo scrittore ha davvero bisogno di cercare di scrivere nel flusso correttamente.

Ma nell'ultimo codice sorgente, assicurarsi di utilizzare MemoryStream.ToArray() per ottenere i dati corretti o, se non si desidera copiare i dati, utilizzare MemoryStream.GetBuffer() con MemoryStream.Length e non la lunghezza dell'array restituito.

GetBuffer restituirà il buffer interno utilizzato da MemoryStream e la sua lunghezza generalmente superiore alla lunghezza dei dati che sono stati scritti nel flusso.

Questo eviterà di inviare immondizie alla fine del flusso e di non rovinare alcuni rigorosi decodificatori di immagine che non tollererebbero spazzatura finale. (E trasferire meno dati ...)

+0

Buona cattura, grazie! MSDN dice praticamente la stessa cosa su GetBuffer(): http://msdn.microsoft.com/en-us/library/system.io.memorystream.getbuffer.aspx – Serguei

1

Credo che il problema è che Response.OutputStream non supporta la ricerca. Per salvare un PNG (o JPEG), l'oggetto immagine deve essere in grado di scrivere l'output in modo non sequenziale. Se ricordo male, avrebbe funzionato se avessi salvato l'immagine come BMP poiché quel formato di immagine può essere scritto senza cercare il flusso.

+0

L'ho provato in realtà ma il risultato si è rivelato lo stesso. – Serguei

0

Ok, ho utilizzato un wrapper per Stream (implementa Stream e passa le chiamate a un flusso sottostante) per determinare che Image.Save() chiama le proprietà Position e Length senza controllare CanSeek che restituisce false. Cerca anche di impostare la Posizione su 0.

Quindi sembra che sia richiesto un buffer intermedio.

3

Image.Save (Stream di memoria) richiede un oggetto MemoryStream che può essere cercato. Il contesto.Response.OutputStream è di tipo forward-only e non supporta la ricerca, quindi è necessario uno stream intermedio. Tuttavia, non è necessario il buffer di array di byte. È possibile scrivere direttamente dal flusso di memoria temporanea nella 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); 
     } 
    } 
} 

Un esempio di codice completamente funzionale è disponibile qui:

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

Problemi correlati