此處專門為相冊子產品加上解析和效果視訊
其實很多事情隻是看起來困難,慢慢做起來就會不斷有思路了,關鍵是有目标就要動手
//縮放和圖檔(花樣)展示很多地方都要用到,就在用到的地方寫,不特地分開寫了
文章目錄
- 音樂相冊
- 相冊的縮略圖
- 視訊效果
音樂相冊
首先是音樂相冊
//音樂相冊
#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
視訊效果
我的娛樂系統世界之相冊子產品