歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

用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語言的版本,僅供參考,如有錯誤,歡迎指正。

  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("保留字:%d \n", bmpFileHeader.bfReserved1); 
  89.         printf("保留字:%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("該位圖為位真彩色\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位,通道,彩圖   
  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. }  
Copyright © Linux教程網 All Rights Reserved