首页
关于我们
服务项目
作品展示
服务支持
联系我们
友情链接
网站地图
 您当前位置:网络学院 -> 编程开发系-> 编程开发-> 其他语言
用Delphi实现24位真彩色图标
作者:admin 来源:网络
日期: 2007-2-27
站内搜索
文章页数:[1] 

摘 要 本文详细介绍了ICO文件的格式,以及利用Jpeg、BMP等格式的24位真彩色图片,生成图标的一种方法。

关键词 图标,位图,24位真彩色

引言

Delphi是目前广泛使用的可视化开发工具,它自身带有一个图片、图标的编辑器——Image Editor,但是到Delphi7为止,都不能进行真彩图标的编辑,可以说是一个遗憾。笔者通过对图标文件的研究,实现了产生24位真彩色图标。

图标文件的格式

首先,分析一个具体的图标 。在CS1.6中有一个图标game.ico( ),如果用WinHex等可以进行16进制编辑的软件打开这个图标文件,我们可以看到如下数据:

00 00 01 00 04 00 10 10 00 00 00 00 00 00 68 05

00 00 46 00 00 00 10 10 00 00 00 00 00 00 68 03

00 00 AE 05 00 00 20 20 00 00 00 00 00 00 A8 08

00 00 16 09 00 00 20 20 00 00 00 00 00 00 A8 0C

00 00 BE 11 00 00 28 00 00 00 10 00 00 00 20 00

00 00 01 00 08 00 00 00 00 00 40 01 00 00 47 46

6C 65 6D 69 6E 67 00 01 00 00 00 00 00 00 00 00

下面我们就说一说,这些数据的具体含义。一个图标文件(*.ICO),实际上可以含有多个图标.通常,每个图标都会被转换为针对特定显示设备的图标图像。图标文件由文件头和数据组成, ICO文件一开始,是一个叫做tagIconDir的记录型的结构,在Delphi中这样来描述(括号内的数值,是针对CS图标的具体数据):

tagIconDir = packed record

idReserved:WORD;// 保留域,目前始终为 0(开始的数据$00 00)

idType:WORD; //定义为资源类型,图标值为 $0001、光标是$0002($0001)

idCount:WORD; //idCount 表示的是这个文件里包含了几个图标($0004)

idEntries:array[0..0] of tagIconDirEntry; //不包括本数组,以上一共6个字节

end;

这个记录中的idEntries 是个数组结构,这个结构的大小不是始终为 1 的一个数组,它需要根据图标数目 ( idCount ) 来确定真实的数组大小。它的类型为tagIconDirEntry记录,定义如下:

tagIconDirEntry = packed record

bWidth:BYTE;// 图标图片的显示宽度,以像素为单位,最大值为255 ($10=16D)

bHeight:BYTE;// 图标图片的显示高度,以像素为单位,最大值为255 ($10=16D)

bColorCount:BYTE;// 图标图片的颜色数($00)

bReserved:BYTE;// 保留域总是 0 ($00)

wPlanes:WORD;// 图标图片的位面数 ($00 00)

wBitCount:WORD;// 图标图片的颜色深度($00 00)

dwBytesInRes:DWORD;// 图标图片占用的数据量($00000568)

dwImageOffset:DWORD; // 图标图片的开始位置 ($00000046)

end;.// 这个结构是16个字节

上面说的idCount 表示图标文件里包含的图标个数,每个图标都要有一个tagIconDirEntry结构来表示图标的具体信息。根据本结构的dwBytesInRes和dwImageOffset我们就可以确定图片(图标)的位置了。在该位置的数据是一个称为agIconImage的记录,它是这样定义的:

tagIconImage = packed record

icHeader:TBitmapInfoHeader; //BMP文件的信息头

icColors:array[0..0]of TRGBQuad;

icXOR:array[0..0]of BYTE;

icAND:array[0..0]of BYTE;

end;

从这个定义中我们可以看出,这个内容就是一个标准的位图格式,只不过多了两项,icXOR和icAND,普通的位图信息里是没有这2 个成员的。大家知道,图标在被显示时,是利用遮罩方法将 2 副位图在同一个位置显示才产生任意轮廓的,先使用 XOR 位 图抠出需要显示的区域,然后再在抠出的区域中显示出需要显示的图形。由于这个缘故,图标的位图格式中的位图信息头 ( TBitmapInfoHeader ) 是 2 个位图共用 的。它与普通位图头信息最大的不同是 TBitmapInfoHeader.biHeight 成员,显然它是 2 副位图高度的总和。讲到这里,我们需要对位图(BMP)文件的格式有些了解了。

位图文件的格式

BMP文件由文件头、位图信息头、颜色信息和图形数据四部分组成。按照微软的定义,在开始的文件头由14个字节组成:

tagBITMAPFILEHEADER= packed record

bfType:WORD; // 位图文件的类型,必须为BM

bfSize:DWORD; // 位图文件的大小,以字节为单位

bfReserved1:WORD; // 位图文件保留字,必须为0

bfReserved2:WORD; // 位图文件保留字,必须为0

bfOffB its:DWORD; // 位图数据的起始位置,以相对于位图

// 文件头的偏移量表示,以字节为单位

End;

紧接着上一记录的是位图信息头tagBITMAPINFOHEADER,BMP位图信息头数据用于说明位图的尺寸等信息。这个信息头就是上文说的TBitmapInfoHeader,它的长度固定为40字节。

tagBITMAPINFOHEADER= packed record

biSize:DWORD; // 本结构所占用字节数

biWidth:LONGINT // 位图的宽度,以像素为单位

biHeight; :LONGINT // 位图的高度,以像素为单位

biPlanes; :WORD // 目标设备的级别,必须为1

biBitCount :WORD // 每个像素所需的位数,必须是1(双色),

// 4(16色),8(256色)或24(真彩色)之一

biCompression :DWORD; // 位图压缩类型,必须是 0(不压缩),

// 1(BI_RLE8压缩类型)或2(BI_RLE4压缩类型)之一

biSizeImage :DWORD; // 位图的大小,以字节为单位

biXPelsPerMeter:LONGINT; // 位图水平分辨率,每米像素数

biYPelsPerMeter:LONGINT; // 位图垂直分辨率,每米像素数

biClrUsed:DWORD;// 位图实际使用的颜色表中的颜色数

biClrImportant:DWORD;// 位图显示过程中重要的颜色数

End;

紧接着就是颜色表,用于说明位图中的颜色,它有若干个表项,每一个表项是一个RGBQUAD类型的结构,定义一种颜色。RGBQUAD结构的定义如下:

tagRGBQUAD = packed record

rgbBlue:BYTE;// 蓝色的亮度(值范围为0-255)

rgbGreen:BYTE; // 绿色的亮度(值范围为0-255)

rgbRed:BYTE; // 红色的亮度(值范围为0-255)

rgbReserved:BYTE;// 保留,必须为0

end;

颜色表中RGBQUAD结构数据的个数有biBitCount来确定:

当biBitCount=1,4,8时,分别有2,16,256个表项;

当biBitCount=24时,没有颜色表项。

位图信息头和颜色表组成位图信息,BITMAPINFO结构定义如下:

tagBITMAPINFO = packed record

bmiHeader :BITMAPINFOHEADER; // 位图信息头

bmiColors[0..0] :RGBQUAD; // 颜色表

End;

24位真彩色图形转化为ICO文件

有了上面的基础知识,把24位真彩色图形转化为ICO文件就比较简单了,至于采用哪种编程语言,就看编程者的爱好了。下面笔者就采用Delphi实现本功能,进行详细介绍。

上面讲的是把BMP格式的图像转换为ICO文件,因此,对于其他格式的图像我们要先把它转换为位图。在Delphi中我们可以采用如下方法:

procedure TFormMain.Pic2BMP(Picture:TPicture);

var Bmp:TBitmap;

begin

if not(Picture.Graphic is TBitmap)then//判断是否是BMP图像

begin

Bmp:=TBitmap.Create;//不是BMP图形,就生成一个

try

Bmp.Width:=Picture.Width;

bmp.Height:=Picture.Height;

bmp.Canvas.Draw(0,0,Picture.Graphic);//把其他格式的图像复制到BMP

Picture.Graphic:=Bmp;//原始非BMP图像转换为BMP图像

Finally

Bmp.Free;

end;

end;

end;

有了BMP图像了,我们还要改变图像的长和宽,使它们符合要求的图表尺寸,注意不超出255。我们用如下方法实现尺寸的改变:

procedure TFormMain.PicToMiniature(SourceBMP, DescBMP:TBitmap; picH,picW :Integer);

var

bmp: TBitmap;

begin

try

bmp := TBitmap.Create;//生成位图

bmp.Assign(SourceBMP);//位图图像为SourceBMP,

if picW>255 then PicW:=255;//长宽不可超出255

if picH>255 then picH:=255;

bmp.Width := PicW;

bmp.Height :=PicH;

bmp.PixelFormat := pf24bit;//24位位图

bmp.Canvas.StretchDraw(Rect(0,0,picW,picH), SourceBMP);//使位图尺寸符合要求

DescBMP.Assign(bmp);

finally

bmp.Free;

end;

end;

生成位图的原料已经准备好了,就可以按ICO的文件头,关于程序的说明请看注释。

function TFormMain.MakICOHead(const Mem:TStream): Boolean;

var//采用流来生成

BMPHead1:tagBITMAPFILEHEADER;

BMPHead2: TBitmapInfoHeader;

BitsTotal:DWord;

begin

Result:=False;

Mem.Position:=0;

Mem.Read(BMPHead1,SizeOf(tagBITMAPFILEHEADER));//读取BMP文件由文件头

Mem.Read(BMPHead2,SizeOf(TBitmapInfoHeader));// 读取BMP位图信息头

if BMPHead2.biCompression=0 then //位图没有压缩

begin

if (BMPHead2.biWidth<=255) and (BMPHead2.biHeight <=255)then

begin

//caption:=IconFileName;

IconHand.idEntries.bWidth:= Byte(BMPHead2.biWidth) ;//IOC宽

IconHand.idEntries.bHeight:=Byte(BMPHead2.biHeight); //IOC高

BitsTotal:=(Mem.Size-54)*2+40;

//(BMP文件的大小- 文件头、位图信息头)*2+位图信息头=ICO数据量

//乘以二的原因是:加icXOR的信息

IconHand.idEntries.dwBytesInRes:= BitsTotal;

IconHand.idEntries.dwImageOffset:=$00000016;

Result:=True;

end;

Mem.Position:=0;

end;

end;

有了文件头,最终可以生成ICO了,同样详细内容请看程序的注释。

function TFormMain.MakICOData( Mem:TStream): Boolean;

var

Mem1,Mem2:TMemoryStream;

Size:Longint;

BmtMapHandle2:TBitmapInfoHeader;

begin

Mem1:=TMemoryStream.Create;

Mem2:=TMemoryStream.Create;

Size:=Mem.Size-14;//跳过14字节的BMP文件由文件头

Mem.Position:=14;

try

Mem1.SetSize(Size);

Mem.Read(Mem1.Memory^,Size);//BMP到Mem1

Mem1.Seek(0,soFromBeginning);

Mem1.Read(BmtMapHandle2,sizeof(TBitmapInfoHeader));//BMP文件的信息头

Mem2.SetSize(Size-40);//跳过40字节的BMP文件信息头

FillChar(Mem2.Memory^,Size-40,$0);//Mem2填充0 ,使掩码效果为白色

Mem2.Position:=0;

BmtMapHandle2.biHeight:=IconHand.idEntries.bHeight *2;//有两幅图

BmtMapHandle2.biSizeImage:=Mem2.Size*2;

Mem1.Seek(0,soFromBeginning);

Mem1.Write(BmtMapHandle2,sizeof(TBitmapInfoHeader));

Mem1.Position:=0;

Mem.Size:=0;

//MS.SetSize(0);

Mem.Write(IconHand,sizeof(tagIconDir){22});//写ICO文件头

Mem.Write(Mem1.Memory^,Mem1.Size);//写BMP片

Mem.Write(Mem2.Memory^,Mem2.Size);//写掩码

Result:=True;

finally

FreeAndNil(Mem1);

FreeAndNil(Mem2);

end;

end;

结束语

目前Delphi支持的图片格式比较多,例如我们可以给程序加上uses jpeg 语句就可以支持Jpeg格式的图像,当然如你给Delphi安装了支持其他图像格式的控件,使用本程序照样可以转换,得到的ICO文件可以供VB、Delphi等调用。程序的调试环境为Delphi7+WinxpSp2。

文章页数:[1] 
放大字体显示 缩小字体显示 打印文章 推荐给朋友
热门文章
·PHP开发中文件操作疑难问答
·测试 Apache Web 和 PHP 应用程序服务器
·用Delphi实现24位真彩色图标
·未来几年动态语言谁将成为主流
·致初学者:PHP比ASP优秀的七个理由
·大型系统上PHP令人不爽的九大原因
·PHP中通过Web 执行C/C++应用程序
·打造超酷的PHP数据饼图
·程序员之间的战争 战场是用户电脑
·用PHP与XML 联手进行网站编程
最新文章
·程序员之间的战争 战场是用户电脑
·PHP开发中文件操作疑难问答
·用PHP与XML 联手进行网站编程
·PHP中通过Web 执行C/C++应用程序
·用Delphi实现24位真彩色图标
·打造超酷的PHP数据饼图
·大型系统上PHP令人不爽的九大原因
·使用PHP 5.0 轻松解析XML文档
·测试 Apache Web 和 PHP 应用程序服务器
·未来几年动态语言谁将成为主流
相关主题
版权申明:除部分特别声明不要转载,或者授权本站独家播发的文章外,大家可以自由转载本站的原创文章,但原作者和来自本站的链接必须保留(非本站原创的,按照原来自一节,自行链接)。文章版权归本站和作者共有。
转载要求:转载之图片、文件,链接请不要盗链到本站,且不准打上各自站点的水印,亦不能抹去本站水印。
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有。
发表评论  打印  刷新  推荐给朋友  返回顶部  关闭

网上大名: