找回密码
 用户注册

QQ登录

只需一步,快速开始

查看: 3843|回复: 0

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

[复制链接]
发表于 2011-12-17 20:20:30 | 显示全部楼层 |阅读模式
bmp是BitMap(位图)的简称,也是所有windows上图片显示的基础。所有的图片格式,都必须转换成bmp才能进行最终的显示。所以,bmp文件的读写,就变得非常重要了。然而,很多人是借助于MFC,C# 库函数,OpenCV,OpenGL等库函数进行bmp文件的读写。试想一下,如果你要在诸如DSPFPGA之类的嵌入式设备上进行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. typedef struct
  5. {
  6.         //unsigned short    bfType;
  7.         unsigned long    bfSize;
  8.         unsigned short    bfReserved1;
  9.         unsigned short    bfReserved2;
  10.         unsigned long    bfOffBits;
  11. } ClBitMapFileHeader;
  12. typedef struct
  13. {
  14.         unsigned long  biSize;
  15.         long   biWidth;
  16.         long   biHeight;
  17.         unsigned short   biPlanes;
  18.         unsigned short   biBitCount;
  19.         unsigned long  biCompression;
  20.         unsigned long  biSizeImage;
  21.         long   biXPelsPerMeter;
  22.         long   biYPelsPerMeter;
  23.         unsigned long   biClrUsed;
  24.         unsigned long   biClrImportant;
  25. } ClBitMapInfoHeader;
  26. typedef struct
  27. {
  28.         unsigned char rgbBlue; //该颜色的蓝色分量
  29.         unsigned char rgbGreen; //该颜色的绿色分量
  30.         unsigned char rgbRed; //该颜色的红色分量
  31.         unsigned char rgbReserved; //保留值
  32. } ClRgbQuad;
  33. typedef struct
  34. {
  35.         int width;
  36.         int height;
  37.         int channels;
  38.         unsigned char* imageData;
  39. }ClImage;
  40. ClImage* clLoadImage(char* path);
  41. bool clSaveImage(char* path, ClImage* bmpImg);
  42. #endif
  43. chenLeeCV.cpp
  44. #include "chenLeeCV.h"
  45. #include <stdio.h>
  46. #include <stdlib.h>
  47. ClImage* clLoadImage(char* path)
  48. {
  49.         ClImage* bmpImg;
  50.         FILE* pFile;
  51.         unsigned short fileType;
  52.         ClBitMapFileHeader bmpFileHeader;
  53.         ClBitMapInfoHeader bmpInfoHeader;
  54.         int channels = 1;
  55.         int width = 0;
  56.         int height = 0;
  57.         int step = 0;
  58.         int offset = 0;
  59.         unsigned char pixVal;
  60.         ClRgbQuad* quad;
  61.         int i, j, k;
  62.         bmpImg = (ClImage*)malloc(sizeof(ClImage));
  63.         pFile = fopen(path, "rb");
  64.         if (!pFile)
  65.         {
  66.                 free(bmpImg);
  67.                 return NULL;
  68.         }
  69.         fread(&fileType, sizeof(unsigned short), 1, pFile);
  70.         if (fileType == 0x4D42)
  71.         {
  72.                 //printf("bmp file! \n");
  73.                 fread(&bmpFileHeader, sizeof(ClBitMapFileHeader), 1, pFile);
  74.                 /*printf("\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n");
  75.                 printf("bmp文件头信息:\n");
  76.                 printf("文件大小:%d \n", bmpFileHeader.bfSize);
  77.                 printf("保留字1:%d \n", bmpFileHeader.bfReserved1);
  78.                 printf("保留字2:%d \n", bmpFileHeader.bfReserved2);
  79.                 printf("位图数据偏移字节数:%d \n", bmpFileHeader.bfOffBits);*/
  80.                 fread(&bmpInfoHeader, sizeof(ClBitMapInfoHeader), 1, pFile);
  81.                 /*printf("\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n");
  82.                 printf("bmp文件信息头 \n");
  83.                 printf("结构体长度:%d \n", bmpInfoHeader.biSize);
  84.                 printf("位图宽度:%d \n", bmpInfoHeader.biWidth);
  85.                 printf("位图高度:%d \n", bmpInfoHeader.biHeight);
  86.                 printf("位图平面数:%d \n", bmpInfoHeader.biPlanes);
  87.                 printf("颜色位数:%d \n", bmpInfoHeader.biBitCount);
  88.                 printf("压缩方式:%d \n", bmpInfoHeader.biCompression);
  89.                 printf("实际位图数据占用的字节数:%d \n", bmpInfoHeader.biSizeImage);
  90.                 printf("X方向分辨率:%d \n", bmpInfoHeader.biXPelsPerMeter);
  91.                 printf("Y方向分辨率:%d \n", bmpInfoHeader.biYPelsPerMeter);
  92.                 printf("使用的颜色数:%d \n", bmpInfoHeader.biClrUsed);
  93.                 printf("重要颜色数:%d \n", bmpInfoHeader.biClrImportant);
  94.                 printf("\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n");*/
  95.                 if (bmpInfoHeader.biBitCount == 8)
  96.                 {
  97.                         //printf("该文件有调色板,即该位图为非真彩色\n\n");
  98.                         channels = 1;
  99.                         width = bmpInfoHeader.biWidth;
  100.                         height = bmpInfoHeader.biHeight;
  101.                         offset = (channels*width)%4;
  102.                         if (offset != 0)
  103.                         {
  104.                                 offset = 4 - offset;
  105.                         }
  106.                         //bmpImg->mat = kzCreateMat(height, width, 1, 0);
  107.                         bmpImg->width = width;
  108.                         bmpImg->height = height;
  109.                         bmpImg->channels = 1;
  110.                         bmpImg->imageData = (unsigned char*)malloc(sizeof(unsigned char)*width*height);
  111.                         step = channels*width;
  112.                         quad = (ClRgbQuad*)malloc(sizeof(ClRgbQuad)*256);
  113.                         fread(quad, sizeof(ClRgbQuad), 256, pFile);
  114.                         free(quad);
  115.                         for (i=0; i<height; i++)
  116.                         {
  117.                                 for (j=0; j<width; j++)
  118.                                 {
  119.                                         fread(&pixVal, sizeof(unsigned char), 1, pFile);
  120.                                         bmpImg->imageData[(height-1-i)*step+j] = pixVal;
  121.                                 }
  122.                                 if (offset != 0)
  123.                                 {
  124.                                         for (j=0; j<offset; j++)
  125.                                         {
  126.                                                 fread(&pixVal, sizeof(unsigned char), 1, pFile);
  127.                                         }
  128.                                 }
  129.                         }                       
  130.                 }
  131.                 else if (bmpInfoHeader.biBitCount == 24)
  132.                 {
  133.                         //printf("该位图为24位真彩色\n\n");
  134.                         channels = 3;
  135.                         width = bmpInfoHeader.biWidth;
  136.                         height = bmpInfoHeader.biHeight;
  137.                         bmpImg->width = width;
  138.                         bmpImg->height = height;
  139.                         bmpImg->channels = 3;
  140.                         bmpImg->imageData = (unsigned char*)malloc(sizeof(unsigned char)*width*3*height);
  141.                         step = channels*width;
  142.                         offset = (channels*width)%4;
  143.                         if (offset != 0)
  144.                         {
  145.                                 offset = 4 - offset;
  146.                         }
  147.                         for (i=0; i<height; i++)
  148.                         {
  149.                                 for (j=0; j<width; j++)
  150.                                 {
  151.                                         for (k=0; k<3; k++)
  152.                                         {
  153.                                                 fread(&pixVal, sizeof(unsigned char), 1, pFile);
  154.                                                 bmpImg->imageData[(height-1-i)*step+j*3+k] = pixVal;
  155.                                         }
  156.                                         //kzSetMat(bmpImg->mat, height-1-i, j, kzScalar(pixVal[0], pixVal[1], pixVal[2]));
  157.                                 }
  158.                                 if (offset != 0)
  159.                                 {
  160.                                         for (j=0; j<offset; j++)
  161.                                         {
  162.                                                 fread(&pixVal, sizeof(unsigned char), 1, pFile);
  163.                                         }
  164.                                 }
  165.                         }
  166.                 }
  167.         }
  168.         return bmpImg;
  169. }
  170. bool clSaveImage(char* path, ClImage* bmpImg)
  171. {
  172.         FILE *pFile;
  173.         unsigned short fileType;
  174.         ClBitMapFileHeader bmpFileHeader;
  175.         ClBitMapInfoHeader bmpInfoHeader;
  176.         int step;
  177.         int offset;
  178.         unsigned char pixVal = '\0';
  179.         int i, j;
  180.         ClRgbQuad* quad;
  181.         pFile = fopen(path, "wb");
  182.         if (!pFile)
  183.         {
  184.                 return false;
  185.         }
  186.         fileType = 0x4D42;
  187.         fwrite(&fileType, sizeof(unsigned short), 1, pFile);
  188.         if (bmpImg->channels == 3)//24位,3通道,彩图
  189.         {
  190.                 step = bmpImg->channels*bmpImg->width;
  191.                 offset = step%4;
  192.                 if (offset != 4)
  193.                 {
  194.                         step += 4-offset;
  195.                 }
  196.                 bmpFileHeader.bfSize = bmpImg->height*step + 54;
  197.                 bmpFileHeader.bfReserved1 = 0;
  198.                 bmpFileHeader.bfReserved2 = 0;
  199.                 bmpFileHeader.bfOffBits = 54;
  200.                 fwrite(&bmpFileHeader, sizeof(ClBitMapFileHeader), 1, pFile);
  201.                 bmpInfoHeader.biSize = 40;
  202.                 bmpInfoHeader.biWidth = bmpImg->width;
  203.                 bmpInfoHeader.biHeight = bmpImg->height;
  204.                 bmpInfoHeader.biPlanes = 1;
  205.                 bmpInfoHeader.biBitCount = 24;
  206.                 bmpInfoHeader.biCompression = 0;
  207.                 bmpInfoHeader.biSizeImage = bmpImg->height*step;
  208.                 bmpInfoHeader.biXPelsPerMeter = 0;
  209.                 bmpInfoHeader.biYPelsPerMeter = 0;
  210.                 bmpInfoHeader.biClrUsed = 0;
  211.                 bmpInfoHeader.biClrImportant = 0;
  212.                 fwrite(&bmpInfoHeader, sizeof(ClBitMapInfoHeader), 1, pFile);
  213.                 for (i=bmpImg->height-1; i>-1; i--)
  214.                 {
  215.                         for (j=0; j<bmpImg->width; j++)
  216.                         {
  217.                                 pixVal = bmpImg->imageData[i*bmpImg->width*3+j*3];
  218.                                 fwrite(&pixVal, sizeof(unsigned char), 1, pFile);
  219.                                 pixVal = bmpImg->imageData[i*bmpImg->width*3+j*3+1];
  220.                                 fwrite(&pixVal, sizeof(unsigned char), 1, pFile);
  221.                                 pixVal = bmpImg->imageData[i*bmpImg->width*3+j*3+2];
  222.                                 fwrite(&pixVal, sizeof(unsigned char), 1, pFile);
  223.                         }
  224.                         if (offset!=0)
  225.                         {
  226.                                 for (j=0; j<offset; j++)
  227.                                 {
  228.                                         pixVal = 0;
  229.                                         fwrite(&pixVal, sizeof(unsigned char), 1, pFile);
  230.                                 }
  231.                         }
  232.                 }
  233.         }
  234.         else if (bmpImg->channels == 1)//8位,单通道,灰度图
  235.         {
  236.                 step = bmpImg->width;
  237.                 offset = step%4;
  238.                 if (offset != 4)
  239.                 {
  240.                         step += 4-offset;
  241.                 }
  242.                 bmpFileHeader.bfSize = 54 + 256*4 + bmpImg->width;
  243.                 bmpFileHeader.bfReserved1 = 0;
  244.                 bmpFileHeader.bfReserved2 = 0;
  245.                 bmpFileHeader.bfOffBits = 54 + 256*4;
  246.                 fwrite(&bmpFileHeader, sizeof(ClBitMapFileHeader), 1, pFile);
  247.                 bmpInfoHeader.biSize = 40;
  248.                 bmpInfoHeader.biWidth = bmpImg->width;
  249.                 bmpInfoHeader.biHeight = bmpImg->height;
  250.                 bmpInfoHeader.biPlanes = 1;
  251.                 bmpInfoHeader.biBitCount = 8;
  252.                 bmpInfoHeader.biCompression = 0;
  253.                 bmpInfoHeader.biSizeImage = bmpImg->height*step;
  254.                 bmpInfoHeader.biXPelsPerMeter = 0;
  255.                 bmpInfoHeader.biYPelsPerMeter = 0;
  256.                 bmpInfoHeader.biClrUsed = 256;
  257.                 bmpInfoHeader.biClrImportant = 256;
  258.                 fwrite(&bmpInfoHeader, sizeof(ClBitMapInfoHeader), 1, pFile);
  259.                 quad = (ClRgbQuad*)malloc(sizeof(ClRgbQuad)*256);
  260.                 for (i=0; i<256; i++)
  261.                 {
  262.                         quad[i].rgbBlue = i;
  263.                         quad[i].rgbGreen = i;
  264.                         quad[i].rgbRed = i;
  265.                         quad[i].rgbReserved = 0;
  266.                 }
  267.                 fwrite(quad, sizeof(ClRgbQuad), 256, pFile);
  268.                 free(quad);
  269.                 for (i=bmpImg->height-1; i>-1; i--)
  270.                 {
  271.                         for (j=0; j<bmpImg->width; j++)
  272.                         {
  273.                                 pixVal = bmpImg->imageData[i*bmpImg->width+j];
  274.                                 fwrite(&pixVal, sizeof(unsigned char), 1, pFile);
  275.                         }
  276.                         if (offset!=0)
  277.                         {
  278.                                 for (j=0; j<offset; j++)
  279.                                 {
  280.                                         pixVal = 0;
  281.                                         fwrite(&pixVal, sizeof(unsigned char), 1, pFile);
  282.                                 }
  283.                         }
  284.                 }
  285.         }
  286.         fclose(pFile);
  287.         return true;
  288. }
  289. main.cpp
  290. #include "stdafx.h"
  291. #include "chenLeeCV.h"
  292. int _tmain(int argc, _TCHAR* argv[])
  293. {
  294.         ClImage* img = clLoadImage("c:/test.bmp");
  295.         bool flag = clSaveImage("c:/result.bmp", img);
  296.         if(flag)
  297.         {
  298.                 printf("save ok... \n");
  299.         }
  300.        
  301.         while(1);
  302.         return 0;
  303. }
复制代码


作者:carson2005 发表于2011-12-17 17:10:22 原文链接
您需要登录后才可以回帖 登录 | 用户注册

本版积分规则

Archiver|手机版|小黑屋|ACE Developer ( 京ICP备06055248号 )

GMT+8, 2024-4-28 02:26 , Processed in 0.013600 second(s), 7 queries , Redis On.

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表