一、设计目标:
开发一个类似相册的应用程序,利用开发板的液晶屏和触摸屏,支持用户友好界面、多种图片格式,并提供方便浏览照片的功能。
二、功能描述:
-
支持滑动浏览图片:用户可以通过触摸屏滑动操作,在指定目录下浏览图片。
-
支持幻灯片播放:提供幻灯片播放功能,用户可以选择自动播放图片。
-
解析图片格式:应用程序智能调用相关的库,对支持的图片格式(如JPG和BMP)进行解析显示。
-
目录文件过滤:应用程序支持指定目录下的文件过滤,以获取所有符合条件的图片文件。
-
图片自动居中:应用程序会自动将图片在屏幕上居中显示,确保用户可以完整地看到图片内容。
-
图片自适应屏幕尺寸:应用程序会自动缩放大图,以适应屏幕尺寸,保证图片显示效果。
-
双缓冲机制:为了优化画面显示效果,应用程序采用双缓冲机制,避免闪屏现象。
-
功能选择:提供一个功能选择页面,用户可以选择浏览照片、幻灯片播放或其他功能。
三、设计方案:
-
硬件方面:使用开发板的液晶屏和触摸屏来显示图片,并支持滑动操作。
-
数据结构:采用内核双向链表来保存目录下的文件信息,包括文件名、路径等。通过遍历链表来实现图片的显示和滑动操作。
-
用户界面设计:设计一个用户友好的界面,通过触摸屏进行交互操作。
-
功能实现:根据用户操作,调用相应的功能模块,如图片显示模块、幻灯片播放模块等。
-
动态库加载:根据图片格式,动态加载相应的库进行解析和显示。
-
目录检索和文件过滤:使用文件系统相关的API,遍历指定目录,筛选出符合条件的图片文件。
四、系统框架
- 用户界面层:
- 主页:显示电子相册的主界面,提供功能选择入口。
- 浏览界面:展示图片,支持滑动操作和幻灯片播放。
- 应用逻辑层:
- 图片管理模块:负责管理图片数据和文件信息,包括读取目录、文件过滤、链表存储等。
- 图片显示模块:负责显示图片,支持居中和自适应屏幕尺寸。
- 幻灯片播放模块:实现幻灯片自动播放功能,包括时间间隔控制和图片切换。
- 功能选择模块:处理用户选择的功能,根据不同选项调用相应模块。
- 库调用层:
- 图片解析库:根据图片格式动态加载相应的库文件,解析并显示图片。
- 文件系统库:提供文件操作接口,用于目录遍历和文件过滤。
- 硬件驱动层:
- LCD驱动:控制液晶屏的显示。
- 触摸屏驱动:处理用户触摸输入。
- 系统核心层:
- 操作系统:提供系统资源管理和任务调度功能。
- 设备驱动:与硬件驱动层配合,实现对硬件设备的操作。
五、实现过程
- 初始化lcd
void lcd_init(struct lcd_info *p) { p->lcd = open("/dev/fb0",O_RDWR); if(p->lcd == -1) { perror("打开lcd失败"); return; } // 准备好lcd设备(如果多次显示,应该只做一遍) static bool initialized = false; if(initialized) { return; } // 获取硬件参数 ioctl(p->lcd,FBIOGET_VSCREENINFO,&finfo); p->width = finfo.xres; p->height = finfo.yres; p->bpp = finfo.bits_per_pixel; p->screen_size = p->width * p->height * p->bpp/8; // 映射内存 p->fmb = mmap(NULL,p->screen_size*2,PROT_READ|PROT_WRITE,MAP_SHARED,p->lcd,0); if(p->fmb == MAP_FAILED) { perror("内存映射失败"); exit(0); } //将映射的内存块清零 bzero(p->fmb,p->screen_size); initialized = true; }
- 初始化内核链表
struct photo *init_list() { struct photo *head = calloc(1, sizeof(struct photo)); if(head != NULL) { INIT_LIST_HEAD(&head->list); } return head; }
- 对目录进行操作文件过滤
// 打开目录获得目录指针 DIR *dp = opendir(argv[1]); if(argc != 2) { fprintf(stderr,"请指定一个目录\n"); exit(0); } // 获得当前进程所在路径 char path[100]; bzero(path,100); printf("当前路径: %s\n",getcwd(path,100)); // 进入目录 chdir(dirent_path); // 目录项结构体 struct dirent *ep; while (1) { // 读取目录项 ep = readdir(dp); if(ep == NULL) { printf("读完了\n"); break; } // 跳过以‘.’开头的文件 if(ep->d_name[0] == '.') continue; // 过滤不是.jpg格式的文件名 // DT_REG是普通文件类型 if (ep->d_type == DT_REG && ((strstr(ep->d_name, ".jpg") !=NULL) || (strstr(ep->d_name, ".bmp")!= NULL))) { struct photo *p = new_node(ep->d_name); list_add_tail(&p->list,&head->list); } }
- 读取触摸屏数据并判定滑动方向
int fd = open("/dev/input/event0",O_RDWR); if(fd == 0) { perror("打开触摸屏失败\n"); return -1; } struct input_event ev; int ret; int flag = 0; int count = 0; while(1) { // 读取触摸屏数据 ret = read(fd,&ev,sizeof(ev)); if(ret != sizeof(ev)) { close(fd); perror("读取失败"); return -1; } // 判断触摸事件,并获取x值 if(ev.type == EV_ABS && ev.code == ABS_X) { if(p1.x < 0) { p1.x = ev.value; } else { p2.x = ev.value; } } if(ev.type == EV_ABS && ev.code == ABS_Y) { if(p1.y < 0) { p1.y = ev.value; } else { p2.y = ev.value; } } // 最后读取到的数据与第一次读取到的数据相比较 // 判断滑动的方向 if(ev.type == EV_KEY && ev.code == BTN_TOUCH && ev.value == 0) { int dt_x = abs(p1.x - p2.x); int dt_y = abs(p1.y - p2.y); if(dt_x > 2*dt_y) { if(p1.x > p2.x) return left; if(p1.x < p2.x) return right; }else if(2*dt_x < dt_y) { if(p1.y > p2.y) return up; if(p1.y < p2.y) return down; } else // 单击不滑屏 { p1.x = -1; p1.y = -1; p2.x = -1; p2.y = -1; } } }
- 根据图片文件名字选择加载哪个类型的动态库
p = list_entry(pos,struct photo,list); //打开指定的动态库,并找到显示图片的函数指针 void *handle; if(strstr(p->name,".jpg")) { handle = dlopen("libjpg.so",RTLD_NOW); printf("%d\n",__LINE__); } else if(strstr(p->name,".bmp")) { handle = dlopen("libbmp.so",RTLD_NOW); printf("%d\n",__LINE__); } if(handle == NULL) { fprintf(stderr,"打开动态库失败:%s\n",dlerror()); exit(0); } void (*show_img)(const char *jpgFile, struct lcd_info *p); show_img = dlsym(handle,"show_img"); if(show_img == NULL) { fprintf(stderr,"dlsym()失败:%s\n",dlerror()); exit(0); }
- 对滑动后做出响应,显示相应的图片
switch(x) { case left: if(pos->prev != &head->list) { pos = pos->prev; printf("向左滑动,前一张\n"); } else { printf("最后一张啦,从头开始滑\n"); pos = head->list.prev; } break; case right: if(pos->next != &head->list) { printf("向右滑动,下一张\n"); pos = pos->next; } else { printf("滑到头啦,重新开始\n"); pos = head->list.next; } break; }