位图文件结构解析

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

我们称这种显示器为位映象设备。所谓位映象,就是指一个二维的象素矩阵,而位图就是采用位映象方法显示和存储的图象。

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

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

位图(bmp)文件由文件头、位图信息头、颜色信息和图形数据四部分组成。

1.位图文件头
BMP文件头数据结构含有BMP文件的类型、文件大小和位图起始位置等信息。

 其结构定义如下:
 typedef struct tagBITMAPFILEHEADER
 {
  WORD bfType;          // 位图文件的类型,必须为BM
  DWORD bfSize;    // 位图文件的大小,以字节为单位
  WORD bfReserved1;  // 位图文件保留字,必须为0
  WORD bfReserved2;  // 位图文件保留字,必须为0
  DWORD bfOffBits;   // 位图数据的起始位置,以相对于位图
             // 文件头的偏移量表示,以字节为单位
 } BITMAPFILEHEADER;
2.位图信息头
BMP位图信息头数据用于说明位图的尺寸等信息。

 typedef struct tagBITMAPINFOHEADER{
  DWORD biSize;    // 本结构所占用字节数
  LONG     biWidth;     // 位图的宽度,以像素为单位
  LONG     biHeight;    // 位图的高度,以像素为单位
  WORD     biPlanes;   // 目标设备的级别,必须为1
  WORD     biBitCount  // 每个像素所需的位数,必须是1(双色),
            // 4(16色),8(256色)或24(真彩色)之一
  DWORD biCompression; // 位图压缩类型,必须是 0(不压缩),
            // 1(BI_RLE8压缩类型)或2(BI_RLE4压缩类型)之一
  DWORD biSizeImage; // 位图的大小,以字节为单位
  LONG biXPelsPerMeter; // 位图水平分辨率,每米像素数
  LONG biYPelsPerMeter; // 位图垂直分辨率,每米像素数
  DWORD biClrUsed; // 位图实际使用的颜色表中的颜色数
  DWORD biClrImportant; // 位图显示过程中重要的颜色数
 } BITMAPINFOHEADER;

3.颜色表(或者调色板)

为什么有必要使用颜色表呢,我们来看一个例子。

有一个长宽各为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位色图。


在具体的文件结构中,颜色表有若干个表项,每一个表项是一个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.图形数据
位图数据记录了位图的每一个像素值或该对应像素的颜色表的索引值,图像记录顺序在扫描行内是从左到右,扫描行之间是从下到上。这种格式我们又称为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;

1.假设屏幕分辨率为n; 2.每个像素点用 x bit来表示; 3.图片中实际的颜色数为y 直接存储: n * x / 8 使用调色板的存储: y * x / 8 + n * log以2为底y / 8 注:调色板包含实际使用到的颜色值,FrameBuffer里则存储着对调色板的索引。
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值