BMP文件的读取与写入

来源:互联网 发布:服装cad软件排名 编辑:程序博客网 时间:2024/04/28 13:04

注:BMP文件格式在这里只做简单介绍,详细介绍可以参看我整理的这个文档<a target=_blank href="http://download.csdn.net/detail/zhangyi19930704/9262043">点击打开链接</a>

1、BMP文件格式

BMP文件主要包含四个部分:位图文件头,位图信息头,位图调色板,位图数据。

用结构体表示就是:

<span style="background-color: rgb(255, 255, 255);"><span style="font-size:18px;"></span></span><pre name="code" class="cpp"><pre name="code" class="cpp"><span style="color:#3366ff;"><span style="white-space:pre"></span>typedef struct tagBITMAP_FILE{      <span style="white-space:pre"></span>BMPHeader bitmapheader;      <span style="white-space:pre"></span>BMPInfoHeader bitmapinfoheader;      <span style="white-space:pre"></span>PALETTEENTRY palette[256];      <span style="white-space:pre"></span>UCHAR *buffer;   <span style="white-space:pre"></span>} BITMAP_FILE;</span>

其中位图文件头结构体为:

<span style="font-size:18px;color:#3366ff;"><span style="white-space:pre"></span>typedef struct{<span style="white-space:pre"></span>short type;<span style="white-space:pre"></span>int size;<span style="white-space:pre"></span>short reserved1;<span style="white-space:pre"></span>short reserved2;<span style="white-space:pre"></span>int offset;<span style="white-space:pre"></span>} BMPHeader;//该结构体总共2+4+2+2+4=14字节</span>
位图信息头结构体为:

<span style="font-size:18px;color:#3366ff;"><span style="white-space:pre"></span>typedef struct<span style="white-space:pre"></span>{<span style="white-space:pre"></span>int size;<span style="white-space:pre"></span>int width;<span style="white-space:pre"></span>int height;<span style="white-space:pre"></span>short planes;<span style="white-space:pre"></span>short bitsPerPixel;<span style="white-space:pre"></span>unsigned compression;<span style="white-space:pre"></span>unsigned imageSize;<span style="white-space:pre"></span>int xPelsPerMeter;<span style="white-space:pre"></span>int yPelsPerMeter;<span style="white-space:pre"></span>int clrUsed;<span style="white-space:pre"></span>int clrImportant;<span style="white-space:pre"></span>} BMPInfoHeader;</span>
位图调色板结构体为(24位、32为真彩色图像没有调色板,详细介绍可以查看本文开始时的链接文档,内有测试):

<span style="font-size:18px;color:#3366ff;"><span style="white-space:pre"></span>typedef struct tagPALETTEENTRY {    <span style="white-space:pre"></span>BYTE peBlue;    <span style="white-space:pre"></span>BYTE peGreen;     <span style="white-space:pre"></span>BYTE peRed;     <span style="white-space:pre"></span>BYTE peFlags; <span style="white-space:pre"></span>} PALETTEENTRY; </span>
位图数据自己定义为char类型字符数组即可。

<span style="font-size:18px;color:#3366ff;"><span style="white-space:pre"></span>char* imagedata = (char* ) malloc (sizeof(char) * width * height)</span>

注:由于结构体内部存在字节对其原则,在代码实现阶段,声明结构体时前面加上#pragma pack(1),表示该申明之后的结构体以1字节对齐

2、读入图像文件

<img src="http://img.blog.csdn.net/20151112134014958" alt="" />

初始定义变量:(此处以8位灰度BMP图像为例,包含调色板信息,24为真彩色图像没有调色板信息)

<span style="white-space:pre"></span><span style="color:#3366ff;">int width;int height;int size;int offset;int paletsize;BMPHeader hdr;BMPInfoHeader infoHdr;PALETTEENTRY * Palet = NULL;unsigned char * imagedata = NULL;</span>


首先使用fopen以可读二进制方式打开该BMP图像文件(打开成功与否,读取成功与否等异常情况在这里不做赘述):

<span style="white-space:pre"></span><span style="color:#3366ff;">FILE *fp = fopen("test.bmp", "rb");</span>
读取文件头信息:
<span style="font-size:18px;"><span style="white-space:pre"></span><span style="color:#3366ff;">fread(&hdr, sizeof(hdr), 1, fp);</span></span>
读取信息头信息:

<span style="white-space:pre"></span><span style="color:#3366ff;">fread(&infoHdr, sizeof(infoHdr), 1, fp);</span>
接下来可以获取文件头和信息头内部信息

<span style="white-space:pre"></span><pre name="code" class="html"><span style="white-space:pre"></span><span style="color:#3366ff;">paletsize = infoHdr.clrUsed;width = infoHdr.width;height = infoHdr.height;<span style="white-space:pre"></span>offset = hdr.offset;</span>

为调色板申请空间,并读入该图像的调色板信息到申请的空间中

<span style="white-space:pre"></span><span style="color:#3366ff;">Palet = (PALETTEENTRY *)malloc(sizeof(PALETTEENTRY) * paletsize);fread(Palet, sizeof(PALETTEENTRY), paletsize, fp);</span>
申请图像数据空间,并将图像数据读入申请的字符数组中,注意对齐操作,由于Windows在进行行扫描的时候最小的单位为4个字节,所以当图片宽 每个像素的字节数 != 4的整数倍时要在每行的后面补上缺少的字节,以0填充,当做补充字节。详细内容可以查看之前文档

<span style="color:#3366ff;">imagedata = (unsigned char *)malloc(sizeof(char) * width*height);int skip = 4-(width%4)%4;if (4 == skip)skip = 0;for (int i = 0; i < height; i++){for (int j = 0; j < width; j++){imagedata[i*width + j] = fgetc(fp);}for (int j = 0; j < skip; j++)fgetc(fp);}</span>
至此,test.bmp的图像就读入到imagedata数组中了。至于文件头、信息头和调色板信息就读入到hdr,infoHdr,Palet中了。

3、图像数据处理

如果要用GPU做图像处理,最好将imagedata数据变换为浮点类型数据,因为GPU非常适合处理浮点运算。

直接对imagedata数据进行操作,加减乘除等等,可以用于做图像去噪、增强、去雾等。


4、写入图像数据

与读入图像数据类似,写图像的顺序和读图像相同。

打开要写入的图像:

<span style="white-space:pre"></span><span style="color:#3366ff;">FILE* fpOut = fopen("out.bmp", "wb");</span>

首先定位到文件开头:

<span style="white-space:pre"></span><span style="color:#3366ff;">fseek(fpOut, 0, SEEK_SET);</span>
读入文件头:

<span style="color:#3366ff;">fwrite(&hdr, sizeof(hdr), 1, fpOut)</span>;
读入信息头:

<span style="color:#3366ff;">fwrite(&infoHdr, sizeof(infoHdr), 1, fpOut);</span>
读入调色板信息:

<span style="white-space:pre"></span><span style="color:#3366ff;">fwrite(Palet, sizeof(PALETTEENTRY), paletsize, fpOut);</span>
读入实际数据:

<span style="white-space:pre"></span><span style="color:#3366ff;">for (int i = 0; i < height; i++){for (int j = 0; j < width; j++){fputc(imagedata[i*width + j], fpOut);}for (int j = 0; j < skip; j++)fputc(0, fpOut);}</span>
注意关闭文件指针!

至此,BMP文件的读取和写入完成了。
















0 0