micropython驱动ST7789v液晶屏幕显示24位真彩BMP文件图片

您所在的位置:网站首页 tft32位真彩色 micropython驱动ST7789v液晶屏幕显示24位真彩BMP文件图片

micropython驱动ST7789v液晶屏幕显示24位真彩BMP文件图片

2023-07-05 01:37| 来源: 网络整理| 查看: 265

继续折腾ST7789v液晶屏幕,这次我们要在屏幕上显示BMP文件图片。

一、BMP图片文件格式

BMP图片文件格式问题,网上有很多文章能找到,我也找了很多资料来学习。关于文件头的问题,网上的文章大概都讲得很透彻。我只是拿这个ST7789v液晶来玩玩,没那么多时间去研究和兼容每种格式,所以我只打算锚定其中一种比较简单的24位真彩色格式来显示在我的液晶上,其他格式可以在电脑上转换成24位真彩色格式后再传给液晶。

所以,在文章的开头,我还是得啰嗦一下24位真彩色格式的BMP文件结构。

BMP文件包含四个部分: 1.位图文件头(BITMAPFILEHEADER)(14字节) 2.位图信息头(BITMAPINFOHEADER)(40字节) 3.颜色表*(RGBQUAD[])(不一定存在) 4.像素阵列(Pixels[][])(图像数据)

其中1和2是固定的大小;3在24位真彩色格式中是没有的,可以忽略;4就是图像数据了。

1.文件头

文件头的结构定义如下:

typedef struct tagBITMAPFILEHEADER{         WORD    bfType;                  // 位图文件的类型,必须为BMP (2个字节)         DWORD    bfSize;                  // 位图文件的大小,以字节为单位 (4个字节)         WORD    bfReserved1;             // 位图文件保留字,必须为0 (2个字节)         WORD    bfReserved2;             // 位图文件保留字,必须为0 (2个字节)         DWORD    bfOffBits;               // 位图数据的起始位置,以相对于位图 (4个字节)     } BITMAPFILEHEADER;

其中文件的大小bfSize稍微有点用,可以用以下代码读取出来:

f.seek(2)#文件大小 buff=f.read(4) fileSize=buff[3]*1024+buff[2]*512+buff[1]*256+buff[0] print("BMP文件大小:",fileSize,"字节")

下图是本文所用的一张图片用二进制编辑器打开后的文件大小数值。

 注意,低位在后,高位在前。图中文件大小是十六进制的0x00016926,十进制是92454字节。

后续占用多个字节的数值都是用这种低位在后,高位在前的规则。

2.信息头

信息头的结构体定义如下: typedef struct tagBITMAPINFOHEADER{         DWORD biSize;             // 本结构所占用字节数  (4个字节)         LONG biWidth;              // 位图的宽度,以像素为单位(4个字节)         LONG biHeight;             // 位图的高度,以像素为单位(4个字节)         WORD biPlanes;            // 目标设备的级别,必须为1(2个字节)         WORD biBitCount;         // 每个像素所需的位数,必须是1(双色)、// 4(16色)、8(256色)、                                 //24(真彩色)或32(增强真彩色)之一 (2个字节)         DWORD biCompression;     // 位图压缩类型,必须是 0(不压缩)、 1(BI_RLE8                                  // 压缩类型)或2(BI_RLE4压缩类型)之一 ) (4个字节)         DWORD biSizeImage;         // 位图的大小,以字节为单位(4个字节)         LONG biXPelsPerMeter;      // 位图水平分辨率,每米像素数(4个字节)         LONG biYPelsPerMeter;   // 位图垂直分辨率,每米像素数(4个字节)         DWORD biClrUsed;        // 位图实际使用的颜色表中的颜色数(4个字节)         DWORD biClrImportant;   // 位图显示过程中重要的颜色数(4个字节)     } BITMAPINFOHEADER;

其中有几个信息是必须要取出来的。

biWidth;              // 位图的宽度,以像素为单位(4个字节),--即图片横向的像素宽度。

biHeight;             // 位图的高度,以像素为单位(4个字节),--即图片纵向的像素高度。

biBitCount;         // 每个像素所需的位数,必须是1(双色)、// 4(16色)、8(256色)、                                 //24(真彩色)或32(增强真彩色)之一 (2个字节)。---判断图片格式是不是24位真彩色

3.颜色表

24位真彩色格式没有颜色表,直接忽略。

4.像素阵列

很多文章里没有详细介绍这部分的格式,我也走了写弯路,所以我必须把这部分详细讲一下。

24位真彩色文件格式里,像素阵列是从第55个字节开始的(文件头14+信息头40),从0开始的话是54。

1个像素占3个字节,顺序分别是B、G、R(注意顺序不是RGB!!!)。

但是的但是,你要注意了!第55字节并不是图片左上第一个像素点!!!

数据的规律是这样的。

首先,由于某些原因(DWORD),像素阵列对图片每一行数据的字节数进行了约束,必须是4的整数倍。比如,图像横向时5个像素点,每像素3字节,3*5=15字节;为了是4的倍数,这时就会填充以0x00填充1个字节。这时图片一行所占用的字节数是16,而不是15,这个知识点网上大多数文章都提到了。

然后下面我要讲的这个知识点网上那些文章就没有告诉你了。

用个例子说明:

假设一张图片是横向5像素,纵向4像素。前面讲了,横向每行占用的字节数是16字节。一共4行,占用的字节数就应该是16*4=64字节。

这64字节在BMP文件中的存放时,行顺序是倒着像下图这样存放的(图中蓝色箭头的顺序):

即:首先是最后一行,然后倒数第二行。。。。最后是第一行。

如果不知道这个规律,你的图像显示可能变成这个样子(倒着显示):

二、源代码

好了,知识点到此就讲完了,剩下的就是源代码了。

'''     本程序只处理24位真彩色bmp文件。24位真彩色即RGB888,分别用8位(1个字节) 来表达一个像素点的R、G、B色彩信息。     BMP文件包含四个部分:     1.位图文件头(BITMAPFILEHEADER)     2.位图信息头(BITMAPINFOHEADER)     3.颜色表*(RGBQUAD[])----不一定存在     4.像素阵列(Pixels[][]) 各个部分的结构:     1.文件头(14字节)     typedef struct tagBITMAPFILEHEADER{         WORD    bfType;                  // 位图文件的类型,必须为BMP (2个字节)         DWORD    bfSize;                  // 位图文件的大小,以字节为单位 (4个字节)         WORD    bfReserved1;             // 位图文件保留字,必须为0 (2个字节)         WORD    bfReserved2;             // 位图文件保留字,必须为0 (2个字节)         DWORD    bfOffBits;               // 位图数据的起始位置,以相对于位图 (4个字节)     } BITMAPFILEHEADER;          2.信息头(40字节),用于描述大小等信息     typedef struct tagBITMAPINFOHEADER{         DWORD biSize;             // 本结构所占用字节数  (4个字节)         LONG biWidth;              // 位图的宽度,以像素为单位(4个字节)         LONG biHeight;             // 位图的高度,以像素为单位(4个字节)         WORD biPlanes;            // 目标设备的级别,必须为1(2个字节)         WORD biBitCount;         // 每个像素所需的位数,必须是1(双色)、// 4(16色)、8(256色)、                                 //24(真彩色)或32(增强真彩色)之一 (2个字节)         DWORD biCompression;     // 位图压缩类型,必须是 0(不压缩)、 1(BI_RLE8                                  // 压缩类型)或2(BI_RLE4压缩类型)之一 ) (4个字节)         DWORD biSizeImage;         // 位图的大小,以字节为单位(4个字节)         LONG biXPelsPerMeter;      // 位图水平分辨率,每米像素数(4个字节)         LONG biYPelsPerMeter;   // 位图垂直分辨率,每米像素数(4个字节)         DWORD biClrUsed;        // 位图实际使用的颜色表中的颜色数(4个字节)         DWORD biClrImportant;   // 位图显示过程中重要的颜色数(4个字节)     } BITMAPINFOHEADER;     3.颜色表     typedef struct tagRGBQUAD      {       BYTE rgbBlue;          // 蓝色的亮度(值范围为0-255)       BYTE rgbGreen;         // 绿色的亮度(值范围为0-255)       BYTE rgbRed;           // 红色的亮度(值范围为0-255)       BYTE rgbReserved;      // 保留,必须为0     } RGBQUAD;     可以看到一个RGB表项为4个字节。     颜色表中RGBQUAD结构数据的个数由位图信息头中的biBitCount来确定:     当biBitCount=1, 4, 8时,分别有2, 16,256个表项     !!!!!!!!当biBitCount=24时,没有颜色表项!!!!!!!!!     4.像素阵列     记录了位图的每一个像素值,记录顺序是在扫描行内是从左到右,扫描行之间是从下到上。位图的一个像素值所占的字节数如下:     当biBitCount=1时,8个像素占1个字节;     当biBitCount=4时,2个像素占1个字节;     当biBitCount=8时,1个像素占1个字节;     当biBitCount=24时,1个像素占3个字节,分别是R、G、B;     Windows规定一个扫描行所占的字节数必须是4的倍数(即以long为单位),不足的以0填充。 ''' f=open('csdn.bmp',"rb") buff=f.read(1) cnt=0 f.seek(2)#文件大小 buff=f.read(4) fileSize=buff[3]*1024+buff[2]*512+buff[1]*256+buff[0] print("BMP文件大小:",fileSize,"字节") f.seek(18)#水平分辨率 buff=f.read(4) HResolution=buff[3]*1024+buff[2]*512+buff[1]*256+buff[0] print("图片水平分辨率:",HResolution,"像素") f.seek(22)#垂直分辨率 buff=f.read(4) VResolution=buff[3]*1024+buff[2]*512+buff[1]*256+buff[0] print("图片垂直分辨率:",VResolution,"像素") f.seek(28)#每个像素所需的位数 buff=f.read(2) colorMode=buff[1]*256+buff[0] print("颜色模式:",colorMode) BMPBuffer=bytearray(0) #准备传给液晶的buffer #计算图片每行占用的字节数(向上往4的整数倍靠) if HResolution*3%4==0: bytesPerRow=(HResolution*3//4)*4 else: bytesPerRow=(HResolution*3//4+1)*4 rgb565=bytearray(2) for rowCnt in range(VResolution-1,-1,-1):#行号要倒着来 f.seek(bytesPerRow*rowCnt+54)#注意偏移量54,因为图像数据是从54字节开始的 for cntInARow in range(int(bytesPerRow/3)):#读取行中的有效数据,填充的0x00将被忽略 buff=f.read(3)#RGB888格式,一次读取3字节 #从24位真彩色RGB888转换为RGB565格式 blue=buff[0]&0xf8#注意第一字节为蓝色blue数据 green=buff[1]&0xfc red=buff[2]&0xf8 rgb565[0]=red | (green & 0xe0)>>5 rgb565[1]=(blue>>3) | ((green & 0x1b)


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3