歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> 用C語言進行BMP文件的讀寫

用C語言進行BMP文件的讀寫

日期:2017/3/1 10:21:17   编辑:Linux編程

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