有道云笔记详细地址:
文档:图片解码播放器小项目(详解).note
链接:http://note.youdao.com/noteshare?id=9f9a43ac5ec6828cf467940dfa10da51&sub=A8280EB4B5A146C9A1F6612031305071
(1)这是一个通用的项目管理的Makefile体系,自己写的(有子文件夹组织的)项目可以直接套用这套Makefile体系。
(2)包含三类:顶层Makefile、Makefile.build(完全不需要改动)、子文件夹下面的Makefile。
子文件夹下的Makefile一般是类似下面的内容。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pwsgMELC-1570028293237)(F95308E307894BA1A9ECE5BC07CFA0A1)]
(3)可以参考:http://www.cnblogs.com/lidabo/p/4521123.html。
打开SI,在E:\Linux\winshare\x210kernel\tupian_project中新建一个SI_Proj文件夹,用于建立SI工程,然后新建一个输出hello word的main.c文件,并在ubuntu中make整个工程,并make cp到根文件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-28cgC87l-1570028293240)(D3212F76475F446D8A238276FDAB198D)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3oy9ZgzM-1570028293241)(61AD59BE2EEA47A89184B37C33D2317A)]
启动开发板,进入driver_test目录下,可以查看到我们的工程目录,进入执行生成的imageplayer文件,可以输出hello word,到此新建工程结束。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tuvzJgKR-1570028293244)(321FA7F935AC44FBAEB009AF46656C7A)]
新建一个脚本文件run.sh,用于管理各种可执行文件,比如上面我们生成的./imageplayer文件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bOKzRF4J-1570028293246)(107A0A80C7444F0EACCFD669B6224802)]
E:\Linux\winshare\x210kernel\tupian_project
显示图片,需要framebuffer驱动。
并在display文件夹里新建Makefile并添加内容
obj-y += fb.o(这就是子makefile,作用就是让fb.c能被编译进去)
故将我们在驱动学习中framebuffer哪一阶段的应用程序拷贝到fb.c中
(即E:\Linux\4.LinuxDriver\7.frambuffer\7.1.fb1\appfb.c),并修改部分代码
(即将之前的所有宏定义和函数声明放在fb.h中,并在主Makefile中添加命令,使其将子目录能编译进去)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eGAxAg1q-1570028293250)(C0D3963AFF084915B8931301C41F7343)]
man.c如下:
#include
#include
#include
int main(void)
{
int ret=-1;
printf("image player demo........star \n");
//第一步,打开设备
ret = fb_open();
if(ret < 0)
{
perror("fb_open error.\n");
return -1;
}
fb_draw_badk(WIDTH, HEIGHT, YELLOW);//调用背景填充函数
}
从新make编译,并拷贝到根文件系统中,重启开发板,执行脚本,显示预期一致。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-86ARibZo-1570028293255)(9AEAFC67E9E34E4BB28D68B3BA5FD8A5)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RXbxT1fd-1570028293256)(2108333A2096471A97479662733A7263)]
在fb.c中添加如下代码,且在主函数中调动该函数,编译程序,拷贝到跟文件系统
//测试显示1024600分辨率的图片
void fb_draw_picture(void)
{
unsigned char pdata=gImage_1024;//指针指向图像数组
unsigned int i,j,cnt;
unsigned int*p=pfb;//等于显示缓存区的首地址
for(i=0;i
}
重启开发板,执行.、run.sh脚本,看到屏幕如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NNbLZtZH-1570028293258)(63BFF505A0AF4F519147EEF410B2D335)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-10zlyp5i-1570028293259)(CD381E03B4114362AE2046736739C10D)]
与我们图片周边是粉色颜色不符合,原因肯定是RGB弄反了,这里,我们可以在上面的fb_draw_picture函数中进行修改,将RB调换,从新编译,执行脚本,显示和我们的原图就一样了。
*p=((pdata[cnt+2]<<0)|(pdata[cnt+1]<<8)|(pdata[cnt+0]<<16));//可以在这里修改,达到正确的显示(当RB相反时)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3l0QCy6i-1570028293260)(05F0F24F487648B7BB91E05F2335095B)]
(2)通过图片/视频文件直接代码方式提取
(1)RGB顺序有三个地方都有影响
(2)如果三个点中RGB顺序是一致的就会显示正常。如果三个设置不一致就可能会导致显示结果中R和B相反了;
(3)实际写程序时,一般不去分析这东西,而是根据实际显示效果去调。如果反了就去调正应用程序中的RGB顺序就行了,这样最简单。
void fb_draw_picture2(void)
{
unsigned char* pdata=gImage_1024;//指针指向图像数组
unsigned int x,y,cnt;
for(y=0;y
}
这种情况下多出来的部分肯定是没法显示的。处理方法是直接在显示函数中把多余不能被显示的部分给丢掉。
这种情况下图片只是填充屏幕中一部分,剩余部分仍然保持原来的底色。
在获取图片数据时,大小和图片实际大小在这里是一致的。假如不一致呢?
//测试显示分辨率比屏幕小的图片
//pdata://指针指向图像数组
void fb_draw_picture3(unsigned char* pdata)
{
//unsigned char* pdata=gImage_320480;
unsigned int x,y,cnt;
unsigned int a=0;
//图片的分辨率是320*480
for(y=0;y<480;y++)
{
for(x=0;x<320;x++)
{
cnt=y*WIDTH+x;/*cnt始终都是framebuff像素点的编号*/
*(pfb+cnt)=((pdata[a+0]<<16)|(pdata[a+1]<<8)|(pdata[a+2]<<0));
a+=3;/*由于空缺一部分,像素点编号与像素点矩阵不存在倍数关系了,此时应该三个三个地传送进来*/
}
}
}
//测试显示分辨率比屏幕小的图片 另一种写法,对比看出
//pdata:指针指向图像数组
void fb_draw_picture4(unsigned char* pdata)
{
// unsigned char* pdata=gImage_320480;//指针指向图像数组
unsigned int x,y,cnt1;
unsigned int cnt2=0;
//图片的分辨率是320*480
for(y=0;y<480;y++)
{
for(x=0;x<320;x++)
{
cnt1=y*WIDTH+x;//取出当前屏幕像素点编号
cnt2=y*320+x; //取出当前图片像素点编号
//当前像素点对应的图像数据的RGB应该分别是pData[cnt+0]、pData[cnt+1]、pData[cnt+2]
//当前像素点的数据
*(pfb+cnt1)=((pdata[cnt2*3+2]<<0)|(pdata[cnt2*3+1]<<8)|(pdata[cnt2*3+0]<<16));////这里的像素矩阵和cnt有线性关系,所以可以这样写
}
}
}
另一种写法,对比两种函数的写法,看出区别,烧录效果都一样,这里,不再赘述
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VBD33q4p-1570028293261)(108ACE9C4BBF4C62A50F3FAFA3E634CB)]
算法1:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-s1btYqX1-1570028293263)(B819CC65CF0C41769D83150895A1202B)]
//测试在屏幕指定坐标显示图片的位置
//x0:图片想要显示的x坐标 y0:图片想要显示的y坐标
void fb_draw_picture5(unsigned int x0,unsigned int y0,unsigned char* pdata)
{
//unsigned char* pdata=gImage_320480;//指针指向图像数组
unsigned int x,y,cnt1;
unsigned int cnt2=0;
//图片的分辨率是320*480
for(y=y0;y<480+y0;y++)
{
for(x=x0;x<320+x0;x++)
{
cnt1=y*WIDTH+x;//取出当前屏幕像素点编号
cnt2=(y-y0)*320+(x-x0); //取出当前图片像素点编号
*(pfb+cnt1)=((pdata[cnt2*3+2]<<0)|(pdata[cnt2*3+1]<<8)|(pdata[cnt2*3+0]<<16));////这里的像素矩阵和cnt有线性关系,所以可以这样写
/*左值考虑当前像素点在fb中的偏移量*/
/*右值考虑当前像素点在图像数据数组的下标(这里是三个为一个元素的数组的下标,因此上面会*3)*/
}
}
}
算法2:(因为每循环一次,+3)
//测试在屏幕指定坐标显示图片的位置,和fb_draw_picture5函数一样的功能,只是实现算法不一样,更加简单
//x0:图片想要显示的x坐标 y0:图片想要显示的y坐标
void fb_draw_picture6(unsigned int x0,unsigned int y0,unsigned char* pdata)
{
//unsigned char* pdata=gImage_320480;
unsigned int x,y,cnt;
unsigned int a=0;
//图片的分辨率是320*480
for(y=y0;y<480+y0;y++)
{
for(x=x0;x<320+x0;x++)
{
cnt=y*WIDTH+x;/*cnt始终都是framebuff像素点的编号*/
*(pfb+cnt)=((pdata[a+0]<<16)|(pdata[a+1]<<8)|(pdata[a+2]<<0));
a+=3;/*由于空缺一部分,像素点编号与像素点矩阵不存在倍数关系了,此时应该三个三个地传送进来*/
}
}
}
在主函数中,调用上面两种不同算法实现的任意起点位置图片显示函数
int main()
{
int ret=-1;
printf("image player demo........star \n");
//第一步,打开设备
ret = fb_open();
if(ret < 0)
{
perror("fb_open error.\n");
return -1;
}
fb_draw_badk(WIDTH, HEIGHT, RED);//调用背景填充函数
fb_draw_picture6((1024-320)/2,(600-480)/2,gImage_320480);//居中显示该图片
fb_close();
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jmpwWQkS-1570028293264)(E33B3E0C2EBC41DDAAFAB3FBCB3BF3D2)]
(1)现象
在主函数中调用任意起点位置图片显示函数:
fb_draw_picture5(900,100);//图片大小超出屏幕范围测试
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xSoDa7N4-1570028293265)(979CE78FD41744F2B7D0CE7C59E6EB29)]
(2)修改代码,使得超出部分不再显示。
算法1:
//x和y两个方向超出屏幕外的部分都不显示
void fb_draw_picture7(unsigned int x0,unsigned int y0, unsigned char* pdata)
{
//unsigned char* pdata=gImage_320480;
unsigned int x,y,cnt;
unsigned int a=0;
//图片的分辨率是320*480
for(y=y0;y<480+y0;y++)
{
if(y>=HEIGHT)//y方向超出
{
a+=3;
break;//最后一行已经显示了,剩下的不用考虑了
}
for(x=x0;x<320+x0;x++)
{
if(x>=WIDTH)//x方向超出了
{
a+=3;
continue;//仅结束本次循环
}
cnt=y*WIDTH+x;/*cnt始终都是framebuff像素点的编号*/
*(pfb+cnt)=((pdata[a+0]<<16)|(pdata[a+1]<<8)|(pdata[a+2]<<0));
a+=3;/*由于空缺一部分,像素点编号与像素点矩阵不存在倍数关系了,此时应该三个三个地传送进来*/
}
}
}
算法2:
//x和y两个方向超出屏幕外的部分都不显示 和fb_draw_picture7一样的功能 实现算法不一样
void fb_draw_picture8(unsigned int x0,unsigned int y0, unsigned char* pdata)
{
// unsigned char* pdata=gImage_320480;//指针指向图像数组
unsigned int x,y,cnt1;
unsigned int cnt2=0;
//图片的分辨率是320*480
for(y=y0;y<480+y0;y++)
{
if(y>=HEIGHT)//y方向超出
{
break;//最后一行已经显示了,剩下的不用考虑了
}
for(x=x0;x<320+x0;x++)
{
if(x>=WIDTH)//x方向超出了
{
continue;//仅结束本次循环
}
cnt1=y*WIDTH+x;//取出当前屏幕像素点编号
cnt2=(y-y0)*320+(x-x0); //取出当前图片像素点编号
*(pfb+cnt1)=((pdata[cnt2*3+2]<<0)|(pdata[cnt2*3+1]<<8)|(pdata[cnt2*3+0]<<16));////这里的像素矩阵和cnt有线性关系,所以可以这样写
/*左值考虑当前像素点在fb中的偏移量*/
/*右值考虑当前像素点在图像数据数组的下标(这里是三个为一个元素的数组的下标,因此上面会*3)*/
}
}
}
在主函数中调用该函数:
//fb_draw_picture7(900,100);
fb_draw_picture8(900,100,gImage_320480);//图片大小超出屏幕范围测试
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Tn3LV1BO-1570028293266)(682FEBF34B51492B922EC770ED1D7FC1)]
(1)图片文件是二进制文件。
文件分两种,即二进制文件、文本文件;
(2)不同格式的图片文件的差别。
图片被压缩与否的区别。
(3)BMP图片的基本特征
未被压缩的元素位图格式(bit map)。
(1)如何识别BMP文件?
每种图片格式都有定义好的一种识别方法,BMP图片特征是以0x424D开头;
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0cOqRkx3-1570028293267)(0078B254880F41FA8EA756D6AEF94BA2)]
(2)BMP文件组成
头信息+有效信息
以下对BMP文件的测试都是参考这里:https://blog.csdn.net/oqqHuTu12345678/article/details/78862613
(1)文件大小
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RYjtiQur-1570028293268)(F124EA63B0BC497AB887E31665689473)]
(2)有效数据开始的位置
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kojTUOTh-1570028293292)(4030384155844CF2AB82D92A32C1EC27)]
(3)信息头的大小:40个字节
(4)分辨率
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QIiMZfWn-1570028293293)(88E96E617AF2439C82B9D8C3B68FCE86)]
(5)24位真彩色
//path是bmp图片的pathname
//该函数解析path图片,并将图片数据丢到bmp_buf中
//返回值错误时返回-1,正确返回0
int bmp_analyze(unsigned char *path)
{
int fd=-1;
unsigned char buf[54]={0};
ssize_t ret=-1;
//第一步:打开BMP图片
fd=open(path,O_RDONLY);
if(fd<0)
{
fprintf(stderr,"open %s error.\n",path);
return -1;
}
// 第二步: 读取文件头信息
ret=read(fd,buf,54);//这里为什么是54,因为有效数据开始的位置地址为0x36=54
if(ret!=54)
{
fprintf(stderr,"read file header error.\n");
return -1;
}
// 解析头
// 第三步: 判断是不是BMP图片
if(buf[0]!='B'||buf[1]!='M')//BMP头肯定为BM
{
fprintf(stderr,"file %s is not a bmp picture.\n",path);
return -1;
}
printf("file %s is a bmp picture....ok\n",path);
// 第四步:
printf("width is %d\n",*((unsigned int*)(buf+0x12)));//这里为什么是buf+0x12,因为0x12是位图的宽度
printf("hith is %d\n",*((unsigned int*)(buf+0x16)));//0x16是位图的高度
close(fd);
return 0;
}
ret=read(fd,buf,54);//这里为什么是54,因为有效数据开始的位置地址为0x36=54
因为有效数据开始的位置地址为0x36=54
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4gWJOTD0-1570028293294)(41C67C8DFD754CA89F9D1BEC321CF639)]
为什么这里使用了buf+0x12??
printf("width is %d\n",
*((unsigned int*)(buf+0x12)));//这里为什么是buf+0x12,
因为0x12是位图的宽度printf("hith is %d\n",*((unsigned int*)(buf+0x16)));//0x16是位图的高度
原因如下,这是在上面的博客地址中BMP头信息的地址
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cdIb2y69-1570028293295)(EB2DCC1F79B4439C9E2EDD771061DC7B)]
bmp_analyze("cute_pic.bmp");//必须保证在工程中已经存在该BMP文件
且修改dispaly子文件夹下的Makefile,包含Fb_bmp.c,不然编译肯定报错
obj-y += Fb_bmp.o
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pWkAAKht-1570028293296)(BC2C0AC96CA94264A9E629DA27D9D3C0)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SK6ebTeN-1570028293297)(ABC4C30F2F03460BBE73F7C8FC8D346E)]
typedef struct
{
unsigned char bfType[2];//文件类?
unsigned long bfSize; //位图大小
unsigned short bfReserved1; //位0
unsigned short bfReserved2; //位0
unsigned long bfOffBits;//到数据偏移量
}__attribute__((packed))BitMapFileHeader;//使编译器不优化,其大小为14字节
//信息头结构体
typedef struct
{
unsigned long biSize;// BitMapFileHeader 字节数
long biWidth;//位图宽度
long biHeight;//位图高度,正位正向,反之为倒图
unsigned short biPlanes;//为目标设备说明位面数,其值将总是被设为1
unsigned short biBitCount;//说明比特数/象素,为1、4、8、16、24、或32。
unsigned long biCompression;//图象数据压缩的类型没有压缩的类型:BI_RGB
unsigned long biSizeImage;//说明图象的大小,以字节为单位
long biXPelsPerMeter;//说明水平分辨率
long biYPelsPerMeter;//说明垂直分辨率
unsigned long biClrUsed;//说明位图实际使用的彩色表中的颜色索引数
unsigned long biClrImportant;//对图象显示有重要影响的索引数,0都重要。
} __attribute__((packed)) BitMapInfoHeader;
// 判断一个图片文件是不是一个合法的bmp文件
// 返回值: 如果是则返回0,不是则返回-1
int is_bmp(const char *path)
{
int fd=-1;
unsigned char buf[2]={0};
ssize_t ret=-1;
//第一步:打开BMP图片
fd=open(path,O_RDONLY);
if(fd<0)
{
fprintf(stderr,"open %s error.\n",path);
return -1;
}
// 第二步: 读取文件头信息
ret=read(fd,buf,2);//只读取文件头2个字节
if(ret!=2)
{
fprintf(stderr,"read file header error.\n");
ret = -1;
goto close;
}
// 解析头
// 第三步: 判断是不是BMP图片
if(buf[0]!='B'||buf[1]!='M')//BMP头肯定为BM
{
fprintf(stderr,"file %s is not a bmp picture.\n",path);
ret = -1;
goto close;
}
else
{
ret=0;
}
printf("file %s is a bmp picture....ok\n",path);
close:
close(fd);
return ret;
}
//path是bmp图片的pathname
//该函数解析path图片,并将图片数据丢到bmp_buf中
//返回值错误时返回-1,正确返回0
int bmp_analyze(unsigned char *path)
{
int fd=-1;
BitMapFileHeader fheader;
BitMapInfoHeader info;
ssize_t ret=-1;
int i=0;
//第一步:打开BMP图片
fd=open(path,O_RDONLY);
if(fd<0)
{
fprintf(stderr,"open %s error.\n",path);
return -1;
}
// 第二步: 读取文件头信息
ret=read(fd,&fheader,sizeof(fheader));
printf("bfsize =%d.\n",fheader.bfSize);//位图大小
printf("boffsize =%d.\n",fheader.bfOffBits);//有效信息偏移量
#if 0
for( i=0;i
====> 细节:上面的这段代码用于测试打印出的像素数据是否一致
#if 1
for( i=0;i
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iTFQuaXg-1570028293298)(DF2F4E57A4DF40A593A45C8E4183301E)]
注意:
//用于测试使用结构体来解析图片数据时,图片会180°显示后还原显示函数
void fb_draw(unsigned char* pdata)
{
//unsigned char* pdata=gImage_320480;
unsigned int x,y,cnt;
unsigned int a=0;
/*数据和使用image2lcd获取的不一样 这里会旋转180度颠倒
即第一个像素放到最后一个像素点像素,依次类推了*/
a= HEIGHT*WIDTH*3-3;//让a一开始就指向了最后一个像素的第一个字节
for(y=0;y
is_bmp("cute_pic.bmp");
bmp_analyze("cute_pic.bmp");
smen_len = xres_virtual * yres_virtual * bpp / 8
若调用之前没有修改的显示图片函数,则会180°倒置 如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EpPJinvf-1570028293301)(1E94ED09D0EB467E824F9370DDCEE951)]
调用上面修改之后的fb_draw函数,则会正常显示如下:”
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-g5dpCreK-1570028293301)(FCDB3B7AE5354B6CAED5EB7C109086FD)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7RqjGE1N-1570028293302)(D2A7680579BC45439B8F0D4123910267)]
(1)去掉测试显示时头文件形式提供的图片显示相关的东西
debug宏添加好后,要使能输出可以有2种方式:
第一种:在debug宏定义之前定义DEBUG宏。
#define DEBUG //打开调试信息输出的开关
// debug宏的定义
#ifdef DEBUG
#define debug(...) \
{ \
fprintf(stderr, "[debug][%s:%s:%d] ", \
__FILE__, __FUNCTION__, __LINE__); \
fprintf(stderr, __VA_ARGS__); \
}
#else
#define debug(...)
#endif
第二种:在编译参数中添加-DDEBUG编译选项。(在makefile中添加)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-L3HQS8vw-1570028293303)(AB4DB63A7A10497DBD3A7ECDD8AB4127)]
//封装图片各种信息
//封装图片各种信息
typedef struct pic_info
{
char* pathname;//路径和文件名字
unsigned int width;//位图宽度
unsigned int height;//位图高度
unsigned int bpp;//位图bpp
char *pData;//指向图片有效数据存储的buff
}pic_info;
从而需要修改相关代码。
//path是bmp图片的pathname
//该函数解析path图片,并将图片数据丢到bmp_buf中
//返回值错误时返回-1,正确返回0
int bmp_analyze(struct pic_info *pPic)
{
int fd=-1;
BitMapFileHeader fheader;
BitMapInfoHeader info;
ssize_t ret=-1;
unsigned long len;
//int i=0;
//第一步:打开BMP图片
fd=open(pPic->pathname,O_RDONLY);
if(fd<0)
{
fprintf(stderr,"open %s error.\n",pPic->pathname);
return -1;
}
// 第二步: 读取文件头信息
ret=read(fd,&fheader,sizeof(fheader));
debug("bfsize =%ld.\n",fheader.bfSize);//位图大小
debug("boffsize =%ld.\n",fheader.bfOffBits);//有效信息偏移量
#if 0
for( i=0;iwidth = info.biWidth;//填充图片的各个数据
pPic->height =info.biHeight;
pPic->bpp = info.biBitCount;// 利用输出型参数
debug("image resolution: %d * %d, bpp=%d.\n", pPic->width, pPic->height, pPic->bpp);
// 第三步: 读取图片有效信息
// 先把文件指针移动到有效信息的偏移量处
//然后读出图片大小=info.biHeight*info.biWidth*info.biBitCount/8个字节,这个公式在驱动frambuff有说明
lseek(fd,fheader.bfOffBits,SEEK_SET);//从文件开始的位置开始
len=info.biHeight * info.biWidth * info.biBitCount /8;
debug("len put to buff :%ld.\n",len);
read(fd,bmp_buf,len);
pPic->pData = bmp_buf;
//把内容丢到fb中去显示
fb_draw(pPic);//用于测试使用结构体来解析图片数据时,图片会180°显示后还原显示函数
close(fd);
return 0;
}
//用于测试使用结构体来解析图片数据时,图片会180°显示后还原显示函数
void fb_draw(struct pic_info *pPic)
{
char* pData=pPic->pData; //指针指向图像数组
//const char *pData = (const char *)pPic->pData;
unsigned int x,y,cnt;
unsigned int a=0;
debug("image resolution: %d * %d, bpp=%d.\n", pPic->width, pPic->height, pPic->bpp);
if((pPic->bpp !=24))
{
fprintf(stderr,"bpp %s is not support.\n",pPic->bpp);
return -1;
}
/*数据和使用image2lcd获取的不一样 这里会旋转180度颠倒
即第一个像素放到最后一个像素点像素,依次类推了*/
a = pPic->height * pPic->width * 3 - 3;//让a一开始就指向了最后一个像素的第一个字节
for (y=0; y<(pPic->height); y++)
{
for (x=0; x<(pPic->width); x++)
{
cnt = WIDTH * y + x;/*cnt始终都是framebuff像素点的编号,注意这里的WIDTH是屏幕的高度*/
*(pfb+cnt)=((pData[a+0]<<16)|(pData[a+1]<<8)|(pData[a+2]<<0));
a-=3;/*由于空缺一部分,像素点编号与像素点矩阵不存在倍数关系了,此时应该三个三个地传送进来*/
}
}
}
} }}
struct pic_info pictrue;//要显示的图片
// 测试bmp图片显示,ok
pictrue.pathname = "cute_pic.bmp";// 指向要显示的图片
bmp_analyze(&pictrue);
在这个过程中遇到的问题:一定要多用DEBUG宏以控制调试信息输出,例如我遇到了刚开始段错误以及图片不正常显示等问题,都是跟踪debug宏输出调试信息解决:截图如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Q7suSW5M-1570028295463)(A55015739417449E9DA6413A53AF013D)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-z0Y7tgBb-1570028293304)(EB2BDF4E94F447579A7E58BE8AD4BC3E)]
(1)属于二进制文件。
(2)有其固定的识别特征,后面我们判断是否为jpg图片,需要识别特征http://www.cnblogs.com/Wendy_Yu/archive/2011/12/27/2303118.html
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kWfIx3oM-1570028293305)(028CAD3110E342D495E2A018F13EC352)]
(3)是经过压缩的图片格式。
(1)jpg图片中的二进制数并不对应像素数据。
(2)LCD显示器的接口仍然是framebuffer。
(3)要显示jpg图片必须先解码jpg得到相应的位图数据。
(1)图片编码和解码对应着压缩和解压缩过程
(2)编码和解码其实就是一些数学运算(压缩度、算法复杂度、时间、清晰度)
(3)软件编解码和硬件编解码需要频繁进行编解码的话,一般使用硬件编解码。
(4)不同的图片格式其实就是编解码的算法不同,结果是图片特征不同
(5)编程实战:使用开源编解码库
(1)基于linux的开源软件;
(2)C语言编写(gcc、使用Makefile管理);
(3)提供JPEG图片的编解码算法实现;
(1)经典版本v6b:https://sourceforge.net/projects/libjpeg/files/libjpeg/6b/
(2)最新版本v9b:http://www.ijg.org/
(1)移植(源码下载、解压、配置、修改Makefile、编译或交叉编译)
总结:静态库和头文件,是在编译链接过程中需要的,因此要把静态库.a文件和头文件.h文件放到ubuntu的文件系统中。
动态库是在运行时需要的,所以动态库so文件要放到开发板的文件系统中(放的过程就叫部署)。
(3)注意三个编译链接选项:-I -l(小L) -L
举例如-I:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1yTyLgOS-1570028293306)(2B410CAF37F6411894CBC0E744109972)]
总结:-l(小写L)是告诉链接器要链接的动态库的名字,而-L是告诉链接器要链接的动态库的路径。
(1)源码下载、解压至/root/decodeporting/目录下。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-42S0TZJA-1570028293307)(B5B1205C32FB487F9F3E038F90100C38)]
(2)编译前的配置(分析configure文件的usage、借鉴前辈的设置)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1Kkgv1sf-1570028293307)(377FB57A528F4FCE91DD7AB6C597EBAF)]
得到应该在/root/decodeporting/jpeg-6b目录下执行下面命令:
./configure --prefix=/opt/libcode --exec-prefix=/opt/libcode --enable-shared --enable-static-build=i386 -host=arm
说明:/opt/libcode:用于存放移植后得到的3个文件,所以我们需要先建立这个目录
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PRPsXThY-1570028293308)(AAB032DBC7124B72B33A4F0BDEC6D82F)]
指定编译结果放置的目录(如果没有则需要先建立相应的目录)
配置完成后生成了makefile文件,通过查看知道需要在/opt/libcode中创建include、bin、lib目录。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ssiiMTdD-1570028293309)(0FA0FF963EA94C1DAF84E2AF8FFB634D)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-00fVttTK-1570028293310)(8E4BBCC6A90B4D50BF14DD9FD7825A5F)]
(3)Makefile检查,主要查看交叉编译设置是否正确
CC=gcc 改为 CC=arm-linux-gcc //编译器,如果不改,只能在ubuntu使用,不能在开发板使用。
AR=ar rc 改为 AR=arm-linux-ar rc
AR2=ranlib 改为 AR2=arm-linux-ranlib
(4)编译:执行make命令。
(5)安装:执行make install-lib;
安装就是将编译生成的库文件、头文件、可执行文件分别装载到–prefix --exec-prefix所指定的那些目录中去。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2SyFEl6H-1570028293311)(4950154F750A4101A3134EF8E7337367)]
前面只是完成移植,相关文件都在ubuntu上。我们要把动态链接库(.so文件)放到开发板的根文件系统中(/root/porting_x210/rootfs/rootfs),可以考虑三者之一:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iILIW5AC-1570028293312)(B2A88702CAF84D8FB75C5CA24B63EBE9)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2n67efTl-1570028293313)(9E9B683BCA8A4CFF99DAC980FE0F1964)]
(1)思路一:网络上找别人使用过后写的文档、博客等作为参考。
(2)思路二:看库源码自带的文档(说明文档和示例代码)。我们从思路二出发。
(1)说明文档:README和libjpeg.doc
(2)示例代码:example.c
example.c测试程序提供了两个接口:
写jpeg文件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mR27RL8z-1570028293314)(90878E2F277C49A5835043BC095FF187)]
读jpeg文件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-weJUH05t-1570028293314)(F546B1326276447E9F88F109D10587FC)]
另外,还定义了几个外部变量和一个外部函数:
extern JSAMPLE * image_buffer;
extern int image_height;
extern int image_width;
void put_scanline_someplace(char *buf, int count);
这个函数就是在读jpeg文件时,扫描一行的数据通过这个函数传出
/*
* 本文件用来解码jpg图片,并调用fb.c中的显示接口来显示到lcd上
*/
#include
#include // for debug
#include
#include
#include
#include
struct my_error_mgr
{
struct jpeg_error_mgr pub; /* "public" fields */
// jmp_buf setjmp_buffer; /* for return to caller */
};
typedef struct my_error_mgr * my_error_ptr;
// 自己定义的错误处理函数
METHODDEF(void)my_error_exit (j_common_ptr cinfo)
{
//my_error_ptr myerr = (my_error_ptr) cinfo->err;
//(*cinfo->err->output_message) (cinfo);
fprintf(stderr, "my_error_exit\n");
//longjmp(myerr->setjmp_buffer, 1);
}
/*
* 函数功能: 解码jpg图片,并将解码出来的数据存储
* 函数参数: pPIC,记录源jpg图片,解码出来的图片宽高、图片数据缓冲区等信息
* 返回值 : 成功解码则返回0,失败则返回-1
*/
int jpg_analyze(struct pic_info *pPic)
{
struct jpeg_decompress_struct cinfo; // cinfo贯穿整个解码过程的信息记录和传递的数据结构
struct my_error_mgr jerr; // 错误处理的
//JSAMPARRAY buffer = NULL; // 指向解码行数据的指针
char * buffer = NULL;
FILE * infile; // 指向fopen打开源jpg图片文件的指针
int row_stride; // 解码出来的一行图片信息的字节数
if ((infile = fopen(pPic->pathname, "rb")) == NULL)
{
fprintf(stderr, "can't open %s\n", pPic->pathname);
return -1;
}
// 第1步: 错误处理函数部分的绑定
cinfo.err = jpeg_std_error(&jerr.pub);
jerr.pub.error_exit = my_error_exit;
// 给解码器做必要的内存分配和数据结构的初始化
jpeg_create_decompress(&cinfo);
// 第2步: 将fopen打开的源jpg图片和解码器相关联
jpeg_stdio_src(&cinfo, infile);
// 第3步: 读jpg文件头
jpeg_read_header(&cinfo, TRUE);
//打印出图片的宽度高度信息等
debug("image resolution: %d * %d, bpp/8=%d.\n",
cinfo.output_width, cinfo.output_height, cinfo.output_components);
// 解码完了,做各种清理工作
jpeg_destroy_decompress(&cinfo);
fclose(infile);
return 0;
}
pictrue.pathname = "cute_pic.jpg";// 指向要显示的图片
jpg_analyze(&pictrue);
(1)测试代码,先试图读取jpg图片头信息。
(2)问题排除
注意-I、-l、-L三个编译链接选项的使用
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sopy99CJ-1570028293315)(DEA568A9B0354A7197E0266DB241057B)]
重新make&make cp,然后启动开发板,运行。run.sh脚本,能正常打印信息,但当我们把lib目录下的动态链接文件删除后,从新运行如下,显示错误。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pd0iigYt-1570028293316)(33FBA27822014DEFB0DA8FF56E14AA5C)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xM7ubpjT-1570028293317)(E61CEBABD49E427C961318ED635FB27A)]
(1)一般放到开发板根文件系统/lib或者/usr/lib下
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nUfcVOF5-1570028293318)(5E99CC674B9C4D05A5C5172E0E75E3A3)]
(2)放到自定义的第三方的目录
(在开发板根文件中新建/opt/mylib/目录,用于存放动态库)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hhtPeh5p-1570028293318)(BD30339BB3674C40A22F9026B2D74B4E)]
将该自定义第三方目录导出到环境变量LD_LIBRARY_PATH下即可。
export LD_LIBRARY_PATH=/opt/mylib:$LD_LIBRARY_PATH
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HDhapWrH-1570028293319)(9352EB30DE4E4E999510DE73E8BE569A)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cgfuI58T-1570028293320)(11C16DA371884FD3B36B71D21360CB28)]
在fb_jpeg.c文件中的jpg_analyze函数中继续添加源码如下(注意,都是根据example.c的步骤添加修改的):
// 第1步: 错误处理函数部分的绑定
cinfo.err = jpeg_std_error(&jerr.pub);
jerr.pub.error_exit = my_error_exit;
// 给解码器做必要的内存分配和数据结构的初始化
jpeg_create_decompress(&cinfo);
// 第2步: 将fopen打开的源jpg图片和解码器相关联
jpeg_stdio_src(&cinfo, infile);
// 第3步: 读jpg文件头
jpeg_read_header(&cinfo, TRUE);
// 第4步: 启动解码器
jpeg_start_decompress(&cinfo);
debug("image resolution: %d * %d, bpp/8=%d.\n",
cinfo.output_width, cinfo.output_height, cinfo.output_components);
// 解码出来的数据一行的字节数
row_stride = cinfo.output_width * cinfo.output_components;
buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
if (NULL == buffer)
{
fprintf(stderr, "cinfo.mem->alloc_sarray error.\n");
return -1;
}
// 第5步: 逐行解码,并将解码出的数据丢到事先准备好的缓冲区去
while (cinfo.output_scanline < cinfo.output_height)
{
// 解码一行信息,并且丢到buffer中
jpeg_read_scanlines(&cinfo, buffer, 1);
// 将buffer中这一行数据移走到别的地方去暂存或者使用,总之是要腾出buffer空间
// 来给循环的下一次解码一行来使用
memcpy(pPic->pData + (cinfo.output_scanline-1) * row_stride, buffer, row_stride);
}
// 第6步: 解码完了,做各种清理工作
jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
fclose(infile);
//显示该图片,先填充pPic的数据
pPic->width = cinfo.output_width;
pPic->height = cinfo.output_height;
pPic->bpp = cinfo.output_components * 8;
fb_draw(pPic);
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Lxf9N4iO-1570028293321)(4C252DD4039F465C8E472329B321EC79)]
对pictrue.pData 缓存区必须先指定填充大小,
// ②测试jpg图片显示
pictrue.pathname = "cute_pic.jpg";// 指向要显示的图片
pictrue.pData = bmp_buf;
jpg_analyze(&pictrue);
从新make&&make cp.,运行脚本,开发板显示图片有问题。
(1)根据LCD错误的显示状态,分析有可能是显示函数fb_draw中的图片宽高数据有误,于是在fb_draw函数中添加debug打印出宽和高来。结果发现是对的。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UpJaS1Tm-1570028293322)(C18EA21AA593465AAA3BBA366367BBE2)]
(2)显示函数中的图片宽高和fb宽高都是对的,结果显示时还是只有一溜(其余位置黑屏),可能的一个原因就是:显示数据本身不对,很多都是0。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-auLfphsS-1570028293323)(B6CCE5C0E9F14E0ABB14633E95409E8B)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kaw9ATL2-1570028293324)(F395199C15B6419EBDFBF35F4AA0016B)]
(3)这些待显示数据为什么会错?
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Vkp7C8L4-1570028293326)(DAFADBC0E41F4719A566AEC825768CF9)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9XM7DlKT-1570028293326)(29E9D6CAA3DC45389EDCCE3E8E87A5D7)]
(4)截至目前已经锁定问题,就是jpeg_read_scanlines解码出来的数据本身就不对。
(5)可能的问题
(6)没有思路怎么办
int jpg_analyze(struct pic_info *pPic)
{
.......
//JSAMPARRAY buffer = NULL; // 指向解码行数据的指针 这是原生的
char * buffer = NULL;
............................
// 第4步: 启动解码器
jpeg_start_decompress(&cinfo);
debug("image resolution: %d * %d, bpp/8=%d.\n",
cinfo.output_width, cinfo.output_height, cinfo.output_components);
// 解码出来的数据一行的字节数
row_stride = cinfo.output_width * cinfo.output_components;
/*按照提供的example.c,这里这样使用就是有问题,所以解码出来的数据全是0,故我们选择下面另一种方法,自己申请空间*/
//buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
buffer = (char *)malloc(row_stride);
if (NULL == buffer)
{
fprintf(stderr, "cinfo.mem->alloc_sarray error.\n");
return -1;
}
// 第5步: 逐行解码,并将解码出的数据丢到事先准备好的缓冲区去
while (cinfo.output_scanline < cinfo.output_height)
{
// 解码一行信息,并且丢到buffer中
//jpeg_read_scanlines(&cinfo, buffer, 1);
jpeg_read_scanlines(&cinfo, &buffer, 1);
.............
}
编译拷贝,重启开发板运行,就能显示图片了(但图片是翻过来,还有RGB不对) 。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gP5rv6a6-1570028293327)(8FD52B9118C849FEB98E343DBCCE9827)]
(7)解决了buffer申请导致的问题之后,我们再来解决2个遗留的问题
void fb_draw2(const struct pic_info *pPic)
{
const char *pData = (const char *)pPic->pData; // 指针指向图像数组
unsigned int cnt = 0, a = 0;
unsigned int x, y;
if ((pPic->bpp != 32) && (pPic->bpp != 24))
{
fprintf(stderr, "BPP %d is not support.\n", pPic->bpp);
return;
}
a = 0;
for (y=0; yheight; y++)
{
for (x=0; xwidth; x++)
{
//cnt表示当前像素点的编号
cnt = WIDTH * y + x;
// 当前像素点对应的图像数据的RGB就应该分别是:
// pData[cnt+0] pData[cnt+1] pData[cnt+2]
// 当前像素点的数据
*(pfb + cnt) = ((pData[a+2]<<0) | (pData[a+1]<<8)| (pData[a+0]<<16));
//*p = ((pData[cnt+0]<<16) | (pData[cnt+1]<<8)| (pData[cnt+2]<<0));
a += 3;
}
}
}
(8)添加了fb_draw2函数并且调用后,2个遗留问题彻底解决。至此,jpg图片显示完美实现。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KdXBagMd-1570028293336)(677469A2D0244133A3AAC8DDF98E846E)]
(1)加上jpg图片格式识别:判断开头和结尾的特征字节。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oiTagJUQ-1570028293338)(1897C78CE11B49588308F94D0CBED565)]
// 函数功能: 判断一个图片文件是不是jpg图片
// 函数参数: path是图片文件的pathname
// 返回值: 如果是jpg则返回0,不是则返回1,错误返回-1
int is_jpg(const char *path)
{
FILE *file = NULL;
char buf[2] = {0};
// 打开文件
file = fopen(path, "rb");
if (NULL == file)
{
fprintf(stderr, "fopen %s error.\n", path);
fclose(file);
return -1;
}
// 读出前2个字节
fread(buf, 1, 2, file);
debug("read: 0x%x%x\n", buf[0], buf[1]);
// 判断是不是0xffd8
if (!((buf[0] == 0xff) && (buf[1] == 0xd8)))
{
fclose(file);
return 1; // 不是jpg图片
}
// 是0xffd8开头,就继续
// 文件指针移动到倒数2个字符的位置
fseek(file, -2, SEEK_END);
// 读出2个字节
fread(buf, 1, 2, file);
debug("read: 0x%x%x\n", buf[0], buf[1]);
// 判断是不是0x
if (!((buf[0] == 0xd9) && (buf[1] == 0xa)))
{
fclose(file);
return 1; // 不是jpg图片
}
fclose(file);
return 0;
}
// ②测试jpg图片显示
ret=is_jpg("cute_pic.jpg");
printf("ret = %d.\n",ret);
pictrue.pathname = "cute_pic.jpg";// 指向要显示的图片
pictrue.pData = bmp_buf;
jpg_analyze(&pictrue);
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hT8VQJZe-1570028293339)(4A9DEE52195D4D79B3D9CF90B9011F36)]
(2)对外封装好用的jpg图片显示函数
// 封装的一个对外使用的jpg显示函数
// 本函数对外只需要一个jpg图片的pathname即可,那些复杂的数据结构都是jpg显示模块内部处理的
// 正确显示图片返回0,显示过程中出错则返回-1
int display_jpg(const char *pathname)
{
int ret = -1;
struct pic_info picture;
// 第一步: 检测给的图片是不是jpg图片
ret = is_jpg(pathname);
if (ret != 0)
{
return -1;
printf("ret = %d.\n",ret);
}
printf("ret = %d.\n",ret);
// 第二步: 解析该jpg图片
picture.pathname = pathname;
picture.pData = rgb_buf;
jpg_analyze(&picture);
// 第三步: 显示该jpg图片
fb_draw2(&picture);
}
(3)对外封装好用的bmp图片显示函数
// 封装的一个对外使用的bmp显示函数
// 本函数对外只需要一个bmp图片的pathname即可,那些复杂的数据结构都是bmp显示模块内部处理的
// 正确显示图片返回0,显示过程中出错则返回-1
int display_bmp(const char *pathname)
{
int ret = -1;
struct pic_info picture;
// 第一步: 检测给的图片是不是jpg图片
ret = is_bmp(pathname);
if (ret != 0)
{
return -1;
printf("ret = %d.\n",ret);
}
printf("ret = %d.\n",ret);
// 第二步: 显示该jpg图片
picture.pathname = pathname;
picture.pData = rgb_buf;
bmp_analyze(&picture);
}
主函数调用:编译拷贝,重启运行开发板,开发板图片正常显示,先显示jpg图片,3s后显示bmp图片,完美解决所以小问题。
// ③测试新的显示接口函数jpg图片显示和bmp图片显示
display_jpg("cute_pic2.jpg");
sleep(3);
display_bmp("cute_pic.bmp");
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-r9PaEWNd-1570028293339)(6A684775A885476FBB5016BC74A25F34)]
(1)png更像是jpg而不像是bmp;
(2)png和jpg都是压缩格式的图片,都是二进制文件,不同之处是压缩和解压缩的算法不同。
(3)通过libjpeg来编解码jpg图片,那么同样有一个libpng用来编解码png图片。
(4)工作思路和顺序
找到并移植并部署libpng,然后查readme和其他文档示例代码等来使用libpng提供的API来对png图片进行解码,并将解码出来的数据丢到framebuffer中去显示。
root@wwj:~/decodeporting# cp /mnt/hgfs/Linux/winshare/x210kernel/tupian_project/libpng-1.6.6.tar.gz ./
root@wwj:~/decodeporting# tar -zxvf libpng-1.6.6.tar.gz
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kMNv4Ks3-1570028293340)(DE86545FFEF74281A0AF742027A6B5E8)]
./configure --host=arm-linux --enable-shared --enable-static --prefix=/opt/libcode
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ieZ15hGA-1570028293341)(F555948F39AE4DE3BEB966D7A8B43460)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tHI4Y2ZU-1570028293342)(5F69EC1AE95E418CBB7A18A5F23DF9E1)]
root@wwj:~/decodeporting/zlib-1.2.8# export CC=arm-linux-gcc
root@wwj:~/decodeporting/zlib-1.2.8# ./configure -shared --prefix=/opt/libcode
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ym3IoAFZ-1570028293343)(D762437977594388BE1A40866B580906)]
④make && make install:执行后/out/libcode目录下的lib和include目录下就有zlib的静态库动态库和头文件了,然后回到上面的libpng的配置步骤
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9NCHbQz5-1570028293349)(A5F829A8813A40E58DABE79307F097CB)]
原因是因为没有导出相关环境变量,所以libpng在配置的时候找不到刚才移植的zlib库的库文件和头文件。
export LDFLAGS="-L/opt/libcode/lib"
export CFLAGS="-I/opt/libcode/include"
export CPPFLAGS="-I/opt/libcode/include"
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vEjg5ap0-1570028293350)(175E21CB39F9461188F34D576F6FB4A0)]
然后在/opt/libcode/lib目录下,可以看到动态库文件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ffGuKGWX-1570028293350)(99155F8BD8AE458DAFD98A667B54E254)]
(1)readme
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-29r8cYhs-1570028293351)(C1819047A3694F849462D862B5537D6F)]
(2)libpng-manual.txt
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IX8ZQYtd-1570028293352)(150DFB1780DD47D8BAFB9E2D9B7B6878)]
(3)example.c 和 pngtest.c
新建fb_png.c,并将之前的fb_jpeg.c中的函数原型cp过来修改,并在子文件夹下makefile包含头文件等,这里不再赘述
int is_png(const char *path)
{
FILE *fp = NULL;
char buf[PNG_BYTES_TO_CHECK];
/* Open the prospective PNG file. */
if ((*fp = fopen(file_name, "rb")) == NULL)
return -1;
/* Read in some of the signature bytes */
if (fread(buf, 1, PNG_BYTES_TO_CHECK, fp) != PNG_BYTES_TO_CHECK)
return -1;
/* Compare the first PNG_BYTES_TO_CHECK bytes of the signature. Return nonzero (true) if they match */
return(!png_sig_cmp(buf, (png_size_t)0, PNG_BYTES_TO_CHECK));
}
然后同样步骤将之前jpeg显示函数cp过来修改,我们这里只是先测试is_png函数能否工作。
int display_png(const char *pathname)
{
int ret = -1;
struct pic_info picture;
// 第一步: 检测给的图片是不是jpg图片
ret = is_png(pathname);
if (ret != 0)
{
return -1;
printf("ret = %d.\n",ret);
}
printf("ret = %d.\n",ret);
/*
// 第二步: 解析该jpg图片
picture.pathname = pathname;
picture.pData = rgb_buf;
jpg_analyze(&picture);
// 第三步: 显示该jpg图片
fb_draw2(&picture);
*/
}
//④测试png图片显示
display_png("cute_pic4.png");//测试是否为png文件
make编译报错如下:没有找到这个,原因是没有包含相关头文件 怎么解决?
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-x9k8W7fl-1570028293353)(367344F78ED748C08E3B9F067829EB30)]
我们可以在ubuntu中使用grep命令查找这个变量头文件在那?
grep "PNG_BYTES_TO_CHECK" * -nR
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SCUgs6wV-1570028293354)(4333D403D98D48F39ACDC12A03395C2B)]
我们也在开始处直接宏定义即可
继续make,报错如下,包含了头文件的,为什么还是找不到这个函数,原因是主Makefile 没有链接进来
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-soHKLIVm-1570028293354)(2F887788925D4B0CB4F302C28DF961F7)]
从新make&&make cp…重启开发板,运行脚本,显示找不到lib相关动态库
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BOtjiVOT-1570028293355)(79774617725B4D5AA2CFB9897C76AF0C)]
解决方法:我们将之前生成的动态库拷贝到我们的跟文件系统的目录下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Br8MkVY1-1570028293356)(F010731D32354AEF8947303C8BC946C6)]
然后从新make &&make cp ,运行后并没有打印 is_png函数相关信息,经过debug排查问题,发现错误(方法就是使用debug定位错误在最后的png_sig_cmp函数这,然后使用SI建立libpng-1.6.6的工程,找到这个函数的原型,分析它的功能,发现正常匹配的话,返回值应该是0,但是我们这里使用!取反了,故判断不是png),修改,从新执行
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-C9ZWQPHz-1570028293357)(FD1C79F424904EABA29A61157858E5E2)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zFW82L9K-1570028293358)(16BB1996F2454DFFA52FB94F596DE013)]
这个函数参考example.c中的解码函数read_png函数了(因为过于复杂),我们选择直接在网上参考别人的。
int png_analyze(struct pic_info *pPic)
{
FILE *fp = NULL;
png_structp png_ptr;
png_infop info_ptr;
int color_type;
png_bytep* row_pointers;
unsigned long len = 0;
int pos = 0;
int i = 0, j = 0;
if ((fp = fopen(pPic->pathname, "rb")) == NULL)
{
fprintf(stderr, "can't open %s\n", pPic->pathname);
return -1;
}
// 第1步: 相关数据结构实例化
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
if (png_ptr == 0)
{
fclose(fp);
return -1;
}
info_ptr = png_create_info_struct(png_ptr);
if (info_ptr == 0)
{
png_destroy_read_struct(&png_ptr, 0, 0);
fclose(fp);
return -1;
}
// 第2步: 设置错误处理函数
if (setjmp(png_jmpbuf(png_ptr)))
{
png_destroy_read_struct(&png_ptr, &info_ptr, 0);
fclose(fp);
return -1;
}
// 第3步: 将要解码的png图片的文件指针和png解码器绑定起来
png_init_io(png_ptr, fp);
// 第4步: 读取png图片信息
png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_EXPAND | PNG_TRANSFORM_STRIP_ALPHA, 0);
// 第5步: 相关图片信息打印出来看一看
color_type = info_ptr->color_type;
debug("color_type = %d\n", color_type);
pPic->width = info_ptr->width;
pPic->height = info_ptr->height;
pPic->bpp = info_ptr->pixel_depth;
len = info_ptr->width * info_ptr->height * info_ptr->pixel_depth / 8;
debug("width = %u, height = %u, bpp = %u\n", pPic->width, pPic->height, pPic->bpp);
//打印png图片相关信息
return 0;
}
make 报错如下:没找到这个文件,说明我们配置libpng的时候这几个文件没有生成,需要我们手动添加到动态库。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rYJYcEAu-1570028293359)(D5CB69D31E744F34BEE454DD05A4944D)]
依次执行以下命令即可:
cp pngstruct.h /opt/libcode/include/
cp pnginfo.h /opt/libcode/include/
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Aw5FpM0u-1570028293359)(900D1EEE7A4B4A8694CE7BA93D12AE48)]
然后make && make cp,…从新启动开发板,运行脚本,显示如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nqXVTaoZ-1570028293360)(D2FF42F0690D49EB892F76A3EAA5F801)]
在上一步中,已经实现将相关图片信息打印出来了,接下来就是图片的显示相关了。
继续对函数进行添加:
int png_analyze(struct pic_info *pPic)
{
// 第5步: 相关图片信息打印出来看一看
.......
// 第6步: 读取真正的图像信息
row_pointers = png_get_rows(png_ptr,info_ptr);
// 只处理RGB24位真彩色图片,其他格式的图片不管
// 第7步: 图像数据移动到我们自己的buf中
if(color_type == PNG_COLOR_TYPE_RGB)//PNG_COLOR_TYPE_RGB=2,和我们之前打印的信息要吻合
{
//memcpy(pPic->pData, row_pointers, len);/*直接这样不行,因为数据是乱的*/
for(i=0; iheight; i++)
{
for(j=0; j<3*pPic->width; j+=3)
{
pPic->pData[pos++] = row_pointers[i][j+0]; //red
pPic->pData[pos++] = row_pointers[i][j+1]; //green
pPic->pData[pos++] = row_pointers[i][j+2]; //blue
}
}
}
// 第8步: 收尾处理
png_destroy_read_struct(&png_ptr, &info_ptr, 0);
// close file
fclose(fp);
return 0;
}
主函数调用
//④测试png图片显示
display_png("cute_pic4.png");
然后make && make cp,…从新启动开发板,运行脚本,显示如下,且开发板正常显示PNG图片
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RAGV2YKS-1570028293361)(DCB95ACEBFFC47B58399AF514EC13A85)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nKvrT7Dq-1570028293362)(C6561FDA37464B3DBDACCA7827858480)]
到这里,对png图片的解码显示就搞定了。
(1)在物理磁盘存储层次上,用一个文件夹来管理;
(2)在程序中,用数据结构来管理。
(4)编程实战(细节见代码,下面是关键点)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YEwdwJbR-1570028293363)(87268EC3BE6C44B9B855B6A0B5B53FE5)]
readdir的使用====读取文件夹的文件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AY0KryjT-1570028293364)(98CEAA27434D458686A02A24C4F5487E)]
linux读取文件夹内容,我们直接百度,选择这篇文章参考,修改为自己的
https://blog.csdn.net/weixin_40535588/article/details/89668934
新建image_manage.h
typedef enum image_type
{
IMAGE_TYPE_BMP,
IMAGE_TYPE_JPG,
IMAGE_TYPE_PNG,
IMAGE_TPPE_UNKNOWN,
}image_type_e;
// 结构体用来封装一个图片的信息
typedef struct image_info
{
char pathname[PATHNAME_LEN]; // 图片文件的pathname
image_type_e type; // 图片文件的格式
}image_info_t;
新建image_manage.c, 使用readdir函数来读取文件夹内容
(readdir函数有问题,有时可以,有时不行,仔细阅读man手册,发现readdir函数中真正起作用的是lstat函数)
// images数组本来是空的,然后程序初始化时会去一个事先约定好的目录(image目录)下去
// 递归检索所有的文件及子文件夹,并且将所有的图片格式收集并且填充记录到images数组中
// 经过检索后,image数组中就记录了所有的图片,然后显示图片逻辑部分再去这个图片库中
// 拿出相应的图片来显示即可
// path是要去检索的文件夹的目录的路径
int scan_image(const char *path)
{
// 在本函数中递归检索path文件夹,将其中所有图片填充到iamges数组中去
DIR *dir;
struct dirent *ptr;
char base[1000];
if ((dir = opendir(path)) == NULL)
{
perror("Open dir error...");
exit(1);
}
// readdir函数每调用一次就会返回opendir打开的basepath目录下的一个文件,直到
// basepath目录下所有文件都被读完之后,就会返回NULL
while ((ptr = readdir(dir)) != NULL)
{
if(strcmp(ptr->d_name, ".")==0 || strcmp(ptr->d_name, "..")==0) ///current dir OR parrent dir
continue;
debug("d_name = %s.\n", ptr->d_name);
debug("d_type = %d, DT_REG = %d, DT_DIR = %d, DT_UNKNOWN = %d.\n",
ptr->d_type, DT_REG, DT_DIR, DT_UNKNOWN);
switch (ptr->d_type)
{
case DT_REG: // 普通文件
printf("d_name:%s/%s\n", path, ptr->d_name);
break;
case DT_DIR: // 文件夹
memset(base,'\0',sizeof(base));
strcpy(base,path);
strcat(base,"/");
strcat(base,ptr->d_name);
scan_image(base);
break;
case DT_UNKNOWN: // 不识别的文件格式
printf("unknown file type.\n");
break;
default:
break;
}
}
}
主函数调用该函数:
scan_image("./image");//readdir读取文件夹下相关内容
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mLcsAZVL-1570028293364)(E53B4EA5A57245498B1D152C0033B06C)]
/*
使用lstat函数来实现读取文件夹下的内容,因为使用readdir函数有问题
扫描目录,索引图片,并完成图片数据的初始化
参数:目录的路径
*/
int scan_image2(const char *path)
{
// 在本函数中递归检索path文件夹,将其中所有图片填充到iamges数组中去
DIR *dir;
struct dirent *ptr;
char base[1000];
struct stat sta;
if ((dir = opendir(path)) == NULL)
{
perror("Open dir error...");
exit(1);
}
// readdir函数每调用一次就会返回opendir打开的basepath目录下的一个文件,直到
// basepath目录下所有文件都被读完之后,就会返回NULL
while ((ptr = readdir(dir)) != NULL)
{
if(strcmp(ptr->d_name, ".")==0 || strcmp(ptr->d_name, "..")==0) ///current dir OR parrent dir
continue;
// 用lstat来读取文件属性并判断文件类型
memset(base,'\0',sizeof(base));
strcpy(base,path);
strcat(base,"/");
strcat(base,ptr->d_name);
lstat(base, &sta);
if (S_ISREG(sta.st_mode))
{
//printf("regular file.\n");
//printf("d_name:%s/%s\n", path, ptr->d_name);
// 如果是普通文件,就要在这里进行处理:
// 处理思路就是 先判定是否属于已知的某种图片格式,如果是则放到images数组中
// 如果都不属于则不理他
if (!is_bmp(base))
{
strcpy(images[image_index].pathname, base);
images[image_index].type = IMAGE_TYPE_BMP;
}
if (!is_jpg(base))
{
strcpy(images[image_index].pathname, base);
images[image_index].type = IMAGE_TYPE_JPG;
}
if (!is_png(base))
{
strcpy(images[image_index].pathname, base);
images[image_index].type = IMAGE_TYPE_PNG;
}
image_index++;
}
if (S_ISDIR(sta.st_mode))
{
//printf("directory.\n");
//printf("d_name:%s/%s\n", path, ptr->d_name);
scan_image2(base);
}
}
}
//打印出文件夹下图片的路径和文件名
void print_images(void)
{
int i;
printf("iamge_index = %d.\n", image_index);
for (i=0; i
测试print_images函数,主函数调用:
scan_image2("./image");
print_images();
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mTbZ7a2n-1570028293366)(4A769E0560F54CCD83D97AD7CED27F5E)]
//循环显示各个图片函数,并打印出文件路径和文件名
void show_images(void)
{
int i;
for (i=0; i
测试show_images函数,主函数调用://循环显示各个图片函数,并打印出文件路径和文件名
scan_image2("./image");
//print_images();
while(1)
{
show_images();
}
编译拷贝,运行开发板,能看到循环显示我们imag目录下的图片,且终端移植打印出各个图片的类型及其路径等相关信息。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-V9CU2FbQ-1570028293366)(7094E6834F6641808B5A5759E6CB6017)]
完成触摸屏驱动后,点击左右屏幕实现切换图片。
参考如下触摸屏驱动移植实战中的app_input目录下的程序,并修改为我们的
在image_manage.c中新建一下函数,
开发板上的触摸屏设备文件是/dev/input/event2(我这里是event2)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rFj7AdC6-1570028293367)(06488D27A01C4AC0838088DEFECA8619)]
//定义系统中的触摸屏设备的设备名
#define DEVICE_TOUCHSCREEN "/dev/input/event2"
/*
*检测触摸屏,根据结果实现图片上下切换
*参数:无传参
*/
int ts_updown(void)
{
// 第一步: 触摸屏的触摸操作检测
int fd = -1, ret = -1;
struct input_event ev;
fd = open(DEVICE_TOUCHSCREEN, O_RDONLY);// 打开设备文件
if (fd < 0)
{
perror("open");
return -1;
}
while (1)
{
// 读取一个event事件包
memset(&ev, 0, sizeof(struct input_event));
ret = read(fd, &ev, sizeof(struct input_event));
if (ret != sizeof(struct input_event))
{
perror("read");
close(fd);
return -1;
}
// 解析event包,才知道发生了什么样的输入事件
printf("-------------------------\n");
printf("type: %hd\n", ev.type);
printf("code: %hd\n", ev.code);
printf("value: %d\n", ev.value);
printf("\n");
}
// 关闭设备
close(fd);
// 第二步: 根据触摸坐标来翻页
return 0;
}
//⑥测试触摸翻页显示图片功能
scan_image2("./image");
ts_updown();
make &&make cp, 开发板运行该程序,触摸屏幕,终端显示坐标信息如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qj8K5A6s-1570028293368)(89E56667FE684193A3DD7DFE324C32F0)]
code 0表示x坐标,value为x的值;code 1表示y坐标,value为y的值。
修改ts_updown函数,使其能实现触摸翻页,红色部分为修改的源码
//定义触摸翻页区域的宽度
#define TOUCH_WIDTH 200
/*
*检测触摸屏,根据结果实现图片上下切换
*参数:无传参
*/
int ts_updown(void)
{
// 第一步: 触摸屏的触摸操作检测
int fd = -1, ret = -1;
struct input_event ev;
int i = 0; // 用来记录当前显示的是第几个图片
fd = open(DEVICE_TOUCHSCREEN, O_RDONLY);// 打开设备文件
if (fd < 0)
{
perror("open");
return -1;
}
while (1)
{
// 读取一个event事件包
memset(&ev, 0, sizeof(struct input_event));
ret = read(fd, &ev, sizeof(struct input_event));
if (ret != sizeof(struct input_event))
{
perror("read");
close(fd);
return -1;
}
// 第二步: 根据触摸坐标来翻页
if ((ev.type == EV_ABS) && (ev.code == ABS_X))
{
// 确定这个是x坐标 如果在这个0~200的宽度范围
if ((ev.value >= 0) && (ev.value < TOUCH_WIDTH))
{
// 上翻页
if (i-- <= 1)
{
i = image_index;
debug("i=%d.\n", i);
}
} //如果在这个1024-200 ~1024的宽度范围
else if ((ev.value > (WIDTH - TOUCH_WIDTH)) && (ev.value <= WIDTH))
{
// 下翻页
if (i++ >= image_index)
{
i = 1;
debug("i=%d.\n", i);
}
}
else
{
// 不翻页
}
show_image(i - 1);//将i用来记录当前显示的是第几个图片,然后传给这个函数,用于显示图片
}
/*
// 解析event包,才知道发生了什么样的输入事件
printf("-------------------------\n");
printf("type: %hd\n", ev.type);
printf("code: %hd\n", ev.code);
printf("value: %d\n", ev.value);
printf("\n");
*/
}
// 关闭设备
close(fd);
return 0;
}
//⑥测试触摸翻页显示图片功能
scan_image2("./image");
ts_updown();
make &&make cp, 开发板运行该程序,触摸屏幕,终端显示坐标信息如下:
(1)执行./run.sh后会阻塞,如果点击触摸屏,会在终端中显示测试的内容。
(2)在不同区域点一下,有不同的效果。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hGATF2JG-1570028293369)(C0C0B0C9E68547D79AE8D4A06B25A431)]
硬件平台使用使用s5pv210开发板,软件以linux平台开发。
支持解码显示bmp,png,JPEG图片,并通过点击触摸屏左右两端实现上下切换图片的效果
第三方库libpng、 libgpeg库的移植
图片文件的管理和检索,刚开始使用read函数,出现问题,后来使用lstat函数来实现读取文件夹下内容,实现目录扫描
通过判断头两个字符是否为”BM”,判断是否为BMP图片,BMP本身没有对数据进行压缩,所以可直接读取数据进行操作
判断是否为JPEG图片, 通过判断特点位是否为JPEG专用字符,进而确认为JPEG图片后,解码jpg图片(使用libjpeg库提供JPEG图片的编解码算法实现),并将解码出来相应的位图数据进行存储。显示该图片
通过调用libpng库函数png_sig_cmp,判断是否为PNG图片。显示PNG图片,运用libpng库,完成PNG图片的显示
TOUCH_WIDTH 200
/*
*检测触摸屏,根据结果实现图片上下切换
*参数:无传参
*/
int ts_updown(void)
{
// 第一步: 触摸屏的触摸操作检测
int fd = -1, ret = -1;
struct input_event ev;
int i = 0; // 用来记录当前显示的是第几个图片
fd = open(DEVICE_TOUCHSCREEN, O_RDONLY);// 打开设备文件
if (fd < 0)
{
perror(“open”);
return -1;
}
while (1)
{
// 读取一个event事件包
memset(&ev, 0, sizeof(struct input_event));
ret = read(fd, &ev, sizeof(struct input_event));
if (ret != sizeof(struct input_event))
{
perror(“read”);
close(fd);
return -1;
}
// 第二步: 根据触摸坐标来翻页
if ((ev.type == EV_ABS) && (ev.code == ABS_X))
{
// 确定这个是x坐标 如果在这个0~200的宽度范围
if ((ev.value >= 0) && (ev.value < TOUCH_WIDTH))
{
// 上翻页
if (i-- <= 1)
{
i = image_index;
debug(“i=%d.\n”, i);
}
} //如果在这个1024-200 ~1024的宽度范围
else if ((ev.value > (WIDTH - TOUCH_WIDTH)) && (ev.value <= WIDTH))
{
// 下翻页
if (i++ >= image_index)
{
i = 1;
debug(“i=%d.\n”, i);
}
}
else
{
// 不翻页
}
show_image(i - 1);//将i用来记录当前显示的是第几个图片,然后传给这个函数,用于显示图片
}
/*
// 解析event包,才知道发生了什么样的输入事件
printf("-------------------------\n");
printf(“type: %hd\n”, ev.type);
printf(“code: %hd\n”, ev.code);
printf(“value: %d\n”, ev.value);
printf("\n");
*/
}
// 关闭设备
close(fd);
return 0;
}
## 主函数调用该函数
//⑥测试触摸翻页显示图片功能
scan_image2("./image");
ts_updown();
make &&make cp, 开发板运行该程序,触摸屏幕,终端显示坐标信息如下:
(1)执行./run.sh后会阻塞,如果点击触摸屏,会在终端中显示测试的内容。
(2)在不同区域点一下,有不同的效果。
[外链图片转存中...(img-hGATF2JG-1570028293369)]
# 十七、总结与回顾
## 1、项目总结
### (1)项目描述:软硬件平台等
硬件平台使用使用s5pv210开发板,软件以linux平台开发。
支持解码显示bmp,png,JPEG图片,并通过点击触摸屏左右两端实现上下切换图片的效果
### (2)重点和难点
第三方库libpng、 libgpeg库的移植
图片文件的管理和检索,刚开始使用read函数,出现问题,后来使用lstat函数来实现读取文件夹下内容,实现目录扫描
### (3)主要技术:
- linux Framebuffer驱动移植
- linux input输入子系统移植
- linux i2c子系统
- 触摸屏驱动移植
- libjpeg库移植
- libpng库移植
#### 1.1.驱动模块(驱动模块主要的任务就是进行Framebuffer地址映射)
- linux Framebuffer驱动
参考前面我们学习的framebufer驱动,移植framebufer驱动。
- 触摸屏(gslX680)驱动
参考驱动篇触摸屏驱动,移植gslX680驱动。
#### 1.2.目录扫描,图片管理模块
- 目录扫描功能采用递归方法,扫描目录的所有文件,经过排除,最后只对普通文件做进一步处理。图片管理采用数组来组织。
#### 1.3.图片切换模块
- 完成触摸屏驱动后,点击左右屏幕实现切换图片。
#### 1.4.图片显示模块
- BMP显示
通过判断头两个字符是否为”BM”,判断是否为BMP图片,BMP本身没有对数据进行压缩,所以可直接读取数据进行操作
- JPEG显示
判断是否为JPEG图片, 通过判断特点位是否为JPEG专用字符,进而确认为JPEG图片后,解码jpg图片(使用libjpeg库提供JPEG图片的编解码算法实现),并将解码出来相应的位图数据进行存储。显示该图片
- 显示PNG图片
通过调用libpng库函数png_sig_cmp,判断是否为PNG图片。显示PNG图片,运用libpng库,完成PNG图片的显示