*.bmp文件结构
*.bmp文件和大多数图形文件一样,分为文件描述区(头文件信息)和图象存储区(象素数据)两部分。而头文件信息中又包含了信息区和调色板区两部分,信息区又可以细分为文件信息区和图象信息区两部分。
这里以256色320*200的bmp图象为例。头文件描述区的偏移长度是1078个字节,也就是说图象存储区是从文件偏移1078后开始读取的。在头文件描述区中头信息区的偏移长度是54个字节,也就是说调色板数据区是从54-1078之间的1024字节。在头信息区中文件信息区占14个字节而图象信息区占40字节。
(1) 文件信息区
typedef struct BMP_file
{
unsigned int bfType; //文件类型
unsigned long bfSize; //bmp文件长度
unsigned int Reserved1;
unsigned int Reserved2;
unsigned long bfOffset; //文件描述区长度,16色为118,256色为1078
}bitmapfile;
现在算一下,有3个int,2个long,正好3*2+2*4=14字节
(2) 图象信息区
type struct BMP_info
{
unsigned long biSize;
unsigned long biWidth;
unsigned long biHeight;
unsigned int biPlanes;
unsigned int biBitCount;
unsigned long biCompression;
unsigned long biSizeImage;
unsigned long biXplosPerMeter;
unsigned long biYplosPerMeter;
unsigned long biClrUsed;
unsigned long biClrImportant;
}bitmapinfo;
现在算一下,2个int,9个long,正好是2+2*9*4=40字节。
(3)调色板区
typedef struct RGB_BMP_typ
{
unsigned char blue;
unsigned char green;
unsigned char red;
unsigned char reserved;
}RGB_BMP,*RGB_BMP_ptr;
说明:三原色+灰度,共4*256=1024字节。
下面是bmp文件的完整的结构定义:
typedef struct bmp_picture_typ
{
bitmapfile file;
bitmapinfo info;
RGB_BMP palette[256];
char far *buffer;
}bmp_picture, *bmp_picture_ptr;
2. bmp文件的显示
(1)图象存储区的读取
由于bmp图象是从下至上存储的,所以我们不能进行直接顺序读取。详细的说,bmp图象存储区数据是从1078偏移字节开始。文件内第一个图象点实际上是对应图象(320*200)第200行的最左边的第一个点,而从1078开始的320个点则是图象最下面一行对应的点,之后的321个点是图象倒数第二行最左边的第一个点。这样,bmp文件最后一个字节对应的点是第一行最后边的点了。
BMP
BMP是一种与硬件设备无关的图像文件格式,使用非常广。它采用位映射存储格式,除了图像深度可选以外,不采用其他任何压缩,因此,BMP文件所占用的空间很大。BMP文件的图像深度可选lbit、4bit、8bit及24bit。BMP文件存储数据时,图像的扫描方式是按从左到右、从下到上的顺序。
由于BMP文件格式是Windows环境中交换与图有关的数据的一种标准,因此在Windows环境中运行的图形图像软件都支持BMP图像格式。
典型的BMP图像文件由三部分组成:位图文件头数据结构,它包含BMP图像文件的类型、显示内容等信息;位图信息数据结构,它包含有BMP图像的宽、高、压缩方法,以及定义颜色等信息。
具体数据举例:
如某BMP文件开头:
424D 4690 0000 0000 0000 4600 0000 2800 0000 8000 0000 9000 0000 0100*1000 0300 0000 0090 0000 A00F 0000 A00F 0000 0000 0000 0000 0000*00F8 0000 E007 0000 1F00 0000 0000 0000*02F1 84F1 04F1 84F1 84F1 06F2 84F1 06F2 04F2 86F2 06F2 86F2 86F2 .... ....
BMP文件可分为四个部分:位图文件头、位图信息头、彩色板、图像数据阵列,在上图中已用*分隔。
一、图像文件头
1)1:(这里的数字代表的是"字",即两个字节,下同)图像文件头。424Dh=’BM’,表示是Windows支持的BMP格式。
2)2-3:整个文件大小。4690 0000,为00009046h=36934。
3)4-5:保留,必须设置为0。
4)6-7:从文件开始到位图数据之间的偏移量。4600 0000,为00000046h=70,上面的文件头就是35字=70字节。
5)8-9:位图图信息头长度。
6)10-11:位图宽度,以像素为单位。8000 0000,为00000080h=128。
7)12-13:位图高度,以像素为单位。9000 0000,为00000090h=144。
8)14:位图的位面数,该值总是1。0100,为0001h=1。
二、位图信息头
9)15:每个像素的位数。有1(单色),4(16色),8(256色),16(64K色,高彩色),24(16M色,真彩色),32(4096M色,增强型真彩色)。1000为0010h=16。
10)16-17:压缩说明:有0(不压缩),1(RLE 8,8位RLE压缩),2(RLE 4,4位RLE压缩,3(Bitfields,位域存放)。RLE简单地说是采用像素数+像素值的方式进行压缩。T408采用的是位域存放方式,用两个字节表示一个像素,位域分配为r5b6g5。图中0300 0000为00000003h=3。
11)18-19:用字节数表示的位图数据的大小,该数必须是4的倍数,数值上等于位图宽度×位图高度×每个像素位数。0090 0000为00009000h=80×90×2h=36864。
12)20-21:用象素/米表示的水平分辨率。A00F 0000为0000 0FA0h=4000。
13)22-23:用象素/米表示的垂直分辨率。A00F 0000为0000 0FA0h=4000。
14)24-25:位图使用的颜色索引数。设为0的话,则说明使用所有调色板项。
15)26-27:对图象显示有重要影响的颜色索引的数目。如果是0,表示都重要。
三、彩色板
16)28-35:彩色板规范。对于调色板中的每个表项,用下述方法来描述RGB的值:
1字节用于蓝色分量
1字节用于绿色分量
1字节用于红色分量
1字节用于填充符(设置为0)
对于24-位真彩色图像就不使用彩色板,因为位图中的RGB值就代表了每个象素的颜色。
如,彩色板为00F8 0000 E007 0000 1F00 0000 0000 0000,其中:
00FB 0000为FB00h=1111100000000000(二进制),是红色分量的掩码。
E007 0000为 07E0h=0000011111100000(二进制),是绿色分量的掩码。
1F00 0000为001Fh=0000000000011111(二进制),是红色分量的掩码。
0000 0000总设置为0。
将掩码跟像素值进行“与”运算再进行移位操作就可以得到各色分量值。看看掩码,就可以明白事实上在每个像素值的两个字节16位中,按从高到低取5、 6、5位分别就是r、g、b分量值。取出分量值后把r、g、b值分别乘以8、4、8就可以补齐第个分量为一个字节,再把这三个字节按rgb组合,放入存储器(同样要反序),就可以转换为24位标准BMP格式了。
四、图像数据阵列
17)17-...:每两个字节表示一个像素。阵列中的第一个字节表示位图左下角的象素,而最后一个字节表示位图右上角的象素。
五、存储算法
BMP文件通常是不压缩的,所以它们通常比同一幅图像的压缩图像文件格式要大很多。例如,一个800×600的24位几乎占据1.4MB空间。因此它们通常不适合在因特网或者其它低速或者有容量限制的媒介上进行传输。根据颜色深度的不同,图像上的一个像素可以用一个或者多个字节表示,它由n/8所确定(n是位深度,1字节包含8个数据位)。图片浏览器等基于字节的 ASCII值计算像素的颜色,然后从调色板中读出相应的值。更为详细的信息请参阅下面关于位图文件的部分。 n位2n种颜色的位图近似字节数可以用下面的公式计算: BMP文件大小约等于 54+4*2的n次方+(w*h*n)/8
,其中高度和宽度都是像素数。需要注意的是上面公式中的54是位图文件的文件头,是彩色调色板的大小。另外需要注意的是这是一个近似值,对于n位的位图图像来说,尽管可能有最多2n中颜色,一个特定的图像可能并不会使用这些所有的颜色。由于彩色调色板仅仅定义了图像所用的颜色,所以实际的彩色调色板将小于。如果想知道这些值是如何得到的,请参考下面文件格式的部分。由于存储算法本身决定的因素,根据几个图像参数的不同计算出的大小与实际的文件大小将会有一些细小的差别。
1using System;
2using JJBase.FILE;
3namespace JJBase.Image
4{
5 /**
6 /// BMP 的摘要说明。
7 ///
8 public class BMP
9 {
10
11 public BMP()
12 {
13 //
14 //TODO: 在此处添加构造函数逻辑
15 //作者:梁俊杰
16 //时间:2005-9-29
17 //功能:分析bmp文件格式
18 //本文参考了林福宗老师的有关BMP文件格式的文章
19 //参考链接:http://www.chinahacker.net/article/showarticle.asp?articleid=20809
20 //参考链接:http://www.moon-soft.com/program/FORMAT/graphics/Bmp.html
21 //
22 }
23 /**//*BMP(BitMap-File)图形文件是Windows采用的图形文件格式,在Windows环境
24 * 下运行的所有图象处理软件都支持BMP图象文件格式。Windows系统内部各
25 * 图像绘制操作都是以BMP为基础的。Windows 3.0以前的BMP图文件格式与
26 * 显示设备有关,因此把这种BMP图象文件格式称为设备相关位图DDB
27 * (device-dependent BitMap)文件格式。Windows 3.0以后的BMP图象文件与
28 * 显示设备无关,因此把这种BMP图象文件格式称为设备无关位图DIB
29 * (device-independent BitMap)格式(注:Windows 3.0以后,在系统中仍
30 * 然存在DDB位图,象BitBlt()这种函数就是基于DDB位图的,只不过如果你想将
31 * 图像以BMP格式保存到磁盘文件中时,微软极力推荐你以DIB格式保存),目的
32 * 是为了让Windows能够在任何类型的显示设备上显示所存储的图象。BMP位图文件
33 * 默认的文件扩展名是BMP或者bmp(有时它也会以.DIB或.RLE作扩展名)。
34 * */
35 public struct StructBMP
36 {
37 public BMPHeader Header;
38 public BMPPalette Palette;
39 public BMPData Data;
40 }
41 public struct BMPHeader
42 {
43 /**//*位图文件可看成由4个部分组成:位图文件头(BitMap-file header)、
44 * 位图信息头(BitMap-information header)、彩色表(color table)和
45 * 定义位图的字节阵列,
46 * */
47 public string Identifier;/**//*2 bytes,识别位图的类型:
48 ‘BM’ : Windows 3.1x, 95, NT, …
49 ‘BA’ :OS/2 BitMap Array
50 ‘CI’ :OS/2 Color Icon
51 ‘CP’ :OS/2 Color Pointer
52 ‘IC’ : OS/2 Icon
53 ‘PT’ :OS/2 Pointer
54 注:因为OS/2系统并没有被普及开,所以在编程时,你只需判断第一个标识“BM”就行。
55 */
56 public System.Int32 FileSize;//1 dword,用字节表示的整个文件的大小
57 public byte[] Reserved;//1 dword,保留,必须设置为0
58 public System.Int32 BitMapDataOffset;//1 dword,从文件开始到位图数据开始之间的数据(BitMap data)之间的偏移量
59 public System.Int32 BitMapHeaderSize;/**//*1 dword
60 位图信息头(BitMap Info Header)的长度,用来描述位图的颜色、压缩方法等。下面的长度表示:
61 28h - windows 3.1x, 95, nt, …
62 0ch - os/2 1.x
63 f0h - os/2 2.x
64 注:在Windows95、98、2000等操作系统中,位图信息头的长度并不一定是28h,因为微软已经制定出了新的BMP文件格式,其中的信息头结构变化比较大,长度加长。所以最好不要直接使用常数28h,而是应该从具体的文件中读取这个值。这样才能确保程序的兼容性。
65 */
66 public System.Int32 Width;//1 dword,位图的宽度,以象素为单位
67 public System.Int32 Height;//1 dword,位图的高度,以象素为单位
68 public System.Int16 Planes;//1 word,位图的位面数(注:该值将总是1)
69 public System.Int16 BitsPerPixel;
70 /**//*1 word
71 每个象素的位数
72 1 - 单色位图(实际上可有两种颜色,缺省情况下是黑色和白色。你可以自己定义这两种颜色)
73 4 - 16 色位图
74 8 - 256 色位图
75 16 - 16bit 高彩色位图
76 24 - 24bit 真彩色位图
77 32 - 32bit 增强型真彩色位图
78 */
79 public System.Int32 Compression;
80 /**//*1 dword
81 压缩说明:
82 0 - 不压缩 (使用BI_RGB表示)
83 1 - RLE 8-使用8位RLE压缩方式(用BI_RLE8表示)
84 2 - RLE 4-使用4位RLE压缩方式(用BI_RLE4表示)
85 3 - Bitfields-位域存放方式(用BI_BITFIELDS表示)
86 */
87 public System.Int32 BitMapDataSize;//1 dword,用字节数表示的位图数据的大小。该数必须是4的倍数
88 public System.Int32 HResolution;//1 dword,用象素/米表示的水平分辨率
89 public System.Int32 VResolution;//1 dword,用象素/米表示的垂直分辨率
90 public System.Int32 Colors;//1 dword,位图使用的颜色数。如8-比特/象素表示为100h或者 256.
91 public System.Int32 ImportantColors;
92 /**//*1 dword,指定重要的颜色数。当该域的值等于颜色数时(或者等于0时),表示所有颜色都一样重要
93 */
94 }
95 public struct BMPPalette
96 {
97 public byte[] Palette;//new byte[8192];//bmp规范没有规定调色板最大81926字节,此处可以根据程序需要调节
98 /**//*调色板数据根据BMP版本的不同而不同PaletteN * 4 byte调色板规范。
99 对于调色板中的每个表项,这4个字节用下述方法来描述RGB的值: 1字节用于蓝色分量
100 1字节用于绿色分量
101 1字节用于红色分量
102 1字节用于填充符(设置为0)
103 */
104 }
105 public struct BMPData
106 {
107 public byte[] BitMapData;//=new byte[1024000];//bmp规范没有规定bmp数据最多为1024000,此处可以根据需要调整
108 /**//*
109 图象数据根据BMP版本及调色板尺寸的不同而不同BitMap Dataxxx bytes该域的大小取决
110 于压缩方法及图像的尺寸和图像的位深度,它包含所有的位图数据字节,这些数据可能是
111 彩色调色板的索引号,也可能是实际的RGB值,这将根据图像信息头中的位深度值来决定。
112 */
113 }
114 public void ProcessBMP(ref StructBMP sbmp,byte[] bytesFile)
115 {
116 byte[] word1=new byte[2];
117 byte[] word2=new byte[4];
118 System.Int32 result;
119 string str="";
120 word1[0]=bytesFile[0];
121 word1[1]=bytesFile[1];
122 str=FromBytesToString(word1);
123 sbmp.Header.Identifier=str;
124 word2[0]=bytesFile[2];
125 word2[1]=bytesFile[3];
126 word2[2]=bytesFile[4];
127 word2[3]=bytesFile[5];
128 result=this.FromBytesToInt32(word2);
129 sbmp.Header.FileSize=result;
130 word2[0]=bytesFile[10];
131 word2[1]=bytesFile[11];
132 word2[2]=bytesFile[12];
133 word2[3]=bytesFile[13];
134 result=this.FromBytesToInt32(word2);
135 sbmp.Header.BitMapDataOffset=result;
136 word2[0]=bytesFile[14];
137 word2[1]=bytesFile[15];
138 word2[2]=bytesFile[16];
139 word2[3]=bytesFile[17];
140 result=this.FromBytesToInt32(word2);
141 sbmp.Header.BitMapHeaderSize=result;
142 word2[0]=bytesFile[18];
143 word2[1]=bytesFile[19];
144 word2[2]=bytesFile[20];
145 word2[3]=bytesFile[21];
146 sbmp.Header.Width=result;
147 word2[0]=bytesFile[22];
148 word2[1]=bytesFile[23];
149 word2[2]=bytesFile[24];
150 word2[3]=bytesFile[25];
151 result=this.FromBytesToInt32(word2);
152 sbmp.Header.Height =result;
153 word1[0]=bytesFile[26];
154 word1[1]=bytesFile[27];
155 sbmp.Header.Planes=(System.Int16)FromBytesToInt32(word1);
156 word1[0]=bytesFile[28];
157 word1[1]=bytesFile[29];
158 sbmp.Header.BitsPerPixel=(System.Int16)FromBytesToInt32(word1);
159 word2[0]=bytesFile[30];
160 word2[1]=bytesFile[31];
161 word2[2]=bytesFile[32];
162 word2[3]=bytesFile[33];
163 result=this.FromBytesToInt32(word2);
164 sbmp.Header.Compression =result;
165 word2[0]=bytesFile[34];
166 word2[1]=bytesFile[35];
167 word2[2]=bytesFile[36];
168 word2[3]=bytesFile[37];
169 result=this.FromBytesToInt32(word2);
170 sbmp.Header.BitMapDataSize =result;
171 word2[0]=bytesFile[38];
172 word2[1]=bytesFile[39];
173 word2[2]=bytesFile[40];
174 word2[3]=bytesFile[41];
175 result=this.FromBytesToInt32(word2);
176 sbmp.Header.HResolution =result;
177 word2[0]=bytesFile[42];
178 word2[1]=bytesFile[43];
179 word2[2]=bytesFile[44];
180 word2[3]=bytesFile[45];
181 result=this.FromBytesToInt32(word2);
182 sbmp.Header.VResolution =result;
183 word2[0]=bytesFile[46];
184 word2[1]=bytesFile[47];
185 word2[2]=bytesFile[48];
186 word2[3]=bytesFile[49];
187 result=this.FromBytesToInt32(word2);
188 sbmp.Header.Colors =result;
189 word2[0]=bytesFile[50];
190 word2[1]=bytesFile[51];
191 word2[2]=bytesFile[52];
192 word2[3]=bytesFile[53];
193 result=this.FromBytesToInt32(word2);
194 sbmp.Header.ImportantColors =result;
195 //计算位图数据的开始位置
196 //sbmp.Header.BitMapDataSize是位图数据的大小,sbmp.Header.FileSize是整个文件的大小
197 //sbmp.Header.FileSize-sbmp.Header.BitMapDataSize-1就是位图数据的开始位置
198 //0x36到sbmp.Header.FileSize-sbmp.Header.BitMapDataSize-2就是调色板数据
199 result=sbmp.Header.FileSize-sbmp.Header.BitMapDataSize;
200 int j=0;
201 byte[] b=new byte[sbmp.Header.BitMapDataSize];
202 for(int i=result;i
204 b[j]=bytesFile[i];j++;
205 }
206 sbmp.Data.BitMapData=b;
207 j=0;
208 b=new byte[result-sbmp.Header.BitMapDataOffset];
209 for(int i=sbmp.Header.BitMapDataOffset;i
211 b[j]=bytesFile[i];j++;
212 }
213 sbmp.Palette.Palette=b;
214 }
215 public void ProcessBMP(ref StructBMP sbmp,string File)
216 {
217 //先读取文件成字节数组,统一由ProcessBMP(StructBMP sbmp,byte[] bytesFile)处理
218 JJBase.FILE.ReadAndWrite f=new ReadAndWrite();
219 byte[] result=f.ReadBytesFromFile(File);
220 ProcessBMP(ref sbmp,result);
221 }
222 private System.Int32 FromBytesToInt32(byte[] b)
223 {
224 System.Int32 result=0;
225 System.Int32 t=0;
226 for(int i=b.Length-1;i>=0;i--)
227 {
228
229 if((int)b[i]!=0)
230 {
231 t=(int)Math.Pow(256,i);
232 result+=(int)b[i]*t;
233 }
234
235 }
236 return result;
237 }
238 private string FromBytesToString(byte[] b)
239 {
240 string result="";
241 for(int i=0;i
243 result+=Convert.ToChar((int)(b[i])).ToString();
244 }
245 return result;
246 }
247
248 }
249}