BMP图片格式分析(超详细)

news2025/1/19 11:08:50

系列文章目录

文章目录

  • 系列文章目录
  • 前言
  • 一、BMP格式概览
  • 二、实战分析bmp图片数据


前言

对学习C++感兴趣的可以看看这篇文章哦:C/C++实战入门到精通

BMP图片大家见的应该也比较多,它是一种非常基本的图片格式

因为最近对C++生成二维码比较感兴趣,用第三方库可以很容易得到二维码的信息

但还需要将生成的二维码源数据保存为图片,而BMP结构稍微简单一点,所以便研究了一下

一、BMP格式概览

BMP文件格式还是比较简单的,总共分为四部分:

  1. BITMAPFILEHEADER结构体,
  2. BITMAPINFOHEADER结构体,
  3. RGBQUAD结构体(这个结构体可以有,也可以没有),
  4. DIB数据区。(Device-Independent Bitmap,设备无关位图)。

在继续探究这些格式之前,我们还需要明白一个概念,即:RGBRedGreenBlue)三原色,我们图片中的像素就是用这三种颜色构成的

我们常看到的8位色,16位色,24位色和32位色这些,实际指的就是用多少位来表示一个颜色(又称位深度)

位 指的是二进制的一位,一个字节(char)有8位

在这里插入图片描述
以8位色为例,即一个char,可以表示的范围为:0 - 28-1,即256种颜色,如果是1位色,那就只能表示两个颜色,即黑白图片

目前主流的是24位色和32位色,所以这里不讨论8位数和16位色

事实上第三个结构体RGBQUAD就是为8位、16位色等较低位数准备的,使用起来也更麻烦

本文以24位色为主。即RGB三原色,各占8位大小,即各占一个字节

如果是32位,则RGB三原色各占8位,还剩下8位用于描述透明度的,即:rgba最后的aAlpha透明度

综上,我们需要了解的就只有前两个结构体,和最后的DIB数据区了

首先来看第一个结构体定义:

typedef struct tagBITMAPFILEHEADER {
        WORD    bfType; //图片种类,BMP图片固定为BM,表示为十六进制就是0x4d42
        DWORD   bfSize; //该图片文件的大小
        WORD    bfReserved1; //保留字,不用管
        WORD    bfReserved2;//保留字,不用管
        DWORD   bfOffBits; //实际图片数据的偏移量,即`DIB`的偏移量,也即前三个结构体的大小
} BITMAPFILEHEADER, FAR *LPBITMAPFILEHEADER, *PBITMAPFILEHEADER;

该结构体中,我们需要在意的只有两个属性:bfSizebfOffBits,分别等于该图片文件的大小,以及DIB数据区前三个结构体的大小

然后是第二个结构体:

typedef struct tagBITMAPINFOHEADER{
        DWORD      biSize; //指定此结构体的长度
        LONG       biWidth; //bmp图片的宽度
        LONG       biHeight; //bmp图片的高度
        WORD       biPlanes; //平面数,显示器只有一个平面,所以一般为1
        WORD       biBitCount; //颜色位数,目前一般用24位或32位
        DWORD      biCompression; //压缩方式,可以是0,1,2,0表示不压缩,BMP为不压缩,所以为0
        DWORD      biSizeImage; //实际位图数据占用的字节数.由于上面不压缩,所以这里填0即可
        LONG       biXPelsPerMeter; //X方向分辨率,即每米有多少个像素,可以省略
        LONG       biYPelsPerMeter; //Y方向分辨率,即每米有多少个像素,可以省略
        DWORD      biClrUsed;  //使用的颜色数,如果为0,则表示默认值(2^颜色位数)
        DWORD      biClrImportant; //重要颜色数,如果为0,则表示所有颜色都是重要的
} BITMAPINFOHEADER, FAR *LPBITMAPINFOHEADER, *PBITMAPINFOHEADER;

这个结构体的信息量非常多,但需要我们填的其实并不多:

  • biSize:指定此结构体的长度,一般都直接为: sizeof(BITMAPINFOHEADER)即可
  • biWidth:图片宽度,需要自己根据需要填
  • biHeight:图片高度,需要自己根据需要填
  • biPlanes:平面数,填1即可
  • biBitCount:位数,本文采用的是24位图,所以填24

除了以上几个需要填的,其它都直接清零即可

由于第三个结构体只有低于24位的才用得到,所以这里不予讨论了

结构体为:

typedef struct tagRGBQUAD {
        BYTE    rgbBlue; //该颜色的蓝色分量
        BYTE    rgbGreen;  //该颜色的绿色分量
        BYTE    rgbRed; //该颜色的红色分量
        BYTE    rgbReserved;  //保留值
} RGBQUAD;

最后是数据区域,由于本文以24位图为主,所以每一个数据都是三个字节,分别代表红绿蓝

二、实战分析bmp图片数据

这里仍然是以24位图为例,用十六进制编辑器打开bmp图片:

在这里插入图片描述

首先来看第一个结构体:BITMAPFILEHEADER,其四个成员变量定义分别为:

  • WORD bfType

WORD,两个字节,这里为42 4D,右边也显示出字符为BM,但由于内存中数据排列高位在左,低位在右,所以代码中我们要写为0x4D42

  • DWORD bfSize

DWORD,4个字节,这里为76 05 00 00,颠倒还原之后为 00 00 05 76,换算为十进制为1398字节
在这里插入图片描述

然后是两个保留字段,没有意义,都为WORD类型,共占4个字节,跳过

然后是

  • DWORD bfOffBits;

DWORD,占4个字节,为36 00 00 00,颠倒还原后为00 00 00 36 ,换算为10进制为:54,两个结构体大小分别为:14 和 40 符合

在这里插入图片描述

然后再来看第二个结构体:

  • DWORD biSize;

占4个字节,为28 00 00 00 ,还原后为00 00 00 28,换算为十进制为:40,符合该结构体的大小

  • LONG biWidth;

4字节,为15 00 00 00,颠倒还原,转换为10进制为21

  • LONG biHeight;

4字节,EB FF FF FF,颠倒后为 FF FF FF EB,第一位为F(即1111),二进制首位为1,说明它为负数,转换为10进制后为 -21,可参考官方文档对它的说明:

在这里插入图片描述

简单来说,就是该数如果为正,那么该图片的数据就是倒着放的,先放倒数第一行的数据,然后是倒数第二行,最后放第一行

而如果为负数,则相反,数据正着放,更符合我们的直观

同样符合:

在这里插入图片描述

  • WORD biPlanes;

2字节,为01 00 ,还原后就是1,即一个平面数,符合

  • WORD biBitCount;

2字节,为18 00,还原后为24,即24位图,符合

  • DWORD biCompression;

4字节,为00 00 00 00 ,即为0,未压缩,符合

  • DWORD biSizeImage;

4字节,同样是00 00 00 00,由于未压缩,所以该字段为0,符合

最后四个字段,都为4字节,即16个字节。都为0,即默认值,符合
在这里插入图片描述

结束了前面两个结构体的解析,后面就是真正的颜色数据了,但由于这张图片是一个我自己生成的二维码:

在这里插入图片描述
所以只有两种色值,即黑色(rgb均为 0)与白色(rgb均为0xFF)

随便举个例子:
在这里插入图片描述
分别三个字节,即24位表示一个颜色,00 00 00 代表一个黑色点,而 FF FF FF则代表一个白色点

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

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

相关文章

【golang】rune

一、背景 来看下2023.1.11的每日一题,是个简单题 2283. 判断一个数的数字计数是否等于数位的值几乎都有思路,先遍历一遍把数存在map中,第二次遍历直接判断就可以。 二、解答 我的解答(很久不写代码了) 开始想着map的…

autoCell:用于scRNA-seq的分析工具

目录简介引言相关工作贡献数据集和对比方法autoCell高斯混合模型图嵌入结果插补去噪后轨迹分析潜在特征捕获细胞病理学发现细胞类型特异性分子网络简介 动机:scRNA-seq使研究人员能够以单细胞分辨率研究基因表达。然而,由dropout引起的噪声可能会妨碍精…

mac快速配置iterm2

文章目录安装 iterm2设置为默认终端安装 oh-my-zsh 设置默认 shell查看 shell 有几种安装 oh-my-zsh设置默认 shell配置主题安装插件安装高亮插件设置快捷键安装 iterm2 自行官网下载 iterm2 设置为默认终端 Mac 默认终端即“终端”,我们可以把好用的 iterm2 设置…

Pytorch复习笔记--导出Onnx模型为动态输入和静态输入

目录 1--动态输入和静态输入 2--Pytorch API 3--完整代码演示 4--模型可视化 5--测试动态导出的Onnx模型 1--动态输入和静态输入 当使用 Pytorch 将网络导出为 Onnx 模型格式时,可以导出为动态输入和静态输入两种方式。动态输入即模型输入数据的部分维度是动态…

Elasticsearch:运用 Go 语言实现 Elasticsearch 搜索 - 8.x

在我之前的文章 “Elasticsearch:Go 客户端简介 - 8.x”,我对 Elasticsearch golang 客户端做了一个简单的介绍。在今天的这篇文章中,我将详细介绍如何使用这个客户端来一步一步地连接到 Elasticsearch,进而创建索引,搜…

流程编辑器bpmnjs的改造1:设计器外观和布局

重新设计页面,弄一个比较规范的设计器外观和布局,bpmnjs.css加入如下的代码:/* Frame CSS */html,body{width:100%;height:100%}.toolsBar{position:fixed;width:100%;height:40px;background-color:#FFF; border-bottom:1px solid #E1E1E1;d…

Linux安装Docker完整详细教程

目录 Docker及系统版本 Docker的自动化安装 Docker的手动安装(CentOS7) 1.1 卸载历史版本的Docker 1.2 安装依赖包 1.3 更新本地镜像源(也可以叫做:设置源仓库) 1.4 Docker安装 1.5 配置镜像加速 Docker启动 删除Docker Docker其…

连接池PgBouncer部署与踩坑实践

安装 可以直接使用 yum install pgbouncer 安装(rpm管理的是1.14版本) 或者在http://www.pgbouncer.org/downloads/ 下载最新的tat.gz包 解压出来进入目录,通过 ./configure --prefix/home/pgbouncermake & make install 安装&…

01等概率发生器、随机函数、对数器

1.数据结构 数据结构:是由连续结构、跳转结构或者连续加跳转(可能有多个叉)结构组成 数据结构是很多算法得以进行的载体 数组:便于寻址不便于删增数据(需要不断移动数据,如果不动可能就不是连续结构) 链表(跳转结构…

jupyter notebook 暗黑模式新方法

1 直接浏览器采用暗黑模式 (1)首先我们打开谷歌浏览器,在浏览器地址栏中输入“chrome://flags”然后按下回车键。 (2)之后我们会进入谷歌浏览器的实验室页面,在页面左上方的搜索框中输入“enable-force-…

DocuWare客户案例——温德姆镇使用 DocuWare Cloud 改善市民服务

DocuWare客户案例——温德姆镇使用 DocuWare Cloud 改善市民服务 新冠疫情刚开始时,州和地方政府除了发挥传统作用以外,还要负责遏制疫情的关键措施。税收和联邦援助的收入没有增加,跟不上这一新职责的需求。采用减轻管理负担的技术是节省资源…

2022十大边缘计算开源项目

随着“开源”被纳入“十四五”规划发展纲要,“支持数字技术开源社区等创新联合体发展,完善开源知识产权和法律体系,鼓励企业开放软件源代码、硬件设计和应用服务”。开源发展按下了加速键! 开源软件生态蓬勃发展,边缘…

Internet结构和ISP

目录 1. ISP / IXP / ICP 定义 2. 网络连接宏观结构 3. 网络连接层级结构 4. ISP 连接方式 1. ISP / IXP / ICP 定义 ISP:Internet Service Provider,即互联网服务提供商。主要为用户提供互联网接入业务、信息业务的运营商,如移动和电信等。 …

数据结构学习之栈

这里写目录标题栈的定义与性质栈的实现栈的定义栈的功能栈的创建入栈出栈栈顶判断栈为空得到栈的个数栈的销毁栈的定义与性质 第一个问题:什么是栈? 栈的定义是: 一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。…

【从零开始学习深度学习】45. Pytorch迁移学习微调方法实战:使用微调技术进行2分类图片热狗识别模型训练【含源码与数据集】

通常为了使模型的预测精度达到较高的标准,需要收集十分庞大的数据集来进行模型训练。一种比较巧妙解决该问题的办法是应用迁移学习(transfer learning),将从某个已有的数据集学到的知识迁移到目标数据集上。例如,假如我…

微信小程序安装 Vant 组件库与API Promise组件库并实现简单的增删改查

在项目内右键空白处选择在外部终端打开2、在终端窗口输入 npm init -y,创建package-lock.jsonnpm init -y3、在终端输入npm i vant/weapp1.3.3 -S --production,创建node_modules文件夹npm i vant/weapp1.3.3 -S --production4、详情-本地设置&#xff0…

Vue2.0开发之——Vue组件-组件的实例对象(36)

一 概述 浏览器无法直接解析Vue文件package.json中的’vue-template-compiler’将vue结尾的文件解析为js文件交给浏览器处理Count组件实例对象 二 浏览器无法直接解析Vue文件 将Vue文件拖放到浏览器中无法直接显示 三 package.json中的’vue-template-compiler’将vue结尾的文…

软件著作权登记指南

一、什么是计算机软件《计算机软件保护条例》第二条、第三条规定,本条例所称计算机软件(以下简称软件),是指计算机程序及其有关文档;(一)计算机程序,是指为了得到某种结果而可以由计…

第13章 Token的Postman、Swagger和Vue调试

1 准备工作 1.1 WebApi.Controllers.JwtSettingModel namespace WebApi.Test { /// <summary> /// 【Jwt设置模型--纪录】 /// <remarks> /// 摘要&#xff1a; /// 通过该纪录中的属性成员实例存储“AppSettings.json”文件中的Jwt相关设置数据&#xff0…

java应用程序多级缓存架构

多级缓存架构 一级缓存&#xff1a;OpenResty—Lua—Redis 二级缓存&#xff1a;Nginx proxy-cache 三级缓存&#xff1a;Redis 使用OpenResty lua脚本访问redis proxy-cache 缓存注解 <!--依赖--> <dependency><groupId>org.springframework.boot</gr…