本文分享&备忘最近了解到的icon资源在windows平台下相关的一部分知识,所有测试代码都尽可能的依赖win32 API实现。更全面的知识,参考文末列出的”参考资料“。

     关键字:Icon资源存储结构、windows shell下显示哪个图标、如何获取EXE各种长宽的显示图标。

    一个icon资源(可以是*.ico文件,也可以是windows资源节区里的icon group),可以包含多张图片,这些图片有着各自的size或者颜色深度,这些图片可以是bmp格式或者png格式(vista之后支持,一般256*256时使用)。

一、Icon文件的组成

    Icon文件结构由两部分组成:icon文件头和多张图片数据,图片可以是bmp、png:
1、Icon文件头
typedef struct
{WORD idReserved; // Reserved (must be 0)WORD idType; // Resource Type (1 for icons)WORD idCount; // How many images?ICONDIRENTRY idEntries[1]; // An entry for each image (idCount of 'em)
} ICONDIR, *LPICONDIR;

    其中idReserved必须是0;idType对于ICON文件来说必须是1;idCount指明icon文件有多少张图片,也就指明了接下来有多少个ICONDIRENTRY结构体数据。
typedef struct
{BYTE bWidth; // Width, in pixels, of the imageBYTE bHeight; // Height, in pixels, of the imageBYTE bColorCount; // Number of colors in image (0 if >=8bpp)BYTE bReserved; // Reserved ( must be 0)WORD wPlanes; // Color PlanesWORD wBitCount; // Bits per pixelDWORD dwBytesInRes; // How many bytes in this resource?DWORD dwImageOffset; // Where in the file is this image?
} ICONDIRENTRY, *LPICONDIRENTRY;

    其中dwBytesInRes指明本图片占用多少字节,dwImageOffset指明本图片数据开始位置相对文件头的偏移。颜色深度:bColorCount = 1 << (wBitCount * wPlanes),如果大于等于8,则填0。
2、图片数据
    如果是位图格式图片:
typdef struct
{BITMAPINFOHEADER icHeader; // DIB headerRGBQUAD icColors[1]; // Color tableBYTE icXOR[1]; // DIB bits for XOR maskBYTE icAND[1]; // DIB bits for AND mask
} ICONIMAGE, *LPICONIMAGE;

icHeader中只有部分信息是icon文件需要的。icXOR也称为“image“,icAND也称为“mask”。
 
一个有两张位图图片的ico文件,文件头内容(前0x15字节是icon文件头 + ICONDIRENTRY 的内容):
 
 
如果是PNG格式图片,则Icon文件头后边接着的是png数据格式,譬如:
icon中含有一张png图片,文件头内容(前0x15字节是icon文件头 + ICONDIRENTRY 的内容):

 
 
    png格式API相关:虽然LoadImage在vista版本下可以加载含有png格式图片的ico文件,但是windows没有直接API支持应用程序对png、jpeg格式文件的解压使用。在显示png、jpeg格式数据时,有StretchDIBits、SetDIBitsToDevice两API可以使用,但必须先检查硬件是否支持,因为这属于硬件级别的解码支持。想在GetDIBits中使用BI_PNG,获取PNG格式的数据是行不通的,BITMAPINFOHEADER结构体中的biCompression值BI_PNG,仅仅在上述两API中生效。
    为什么在icon文件中有png格式存储:*.ico文件中含有png格式,这是vista以及之后的版本才做的支持,目的是为了减小256*256 ico 文件的size,一般的ico编辑工具都会默认把ico文件中256*256 size的图片保存为png格式,这是微软推荐的保存格式(参考资料5)。xp以及之前的系统用不到256*256格式的ico,所以没有支持。

二、Icon在windows中的显示

    这里的icon特指两种情形:(1)EXE中的icon group资源;(2)*.ico文件。
    EXE文件在windows shell下显示哪个icon,按照MSDN文文件档(参考资料1)的介绍,是这样子:
桌面图标显示哪个ICON图片,有两个步骤,1、选择序号最小的RT_GROUP_ICON,优先字母序号,再找数字序号;2、在RT_GROUP_ICON里面选择合适的RC_ICON:(1)size跟要求的最接近;(2)如果size符合要求的有多个,则选择颜色深度跟显示系统颜色深度匹配的;(3)如果颜色深度没有匹配的,则选择在显示系统支持范围内颜色深度值大的;(4)如果所有的颜色深度都大于显示系统支持范围,则选择颜色深度最低的;(5)系统把8位以及大于8位的颜色深度当作相同深度,这时,系统选择最先遍历到的RC_ICON;(6)如果显示系统的颜色深度是8位,则系统会在16色(颜色深度4位) 和256色(颜色深度8位)之间选择16色的,并且使用系统默认调色板。(这一条规律似乎跟(3)矛盾,有人说这是在安全模式下才成立的)。
    在RT_GROUP_ICON选定的情况下,按照我自己的实践测试:
    自己绘制一个*.ico文件并对各个size做标记,可以发现windows7下exe在选择显示哪个图标的时候,只用到:16 * 16(文件夹内小图标),32 * 32(属性、桌面小图标), 48 * 48(中等图标), 256 * 256(大图标)这四种size,xp下则使用前3种。如果ico中含有png格式,则需要使用VS2008以及以上的IDE,否则rc无法对其进行编译。对于windows显示何种图标参考资料4、5、6有更详细的介绍。

三、从PE文件中提取icon资源

    对于EXE文件,最简单的是使用SHGetFileInfo API,但只能获取16* 16,32 * 32 size的图标。该api如果只指定SHGFI_ICON,则表明使用默认的32*32,如果指定SHGFI_LARGEICON,则表明是32*32,如果指定SHGFI_SMALLICON,则表明是16*16。SHGetFileInfo 还可以根据文件后缀名获取某类文件的图标。
    示例代码:
1、某文件的32 * 32 pixels icon
//获取exe的32 * 32 iconSHFILEINFO sfi;ZeroMemory(&sfi, sizeof(SHFILEINFO));::SHGetFileInfo(L"D:\\a.exe", FILE_ATTRIBUTE_NORMAL, &sfi, sizeof(SHFILEINFO), SHGFI_ICON | SHGFI_LARGEICON);HICON icon_handle = sfi.hIcon;

2、某类文件的32 * 32 pixels icon
//获取*.rmvb文件类型的32 * 32 iconSHFILEINFO sfi;ZeroMemory(&sfi, sizeof(SHFILEINFO));::SHGetFileInfo(L"*.rmvb", FILE_ATTRIBUTE_NORMAL, &sfi, sizeof(SHFILEINFO), SHGFI_ICON | SHGFI_USEFILEATTRIBUTES);HICON icon_handle = sfi.hIcon;

3、 提取其它size的图标,譬如: 48 * 48、256 * 256,则需要使用另外的方法
//获取48 * 48 或者 256 * 256 pixels iconSHFILEINFO sfi;ZeroMemory(&sfi, sizeof(SHFILEINFO));::SHGetFileInfo(L"D:\\b.exe", FILE_ATTRIBUTE_NORMAL, &sfi, sizeof(SHFILEINFO), SHGFI_SYSICONINDEX);HIMAGELIST* imageList = NULL;//SHIL_EXTRALARGE获取48 * 48的图标, SHIL_JUMBO 获取256 * 256的图标。HRESULT hResult = ::SHGetImageList(SHIL_EXTRALARGE , IID_IImageList, (void**)&imageList);HICON icon_handle = NULL;if (hResult == S_OK){hResult = ((IImageList*)imageList)->GetIcon(sfi.iIcon, ILD_NORMAL, &icon_handle);}

     获取到HICON之后,可以使用DrawIcon API执行绘制,也可以使用AlphaBlend“重造轮子”执行绘制。如果要保存为文件,则构造一个ICON文件头,再把HICON转换为DIB数据拼在ICON文件头后边,注意:hbmColor和hbmMask这两个句柄的DIB数据都要有。我试过直接拿bmp位图数据修改:前头加上icon文件头,BITMAPINFOHEADER的biHeight *= 2,保存后各种size的图片都变残缺了(好像是被挖去了一个二维码),只有256*256的图片少部分像素丢失,显示稍微正常点,可能是因为256*256的图片mask部分用处不大的缘故,另外,还发现这样子的256*256 icon图片是留有透明通道的,这也说明,*.bmp位图文件中是可以有透明通道的,只是显示图片的工具把它忽略了。(2014.3.22 部分内容补充)
    上边所说到的ico资源,都是在windows shell下能显示的图片,如果要提取没有显示的图片,则要利用资源枚举系列函数:EnumResourceNames、FindResouce、LoadResource、LockResource、CreateIconFromResourceEx。
本文所在:http://www.cnblogs.com/cswuyg/p/3603707.html

四、参考资料

1、ICON结构,很全面的知识:http://msdn.microsoft.com/en-us/library/ms997538.aspx
2、ICON发展历史系列,涉及一些MSDN没有谈到的细节:
http://blogs.msdn.com/b/oldnewthing/archive/2010/10/18/10077133.aspx
http://blogs.msdn.com/b/oldnewthing/archive/2010/10/19/10077610.aspx
http://blogs.msdn.com/b/oldnewthing/archive/2010/10/21/10078690.aspx
http://blogs.msdn.com/b/oldnewthing/archive/2010/10/22/10079192.aspx
3、HICON保存为*.ico文件,对于256格式的icon图片,保存时没有保存为png,其中一个答案的代码:“WriteFile(hFile, &padding, 4 - bmp.bmWidthBytes, &nWritten, 0);”有错误,应该是:“ WriteFile(hFile, &padding, 4 - (bmp.bmWidthBytes & 3), &nWritten, 0); ”,该答案对于低于8颜色深度的图片没有做处理,另一个使用GetDiBits实现的答案更好。
:http://stackoverflow.com/questions/2289894/how-can-i-save-hicon-to-an-ico-file
4、windows系统对ICON显示的各种选择:http://stackoverflow.com/questions/3236115/which-icon-sizes-should-my-windows-applications-icon-include
5、ICO 文件格式以及发展历史:http://en.wikipedia.org/wiki/ICO_(file_format)
6、vista中的icons图标:http://msdn.microsoft.com/en-us/library/aa511280.aspx
7、不支持在应用程序中使用jpeg、png格式的解压,仅仅StretchDIBits、SetDIBitsToDevice两API支持直接向输出设备输出jpeg、png压缩格式数据,这是硬件支持的,使用时需要先判断硬件是否支持: http://msdn.microsoft.com/en-us/library/dd145023%28VS.85%29.aspx
8、获取exe *.ico文件中所有size的图片,批评者的观点很全面:http://stackoverflow.com/questions/16330403/get-hbitmaps-for-all-sizes-and-depths-of-a-file-type-icon-c
9、总结了IOS、Windows上的各种icon size对比:http://www.visualpharm.com/articles/icon_sizes.html

转载于:https://www.cnblogs.com/cswuyg/p/3603707.html

Icon资源详解[1]相关推荐

  1. VS2010-MFC(菜单:VS2010菜单资源详解)

    转自:http://www.jizhuomi.com/software/210.html 上一节讲了标签控件Tab Control以后,常用控件的内容就全部讲完了,当然并没有包括所有控件,主要是一些很 ...

  2. VMWare虚拟机处理器数量与每个处理器内核数量概念,以及分配CPU资源详解

    VMWare虚拟机处理器数量与每个处理器内核数量概念,以及分配CPU资源详解 概念 CPU的物理核心和超线程 CPU的睿频机制 总结 概念 处理器数量:虚拟机上的CPU个数(上图中的插槽数,是机器主板 ...

  3. gateway资源详解

    istio课程发布:https://edu.csdn.net/course/detail/29911 这是我目前见过最详细,最有深度的istio课程 学习目标 什么是gateway 在Kubernet ...

  4. VirtualService资源详解

    ** istio课程发布:https://edu.csdn.net/course/detail/29911 这是我目前见过最详细,最有深度的istio课程 ** VirtualService资源详解 ...

  5. stm32存储资源详解

    战舰STM32F103ZET6开发板 ZET6芯片 该芯片内部自带了64k字节的SRAM,以及512K的内部FLASH IROM1=0x80000=512K 和IRAM1=0X10000=64k的大小 ...

  6. 【愚公系列】2022年08月 微信小程序-icon图标详解

    文章目录 前言 一.自带图标 二.实现图标的五种方案 1.图片 2.精灵图 3.CSS绘图 4.矢量字体 4.1 使用步骤 5.SVG格式 前言 在小程序中经常会用到各种各样的图标,如果这些图标都使用 ...

  7. 静态资源详解和帮助文档的使用

    1.静态:(static 修饰变量,方法) 概述:静态就是static关键字修饰的变量或方法 static是一个关键字,静止的,在java中表示资源共享的. 为什么要使用静态?: 1.例子:人人都有国 ...

  8. k8s、Deployment多副本资源详解、SERVICE通信、案例一nginx端口暴漏、案例二tomcat端口暴漏、案例三jenkins端口暴漏

    文章目录 案例一 创建SERVICE 案例一nginx端口暴露 案例二tomcat端口暴露 案例三jenkins端口暴漏 使用yaml创建Deployment k8s deployment资源创建流程 ...

  9. Spartan6系列之时钟资源详解

    本文转自:https://www.cnblogs.com/dhyc/p/3968729.html,感谢作者 1.   时钟资源概述 时钟设施提供了一系列的低电容.低抖动的互联线,这些互联线非常适合于传 ...

最新文章

  1. OCS2007安装配置指南
  2. 创新工场2018年夏令营DeepCamp第一套解答笔记
  3. ROS 总结(一):ROS系统框架
  4. slf4j 和 log4基础入门(Maven配置)
  5. 常用正则表达 (转)
  6. Java中常用的类,包,接口
  7. ExtJS4之helloworld
  8. 下滑加载更多js_vue.js怎么实现滑动到底部加载更多数据效果?
  9. 你真的理解反向传播吗?面试必备
  10. 绝对定向 c++_【007】Linux重定向、管道符及环境变量(看这一文就够了)
  11. php 读xml的两种方式
  12. 网易整合邮箱和博客 可通过邮件更新博客日志
  13. python多重继承super父类参数_Python super()函数使用及多重继承
  14. python老齐_python-basic
  15. 五大黑科技资源网站,你想要的这里都有
  16. ipad python编程软件_7款学习Python编程的iPhone/iPad应用
  17. 让Fireball CodeEditor控件支持中文
  18. python雨课堂答案_雨课堂和微助教的比较分析
  19. MathType的配置问题;将word中的公式转换为mathtype格式失败,缺少OMML2MML.XSL
  20. 马尔科夫链细致平衡条件

热门文章

  1. HBase完全分布式搭建
  2. python 结构体嵌套_Python 3不更新嵌套包中的变量(使用“递归”相对导入)
  3. [JLOI2014]松鼠的新家【树上差分】
  4. 提升R代码运算效率的11个实用方法——并行、效率
  5. Cognos8.3 + oracle9i数据集市 建cube性能调整
  6. iOS 协议 委托 代理 delegate
  7. Redis 安装配置(一)
  8. PHPExcel导出文件
  9. HTML标记语言——表单的详细使用说明
  10. jQuery Mobile 中文手册 Ajax开发版(2)