1.使用lodepng解码,源代码为。使用最少2个文件就能完成png的解码。不像libpng + Zlib需要许多文件,并且有很多关联头文件。
lodepng-master为原始代码
https://lodev.org/lodepng/
也有github主页https://github.com/lvandeve/lodepng
2.png_examples是配合NXP RT1170 SDK,仿照jpeg_example的例子,主要是借助从这个示例,可以从从SD卡文件系统直接读取.png文件
2.1修改loadpng.c中对文件的操作,使用fatfs API操作图片文件,比如f_open,而不是fopen
2.2仿照example_sdl.c调用以下函数完成对png的解码,解码成8888的格式
lodepng_decode32_file(&image, &width, &height, filename);
获取png图片的高度和宽度
2.3 在framebuff的中间位置,将获取到的rgba数据显示到屏上。
因为大部分显示driver不含有alpha blending功能,所以a透明度数据被综合到r,b,g数据中
并且最终按照b,g,r的顺序填入framebuffer
如果显示驱动定义的格式为ARGB8888,这种情况直接按序填入framebuffer即可。
/*plot the pixels of the PNG file*/
for(y = 0; y + jump - 1 < h; y += jump)
{
bufp = pBuffStart + y * row_stride;
for(x = 0; x + jump - 1 < w; x += jump)
{
/*get RGBA components*/
r = image[4 * y * w + 4 * x + 0]; /*red*/
g = image[4 * y * w + 4 * x + 1]; /*green*/
b = image[4 * y * w + 4 * x + 2]; /*blue*/
a = image[4 * y * w + 4 * x + 3]; /*alpha*/
/*make translucency visible by placing checkerboard pattern behind image*/
//处理透明情况
checkerColor = 191 + 64 * (((x / 16) % 2) == ((y / 16) % 2));
r = (a * r + (255 - a) * checkerColor) / 255;
g = (a * g + (255 - a) * checkerColor) / 255;
b = (a * b + (255 - a) * checkerColor) / 255;
/*give the color value to the pixel of the screenbuffer*/
//bufp = (Uint32 *)scr->pixels + (y * scr->pitch / 4) / jump + (x / jump);
//*bufp = 65536 * r + 256 * g + b;
*bufp++ = b;
*bufp++ = g;
*bufp++ = r;
}
2.4 以上即可解码png格式图片,loadpng还支持生成png格式图片,或者将png格式图片转成bmp图片等。
当然现在lodepng的实现需要filesystem接口来操作图片。
LODEPNG_COMPILE_DISK定义后,可以使用lodepng_decode_file来直接解码图片文件
对于单片机系统,也有一些情况下需要将png图片作为bin文件存放。这时候要先手动把文件数据读取到buffer中
再调用unsigned lodepng_decode32(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in, size_t insize)
传入in,w,h,insize,colortype, bitdepth等参数转换为out输出
lodepng_decode32_file只需传入文件名,colortype, bitdepth即可,会自动调用文件系统读取文件大小。通过lodepng_load_file获得文件大小,并且将文件读取到一个动态malloc分配的buffer中
而lodepng_decode32的insize参数需要自行通过文件获取,并将该文件读取到buffer中。或者文件大小在编译时指定。比如在远程下载一个png文件的时候,将下载大小保存起来,作为下次解码png的参数。
2.5 接上问题:如何在IAR中不使用文件系统直接使用一个png文件
2.5.1:首先需要在IAR中link一张png图片,并将其与代码段link在一起,4字节对齐,指定其symbol为symbol_snowy
Link: extra option
--image_input=$PROJ_DIR$/../snowy.png,symbol_snowy,.text,4
--keep=symbol_snowy
在代码中如下应用该png文件对应的buffer
extern unsigned char symbol_snowy[];
例程是针对于NXP i.MXRT系列做的一个范例,在IAR工程中采用两种方式解码并显示png图片。
1.第一种,000.png放于sd卡上,通过fatfs读取该文件,并使用lodepng_decode_file解码
2.第二种,直接将一张png图片编译在工程中,直接将该文件使用lodepng_decode32解码
补充:
通过定义一些NO_COMPILE选项,可以屏蔽掉不需要的功能,加快编译速度
#define LODEPNG_NO_COMPILE_DISK 不需要文件系统,而采用裸数据解码
#define LODEPNG_NO_COMPILE_ENCODER 不需要编码png图片
lodepng_decode32可以解出RBGA 4种数据,输出out buffer也是每4个字节为一个像素
lodepng_decode24可以解出RGB3种数据,输出out buffer每3个字节为一个像素
/*get RGBA components*/
r = image[3 * y * w + 3 * x + 0]; /*red*/
g = image[3 * y * w + 3 * x + 1]; /*green*/
b = image[3 * y * w + 3 * x + 2]; /*blue*/
a = 255; /*no alpha,不透明*/
/*make translucency visible by placing checkerboard pattern behind image*/
//处理透明情况
checkerColor = 191 + 64 * (((x / 16) % 2) == ((y / 16) % 2));
r = (a * r + (255 - a) * checkerColor) / 255;
g = (a * g + (255 - a) * checkerColor) / 255;
b = (a * b + (255 - a) * checkerColor) / 255;
/*give the color value to the pixel of the screenbuffer*/
//bufp = (Uint32 *)scr->pixels + (y * scr->pitch / 4) / jump + (x / jump);
//*bufp = 65536 * r + 256 * g + b;
*bufp++ = b;
*bufp++ = g;
*bufp++ = r;
当然前者需要更多的heap资源,虽然png相比jpeg为无损压缩,且数据压缩率也可以,但是解码的时候需要大量的RAM,小单片机还是慎用,情愿用SPI Flash空间存储bmp文件换取珍贵的RAM资源