当前位置: 首页 > news >正文

06实现相册小项目

一、涉及的知识点:

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,译音八分贝,道友,下期见!

相关文章:

  • 个人学习编程(3-06) 树形数据结构
  • Go语言里面的堆跟栈 + new 和 make + 内存逃逸 + 闭包
  • URL中的特殊字符与web安全
  • uniapp封装路由管理(兼容Vue2和Vue3)
  • module ‘matplotlib‘ has no attribute ‘colormaps‘
  • phpstorm 无法重建文件
  • 统信UOS上AI辅助绘图:用DeepSeek+draw.io生成流程图
  • NET400协议网关(老款GRM300):跨品牌PLC与多协议数据整合解决方案,包含NET421,NET422,NET431等
  • 单细胞分析(22)——高效使用 Cell Ranger:安装、参数解析及 Linux 后台运行指南
  • Mysql中的常用函数
  • 系统架构设计师—数据库基础篇—数据库规范化
  • RxJava 用法封装举例
  • 初中文凭怎么成人大专-一种简单省心的方式
  • Gauss数据库omm用户无法连接处理
  • 写作思维魔方
  • 下载PyCharm 2024.3.4 (Community Edition)来开发测试python
  • 多线程或多进程或多协程部署flask服务
  • 网络安全等级保护2.0 vs GDPR vs NIST 2.0:全方位对比解析
  • linux0.11源码分析第四弹——操作系统的框架代码
  • 类和对象—多态—案例2—制作饮品
  • 南京小程序开发哪家好/上海正规seo公司
  • 河源网站搭建费用/品牌seo如何优化
  • 香港网站建设公司/小程序运营推广公司
  • 如何做双语网站/网页制作软件手机版
  • 网站建设商标保护/企业宣传视频
  • 南通高端网站建设机构/网页关键词排名优化