L'utilizzo di WebClient per ottenere immagini remote produce GIF granulose e non è in grado di gestire PNG+BMP
Domanda
Saluti!
Sto creando un prototipo di modulo Web (ImageLaoder.aspx) che restituirà un'immagine in modo che possa essere utilizzata come questo semplice esempio in altri Web Form/pagine Web:
<img src="http://www.mydomain.com/ImageLoader.aspx?i=http://images.mydomain.com/img/a.jpg" />
Finora carica i JPG senza problemi, tuttavia i GIF appaiono "granulosi" rispetto agli originali e i BMP e PNG comportano la seguente eccezione:
System.Runtime.InteropServices.ExternalException:Si è verificato un errore generico in GDI+
Il mio codice finora assomiglia a questo:
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);
}
Qualche idea sul perché le GIF sono granulose e PNG e BMP causano eccezioni?
Soluzione
Alcuni punti sul tuo metodo GetImage:
- Quando usi Image.FromStream non dovresti chiudere (o eliminare) il flusso
- Se chiami Dispose su un flusso (con l'istruzione using) non è necessario chiamare Close
- Stai scrivendo nello stream, ma non lo "riavvolgi", quindi l_image in realtà non ottiene alcun dato per quanto posso vedere (a meno che Image.FromStream non ripristini la posizione stessa).(Potrebbe darsi che i decoder gif/jpg riavvolgano lo streaming ma bmp/png no, da qui l'errore.)
- Perché non usi semplicemente il costruttore MemoryStream che accetta un array di byte?
In breve, credo che il tuo metodo GetImage possa essere sostituito con:
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);
}
Ora, cosa più importante: perché stai caricando l'immagine?Perché non fornisci semplicemente il file stesso come risposta, impostando il tipo di contenuto come stai già facendo o magari solo in base all'estensione?In altre parole, tutto il tuo codice diventerebbe:
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();
}
Sarebbe utile una maggiore gestione degli errori (incluso "è un'estensione ragionevole?"), ma a parte questo penso che vada bene.L'unico vantaggio di caricare effettivamente l'immagine da solo è che puoi convalidarla davvero È un'immagine piuttosto che un virus o qualcosa del genere.
MODIFICARE:Solo per curiosità, hai una buona ragione per cui lo faresti Volere richieste di immagini per passare attraverso il tuo server?Perché l'autore della pagina web dovrebbe scrivere:
<img src="http://www.mydomain.com/ImageLoader.aspx?i=http://images.mydomain.com/img/a.jpg" />
invece di
<img src="http://images.mydomain.com/img/a.jpg" />
Là Sono alcuni motivi per cui potrebbe essere utile, ma in molti casi è solo uno spreco.