使用 VB.NET 提取和显示图标






4.35/5 (8投票s)
2007 年 3 月 22 日
6分钟阅读

52552

1536
使用纯 VB.NET 代码提取和显示图标作为位图对象。
引言
作为 .NET 框架用户遇到的“bug”之一,就是缺乏对带有 alpha 通道的 32 位图标的支持。这可能是最令人烦恼的 bug 之一,因为 32 位图标能为用户界面增添额外的魅力和专业性,其半透明特性使其能够与您或您应用程序的最终用户可能选择的任何背景融合。本文将解释图标如何在 .ico 文件中存储,并提供能够处理 4 位、8 位、24 位和 32 位图标并正确显示带 alpha 通道的 32 位图标的代码。
延伸阅读
有关图标的更多信息可以在以下文章中找到
- John Hornick 在 1995 年于 MSDN 上发表的一篇文章
- Narb M 在 CodeProject 上发表的关于如何使用 Windows API 获取 32 位图标的文章
- Joshua Flanagan 在 CodeProject 上发表的关于将位图转换为图标的文章
使用代码
在您的应用程序中包含
以上链接提供了源代码和一个测试该代码的示例应用程序。您可以将 Icons.dll 引用到您的项目中,将 Icons 项目添加到您的解决方案中,或者将 IconFile.vb、IconImage.vb 和 IconImageCollection.vb 添加到项目中。Icons 项目和 Icons.dll 的默认命名空间是 System.Drawing,因此命名空间保持整洁有序。
对象概述
该项目包含五个类:三个公共类和两个内部类。公共类是
IconFile
表示一个图标文件。构造函数参数可以是文件名、FileInfo 或 Stream,从中加载图标信息。包含一个 GetIcon 函数,该函数返回最符合指定大小和像素格式的图标。还包含一个 Entries 属性,该属性返回一个 IconImageCollection。IconImage
表示图标文件中的单个图标图像。使用一个内部构造函数,该构造函数接收用于创建父 IconFile 的流。公开一个 Icon 属性,该属性将图标图像作为 Bitmap 返回,以便您的应用程序可以根据需要轻松编辑。不应从您的代码实例化 IconImages。IconImageCollection
IconFile 中的 IconImages 集合。公开了标准的集合方法、函数和属性。
内部类是
SizeCollection
一个大小集合,用于在 IconFile.GetIcon 中查找最佳图标PixelFormatCollection
一个像素格式集合,用于在 IconFile.GetIcon 中查找最佳图标
关注点
我想花些时间来解释图标文件格式,因为我在(尽管进行了无数次密集的 Google 搜索)仅在一个地方找到了完成项目所需的信息,而且我再也找不到它了。每个图标文件都有一个头,即 IconDir 结构,其中包含以下成员:
名称 |
大小 |
目的 |
|
Int16/Short/Word |
两个保留字节,都应为零 |
|
Int16/Short/Word |
两个字节,指定此资源的类型,因为图标文件格式和光标文件格式非常相似。对于图标,应为 1。 |
|
Int16/Short/Word |
指定图标文件中图标的数量 |
|
IconDirEntry |
指定文件中每个图标的信息 |
如上所述,对于每个图标,都有一个相应的 IconDirEntry,它指定了图标的大小和在文件中的位置
名称 |
大小 |
目的 |
|
字节型 |
图标的宽度 |
|
字节型 |
图标的高度。有时我发现此值是图标高度的两倍,但这并不常见,因此我的代码会忽略此值。 |
|
字节型 |
图标中使用的颜色数量。如果使用了所有 256 种或更多颜色(即 8bpp+),则此值为零。 |
|
字节型 |
另一个保留字节 |
|
Int16/Short/Word |
图标图像中的平面数 |
|
Int16/Short/Word |
编码每个像素使用的位数 |
|
Int32/Integer/DWord |
图标及其位图头所占的字节数 |
|
Int32/Integer/DWord |
图标在文件中的第一个字节的地址 |
在指定完所有图标的信息后,文件会直接进入第一个图标。每个图标都有一个 BitmapInfoHeader、一个颜色表以及一个 XOR 和一个 AND 蒙版。对于了解位图文件格式的人来说,这可能看起来很熟悉,但对于不熟悉的人,我将解释:
名称 |
大小 |
目的 |
|
Int32/Integer/DWord |
BitmapInfoHeader 的大小(以字节为单位)(通常为 40) |
|
Int32/Integer/DWord |
图标的宽度 |
|
Int32/Integer/DWord |
图标的高度。此处实际的值是图标高度的两倍,因为 Windows 需要知道 XOR 和 AND 蒙版的高度。 |
|
Int16/Short/Word |
图标中的平面数 |
|
Int16/Short/Word |
编码每个像素使用的位数 |
|
Int32/Integer/DWord |
在位图文件中,此 DWord 描述了图像使用的压缩方式。在图标中,这总是 0,表示没有压缩。 |
|
Int32/Integer/DWord |
图像的大小(以字节为单位) |
|
Int32/Integer/DWord |
这些 DWord 在图标中未使用,应为零。 |
然后我们进入 RGB 表、XOR 和 AND 蒙版。在这里,根据图标图像的 BitCount,会发生一些不同的情况。
- 在 4bpp 图标和 8bpp 图标中,RGB 表包含多种颜色,然后 XOR 表提供一个数字数组,这些数字是 RGB 表中相应像素应采用的颜色的索引。
- 在 24bpp 图标中,实际上没有 RGB 表,XOR 数字是相应像素应采用的颜色的蓝色、绿色和红色值。
- 在 32bpp 图标中,实际上没有 XOR 蒙版,RGB 表为每个像素提供单独的 RgbQuads。
RGB 表使用 RgbQuads 来指定其颜色
名称 |
大小 |
目的 |
|
字节型 |
像素的蓝色值 |
|
字节型 |
像素的绿色值 |
|
字节型 |
像素的红色值 |
|
字节型 |
对于 4 位和 8 位图标为 0,对于 24 位图标不包含,或者对于 32 位图标为像素的 Alpha 值。 |
AND 蒙版指定哪些像素显示颜色,哪些像素是透明的。它基本上是一个 1bpp 的 XOR 蒙版,表示不透明和透明。这最初给我带来了麻烦,因为我无法让 AND 蒙版在 16x16 和 48x48 图标上对齐。这是因为 XOR 和 AND 蒙版中的索引会进行填充,以使每一行都以 32 位边界结束。对于 XOR 蒙版,这通常没问题,因为行最终会以 32 位边界结束(16x4=64,可以被 32 整除)。
一旦读取了 AND 蒙版,您就到达了图标的末尾,可以准备将字节转换为正确的索引号,并使用它们来构建图标的位图。
读取文件很简单,只需使用 Binary Reader。将字节转换为四位块是通过将字节转换为两位十六进制数字,并使用第一个数字表示第一个像素,第二个数字表示第二个像素来完成的。
结论
此代码现在允许开发人员通过在工作中支持 32 位图标来增强其应用程序的专业性,同时保持跨平台兼容性。