解读图标文件

 

解读图标文件

告诉您:图标是怎样支持透明特性的,及各种格式图标的建立

 

图标文件是一种特殊的位图,它的大小固定(16*16 32*32像素大小),且支持透明的特性。图标的格式也有24位、8位和4位几种不同的格式,它与位图最大的区别是:位图无法支持透明而图标可以。那图标是怎样做到这一点的呢?原来,图标采用对图像扫描两遍的方式进行记录位图信息的,第一遍扫描每个像素上的颜色数据完成后,重新以1位位图的方式对图像进行第二次扫描,并以辅助信息的方式追加在文件的后面,这样,图标文件的结构就比位图文件多了辅助信息这部分(见图)。

 

图标文件头     位图信息头     [系统调色盘]      图片信息      辅助信息

icofileheader     bmpinfoheader    rgbquad          rgbdata         fby

(14bytes)        (40bytes)                                    

 

 

 

 

 

 


为了使图标的某些部分变得透明,在第一遍扫描时,把这部分的颜色值改为黑色,在第二遍扫描时,这部分的颜色为白色,不透明的部分为黑色(0为黑色,1为白色)。这样,图标的背景就变透明了。

我们以32*32像素大小的图标为例来计算一下图标文件的大小:

种类

文件头

信息头

调色盘

图片信息

辅助信息

文件大小

24bit

22

40

0

32*32*3

128

3262

8bit

22

40

4*256

32*32

128

2238

4bit

22

40

4*16

32*32/2

128

766

 

编程举例:(保存为24位透明图标)

我们熟悉图标文件的组成,就可以用照片来创建自己的高品质的带透明背景的图标了,为了简化程序代码,在下例的程序中,我省去了图像的操作,仅保留了把一幅32*32像素大小,带白色背景的24位位图,转化成24位透明图标的代码。

 

 

 

 

 

 

 


VB6新建一个工程,命名为WriteIcoFile.vbp。添加一个窗体WriteIcoFile.frm caption=” WriteIcoFile”。添加图片框picture1scalemode=3-pixelautoredraw=trueautosize=true;borderstyle=0-none。添加一个按钮command1caption=”BmpToIco”,添加两个标签Label1label2。粘贴代码:

 

Option Explicit

Private Type ICONFILEHEADER  '22bytes

   idReserved As Integer   0

   idType As Integer    1

   idCount As Integer   文件中图标个数,为1

   bWidth As Byte      宽,为1632

   bHeight As Byte      高,为1632

   bColorCount As Byte  调色盘颜色数量:16255 0

   bReserved As Byte    0

   wPlanes As Integer    1

   wBitCount As Integer   每个像素占的位数

   dwBytesInRes As Long    图标文件后四项总字节数

   dwImageOffset As Long   图标文件头长度,为22

End Type

 

Private Type BITMAPINFOHEADER '40 bytes

        biSize As Long  信息头的长度,为40

        biWidth As Long 

        biHeight As Long  扫描两遍,值为实实际高度的2

        biPlanes As Integer  1

        biBitCount As Integer  每个像素占的位数

        biCompression As Long  0

        biSizeImage As Long  图标文件后三项总字节数

        biXPelsPerMeter As Long  0

        biYPelsPerMeter As Long  0

        biClrUsed As Long     0

        biClrImportant As Long  0

End Type

 

Private Type RGBQUAD '4bytes调色盘中颜色

        rgbBlue As Byte

        rgbGreen As Byte

        rgbRed As Byte

        rgbReserved As Byte

End Type

 

Private Type RGBDATA '24bitcolor图像信息中每一个像素包含的RGB

    b As Byte

    g As Byte

    r As Byte

End Type

 

Private Sub Command1_Click()  保存为24位透明图标

If Picture1.Height = 32 And Picture1.Width = 32 Then

 

Dim ifh As ICONFILEHEADER                'ICOfileheader

Dim bih As BITMAPINFOHEADER

Dim rgbd() As RGBDATA

Dim rgbl() As Long

Dim fby() As Byte

 

    Open App.Path & "/temp.ico" For Binary As #1

    设置图标文件头的值

    ifh.idReserved = 0

    ifh.idCount = 1

    ifh.idType = 1

    ifh.bHeight = 32

    ifh.bWidth = 32

    ifh.bColorCount = 0

    ifh.bReserved = 0

    ifh.wPlanes = 1

    ifh.wBitCount = 24

    ifh.dwBytesInRes = 3240

    ifh.dwImageOffset = Len(ifh)

       

    Put #1, , ifh

    设置图片信息头的值

    bih.biSize = Len(bih)

    bih.biWidth = 32

    bih.biHeight = 64     '!!!

    bih.biPlanes = 1

    bih.biBitCount = 24

    bih.biCompression = 0&

    bih.biSizeImage = 3200

    bih.biXPelsPerMeter = 0&

    bih.biYPelsPerMeter = 0&

    bih.biClrUsed = 0&

    bih.biClrImportant = 0&

   

    Put #1, , bih

   

    Dim i, j, k As Integer

    Dim by, byy As Long

    by = 16777215

    ReDim rgbd(1023)   申请1024个像素的RGB空间

从左下角逐行扫描

    For i = 0 To 31

    For j = 0 To 31

    byy = Picture1.Point(j, 31 - i)  获得图像上某一点的颜色Long

    If byy = by Then  如果该点为白色(16777215=RGB255255255))

    rgbd(k).r = 0

    rgbd(k).g = 0

    rgbd(k).b = 0

    Else

    rgbd(k).b = Int(byy / 65536)

    byy = byy - rgbd(k).b * 65536

    rgbd(k).g = Int(byy / 256)

    rgbd(k).r = byy Mod 256

    End If

    k = k + 1

    Next

    Next

   

    Put #1, , rgbd

 

    计算图标的辅助信息,白色背景部分对应的位的值为1

    ReDim fby(127)

    k = 0

    For i = 0 To 31

    For j = 0 To 3  每个字节包含8个像素的1位信息

    byy = 0

    If Picture1.Point(j * 8 + 7, 31 - i) = by Then byy = 1

    If Picture1.Point(j * 8 + 6, 31 - i) = by Then byy = byy + 2

    If Picture1.Point(j * 8 + 5, 31 - i) = by Then byy = byy + 4

    If Picture1.Point(j * 8 + 4, 31 - i) = by Then byy = byy + 8

    If Picture1.Point(j * 8 + 3, 31 - i) = by Then byy = byy + 16

    If Picture1.Point(j * 8 + 2, 31 - i) = by Then byy = byy + 32

    If Picture1.Point(j * 8 + 1, 31 - i) = by Then byy = byy + 64

    If Picture1.Point(j * 8, 31 - i) = by Then byy = byy + 128

    fby(k) = byy

    k = k + 1

    Next

    Next

   

    Put #1, , fby

       

    Close #1

   

Label1.Caption = "成功创建" & App.Path & "/temp.ico"

Else

Label1.Caption = "图片大小应为32*32"

End If

  

End Sub

 

Private Sub Form_Load()

Label2.Caption = "本例程序展示了图标创建的巅峰水平(能写出24位的透明的标准图标)" & vbCrLf & "为了简化程序,程序中只展示了将32*32带白色背景的的24位位图转化成图标文件的代码。" & vbCrLf & "您如果想创建自已的图标,可以用自己做的图片代替同目录下的temp.bmp" & vbCrLf & "即可做出属于自己的高品质图标。"

Picture1.Picture = LoadPicture(App.Path & "/temp.bmp")

End Sub

 

编程原理:

窗体导入时,导入同目录下的24位位图“temp.bmp”,command1按下时,判断图片大小是否为32*32,为图标文件头和位图信息头赋值,利用Picture1Point(x,y) as long方法,从左下角逐行扫描,获得图像的像素颜色的long值,然后经过计算,转换成rgbd(),来获得图像的24位图像信息,需注意的是,把白色背景的值,改为黑色的值(r=0;g=0,b=0),接着,再重新扫描,把白色背景的值设为1,不透明部分值设为0 ,经过计算获得图像的1位图像信息,最后写入同目录下的“temp.ico”。

 

Long (R,G,B)之间的转换:

我说明一下二进制和十进制的转换问题,我们在利用图片框Picture1PSet (x,y), colPoint(x,y) 来描绘图像和获得图像颜色值时,使用的是Long类型的数据,而24位位图文件中的颜色信息是以(RGBBytes类型的数据存储的,在(RGB)与Long互换的计算中,需要用到二进制与十进制的转换。

        R=255                       G=255                      B=255

 1  1  1  1  1  1  1  1      1  1  1  1  1  1  1  1     1  1  1  1  1  1  1  1

128 64 32 16  8  4  2  1

这样每8位上的数加起来就有255

       RGBb,g,r)就是把38位二进制连成1 24位的数

 1  1  1  1  1  1  1  1      1  1  1  1  1  1  1  1     1  1  1  1  1  1  1  1

8388608…………………..65536…………………………512  256………………… 8  4  2  1

这样24位上的数加起来就有16777215  RGB255,255,255=16777215

 

        R=1                       G=1                      B=1

 0  0  0  0  0  0  0  1      0  0  0  0  0  0  0  1     0  0  0  0  0  0  0  1

0  0  0  0  0  0  0  1

这样每8位上的数加起来就有1

       RGBb,g,r)把38位二进制连成1 24位的数

 0  0  0  0  0  0  0  1      1  1  1  1  1  1  1  1     1  1  1  1  1  1  1  1

0   0  0  0  0  0  0  65536  0  0  0  0  0  0  0  256   0  0  0  0  0  0  0  1

这样24位上的数加起来就有65739  RGB1,1,1=65793

 

 

 

 

 

 

我通过举几个例子来说明这方面的知识:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


把(RGB)转换成LongRGBb,g,r)就可以完成。(用算式:b *65536 + g *256 + r        来计算也可以)

那怎样把Long转换成(RGB)呢?我们可以用逆运算的计算方法来完成,用上面举的例了来说,

如果一个颜色的Long值为65793

B=Int(Long/65536)        =Int(1.00392)  =1

G=Int((Long – B * 65536) / 256)  =Int(257 / 256)  = 1

R=(Long – R * 65536) Mod 256  = 257  Mod 256   =1 

  经过计算,Long值为65793,可转换成(111)。

 

编程举例2:(保存为8256色不透明图标)

 

在上面的窗体中,添加一个按钮command2 caption=”Save256ColorIco”,编写代码:

 

Private Sub Command2_Click()  保存为8256色不透明图标

If Picture1.Height = 32 And Picture1.Width = 32 Then

 

Dim ifh As ICONFILEHEADER                'ICOfileheader

Dim bih As BITMAPINFOHEADER

Dim rgbq(255) As RGBQUAD

Dim rgbby(1023) As Byte

Dim fby(127) As Byte

 

    Open App.Path & "/temp2.ico" For Binary As #1

   

    ifh.idReserved = 0

    ifh.idCount = 1

    ifh.idType = 1

    ifh.bHeight = 32

    ifh.bWidth = 32

    ifh.bColorCount = 255

    ifh.bReserved = 0

    ifh.wPlanes = 1

    ifh.wBitCount = 8

    ifh.dwBytesInRes = 2216

    ifh.dwImageOffset = Len(ifh)

       

    Put #1, , ifh

   

    bih.biSize = Len(bih)

    bih.biWidth = 32

    bih.biHeight = 64     '!!!

    bih.biPlanes = 1

    bih.biBitCount = 8

    bih.biCompression = 0&

    bih.biSizeImage = 2176

    bih.biXPelsPerMeter = 0&

    bih.biYPelsPerMeter = 0&

    bih.biClrUsed = 0&

    bih.biClrImportant = 0&

   

    Put #1, , bih

   

    Dim i, j, k As Integer

    Dim r, g, b, ra, ga, ba, lIndex As Integer

    Dim by, byy As Long

    by = 16777215

    创建调色盘中的颜色(创建216个,其余为初始值0000

For b = 0 To 255 Step 51

        For g = 0 To 255 Step 51

            For r = 0 To 255 Step 51

                With rgbq(lIndex)

                    .rgbRed = r: .rgbGreen = g: .rgbBlue = b

                End With

                lIndex = lIndex + 1

            Next r

        Next g

        Next b

    Put #1, , rgbq

 

    For i = 0 To 31

    For j = 0 To 31

    byy = Picture1.Point(j, 31 - i)

    If byy = by Then

    rgbby(k) = 0

    Else

算出某点上的RGB的值

    b = Int(byy / 65536)

    byy = byy -b * 65536

    g = Int(byy / 256)

    r = byy Mod 256

算出该点上的颜色在调色盘中的ID号,并存入像素流rgbby()

    ra = Cint(r/51)

    ga = Cint(g/51)

    ba = Cint(b/51)

    rgbby(k) = ba * 36 + ga * 6 + ra

    End If

    k = k + 1

    Next

    Next

   

    Put #1, , rgbby

    不对fby() 赋值,那么fby() 中的每个数值都为初始值0 ,图标没有透明部分

    Put #1, , fby

       

    Close #1

   

Label1.Caption = "成功创建" & App.Path & "/temp2.ico"

Else

Label1.Caption = "图片大小应为32*32"

End If

  

End Sub

 

用计算的方法获得像素流:

调色盘中的颜色可以自由创建,我们把每一种颜色分成5档共6个不同的值(052102153204255),然后按一定的排列顺序,组成0~215 216种不同的颜色。

接着我们在扫描图片时,获得每个像素上的颜色Long ,用计算的方法算出(RGB)的值,再根据上面创建调色盘的方法,计算出与该点颜色相近的调色盘中的某一个颜色,在调色盘中排列的序号ID,把这个ID值存入Byte 类型的rgbby() 数组中,就形成了像像素流。

必须注意的是,由于位图和图标的像素流是倒置的,所以,除了要从左下角开始扫描外,还要在保存的过程中把RGB 倒置成BGR

 

童跃   福建省华安县际头小学

tongyue2007@126.com

2007 5 1

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

tongyue

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值