一、涉及的知识点:
1、bmp的显示
2、双向循环链表实现图片的轮播
3、触摸屏的滑动算法实现图片的切换
4、目录操作用以检索bmp图片文件
5、项目的优化方向
(1)可以实现不同图片大小的显示
(2)图片轮播的时候可以点击屏幕以实现暂停,返回,等的操作。
程序代码:(有待完善优化)
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/input.h>
#include <sys/mman.h>
#include <dirent.h>
#include <strings.h>
#include <string.h>
#include <stdlib.h>
// 双链表设计
struct node
{
char path[1024];
struct node *next;
struct node *prev;
};
// bmp文件头结构体-》占用14个字节
struct bitmap_header
{
int16_t type;
int32_t size; // 图像文件大小
int16_t reserved1;
int16_t reserved2;
int32_t offbits; // bmp图像数据偏移量
} __attribute__((packed));
// bmp位图信息头结构体 -》占用40个字节
struct bitmap_info
{
int32_t size; // 本结构大小
int32_t width; // 图像宽
int32_t height; // 图像高
int16_t planes;
int16_t bit_count; // 色深
int32_t compression;
int32_t size_img; // bmp数据大小,必须是4的整数倍
int32_t X_pel;
int32_t Y_pel;
int32_t clrused;
int32_t clrImportant;
} __attribute__((packed));
extern int open_lcd(void);
extern void close_lcd(void);
extern int show_bmp24(char *bmp_path);
extern void filter_bmp(char *dir_path);
extern int open_ts(void);
extern void close_ts(void);
extern void func_photo(void);
extern void Acq_xy(int *X, int *Y);
extern void insert_node(struct node *head, char *path);
extern void show_phone_list_next(void);
extern void show_phone_list_pre(void);
int lcd_fd;
int pox_X, pox_Y;
int T_fd;
int i_bmp; //bmp文件数量
char bmp_list[10][50]; //bmp文件列表
int (*lcd)[800] = NULL;
int touch_x, touch_y; // 记录按下的坐标
int main()
{
open_lcd();
open_ts();
show_bmp24("/CJH/ui/ui_main.bmp");
while (1)
{
Acq_xy(&pox_X, &pox_Y);
printf("(%d, %d)\n", pox_X, pox_Y);
//点击左上角进入相册功能
if(pox_X>=0 && pox_X<150 && pox_Y>=0 && pox_Y<100)
{
printf("点击屏幕左上角->进入相册\n");
func_photo();
}
}
close_ts();
close_lcd();
return 0;
}
//打开触摸屏
int open_ts(void)
{
//打开触摸屏设备文件
T_fd = open("/dev/input/event0", O_RDWR);
if (T_fd <= 0)
{
perror("打开触摸屏失败\n");
return -1;
}
}
//关闭触摸屏
void close_ts(void)
{
//关闭触摸屏设备文件
close(T_fd);
}
void Acq_xy(int *X, int *Y)
{
while (1)
{
struct input_event ev;
read(T_fd, &ev, sizeof(ev));
if (ev.type == EV_ABS && ev.code == ABS_X)
{
*X = ev.value*800/1024;
}
if (ev.type == EV_ABS && ev.code == ABS_Y)
{
*Y = ev.value*480/600;
}
// printf("x=%d, y=%d\n", X, Y);
if (ev.type == EV_KEY && ev.code == BTN_TOUCH)
{
if (ev.value > 0)
{
printf("按下 x=%d y=%d\n", *X, *Y);
touch_x = *X;
touch_y = *Y;
}
else
{
printf("松开 x=%d y=%d\n",*X, *Y);
break;
}
}
}
}
void func_photo(void)
{
filter_bmp("/CJH/phone");
int k;
for (k = 0; k < i_bmp; k++)
printf("%d: %s\n", k+1, bmp_list[k]);
show_bmp24("/CJH/phone/11.bmp");
int i = -1;
while (1)
{
Acq_xy(&pox_X, &pox_Y);
// 计算坐标x差值
if (touch_x - pox_X < -30)
{
printf("右滑动\n");
i++;
if (i>i_bmp-1)
i=1;
show_bmp24(bmp_list[i]);
}
if (touch_x - pox_X > 30)
{
printf("左滑动\n");
i--;
if(i<0)
i=i_bmp-1;
show_bmp24(bmp_list[i]);
}
if (pox_X>=0 && pox_X<150 && pox_Y>=0 && pox_Y<100)
{
printf("点击屏幕左上角->返回主界面\n");
show_bmp24("/CJH/ui/ui_main.bmp");
break;
}
if (touch_y - pox_Y > 45)
{
printf("下滑动->前续遍历\n");
show_phone_list_pre();
show_bmp24("/CJH/ui/ui_main.bmp");
break;
}
if (touch_y - pox_Y < -45)
{
printf("下滑动->后续遍历\n");
show_phone_list_next();
show_bmp24("/CJH/ui/ui_main.bmp");
break;
}
}
}
//筛选检索bmp
void filter_bmp(char *dir_path)
{
i_bmp = 0;
bzero(bmp_list, sizeof(bmp_list));
// 1.打开目录
DIR *dp = opendir(dir_path);
// 2.读取目录项(包括文件名)
struct dirent *temp;
while(1)
{
temp = readdir(dp);
if(temp == NULL)
break;
//成功读取到
// printf("%s\n", temp->d_name);
int len = strlen(temp->d_name);
if(len>4 &&
temp->d_name[len-4] == '.' &&
temp->d_name[len-3] == 'b' &&
temp->d_name[len-2] == 'm' &&
temp->d_name[len-1] == 'p')
{
// printf("yes: %s\n", temp->d_name);
char temp_path[50] = {0};
//将文件名与完整路径拼接起来
sprintf(temp_path, "%s/%s", dir_path, temp->d_name);
strncpy(bmp_list[i_bmp], temp_path, sizeof(bmp_list[i_bmp]));
i_bmp++;
}
}
// 3.关闭目录
closedir(dp);
}
int open_lcd(void)
{
lcd_fd = open("/dev/fb0", O_RDWR);
if (lcd_fd < 0)
{
printf("LCD设备打开失败\n");
return -1;
}
// 映射LCD设备
lcd = mmap(NULL, 800 * 480 * 4, PROT_READ | PROT_WRITE, MAP_SHARED, lcd_fd, 0);
if (lcd == MAP_FAILED)
{
printf("映射失败\n");
return -1;
}
else
{
printf("映射成功\n");
}
}
//关闭lcd
void close_lcd(void)
{
close(lcd_fd);
// 解除映射
munmap(lcd, 800 * 4 * 480);
}
// 显示24位的BMP图片
int show_bmp24(char *bmp_path)
{
// 1.打开图片文件
int bmp_fd = open(bmp_path, O_RDWR);
if (bmp_fd < 0)
{
printf("打开图片失败\n");
return -1;
}
// 2.读取14个字节头数据
struct bitmap_header head;
read(bmp_fd, &head, 14);
struct bitmap_info info;
read(bmp_fd, &info, 40);
int widht = info.width;
int height = info.height;
int bbp = info.bit_count;
printf("%s 大小 %d 宽度 %d 高度 %d 色深 %d\n", bmp_path, head.size, widht, height, bbp);
// 像素缓存区
char rgb[widht * 3 * height];
read(bmp_fd, rgb, sizeof(rgb));
// 3.把rgb的数据转换为argb数据
char argb[800 * 4 * 480];
for (int i = 0; i < 800 * 480; i++)
{
argb[0 + i * 4] = rgb[0 + i * 3];
argb[1 + i * 4] = rgb[1 + i * 3];
argb[2 + i * 4] = rgb[2 + i * 3];
argb[3 + i * 4] = 0;
}
// 4.把一维数组转换为二维数组显示正向图片
int(*color)[800] = (void *)argb;
for (int y = 0; y < 480; y++)
{
for (int x = 0; x < 800; x++)
{
lcd[y][x] = color[479 - y][x];
}
}
// 关闭图片
close(bmp_fd);
}
// 插入节点
void insert_node(struct node *head, char *path)
{
// 1.新建节点
struct node *xnew = malloc(sizeof(struct node));
// 2.初始化数据域
strcpy(xnew->path, path);
// 初始化地址域
xnew->next = xnew;
xnew->prev = xnew;
// 3.插入节点到链表中
xnew->prev = head->prev;
xnew->next = head;
head->prev->next = xnew;
head->prev = xnew;
}
void show_phone_list_next(void)
{
// 1.创建一个头结点
struct node *head = malloc(sizeof(struct node));
// 2.初始化头结点
strcpy(head->path, "NULL");
head->next = head;
head->prev = head;
filter_bmp("/CJH/phone");
int k;
for (k = 0; k < i_bmp; k++)
{
printf("%d: %s\n", k+1, bmp_list[k]);
insert_node(head, bmp_list[k]);
}
// 指向头结点
struct node *pos = head;
while (1)
{
if (strcmp(pos->path, "NULL") != 0)
{
show_bmp24(pos->path);
}
sleep(1);
pos = pos->next;
if (pos == head)
{
break;
}
}
}
void show_phone_list_pre(void)
{
// 1.创建一个头结点
struct node *head = malloc(sizeof(struct node));
// 2.初始化头结点
strcpy(head->path, "NULL");
head->next = head;
head->prev = head;
filter_bmp("/CJH/phone");
int k;
for (k = 0; k < i_bmp; k++)
{
printf("%d: %s\n", k+1, bmp_list[k]);
insert_node(head, bmp_list[k]);
}
// 指向头结点
struct node *pos = head;
while (1)
{
if (strcmp(pos->path, "NULL") != 0)
{
show_bmp24(pos->path);
}
sleep(1);
pos = pos->prev;
if (pos == head)
{
break;
}
}
}
至此,希望看完这篇文章的你有所收获,我是Bardb,译音八分贝,道友,下期见!