在开发产品的时候,很多时候,我们都会用到图片解码,在本章中,我们将向大家介绍如何通过STM32F1来解码BMP/JPG/JPEG/GIF等图片,并在LCD上显示出来。本章分为如下几个部分:
46.1图片格式简介
46.2硬件设计
46.3软件设计
46.4下载验证
46.1图片格式简介
我们常用的图片格式有很多,一般最常用的有三种:JPEG(或JPG)、BMP和GIF。其
中JPEG(或JPG)和BMP是静态图片,而GIF则是可以实现动态图片。下面,我们简单
介绍一下这三种图片格式。
首先,我们来看看BMP图片格式。BMP(全称Bitmap)是Window操作系统中的标准
图像文件格式,文件后缀名为“.bmp”,使用非常广。它采用位映射存储格式,除了图像深
度可选以外,不采用其他任何压缩,因此,BMP文件所占用的空间很大,但是没有失真。
BMP文件的图像深度可选lbit、4bit、8bit、16bit、24bit及32bit。BMP文件存储数据时,
图像的扫描方式是按从左到右、从下到上的顺序。
典型的BMP图像文件由四部分组成:
1,位图头文件数据结构,它包含BMP图像文件的类型、显示内容等信息;
2,位图信息数据结构,它包含有BMP图像的宽、高、压缩方法,以及定义颜色等信
息
3,调色板,这个部分是可选的,有些位图需要调色板,有些位图,比如真彩色图(24
位的BMP)就不需要调色板;
4,位图数据,这部分的内容根据BMP位图使用的位数不同而不同,在24位图中直接
使用RGB,而其他的小于24位的使用调色板中颜色索引值。
关于BMP的详细介绍,请参考光盘的《BMP图片文件详解.pdf》。接下来我们看看JPEG
文件格式。
JPEG是JointPhotographicExpertsGroup(联合图像专家组)的缩写,文件后辍名为“.jpg”
或“.jpeg”,是最常用的图像文件格式,由一个软件开发联合会组织制定,同BMP格式不
同,JPEG是一种有损压缩格式,能够将图像压缩在很小的储存空间,图像中重复或不重要
的资料会被丢失,因此容易造成图像数据的损伤(BMP不会,但是BMP占用空间大)。尤
其是使用过高的压缩比例,将使最终解压缩后恢复的图像质量明显降低,如果追求高品质图
像,不宜采用过高压缩比例。但是JPEG压缩技术十分先进,它用有损压缩方式去除冗余的
图像数据,在获得极高的压缩率的同时能展现十分丰富生动的图像,换句话说,就是可以用
最少的磁盘空间得到较好的图像品质。而且JPEG是一种很灵活的格式,具有调节图像质量
的功能,允许用不同的压缩比例对文件进行压缩,支持多种压缩级别,压缩比率通常在10:
1到40:1之间,压缩比越大,品质就越低;相反地,压缩比越小,品质就越好。比如可以
把1.37Mb的BMP位图文件压缩至20.3KB。当然也可以在图像质量和文件尺寸之间找
到平衡点。JPEG格式压缩的主要是高频信息,对色彩的信息保留较好,适合应用于互联网,
可减少图像的传输时间,可以支持24bit真彩色,也普遍应用于需要连续色调的图像。
JPEG/JPG的解码过程可以简单的概述为如下几个部分:
1、从文件头读出文件的相关信息。
JPEG文件数据分为文件头和图像数据两大部分,其中文件头记录了图像的版本、
长宽、采样因子、量化表、哈夫曼表等重要信息。所以解码前必须将文件头信息读出,
以备
图像数据解码过程之用。
2、从图像数据流读取一个最小编码单元(MCU),并提取出里边的各个颜色分量单元。
3、将颜色分量单元从数据流恢复成矩阵数据。
使用文件头给出的哈夫曼表,对分割出来的颜色分量单元进行解码,把其恢复成8
×8的数据矩阵。
4、8×8的数据矩阵进一步解码。
此部分解码工作以8×8的数据矩阵为单位,其中包括相邻矩阵的直流系数差分
解码、使用文件头给出的量化表反量化数据、反Zig-zag编码、隔行正负纠正、反向
离散余弦变换等5个步骤,最终输出仍然是一个8×8的数据矩阵。
5、颜色系统YCrCb向RGB转换。
将一个MCU的各个颜色分量单元解码结果整合起来,将图像颜色系统从YCrCb向
RGB转换。
6、排列整合各个MCU的解码数据。
不断读取数据流中的MCU并对其解码,直至读完所有MCU为止,将各MCU解
码后的数据正确排列成完整的图像。
JPEG的解码本身是比较复杂的,这里FATFS的作者,提供了一个轻量级的JPG/JPEG
解码库:TjpgDec,最少仅需3KB的RAM和3.5KB的FLASH即可实现JPG/JPEG解码,
本例程采用TjpgDec作为JPG/JPEG的解码库,关于TjpgDec的详细使用,请参考光盘:6,
软件资料\图片编解码\TjpgDec技术手册这个文档。
BMP和JPEG这两种图片格式均不支持动态效果,而GIF则是可以支持动态效果。最
后,我们来看看GIF图片格式。
GIF(GraphicsInterchangeFormat)是CompuServe公司开发的图像文件存储格式,
年开发的GIF文件格式版本号是GIF87a,年进行了扩充,扩充后的版本号定义为GIF89a。
GIF图像文件以数据块(block)为单位来存储图像的相关信息。一个GIF文件由表示图形
/图像的数据块、数据子块以及显示图形/图像的控制信息块组成,称为GIF数据流(Data
Stream)。数据流中的所有控制信息块和数据块都必须在文件头(Header)和文件结束块(Trailer)
之间。
GIF文件格式采用了LZW(Lempel-ZivWalch)压缩算法来存储图像数据,定义了允许用
户为图像设置背景的透明(transparency)属性。此外,GIF文件格式可在一个文件中存放多幅
彩色图形/图像。如果在GIF文件中存放有多幅图,它们可以像演幻灯片那样显示或者像动
画那样演示。
一个GIF文件的结构可分为文件头(FileHeader)、GIF数据流(GIFDataStream)和文件终
结器(Trailer)三个部分。文件头包含GIF文件署名(Signature)和版本号(Version);GIF数据流
由控制标识符、图象块(ImageBlock)和其他的一些扩展块组成;文件终结器只有一个值为
0x3B的字符(;)表示文件结束。
关于GIF的详细介绍,请参考光盘GIF解码相关资料。图片格式简介,我们就介绍到
这里。
46.2硬件设计
本章实验功能简介:开机的时候先检测字库,然后检测SD卡是否存在,如果SD卡存
在,则开始查找SD卡根目录下的PICTURE文件夹,如果找到则显示该文件夹下面的图片
文件(支持bmp、jpg、jpeg或gif格式),循环显示,通过按KEY0和KEY2可以快速浏
览下一张和上一张,KEY_UP按键用于暂停/继续播放,DS1用于指示当前是否处于暂停状
态。如果未找到PICTURE文件夹/任何图片文件,则提示错误。同样我们也是用DS0来指
示程序正在运行。
所要用到的硬件资源如下:
1)指示灯DS0和DS1
2)KEY0、KEY2和KEY_UP三个按键
3)串口
4)TFTLCD模块
5)SD卡
6)SPIFLASH
这几部分,在之前的实例中都介绍过了,我们在此就不介绍了。需要注意的是,我们在
SD卡根目录下要建一个PICTURE的文件夹,用来存放JPEG、JPG、BMP或GIF等图片。
46.3软件设计
打开上一章的工程,首先在HARDWARE文件夹所在的文件夹下新建一个PICTURE的
文件夹。在该文件夹里面新建bmp.c、bmp.h、tjpgd.c、tjpgd.h、integer.h、gif.c、gif.h、piclib.c
和piclib.h等9个文件。并将PICTURE文件夹加入头文件包含路径。
其中bmp.c和bmp.h用于实现对bmp文件的解码;tjpgd.c和tjpgd.h用于实现对jpeg/jpg
文件的解码;gif.c和gif.h用于实现对gif文件的解码;这几个代码太长了,所以我们在这里
不贴出来,请大家参考光盘本例程的源码,我们打开piclib.c,在里面输入如下代码:
_pic_infopicinfo;//图片信息
_pic_phypic_phy;//图片显示物理接口
//lcd.h没有提供划横线函数,需要自己实现
voidpiclib_draw_hline(u16x0,u16y0,u16len,u16color)
if((len==0)
(x0lcddev.width)
(y0lcddev.height))return;
LCD_Fill(x0,y0,x0+len-1,y0,color);
//填充颜色
//x,y:起始坐标
//width,height:宽度和高度。
//*color:颜色数组
voidpiclib_fill_color(u16x,u16y,u16width,u16height,u16*color)
LCD_Color_Fill(x,y,x+width-1,y+height-1,color);
//画图初始化,在画图之前,必须先调用此函数
//指定画点/读点
voidpiclib_init(void)
pic_phy.read_point=LCD_ReadPoint;//读点函数实现,仅BMP需要
pic_phy.draw_point=LCD_Fast_DrawPoint;//画点函数实现
pic_phy.fill=LCD_Fill;//填充函数实现,仅GIF需要
pic_phy.draw_hline=piclib_draw_hline;//画线函数实现,仅GIF需要
pic_phy.fillcolor=piclib_fill_color;//颜色填充函数实现,仅TJPGD需要
picinfo.lcdwidth=lcddev.width;//得到LCD的宽度像素
picinfo.lcdheight=lcddev.height;//得到LCD的高度像素
picinfo.ImgWidth=0;//初始化宽度为0
picinfo.ImgHeight=0;//初始化高度为0
picinfo.Div_Fac=0;//初始化缩放系数为0
picinfo.S_Height=0;//初始化设定的高度为0
picinfo.S_Width=0;//初始化设定的宽度为0
picinfo.S_XOFF=0;//初始化x轴的偏移量为0
picinfo.S_YOFF=0;//初始化y轴的偏移量为0
picinfo.staticx=0;//初始化当前显示到的x坐标为0
picinfo.staticy=0;//初始化当前显示到的y坐标为0
//快速ALPHABLENDING算法.
//src:源颜色
//dst:目标颜色
//alpha:透明程度(0~32)
//返回值:混合后的颜色.
u16piclib_alpha_blend(u16src,u16dst,u8alpha)
u32src2;
u32dst2;
//Convertto32bit
-----GGGGGG-----RRRRR------BBBBB
src2=((src16)
src)0x07E0F81F;
dst2=((dst16)
dst)0x07E0F81F;
//PerformblendingR:G:Bwithalphainrange0..32
//Notethatthereasonthatalphamaynotexceed32isthatthereareonly
//5bitsofspacebetweeneachR:G:Bvalue,anyhighervaluewilloverflow
//intothenext