【寒江雪】BMP位图文件格式分析

来源:互联网 发布:简述算法的复杂度分析 编辑:程序博客网 时间:2024/05/01 00:58

BMP位图文件格式分析

今天实验课主要要做BMP格式的文件解析。参照着学姐(长)的代码,将BMP文件按二进制格
式读到内存中。
所用的图片是一张25*25的全白色图片,由于背景图也为白色,就不上图了
首先对位图做一个解释

BMP文件格式

图片描述
BMP文件格式由文件头,位图信息段,调色板信息(如果有的话),位图数据RGB像素或索引数据组成
由此,可以知道位图文件的代码可以这么表示:

typedef struct tagBITMAP_FILE {    BITMAPFILEHEADER bitmapheader;    BITMAPINFOHEADER bitmapinfoheader;    PALETTEENTRY palette[256];    UCHAR *buffer;   //UCHAR 大小1字节(同BYTE), 在VC6下} BITMAP_FILE;

BMP文件头:BITMAPFILEHEADER bitmapheader

typedef struct tagBITMAPFILEHEADER {    WORD    bfType;     DWORD   bfSize;     WORD    bfReserved1;     WORD    bfReserved2;     DWORD   bfOffBits; } BITMAPFILEHEADER;
  • bfType:表明文件类型,位图文件设置为”BM”,占用一个字的存储空间
  • bfSize:表明文件大小,占用两个字的存储空间
  • bfReserved1:保留字,占用一个字的存储空间
  • bfReserved2:保留字,占用一个字的存储空间
  • bfOffBits:从文件头位置到图像数据位置的偏移量。占用两个字的存储空间

文件头的大小总共7个字,共14字节

以下是我那张25*25纯白色的图的详细信息以及通过程序解析得到的数据
图片描述
图片描述

  • 其中42 4d是文件类型,查阅ASCII表可得到BM
  • 00 00 07 a2表明文件大小为1954字节
  • 00 00 00 00是两个保留字
  • 00 00 00 36是偏移量,大小为54字节(我数了一下,文件头开始偏移54字节,刚好到第一个ff的位置)

位图信息段

typedef struct tagBITMAPINFOHEADER { // bmih     DWORD  biSize;    LONG   biWidth;    LONG   biHeight;    WORD   biPlanes;    WORD   biBitCount;    DWORD  biCompression;    DWORD  biSizeImage;    LONG   biXPelsPerMeter;    LONG   biYPelsPerMeter;    DWORD  biClrUsed;    DWORD  biClrImportant;} BITMAPINFOHEADER;
  • biSize:说明BITMAPINFOHEADER所需要的字节数。占用2个字
  • biWidth:说明图像的宽度。占用2个字
  • biHeight:说明图像的高度。占用2个字
  • biPlanes:表示BMP图像的平面属性。由于显示器只有一个平面,顾恒等于1。占用1个字
  • biBitCount:说明比特数,其值位1/4/8/16/24或32。占用1个字
  • biCompression:说明图像数据压缩的类型。占用2个字
    • BI_RGB:没有压缩
    • BI_RLE8:每个象素8比特的RLE压缩编码,压缩格式由2字节组成(重复像素和颜色索引)
    • BI_RLE4:每个象素4比特的RLE压缩编码,压缩格式由2字节组成
    • BI_BITFIELDS:每个象素的比特由指定的掩码决定。
    • BI_JPEG:JPEG格式
  • biSizeImage:说明图像的大小,以字节为单位。当用BI_RGB格式时,可设置为0。占用2个字
  • biXPelsPerMeter:说明水平分辨率,用像素/米表示。占用2个字
  • biYPelsPerMeter:说明竖直分辨率,用像素/米表示。占用2个字
  • biClrUsed:说明位图实际使用的彩色表中的颜色索引数(设为0的话,则说明使用所有调色板项)。占用2个字
  • biClrImportant:说明对图象显示有重要影响的颜色索引的数目,如果是0,表示都重要。占用2个字

总共使用20个字,共40字节。

到目前为止,文件头和位图信息总共使用了14+40=54字节。因此文件首部到图像数据位置总共偏移了54字节

以下是我那张白色25*25的图片的位图信息
图片描述

  • biSize:00 00 00 28,大小为40,表明位图信息字段占了40字节
  • biWidth:00 00 00 19,大小为25,表明位图宽度为25像素
  • biHeight:00 00 00 19,大小为25,表明位图高度为25像素
  • biPlanes:00 01,大小为1,表明这张图只有一个平面
  • biBitCount:00 18,大小为24,这是24位位图
  • biCompression:00 00 00 00,表示没有压缩
  • biSizeImage:00 00 07 6c,1900字节,表示图像的大小信息,计算方法是25*25*3+25
          每一个像素的颜色信息占3个字节,为了对齐在末尾补了0,多了25字节。
  • biXPlsPerMeter:00 00 00 00
  • biYPlsPerMeter:00 00 00 00
  • biClrUsed:00 00 00 00;为0表明没有使用调色板
  • biClrImportant:00 00 00 00;表明都很重要

图像信息段

接下里要展示最精彩的部分了,那就是位图的颜色信息字段。(虽然我用的25*25的白色位图都是白色,但是不会影响分析质量)
这张图便显示了这张位图的所有颜色信息
图片描述
直接从这里分析确实不好看,我把它们复制出来就好看多了。
图片描述
图片太多,就不一一列举了。
从中我们可以发现,25个 ff ff ff,表示白色。最后添一个0是为了对齐,凑成4的倍数
如果把biWidth设置为4的倍数就不会出现这种问题,不信你看,这是32*25的白色图片
图片描述

为什么需要对齐

  这是由于Windows在进行行扫描的时候最小单位为4个字节
所以当图片宽X每个像素的字节数MOD4!=0时,以0填充。

这张图有没有调色板

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

代码

#include<iostream>#include<string>#include<cstring>#include<fstream>using namespace std;unsigned char binaryData[256*1024];int main() {    string str;    ifstream fin("***\\white.bmp", ios::binary|ios::app);//自己弄自己的文件吧    int length;    int length_sum = 0;    while (getline(fin, str)) {        length = str.length();        memcpy(binaryData+length_sum, str.c_str(), length);        length_sum += length;    }    int count = 0;    for (int i = 0; i < length_sum; i++,count++) {        if (count > 0 && count % 16 == 0)            cout << endl;        cout << hex << (int)(binaryData[i]) << " ";    }    fin.close();    return 0;}


Copyright© by 寒江雪
QQ:211392413
Email:211392413@qq.com
Date:2016-11-23

0 0