micropython驱动ST7789v液晶屏幕显示24位真彩BMP文件图片 |
您所在的位置:网站首页 › tft32位真彩色 › micropython驱动ST7789v液晶屏幕显示24位真彩BMP文件图片 |
继续折腾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 |