位图文件分析

来源:互联网 发布:优化教育的意思 编辑:程序博客网 时间:2024/06/03 21:22

位图是Windows系统中一种最简单也是最基本的图像格式,了解位图的文件结构有助于对位图进行各种操作。

关于位图的存储和显示

普通的显示器屏幕是由许许多多点构成的,我们称之为象素。显示时采用扫描的方法:电子枪每次从左到右扫描一行,为每个象素着色,然后从上到下这样扫描若干行,就扫过了一屏。为了防止闪烁,每秒要重复上述过程若干次。例如我们常说的屏幕分辨率为1024*768,刷新频率为80Hz,意思是说每行要扫描1024个象素,一共有768行,每秒重复扫描屏幕80次。 我们称这种显示器为位映象设备。所谓位映象,就是指一个二维的象素矩阵,而位图就是采用位映象方法显示和存储的图象。

关于位图的结构

位图文件主要由4个部分构成,分别为位图文件头、位图信息图、调色板和实际位图数据,如下图1-1所示

图1-1 位图结构

位图信息结构(BITMAPFILEHEADER)

位图信息图(BITMAPINFOHEADER)

调色板(LOGPALLETE)

实际位图数据

1.位图文件头

位图文件头对应的结构为BITMAPFILEHEADER,共占14个字节。 它(位图文件头)的数据结构含有BMP文件的类型、文件大小和位图起始位置等信息。

其结构定义如下:  

typedef struct tagBITMAPFILEHEADER
 {
  WORD bfType; 

DWORD bfSize;

WORD bfReserved1;

WORD bfReserved2;

DWORD bfOffBits; 

 } BITMAPFILEHEADER;

bfType:位图文件的类型,值为0x4d42,即字符串BM

bfSize:位图文件的大小,即图1-1中所描述的4个部分的大小以字节为单位

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

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

bfOffBits:从头文件到实际的位图数据的偏移字节数,也就是图1-1中前三个部分长度之和。 

2.位图信息头 

位图信息头数据用于说明位图的尺寸等信息。它对应的结构为BITMAPINFOHEADER,共占用40个字节。

其结构定义如下: 
 typedef struct tagBITMAPINFOHEADER{
  DWORD      biSize;

        LONG      biWidth;  

  LONG      biHeight; 

  WORD      biPlanes; 

WORD      biBitCount;

        DWORD      biCompression;            

  DWORD  biSizeImage; 

        LONG  biXPelsPerMeter; 

  LONG  biYPelsPerMeter; 

  DWORD  biClrUsed;  

        DWORD  biClrImportant; 

} BITMAPINFOHEADER; 

biSize:本结构所占用字节数,固定值40

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

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

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

biBitCount:指定颜色所用的位(Bit)数,取值:

0,用在JPEG格式中  

1,单色图,调色板中含有两种颜色,也就是我们通常说的黑白图片 

4表示16色图  

8表示256色图,通常说的灰度图  

16表示64K图,一般没有调色板,图像数据中每两个字节表示一个图像,个或6个位表示一个RGB分量

24表示16M真彩色图,一般没有调色板,图像数据中每3个字节表示一个像素,每个字节表示一个RGB分量  

32表示4G真彩色,一般没有调色板,每4个字节表示一个像素,相对24位 真彩图而言,加入了一个透明度,即RGBA模式

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

biSizeImage:位图的实际大小,以字节为单位

biXPelsPerMeter:目标设备的水平分辨率,单位是像素数/米

biYPelsPerMeter:目标设备的垂直分辨率,单位是像素数/米

biClrUsed:位图实际使用的颜色表中的颜色数,如果是0,表示用到了2的biBitCount次方

biClrImportant:图像中重要的颜色数,如果为0,表示所有的颜色都是重要的。 

3.调色板(颜色表)

在介绍位图文件结构之前,我们来了解一下关于图像颜色的知识。

我们知道,自然界中的所有颜色都可以由红、绿、蓝(R,G,B)组合而成,我们称这三种颜色为三原色。其中每一种颜色成分在计算机中都由一个字节来表示,在数值上分成0~255共256个等级,那么由三原色构成的颜色就可以用一个24位的二进制数来表示,这样我们可以得到256*256*256约1600万种颜色,这些颜色对我们来说已经足够丰富来表现我们这个多彩缤纷的世界。但在接下来的介绍中你会发现聪明的编程人员采用了简便的方法来节省我们有限的存储空间。来看一个例子。

有一个长宽各为200个象素,颜色数为16色的彩色图,每一个象素都用R、G、B三个分量表示。因为每个分量有256个级别,要用8位(bit),即一个字节(byte)来表示,所以每个象素需要用3个字节。整个图象要用200×200×3,约120k字节,可不是一个小数目!如果我们用下面的方法,就能省的多。

因为是一个16色图,也就是说这幅图中最多只有16种颜色,我们可以用一个表:表中的每一行记录一种颜色的R、G、B值。这样当我们表示一个象素的颜色时,只需要指出该颜色是在第几行,即该颜色在表中的索引值。举个例子,如果表的第0行为255,0,0(红色),那么当某个象素为红色时,只需要标明0即可。

再来计算一下:16种状态可以用4位(bit)表示,所以一个象素要用半个字节。整个图象要用200×200×0.5,约20k字节,再加上表占用的字节为3×16=48字节.整个占用的字节数约为前面的1/6,省很多吧?

这张R、G、B的表,就是我们常说的颜色表调色板(Palette),另一种叫法是颜色查找表LUT(Look Up Table),似乎更确切一些。

有一种图,它的颜色数高达256×256×256种,也就是说包含我们上述提到的R、G、B颜色表示方法中所有的颜色,这种图叫做真彩色图(true color)

真彩色图并不是说一幅图包含了所有的颜色,而是说它具有显示所有颜色的能力,即最多可以包含所有的颜色。表示真彩色图时,每个象素直接用R、G、B三个分量字节表示,而不采用调色板技术。原因很明显:如果用调色板,表示一个象素也要用24位,这是因为每种颜色的索引要用24位(因为总共有224种颜色,即调色板有224行),和直接用R,G,B三个分量表示用的字节数一样,不但没有任何便宜,还要加上一个256×256×256×3个字节的大调色板。所以真彩色图直接用R、G、B三个分量表示,它又叫做24位色图。

调色板是一种GDI对象,可以认为它是一个颜色数组,列举了图像用到的所有颜色。对于真彩色位图来说,是没有调色板的,此时在位图信息后直接是位图的实际数据。

在具体的文件结构中,颜色表有若干个表项,每一个表项是一个RGBQUAD类型的结构,定义一种颜色。

RGBQUAD结构的定义如下:  

typedef struct tagRGBQUAD {
  BYTE rgbBlue;// 蓝色的亮度(值范围为0-255)
  BYTE rgbGreen; // 绿色的亮度(值范围为0-255)
  BYTE rgbRed; // 红色的亮度(值范围为0-255)
  BYTE rgbReserved;// 保留,必须为0
 } RGBQUAD;
 颜色表中RGBQUAD结构数据的个数有biBitCount来确定:
 当biBitCount=1,4,8时,分别有2,16,256个表项;
 当biBitCount=24时(真彩色位图),没有颜色表项。


 位图信息头和颜色表组成位图信息,BITMAPINFO结构定义如下:
 typedef struct tagBITMAPINFO {
  BITMAPINFOHEADER bmiHeader; // 位图信息头
  RGBQUAD bmiColors[1]; // 颜色表
 } BITMAPINFO;

 

4.实际位图数据

对于使用了调色板的位图,位图实际数据描述的是像素值在调色板中的索引值;如果没有使用调色板,位图实际数据就是实际的RGB颜色值。

图形数据位图数据记录了位图的每一个像素值或该对应像素的颜色表的索引值,图像记录顺序在扫描行内是从左到右,扫描行之间是从下到上。这种格式我们又称为Bottom_Up位图,当然与之相对的还有Up_Down形式的位图,它的记录顺序是从上到下的,对于这种形式的位图,也不存在压缩形式。位图的一个像素值所占的字节数:当biBitCount=1时,8个像素占1个字节;当biBitCount=4时,2个像素占1个字节;当 biBitCount=8时,1个像素占1个字节;当biBitCount=24时,1个像素占3个字节,此时图像为真彩色图像。当图像不是为真彩色时,图像文件中包含颜色表,位图的数据表示对应像素点在颜色表中相应的索引值,当为真彩色时,每一个像素用三个字节表示图像相应像素点彩色值,每个字节分别对应R、G、B分量的值,这时候图像文件中没有颜色表。Windows规定一个扫描行所占的字节数必须是 4的倍数(即以long为单位),不足的以0填充。

一个扫描行所占的字节数计算方法:DataSizePerLine = (biWidth* biBitCount+31)/8;

一个扫描行所占的字节数:DataSizePerLine= DataSizePerLine/4*4; // 字节数必须是4的倍数

位图数据的大小(不压缩情况下): DataSize= DataSizePerLine* biHeight

 


0 0