本帖最后由 gtbestom 于 2021-8-19 17:19 编辑
#申请原创# @21小跑堂
在 CH32V103 上移植成功 FATFS 文件系统后,就可以对存储卡里的 电子书,图片,音乐 等文件进行读取了
每种文件都有特定的格式,记录文件的信息
就拿 BMP 格式的位图来说
BMP 文件特定区域记录着文件的 宽度、高度、位深 等信息
BMP 格式文件 编解码相对简单
我们化繁为简,长话短说
先上图,要读取内存卡里的 2 张单色位图,并显示在 oled 12864 上
图片竖向保存,方便按字节顺序直接显示在 oled 屏上
BMP 格式文件有个信息头,记录文件的各种信息
前2字节是 “BM” 标识这是一个 BMP 格式的文件
长话短说,用结构体表示
//BMP头文件结构体
typedef struct
{
u16 bfType; // 文件标志.只对'BM' 0x424D ,用来识别BMP位图类型
u32 bfSize; // 文件大小,包括这14个字节
u16 bfReserved1; // 保留
u16 bfReserved2; // 保留
u32 bfOffBits; // 从文件开始到位图数据(bitmap data)开始之间的的偏移量,前三个部分的长度之和
}__attribute__((packed)) BITMAPFILEHEADER; // 固定14个字节
这开头的14字节就标识了一些文件信息,紧接着又是固定的40字节
//BMP信息头
typedef struct
{
u32 biSize; // 说明BITMAPINFOHEADER结构所需要的字数
s32 biWidth; // 说明图象的宽度,以象素为单位
s32 biHeight; // 说明图象的高度,以象素为单位
u16 biPlanes; // 为目标设备说明位面数,其值将总是被设为1
u16 biBitCount; // 说明比特数/象素,其值为1、4、8、16、24、或32
u32 biCompression; // 说明图象数据压缩的类型。其值可以是下述值之一:
// BI_RGB:没有压缩;
// BI_RLE8:每个象素8比特的RLE压缩编码,压缩格式由2字节组成(重复象素计数和颜色索引);
// BI_RLE4:每个象素4比特的RLE压缩编码,压缩格式由2字节组成
// BI_BITFIELDS:每个象素的比特由指定的掩码决定。
u32 biSizeImage; // 说明图象的大小,以字节为单位。当用BI_RGB格式时,可设置为0
s32 biXPelsPerMeter; // 说明水平分辨率,用象素/米表示
s32 biYPelsPerMeter; // 说明垂直分辨率,用象素/米表示
u32 biClrUsed; // 说明位图实际使用的彩色表中的颜色索引数
u32 biClrImportant; // 说明对图象显示有重要影响的颜色索引的数目,如果是0,表示都重要。
}__attribute__((packed)) BITMAPINFOHEADER ; // 固定40个字节
进一步说明了文件的各种信息,其中重要的就是 文件宽度 biWidth,高度 biHeight,位深 biBitCount,数据偏移 bfOffBits
紧接着还有一个颜色对照表,文末再说,不影响单色位图解码
单色位图也有颜色对照表,但是我发现 Win10 系统不会对照表显示,都是显示黑白两色,所以我们不做对照表
根据数据偏移 bfOffBits 信息,我们可以直接跳转到图像数据区(跳过 54 字节信息表、n 字节颜色对照表)
f_lseek(&imginfo->FileInfo, imginfo->OffsetByte);
读取图像信息
f_read(&imginfo->FileInfo, Buff, 1024, &cout);
由于我们使用的是 12864 点阵屏,128x64/8 = 1024 为了简要说明,所以直接读取全部图像数据
接着对读取的数据进行排列和整理,以防止出现错乱和颠倒
for(i=0;i<128;i++)
{
for(j=0;j<8;j++)
{
gd_DispBuf[j][i] = ~SWAP(Buff[i*8+j]);
}
}
SWAP 函数用来交换高低位
这样处理后,gd_DispBuf 的数据就可以直接写到 OLED12864了
至于位深更高的 16 色图、256 色图,需要用到颜色对照表
还有 24 位图,就是我们比较常见的 RGB888 也就是 16,777,216 色图了,24 位图就不需要对照表了,直接读数据显示
16 色图、256 色图涉及的颜色转换表,也用结构体表示:
// 彩色表
typedef struct
{
u8 rgbBlue; // 指定蓝色强度
u8 rgbGreen; // 指定绿色强度
u8 rgbRed; // 指定红色强度
u8 rgbReserved; // 保留,设置为0
}__attribute__((packed)) RGBQUAD;
16 色图因为只有 16 种颜色,只需要 16 个对照表,也就是 16x4=64 字节的对照表
256 色图因为有 256 种颜色,需要 256 个对照表,也就是 256x4=1024 字节的对照表
获取偏移位置后的图像数据后,不能直接显示,要经过对照表处理,转换成 RGB888 数据,才能正常使用
24 位图转 RGB565 换算如下
(Buff>>3) | ((Buff[i+1]>>2)<<5) | ((Buff[i+2]>>3))<<11
256 色转 RGB565 换算如下
(imginfo->ColorTab[Buff].rgbBlue>>3) | ((imginfo->ColorTab[Buff].rgbGreen>>2)<<5) | ((imginfo->ColorTab[Buff].rgbRed>>3)<<11)
16 色转 RGB565 换算如下
(imginfo->ColorTab[Buff>>4].rgbBlue>>3) | ((imginfo->ColorTab[Buff>>4].rgbGreen>>2)<<5) | ((imginfo->ColorTab[Buff>>4].rgbRed>>3)<<11)
(imginfo->ColorTab[Buff&0x0f].rgbBlue>>3) | ((imginfo->ColorTab[Buff&0x0f].rgbGreen>>2)<<5) | ((imginfo->ColorTab[Buff&0x0f].rgbRed>>3)<<11)
|