Die Verwendung von WebClient zum Abrufen von Remote-Bildern erzeugt körnige GIFs und kann PNG+BMP nicht verarbeiten

StackOverflow https://stackoverflow.com/questions/499210

  •  20-08-2019
  •  | 
  •  

Frage

Grüße!

Ich erstelle einen Webformular-Prototyp (ImageLaoder.aspx), der ein Bild zurückgibt, damit es wie dieses einfache Beispiel für andere Webformulare/Webseiten verwendet werden kann:

<img src="http://www.mydomain.com/ImageLoader.aspx?i=http://images.mydomain.com/img/a.jpg" />

Bisher lädt es JPGs ohne Probleme, GIFs sehen jedoch im Vergleich zu den Originalen „körnig“ aus und BMPs und PNGs führen zu der folgenden Ausnahme:

System.Runtime.InteropServices.ExternalException:In GDI+ ist ein allgemeiner Fehler aufgetreten

Mein Code sieht bisher so aus:

protected void Page_Load(object sender, EventArgs e)
{
    string l_filePath = Request.QueryString["i"];

    System.Drawing.Image l_image = GetImage(l_filePath);
    if (l_image != null)
    {
        System.Drawing.Imaging.ImageFormat l_imageFormat = DetermineImageFormat(l_filePath);
        WriteImageAsReponse(l_image, l_imageFormat);
    }
}

private System.Drawing.Image GetImage(string filePath)
{
    WebClient l_WebClient = new WebClient();
    byte[] l_imageBytes = l_WebClient.DownloadData(filePath);

    System.Drawing.Image l_image = null;
    using (MemoryStream l_MemStream = new MemoryStream(l_imageBytes, 0, l_imageBytes.Length))
    {
        l_MemStream.Write(l_imageBytes, 0, l_imageBytes.Length);
        l_image = System.Drawing.Image.FromStream(l_MemStream, true);
        l_MemStream.Close();
    }

    return l_image;
}

private System.Drawing.Imaging.ImageFormat DetermineImageFormat(string filePath)
{
    if (filePath.EndsWith(".jpg", StringComparison.OrdinalIgnoreCase))
        return System.Drawing.Imaging.ImageFormat.Jpeg;
    else if (filePath.EndsWith(".gif", StringComparison.OrdinalIgnoreCase))
        return System.Drawing.Imaging.ImageFormat.Gif;
    else if (filePath.EndsWith(".png", StringComparison.OrdinalIgnoreCase))
        return System.Drawing.Imaging.ImageFormat.Png;
    else
        return System.Drawing.Imaging.ImageFormat.Bmp;
}

private void WriteImageAsReponse(System.Drawing.Image image, System.Drawing.Imaging.ImageFormat imageFormat)
{
    if (image == null)
        return;

    System.Drawing.Bitmap l_outputBitMap = new Bitmap(image);

    if (imageFormat == System.Drawing.Imaging.ImageFormat.Jpeg)
        Response.ContentType = "image/jpg";
    else if (imageFormat == System.Drawing.Imaging.ImageFormat.Gif)
        Response.ContentType = "image/gif";
    else if (imageFormat == System.Drawing.Imaging.ImageFormat.Png)
        Response.ContentType = "image/png";
    else
        Response.ContentType = "image/bmp";

    l_outputBitMap.Save(Response.OutputStream, imageFormat);
}

Irgendwelche Ideen, warum GIFs körnig sind und PNGs und BMPs Ausnahmen verursachen?

War es hilfreich?

Lösung

Ein paar Punkte zu Ihrer GetImage-Methode:

  • Wenn Sie Image.FromStream verwenden, sollten Sie den Stream nicht schließen (oder entsorgen).
  • Wenn Sie Dispose für einen Stream aufrufen (mit der using-Anweisung), müssen Sie Close nicht aufrufen
  • Sie schreiben in den Stream, spulen ihn dann aber nicht zurück, sodass l_image meines Erachtens keine Daten erhält (es sei denn, Image.FromStream setzt die Position selbst zurück).(Es könnte sein, dass die GIF/JPG-Decoder den Stream zurückspulen, BMP/PNG jedoch nicht, daher der Fehler.)
  • Warum verwenden Sie nicht einfach den MemoryStream-Konstruktor, der ein Byte-Array benötigt?

Kurz gesagt, ich glaube, Ihre GetImage-Methode kann ersetzt werden durch:

private Image GetImage(string filePath)
{
    WebClient l_WebClient = new WebClient();
    byte[] l_imageBytes = l_WebClient.DownloadData(filePath);
    MemoryStream l_stream = new MemoryStream(l_imageBytes);
    return Image.FromStream(l_stream);
}

Was noch wichtiger ist: Warum laden Sie das Bild überhaupt?Warum stellen Sie nicht einfach die Datei selbst als Antwort bereit und legen den Inhaltstyp so fest, wie Sie es bereits tun – oder möglicherweise nur basierend auf der Erweiterung?Mit anderen Worten, Ihr gesamter Code würde wie folgt aussehen:

protected void Page_Load(object sender, EventArgs e)
{
    string filePath = Request.QueryString["i"];
    string extension = l_filePath.Substring(l_filePath.LastIndexOf('.') + 1);
    Response.ContentType = "image/" + extension;
    byte[] data = new WebClient.DownloadData(filePath);
    Response.OutputStream.Write(data, 0, data.Length);
    Response.End();
}

Ein bisschen mehr Fehlerbehandlung (einschließlich „Ist das eine sinnvolle Erweiterung?“) wäre schön, aber ansonsten denke ich, dass es in Ordnung ist.Der einzige Vorteil, wenn Sie das Bild tatsächlich selbst laden, besteht darin, dass Sie es wirklich überprüfen können Ist ein Bild und kein Virus oder ähnliches.

BEARBEITEN:Nur aus Interesse: Haben Sie einen guten Grund dafür? wollen Bildanfragen über Ihren Server laufen?Warum sollte der Autor der Webseite schreiben:

<img src="http://www.mydomain.com/ImageLoader.aspx?i=http://images.mydomain.com/img/a.jpg" />

anstatt

<img src="http://images.mydomain.com/img/a.jpg" />

Dort Sind Es gibt einige Gründe, warum es nützlich sein könnte, aber in vielen Fällen ist es einfach nur Verschwendung.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top