此处专门为相册模块加上解析和效果视频
其实很多事情只是看起来困难,慢慢做起来就会不断有思路了,关键是有目标就要动手
//缩放和图片(花样)展示很多地方都要用到,就在用到的地方写,不特地分开写了
音乐相册
首先是音乐相册
//音乐相册
#include "myiohead.h"
//获取触摸屏坐标
int get_x_y(int *touch_x,int *touch_y)
{
int flag = 0;
int to = open ("/dev/input/event0",O_RDWR);
if (-1 == to)
{
perror("打开触摸屏的驱动失败!");
exit(0);
}
struct input_event myevent;
while(1)
{
read(to,&myevent,sizeof(struct input_event));
if (myevent.type == EV_ABS)
{
if(myevent.code==ABS_X) //x坐标
//由于新开发板的坐标范围跟800*480不一致,按比例修正
//printf("你点击的坐标位置X坐标是:%d\n",myevent.value);
{
flag++;
* touch_x = (myevent.value*800)/1024;
}
if(myevent.code==ABS_Y) //y坐标
{
flag++;
* touch_y = (myevent.value*480)/600;
}
if (2 == flag)
{
flag = 0;
break;
}
}
}
close(to);
}
//普通展示图片
int showbmp(char *bmppath)
{
int bmpfd;
int lcdfd;
int w,h;
int i;
int x,y;
//打开你要显示的w*h大小的bmp
bmpfd=open(bmppath,O_RDWR);
if(bmpfd==-1)
{
perror("打开图片失败!\n");
return -1;
}
//读取图片的宽和高
lseek(bmpfd,18,SEEK_SET);
read(bmpfd,&w,4);//读取宽
read(bmpfd,&h,4);//读取高
//定义一个数组,依据图片的大小
char bmpbuf[w*h*3]; //char占1个字节
//定义另外一个数组,存放转换得到的ARGB数据
int lcdbuf[w*h]; //int占4字节
//定义中间变量。临时存放数据
int tempbuf[w*h];
//打开lcd驱动
lcdfd=open("/dev/fb0",O_RDWR);
if(lcdfd==-1)
{
perror("打开lcd失败!\n");
return -1;
}
//映射得到lcd的首地址
int *lcdmem=mmap(NULL,800*480*4,PROT_READ|PROT_WRITE,MAP_SHARED,lcdfd,0);
if(lcdmem==NULL)
{
perror("映射lcd失败!\n");
return -1;
}
//跳过bmp图片头信息54字节,从55字节开始读取
lseek(bmpfd,54,SEEK_SET);
//读取bmp图片的RGB数据
//每三个字节为一组,构成一个像素点的RGB数据
read(bmpfd,bmpbuf,w*h*3); //bmpbuf[0] bmpbuf[1] bmpbuf[2]
// B G R
//bmpbuf[3] bmpbuf[4] bmpbuf[5]
//把三个字节--》转换成四个字节
/*
细节分析如下:
lcdbuf[0]=0x00<<24|bmpbuf[0]<<16|bmpbuf[1]<<8|bmpbuf[2]
lcdbuf[1]=0x00<<24|bmpbuf[3]<<16|bmpbuf[4]<<8|bmpbuf[5]
*/
for(i=0; i<w*h; i++)
lcdbuf[i]=0x00<<24|bmpbuf[3*i+2]<<16|bmpbuf[3*i+1]<<8|bmpbuf[3*i];
//把颠倒的图片翻转过来
/*
细节分析如下:
lcdbuf[0] --->lcdbuf[479*800]
*/
for(x=0; x<w; x++)
for(y=0; y<h; y++)
//lcdbuf[(h-1-y)*w+x]=lcdbuf[y*w+x];
tempbuf[(h-1-y)*w+x]=lcdbuf[y*w+x];
//把转换后的数据写入lcd中(一一对应)
for (int j = 0; j < h; j++)
{
for(int i = 0,n = 0;i < w;i++)
{
*(lcdmem+(j*800)+i)=tempbuf[j*w+i];
//n++;
}
}
//关闭
close(bmpfd);
close(lcdfd);
return 0;
}
//定义一个结构体表示双向循环列表,为了省事把此双向链表类型定义为dlist
typedef struct doublelist
{
char data[100];
struct doublelist *next;
struct doublelist *fnext;
}dlist;
dlist * init_list()
{
dlist *head = calloc(1,sizeof(dlist));
// head->data = "1.bmp";
strcpy(head->data, "1.bmp");
head->next = head;
head->fnext = head;
return head;
}
//尾插
int insert_(char * newdata,dlist * head)
{
dlist * p =head;
while(p->next != head)
{
p = p->next;
}
dlist *newnode = calloc(1,sizeof(dlist));
//newnode->data = newdata;
strcpy(newnode->data, newdata);
newnode->next = head;
p->next = newnode;
head->fnext = newnode;
newnode->fnext = p;
}
//读取目录,获得图片名字
int read_dir(char *path,dlist * head)
{
DIR * dir = opendir(path);
if (NULL == dir)
{
perror("打开目录失败!");
exit(0);
}
struct dirent * rd = NULL;
while((rd = readdir(dir)) != NULL)
{
//printf("d_name : %s\n", rd->d_name);
if (rd->d_type == DT_REG)
{
//printf("这是普通文件!\n");
if (strstr(rd->d_name,".bmp") != 0)
{
insert_(rd->d_name,head);
}
}
}
return 0;
}
void * task(void * n)//循环播放相册
{
dlist * mydlist = init_list();
read_dir("/myphoto",mydlist);
char a[100] = "/myphoto/";
dlist * p =mydlist;
while(p->next != NULL)
{
p = p->next;
if (p == mydlist)
{
p = p->next;
}
bzero(a,100);
strcpy(a,"/myphoto/");
strcat(a,p->data);
showbmp(a);
sleep(1);
}
}
void * task1(void * n)
{
system("mplayer Apologize.mp3 &");
}
int main(int argc, char const *argv[])
{
pthread_t id;
pthread_create(&id,NULL,task, NULL);
pthread_t id1;
pthread_create(&id1,NULL,task1, NULL);
int *touch_x = calloc(1,1000);
int *touch_y = calloc(1,1000);
while(1)
{
get_x_y(touch_x,touch_y);
if ((*touch_x>742) && (*touch_y<36))
{
pthread_cancel(id);
pthread_cancel(id1);
system("killall -9 mplayer");
raise(9);
break;
}
}
return 0;
}
相册的缩略图
#include "myiohead.h"
//获取滑动方向的触摸屏坐标
int yxget_x_y(int *touch_x,int *touch_x1,int *touch_y,int *touch_y1)
{
int flag = 1;
int to = open ("/dev/input/event0",O_RDWR);
if (-1 == to)
{
perror("打开触摸屏的驱动失败!");
exit(0);
}
struct input_event myevent;
int count = 1;
while(1)
{
read(to,&myevent,sizeof(struct input_event));
if (myevent.type == EV_ABS)
{
if(myevent.code==ABS_X) //x坐标
//由于新开发板的坐标范围跟800*480不一致,按比例修正
//printf("你点击的坐标位置X坐标是:%d\n",myevent.value);
{
* touch_x1 = (myevent.value*800)/1024;
if (count)
{
* touch_x = (myevent.value*800)/1024;
count = 0;
}
}
if(myevent.code==ABS_Y) //y坐标
{
* touch_y1 = (myevent.value*480)/600;
if (flag)
{
* touch_y = (myevent.value*480)/600;
flag = 0;
}
}
}
if(myevent.type==EV_KEY && myevent.code==BTN_TOUCH && myevent.value==0)
{
//count = 0;
//printf("x0=%d,y0=%d\n", *touch_x,*touch_y);
//printf("x1=%d,y1=%d\n", *touch_x1,*touch_y1);
break;
}
}
close(to);
}
//花样展示图片
int special_showbmp(char *bmppath)
{
int bmpfd;
int lcdfd;
int i;
int x,y;
int w,h;
//打开你要显示的w*h大小的bmp
bmpfd=open(bmppath,O_RDWR);
if(bmpfd==-1)
{
perror("打开图片失败!\n");
return -1;
}
//读取图片的宽和高
lseek(bmpfd,18,SEEK_SET);
read(bmpfd,&w,4);//读取宽
read(bmpfd,&h,4);//读取高
//定义一个数组,依据图片的大小
char bmpbuf[w*h*3]; //char占1个字节
//定义另外一个数组,存放转换得到的ARGB数据
int lcdbuf[w*h]; //int占4字节
//定义中间变量。临时存放数据
int tempbuf[w*h];
//打开lcd驱动
lcdfd=open("/dev/fb0",O_RDWR);
if(lcdfd==-1)
{
perror("打开lcd失败!\n");
return -1;
}
//映射得到lcd的首地址
int *lcdmem=mmap(NULL,800*480*4,PROT_READ|PROT_WRITE,MAP_SHARED,lcdfd,0);
if(lcdmem==NULL)
{
perror("映射lcd失败!\n");
return -1;
}
//跳过bmp图片头信息54字节,从55字节开始读取
lseek(bmpfd,54,SEEK_SET);
//读取bmp图片的RGB数据
//每三个字节为一组,构成一个像素点的RGB数据
read(bmpfd,bmpbuf,w*h*3); //bmpbuf[0] bmpbuf[1] bmpbuf[2]
// B G R
//bmpbuf[3] bmpbuf[4] bmpbuf[5]
//把三个字节--》转换成四个字节
/*
细节分析如下:
lcdbuf[0]=0x00<<24|bmpbuf[0]<<16|bmpbuf[1]<<8|bmpbuf[2]
lcdbuf[1]=0x00<<24|bmpbuf[3]<<16|bmpbuf[4]<<8|bmpbuf[5]
*/
for(i=0; i<w*h; i++)
lcdbuf[i]=0x00<<24|bmpbuf[3*i+2]<<16|bmpbuf[3*i+1]<<8|bmpbuf[3*i];
//把颠倒的图片翻转过来
/*
细节分析如下:
lcdbuf[0] --->lcdbuf[479*800]
*/
for(x=0; x<w; x++)
for(y=0; y<h; y++)
//lcdbuf[(h-1-y)*w+x]=lcdbuf[y*w+x];
tempbuf[(h-1-y)*w+x]=lcdbuf[y*w+x];
// //把转换后的数据写入lcd中
// for(int i = 0;i < h;i++)
// {
// usleep(4000);
// write(lcdfd,&tempbuf[w*i],w*4);
// // *(lcdmem+(j*800)+i)=tempbuf[j*w+i];
// lseek(lcdfd,(800-w)*4,SEEK_CUR);
// }
//把转换后的数据写入lcd中
for (int j = 0; j < h; j++)
{
usleep(4000);
for(int i = 0,n = 0;i < w;i++)
{
*(lcdmem+(j*800)+i)=tempbuf[j*w+i];
//n++;
}
}
//关闭
close(bmpfd);
close(lcdfd);
return 0;
}
//缩放图片
int zoom1_showbmp(char *bmppath,int num)
{
int bmpfd;
int lcdfd;
int w,h;
//打开你要显示的w*h大小的bmp
bmpfd=open(bmppath,O_RDWR);
if(bmpfd==-1)
{
perror("打开图片失败!\n");
return -1;
}
//读取图片的宽和高
lseek(bmpfd,18,SEEK_SET);
read(bmpfd,&w,4);//读取宽
read(bmpfd,&h,4);//读取高
//定义一个数组,依据图片的大小
char bmpbuf[w*h*3]; //char占1个字节
//定义另外一个数组,存放转换得到的ARGB数据
int lcdbuf[w*h]; //int占4字节
//定义中间变量。临时存放数据
int tempbuf[w*h];
//打开lcd驱动
lcdfd=open("/dev/fb0",O_RDWR);
if(lcdfd==-1)
{
perror("打开lcd失败!\n");
return -1;
}
//映射得到lcd的首地址
int *lcdmem=mmap(NULL,800*480*4,PROT_READ|PROT_WRITE,MAP_SHARED,lcdfd,0);
if(lcdmem==NULL)
{
perror("映射lcd失败!\n");
return -1;
}
//跳过bmp图片头信息54字节,从55字节开始读取
lseek(bmpfd,54,SEEK_SET);
//读取bmp图片的RGB数据
//每三个字节为一组,构成一个像素点的RGB数据
read(bmpfd,bmpbuf,w*h*3); //bmpbuf[0] bmpbuf[1] bmpbuf[2]
// B G R
//bmpbuf[3] bmpbuf[4] bmpbuf[5]
//把三个字节--》转换成四个字节
/*
细节分析如下:
lcdbuf[0]=0x00<<24|bmpbuf[0]<<16|bmpbuf[1]<<8|bmpbuf[2]
lcdbuf[1]=0x00<<24|bmpbuf[3]<<16|bmpbuf[4]<<8|bmpbuf[5]
*/
for(int i=0; i<w*h; i++)
lcdbuf[i]=0x00<<24|bmpbuf[3*i+2]<<16|bmpbuf[3*i+1]<<8|bmpbuf[3*i];
//把颠倒的图片翻转过来
/*
细节分析如下:
lcdbuf[0] --->lcdbuf[479*800]
*/
for(int x=0; x<w; x++)
for(int y=0; y<h; y++)
//lcdbuf[(h-1-y)*w+x]=lcdbuf[y*w+x];
tempbuf[(h-1-y)*w+x]=lcdbuf[y*w+x];
/*//把转换后的数据写入lcd中,高缩小2倍,宽缩小2倍
for (int j = 0,m = 0; j < (h/2); j++,m = m+2)
{
for(int i = 0,n = 0;i < (w/2);i++,n = n+2)
{
*(lcdmem+(j*800)+i)=tempbuf[m*w+n];
}
}
*/
/* 要做到缩放,就要舍弃一些字节。如果行要缩小2分之1,列也是缩小2分之1,那么
行每2个只能映射一个,列每2个只能映射一个。一样的道理,如果行要缩小5分之1,列
要缩小3分之1,那么行每5个只能映射一个,列每3个只能映射一个。(间隔舍弃一些像
素点,人眼看不出他们太大的差别)*/
// 把转换后的数据写入lcd中,高缩小(h/160)倍,宽缩小w/160倍
int a = (num%5)*160;//800*480的屏幕一行最多放5张160*160的图片
int b = (num/5)*160;//800*480的屏幕一行最多放5张160*160的图片
for (int j = 0,m = 0; j < (h/(h/160)); j = j-b+1,m = m+(h/160))
{
j = j+b;//j不能一开始就等于b,所以转个弯
for(int i = 0,n = 0;i < (w/(w/160));i = i-a+1,n = n+(w/160))
{
i = i + a;//i不能一开始就等于a,所以转个弯
*(lcdmem+(j*800)+i)=tempbuf[m*w+n];
}
}
//关闭
close(bmpfd);
close(lcdfd);
return 0;
}
//定义一个结构体表示双向循环列表,为了省事把此双向链表类型定义为dlist
typedef struct doublelist
{
char data[100];
struct doublelist *next;
struct doublelist *fnext;
}dlist;
dlist * init_list()
{
dlist *head = calloc(1,sizeof(dlist));
// head->data = "1.bmp";
//strcpy(head->data, "1.bmp");
head->next = head;
head->fnext = head;
return head;
}
//尾插
int insert_(char * newdata,dlist * head)
{
dlist * p =head;
while(p->next != head)
{
p = p->next;
}
dlist *newnode = calloc(1,sizeof(dlist));
//newnode->data = newdata;
strcpy(newnode->data, newdata);
newnode->next = head;
p->next = newnode;
head->fnext = newnode;
newnode->fnext = p;
}
//读取目录,获得图片名字
int read_dir(char *path,dlist * head)
{
DIR * dir = opendir(path);
if (NULL == dir)
{
perror("打开目录失败!");
exit(0);
}
struct dirent * rd = NULL;
while((rd = readdir(dir)) != NULL)
{
//printf("d_name : %s\n", rd->d_name);
if (rd->d_type == DT_REG)
{
//printf("这是普通文件!\n");
if (strstr(rd->d_name,".bmp") != 0)
{
insert_(rd->d_name,head);
}
}
}
return 0;
}
//我的相册缩略图和点击跳转
int myphoto()
{
int *touch_x1 = calloc(1,1000);
int *touch_y1 = calloc(1,1000);
int *touch_x = calloc(1,1000);
int *touch_y = calloc(1,1000);
dlist *mydlist=init_list();
read_dir("/myphoto/",mydlist);
//我的相片会出现中文名而且特别长,100个字节会溢出,给500个字节
char a[500] = "/myphoto/";
int page = 0;
int count = 0;
int num = 0;
//计算总共有多少张图片
dlist * p = mydlist;
while(p->next != mydlist)
{
p = p->next;
count++;
}
//开头显示第一页缩略图
int k = 0;
page = 0;
p = mydlist;
while(p->next != mydlist && k<15)
{
k++;
p = p->next;
num++;
bzero(a,500);
strcpy(a,"/myphoto/");
strcat(a,p->data);
zoom1_showbmp(a,num-1);
}
num = 0;
p = mydlist;
while(1)
{
//到while循环的顶部了
yxget_x_y(touch_x,touch_x1,touch_y,touch_y1);
//向左划,下一页缩略图
if((*touch_x>*touch_x1)&&((*touch_x-*touch_x1)>=80))
{
if (count<=15)
{
printf("所有图片都在这里了噢。\n");
continue;
}
if (page <= count/15)
{
page++;
}
if (page > count/15)
{
if (count%15 == 0)
{
printf("这已经是最后一页了。\n");
if (page > count/15)
{
page--;
}
continue;
}
}
p = mydlist;
for (int i = 0; i < 15*page; i++)
{
p = p->next;
}
k = 0;
while(p->next != mydlist && k<15)
{
k++;
p = p->next;
num++;
bzero(a,500);
strcpy(a,"/myphoto/");
strcat(a,p->data);
zoom1_showbmp(a,num-1);
}
}
num = 0;
//向右划,上一页
if( ((*touch_x1-*touch_x) >=80) && (*touch_x1>=*touch_x) )
{
if (page==0)
{
printf("当前已经是第一页了。\n");
continue;
}
page--;
p = mydlist;
for (int i = 0; i < 15*page; i++)
{
p = p->next;
}
k = 0;
while(p->next != mydlist && k<15)
{
k++;
p = p->next;
num++;
bzero(a,500);
strcpy(a,"/myphoto/");
strcat(a,p->data);
zoom1_showbmp(a,num-1);
}
}
num = 0;
//跳转点击到的图片
if( ((*touch_x1-*touch_x) <80) && (*touch_x1>=*touch_x) )
{
int h = (*touch_x1/160) + (*touch_y1/160)*5;
p = mydlist->next;
for (int i = 0; i < 15*page; i++)
{
p = p->next;
}
for (int i = 0; i < h; i++)
{
if (p->next != mydlist)
{
p = p->next;
}
else
{
printf("当前位置没有对应图片,自动跳转到最后一张图片。\n");
break;
}
}
bzero(a,500);
strcpy(a,"/myphoto/");
strcat(a,p->data);
special_showbmp(a);
break;
}
//跳转点击到的图片
if( ((*touch_x-*touch_x1) <80) && (*touch_x>=*touch_x1) )
{
int h = (*touch_x1/160) + (*touch_y1/160)*5;
p = mydlist->next;
for (int i = 0; i < 15*page; i++)
{
p = p->next;
}
for (int i = 0; i < h; i++)
{
if (p->next != mydlist)
{
p = p->next;
}
else
{
printf("当前位置没有对应图片,自动跳转到最后一张图片。\n");
break;
}
}
bzero(a,500);
strcpy(a,"/myphoto/");
strcat(a,p->data);
special_showbmp(a);
break;
}
//到while循环的底部了
}
//printf("退出了我的相册\n");
}
int main(int argc, char const *argv[])
{
myphoto();
return 0;
}
用数据结构的链表存储图片路径名,用上文件io,系统编程的知识,综合起来(其实内容挺多的,这里写少了,都写出来就又很复杂了,所以就在阅读代码中理解吧。),就形成了我第一篇博客中的相册模块。
我的第一篇博客链接(相册模块包含其中):
https://blog.csdn.net/weixin_43764094/article/details/107720347
视频效果
我的娱乐系统世界之相册模块