Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Problem converting .ico in byte array to Image object in .net

Tags:

.net

gdi+

I am trying to take favicons and add them to a dynamic image that I am creating. See StackFlair. The website code works fine locally, and on one shared hosting server. blah blah, free hosting plan, you get what you pay for, blah blah My trouble is that I get an exception from a new hosting setup. This exception only happens for .ico files. I can process .gif and .png images just fine on all servers I've tested (ie, a gravatar image). The favicons I am trying to use are favicons from the SE network, but even http://www.google.com/favicon.ico results in the following exception.

System.ArgumentException: Parameter is not valid.

  • System.Drawing.Image.FromStream(Stream stream, Boolean useEmbeddedColorManagement, Boolean validateImageData)
  • System.Drawing.Image.FromStream(Stream stream)

The variations of code that I am trying are below. I get the same Parameter not valid exception for all variations.

byte[] imageBytes = //pull from Image field in SQL Server
//or
byte[] imageBytes = new WebClient().DownloadData(imageUrl);


MemoryStream ms = new MemoryStream(imageBytes);
Image image = Image.FromStream(ms);
 //or
Icon icon = new Icon(ms);
Image image = icon.ToBitmap();
//or
Image image = new Bitmap(ms);

All of these work just fine locally and on the bad hosting server. None of them work on the server I want to be on. By using Trace output, I can verify that the length of the array contains the correct number of bytes. If I do the following, I see the image displayed as expected.

Response.Clear();
Response.BinaryWrite(imageBytes);
Response.End();

If I loop through the array and write out each byte value, the output is identical from my local instance to the server where I get the exception.

If it helps, the server where my code doesn't work is a Windows 2003 server with sp2.

Clearly the framework is telling me that the stream of bytes is not valid, but everything I've checked, checks out. Any ideas on why this specific server is choking on .ico files?

like image 677
Rebecca Chernoff Avatar asked Sep 26 '10 23:09

Rebecca Chernoff


2 Answers

I have a workaround. Use ImageMagick to convert the ico files to png files:

convert favicon.ico[0] favicon.png

Then those are easy to work with. ImageMagick is pre-installed on lots of shared hosts, or you can download precompiled binaries for Windows.

If you leave off the [0], then you will get a series of files favicon-0.png favicon-1.png etc if there is more than one icon image stored in the .ico file. You will then need to sort through them, to choose the one that is closest to what you want: 16x16 with alpha transparency. (I include 32x32 and 48x48 in my favicon files, for IE users who drag internet shortcuts to their desktop.) ImageMagick preserves the transparency when converting to png.

The stackapps.com/favicon.ico gear icon has two images. The first one has alpha transparency, and looks great on your light grey #DBDCDB background.

I assume you are building a dynamic image like your http://i.stack.imgur.com/SNHfF.png at the server, rather than sending all 6 top site icons to the browser. If not, it's still a good idea to send the icons converted to png, because they were not designed to render within web pages.

...Tom

like image 113
Tom Robinson Avatar answered Sep 17 '22 12:09

Tom Robinson


I have reproduced your issue on Windows Server 2003 SP2 and founded solution. Your mistake was in making response as you use HTTP so you should provide response content type. Also I added "content-disposition" to response header - but hasn't matter and not required - I used it just for testing server response via browser.

// Part #1: Server
// read ico - you can make it in your manner
Stream fileStream = File.OpenRead( Server.MapPath( @"~\images\myicon.ico" ) );
byte[] fileBytes = new byte[ fileStream.Length ];
fileStream.Read( fileBytes, 0, (int) fileStream.Length );

// here is making response
Response.ContentType = "application/ico";
Response.AddHeader( "content-disposition", string.Format( "attachment;filename=myico.ico" ) );
Response.BinaryWrite( fileBytes );
Response.End();

and server part

// Part#2: Client ( seems same as your )
WebClient client = new WebClient();
byte[] bytes = client.DownloadData( @"http://my url - you can't use it" );
MemoryStream ms = new MemoryStream(bytes);

Icon icon = new Icon( ms );
Image image = icon.ToBitmap();         // 1st way
Image yetOneImage = new Bitmap( ms );  // 2nd way

// or just put your url into browser and preview with your default images viewer

I hope it help you.

like image 35
mastak Avatar answered Sep 20 '22 12:09

mastak