BMP文件格式
Posted 独饮月色的猫
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BMP文件格式相关的知识,希望对你有一定的参考价值。
介绍:在生活中我们经常会用到各种格式的图片文件,当中bmp文件算是最为基础的,其全称为bitmap image file(位图文件),别名device independent bitmap file(设备无关位图文件),后缀为.bmp,.dib。设备无关的意思为bmp文件的显示不依赖于操作系统、平台。bmp的文件格式使得它能够存储任意宽高、任意分辨率的二维数字化图片,不管是黑白的,有多种颜色的,还是色深不同的,亦或是选择了数据压缩、alpha通道,color profiles(颜色配置文件),都能实现需求。
BMP文件结构:
这里忽略以前使用的.dib格式,只关注.bmp。
以win32 GDI为例:可分为FileHeader, InfoHeader, PixelArray(代指图像数据),ColorTable四部分。
1.
typedef struct tagBITMAPFILEHEADER
WORD bfType;
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
BITMAPFILEHEADER, FAR *LPBITMAPFILEHEADER, *PBITMAPFILEHEADER;
FileHeader:
bfType--声明文件类型为bmp, 具体数值为字符“BM”, ASCII码为0x4D42(十进制为19778)
bfSize--文件大小(单位:字节),非文件实际占用空间大小
bfReserved1、bfReserved2--保留区,默认为0
bfOffBits--文件头开始到图像数据之间的偏移字节量
2.
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, FAR *LPBITMAPINFOHEADER, *PBITMAPINFOHEADER;
InfoHeader:
biSize--相当于sizeof(BITMAPINFOHEADER)
biWidth、biHeight--图像宽高(单位:像素)
biPlanes--位面数,总是为1
biBitCount--即像素位深(bpp, bits per pixel),常用24位(R8G8B8)与32位(R8G8B8,最高位保留)
biCompression--压缩类型,常为BI_RGB(数值为0L)
biSizeImage--图像大小(单位:字节),当压缩类型为BI_RGB时,取0
biXPelsPerMeter--水平分辨率(单位:像素/米)
biYPelsPerMeter--垂直分辨率(单位:像素/米)
biClrUsed--实际所用ColorTable的颜色索引数(0代表使用全部)
biClrImportant--对图像显示有重要影响的颜色索引数(0代表都重要)
3.
typedef struct tagRGBQUAD
BYTE rgbBlue;
BYTE rgbGreen;
BYTE rgbRed;
BYTE rgbReserved;
RGBQUAD;
RGBQUAD即组成调色板的元素,占4字节(红绿蓝各占1字节,剩下的保留)
调色板就相当于一个RGBQUAD数组,大小为2^biBitCount,举
个例子,黑白照片biBitCount为2,调色板RGBQUAD[2]只含黑(RGBQUAD(0,0,0))、
白(RGBQUAD(255,255,255))两种颜色,biClrUsed为2,颜色索引从0-1。
不过要注意,如biBitCount为16、24、32的位图在biCompression为BI_RGB时没有调色板。
这就使得BITMAPFILEHEADER的bfOffBits属性有用起来了,其可以让我们在不知道
bmp文件具体内存信息时直接找到像素数据(PixelArray)进行数据处理。
4.注意点
BMP文件记录高1像素的一整行像素时采取的单位是字节,根据biBitCount的不同每个像素点可得到的颜色范围是变化的(颜色索引数是变化的),所以我们规定每行像素的字节数与4字节对齐。
比如这一行有242个像素且bpp为1,那么计算得到每行字节数为242*1,由于补齐规则最后结果是244字节。
最后PixelArray = 244*biHeight;
如果你和我一样在了解了BMP文件格式后,去尝试相加BITMAPFILEHEADER、
BITMAPINFOHEADER、调色板、PixelArray计算过BMP文件大小,那么一般来说你得到的结果
与右键文件属性里得到的大小不一样。
这里我举一张8位的BMP(biBitCount == 8)图片为例,
用代码取得这些头信息:
其宽242px,高212px,bpp=8
sizeof(BITMAPFILEHEADER) = 14;
sizeof(BITMAPINFOHEADER) = 40;
每行字节数为242*1,补齐得到244字节/行,乘以高212,
sizeof(PixelArray) = 51728;
调色板RGBQUAD[2^8],但实际上我用的这张图片只用到了32种颜色(BiClrUsed = 32)
sizeof(ColorTable) = 32*sizeof(RGBQUAD); // 128
40+14+128+51728 = 51910 文件大小正确。
或者将图片后缀改为.dat, 用文本编辑器打开查看字节码,开头0x424d表明bmp文件:
观察字节码可以发现PixelArray部分的单字节数值都在0-31(0x1f)之间,刚好证明8位的bmp是由调色板中的索引值来得到每位像素点颜色的。
如果要读出8位bmp文件每个像素的RGB值,那么需要根据读出的索引值去映射ColorTable来得到。
为了验证这些推论,我将PixelArray的所有字节数事先读取出来,通过ColorTable将PixelArray的每个字节映射得到对应的RGB值, 再当作输入数据输入到一个可指定逐一像素颜色来生成24位位图的程序中生成图片,比对两幅图片即可。
5.实验相关代码:
链接:http://pan.baidu.com/s/1pLpjUjT
// 之前传到csdn上被删了= =,由于是个小实验。。没什么后续,就不传github了,网盘见吧2333
示意图:
以上是关于BMP文件格式的主要内容,如果未能解决你的问题,请参考以下文章