Problem converting .ico in byte array to Image object in .net
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.
开发者_Python百科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?
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
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.
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.
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?
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.
Here there is a very clean and detailed project for extracting multiple icons from a file: http://www.codeproject.com/Articles/6171/Access-multiple-icons-in-a-single-icon-file
I added this function:
Private Sub readIcoFromWebLink(ByVal link As Uri)
' Create the byte array and read it in
'
Dim byteArray() As Byte = New WebClient().DownloadData(link)
' Load the stream with the bytearray
'
icoStream = New MemoryStream(byteArray)
icoStream.Seek(0, SeekOrigin.Begin)
End Function
and changed construnctor to this:
Public Sub New(ByVal filename As String)
If IO.File.Exists(filename) Then
readIcoFile(filename) ' Load the file
Else
readIcoFromWebLink(New Uri(filename))
End If
icoHeader = New iconHeader ' Read the header
Dim counter As Integer ' Read each icons header
For counter = 1 To icoHeader.Count
icons.Add(New iconEntry(counter - 1))
Next
End Sub
to add support for loading icons from web links in multiIcon
class.
精彩评论