找回密码
 立即注册→加入我们

QQ登录

只需一步,快速开始

搜索
热搜: 下载 VB C 实现 编写
查看: 4806|回复: 2

【汇编】使用NASM“编译”制作ICO、CUR文件

[复制链接]

1110

主题

1651

回帖

7万

积分

用户组: 管理员

一只技术宅

UID
1
精华
244
威望
743 点
宅币
24219 个
贡献
46222 次
宅之契约
0 份
在线时间
2296 小时
注册时间
2014-1-26
发表于 2015-1-24 03:18:30 | 显示全部楼层 |阅读模式

欢迎访问技术宅的结界,请注册或者登录吧。

您需要 登录 才可以下载或查看,没有账号?立即注册→加入我们

×
所谓ICO、CUR指的是Windows的图标和光标文件。这种文件结构十分简单,描述一下就是这样:

ICO、CUR文件结构:
1个文件信息头
N个图像信息头
然后是N个BMP(BITMAPINFOHEADER、调色板、位图)
BITMAPINFOHEADER的高的值是宽的两倍。
如果不是32位的位图,则尾部附带单色位图透明数据

文件信息头的结构:
  1. struct ICONFILEHEADER                //文件信息头,一个ICO只有一个
  2. {
  3.         WORD        wReserved;                //保留,值为0
  4.         WORD        wType;                        //类型,1为ICO,2为CUR
  5.         WORD        wCount;                        //整个ICO文件的图像数
  6. };
复制代码
图像信息头的结构:
  1. struct ICONINFOHEADER                //图像信息头,有多少图像就有多少个图像信息头
  2. {
  3.         BYTE        bWidth;                        //图像宽度
  4.         BYTE        bHeight;                //图像高度
  5.         BYTE        bColorCount;        //图像颜色数低8位
  6.         BYTE        bReserved;                //保留
  7.         union
  8.         {
  9.                 struct
  10.                 {
  11.                         INT16        wCursorX;                //光标中心X
  12.                         INT16        wCursorY;                //光标中心Y
  13.                 }AsCursor;
  14.                 struct
  15.                 {
  16.                         WORD        wPlanes;                //位面数
  17.                         WORD        wBitCount;                //颜色位数
  18.                 }AsIcon;
  19.         };
  20.         DWORD        dwBytesInRes;        //图像大小
  21.         DWORD        dwImageOffset;        //图像位置
  22. };
复制代码
之后的数据就是ICO、CUR文件包含的位图图像了。这些图像都是以BMP位图的形式存在的——就像去掉了BMP文件头的BMP文件一样,结构如下说明:
  • 一个BITMAPINFOHEADER结构体。
  • 如果是索引颜色,这里有调色板,否则没有。
  • 位图数据。
  • 位图透明通道数据,如果位图不是32位的

其中BITMAPINFOHEADER结构体中的“高度”(即biHeight)的数值是“宽度”(即biWidth)的数值的两倍。如果位图不是32位位图(比如24位、16位、8位、4位、2位、1位等)则在位图数据后面有透明通道数据,这个透明通道数据的内容,相当于一个单色BMP文件的位图部分。

根据如上的资料,我们就能制作出一个ICO、CUR文件的编辑器了。不过我可不想造轮子,造一个功能像画图一样不支持透明通道的不爽,而造一个像PhotoShop一样的则感觉没啥意义。因此我干脆借助NASM汇编的平坦模型原理,编写了一个“脚本”,用NASM编译一下它,就能得到一个ICO、CUR文件,原理是将BMP位图合并到位图里。
想必大家可能失望了……我可不想用汇编语言造一个这样的画图器轮子啊!只是利用了NASM的特性了而已,把它当作组装文件的“脚本解释器”了而已。
我这套工具主要就三个文件:
makeicon.asm
makeicon.inc
makeicon.bat
20150124022538.png
用法:将位图文件准备好,放到指定位置(比如这个工具的文件夹)
20150124022653.png
其中文件名以“mask”结尾的BMP文件是黑白位图(所谓“单色位图”),作用是定义位图的透明通道,黑色表示对应像素不透明,白色表示透明。
然后我们来编写makeicon.asm吧。需要的宏已经在makeicon.inc提供了。大家可以看看makeicon.inc的内容:
  1. ;==============================================================================
  2. ;作者:0xAA55
  3. ;网站:http://www.0xaa55.com/
  4. ;请注明原作者信息,否则视为侵权。
  5. ;------------------------------------------------------------------------------
  6. %ifndef        _ICON_CURSOR_FILE_GEN_
  7. %define        _ICON_CURSOR_FILE_GEN_

  8. ;==============================================================================
  9. ;ICO、CUR文件结构:
  10. ;1个文件信息头
  11. ;N个图像信息头
  12. ;然后是N个BMP(BITMAPINFOHEADER、调色板、位图)
  13. ;BITMAPINFOHEADER的高的值是宽的两倍。
  14. ;如果不是32位的位图,则尾部附带单色位图透明数据
  15. ;------------------------------------------------------------------------------

  16. ;==============================================================================
  17. ;BMP文件头
  18. ;------------------------------------------------------------------------------
  19. struc BMFH;BITMAPFILEHEADER
  20.   .bfType                resw 1
  21.   .bfSize                resd 1
  22.   .bfReserved1        resw 1
  23.   .bfReserved2        resw 1
  24.   .bfOffBits        resd 1
  25.   .Size:
  26. endstruc

  27. ;==============================================================================
  28. ;BMP信息头
  29. ;------------------------------------------------------------------------------
  30. struc BMIF;BITMAPINFOHEADER
  31.         .biSize                                resd 1
  32.         .biWidth                        resd 1
  33.         .biHeight                        resd 1
  34.         .biPlanes                        resw 1
  35.         .biBitCount                        resw 1
  36.         .biCompression                resd 1
  37.         .biSizeImage                resd 1
  38.         .biXPelsPerMeter        resd 1
  39.         .biYPelsPerMeter        resd 1
  40.         .biClrUsed                        resd 1
  41.         .biClrImportant                resd 1
  42.         .Size:
  43. endstruc

  44. ;==============================================================================
  45. ;调色板项
  46. ;------------------------------------------------------------------------------
  47. struc RGBQ
  48.         .R        resb 1
  49.         .G        resb 1
  50.         .B        resb 1
  51.         .X        resb 1
  52.         .Size:
  53. endstruc

  54. ;==============================================================================
  55. ;宏:FileHeader
  56. ;用法:用在汇编文件最开始的地方,定义ICO或CUR文件的文件头。
  57. ;参数:FT_Ico或FT_Cur,指明文件格式。
  58. ;------------------------------------------------------------------------------
  59. %define        FT_Ico        1
  60. %define FT_Cur        2

  61. %macro FileHeader 1
  62.         segment .data align=1
  63.         segment .text align=1
  64.         %define FT_FileType %1
  65.         %assign NumImages 0
  66.         dw 0
  67.         dw %1
  68.         dw NbImages
  69. %endmacro

  70. ;宏:_bitmap_pitch
  71. ;用于计算位图每行字节数
  72. %define _bitmap_pitch(w,b) ((((w) * (b) - 1) / 32 + 1) * 4)

  73. ;==============================================================================
  74. ;宏:IncludeBMP
  75. ;参数:
  76. ;如果是图标:
  77. ;    尺寸,颜色数,位面数,颜色位数,BMP文件路径
  78. ;
  79. ;如果是光标:
  80. ;    尺寸,颜色数,位面数,颜色位数,焦点X,焦点Y,BMP文件路径
  81. ;
  82. ;如果BMP文件是索引颜色,则有第六个参数:作为透明通道的BMP文件路径,必须为单色位
  83. ;图。
  84. ;------------------------------------------------------------------------------
  85. %macro IncludeBMP 5-6
  86.         segment .text
  87.         db (%1)&0xFF;宽度
  88.         db (%1)&0xFF;高度
  89.         db (1 << (%4))&0xFF;颜色数
  90.         db 0                ;保留
  91.        
  92.         ;如果是图标,下面两个参数分别是位面数和颜色位数,如果是光标,则是焦点坐标
  93.         %if FT_FileType == FT_Ico
  94.                 dw %3, %4
  95.                 %define Color_File %5
  96.                 %define Alpha_File %6
  97.         %else
  98.                 dw %5, %6
  99.                 %define Color_File %7
  100.                 %define Alpha_File %8
  101.         %endif
  102.        
  103.        
  104.         dd %%ImageDataLen
  105.         dd %%ImageData
  106.        
  107.         segment .data
  108.         %%ImageData:
  109.         dd BMIF.Size
  110.         dd (%1)
  111.         dd (%1) * 2 ;高的值是宽的两倍
  112.         dw %3, %4
  113.         dd 0 ;不能是压缩格式,也不能有位域
  114.         dd (%1) * _bitmap_pitch(%1, %4) ; 实际大小
  115.         ;从文件取打印尺寸
  116.         incbin Color_File, BMFH.Size + BMIF.biXPelsPerMeter, 4 * 2
  117.         %if (%4)<=8 ;调色板颜色
  118.                 dd 1 << (%4) ;使用的颜色数
  119.                 dd 1 << (%4) ;重要的颜色数
  120.                 incbin Color_File, BMFH.Size + BMIF.Size, 4 * (%2) ;插入调色板
  121.                 times (1 << (%4)) - (%2) dd 0 ;补全调色板颜色
  122.                 incbin Color_File, BMFH.Size + BMIF.Size + 4 * (%2), (%1) * _bitmap_pitch(%1, %4) ;按照实际大小插入位图
  123.                 incbin Alpha_File,BMFH.Size + BMIF.Size + 4 * 2 ;然后插入透明通道
  124.         %else
  125.                 dd 0 ;无调色板数据
  126.                 dd 0
  127.                 incbin Color_File, BMFH.Size + BMIF.Size ;插入整张位图
  128.         %endif
  129.         %%ImageDataLen equ $-%%ImageData
  130.        
  131.         %assign NumImages NumImages+1
  132. %endmacro

  133. ;==============================================================================
  134. ;宏:IncludePNG
  135. ;参数:
  136. ;如果是图标:
  137. ;    尺寸,PNG文件路径
  138. ;
  139. ;如果是光标:
  140. ;    尺寸,焦点X,焦点Y,PNG文件路径
  141. ;
  142. ;------------------------------------------------------------------------------
  143. %macro IncludePNG 2-4
  144.         segment .text
  145.         db (%1)&0xFF;宽度
  146.         db (%1)&0xFF;高度
  147.         db 0                ;颜色数
  148.         db 0                ;保留
  149.        
  150.         ;如果是图标,下面两个参数分别是位面数和颜色位数,如果是光标,则是焦点坐标
  151.         %if FT_FileType == FT_Ico
  152.                 dw 1, 32
  153.                 %define Color_File %2
  154.         %else
  155.                 dw %2, %3
  156.                 %define Color_File %4
  157.         %endif
  158.        
  159.         dd %%ImageDataLen
  160.         dd %%ImageData
  161.        
  162.         segment .data
  163.         %%ImageData:
  164.         incbin Color_File
  165.         %%ImageDataLen equ $-%%ImageData
  166.        
  167.         %assign NumImages NumImages+1
  168. %endmacro

  169. ;==============================================================================
  170. ;宏:FileEnd
  171. ;用法:用在文件结尾。
  172. ;------------------------------------------------------------------------------
  173. %macro FileEnd 0
  174.         NbImages equ NumImages
  175. %endmacro

  176. %endif
复制代码
可以从源码上看出这些宏的用法:
FileHeader:定义文件头的内容。
IncludeBMP:将BMP位图文件加入到ICO或CUR中,参数已经在源码中说明了。
IncludePNG:将PNG文件加入到ICO或CUR中。
FileEnd:做一些结尾工作。
为了缩小文件尺寸,我已经把icon16.bmp、icon32.bmp、icon48.bmp处理为256色(8位色)位图了。
因此当我们需要把刚才那些位图组合成一个ICO文件,我们只需要这样编写makeicon.asm就行了:
  1. %include"makeicon.inc"

  2. FileHeader FT_Ico

  3. ;IncludeBMP 尺寸,颜色数,位面数,颜色位数,位图文件名[,透明通道文件名]
  4. ;如果不是图标,是光标,那么参数则应该是:
  5. ;IncludeBMP 尺寸,颜色数,位面数,颜色位数,焦点X,焦点Y,位图文件名[,透明通道文件名]
  6. ;如果不是32位色(或者0x100000000色)那么就必须要有透明通道文件,这里叫“掩码”。
  7. ;前两张位图实际颜色数是22,这是用PS看到的
  8. IncludeBMP 16,22,1,8,"icon16x16.bmp","mask16x16.bmp"
  9. IncludeBMP 32,22,1,8,"icon32x32.bmp","mask32x32.bmp"
  10. ;后面这张48x48的实际颜色数是256
  11. IncludeBMP 48,256,1,8,"icon48x48.bmp","mask48x48.bmp"
  12. ;PNG格式的图标用不着啰嗦
  13. IncludePNG 128,"icon128x128.png"

  14. FileEnd
复制代码
边写好了以后,保存,然后双击makeicon.bat。哦?对了,我们必须要有nasm.exe这个编译器在系统里,它是一个著名的汇编器,非常屌。
NASM汇编器点此下载
之后把它放到这个源码文件夹,或者干脆放到%PATH%下使其随时都能使用(我就是这么做的)。

双击了makeicon.bat之后,它只显示了“请按任意键继续。。。”
那么让我们切克闹。
20150124031318.png
可以看到我们得到了makeicon.ico这个文件。是它是它就是它,我们的朋友小哪吒。
事实证明这个图标文件没有问题,一切正常,它的三个图像都能正常显示。
20150124031448.png 20150124031505.png 20150124031518.png

从某种程度上来说,我这个东西基本只依赖NASM这个汇编器(makeicon.bat这个文件也只是调用了nasm,给了一个很简单的命令行参数而已。)而nasm是开源的跨平台汇编器。因此我的这个BMP转图标的“脚本”也是跨平台的哦。要在安卓手机上可以通过安装DOSBox运行DOS版的NASM编译makeicon.asm文件得到图标。

BIN:没有
SRC: makeicon.zip (52.55 KB, 下载次数: 6)
回复

使用道具 举报

1110

主题

1651

回帖

7万

积分

用户组: 管理员

一只技术宅

UID
1
精华
244
威望
743 点
宅币
24219 个
贡献
46222 次
宅之契约
0 份
在线时间
2296 小时
注册时间
2014-1-26
 楼主| 发表于 2019-3-13 03:37:47 | 显示全部楼层
已更新。现在可以包含PNG文件到图标里了。
附件也更新了,欢迎下载。
回复 赞! 1 靠! 0

使用道具 举报

1110

主题

1651

回帖

7万

积分

用户组: 管理员

一只技术宅

UID
1
精华
244
威望
743 点
宅币
24219 个
贡献
46222 次
宅之契约
0 份
在线时间
2296 小时
注册时间
2014-1-26
 楼主| 发表于 2018-2-18 01:37:58 | 显示全部楼层
已更新:修复了索引颜色BMP位图如果不包含完整调色板的话生成的图标显示不正确的问题。
回复 赞! 靠!

使用道具 举报

QQ|Archiver|小黑屋|技术宅的结界 ( 滇ICP备16008837号 )|网站地图

GMT+8, 2024-4-18 09:08 , Processed in 0.041819 second(s), 36 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表