BMP文件格式初步学习

来源:互联网 发布:最好的中文编程语言 编辑:程序博客网 时间:2024/05/05 05:49

以下文字大多来自网上的文章,我按照自己的理解记录并且摘抄了部分写在这里。

BMP文件格式相对jpeg,png,gif要简单一些。

跟elf文件类似,文件头,信息头,偏移量等,也有自己的魔数。

打开windows的画图工具,可以保存4种

image

每种模式存储单一像素需要的大小为1bit,4bit,8bit,24bit,即1/8字节,1/2字节,1字节,3字节。

比如256色位图,表示共有256种像素,正好需要1字节来存储一个像素。

 

位图文件可以看做由4部分组成:

1.位图文件头(BitMap File Header)//主要是文件类型,文件大小的定义

2.位图信息头(BitMap Info Header)//主要是位图的属性,宽高,每像素占用bit数,是否压缩等等。

3.颜色表(Color Table)//24位位图没有

4.位图数据区。

文件大小=sizeof(BitMapFileHeader)+sizeof(BitMapInfoHeader)+sizeof(Color Table)+位图数据大小。

 

我们先逐个看下这4部分具体有什么,例子随后给出.

1.位图文件头:14个字节

起始字节所占字节数具体内容标示12文件类型(“BM”)bfType34文件大小bfSize74保留bfReserved114位图数据开始的字节位置bfOffBits

备注:

有的地方保留字认为是两个,每个占用2个字节。反正是保留字,区别不大,均设为0.

2.位图信息头:40个字节

起始字节所占字节数具体内容标示154位图信息头的长度(40)biSize194位图的宽度biWidth234位图的高度biHeight272位图的位面数(=1)biPlanes292每个像素所占的位数(1,4,8,24等)biBitCount314位图压缩类型biCompression354图像的大小(以字节为单位,必须为4的倍数)biSizeImage394位图水平分辨率(像素/米)biXPelsPerMeter434位图垂直分辨率(像素/米)biYPelsPerMeter474位图实际使用的颜色数(=0使用所有颜色)biClrUsed514指定重要的颜色数(=0,都很重要)biClrImportant

备注:

1.有些变量位面数,压缩方式,重要颜色数这些一般不用关心,设为默认即可。

2.biSize是本结构所占字节数,实际上该结构占用40个字节,但Windows每次还是需要您亲自添上

3.biSizeImage表示图像大小(即位图数据的大小),并不能简单的这么计算:

biSizeImage = biWidth*biHeight*biBitCount/8;//error!!

实际需要这么计算,因为

Windows规定一个扫描行所占的字节数必须是
  4的倍数(即以long为单位),不足的以0填充。

 一个扫描行所占的字节数计算方法:
  DataSizePerLine= (biWidth* biBitCount+31)/8; // 一个扫描行所占的字节数
  DataSizePerLine= DataSizePerLine/4*4; // 字节数必须是4的倍数
  位图数据的大小(不压缩情况下):
  biSizeImage = DataSize= DataSizePerLine* biHeight;

因此进一步修改前面的公式:

文件大小=sizeof(BitMapFileHeader)+sizeof(BitMapInfoHeader)+sizeof(Color Table)+DataSizePerLine* biHeight;

3.颜色表

介绍颜色表前,先介绍一个表示当前像素的结构体:

struct RGBQuad

{

unsigned char rgbBlue;//蓝色的亮度(值范围0~255)

unsigned char rgbGreen;//绿色的亮度(值范围0~255)

unsigned char rgbRed;//红色的亮度(值范围0~255)

unsigned char rgbReserved;//保留

};

备注:

这里的定义是bgr,不是rgb,跟rgb正好相反。

颜色表就是一个该结构体的数组,数组大小为2^biBitCount,因此颜色表总长度为2^biBitCount*4个字节。

具体的对不同位数的bmp:

biBitCount颜色表项数说明12像素值为0时,使用第一项颜色,为1时使用第二项颜色416若点阵位图数据中某个字节为OX1F,则该字节代表2个象素。第一个象素用第2项颜色,第二个象素用第16项8256点阵位图中每一个字节表示一个象素。240无颜色表。位图数据中三个字节表示一个象素的红、绿、蓝值

 

4.位图数据

这里的文件位置也可以通过BitMapFileHeader直接seek过来。

位图数据记录了位图的每一个像素值,记录顺序是在扫描行内是从左到右,扫描行之间是从下到上。值得一提的是,每一行像素所占的字节数必须是4的整倍数,如果实际像素所占字节数不足4的倍数,则需要补齐,下一行像素值也是从4的倍数字节处后开始存放。

位图的一个像素值所占的字节数: 
  当biBitCount=1时,8个像素占1个字节;
  当biBitCount=4时,2个像素占1个字节;
  当biBitCount=8时,1个像素占1个字节;
  当biBitCount=24时,1个像素占3个字节;

如果有颜色表,位图数据内为索引值,根据该索引值在颜色表内查找对应的像素。

如果没有颜色表,位图数据存储的就是像素值。

biBitCount=1 表示位图最多有两种颜色,黑色和白色。图像数据中的每一位(0或1)表示一个像素(黑色或白色)。

biBitCount=4 表示位图最多有16种颜色。每个像素用4位表示,并用这4位作为颜色表的表项来查找该像素的颜色。例如,如果位图中的第一个字节的十六进制数为1F,它表示两个像素,第一像素的颜色就在颜色表的第2表项中查找,第二个像素的颜色在颜色表的第16表项中查找。

biBitCount=8 表示位图最多有256种颜色。每个像素用8位表示,并用这8位作为颜色表的表项来查找该像素的颜色。例如,如果位图中的第一个字节的十六进制数为1F,这个像素的颜色就在颜色表的第32表项中查找。

biBitCount=24 表示位图最多有224=16 777 216种颜色。颜色表为空。每3个字节代表一个像素,每个字节分别表示R、G、B三分量的值。

biBitCount如果写颜色表的话大小为2^24*4=64M,所以不再使用颜色表。。。

 

说了这么多,我们看个例子,利用windows的画图软件,分别存为提到的4种bmp为1.bmp,2.bmp,3.bmp,4.bmp。

读取其中的必要信息,代码如下:

结构体定义部分:

Code Snippet
  1. /*
  2. * =====================================================================================
  3. *       Filename:  Defs.h
  4. *    Description:  defines the structure in bmp
  5. *        Version:  1.0
  6. *        Created:  2013-3-8 22:53:32
  7. *       Compiler:  gcc
  8. *         Author:  y, izualzhy@163.com
  9. * =====================================================================================
  10. */
  11. #pragma pack(2)
  12. //位图文件头
  13. struct BitMapFileHeader
  14. {
  15.     unsigned short bfType;//位图文件类型,必须BM,(16进制0x4d42)
  16.     unsigned int bfSize;//文件大小,以字节为单位
  17.     unsigned short bfReserved1;//保留字,必须为0
  18.     unsigned short bfReserved2;//保留字,必须为0
  19.     unsigned int bfOffBits;//位图数据的起始位置,也就是数据区的起始位置,单位为字节
  20. };
  21. //位图信息头
  22. struct BitMapInfoHeader
  23. {
  24.     unsigned int biSize;//位图信息头的长度,一般为40
  25.     unsigned int biWidth;//位图的宽度
  26.     unsigned int biHeight;//位图的高度
  27.     unsigned short biPlanes;//位图的位面数=1
  28.     unsigned short biBitCount;//每个像素所占的位数,
  29.     //必须为1(双色),4(16色),8(256色),24(真彩色),32(32真彩色)之一
  30.     unsigned int biCompression;//位图压缩类型
  31.     //必须为0(不压缩),1(BI_RLE8压缩类型),2(BI_RLE4压缩类型)之一
  32.     unsigned int biSizeImage;//位图的大小,以字节为单位,必须是4的倍数
  33.     unsigned int biXPelsPerMeter;//位图水平分辨率,像素/米
  34.     unsigned int biYPelsPerMeter;//位图垂直分辨率,像素/米
  35.     unsigned int biClrUsed;//位图实际使用的颜色数
  36.     unsigned int biClrImportant;//指定重要的颜色数
  37. };
  38.  
  39. struct RGBQuad
  40. {
  41.     unsigned char rgbBlue;//蓝色的亮度值
  42.     unsigned char rgbGreen;//绿色的亮度值
  43.     unsigned char rgbRed;//红色的亮度值
  44.     unsigned char rgbReserved;//保留
  45. };
  46. #pragma pack()

main.cpp:

 

Code Snippet
  1. #include <stdio.h>
  2. #include "Defs.h"
  3.  
  4. int main(int argc, char* argv[])
  5. {
  6.     if (argc < 2)
  7.     {
  8.         return -1;
  9.     }
  10.     FILE* fp = fopen(argv[1], "r");
  11.     if (!fp)
  12.     {
  13.         printf("fopen error!\n");
  14.         return -1;
  15.     }
  16.  
  17.     fseek(fp, 0, SEEK_END);
  18.     unsigned int fileSize = ftell(fp);
  19.     printf("seek fileSize: %d\n", fileSize);
  20.     fseek(fp, 0, SEEK_SET);
  21.  
  22.     printf("==============Read BitMapFileHeader=========\n");
  23.     BitMapFileHeader bmfHeader;
  24.     fread(&bmfHeader, sizeof(bmfHeader), 1, fp);
  25.     char type[3] = {0};
  26.     type[0] = (bmfHeader.bfType & 0xff);
  27.     type[1] = (bmfHeader.bfType & 0xff00) >> 8;
  28.     printf("filetype: %s\n", type);//文件类型
  29.     printf("fileSize: %d\n", bmfHeader.bfSize);//文件大小,与实际文件大小一致
  30.     printf("bitmapDataOffset: %d\n", bmfHeader.bfOffBits);//位图数据开始位置
  31.  
  32.     printf("==============Read BitMapInfoHeader=========\n");
  33.     BitMapInfoHeader bmiHeader;
  34.     fread(&bmiHeader, sizeof(bmiHeader), 1, fp);
  35.     printf("sizeof BitMapInfoHeader: %d, %d\n", sizeof(BitMapInfoHeader), bmiHeader.biSize);//位图文件信息头结构体大小
  36.     printf("width: %d, height: %d\n", bmiHeader.biWidth, bmiHeader.biHeight);//位图宽高
  37.     printf("bit per perls: %d\n", bmiHeader.biBitCount);//每个像素所占的位数
  38.     int dataSizePerLine = (bmiHeader.biWidth * bmiHeader.biBitCount + 31)/8;
  39.     dataSizePerLine = dataSizePerLine/4*4;
  40.     const int imageSize = bmiHeader.biHeight * dataSizePerLine;
  41.     printf("ImageSize: %d, %d\n", bmiHeader.biSizeImage, imageSize);//图像的大小,4的倍数
  42.  
  43.     const int colorTableOffset = ftell(fp);//颜色表开始的位置
  44.     printf("colorTableOffset: %d, bitmapDataOffset: %d, colorTableCount: %d\n"
  45.             , colorTableOffset, bmfHeader.bfOffBits, (bmfHeader.bfOffBits - colorTableOffset)/sizeof(RGBQuad));
  46.     fclose(fp);
  47.     return 0;
  48. }

输出为:

y@y-VirtualBox:/mnt/mydocuments/Training/Git/Training/bmp$ ./a.out 1.bmp
seek fileSize: 2862
==============Read BitMapFileHeader=========
filetype: BM
fileSize: 2862
bitmapDataOffset: 62
==============Read BitMapInfoHeader=========
sizeof BitMapInfoHeader: 40, 40
width: 200, height: 100
bit per perls: 1
ImageSize: 2800, 2800
colorTableOffset: 54, bitmapDataOffset: 62, colorTableCount: 2
y@y-VirtualBox:/mnt/mydocuments/Training/Git/Training/bmp$ ./a.out 2.bmp
seek fileSize: 10118
==============Read BitMapFileHeader=========
filetype: BM
fileSize: 10118
bitmapDataOffset: 118
==============Read BitMapInfoHeader=========
sizeof BitMapInfoHeader: 40, 40
width: 200, height: 100
bit per perls: 4
ImageSize: 10000, 10000
colorTableOffset: 54, bitmapDataOffset: 118, colorTableCount: 16
y@y-VirtualBox:/mnt/mydocuments/Training/Git/Training/bmp$ ./a.out 3.bmp
seek fileSize: 21078
==============Read BitMapFileHeader=========
filetype: BM
fileSize: 21078
bitmapDataOffset: 1078
==============Read BitMapInfoHeader=========
sizeof BitMapInfoHeader: 40, 40
width: 200, height: 100
bit per perls: 8
ImageSize: 20000, 20000
colorTableOffset: 54, bitmapDataOffset: 1078, colorTableCount: 256
y@y-VirtualBox:/mnt/mydocuments/Training/Git/Training/bmp$ ./a.out 4.bmp
seek fileSize: 60054
==============Read BitMapFileHeader=========
filetype: BM
fileSize: 60054
bitmapDataOffset: 54
==============Read BitMapInfoHeader=========
sizeof BitMapInfoHeader: 40, 40
width: 200, height: 100
bit per perls: 24
ImageSize: 60000, 60000
colorTableOffset: 54, bitmapDataOffset: 54, colorTableCount: 0

结果分析:

以3.bmp的输出结果为例:

1.文件大小通过计算可以得出与ftell相同

2.位图数据开始bytes=1078=14+40+4*256+200*100。每个数字的含义对应我们的理论部分。

 

参考资料:

http://www.metsky.com/archives/198.html

http://www.cppblog.com/magicqy/archive/2009/02/16/73975.html

http://www.cnblogs.com/scope/archive/2009/06/19/1507003.html

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 中国驾照在美国丢了怎么办 拿了驾照不敢开车怎么办 刚拿驾照不敢上路怎么办 雅思考试作文格式写错了怎么办 英国银行卡注销后钱怎么办 本科毕业有毕业证没有学位证怎么办 莫名收到平安一账通验证码怎么办 新车没带行驶证怎么办 深圳行驶证副本丢了怎么办 新车行驶证是怎么办的 新车怎么办牌和行驶证 b本扣12分了怎么办 车的绿本丢了怎么办 车辆落户查不到购车发票怎么办 扣车凭证丢了怎么办 三轮车驾驶证被扣了怎么办 违章12分不够扣怎么办 忘记带行驶证了怎么办 开车不带行驶证怎么办 屏幕没碎黑屏了怎么办 三星s6屏幕不亮怎么办 苹果手机掉水里屏幕黑屏怎么办 三星s6电池不耐用怎么办 台式电脑显示屏坏了怎么办 三星笔记本电脑不显示韩文怎么办 三星s6开不开机怎么办 电脑显示屏显示检测信号线怎么办 三星s8屏幕坏了怎么办 手机挤压漏液了怎么办 三星显示器跳白色线条怎么办动 三星s6屏幕漏液怎么办 三星电视曲面屏碎了怎么办 平板摔了花屏怎么办 新手机开不了机怎么办 三星a9屏幕漏液怎么办 小米note后面玻璃碎了怎么办 换手机微信钱包怎么办 内外屏一体手机屏幕碎了怎么办 苹果手机显示屏坏了怎么办 华为手机屏裂了怎么办 乐视手机屏坏了怎么办