Method for lossless conversion of C from Image to Icon

  • 2021-12-11 18:44:39
  • OfStack

For example, the common methods in the market are:


var handle = bmp.GetHicon();  // Get the icon handle 
return Icon.FromHandle(handle); // Get icons through handles 

The problem with this method is that if the image is transparent background, the edge of Icon obtained is rough, like the effect of padding a layer of background color first and then removing color, which is very unsatisfactory. Friends who have used it all know. It has not been studied whether there is a problem with bmp. GetHicon or Icon. FromHandle, so we will work hard in the future.

The following is a perfect conversion method:


/// <summary>
///  Conversion Image For Icon
/// </summary>
/// <param name="image"> To convert to an icon Image Object </param>
/// <param name="nullTonull"> When image For null Whether to return when null . false Sell the reference exception </param>
/// <exception cref="ArgumentNullException" />
public static Icon ConvertToIcon(Image image, bool nullTonull = false)
{
  if (image == null)
  {
    if (nullTonull) { return null; }
    throw new ArgumentNullException("image");
  }

  using (MemoryStream msImg = new MemoryStream()
           , msIco = new MemoryStream())
  {
    image.Save(msImg, ImageFormat.Png);

    using (var bin = new BinaryWriter(msIco))
    {
      // Write icon header 
      bin.Write((short)0);      //0-1 Reservation 
      bin.Write((short)1);      //2-3 File type. 1= Icons , 2= Cursor 
      bin.Write((short)1);      //4-5 Number of images (icons can contain multiple images) 

      bin.Write((byte)image.Width); //6 Icon width 
      bin.Write((byte)image.Height); //7 Icon height 
      bin.Write((byte)0);      //8 Number of colors (if pixel bit depth >=8 , fill in 0 . It is obvious that reaching 8bpp The minimum number of colors is 256 , byte Insufficient indication) 
      bin.Write((byte)0);      //9 Keep it. Must be 0
      bin.Write((short)0);      //10-11 Palette 
      bin.Write((short)32);     //12-13 Position depth 
      bin.Write((int)msImg.Length); //14-17 Bitmap data size 
      bin.Write(22);         //18-21 Bitmap data start byte 

      // Write image data 
      bin.Write(msImg.ToArray());

      bin.Flush();
      bin.Seek(0, SeekOrigin.Begin);
      return new Icon(msIco);
    }
  }
}

As the code shows, the principle of the method is:

1. First, encode image into png
2. Package png as it is into an icon

Although the first step is recoding, png is a lossless format, and the image quality will not be lost at all. Then, the converted png is stuffed into the icon intact at the binary level. Therefore, the whole method can afford the saying of "no damage". Please feel free to use it if you mind distortion. Note: The method does not check and process the original image size, so please ensure that the size of the original image conforms to the icon specification before passing it in; In addition, the caller is not responsible for destroying the original drawing, so please be responsible for it externally.

Here's the gossip:

In order to solve this problem, it took a lot of effort. After several laps in places with many miracles, such as stackoverflow and codeproject, I couldn't find a satisfactory way. After thinking about it once, I felt that I could try it from the icon format. Then I found a document about icon format in the universal msdn: https://msdn.microsoft.com/en-us/library/ms997538.aspx.

-Wen Bi-


Related articles: