Проблема преобразования .ico в массив байтов в объект Image в .net
Я пытаюсь принимать значки и добавлять их к динамическому изображению, которое я создаю. См. StackFlair. Код сайта работает нормально локально и на одном общем сервере хостинга. blah blah, бесплатный хостинг, вы получаете то, за что платите, blah blah Моя проблема в том, что я получаю исключение из новой настройки хостинга. Это исключение происходит только для файлов .ico.. Я могу обрабатывать .gif и .png изображения просто отлично на всех проверенных серверах (т.е. изображении гравитара). Фавиконы, которые я пытаюсь использовать, являются знаками из сети SE, но даже http://www.google.com/favicon.ico приводит к следующему исключению.
System.ArgumentException: параметр недействителен.
- System.Drawing.Image.FromStream(поток потока, логическое использованиеEmbeddedColorManagement, логическое значение validateImageData)
- System.Drawing.Image.FromStream(поток потока)
Ниже перечислены варианты кода, который я пытаюсь сделать. Я получаю тот же Параметр недействительным исключением для всех вариантов.
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);
Все они работают нормально локально и на сервере плохого хостинга. Ни один из них не работает на сервере, на котором я хочу быть включенным. Используя вывод Trace, я могу проверить, что длина массива содержит правильное количество байтов. Если я сделаю следующее, я увижу изображение, отображаемое как ожидалось.
Response.Clear();
Response.BinaryWrite(imageBytes);
Response.End();
Если я прохожу через массив и выписываю каждое значение байта, вывод идентичен моему локальному экземпляру на сервер, на котором я получаю исключение.
Если это помогает, сервер, на котором мой код не работает, является сервером Windows 2003 с sp2.
Очевидно, что фреймворк говорит мне, что поток байтов недействителен, но все, что я проверил, проверяет. Любые идеи о том, почему этот конкретный сервер задыхается от файлов .ico?
Ответы
Ответ 1
У меня есть обходное решение. Используйте ImageMagick для преобразования файлов ico в файлы png:
convert favicon.ico[0] favicon.png
Тогда с ними легко работать. ImageMagick предварительно установлен на множество общих хостов или вы можете загружать предварительно скомпилированные двоичные файлы для Windows.
Если вы оставите [0], вы получите серию файлов favicon-0.png favicon-1.png и т.д., если в файле .ico сохранено более одного образа значка. Затем вам нужно будет отсортировать их, чтобы выбрать тот, который наиболее близок к тому, что вы хотите: 16x16 с альфа-прозрачностью. (Я включаю 32x32 и 48x48 в свои файлы favicon, для пользователей IE, которые перетаскивают ярлыки для Интернета на свой рабочий стол.) ImageMagick сохраняет прозрачность при преобразовании в png.
Значок шестеренки stackapps.com/favicon.ico имеет два изображения. Первая имеет альфа-прозрачность и отлично смотрится на светло-сером фоне #DBDCDB.
Я предполагаю, что вы создаете динамическое изображение, подобное http://i.stack.imgur.com/SNHfF.png на сервере, вместо того, чтобы отправлять все 6 значков верхнего сайта в браузер, Если нет, по-прежнему рекомендуется отправить значки, преобразованные в png, потому что они не предназначены для рендеринга в веб-страницах.
... Том
Ответ 2
Я воспроизвел вашу проблему на Windows Server 2003 с пакетом обновления 2 (SP2) и основал решение. Ваша ошибка заключалась в ответе на использование HTTP, поэтому вы должны указать тип содержимого ответа.
Также я добавил "content-disposition" в заголовок ответа, но не имеет значения и не требуется. Я использовал его только для проверки ответа сервера через браузер.
// 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();
и серверная часть
// 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
Надеюсь, это поможет вам.
Ответ 3
У нас была проблема с файлами ico в Media Browser Я помню, что это произошло, потому что GDI + задыхался от икон, в которых были PNG, удаляя их это исправлено. Или примените: http://support.microsoft.com/kb/971644 в Vista исправил его.
Возможно, аналогичный патч для сервера 2003.
Ответ 4
Просто мысль: вы уверены, что не вникаете в какие-либо вовлеченные потоки?
Я знаю, что GDI + не нравится, что вы закрываете поток до его завершения, и ошибка всегда не очень полезна в этих случаях.
У вас есть точный репрограммный код, чтобы мы могли вам в полной мере помочь?
Ответ 5
В документах есть примечание о том, чтобы сохранить поток открытым для жизни изображения. Это может быть проблема?
http://msdn.microsoft.com/en-us/library/93z9ee4x.aspx
Вы должны оставить поток открытым для время жизни изображения.
Поток reset равен нулю, если этот метод называется последовательно с тот же поток.
Ответ 6
Здесь есть очень чистый и подробный проект для извлечения нескольких значков из файла:
http://www.codeproject.com/Articles/6171/Access-multiple-icons-in-a-single-icon-file
Я добавил эту функцию:
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
и изменил construnctor на это:
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
добавить поддержку для загрузки значков из веб-ссылок в классе multiIcon
.