0.前言
目录
0.前言
1.BMP格式详解
1.1图片的构成
1.2BMP格式
1.2.1文件头
1.2.2位图信息头
1.2.3调色板
1.2.4位图数据
2.生成
3.总结
最近工作任务繁重且对我来说小有难度,但是没有困难的事情做起来怎么有收获呢?
今天推荐一本书《寻找光的小女孩》,挺感人的。记得是高中借的同学的看的,刚开始看到书名感觉不怎么投我的胃口,果不其然不可“以貌取书”,熬夜看完了。
最近工作上逐渐步入正轨,研发的工作嘛,对吧,不可以设置限制,这才能体现到研发,才能发挥研发的最大福利。工作也算是小半年了,逐渐慢慢对手里的东西或者说项目有了自己的认识,这或许就是经验。这种感觉我刚刚能觉察到,相信再给我一些时间,可以掌握吧。
喜欢上了喝无糖可乐。哈。
1.BMP格式详解
这是最近工作的内容,任务是从csv文件获取数据,将获取到的数据通过算法转为灰度值,然后填充进BMP格式图片,要求图片位深16位。
1.1图片的构成
其实我们知道每张图片都是由每个像素组成的,多少的像素也构成图片的大小。每个像素是什么构成的呢?在bmp中就是数值。在此之前,先说明两个概念,位深和色深。(好长时间不写博客,手生了起来,逻辑思路也不如以前,见谅)。
位深:这个名词是用来描述什么?每个像素的大小,是一个大小的代名词。比如位深是24的图片,就是说这张图片的每个像素的值是由24比特的大小来表示,比如一幅图片是1080*1280的大小,那么位深24的bmp大小就在1080*1280*3字节左右(这里我是在Linux下做的,从虚拟机拷贝到win下大小会不同,大概是因为架构的不同)。
色深:在bmp中,每个像素的值,其实也就是颜色的值是由三通道RGB组成的,24位的图,每个通道的表示为8比特,即一字节,范围是0-255,三通道(红绿蓝)范围皆是0-255,那这三种通道合成的颜色也就是255*255*255种,这个值就叫做色深,是一个数量的范围,描述颜色的多少。
这两种概念容易模糊,不知道我写的能不能帮助大家理解。
1.2BMP格式
参考:bmp格式andbmp格式
就把这个图片想象成普通的文件就行了,只不过区别就是要有固定的头。
1.2.1文件头
文件头,顾名思义是描述这个文件的信息,也就是这个图片的信息。这里面的内容包含了文件的大小这一重要信息。此部分大小是14字节。
字节顺序 | 数据结构 | 描述 |
1,2 | 16比特 | 高8位位字母‘B,低8位为字母’M‘ |
3,4,5,6 | 32 | 文件尺寸 |
7,8 | 16 | 保留字1 |
9,10 | 16 | 保留字1 |
11,12,13,14 | 32 | 位图数据部分相对于文件的起始偏移量 |
数据部分偏移量的存在,说明图像数据部分并不一定要紧随图像参数或调色板之后放置,BMP图片的制作者其实可以在调色板之后、数据部分之前填充任何内容,只要正确地设置偏移量即可。
1.2.2位图信息头
此部分用来描述图片的信息,比如图像宽高、bpp等。此部分大小是40字节。
字节顺序 | 数据结构 | 描述 |
15,16,17,18 | uint | 当前结构体的大小,通常是40或56 |
19,20,21,22 | int | 图像宽度(像素) |
23,24,25,26 | int | 图像高度(像素) |
27,28 | word | 恒为1 |
29,30 | word | 每个像素占用的位数即bpp |
31,32,33,34 | uint | 压缩方式 |
35,36,37,38 | uint | 图像的尺寸 |
39,40,41,42 | int | 水平分辨率 |
43,44,45,46 | int | 垂直分辨率 |
47,48,49,50 | uint | 引用色彩数 |
51,52,53,54 | uint | 关键色彩数 |
31-34字节表示图像数据的压缩方式,参数取值范围是0,1,2,3等。
0 ----------------RGB方式
1 --------------- 8bpp的run-length-encoding方式
2 --------------- 4bpp的run-length-encoding方式
3 ---------------- bit-fields方式
只有压缩方式选项被设置为bit-fileds时,当前结构体大小为56字节,否则,为40字节。
1.2.3调色板
我们一般见到的图像以24位图像为主,即R、G、B三种颜色各用8个bit来表示,这样的图像我们称为真彩色,这种情况下是不需要调色板的,也就是所位图信息头后面紧跟的就是位图数据了。这部分我略过,有兴趣的同学可以自己研究一下。
1.2.4位图数据
就是每个像素的值,位图数据,每个像素占一个字节。24位数据按照BGR填充,例如一张2个像素的bmp24位图,它的构成就是:14字节文件头信息,40字节位图信息,2个像素,每个像素大小是24位,也就是3字节,第一个像素的blue就是8比特,后面紧跟8比特green,再是8比特red,后一个像素也是如此。一共14+40+2*3=60字节。那这个2个像素的bmp文件就占大小60字节。(不涉及调色板)
后面以详细代码说明。
2.生成
代码部分我只给出生成的,完整代码大家可以下载:完整代码。注意,此代码是从csv文件获取数据、分割数据并提取。
int bmp_gen_pic(char *fileName, uint32_t width, uint32_t height, unsigned char *color)
{// width = 2048 height = 512 color = data_pic#if 1FILE *fp;uint32_t i, j;LITTLE l_width, l_height, l_bfSize, l_biSizeImage;uint8_t r = color[0];uint8_t g = color[0];uint8_t b = color[0];uint32_t width_r = (width * 24 / 8 + 3) / 4 * 4; // width_r 此变量代表的是每行的字节数 6144(整形) 这步保证宽度是4的倍数(bmp格式要求)// printf("width_r = %ld\n",width_r);uint32_t bfSize = width_r * height + 54 + 2; //此变量代表生成的图片的大小 uint32_t biSizeImage = width_r * height; //此变量代表图片的像素大小 // printf("hight = %ld\n",height);// printf("size = %ld\n",biSizeImage);l_width.value = width; // 2048l_height.value = height; // 512l_bfSize.value = bfSize; // 3145784l_biSizeImage.value = biSizeImage; // 3145728/* BMP file format: www.cnblogs.com/wainiwann/p/7086844.html */// bmp格式头 固定uint8_t bmp_head_map[54] = {//这个头文件 包含两部分 一是文件头 14 二是位图信息头 40/* bmp file header: 14 byte */0x42, 0x4d, // 42 代表 B 4d代表M// bmp pixel size: width * height * 3 + 54l_bfSize.bytes[0], l_bfSize.bytes[1], l_bfSize.bytes[2], l_bfSize.bytes[3], //代表文件的尺寸 0, 0, 0, 0,54, 0, 0, 0, /* 14+40=54 */ //位图部分相对文件的起始偏移量 就是多少字节后是位图数据(像素值)/**************************************************************//* bmp map info: 40 byte */40, 0, 0, 0, //当前的大小 就是40 意思后面40都是描述本部分// width 图像宽度(像素)l_width.bytes[0], l_width.bytes[1], l_width.bytes[2], l_width.bytes[3],// height 图像高度(像素)l_height.bytes[0], l_height.bytes[1], l_height.bytes[2], l_height.bytes[3],1, 0, //恒为124, 0, //每个像素占用的位数(bpp) /* 24 bit: R[8]/G[8]/B[8] */0, 0, 0, 0, // biCompression:0 压缩方式//图像的尺寸l_biSizeImage.bytes[0], l_biSizeImage.bytes[1], l_biSizeImage.bytes[2], l_biSizeImage.bytes[3],0, 0, 0, 0, //水平分辨率 //biXPelsPerMeter: 60 0F 00 000, 0, 0, 0, //垂直分辨率 //biYPelsPerMeter0, 0, 0, 0, //引用色彩数 //biClrUsed0, 0, 0, 0 //关键色彩数 //biClrImportant};/* write in binary format */fp = fopen(fileName, "wb+"); // wb+代表打开一个读写打开一个二进制文件if (fp == NULL){printf("%s: file create failed!\n", fileName);return -1;}printf("%s: file create success!\n", fileName);fwrite(bmp_head_map, sizeof(bmp_head_map), 1, fp); //写入1个sizeof(头)的大小uint8_t databmp[KUAN*GAO*3];memset(databmp, 0, sizeof(databmp));uint32_t pos = 0;#if 1for (i = 0; i < height; i++){ // 512for (j = 0; j < width; j++) // 2048{//fprintf(fp, "%c%c%c", color[j + i * width], color[j + i * width], color[j + i * width]); /* BGR */ // FF FF FF 白色 00 00 00 黑色databmp[pos++] = color[j + i * width];databmp[pos++] = color[j + i * width];databmp[pos++] = color[j + i * width];}}fwrite(databmp, sizeof(databmp), 1, fp);#endiffprintf(fp, "%c%c", 0, 0); // PhotoShop two byte "0"if (fclose(fp)){printf("file close failed!\n");return -1;}fp = NULL;return 0;
#endif
}
代码我注解的很清楚,不懂可以留言。
3.总结
好家伙,写了一个星期,shit.
工作忙起来对博客是疏忽很多,见谅。
上班时间消耗完了所有精力,累到不是累,只是想下班后不再想动脑,去获得简单纯粹的娱乐。
生活需要新鲜,Everything is like this.
最后再说一点,觉得难不要陷入“想”的境地,要去做。走过来后就会发现,也是如此。