2009年8月12日星期三

如何在LINUX下处理bmp位图

Microsoft Windows
3.0中的画笔(Paintbrush)工具软件为用户提供了强有力的图形绘制和编辑功能,例如图形的旋转、缩放、拼接等[1].利用这些功能可以非常方便地生成所需要的各种复杂的彩色画面.生成的画面以位图文件的格式存储在磁盘上.以此文件为资源,在Mircosoft
Windows 3.0的支持下,可以在任何需要的时候在任何设备上再现该画面[2].

在实际工作中经常遇到这样的问题:在利用画笔工具软件生成了所需的画面之后,能否脱离开Windows的支持,在其它系统中使用这些画面呢?解决这一问题的关键在于了解位图文件的记录格式.只要了解位图文件的记录格式,这一问题是容易解决的.基于这一目的,文本将详细介绍Mircosoft
Windows 3.0位图文件的记录格式.

Microsoft Windows 3.0位图文件(以.BMP为扩展名)由以下三个部分组成:

* 位图文件头(BITMAPFILEHEADER) 数据结构

* 位图信息(BITMAPINFO)数据结构

* 位图阵列

一. 位图文件头的结构

位图文件头数据结构含有位图文件的类型、大小和打印格式等信息.在Windows.h中对其进行了定义:

Typedef struct tagBITMAPFILEHEADER

{

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

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

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

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

DWORD bfoffbits; /*位图阵列的起始位置,以相对于位图文件*/

/*头的偏移量表示,以字节为单位.*/

}BITMAPFILEHEADER;

二. 位图信息的结构

位图信息数据结构含有位图文件的尺寸和颜色等信息.在Windows.h中对其进行了定义:
typedef stuc tagBITMAPINFO

{

BITMAPINFOHEADER bmiHeader;

RGBQUAD bmiColor[];

}BITMAPINFO;

1.bmiHeader是一个位图信息头(BIMMAPINFOHEADER)类型的数据结构,用于说明位图的尺寸.
BITMAPINFOHEADER的定义:

typedef struct tagBITMAPINFOHEADER

{

DWORD BiSize; /*bmiHeader的长度,以字节为单位.*/

DWORD biWidth; /*位图的宽度,以象素为单位.*/

DWORD biHight; /*位图的高度,以象素为单位.*/

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

WORD biBitCount; /*每个象素所需的位数,必须是1(单色).*/

/*4(16色),8(256色),或24(2^24色)之一. */

DWORD biCompress; /*位图的压缩类型,必须是0(不压缩).*/

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

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

DOWRD biXPeIsPerMeter;
/*位图的目标设备水平分辨率,以每米象素数为单位.*/

DWORD biYPeIsPerMeter;
/*位图的目标设备水平分辨率,以每米象素数为单位.*/

DWORD biCIrUsed;
/*位图实际使用的颜色表中的颜色变址数,详见[3].*/

DWORD biCIrImprotant;
/*位图显示过程中被认为重要颜色的变址数,详见[3]*/

}BITMAPINFOHEADER;

2.
bimColor[]是一个颜色表,用于说明位图中的颜色.它有若干个表项,每一表项是一个RGBQUAD类型的结构,定义了一种颜色.RGBQUAD的定义:

Typedef tagRGBQUAD

{

BYTE rgbBlue;

BYTE rgbGreen;

BYTE rgbRed;

BYTE rgbReserved;

}RGBQUAD;

在RGBQUAD定义的颜色中,蓝色的亮度由rgbBlue来定,绿色的亮度由rgbGreen来定,红色的亮度由rgbred来定,rgbRserved必须为0.

例如: 若某表项为00,00,FF,00, 那么它定义的颜色为纯红色.

bimColor[]表项的个数由bmBitCount来定:

当bmBitCount=1,4,8时,
bimColor[]分别有2,16,256个项.若某点的象素值为n,则该象素的颜色为bimColor[]所定义的颜色.

当bmBitCount=24时,
bimColor[]的表项为空.位图阵列的每3个字节代表一个像素,这3个字节直接定义了象素颜色中蓝、绿、红的相对亮度,因此省去了bimColor[]颜色表.

三. 位图阵列的结构

位图阵列记录了位图的每一个象素值.在生成位图文件时,Windows从位图的左下角开始(即从左到右从上到下)逐行扫描位图,将位图的象素值一一记录下来.这些记录象素值的字节组成了位图阵列.

位图阵列有压缩和非压缩两种存储格式.

1.非压缩格式

在非压缩格式中,位图的每一点的象素值值一对应于位图阵列的若干位(bit),位图阵列的大小由位图的宽度,高度及位图的颜色数(bitBITCount)决定.

(1) 位图扫描行与位图阵列的关系

设记录一个扫描行的象素值需n个字节,则:

位图阵列的0~n-1个字节记录了位图的第一个扫描行的象素值;位图阵列的n~2n-1个字节记录了位图的第二个扫描行的象素值;依些类推,位图阵列的(m-1)*n~m*n-1个字节记录了位图的第m个扫描行的象素值.位图阵列的大小为n*biHight.

当(biWith*bitBITCount)mod32=0时:

n=(biWith*biBITCount)/8

当(biWith*bitBITCount)mod32!=0时:

n=(biWith*biBITCount)/8+4

上式中的+4而不+1的原因是为了使一个扫描行的象素值占用位图阵列的字节数为4的倍数(Windows规定其必须在long边界结束),不足的位用0填充.

(2)位图象素值与位图阵列的关系(以第m扫描行为例)

设记录第m个扫描行的象素值的n个字节分别为:a0,a1,a2,...,则:

当bitBITCount=1时:a0的D7位记录了位图的第m个扫描行的第1个象素值,D6位记录了位图的第m个扫描行的第1个象素值,...,
D0位记录了位图的第m个扫描行的第8个象素值,
a1的D7位记录了位图的第m个扫描行的第9个象素值,D6位记录了位图的第m个扫描行的第10个象素值,...

当bitBITCount=4时:a0的D7-D4位记录了位图的第m个扫描行的第1个象素值,D3-D0位记录了位图的第m个扫描行的第2个象素值,
a1的D7-D4位记录了位图的第m个扫描行的第3个象素值,...

当bitBITCount=8时:a0的D7-D4位记录了位图的第m个扫描行的第1个象素值,a1记录了位图的第m个扫描行的第2个象素值,...

当bitBITCount=24时:a0,a1,a2位记录了位图的第m个扫描行的第1个象素值,a3,a4,a5记录了位图的第m个扫描行的第2个象素值,...

位图其它扫描行的象素值与位图阵列的对应关系与此类似.

2. 压缩格式

Windows支持BI_RLE8及BI_RLE4压缩位图存储格式,减少了位图阵列所占用的磁盘空间.

(1)BI_RLE8压缩格式

当bicompression=1时,位图文件采用此压缩编码格式.压缩编码以两个字节为基本单位.其中第一个字节规定了用两个字节指定的颜色重复画出的连续象素的数目.

例如,压缩编码05
04表示从当前位置开始连续显示5个象素,这5个象素的象素值均为04.

在第一字节为零时,第二字节有特殊的含义:

0: 行末

1: 图末

2:
转义后面的两个字节,用这俩个字节分别表示下一个象素从当前位置开始的水平位移和垂直位移.

n(0x03<n<xff):转义后面的n个字节,其后的n象素分别用这n个字节所指定的颜色画出.注意:实际编码时必须保证后面的字节数是4的倍数.不足的位用0补齐.

例如,压缩编码00 00表示开始新的扫描行,压缩编码00
01表示压缩位图阵列结束,压缩编码00 02 05
01表示从当前位置开始向右移5个象素,向下移1行后再画下一个象素,压缩编码00 03
05 06 07
00表示从当前位置开始连续画3个象素,3个象素的颜色分别为05,06,07,最后面的00是为了保证被转义的字节数是4的倍数.

(2)BI_RLE4压缩格式

当bicompression=4时,位图文件采用此后压缩编码格式.BI_RLE4的压缩编码格式与BI_RLE8的编码方式类似,维一的不同是:BI_RLE4的一个字节包含了两个象素的颜色.

当连续显示时,第一个象素按字节高四位规定的颜色画出,第二个象素按字节低似位规定的颜色画出,第三个象素按字节高四位规定的颜色画出,...,直到所有象素都画出为止.

例如:压缩编码06
67表示从当前位置开始连续画5个象素,5个象素的颜色分别为6,7,6,7,6.

压缩编码00 04 45 67 00表示从当前位置开始连续画4个象素,
4个象素的颜色分别为4,5,6,7.最后面的00是为了保证被转义的字节数是4的倍数.

四. 实例分析

为了更清楚地说明位图文件的格式,下面对存储一个简单划面(如附图所示)的位图文件进行具体分析.画面的底色是蓝色,上面的直线的颜色是黄色,下面的直线的颜色是红色.位图以16色位映象方式存储[1],文件名为DEMO.BMP.用debug分析位图文件的内容如下:

186C:0100 42 4D 3E 01 00 00 00 00-00 00 76 00 00 00 28 00

186C:0110 00 00 26 00 00 00 0A 00-00 00 01 00 04 00 00 00

186C:0120 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00

186C:0130 00 00 00 00 00 00 00 00-00 00 00 00 80 00 00 80

186C:0140 00 00 00 80 80 00 80 00-00 00 80 00 80 00 80 80

186C:0150 00 00 80 80 80 00 40 40-40 00 00 00 FF 00 00 FF

186C:0160 00 00 00 FF FF 00 FF 00-00 00 FF 00 FF 00 FF
FF

186C:0170 00 00 FF FF FF 00 CC CC-CC CC CC CC CC CC CC CC

186C:0180 CC CC CC CC CC CC CC CC-CC 00 CC CC CC CC CC CC

186C:0190 CC CC CC CC CC CC CC CC-CC CC CC CC CC CC CC 99

186C:01A0 99 99 99 99 99 99 99 99-99 99 99 99 99 99 99 CC

186C:01B0 CC 00 CC CC CC CC CC CC-CC CC CC CC CC CC CC CC

186C:01C0 CC CC CC CC CC 00 CC CC-CC CC CC CC CC CC CC CC

186C:01D0 CC CC CC CC CC CC CC CC-CC 00 CC CB BB BB BB BB

186C:01E0 BB BB BB BB BB BB BB BB-BB BB BB BC CC 00 CC CC

186C:01F0 CC CC CC CC CC CC CC CC-CC CC CC CC CC CC CC CC

186C:0200 CC 00 CC CC CC CC CC CC-CC CC CC CC CC CC CC CC

186C:0210 CC CC CC CC CC 00 CC CC-CC CC CC CC CC CC CC CC

186C:0220 CC CC CC CC CC CC CC CC-CC 00 CC CC CC CC CC CC

186C:0230 CC CC CC CC CC CC CC CC-CC 00 CC CC CC 00 00 00

(0,0)

┌───────────┐

│(3,4) (黄色) (35,4)│

│_____________________ │

│ │

│ │

│(2,7) (红色) (34,7)│

│_____________________ │

└───────────┘

(38,10)

附图 实例画面

其中:

0100-010D是BITMAPFILEHEADER数据结构,它说明了如下的信息:位图文件共318B
(bfSize=0x013E),位图阵列从0176处开始(bfoffBits=0x76).

010E-0135是BITMAPFILEHEADER数据结构,它说明了如下的信息:BITMAPFILEHEADER共28B(biSize=0x28),位图的大小为38X10(biWith00x26,
biHight=0x0A,以象素为单位)

位图阵列的每四位表示一个象素,位图有16种颜色,
bmiColor[]有16个表项(bitBITCount=4),位图采用非压缩存储方式(bitCompression=0);

0136-0175是bmiColor[]颜色表,每四个字节定义一种颜色,共64B,定义了16种颜色.其中第九个表项(015A-015D)定义了红色,第11表项(0162-0165)定义了黄色,第12个表项(0166-0169)定义了蓝色.

0176-023D是位图阵列,位图每个扫描行有38个象素,对应位图阵列中的20个字节,其中第20个字节被填0,以保证字节数是4的倍数.黄线在位图的第6扫描行,此行对应位图阵列的01DA-01ED字节,红线在位图的第3行扫描,此行对应位图阵列的0192-01B1字节,位图共有10个扫描行.

没有评论: