views:

344

answers:

5

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?

A: 

We had an issue with ico files in Media Browser I recall it happened cause GDI+ was choking on icons that had PNGs in them, stripping them out fixed it. Or applying: http://support.microsoft.com/kb/971644 on Vista fixed it.

There is possibly a similar patch for server 2003.

Sam Saffron
I'm not seeing a 2k3 version. Can you explain what you mean by stripping out the pngs (or a reference that would get me started)? Not sure how and not turning up search results.
rchern
A: 

Hi,

Just a thought: are you sure you're not messing up with any of the involved streams?

I know GDI+ does not like that you close a stream before it has finished with it, and the error are always not very helpful in these cases.

Would you have an exact repro code so we can fully help you?

Simon Mourier
The only thing you're missing would be to set imageUrl to http://sstatic.net/stackoverflow/img/favicon.ico or http://google.com/favicon.ico
rchern
uhh :) sorry, I don't understand this comment
Simon Mourier
A: 

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.

mastak
I'm not sure I understand. I'm only trying to do part #2. The point of my question was that writing out to the response works in part #1 just fine (without the header). Part #2 **does not work** though.
rchern
can you provide your imageUrl for me to test your server response ? Because I don't see any issues with Part#2.
mastak
See my comment on Simon's answer.
rchern
well.. it works great on my server.. but.. plz look to official comments about using System.Drawing in ASP.NET: http://msdn.microsoft.com/en-us/library/system.drawing.aspx - the new isn't good :(... the one thing how to solve your issue is check .Net framework versions and windows upgrades between working and bad servers.
mastak
.net framework versions are identical and all available windows updates have been installed. That's great that it works on your server - it works on 2 of mine too. Still leaves the 1 server I need it working on, which is the entire point of my posting this question.
rchern
A: 

There's a note in the docs about keeping the stream open for the lifetime of the image. Could that be the issue here?

http://msdn.microsoft.com/en-us/library/93z9ee4x.aspx

You must keep the stream open for the lifetime of the Image.

The stream is reset to zero if this method is called successively with the same stream.

wes
No. My code is just as listed in the OP. I create a new stream, and on the next line try to put it into the Image. No using statement. Nothing happening with the stream in between those actions.
rchern
+2  A: 

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.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

Tom Robinson
Accepting this one because it gave me the idea of running the daily task locally that converts .ico to .png and ftp'ing those to the server so that the web app can just use the .png files.
rchern