Преобразование изображения в значок в С#
У меня есть проект, который преобразует файл формата изображения в файл значка. Однако после преобразования изображения цвет изображения изменяется.
Вот мой код
Bitmap theBitmap = new Bitmap(theImage, new Size(width, height));
IntPtr Hicon = theBitmap.GetHicon();// Get an Hicon for myBitmap.
Icon newIcon = Icon.FromHandle(Hicon);// Create a new icon from the handle.
FileStream fs = new FileStream(@"c:\Icon\" + filename + ".ico", FileMode.OpenOrCreate);//Write Icon to File Stream
![enter image description here]()
Кто-нибудь знает, как это решить?
Ответы
Ответ 1
Bitmap.GetHicon() очень хорош в создании иконок, которые хорошо работают на любой версии Windows, которая может выполнять код .NET. Включая старые, Windows 98 и Windows 2000. Операционные системы, которые еще не поддерживали модные значки.
Таким образом, вы получите иконку только с 16 цветами, используя предварительно приготовленную палитру с основными цветами. Это, как правило, приводит к неутешительным результатам, мягко говоря.
Классы Bitmap или Icon не имеют возможности получить лучший результат. В общем, вам нужно использовать редактор иконок для создания хороших иконок. Который должен включать в себя несколько изображений разных размеров и глубины цвета, чтобы они хорошо работали с любым параметром видеоадаптера и любой версией операционной системы. В частности, уменьшение цвета с 16 миллионов до 256 или 16 цветов - это нетривиальная операция с несколькими способами, ни один из которых не является идеальным. Хороший редактор иконок имеет инструменты, необходимые для того, чтобы это работало достаточно хорошо.
ОБНОВЛЕНИЕ: проблема становится очень устаревшей, XP - это прошлый год. Сегодня вы можете создать очень красивый значок с этим кодом.
Ответ 2
Если вам нужны только 32-разрядные значки, вы можете использовать FreeImage http://freeimage.sourceforge.net
string icoFile = "C:\path\to\file.ico";
FreeImageBitmap fiBitmap = new FreeImageBitmap(theBitmap);
fiBitmap.Rescale(48, 48, FREE_IMAGE_FILTER.FILTER_BICUBIC);
fiBitmap.Save(icoFile);
fiBitmap.Rescale(32, 32, FREE_IMAGE_FILTER.FILTER_BICUBIC);
fiBitmap.SaveAdd(icoFile);
fiBitmap.Rescale(16, 16, FREE_IMAGE_FILTER.FILTER_BICUBIC);
fiBitmap.SaveAdd(icoFile);
Если вам нужна полная поддержка 32, 8, 4 и 1-битных значков, вам нужно будет создать собственный писатель формата ico. Я столкнулся с этой проблемой при разработке моего собственного png png для ico для конвертера ico http://iconverticons.com
На самом деле это не слишком сложно; спецификации формата файла ico, которые вам понадобятся здесь:
http://msdn.microsoft.com/en-us/library/ms997538.aspx
Вам также понадобится спецификация заголовка Bitmap, так как ico является подмножеством растрового изображения:
http://msdn.microsoft.com/en-us/library/dd183376.aspx
Ответ 3
Вы можете попробовать следующее:
Bitmap theBitmap = new Bitmap(theImage, new Size(width, height));
theBitmap.Save(@"C:\Icon\" + filename + ".ico", System.Drawing.Imaging.ImageFormat.Icon);
Ответ 4
Это мой метод, он может преобразовать PNG в значок, включая прозрачность:
public void ConvertToIco(Image img, string file, int size)
{
Icon icon;
using (var msImg = new MemoryStream())
using (var msIco = new MemoryStream())
{
img.Save(msImg, ImageFormat.Png);
using (var bw = new BinaryWriter(msIco))
{
bw.Write((short)0); //0-1 reserved
bw.Write((short)1); //2-3 image type, 1 = icon, 2 = cursor
bw.Write((short)1); //4-5 number of images
bw.Write((byte)size); //6 image width
bw.Write((byte)size); //7 image height
bw.Write((byte)0); //8 number of colors
bw.Write((byte)0); //9 reserved
bw.Write((short)0); //10-11 color planes
bw.Write((short)32); //12-13 bits per pixel
bw.Write((int)msImg.Length); //14-17 size of image data
bw.Write(22); //18-21 offset of image data
bw.Write(msImg.ToArray()); // write image data
bw.Flush();
bw.Seek(0, SeekOrigin.Begin);
icon = new Icon(msIco);
}
}
using (var fs = new FileStream(file, FileMode.Create, FileAccess.Write))
{
icon.Save(fs);
}
}
Ответ 5
Кажется, что .Net Framework
не имеет иконки; поэтому вы не можете сохранить настоящий файл. Сохраненный файл является только PNG файлом.
Ответ 6
Решено для Vista и выше
Если вам нужно динамически создавать значки (у моего приложения есть изменяющееся число), вы бы
вам не повезло, если бы вы все равно должны были использовать редактор.
Ruiwei Bu (darkfall) имеет github gist, показывающий, как. Разумеется, мы не поддерживаем XP и ниже, это сделало это для нас.
Образец с использованием класса я поместил этот код в:
Dim ico As New Icons With {.state = Iconstates.OK, .UpgradeNum = "123"}
Dim tempfile = "C:\file5.ico"
ico.GetIcon(tempfile)
Dim newicon As New Icon(tempfile)
Класс с кодом darkfall:
Imports System.Drawing.Imaging
Imports System.IO
Public Class Icons
Property UpgradeNum As String
Property state As Iconstates
Function GetIcon(Optional OptionalSave As String = "") As Icon
Dim bmp As New Bitmap(16, 16)
Using g = Graphics.FromImage(bmp)
g.Clear(Color.Transparent)
g.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
Select Case state
Case Iconstates.OK
g.FillEllipse(Brushes.Green, 1, 1, 14, 14)
End Select
g.DrawString(UpgradeNum, New Font("Small Fonts", 6), Brushes.Aquamarine, 0, 0)
End Using
bmp.Save(OptionalSave & ".png")
Dim outputStream As New MemoryStream()
Dim size As Integer = bmp.Size.Width
If Not ConvertToIcon(bmp, outputStream, size) Then
Return Nothing
End If
If OptionalSave > "" Then
Using file = New FileStream(OptionalSave, FileMode.Create, System.IO.FileAccess.Write)
outputStream.WriteTo(file)
file.Close()
End Using
End If
outputStream.Seek(0, SeekOrigin.Begin)
Return New Icon(outputStream)
End Function
''' <summary>
''' Converts a PNG image to an icon (ico)
''' </summary>
''' <param name="inputBitmap">The input stream</param>
''' <param name="output">The output stream</param>
''' <param name="size">Needs to be a factor of 2 (16x16 px by default)</param>
''' <param name="preserveAspectRatio">Preserve the aspect ratio</param>
''' <returns>Wether or not the icon was succesfully generated</returns>
Public Shared Function ConvertToIcon(inputBitmap As Bitmap, output As Stream, Optional size As Integer = 16, Optional preserveAspectRatio As Boolean = False) As Boolean
Dim width As Single = size, height As Single = size
Dim newBitmap = New Bitmap(inputBitmap, New Size(CInt(width), CInt(height)))
If newBitmap Is Nothing Then
Return False
End If
' save the resized png into a memory stream for future use
Using memoryStream As New MemoryStream()
newBitmap.Save(memoryStream, ImageFormat.Png)
Dim iconWriter = New BinaryWriter(output)
If output Is Nothing OrElse iconWriter Is Nothing Then
Return False
End If
' 0-1 reserved, 0
iconWriter.Write(CByte(0))
iconWriter.Write(CByte(0))
' 2-3 image type, 1 = icon, 2 = cursor
iconWriter.Write(CShort(1))
' 4-5 number of images
iconWriter.Write(CShort(1))
' image entry 1
' 0 image width
iconWriter.Write(CByte(width))
' 1 image height
iconWriter.Write(CByte(height))
' 2 number of colors
iconWriter.Write(CByte(0))
' 3 reserved
iconWriter.Write(CByte(0))
' 4-5 color planes
iconWriter.Write(CShort(0))
' 6-7 bits per pixel
iconWriter.Write(CShort(32))
' 8-11 size of image data
iconWriter.Write(CInt(memoryStream.Length))
' 12-15 offset of image data
iconWriter.Write(CInt(6 + 16))
' write image data
' png data must contain the whole png data file
iconWriter.Write(memoryStream.ToArray())
iconWriter.Flush()
End Using
Return True
End Function
End Class
' https://gist.github.com/darkfall/1656050
'=======================================================
'Service provided by Telerik (www.telerik.com)
'Conversion powered by NRefactory.
'Twitter: @telerik
'Facebook: facebook.com/telerik
'=======================================================