Skip to content

LV060-显示BMP图片 ​

一、BMP 图片格式 ​

这个可以直接看《LV015-BMP 文件格式 | Media》这篇笔记,这篇笔记详细学习了 BMP 文件格式。不过这里还是简单的再了解一下。

1. BMP 图像介绍 ​

我们常用的图片格式有很多,一般最常用的有三种: JPEG(或 JPG)、 PNG、 BMP 和 GIF。其中 JPEG(或 JPG)、 PNG 以及 BMP 都是静态图片,而 GIF 则可以实现动态图片。

BMP(全称 Bitmap)是 Window 操作系统中的标准图像文件格式,文件后缀名为“.bmp”,使用非常广。它采用位映射存储格式,除了图像深度可选以外,图像数据没有进行任何压缩,因此, BMP 图像文件所占用的空间很大,但是没有失真、 并且解析 BMP 图像简单。

BMP 文件的图像深度可选 lbit、 4bit、 8bit、 16bit、 24bit 以及 32bit, 典型的 BMP 图像文件由四部分组成:

①、 BMP 文件头(BMP file header),它包含 BMP 文件的格式、大小、 位图数据的偏移量等信息;

②、位图信息头(bitmap information) ,它包含位图信息头大小、 图像的尺寸、 图像大小、 位平面数、压缩方式以及颜色索引等信息;

③、调色板(color palette),这部分是可选的,如果使用索引来表示图像, 调色板就是索引与其对应颜色的映射表;

④、位图数据(bitmap data),也就是图像数据。

BMP 文件头、位图信息头、调色板和位图数据, 总结如下表所示:

数据段名称大小(Byte)说明
bmp 文件头 (bmp file header)14包含 BMP 文件的格式、大小、到位图数据的 偏移量等信息
位图信息头 (bitmap information)通常为 40 或 56 字节包含位图信息头大小、 图像的尺寸、图像大 小、位平面数、 压缩方式以及颜色索引等信 息;
调色板 (color palette)由颜色索引数决定可选,如果使用索引来表示图像的颜色, 则调 色板就是索引与其对应颜色的映射表;
位图数据 (bitmap data)由图像尺寸决定图像数据

一般常见的图像都是以 16 位(R、 G、 B 三种颜色分别使用 5bit、 6bit、 5bit 来表示)、 24 位(R、 G、B 三种颜色都使用 8bit 来表示) 色图像为主,我们称这样的图像为真彩色图像, 真彩色图像是不需要调色板的,即位图信息头后面紧跟的就是位图数据了。

对某些 BMP 位图文件说并非如此, 如 16 色位图、 256 色位图,它们需要使用到调色板,具体调色板如何使用,我们不关心,这里我们将会以 16 位色(RGB565) BMP 图像为例进行学习。

2. BMP 图像格式 ​

以一张 16 位 BMP 图像为例(这张图在迁移笔记的时候找不到了,不过可以看LV015-BMP 文件格式 | Media,这里分析的更详细一些),首先在 Windows 下查看该图片的属性,如下所示:

image-20241002075835226

可以看到该图片的分辨率为 800*480,位深度为 16bit,每个像素点使用 16 位表示,也就是 RGB565。接下来使用十六进制查看工具将 image.bmp 文件打开,文件头部分的内容如下所示:

image-20241002075859486

1. bmp 文件头 ​

Windows 下为 bmp 文件头定义了如下结构体:

c
typedef struct tagBITMAPFILEHEADER
{
    UINT16 bfType;
    DWORD bfSize;
    UINT16 bfReserved1;
    UINT16 bfReserved2;
    DWORD bfOffBits;
} BITMAPFILEHEADER;

结构体中每一个成员说明如下:

变量名地址偏移大小作用
bfType00H2 bytes说明 bmp 文件的类型,可取值为: ①BM – Windows ②BA – OS/2 Bitmap Array ③CI – OS/2 Color Icon④CP – OS/2 Color Pointer ⑤IC – OS/2 Icon ⑥PT – OS/2 Pointer
bfSize02H4 bytes说明该文件的大小,以字节为单位。
bfReserved106H2 bytes保留字段,必须设置为 0。
bfReserved208H2 bytes保留字段,必须设置为 0。
bfOffBits0AH4 bytes说明从文件起始位置到图像数据之间的字节偏移量。 这个参数非常有用,因为位图信息头和调色板的长度 会根据不同的情况而变化,所以我们可以用这个偏移 量迅速从文件中找到图像数据的偏移地址。

bmp 文件头的大小固定为 14 个字节。 从上面的描述信息,再来对照文件数据:

image-20241002080311946

00~01H: 0x42、 0x4D 对应的 ASCII 字符分别为为 B、 M,表示这是 Windows 所支持的位图格式,该字段必须是“BM”才是 Windows 位图文件。

02~05H: 对应于文件大小, 0x000BB848 = 768072 字节,与 image.bmp 文件大小是相符的。

06~09H: 保留字段。

0A~0D: 0x00000046 = 70,即从文件头部开始到位图数据需要偏移 70 个字节。

1.2 位图信息头 ​

同样, Windows 下为位图信息头定义了如下结构体:

c
typedef struct tagBITMAPINFOHEADER {
    DWORD biSize;
    LONG biWidth;
    LONG biHeight;
    WORD biPlanes;
    WORD biBitCount;
    DWORD biCompression;
    DWORD biSizeImage;
    LONG biXPelsPerMeter;
    LONG biYPelsPerMeter;
    DWORD biClrUsed;
    DWORD biClrImportant;
} BITMAPINFOHEADER;

结构体中每一个成员说明如下 :

变量名地址偏移大小作用
biSize0EH4 bytes位图信息头大小。
biWidth12H4 bytes图像的宽度,以像素为单位。
biHeight16H4 bytes图像的高度,以像素为单位。 注意,这个值除了用于描述图像的高度之外, 它还有另外一个用途,用于指明该图像是倒向 的位图、还是正向的位图。 如果该值是一个正数,说明是倒向的位图;如果该值是一个负数,则说明是正向的位图。 一般情况下, BMP 图像都是倒向的位图,也就是该值是一个正数。
biPlanes1AH2 bytes色彩平面数,该值总被设置为 1。
biBitCount1CH2 bytes像素深度,指明一个像素点需要多少个 bit 数据 来描述,其值可为 1、 4、 8、 16、 24、 32
biCompression1EH4 bytes说明图像数据的压缩类型,取值范围如下: ①0 – RGB 方式 ②1 – 8bpp 的 RLE 方式,只用于 8bit 位图 ③2 – 4bpp 的 RLE 方式, 只用于 4bit 位图 ④3 – Bit-fields 方式 ⑤4 – 仅用于打印机 ⑥5 – 仅用于打印机
biSizeImage22H4 bytes说明图像的大小,以字节为单位,当压缩类型 为 BI_RGB 时,可设置为 0。
biXPelsPerMeter26H4 bytes水平分辨率,用像素/米来表示,有符号整数。
biYPelsPerMeter2AH4 bytes垂直分辨率,用像素/米来表示,有符号整数。
biClrUsed2EH4 bytes说明位图实际使用的彩色表中的颜色索引数。
biClrImportant32H4 bytes说明对图像显示有重要影响的颜色索引的数 目,如果是 0,则表示都重要。

从上面的描述信息,再来对照文件数据:

image-20241002080638895

0E~11H: 0x00000038 = 56,这说明这个位图信息头的大小为 56 个字节。

12~15H: 0x00000320 = 800,图像宽度为 800 个像素,与文件属性一致。

16~19H: 0x000001E0 = 480,图像高度为 480 个像素,与文件属性一致;这个数是一个正数,说明是一个倒向的位图,什么是正向的位图、什么是倒向的位图, 说的是图像数据的排列问题; 如果是正向的位图, 图像数据是按照图像的左上角到右下角方式排列的,水平方向从左到右,垂直方向从上到下。倒向的位图,图像数据则是按照图像的左下角到右上角方式排列的,水平方向依然从左到右,垂直方向改为从下到上。

1A~1BH: 0x0001 = 1,这个值总为 1。

1C~1DH: 0x0010 = 16,表示每个像素占 16 个 bit。

1E~21H: 0x00000003 = 3, bit-fileds 方式。

22~25H: 0x000BB802 = 768002,图像的大小,注意图像的大小并不是 BMP 文件的大小,而是图像数据的大小。

26~29H: 0x00000EC2 = 3778,水平分辨率为 3778 像素/米。

2A~2DH: 0x00000EC2 = 3778,垂直分辨率为 3778 像素/米。

2E~31H: 0x00000000 = 0,本位图未使用调色板。

32~35H: 0x00000000 = 0。

只有压缩方式选项被设置为 bit-fileds(0x3) 时, 位图信息头的大小才会等于 56 字节,否则,为 40 字节。 56 个字节相比于 40 个字节,多出了 16 个字节, 那么多出的 16 个字节数据描述了什么信息呢? 稍后再学习。

1.3 调色板 ​

调色板是单色、 16 色、 256 色位图图像文件所持有的,如果是 16 位、 24 位以及 32 位位图文件,则 BMP 文件组成部分中不包含调色板,这里就不深入了解了。

1.4 位图数据 ​

位图数据其实就是图像的数据, 对于 24 位位图,使用 3 个字节数据来表示一个像素点的颜色,对于 16 位位图,使用 2 个字节数据来表示一个像素点的颜色,同理, 32 位位图则使用 4 个字节来描述。BMP 位图分为正向的位图和倒向的位图,主要区别在于图像数据存储的排列方式, 如下如所示(左边对应的是正向位图,右边对应的则是倒向位图) :

image-20241002080754732

所以正向位图先存储图像的第一行数据,从左到右依次存放,接着存放第二行,依次这样;而倒向位图,则先存储图像的最后一行(倒数第一行)数据,也是从左到右依次存放,接着倒数二行,依次这样。

二、RGB 和 Bit-Fields ​

当图像中引用的色彩超过 256 种时,就需要 16bpp 或更高 bpp 的位图(24 位、 32 位)。调色板不适合 bpp 较大的位图,因此 16bpp 及以上的位图都不使用调色板,不使用调色板的位图图像有两种编码格式:RGB 和 Bit-Fields(下称 BF) 。

RGB 编码格式是一种均分的思想, 使 Red、 Green、 Blue 三种颜色信息容量一样大,譬如 24bpp-RGB,它通常只有这一种编码格式,在 24bits 中,低 8 位表示 Blue 分量;中 8 为表示 Green 分量;高 8 位表示 Red 分量。

而在 32bpp-RGB 中,低 24 位的编码方式与 24bpp 位图相同,最高 8 位用来表示透明度 Alpha 分量。32bpp 的位图尺寸太大,一般只有在图像处理的中间过程中使用。对于需要半透过效果的图像,更好的选择是 PNG 格式。

BF 编码格式与 RGB 不同,它利用位域操作,人为地确定 RGB 三分量所包含的信息容量。 位图信息头介绍中提及到,当压缩方式选项置为 BF 时, 位图信息头大小比平时多出 16 字节, 这 16 个字节实际上是 4 个 32bit 的位域掩码, 按照先后顺序,它们分别是 R、 G、 B、 A 四个分量的位域掩码, 当然如果没有 Alpha 分量,则 Alpha 掩码没有实际意义。

位域掩码的作用是指出 R、 G、 B 三种颜色信息容量的大小,分别使用多少个 bit 数据来表示,以及三种颜色分量的位置偏移量。例如对于 16 位色的 RGB565 图像,通常使用 BF 编码格式,同样这也是 BF 编码格式最著名和最普遍的应用之一, 它的 R、 G 和 B 分量的位域掩码分别是 0xF800、 0x07E0 和 0x001F,也就是 R 通道使用 2 个字节中的高 5 位表示, G 通道使用 2 个字节中的中间 6 位表示。而 B 通道则使用 2 个字节中的最低 5 位表示, 如下图所示:

image-20241002080958549

三、如何得到 16 位色 RGB565 格式 BMP 图像? ​

在 Windows 下我们转换得到的 BMP 位图通常是 24 位色的 RGB888 格式图像,那如何得到 RGB565 格式 BMP 位图呢?当然这个方法很多,这里可以通过 Photoshop 软件来得到 RGB565 格式的 BMP 位图。

imgimgimg

首先,找一张图片,图片格式无所谓,只要 Photoshop 软件能打开即可;确定图片之后,我们启动 Photoshop 软件,并且使用 Photoshop 软件打开这张图片, 打开之后点击菜单栏中的【文件】→ 【存储为】,接着出现上图最左侧的界面:

在这个界面中,首先选择文件保存的路径,然后设置文件名以及文件格式,选择文件格式为 BMP 格式,之后点击保存,如上面中间的图片所示。然后点击选择 16 位色图,接着点击高级模式按钮,再点击选择 RGB565,接着点击确定按钮即可,这样就可得到 16 位色 RGB565 格式的 BMP 图像。

四、LCD 显示 BMP 图像实例 ​

1. 代码编写 ​

代码及 Makefile 可以看这里:LV18_LCD_DEVICE/03_lcd_show_bmp · linux-dev-org/imx6ull-app-demo

2. 开发板测试 ​

直接在终端执行以下命令即可:

shell
./app_demo image.bmp
image-20241002084850923