转自:用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. 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. }

用C语言进行BMP文件的读写相关推荐

  1. 数字图像处理大作业-BMP文件的读写

    数字图像处理-BMP文件的读写 一.题目背景 二.灰度BMP的读写 1.读入lena.bmp文件 1.1 编写打印文件头信息与信息头数据的函数 2 通过文件内容得到灰度bmp数据信息 2.1 打印信息 ...

  2. C语言实现wav文件的读写

    C语言实现wav文件的读写 wav文件格式 //wav.h typedef unsigned char uint8_t; typedef signed char int8_t; typedef uns ...

  3. linux C语言 对本地文件进行读写操作

    linux C语言 对本地文件进行最简单读写操作 读取json文件 保存json文件 读取json文件 对本地以cjson格式保存的文本进行读取 /* 读取json文件 */ const char* ...

  4. 利用C语言读取BMP文件

    文章目录 什么是bmp文件 1.文件头信息块 2.图像描述信息块 3.颜色表 4.图像数据区 编写代码 C文件 h头文件 存储算法 什么是bmp文件 BMP是bitmap的缩写形式,bitmap顾名思 ...

  5. bmp文件c语言压缩算法,BMP文件数据压缩与解压缩方法.pdf

    BMP文件数据压缩与解压缩方法 20 1 Vol. 20 No. 1 2 0 0 0 3 JOURNAL OF FU SHUN PET ROLEU M INST IT UTE Mar. 2000 : ...

  6. SLAM|C语言实现对文件的读写

    文章目录 前言 一 文件中的数据格式: 二 C语言实现对上述文件的读取 前言 由于项目中需要将C++的实现全部改为C代码,以便后续下到核心板里进行落地.这里简单总结下C语言对wheel.imu以及uw ...

  7. C语言读取BMP文件

    BMP图像编码 BMP即bitmap,也就是位图,一般由4部分组成:文件头信息块.图像描述信息块.颜色表(在真彩色模式无颜色表)和图像数据区. 在图像数据之前,如图所示,共有54位数据 其中,0x42 ...

  8. 使用c语言实现INI文件的读写

    INI文件是Windows上独有的一种存储结构,这只是Windows下发明的存储结构,也有很多类似的,比如xml! 就说一下TXT文本 是按行读取,这就是它的格式! 而xml是类似二叉树的带层次结构的 ...

  9. C语言中对文件的读写操作

    编写程序,实现输入10个数,将这10个数按照从小到大的顺序排列,并将写入data.txt文件中 #include <stdio.h> #include <string.h>in ...

  10. c语言创建一个文件函数,c语言文件读写函数 用C语言的函数创建、打开和读写文件...

    C语言文件读写结构体里面的数据怎样存到磁盘文件上 c语言对同一个文件进行读写(r+) 编写程序,将文本文件c.txt中的所有小写字母转换成相应的大写字母,其他一.标准文件的读写 1.文件的打开 fop ...

最新文章

  1. ComponentOne WebChart for ASP.NET基础
  2. 【流量劫持】躲避 HSTS 的 HTTPS 劫持
  3. 新零售赛道上,便利蜂的美食牌
  4. 【Android】 Android adb常见问题整理
  5. java class 生成对象_面向对象编程,你知道Java有哪些创建对象的方式吗?
  6. php常见错误及总结,PHP常见的错误级别总结
  7. S3C2410 bootloader ----VIVI阅读笔记 (转)下
  8. 【MyBatis框架】Mybatis开发dao方法第二部分
  9. 2021-06-19 sklearn中的线性回归模型
  10. java 6面骰子_Java实现的简单掷骰子游戏示例
  11. cs1.5最新服务器地址,CS1.5服务器地址,不定期更新
  12. 踩坑记:Git的下载、安装和配置
  13. 大桥数据,国外大桥排行榜数据清单,Python爬虫120例第32例
  14. 【Midjourney实操】逼真到颤抖!保姆级教程教生成效果炸裂的图片
  15. android 个人云存储,个人云储存appv1.3
  16. 【C语言】以通讯录为例理解宿舍管理系统,图书管理系统完成C语言期末作业。源代码见文章末尾
  17. centos8之systemd管理服务开机自启动
  18. put: File COPYING could be replicated to 0 nodes instead of minReplication.There are 0 datanodes解决方案
  19. html canvas php,HTML5 canvas实现画图程序(附代码)
  20. 电子取证和司法鉴定笔记

热门文章

  1. WebStorm功能特点以及使用指南
  2. Error: Invalid or corrupt
  3. python mysql 连接超时时间_一段时间后MySQL连接超时(Python、MySQL、FLASK)
  4. python解包裹_python-之基本语法
  5. 笔记本电脑报价单_抚顺x射线扫描仪设备,x-ray设备厂家报价单-老友网
  6. cpoint 两个点距离_Wasserstein距离学习笔记
  7. swoole2.0与java_swoole2.0试用说明
  8. rabbitmq接收不到消息_springboot集成RabbitMQ接收消息及其高级特性
  9. 实战:基于服务端开发和前后端分离开发区别
  10. Mybatis generator 自动生成代码(实例讲解)