转自:
用C语言进行BMP文件的读写
bmp是BitMap(位图)的简称,也是所有windows上图片显示的基础。所有的图片格式,都必须转换成bmp才能进行最终的显示。所以,bmp文件的读写,就变得非常重要了。然而,很多人是借助于MFC类,C# 库函数,OpenCV,OpenGL等库函数进行bmp文件的读写。试想一下,如果你要在诸如DSP、FPGA之类的嵌入式设备上进行bmp文件的读写,总不能去安装一个庞大的MFC,C#类库吧?其实,我们完全可以抛开这些庞杂繁琐的类库和API函数,仅仅利用C语言,编写几个函数,就完全可以实现bmp文件的读写了。本文的意图正在于此。
一个完整的bmp位图文件,可以分为文件信息头,位图信息头和RGB颜 {MOD}阵列三个部分。文件信息头主要包含“是否是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 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;
- unsigned char rgbGreen;
- unsigned char rgbRed;
- 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)
- {
-
-
- fread(&bmpFileHeader, sizeof(ClBitMapFileHeader), 1, pFile);
-
-
-
-
-
-
-
- fread(&bmpInfoHeader, sizeof(ClBitMapInfoHeader), 1, pFile);
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- if (bmpInfoHeader.biBitCount == 8)
- {
-
- channels = 1;
- width = bmpInfoHeader.biWidth;
- height = bmpInfoHeader.biHeight;
- offset = (channels*width)%4;
- if (offset != 0)
- {
- offset = 4 - offset;
- }
-
- 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; i
- {
- for (j=0; j
- {
- fread(&pixVal, sizeof(unsigned char), 1, pFile);
- bmpImg->imageData[(height-1-i)*step+j] = pixVal;
- }
- if (offset != 0)
- {
- for (j=0; j
- {
- fread(&pixVal, sizeof(unsigned char), 1, pFile);
- }
- }
- }
- }
- else if (bmpInfoHeader.biBitCount == 24)
- {
-
- channels = 3;
- width = bmpInfoHeader.biWidth;
- height = bmpInfoHeader.biHeight;
-
- bmpImg->width = 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; i
- {
- for (j=0; j
- {
- for (k=0; k<3; k++)
- {
- fread(&pixVal, sizeof(unsigned char), 1, pFile);
- bmpImg->imageData[(height-1-i)*step+j*3+k] = pixVal;
- }
-
- }
- if (offset != 0)
- {
- for (j=0; j
- {
- fread(&pixVal, sizeof(unsigned char), 1, pFile);
- }
- }
- }
- }
- }
-
- return bmpImg;
- }
-
- bool clSaveImage(char* path, ClImage* bmpImg)
- {
- FILE *pFile;
- unsigned short fileType;
- ClBitMapFileHeader bmpFileHeader;
- ClBitMapInfoHeader bmpInfoHeader;
- int step;
- int offset;
- unsigned char pixVal = '