`

用c语言进行bmp文件的读写

    博客分类:
  • c++
 
阅读更多

参考:http://cvchina.net/thread-1624-1-1.html



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

       一个完整的bmp位图文件,可以分为文件信息头,位图信息头和RGB颜色阵列三个部分(希望对这三部分有详细了解的可以参考我的另外一篇文章:http://blog.csdn.net/carson2005/article/details/6227047)。文件信息头主要包含“是否是BMP文件”,文件的大小等信息。而位图信息头则主要包含bmp文件的位图宽度,高度,位平面,通道数等信息。而RGB颜色阵列,里面才真正包含我们所需要的bmp位图的像素数据。需要提醒的是,bmp位图的颜色阵列部分,像素数据的存储是以左下角为原点。也就是说,当你打开一个bmp图片并显示在电脑屏幕上的时,实际在存储的时候,这个图片的最左下角的像素是首先被存储在bmp文件中的。之后,按照从左到右,从下到上的顺序,依次进行像素数据的存储。如果,你存储的是3通道的位图数据(也就是我们通常说的彩图),那么它是按照B0G0R0B1G1R1B2G2R2...的顺序进行存储的,同时,还要考虑到4字节对齐的问题。OK,了解了这些基本概念,相信,自己编程实现一些bmp文件的读写函数并非难事。这里,我给出C语言的版本,仅供参考,如有错误,欢迎指正。
  1. chenLeeCV.h  
  2. #ifndef CHENLEECV_H   
  3. #define CHENLEECV_H   
  4.   
  5. typedef struct  
  6. {  
  7.     //unsigned short    bfType;   
  8.     unsigned long    bfSize;  
  9.     unsigned short    bfReserved1;  
  10.     unsigned short    bfReserved2;  
  11.     unsigned long    bfOffBits;  
  12. } ClBitMapFileHeader;  
  13.   
  14. typedef struct  
  15. {  
  16.     unsigned long  biSize;   
  17.     long   biWidth;   
  18.     long   biHeight;   
  19.     unsigned short   biPlanes;   
  20.     unsigned short   biBitCount;  
  21.     unsigned long  biCompression;   
  22.     unsigned long  biSizeImage;   
  23.     long   biXPelsPerMeter;   
  24.     long   biYPelsPerMeter;   
  25.     unsigned long   biClrUsed;   
  26.     unsigned long   biClrImportant;   
  27. } ClBitMapInfoHeader;  
  28.   
  29. typedef struct   
  30. {  
  31.     unsigned char rgbBlue; //该颜色的蓝色分量   
  32.     unsigned char rgbGreen; //该颜色的绿色分量   
  33.     unsigned char rgbRed; //该颜色的红色分量   
  34.     unsigned char rgbReserved; //保留值   
  35. } ClRgbQuad;  
  36.   
  37. typedef struct  
  38. {  
  39.     int width;  
  40.     int height;  
  41.     int channels;  
  42.     unsigned char* imageData;  
  43. }ClImage;  
  44.   
  45. ClImage* clLoadImage(char* path);  
  46. bool clSaveImage(char* path, ClImage* bmpImg);  
  47.   
  48. #endif   
  49.   
  50. chenLeeCV.cpp  
  51. #include "chenLeeCV.h"   
  52. #include <stdio.h>   
  53. #include <stdlib.h>   
  54.   
  55. ClImage* clLoadImage(char* path)  
  56. {  
  57.     ClImage* bmpImg;  
  58.     FILE* pFile;  
  59.     unsigned short fileType;  
  60.     ClBitMapFileHeader bmpFileHeader;  
  61.     ClBitMapInfoHeader bmpInfoHeader;  
  62.     int channels = 1;  
  63.     int width = 0;  
  64.     int height = 0;  
  65.     int step = 0;  
  66.     int offset = 0;  
  67.     unsigned char pixVal;  
  68.     ClRgbQuad* quad;  
  69.     int i, j, k;  
  70.   
  71.     bmpImg = (ClImage*)malloc(sizeof(ClImage));  
  72.     pFile = fopen(path, "rb");  
  73.     if (!pFile)  
  74.     {  
  75.         free(bmpImg);  
  76.         return NULL;  
  77.     }  
  78.   
  79.     fread(&fileType, sizeof(unsigned short), 1, pFile);  
  80.     if (fileType == 0x4D42)  
  81.     {  
  82.         //printf("bmp file! \n");   
  83.   
  84.         fread(&bmpFileHeader, sizeof(ClBitMapFileHeader), 1, pFile);  
  85.         /*printf("\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n"); 
  86.         printf("bmp文件头信息:\n"); 
  87.         printf("文件大小:%d \n", bmpFileHeader.bfSize); 
  88.         printf("保留字1:%d \n", bmpFileHeader.bfReserved1); 
  89.         printf("保留字2:%d \n", bmpFileHeader.bfReserved2); 
  90.         printf("位图数据偏移字节数:%d \n", bmpFileHeader.bfOffBits);*/  
  91.   
  92.         fread(&bmpInfoHeader, sizeof(ClBitMapInfoHeader), 1, pFile);  
  93.         /*printf("\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n"); 
  94.         printf("bmp文件信息头 \n"); 
  95.         printf("结构体长度:%d \n", bmpInfoHeader.biSize); 
  96.         printf("位图宽度:%d \n", bmpInfoHeader.biWidth); 
  97.         printf("位图高度:%d \n", bmpInfoHeader.biHeight); 
  98.         printf("位图平面数:%d \n", bmpInfoHeader.biPlanes); 
  99.         printf("颜色位数:%d \n", bmpInfoHeader.biBitCount); 
  100.         printf("压缩方式:%d \n", bmpInfoHeader.biCompression); 
  101.         printf("实际位图数据占用的字节数:%d \n", bmpInfoHeader.biSizeImage); 
  102.         printf("X方向分辨率:%d \n", bmpInfoHeader.biXPelsPerMeter); 
  103.         printf("Y方向分辨率:%d \n", bmpInfoHeader.biYPelsPerMeter); 
  104.         printf("使用的颜色数:%d \n", bmpInfoHeader.biClrUsed); 
  105.         printf("重要颜色数:%d \n", bmpInfoHeader.biClrImportant); 
  106.         printf("\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n");*/  
  107.   
  108.         if (bmpInfoHeader.biBitCount == 8)  
  109.         {  
  110.             //printf("该文件有调色板,即该位图为非真彩色\n\n");   
  111.             channels = 1;  
  112.             width = bmpInfoHeader.biWidth;  
  113.             height = bmpInfoHeader.biHeight;  
  114.             offset = (channels*width)%4;  
  115.             if (offset != 0)  
  116.             {  
  117.                 offset = 4 - offset;  
  118.             }  
  119.             //bmpImg->mat = kzCreateMat(height, width, 1, 0);   
  120.             bmpImg->width = width;  
  121.             bmpImg->height = height;  
  122.             bmpImg->channels = 1;  
  123.             bmpImg->imageData = (unsigned char*)malloc(sizeof(unsigned char)*width*height);  
  124.             step = channels*width;  
  125.   
  126.             quad = (ClRgbQuad*)malloc(sizeof(ClRgbQuad)*256);  
  127.             fread(quad, sizeof(ClRgbQuad), 256, pFile);  
  128.             free(quad);  
  129.   
  130.             for (i=0; i<height; i++)  
  131.             {  
  132.                 for (j=0; j<width; j++)  
  133.                 {  
  134.                     fread(&pixVal, sizeof(unsigned char), 1, pFile);  
  135.                     bmpImg->imageData[(height-1-i)*step+j] = pixVal;  
  136.                 }  
  137.                 if (offset != 0)  
  138.                 {  
  139.                     for (j=0; j<offset; j++)  
  140.                     {  
  141.                         fread(&pixVal, sizeof(unsigned char), 1, pFile);  
  142.                     }  
  143.                 }  
  144.             }             
  145.         }  
  146.         else if (bmpInfoHeader.biBitCount == 24)  
  147.         {  
  148.             //printf("该位图为24位真彩色\n\n");   
  149.             channels = 3;  
  150.             width = bmpInfoHeader.biWidth;  
  151.             height = bmpInfoHeader.biHeight;  
  152.   
  153.             bmpImg->width = width;  
  154.             bmpImg->height = height;  
  155.             bmpImg->channels = 3;  
  156.             bmpImg->imageData = (unsigned char*)malloc(sizeof(unsigned char)*width*3*height);  
  157.             step = channels*width;  
  158.   
  159.             offset = (channels*width)%4;  
  160.             if (offset != 0)  
  161.             {  
  162.                 offset = 4 - offset;  
  163.             }  
  164.   
  165.             for (i=0; i<height; i++)  
  166.             {  
  167.                 for (j=0; j<width; j++)  
  168.                 {  
  169.                     for (k=0; k<3; k++)  
  170.                     {  
  171.                         fread(&pixVal, sizeof(unsigned char), 1, pFile);  
  172.                         bmpImg->imageData[(height-1-i)*step+j*3+k] = pixVal;  
  173.                     }  
  174.                     //kzSetMat(bmpImg->mat, height-1-i, j, kzScalar(pixVal[0], pixVal[1], pixVal[2]));   
  175.                 }  
  176.                 if (offset != 0)  
  177.                 {  
  178.                     for (j=0; j<offset; j++)  
  179.                     {  
  180.                         fread(&pixVal, sizeof(unsigned char), 1, pFile);  
  181.                     }  
  182.                 }  
  183.             }  
  184.         }  
  185.     }  
  186.   
  187.     return bmpImg;  
  188. }  
  189.   
  190. bool clSaveImage(char* path, ClImage* bmpImg)  
  191. {  
  192.     FILE *pFile;  
  193.     unsigned short fileType;  
  194.     ClBitMapFileHeader bmpFileHeader;  
  195.     ClBitMapInfoHeader bmpInfoHeader;  
  196.     int step;  
  197.     int offset;  
  198.     unsigned char pixVal = '\0';  
  199.     int i, j;  
  200.     ClRgbQuad* quad;  
  201.   
  202.     pFile = fopen(path, "wb");  
  203.     if (!pFile)  
  204.     {  
  205.         return false;  
  206.     }  
  207.   
  208.     fileType = 0x4D42;  
  209.     fwrite(&fileType, sizeof(unsigned short), 1, pFile);  
  210.   
  211.     if (bmpImg->channels == 3)//24位,3通道,彩图   
  212.     {  
  213.         step = bmpImg->channels*bmpImg->width;  
  214.         offset = step%4;  
  215.         if (offset != 4)  
  216.         {  
  217.             step += 4-offset;  
  218.         }  
  219.   
  220.         bmpFileHeader.bfSize = bmpImg->height*step + 54;  
  221.         bmpFileHeader.bfReserved1 = 0;  
  222.         bmpFileHeader.bfReserved2 = 0;  
  223.         bmpFileHeader.bfOffBits = 54;  
  224.         fwrite(&bmpFileHeader, sizeof(ClBitMapFileHeader), 1, pFile);  
  225.   
  226.         bmpInfoHeader.biSize = 40;  
  227.         bmpInfoHeader.biWidth = bmpImg->width;  
  228.         bmpInfoHeader.biHeight = bmpImg->height;  
  229.         bmpInfoHeader.biPlanes = 1;  
  230.         bmpInfoHeader.biBitCount = 24;  
  231.         bmpInfoHeader.biCompression = 0;  
  232.         bmpInfoHeader.biSizeImage = bmpImg->height*step;  
  233.         bmpInfoHeader.biXPelsPerMeter = 0;  
  234.         bmpInfoHeader.biYPelsPerMeter = 0;  
  235.         bmpInfoHeader.biClrUsed = 0;  
  236.         bmpInfoHeader.biClrImportant = 0;  
  237.         fwrite(&bmpInfoHeader, sizeof(ClBitMapInfoHeader), 1, pFile);  
  238.   
  239.         for (i=bmpImg->height-1; i>-1; i--)  
  240.         {  
  241.             for (j=0; j<bmpImg->width; j++)  
  242.             {  
  243.                 pixVal = bmpImg->imageData[i*bmpImg->width*3+j*3];  
  244.                 fwrite(&pixVal, sizeof(unsigned char), 1, pFile);  
  245.                 pixVal = bmpImg->imageData[i*bmpImg->width*3+j*3+1];  
  246.                 fwrite(&pixVal, sizeof(unsigned char), 1, pFile);  
  247.                 pixVal = bmpImg->imageData[i*bmpImg->width*3+j*3+2];  
  248.                 fwrite(&pixVal, sizeof(unsigned char), 1, pFile);  
  249.             }  
  250.             if (offset!=0)  
  251.             {  
  252.                 for (j=0; j<offset; j++)  
  253.                 {  
  254.                     pixVal = 0;  
  255.                     fwrite(&pixVal, sizeof(unsigned char), 1, pFile);  
  256.                 }  
  257.             }  
  258.         }  
  259.     }  
  260.     else if (bmpImg->channels == 1)//8位,单通道,灰度图   
  261.     {  
  262.         step = bmpImg->width;  
  263.         offset = step%4;  
  264.         if (offset != 4)  
  265.         {  
  266.             step += 4-offset;  
  267.         }  
  268.   
  269.         bmpFileHeader.bfSize = 54 + 256*4 + bmpImg->width;  
  270.         bmpFileHeader.bfReserved1 = 0;  
  271.         bmpFileHeader.bfReserved2 = 0;  
  272.         bmpFileHeader.bfOffBits = 54 + 256*4;  
  273.         fwrite(&bmpFileHeader, sizeof(ClBitMapFileHeader), 1, pFile);  
  274.   
  275.         bmpInfoHeader.biSize = 40;  
  276.         bmpInfoHeader.biWidth = bmpImg->width;  
  277.         bmpInfoHeader.biHeight = bmpImg->height;  
  278.         bmpInfoHeader.biPlanes = 1;  
  279.         bmpInfoHeader.biBitCount = 8;  
  280.         bmpInfoHeader.biCompression = 0;  
  281.         bmpInfoHeader.biSizeImage = bmpImg->height*step;  
  282.         bmpInfoHeader.biXPelsPerMeter = 0;  
  283.         bmpInfoHeader.biYPelsPerMeter = 0;  
  284.         bmpInfoHeader.biClrUsed = 256;  
  285.         bmpInfoHeader.biClrImportant = 256;  
  286.         fwrite(&bmpInfoHeader, sizeof(ClBitMapInfoHeader), 1, pFile);  
  287.   
  288.         quad = (ClRgbQuad*)malloc(sizeof(ClRgbQuad)*256);  
  289.         for (i=0; i<256; i++)  
  290.         {  
  291.             quad[i].rgbBlue = i;  
  292.             quad[i].rgbGreen = i;  
  293.             quad[i].rgbRed = i;  
  294.             quad[i].rgbReserved = 0;  
  295.         }  
  296.         fwrite(quad, sizeof(ClRgbQuad), 256, pFile);  
  297.         free(quad);  
  298.   
  299.         for (i=bmpImg->height-1; i>-1; i--)  
  300.         {  
  301.             for (j=0; j<bmpImg->width; j++)  
  302.             {  
  303.                 pixVal = bmpImg->imageData[i*bmpImg->width+j];  
  304.                 fwrite(&pixVal, sizeof(unsigned char), 1, pFile);  
  305.             }  
  306.             if (offset!=0)  
  307.             {  
  308.                 for (j=0; j<offset; j++)  
  309.                 {  
  310.                     pixVal = 0;  
  311.                     fwrite(&pixVal, sizeof(unsigned char), 1, pFile);  
  312.                 }  
  313.             }  
  314.         }  
  315.     }  
  316.     fclose(pFile);  
  317.   
  318.     return true;  
  319. }  
  320.   
  321. main.cpp  
  322. #include "stdafx.h"   
  323. #include "chenLeeCV.h"   
  324.   
  325.   
  326. int _tmain(int argc, _TCHAR* argv[])  
  327. {  
  328.     ClImage* img = clLoadImage("c:/test.bmp");  
  329.     bool flag = clSaveImage("c:/result.bmp", img);  
  330.     if(flag)  
  331.     {  
  332.         printf("save ok... \n");  
  333.     }  
  334.       
  335.   
  336.     while(1);  
  337.     return 0;  
  338. }  
复制代码
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics