Greetings!
I’m creating a web form prototype (ImageLaoder.aspx) that will return an image so that it may be used like this simple example other Web Forms/web pages:
<img src="https://www.mydomain.com/ImageLoader.aspx?i=http://images.mydomain.com/img/a.jpg" />
So far, it loads JPGs with no problems, however GIFs look “grainy” compared to the orignals and BMPs and PNGs result in the following exception:
System.Runtime.InteropServices.ExternalException: A generic error occurred in GDI+
My code thus far looks like this:
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);
}
Any ideas why GIFs are grainy and PNGs and BMPs cause exceptions?
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
A few points about your GetImage method:
- When you use Image.FromStream you shouldn’t close (or dispose) the stream
- If you’re calling Dispose on a stream (with the using statement) you don’t need to call Close
- You’re writing to the stream, but then not “rewinding it” so l_image doesn’t actually get any data as far as I can see (unless Image.FromStream resets the position itself). (It could be that the gif/jpg decoders rewind the stream but bmp/png don’t, hence the error.)
- Why don’t you just use the MemoryStream constructor which takes a byte array?
In short, I believe your GetImage method can be replaced with:
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);
}
Now, more importantly – why are you loading the image at all? Why don’t you just serve the file itself as a response, setting the content type as you’re already doing – or possibly just based on the extension? In other words, all of your code would become:
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();
}
A bit more error handling (including “is this a reasonable extension?”) would be nice, but other than that I think it’s okay. The only benefit of actually loading the image yourself is that you get to validate that it really is an image rather than a virus or something like that.
EDIT: Just out of interest, do you have a good reason why you’d want image requests to go through your server? Why would the web page author write:
<img src="https://www.mydomain.com/ImageLoader.aspx?i=http://images.mydomain.com/img/a.jpg" />
instead of
<img src="https://images.mydomain.com/img/a.jpg" />
There are some reasons why it might be useful, but in many cases it’s just a waste.
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0