C语言,BMP格式解析,生成不同位深的图片。

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.

        最后再说一点,觉得难不要陷入“想”的境地,要去做。走过来后就会发现,也是如此。

猜你喜欢

转载自blog.csdn.net/weixin_43920383/article/details/130609419
今日推荐