学习

在C#中将Image文件转换成Icon文件

最近写程序时,要给程序做一个ico图标,以前都是画好在网上找在线转换程序。但每次都上网找,其一是麻烦,其二,当没网的时候,就没有办法了。于是,我准备自己写一个程序来帮我做这些事情。

这虽然看起来是很简单的一个问题,但是却遇到了种种奇怪的问题,接下来我将详细说一下。

使用.NET自带的函数

.NET的Bitmap类有一个Bitmap.Save()函数,此函数可以把bitmap转换成指定类型的图片,其中包括Icon,了解之后接下来就好办了。

首先,把Image转成Bitmap:

接下来,使用Bitmap内置函数将Bitmap转换成Icon:

这样,就完成了将Image到Icon的转换。

但是,这样做有一些问题,在此说明一下:

这样做的话,在资源管理器和图片浏览器中,可以正常显示图标。但是,当用Winhex打开此图标后,我发现文件头根本不是Icon的文件头,而是Png文件,Winhex也很明确的说明了,这不是一个图标文件。
1
2
然后,就有了下边的想法:

手动将Image转换成Icon格式

这步几乎是没有出现什么问题的,谷歌了一下,出现了好多前人写的文章,大概思路都是,手动写入Icon的文件头,然后再将Image的数据写入,这样,就可以转换成Icon。

在参考了几篇文章后,写出如下代码:

这样,就完成了从Image到Icon的手动转变,但是接下来的步骤再一次出现了问题。

将Icon写入到本地文件

这一步我是没有想到会出问题的,建立一个FileStream流,利用Icon.Save()函数将Icon存入流,然后将流保存到本地就可以了。

但是,偏偏这一步出现了一个意料之外的问题:在这样写入之后,在资源管理器和图片浏览器里,无法正常显示图标,会识别为无法识别的格式。
3
但是,用Winhex打开后,则显示其为Icon文件,且预览图可以正常显示。
4
5
此问题困扰了我好久,在多次测试之后,我发现,只有Png格式的图片在这样转换成Icon后,才可以正常在资源管理器中显示,在被其他程序所识别并使用,而Bmp,Jpg等格式转换后,则会出现无法识别的情况。

所以,多做一次转换,先将Image转换成Bitmap,然后再转换成Png格式,写出如下代码:

这样,转换后的Icon文件才是正确的Icon文件,然后,建个FileStream流写入即可:
6
7

总结

将以上代码综合起来,完整转换代码如下:

当然,在进行转换时,还有一系列刷工作,比如判断所选文件是否为Image,异常检测等,此处并没有写明。

后记

虽然以上代码已经可以几乎完美转换Image为Icon文件了,但是后来在修改中发现了一个问题:在加载图片文件后,除非程序关闭,否则无法
正常释放图片文件,经查错后,发现是Image.FromFile()这里出现的问题,用这个函数读取图片时,会无法释放,具体原因暂时还没有研究,解决方法为,将文件以流形式读取后,在转换为Image:

这样做的话,就能解决一直占用的问题了,但是,会出现一个新的问题,即不进行格式转换,直接使用image.Save(msImg, ImageFormat.Png)函数的话,会出现未知错误,此处我并没有研究原因。

完整项目详见Github: Image2Ico

如有错误或不合理之处,欢迎批评指出。

© 本作品采用CC BY 4.0协议进行许可。非原创(转载)文章版权归原作者所有。
© 此文章可随意转载引用,但请注明来源: 在C#中将Image文件转换成Icon文件


不说点什么吗