用C语言进行BMP文件的读写
2019-07-13 21:06发布
生成海报
bmp是BitMap(位图)的简称,也是所有windows上图片显示的基础。所有的图片格式,都必须转换成bmp才能进行最终的显示。所以,bmp文件的读写,就变得非常重要了。然而,很多人是借助于MFC类,C# 库函数,OpenCV,OpenGL等库函数进行bmp文件的读写。试想一下,如果你要在诸如DSP、FPGA之类的嵌入式设备上进行bmp文件的读写,总不能去安装一个庞大的MFC,C#类库吧?其实,我们完全可以抛开这些庞杂繁琐的类库和API函数,仅仅利用C语言,编写几个函数,就完全可以实现bmp文件的读写了。本文的意图正在于此。
一个完整的bmp位图文件,可以分为文件信息头,位图信息头和RGB颜 {MOD}阵列三个部分(希望对这三部分有详细了解的可以参考我的另外一篇文章:http://blog.csdn.net/carson2005/article/details/6227047)。文件信息头主要包含“是否是BMP文件”,文件的大小等信息。而位图信息头则主要包含bmp文件的位图宽度,高度,位平面,通道数等信息。而RGB颜 {MOD}阵列,里面才真正包含我们所需要的bmp位图的像素数据。需要提醒的是,bmp位图的颜 {MOD}阵列部分,像素数据的存储是以左下角为原点。也就是说,当你打开一个bmp图片并显示在电脑屏幕上的时,实际在存储的时候,这个图片的最左下角的像素是首先被存储在bmp文件中的。之后,按照从左到右,从下到上的顺序,依次进行像素数据的存储。如果,你存储的是3通道的位图数据(也就是我们通常说的彩图),那么它是按照B0G0R0B1G1R1B2G2R2...的顺序进行存储的,同时,还要考虑到4字节对齐的问题。OK,了解了这些基本概念,相信,自己编程实现一些bmp文件的读写函数并非难事。这里,我给出C语言的版本,仅供参考,如有错误,欢迎指正。
chenLeeCV.h
#ifndef CHENLEECV_H
#define CHENLEECV_H
typedef struct
{
//unsigned short bfType;
unsigned long bfSize;
unsigned short bfReserved1;
unsigned short bfReserved2;
unsigned long bfOffBits;
} ClBitMapFileHeader;
typedef struct
{
unsigned long biSize;
long biWidth;
long biHeight;
unsigned short biPlanes;
unsigned short biBitCount;
unsigned long biCompression;
unsigned long biSizeImage;
long biXPelsPerMeter;
long biYPelsPerMeter;
unsigned long biClrUsed;
unsigned long biClrImportant;
} ClBitMapInfoHeader;
typedef struct
{
unsigned char rgbBlue; //该颜 {MOD}的蓝 {MOD}分量
unsigned char rgbGreen; //该颜 {MOD}的绿 {MOD}分量
unsigned char rgbRed; //该颜 {MOD}的红 {MOD}分量
unsigned char rgbReserved; //保留值
} ClRgbQuad;
typedef struct
{
int width;
int height;
int channels;
unsigned char* imageData;
}ClImage;
ClImage* clLoadImage(char* path);
bool clSaveImage(char* path, ClImage* bmpImg);
#endif
chenLeeCV.cpp
#include "chenLeeCV.h"
#include
#include
ClImage* clLoadImage(char* path)
{
ClImage* bmpImg;
FILE* pFile;
unsigned short fileType;
ClBitMapFileHeader bmpFileHeader;
ClBitMapInfoHeader bmpInfoHeader;
int channels = 1;
int width = 0;
int height = 0;
int step = 0;
int offset = 0;
unsigned char pixVal;
ClRgbQuad* quad;
int i, j, k;
bmpImg = (ClImage*)malloc(sizeof(ClImage));
pFile = fopen(path, "rb");
if (!pFile)
{
free(bmpImg);
return NULL;
}
fread(&fileType, sizeof(unsigned short), 1, pFile);
if (fileType == 0x4D42)
{
//printf("bmp file!
");
fread(&bmpFileHeader, sizeof(ClBitMapFileHeader), 1, pFile);
/*printf("\\\\\\\\\\\\\\\\\\\\\\\n");
printf("bmp文件头信息:
");
printf("文件大小:%d
", bmpFileHeader.bfSize);
printf("保留字:%d
", bmpFileHeader.bfReserved1);
printf("保留字:%d
", bmpFileHeader.bfReserved2);
printf("位图数据偏移字节数:%d
", bmpFileHeader.bfOffBits);*/
fread(&bmpInfoHeader, sizeof(ClBitMapInfoHeader), 1, pFile);
/*printf("\\\\\\\\\\\\\\\\\\\\\\\n");
printf("bmp文件信息头
");
printf("结构体长度:%d
", bmpInfoHeader.biSize);
printf("位图宽度:%d
", bmpInfoHeader.biWidth);
printf("位图高度:%d
", bmpInfoHeader.biHeight);
printf("位图平面数:%d
", bmpInfoHeader.biPlanes);
printf("颜 {MOD}位数:%d
", bmpInfoHeader.biBitCount);
printf("压缩方式:%d
", bmpInfoHeader.biCompression);
printf("实际位图数据占用的字节数:%d
", bmpInfoHeader.biSizeImage);
printf("X方向分辨率:%d
", bmpInfoHeader.biXPelsPerMeter);
printf("Y方向分辨率:%d
", bmpInfoHeader.biYPelsPerMeter);
printf("使用的颜 {MOD}数:%d
", bmpInfoHeader.biClrUsed);
printf("重要颜 {MOD}数:%d
", bmpInfoHeader.biClrImportant);
printf("\\\\\\\\\\\\\\\\\\\\\\\\n");*/
if (bmpInfoHeader.biBitCount == 8)
{
//printf("该文件有调 {MOD}板,即该位图为非真彩 {MOD}
");
channels = 1;
width = bmpInfoHeader.biWidth;
height = bmpInfoHeader.biHeight;
offset = (channels*width)%4;
if (offset != 0)
{
offset = 4 - offset;
}
//bmpImg->mat = kzCreateMat(height, width, 1, 0);
bmpImg->width = width;
bmpImg->height = height;
bmpImg->channels = 1;
bmpImg->imageData = (unsigned char*)malloc(sizeof(unsigned char)*width*height);
step = channels*width;
quad = (ClRgbQuad*)malloc(sizeof(ClRgbQuad)*256);
fread(quad, sizeof(ClRgbQuad), 256, pFile);
free(quad);
for (i=0; iimageData[(height-1-i)*step+j] = pixVal;
}
if (offset != 0)
{
for (j=0; jwidth = width;
bmpImg->height = height;
bmpImg->channels = 3;
bmpImg->imageData = (unsigned char*)malloc(sizeof(unsigned char)*width*3*height);
step = channels*width;
offset = (channels*width)%4;
if (offset != 0)
{
offset = 4 - offset;
}
for (i=0; iimageData[(height-1-i)*step+j*3+k] = pixVal;
}
//kzSetMat(bmpImg->mat, height-1-i, j, kzScalar(pixVal[0], pixVal[1], pixVal[2]));
}
if (offset != 0)
{
for (j=0; j