用C语言进行BMP文件的读写

bmp是BitMap(位图)的简称,也是所有windows上图片显示的基础。所有的图片格式,都必须转换成bmp才能进行最终的显示。所以,bmp文件的读写,就变得非常重要了。然而,很多人是借助于MFC类,C# 库函数,OpenCV,OpenGL等库函数进行bmp文件的读写。试想一下,如果你要在诸如DSP、FPGA之类的嵌入式设备上进行bmp文件的读写,总不能去安装一个庞大的MFC,C#类库吧?其实,我们完全可以抛开这些庞杂繁琐的类库和API函数,仅仅利用C语言,编写几个函数,就完全可以实现bmp文件的读写了。本文的意图正在于此。

一个完整的bmp位图文件,可以分为文件信息头,位图信息头和RGB颜色阵列三个部分。文件信息头主要包含“是否是BMP文件”,文件的大小等信息。而位图信息头则主要包含bmp文件的位图宽度,高度,位平面,通道数等信息。而RGB颜色阵列,里面才真正包含我们所需要的bmp位图的像素数据。需要提醒的是,bmp位图的颜色阵列部分,像素数据的存储是以左下角为原点。也就是说,当你打开一个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; //该颜色的蓝色分量        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 <stdio.h>    #include <stdlib.h>       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! \n");               fread(&bmpFileHeader, sizeof(ClBitMapFileHeader), 1, pFile);           /*printf("\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n");          printf("bmp文件头信息:\n");          printf("文件大小:%d \n", bmpFileHeader.bfSize);          printf("保留字:%d \n", bmpFileHeader.bfReserved1);          printf("保留字:%d \n", bmpFileHeader.bfReserved2);          printf("位图数据偏移字节数:%d \n", bmpFileHeader.bfOffBits);*/              fread(&bmpInfoHeader, sizeof(ClBitMapInfoHeader), 1, pFile);           /*printf("\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n");          printf("bmp文件信息头\n");          printf("结构体长度:%d \n", bmpInfoHeader.biSize);          printf("位图宽度:%d \n", bmpInfoHeader.biWidth);          printf("位图高度:%d \n", bmpInfoHeader.biHeight);          printf("位图平面数:%d \n", bmpInfoHeader.biPlanes);          printf("颜色位数:%d \n", bmpInfoHeader.biBitCount);          printf("压缩方式:%d \n", bmpInfoHeader.biCompression);          printf("实际位图数据占用的字节数:%d \n", bmpInfoHeader.biSizeImage);          printf("X方向分辨率:%d \n", bmpInfoHeader.biXPelsPerMeter);          printf("Y方向分辨率:%d \n", bmpInfoHeader.biYPelsPerMeter);          printf("使用的颜色数:%d \n", bmpInfoHeader.biClrUsed);          printf("重要颜色数:%d \n", bmpInfoHeader.biClrImportant);          printf("\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n");*/              if (bmpInfoHeader.biBitCount == 8)           {               //printf("该文件有调色板,即该位图为非真彩色\n\n");                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; i<height; i++)               {                   for (j=0; j<width; j++)                   {                       fread(&pixVal, sizeof(unsigned char), 1, pFile);                       bmpImg->imageData[(height-1-i)*step+j] = pixVal;                   }                   if (offset != 0)                   {                       for (j=0; j<offset; j++)                       {                           fread(&pixVal, sizeof(unsigned char), 1, pFile);                       }                   }               }                      }           else if (bmpInfoHeader.biBitCount == 24)           {               //printf("该位图为位真彩色\n\n");                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<height; i++)               {                   for (j=0; j<width; j++)                   {                       for (k=0; k<3; k++)                       {                           fread(&pixVal, sizeof(unsigned char), 1, pFile);                           bmpImg->imageData[(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<offset; 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 = '\0';       int i, j;       ClRgbQuad* quad;          pFile = fopen(path, "wb");       if (!pFile)       {           return false;       }          fileType = 0x4D42;       fwrite(&fileType, sizeof(unsigned short), 1, pFile);          if (bmpImg->channels == 3)//24位,通道,彩图        {           step = bmpImg->channels*bmpImg->width;           offset = step%4;           if (offset != 4)           {               step += 4-offset;           }              bmpFileHeader.bfSize = bmpImg->height*step + 54;           bmpFileHeader.bfReserved1 = 0;           bmpFileHeader.bfReserved2 = 0;           bmpFileHeader.bfOffBits = 54;           fwrite(&bmpFileHeader, sizeof(ClBitMapFileHeader), 1, pFile);              bmpInfoHeader.biSize = 40;           bmpInfoHeader.biWidth = bmpImg->width;           bmpInfoHeader.biHeight = bmpImg->height;           bmpInfoHeader.biPlanes = 1;           bmpInfoHeader.biBitCount = 24;           bmpInfoHeader.biCompression = 0;           bmpInfoHeader.biSizeImage = bmpImg->height*step;           bmpInfoHeader.biXPelsPerMeter = 0;           bmpInfoHeader.biYPelsPerMeter = 0;           bmpInfoHeader.biClrUsed = 0;           bmpInfoHeader.biClrImportant = 0;           fwrite(&bmpInfoHeader, sizeof(ClBitMapInfoHeader), 1, pFile);              for (i=bmpImg->height-1; i>-1; i--)           {               for (j=0; j<bmpImg->width; j++)               {                   pixVal = bmpImg->imageData[i*bmpImg->width*3+j*3];                   fwrite(&pixVal, sizeof(unsigned char), 1, pFile);                   pixVal = bmpImg->imageData[i*bmpImg->width*3+j*3+1];                   fwrite(&pixVal, sizeof(unsigned char), 1, pFile);                   pixVal = bmpImg->imageData[i*bmpImg->width*3+j*3+2];                   fwrite(&pixVal, sizeof(unsigned char), 1, pFile);               }               if (offset!=0)               {                   for (j=0; j<offset; j++)                   {                       pixVal = 0;                       fwrite(&pixVal, sizeof(unsigned char), 1, pFile);                   }               }           }       }       else if (bmpImg->channels == 1)//8位,单通道,灰度图        {           step = bmpImg->width;           offset = step%4;           if (offset != 4)           {               step += 4-offset;           }              bmpFileHeader.bfSize = 54 + 256*4 + bmpImg->width;           bmpFileHeader.bfReserved1 = 0;           bmpFileHeader.bfReserved2 = 0;           bmpFileHeader.bfOffBits = 54 + 256*4;           fwrite(&bmpFileHeader, sizeof(ClBitMapFileHeader), 1, pFile);              bmpInfoHeader.biSize = 40;           bmpInfoHeader.biWidth = bmpImg->width;           bmpInfoHeader.biHeight = bmpImg->height;           bmpInfoHeader.biPlanes = 1;           bmpInfoHeader.biBitCount = 8;           bmpInfoHeader.biCompression = 0;           bmpInfoHeader.biSizeImage = bmpImg->height*step;           bmpInfoHeader.biXPelsPerMeter = 0;           bmpInfoHeader.biYPelsPerMeter = 0;           bmpInfoHeader.biClrUsed = 256;           bmpInfoHeader.biClrImportant = 256;           fwrite(&bmpInfoHeader, sizeof(ClBitMapInfoHeader), 1, pFile);              quad = (ClRgbQuad*)malloc(sizeof(ClRgbQuad)*256);           for (i=0; i<256; i++)           {               quad[i].rgbBlue = i;               quad[i].rgbGreen = i;               quad[i].rgbRed = i;               quad[i].rgbReserved = 0;           }           fwrite(quad, sizeof(ClRgbQuad), 256, pFile);           free(quad);              for (i=bmpImg->height-1; i>-1; i--)           {               for (j=0; j<bmpImg->width; j++)               {                   pixVal = bmpImg->imageData[i*bmpImg->width+j];                   fwrite(&pixVal, sizeof(unsigned char), 1, pFile);               }               if (offset!=0)               {                   for (j=0; j<offset; j++)                   {                       pixVal = 0;                       fwrite(&pixVal, sizeof(unsigned char), 1, pFile);                   }               }           }       }       fclose(pFile);          return true;   }      Main.cpp   #include "stdafx.h"    #include "chenLeeCV.h"          int _tmain(int argc, _TCHAR* argv[])   {       ClImage* img = clLoadImage("c:/test.bmp");       bool flag = clSaveImage("c:/result.bmp", img);       if(flag)       {           printf("save ok... \n");       }                 while(1);       return 0;   }  

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/ppgdy.html