C#如何实现Image无损转Icon

189 阅读3分钟
  • 前言

    • 本文描述如何使用C# 实现图像转图标。正常情况下我们会直接使用Icon类的Icon.FromHandle(image.GetHicon())方法进行图像转Icon图标,但是众所周知的是这个方法的缺点是转换的图标会模糊、与原图不一致。那么如何获取高清的图标呢?

    • 我们可以使用自定义填写数据的方式实现,如下图蓝色区域为Icon文件的头部信息,通过查看图像的头部信息,我们只需要按位填入对应的数值并填入原图byte[]类型数据即可创建Icon图像。

image.png

  • 头部数据对照:

    • 预 留:(地址00-01)(设置0)
    • 类 型:(地址02-03)(1=ICO)
    • 图片数量:(地址04-05)(默认1)
    • 图像宽高:(地址06-07)(图标大小16、32...)
    • 颜色数量:(地址08)(如果>=8bpp 设置0 )
    • 预 留:(地址09)(设置0)
    • 颜色平面:(地址10-11)(默认1)
    • 数据大小:(地址14-17)(图像数据长度)
    • 数据偏移:(地址18-21)(设置22,即图像数据起始位)
  • 两种转换方式效果比较:

    • 如下图,左图为自定义实现转换,右图为直接使用Icon转换。

    在这里插入图片描述

  • 运行效果

![在这里插入图片描述](i-blog.csdnimg.cn/direct/8486… =700x)

  • 代码

    • 自定义方式

     public void ConvertToIcon(string imagePath, string outputPath, byte size = 128)
     {
         using (Image srcImage = Image.FromFile(imagePath))
         {
             
             // 创建内存流保存ICO数据
             using (MemoryStream stream = new MemoryStream())
             {
                 // 写入时ICO文件头:输入小端序,低位在前;
                 // 输出时大端序,高位在前。
                 // 1、保留字
                 stream.Write(new byte[] { 0, 0 }, 0, 2);
                 // 2、类型(1=ICO)
                 stream.Write(new byte[] { 1, 0 }, 0, 2);
                 // 3、图像数量
                 stream.Write(new byte[] { 1, 0 }, 0, 2);
                 // 4、数据偏移
                 int dataOffset = 6 + 16;
                 using (Image newImg = new Bitmap(srcImage, new Size(size, size)))
                 {
                     //5、创建图像数据数组(byte[])、获取图像数据 
                     byte[] imgData = null;
                     using (MemoryStream imageStream = new MemoryStream())
                     {
                         newImg.Save(imageStream, ImageFormat.Png);
                         imgData = imageStream.ToArray();
                     }
                     //6、 设置图标 宽、高
                     stream.Write(new byte[] { size, size }, 0, 2);
                     //7、 设置颜色数(0=真彩色)、保留字
                     stream.Write(new byte[] { 0, 0 }, 0, 2);
                     //8、 设置颜色平面
                     stream.Write(new byte[] { 1, 0 }, 0, 2);
                     //9、 设置每像素位数
                     stream.Write(new byte[] { 32, 0 }, 0, 2);
                     //10、设置图像数据大小
                     stream.Write(BitConverter.GetBytes(imgData.Length), 0, 4);
                     //11、设置数据偏移
                     stream.Write(BitConverter.GetBytes(dataOffset), 0, 4);
                     //12、写入图像数据
                     stream.Write(imgData, 0, imgData.Length);
                     stream.Flush();
                     //保存图标
                     File.WriteAllBytes(outputPath, stream.ToArray());
                 }
             }
         }
     }
    
  • Icon直转方式

    public Icon ConvertToIcon(string source, string target, int size = 128)
     {
         using (Image sourceImage = Image.FromFile(source))
         {
             using (Bitmap newImage = new Bitmap(sourceImage, size, size))
             {
                 using (FileStream stream = new FileStream(target, FileMode.Create))
                 {
                     Icon icon = Icon.FromHandle(newImage.GetHicon());
                     icon.Save(stream);
                     return icon;
                 }
             }
         }
     }
    
  • 窗体UI

    public partial class MainForm : Form
     {
         private string sourcePath = null;
         private Image sourceImage;
         private Image targetImage;
         public MainForm()
         {
             InitializeComponent();
         }
         private void btn_SelectedImage_Click(object sender, EventArgs e)
         {
             OpenFileDialog openFile = new OpenFileDialog();
             openFile.InitialDirectory = Application.StartupPath;
             openFile.Filter = "(图像文件)|*.png;*.jpg;*.jpeg;*.bmp";
             if (openFile.ShowDialog() == DialogResult.OK)
             {
                 sourcePath = openFile.FileName;
                 sourceImage = Image.FromFile(sourcePath);
                 picx_SourceImage.Image = sourceImage;
             }
         }
         private void btn_ConvertImage_Click(object sender, EventArgs e)
         {
             ConvertToIcon(sourcePath, "output1.ico", (byte)128);
             picx_TargetImage.Image = Image.FromFile("output1.ico");
             ConvertToIcon(sourcePath, "output2.ico", 128);
             picx_TargetImage2.Image = Image.FromFile("output2.ico");
         }
     }
    
  • 总结

    • 本文描述了如何无损实现图像转icon。主要是直接使用Icon类进行图像转换图标会与原图又不一致。在网上查找了一些方法实现了Icon无损转换功能。方便后面实现图标转换,其实网上有蛮多的在线图标转换工具站,嫌麻烦的也可以直接在网上找,这里主要是顺便学习一下如何自己编程实现。 ![在这里插入图片描述](i-blog.csdnimg.cn/direct/6a2d… =100x)
  • 最后

    • 如果你觉得这篇文章对你有帮助,不妨点个赞再走呗!
    • 如有其他疑问,欢迎评论区留言讨论!
    • 也可以关注微信公众号 [编程笔记in] ,一起交流学习!
    • 项目地址: gitee.com/incodenotes…