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 1
    FILE *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;             // 2048
    l_height.value = height;           // 512
    l_bfSize.value = bfSize;           // 3145784
    l_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 + 54
        l_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, //恒为1
        24, 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 00
        0, 0, 0, 0, //垂直分辨率     //biYPelsPerMeter
        0, 0, 0, 0, //引用色彩数     //biClrUsed
        0, 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 1
    for (i = 0; i < height; i++)
    {                               // 512
        for (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);
#endif
    fprintf(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.
最后再说一点,觉得难不要陷入“想”的境地,要去做。走过来后就会发现,也是如此。



















