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

news2024/9/20 14:33:06

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.

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/660180.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Windows10环境下载安装Oracle19c教程

Windows10环境下载安装Oracle19c教程 前言1. 官网下载2. 运行setup.exe2.1 解压缩2.2 报错解决 3.正式安装3.1 配置选项3.2 系统类3.3 oracle主目录用户3.4 安装位置3.5 先决条件检查3.6 安装产品3.7 安装完成3.8 完全卸载oracle(非必备) 4. 安装验证4.1 CMD验证4.2 SQL Plus4.…

本周大新闻|Quest游戏订阅服务曝光;平价版苹果XR头显25年推出

本周XR大新闻&#xff0c;AR方面&#xff0c;彭博苹果预计25年推出更亲民头显&#xff1b;Vision Pro外屏含微透镜&#xff1b;WWDC23苹果高管脱口秀爆料更多细节&#xff1b;外媒爆料称Vision Pro预期销量改为15万台&#xff1b;VitreaLab展示RGB激光背光技术。还是提前说一下…

leetcode刷题之字符串相关问题

344.反转字符串 方法一&#xff1a;找中间结点&#xff0c;头尾翻转 var reverseString function(s) {let len s.lengthlet mid Math.floor((s.length - 1) / 2) //向下取整 如果长度是奇数&#xff0c;那么mid是最中间的结点 如果长度是偶数&#xff0c;那么mid是中间两个…

【Java技术专题】「攻破技术盲区」带你攻破你很可能存在的Java技术盲点之动态性技术原理指南(反射技术专题)

带你攻破你很可能存在的Java技术盲点之动态性技术原理指南 带你攻破你很可能存在的Java技术盲点之动态性技术原理指南编程语言的类型静态类型语言动态类型语言 技术核心方向反射API反射案例介绍反射功能操作获取构造器长度可变的参数 - 构造方法使用反射 API 获取参数长度可变的…

【软件测试】

系列文章目录 文章目录 系列文章目录前言第四章 单元测试4.1 软件测试过程概述4.2 什么是单元测试4.2.1 单元测试的定义4.2.2 单元测试的重要性4.2.3 单元测试原则 4.3 单元测试的目标和任务4.3.1 单元测试的目标&#xff1a;单元模块被正确编码4.3.2 单元测试的主要任务 4.4 单…

FreeRTOS:事件标志组

目录 一、事件标志组简介1.1事件位(事件标志)1.2事件组1.3事件标志组和事件位的数据类型 二、创建事件标志组2.1函数 xEventGroupCreate()2.2函数xEventGroupCreateStatic() 三、设置事件位3.1函数 xEventGroupClearBits()3.2函数xEventGroupClearBitsFromISR()3.3函数 xEventG…

Python模块MarkupPy 自定义html报告

简介 MarkupPy是Python模块用于生成HTML和XML格式的字符串。它的主要作用是提供了一种比原生HTML/XML更加易读和易写的编写方式&#xff0c;通过Python代码来生成HTML或XML代码。 使用MarkupPy&#xff0c;可以在Python中使用不同的对象类型和方法&#xff0c;来动态地生成HTML…

做自动化测试老是失败?你真的会做吗?资深测试的总结整理...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 自动化正在不断普…

揭开生成式人工智能的力量:60+医疗保健应用场景

预计生成式AI在医疗保健领域的增长速度将超过任何其他行业。在医疗技术领域&#xff0c;AI可带来更高效流程、个性化客户互动、更大的创新和更高价值。为了帮助领导者理解这些机会&#xff0c;BCG最近研究了医疗技术中生成式AI的60多个应用场景&#xff1a;从产研和软件开发到业…

Android自动化测试,5个必备的测试框架

Appium Appium是一个开源的移动测试工具&#xff0c;支持iOS和Android&#xff0c;它可以用来测试任何类型的移动应用&#xff08;原生、网络和混合&#xff09;。作为一个跨平台的工具&#xff0c;你可以在不同的平台上运行相同的测试。为了实现跨平台的功能&#xff0c;Appi…

关于数据库索引的入门简述

一、简介 数据库索引是现代数据库中高效数据检索的一个重要工具。它在优化查询性能和加快数据检索操作方面发挥着重要作用。这里我们深入了解下数据库索引其内部工作原理、优点和局限性。 二、数据库 1、SQL 数据库 为了理解索引&#xff0c;先说一句数据库&#xff0c;数据库…

Jenkins小技巧汇总

设置变量 设置全局环境变量 全局变量除了系统内置的全局环境变量之外&#xff0c;用户也可以设置全局变量。设置路径&#xff1a;【Dashboard】–>【Manage Jenkins】–>【System Configuration 下的 System】–>【Global properties】从描述中我们可以看到&#xf…

Jetson nano 之 ROS入门 - - 深度学习环境配置

文章目录 前言一、Anaconda安装二、Pytorch 与 TensorFlow 环境配置三、TensorRT 推理引擎配置总结 前言 Jetson Nano是一款由NVIDIA推出的小型计算机&#xff0c;其性能优异、功耗低、体积小巧&#xff0c;非常适合用于嵌入式系统和边缘设备的深度学习应用。Jetson Nano搭载了…

【Git原理与使用】-- 基本操作

目录 添加文件 查看objects中的文件 小结 修改文件 版本回退 回退的回退 小结 撤销修改 情况一&#xff1a;对于工作区的代码&#xff0c;还没有 add 情况二&#xff1a;已经 add &#xff0c;但没有 commit 情况三&#xff1a;已经 add &#xff0c;并且也 commit …

Cordic IP核使用说明以及避坑记录

Cordic IP核使用说明以及避坑记录 参考文章&#xff1a;(140条消息) Vivado cordic IP核rotate和translate使用详解(附有代码)_cordic ip核 rotate_迎风打盹儿的博客-CSDN博客 (140条消息) VIVADO cordic IP核_卡布奇诺加勺糖的博客-CSDN博客 文章目录 Cordic IP核使用说明以及…

面试题:推排序是一种稳定排序吗?

面试题&#xff1a;推排序是一种稳定排序吗&#xff1f; 在回答该问题前&#xff0c;首先需要了解什么是稳定排序。 稳定性就是指对于两个关键字相等的记录&#xff0c;它们在序列中的相对位置&#xff0c;在排序之前和排序之后没有发生改变。通俗地讲就是有两个关键字相等的…

Node.js---菜鸟教程

文章目录 创建第一个应用创建 Node.js 应用 NPM 使用介绍使用 npm 命令安装模块本地安装使用 package.json模块的操作 回调函数阻塞代码实例非阻塞代码 事件循环事件驱动程序 EventEmitterEventEmitter 类方法实例error 事件继承 EventEmitter Buffer&#xff08;缓冲区&#x…

Redis-缓存

新增或者更新数据时,创建以后顺便存到redis中去【维护缓存】 获取的时候先从redis缓存中拿数据 如果拿数据的时候为空,则到数据库中拿数据,后再存到redis缓存中去 大量的商品【包括冷门商品】都进行上面的缓存,那么就很耗内存 针对每个数据进行缓存的时候 维护一个过期时间…

MQTT(一)

MQTT&#xff08;一&#xff09; 1.背景 学习目标&#xff1a;经过了解&#xff0c;Netty占用服务器资源内存大、远距离传感器在极端条件下数据处理兼容较差&#xff08;网络条件差&#xff0c;需要反复重连等&#xff09;。从同行业了解到&#xff0c;现在主流工业传输使用M…

【博学谷学习记录】超强总结,用心分享 | 架构师 zabbix学习总结

文章目录 一、介绍zabbix zabbix专有词汇 二、zabbix zabbix实践修改zabbix zabbix语⾔服务器可视化指标解决zabbix zabbix乱码问题查看监控内容可视化监控agent agent的cpu cpu动态查看模板--监控项⾃定义监控项语法 一、介绍 Zabbix 是由 Alexei Vladishev 开发的⼀种⽹络监…