【汇编】使用NASM“编译”制作ICO、CUR文件
所谓ICO、CUR指的是Windows的图标和光标文件。这种文件结构十分简单,描述一下就是这样:ICO、CUR文件结构:
1个文件信息头
N个图像信息头
然后是N个BMP(BITMAPINFOHEADER、调色板、位图)
BITMAPINFOHEADER的高的值是宽的两倍。
如果不是32位的位图,则尾部附带单色位图透明数据
文件信息头的结构:struct ICONFILEHEADER //文件信息头,一个ICO只有一个
{
WORD wReserved; //保留,值为0
WORD wType; //类型,1为ICO,2为CUR
WORD wCount; //整个ICO文件的图像数
};图像信息头的结构:struct ICONINFOHEADER //图像信息头,有多少图像就有多少个图像信息头
{
BYTE bWidth; //图像宽度
BYTE bHeight; //图像高度
BYTE bColorCount; //图像颜色数低8位
BYTE bReserved; //保留
union
{
struct
{
INT16 wCursorX; //光标中心X
INT16 wCursorY; //光标中心Y
}AsCursor;
struct
{
WORD wPlanes; //位面数
WORD wBitCount; //颜色位数
}AsIcon;
};
DWORD dwBytesInRes; //图像大小
DWORD dwImageOffset; //图像位置
};之后的数据就是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
用法:将位图文件准备好,放到指定位置(比如这个工具的文件夹)
其中文件名以“mask”结尾的BMP文件是黑白位图(所谓“单色位图”),作用是定义位图的透明通道,黑色表示对应像素不透明,白色表示透明。
然后我们来编写makeicon.asm吧。需要的宏已经在makeicon.inc提供了。大家可以看看makeicon.inc的内容:;==============================================================================
;作者:0xAA55
;网站:http://www.0xaa55.com/
;请注明原作者信息,否则视为侵权。
;------------------------------------------------------------------------------
%ifndef _ICON_CURSOR_FILE_GEN_
%define _ICON_CURSOR_FILE_GEN_
;==============================================================================
;ICO、CUR文件结构:
;1个文件信息头
;N个图像信息头
;然后是N个BMP(BITMAPINFOHEADER、调色板、位图)
;BITMAPINFOHEADER的高的值是宽的两倍。
;如果不是32位的位图,则尾部附带单色位图透明数据
;------------------------------------------------------------------------------
;==============================================================================
;BMP文件头
;------------------------------------------------------------------------------
struc BMFH;BITMAPFILEHEADER
.bfType resw 1
.bfSize resd 1
.bfReserved1 resw 1
.bfReserved2 resw 1
.bfOffBits resd 1
.Size:
endstruc
;==============================================================================
;BMP信息头
;------------------------------------------------------------------------------
struc BMIF;BITMAPINFOHEADER
.biSize resd 1
.biWidth resd 1
.biHeight resd 1
.biPlanes resw 1
.biBitCount resw 1
.biCompression resd 1
.biSizeImage resd 1
.biXPelsPerMeter resd 1
.biYPelsPerMeter resd 1
.biClrUsed resd 1
.biClrImportant resd 1
.Size:
endstruc
;==============================================================================
;调色板项
;------------------------------------------------------------------------------
struc RGBQ
.R resb 1
.G resb 1
.B resb 1
.X resb 1
.Size:
endstruc
;==============================================================================
;宏:FileHeader
;用法:用在汇编文件最开始的地方,定义ICO或CUR文件的文件头。
;参数:FT_Ico或FT_Cur,指明文件格式。
;------------------------------------------------------------------------------
%define FT_Ico 1
%define FT_Cur 2
%macro FileHeader 1
segment .data align=1
segment .text align=1
%define FT_FileType %1
%assign NumImages 0
dw 0
dw %1
dw NbImages
%endmacro
;宏:_bitmap_pitch
;用于计算位图每行字节数
%define _bitmap_pitch(w,b) ((((w) * (b) - 1) / 32 + 1) * 4)
;==============================================================================
;宏:IncludeBMP
;参数:
;如果是图标:
; 尺寸,颜色数,位面数,颜色位数,BMP文件路径
;
;如果是光标:
; 尺寸,颜色数,位面数,颜色位数,焦点X,焦点Y,BMP文件路径
;
;如果BMP文件是索引颜色,则有第六个参数:作为透明通道的BMP文件路径,必须为单色位
;图。
;------------------------------------------------------------------------------
%macro IncludeBMP 5-6
segment .text
db (%1)&0xFF;宽度
db (%1)&0xFF;高度
db (1 << (%4))&0xFF;颜色数
db 0 ;保留
;如果是图标,下面两个参数分别是位面数和颜色位数,如果是光标,则是焦点坐标
%if FT_FileType == FT_Ico
dw %3, %4
%define Color_File %5
%define Alpha_File %6
%else
dw %5, %6
%define Color_File %7
%define Alpha_File %8
%endif
dd %%ImageDataLen
dd %%ImageData
segment .data
%%ImageData:
dd BMIF.Size
dd (%1)
dd (%1) * 2 ;高的值是宽的两倍
dw %3, %4
dd 0 ;不能是压缩格式,也不能有位域
dd (%1) * _bitmap_pitch(%1, %4) ; 实际大小
;从文件取打印尺寸
incbin Color_File, BMFH.Size + BMIF.biXPelsPerMeter, 4 * 2
%if (%4)<=8 ;调色板颜色
dd 1 << (%4) ;使用的颜色数
dd 1 << (%4) ;重要的颜色数
incbin Color_File, BMFH.Size + BMIF.Size, 4 * (%2) ;插入调色板
times (1 << (%4)) - (%2) dd 0 ;补全调色板颜色
incbin Color_File, BMFH.Size + BMIF.Size + 4 * (%2), (%1) * _bitmap_pitch(%1, %4) ;按照实际大小插入位图
incbin Alpha_File,BMFH.Size + BMIF.Size + 4 * 2 ;然后插入透明通道
%else
dd 0 ;无调色板数据
dd 0
incbin Color_File, BMFH.Size + BMIF.Size ;插入整张位图
%endif
%%ImageDataLen equ $-%%ImageData
%assign NumImages NumImages+1
%endmacro
;==============================================================================
;宏:IncludePNG
;参数:
;如果是图标:
; 尺寸,PNG文件路径
;
;如果是光标:
; 尺寸,焦点X,焦点Y,PNG文件路径
;
;------------------------------------------------------------------------------
%macro IncludePNG 2-4
segment .text
db (%1)&0xFF;宽度
db (%1)&0xFF;高度
db 0 ;颜色数
db 0 ;保留
;如果是图标,下面两个参数分别是位面数和颜色位数,如果是光标,则是焦点坐标
%if FT_FileType == FT_Ico
dw 1, 32
%define Color_File %2
%else
dw %2, %3
%define Color_File %4
%endif
dd %%ImageDataLen
dd %%ImageData
segment .data
%%ImageData:
incbin Color_File
%%ImageDataLen equ $-%%ImageData
%assign NumImages NumImages+1
%endmacro
;==============================================================================
;宏:FileEnd
;用法:用在文件结尾。
;------------------------------------------------------------------------------
%macro FileEnd 0
NbImages equ NumImages
%endmacro
%endif可以从源码上看出这些宏的用法:
FileHeader:定义文件头的内容。
IncludeBMP:将BMP位图文件加入到ICO或CUR中,参数已经在源码中说明了。
IncludePNG:将PNG文件加入到ICO或CUR中。
FileEnd:做一些结尾工作。
为了缩小文件尺寸,我已经把icon16.bmp、icon32.bmp、icon48.bmp处理为256色(8位色)位图了。
因此当我们需要把刚才那些位图组合成一个ICO文件,我们只需要这样编写makeicon.asm就行了:%include"makeicon.inc"
FileHeader FT_Ico
;IncludeBMP 尺寸,颜色数,位面数,颜色位数,位图文件名[,透明通道文件名]
;如果不是图标,是光标,那么参数则应该是:
;IncludeBMP 尺寸,颜色数,位面数,颜色位数,焦点X,焦点Y,位图文件名[,透明通道文件名]
;如果不是32位色(或者0x100000000色)那么就必须要有透明通道文件,这里叫“掩码”。
;前两张位图实际颜色数是22,这是用PS看到的
IncludeBMP 16,22,1,8,"icon16x16.bmp","mask16x16.bmp"
IncludeBMP 32,22,1,8,"icon32x32.bmp","mask32x32.bmp"
;后面这张48x48的实际颜色数是256
IncludeBMP 48,256,1,8,"icon48x48.bmp","mask48x48.bmp"
;PNG格式的图标用不着啰嗦
IncludePNG 128,"icon128x128.png"
FileEnd边写好了以后,保存,然后双击makeicon.bat。哦?对了,我们必须要有nasm.exe这个编译器在系统里,它是一个著名的汇编器,非常屌。
NASM汇编器点此下载
之后把它放到这个源码文件夹,或者干脆放到%PATH%下使其随时都能使用(我就是这么做的)。
双击了makeicon.bat之后,它只显示了“请按任意键继续。。。”
那么让我们切克闹。
可以看到我们得到了makeicon.ico这个文件。是它是它就是它,我们的朋友小哪吒。
事实证明这个图标文件没有问题,一切正常,它的三个图像都能正常显示。
从某种程度上来说,我这个东西基本只依赖NASM这个汇编器(makeicon.bat这个文件也只是调用了nasm,给了一个很简单的命令行参数而已。)而nasm是开源的跨平台汇编器。因此我的这个BMP转图标的“脚本”也是跨平台的哦。要在安卓手机上可以通过安装DOSBox运行DOS版的NASM编译makeicon.asm文件得到图标。
BIN:没有
SRC:
已更新。现在可以包含PNG文件到图标里了。
附件也更新了,欢迎下载。 已更新:修复了索引颜色BMP位图如果不包含完整调色板的话生成的图标显示不正确的问题。
页:
[1]