visual - Convert image to icon in c#

visual studio create icon from png (4)

I have a project that converts an image format file into an icon file. However, after converting the image, the color of the image changes.

Here is my code

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

Anybody know how to solve this?

Solved for Vista and higher

If you have to dynamically generate icons (my app has a changing number), you'd be out of luck if you had to use an editor anyway.

Ruiwei Bu (darkfall) has a github gist showing how. Since of course we don't support XP and lower this did it for us.

Sample using a class I put that code in:

Dim ico As New Icons With {.state = Iconstates.OK, .UpgradeNum = "123"}
Dim tempfile = "C:\file5.ico"
Dim newicon As New Icon(tempfile)

The class with darkfall's code:

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

      ' 2-3 image type, 1 = icon, 2 = cursor

      ' 4-5 number of images

      ' image entry 1
      ' 0 image width
      ' 1 image height

      ' 2 number of colors

      ' 3 reserved

      ' 4-5 color planes

      ' 6-7 bits per pixel

      ' 8-11 size of image data

      ' 12-15 offset of image data
      iconWriter.Write(CInt(6 + 16))

      ' write image data
      ' png data must contain the whole png data file

    End Using

    Return True
  End Function

End Class
'Service provided by Telerik (
'Conversion powered by NRefactory.
'Twitter: @telerik

Bitmap.GetHicon() is very good at creating icons that work well on any Windows version that can run .NET code. Including the old ones, Windows 98 and Windows 2000. Operating systems that did not yet support fancy icons.

So what you get is an icon with only 16 colors, using a pre-cooked palette with basic colors. This tends to generate disappointing results, to put it mildly.

The Bitmap or Icon classes do not have an option to get a better result. In general you'll need to use an icon editor to create good icons. Which should include multiple images in different sizes and color depths so they'll work well with any video adapter setting and any operating system version. Particularly color reduction from 16 million to 256 or 16 colors is a non-trivial operation with multiple ways to do it, none of them perfect. A good icon editor has the tools you need to make that work well enough.

It seems that .Net Framework doesn't have any Icon Encoder; so you can NOT save any real Icon file. The saved file only is a PNG file.

You can try this:

Bitmap theBitmap = new Bitmap(theImage, new Size(width, height));

theBitmap.Save(@"C:\Icon\" + filename + ".ico", System.Drawing.Imaging.ImageFormat.Icon);