逆寒手游活动资讯网

解读BMP图片

最近在提取《基连的野望 阿克西斯V》的MRG文件时接触了BMP图片,于是从底层对BMP图片进行研究,学习BMP图片的显示和成像原理。

BMP图片简介

BMP图片是一种栅格图片,BMP图片的每一个像素都由一个比特位(bit)或多个比特位(bits)表示,因此BMP全称是bitmap 或 a map of bits and pixels。

BMP是Windows操作系统中的标准图像文件格式,也是众多早期游戏广泛应用的图片格式,从游戏贴图到游戏字幕都可以是BMP图片。

BMP是一种没有经过压缩的图片格式,也就是说,BMP图片的每一个像素有自己的比特位(或一组比特位),常见的PNG或JPEG则不同,这些是经过压缩技术对图片的信息进行压缩,以达到减小图片体积的目的。因此多数情况下,显示相同的图像,BMP图片的大小总是最大的。

BMP图片组成

本文使用以下BMP图为例进行说明,图片另存为可将图片保存到本地。

使用十六进制打开图片,看到部分图片信息如下:

看似杂乱无章的显示,其实bmp图片由以下四部分组成:

文件头(bit map file header): 共14字节

位图信息头(bitmap information): 共40字节

调色板(color palette): 可选

位图数据(pixel data): 可选

下面将对每部分进行详细解读。

注:本文涉及16进制读取均使用小端模式(little-endian)。

第一部分:文件头(bit map file header)

此部分一共包含14个字节,例子中的图片对应的内容为:

一共5个字段,每个字段如下:

字段名

大小

描述

FileType(文件类型)

2 bytes

文件类型,BMP两字节是0x4D42,ASCII字符对应为“BM”

FileSize(文件大小)

4 bytes

文件大小,对应的值单位为字节。例子中的值为0xC016,十进制为49174字节,对应为49KB。

Reserved(保留位)

2 bytes

2位保留位预留给图片渲染应用,初始化必须为0

Reserved(保留位)

2 bytes

同上

PixelDataOffset(从头到位图数据的偏移)

4 bytes

表示从文件头到位图数据的偏移,例子图片的值是0x00000436,十进制是1078,这个值在第三部分调色板会进行验证

第二部分:位图信息头(bitmap information)

此部分一共包含40个字节,例子中的图片对应的内容为:

一共11个字段,每个字段如下:

字段名

大小

描述

HeaderSize

4 bytes

信息头大小,即0x28,十进制为40

ImageWidth

4 bytes

图片宽度,单位像素。例子图片为0x0120,十进制为288,即288px,与实际符合

ImageHeight

4 bytes

图片高度,单位像素。例子图片为0x00A7,十进制为167,即167px,与实际符合

Planes

2 bytes

目标设备说明颜色平面数,总被设置为1

BitsPerPixel

2 bytes

定义颜色的每个像素有多少位,也称为颜色深度,简称bpp,值有1、2、4、8、16、24、32。例子图片值为0x0008,表示每个像素用8位表示,一共有2^8 = 256个颜色

Compression

4 bytes

图像的压缩类型,最常用的就是0(BI_RGB),表示不压缩

ImageSize

4 bytes

位图数据的大小,当用BI_RGB格式时,可以设置为0

XpixelsPerMeter

4 bytes

水平分辨率,单位是像素/米,有符号整数

YpixelsPerMeter

4 bytes

垂直分辨率,单位是像素/米,有符号整数

TotalColors

4 bytes

位图使用的调色板中的颜色索引数,为0说明使用所有

ImportantColors

4 bytes

对图像显示有重要影响的颜色索引数,为0说明都重要

第三部分:调色板(color palette)

调色板就是颜色的索引,但调色板是可选的。由于每个颜色都有RGB三原色,也就是要3个字节表示(例如白色表示为#FFFFFF),当bpp≤8时,2^bpp 所计算出来的颜色就无法表示全部的颜色,因此对于bpp≤8的图片就必须使用调色板,下表展示各种位图的调色板情况:

BitsPerPixel(bpp)

调色板

颜色数量

描述

1

2

调色板中最多只能存在2种颜色

4

8

调色板中最多只能存在8种颜色

8

256

调色板中最多只能存在256种颜色

16

65536

可直接使用RGB三原色,每种原色用5bit表示

24

16M (16777215)

可直接使用RGB三原色,每种原色用8bit表示

32

4B (4294967296)

可直接使用RGBA,每种原色用8bit表示,加8bit Alpha

例子图片中bpp为8,因此每个像素只能有256钟颜色,为了增加图片表现形式,就需要一个索引,使用一个字节表示索引指向4个字节(RGB加Alpha值)。如果把这4个字节表示为一个Color类型,那么调色板就是Color的数组。由于Color类型也是一个数组,调色板就像一个二维数组palette[N][4],其中N是颜色的数量,这里就是256。因此,这个例子中的调色板的大小就是256x4=1024字节,在调色板之前,有14字节的bmp文件头,40字节的位图信息头,加上1024字节的调色板,一共1078字节,也就是说真正的图像数据前面有1078字节,这和bmp文件头中的bfOffBits相符。

第四部分:位图数据(pixel data)

最后就是位图数据,该区域存放的是每个像素的颜色值,以行的形式展示,这个取决于图片的颜色深度(bpp)。同时BMP图片扫描引擎的最小单位是4字节,因此在扫描每一行时,要求每一行的数据长度必须是4的倍数,不足的行将进行比特填充(bit padding)。

BMP扫描

当图片引擎读取了一张BMP图片,从文件头信息读取数据后,引擎就知道该如何扫描BMP数据,进而把图像展示在用户面前。BMP图像扫描使用从左下角开始到右上角,以行为主序进行扫描。下图以一个4px X 4px的图像为例:

构建24位BMP图

经过以上图片组成的详细解说了,相信读到这里的你已经以上众多字段忘的差不多了,没关系,接下来我们将通过自己编写十六进制,运用上述原理自己构建一个5px X 5px的24位bmp图像。

首先初始化文件头(第一部分)和位图信息头(第二部分),这两部分一共占据14+40=54个字节。初始化数据如下:

字段

大小

FileType

2 bytes

0x42 0x4D

FileSize

4 bytes

0x00 0x00 0x00 0x00

Reserved

2 bytes

0x00 0x00

Reserved

2 bytes

0x00 0x00

PixelDataOffset

4 bytes

0x36 0x00 0x00 0x00

HeaderSize

4 bytes

0x28 0x00 0x00 0x00

ImageWidth

4 bytes

0x05 0x00 0x00 0x00

ImageHeight

4 bytes

0x05 0x00 0x00 0x00

Planes

2 bytes

0x01 0x00

BitsPerPixel

2 bytes

0x18 0x00

Compression

4 bytes

0x00 0x00 0x00 0x00

ImageSize

4 bytes

0x00 0x00 0x00 0x00

XpixelsPerMeter

4 bytes

0x00 0x00 0x00 0x00

YpixelsPerMeter

4 bytes

0x00 0x00 0x00 0x00

TotalColors

4 bytes

0x00 0x00 0x00 0x00

ImportantColors

4 bytes

0x00 0x00 0x00 0x00

初始化数据中多数字段都设置为0,有一些非0数据这里做下解释:

FileType: 固定值0x42 0x4D,表示BM。

PixelDataOffset: 从头到位图数据的偏移,一共是54bytes,使用十六进制表示即为0x36。

HeaderSize: 文件头大小,同40bytes,十六进制表示为0x28。

ImageWidth: 图片宽度,5px,十六进制表示为0x05

ImageHeight: 图片高度,5px,十六进制表示为0x05

Planes:固定值1

BitsPerPixel:bpp,24位图,值为24,十六进制表示为0x18

将上述数据随便写入一个文本编辑器中,如下:

42 4D

00 00 00 00

00 00

00 00

36 00 00 00

28 00 00 00

05 00 00 00

05 00 00 00

01 00

18 00

00 00 00 00

00 00 00 00

00 00 00 00

00 00 00 00

00 00 00 00

00 00 00 00

新建一个test.bmp文件,使用十六进制编辑器打开图片,将以上内容复制到图片中,此时一个24位的bmp图片的基本头已经形成,但此时还无法打开文件,因为还缺少了和颜色相关的位图数据,我们把他补上。

24位图,即每个颜色都可以使用24比特位表示,例如#000000的颜色:

十六进制表示:

00 00 00

-- -- --

R G B

二进制表示:

00000000 00000000 00000000

-------- -------- --------

R G B

由于是5x5的图片,因此每一行需要5x3bytes,但扫描行的原则需要每行字节数为4的倍数,因此最后还需加上1个字节进行填充(0x00),故完整的位图数据如下:

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

拼上文件头和文件信息头,完整的图片数据如下:

42 4D

00 00 00 00

00 00

00 00

36 00 00 00

28 00 00 00

05 00 00 00

05 00 00 00

01 00

18 00

00 00 00 00

00 00 00 00

00 00 00 00

00 00 00 00

00 00 00 00

00 00 00 00

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

将数据写入test.bmp中,打开图片,就可以看到一个5x5的黑色图:

之后我们来改变下颜色:

FF FF FF 00 00 00 00 00 00 00 00 00 00 FF FF 00

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

00 00 00 00 00 00 00 FF 00 00 00 00 00 00 00 00

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

00 00 FF 00 00 00 00 00 00 00 00 00 FF 00 00 00

可以验证BMP图片扫描顺序为左下到右上。

构建16位BMP图

16位和24位的区别主要在于位图数据的表现形式不同。16位图是一个像素只有16位表示,即一种颜色只能用16位表示,因此一种三原色只能用5位表示(最高位为0):

[ 0 XXXXX XXXXX XXXXX ]

----- ----- -----

R G B

因此24位的颜色转为16位颜色如下:

RED 0111110000000000 => 01111100 00000000 => 0x7C 0x00

GREEN 0000001111100000 => 00000011 11100000 => 0x03 0xE0

BLUE 0000000000011111 => 00000000 00011111 => 0x00 0x1F

WHITE 0111111111111111 => 01111111 11111111 => 0x7F 0xFF

YELLOW 0111111111100000 => 01111111 11100000 => 0x7F 0xE0

即:每种颜色只能使用2个字节表示,对于5x5的图片,每行字节数需为4的倍数,因此每行最后还需填充2个字节:

42 4D

00 00 00 00

00 00

00 00

36 00 00 00

28 00 00 00

05 00 00 00

05 00 00 00

01 00

10 00

00 00 00 00

00 00 00 00

00 00 00 00

00 00 00 00

00 00 00 00

00 00 00 00

FF 7F 00 00 00 00 00 00 E0 7F 00 00

00 00 00 00 00 00 00 00 00 00 00 00

00 00 00 00 E0 03 00 00 00 00 00 00

00 00 00 00 00 00 00 00 00 00 00 00

00 7C 00 00 00 00 00 00 1F 00 00 00

最后test.bmp图片显示依旧和24位一致,只是16位图片文件更小了。

总结

本文针对bmp图像进行文件结构解析,并逐一解释内部信息的含义,最后通过十六进制编写的方法实现了24位图和16位图以加强对bmp图像的理解,对bmp图像的描述本文可能有错误或遗漏之处,欢迎反馈和指点。

(完)

原创不易,如果觉得这篇文章对你有帮助,不如赏杯咖啡吧

微信

支付宝

← 上一篇

下一篇 →

2026-08-28 19:07:10


性高潮与射精量:提升性体验的方法与注意事项
劲字五行属什么五行