2009-02-24 9 views
7

Grundsätzlich Ich versuche, ein einfaches Bild in einer ASP.NET-Handler zu machen:Kann machen Bild nicht zu 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); 
} 

Aber ich bekomme die folgende Ausnahme:

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

Die Lösung ist dies zu verwenden, anstatt Bild schreiben zu OutputStream:

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

Also ich bin nur neugierig wie Warum ist die erste Variante problematisch?

Edit: Das HRESULT ist 80004005, die nur "generisch" ist.

+0

Auf Ihrer Lösung mit GetBuffer(), muss Sie entsorgen sowohl 'Image'- als auch' MemoryStream'-Objekte nach 'Response.OutputStream.Write'? – Pingpong

Antwort

6

Der Schriftsteller muss tatsächlich versuchen, in den Strom richtig zu schreiben.

Stellen Sie in Ihrem letzten Quellcode sicher, dass Sie entweder MemoryStream.ToArray() verwenden, um die richtigen Daten zu erhalten, oder, wenn Sie die Daten nicht kopieren möchten, verwenden Sie MemoryStream.GetBuffer() mit MemoryStream.Length und nicht die Länge des zurückgegebenen Arrays.

GetBuffer gibt den internen Puffer zurück, der vom MemoryStream verwendet wird, und seine Länge ist im Allgemeinen größer als die Länge der Daten, die in den Stream geschrieben wurden.

Dies wird vermeiden, dass Sie am Ende des Streams Müll senden, und nicht einige strenge Image-Decoder durcheinander bringen, die nachlaufenden Müll nicht tolerieren würden. (Und weniger Daten übertragen ...)

+0

Guter Fang, danke! MSDN sagt ziemlich genau dasselbe über GetBuffer(): http://msdn.microsoft.com/en-us/library/system.io.memorystream.getbuffer.aspx – Serguei

1

Ich glaube, das Problem ist, dass die Response.OutputStream Suche nicht unterstützt. Um ein PNG (oder JPEG) zu speichern, muss das Bildobjekt in der Lage sein, die Ausgabe nicht sequentiell zu schreiben. Wenn ich mich richtig erinnere, hätte es funktioniert, wenn Sie das Bild als BMP gespeichert haben, da dieses Bildformat geschrieben werden kann, ohne den Stream zu suchen.

+0

Ich habe das tatsächlich versucht, aber das Ergebnis ist dasselbe geworden. – Serguei

0

Ok Ich habe einen Wrapper für Stream verwendet (implementiert Stream und übergibt Aufrufe an einen zugrunde liegenden Stream), um zu bestimmen, dass Image.Save() die Positions- und Längeneigenschaften aufruft, ohne CanSeek zu prüfen, was false zurückgibt. Es versucht auch, die Position auf 0 zu setzen.

Es scheint also ein Zwischenpuffer erforderlich.

3

Image.Save (MemoryStream-Stream) erfordert ein MemoryStream-Objekt, das gesucht werden kann. Context.Response.OutputStream ist nur vorwärts und unterstützt keine Suchvorgänge. Daher benötigen Sie einen Zwischenstream. Sie benötigen den Byte-Array-Puffer jedoch nicht.

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

Eine voll funktionsfähige Beispielcode verfügbar ist hier:: Sie können in die context.Response.OutputStream direkt aus dem temporären Speicher-Stream schreiben

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