06实现相册小项目

news2025/3/9 10:04:55

一、涉及的知识点:

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2311000.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Dify+DeepSeek | Excel数据一键可视化(创建步骤案例)(echarts助手.yml)(文档表格转图表、根据表格绘制图表、Excel绘制图表)

Dify部署参考&#xff1a;Dify Rag部署并集成在线Deepseek教程&#xff08;Windows、部署Rag、安装Ragan安装、安装Dify安装、安装ollama安装&#xff09; DifyDeepSeek - Excel数据一键可视化&#xff08;创建步骤案例&#xff09;-DSL工程文件&#xff08;可直接导入&#x…

安装与配置 STK-MATLAB 接口

STK版本为11.6 Matlab版本为R2018a STK 提供 Connect 和 Object Model (COM) 两种接口与 MATLAB 交互&#xff0c;推荐使用 COM接口进行二次开发。 确保安装了 STK&#xff0c;并且 MATLAB 可以访问 STK Object Model。 在 MATLAB 中运行&#xff1a; % 添加 STK COM 库&#…

计算机二级MS之PPT

声明&#xff1a;跟着大猫和小黑学习随便记下一些笔记供大家参考&#xff0c;二级考试之前将持续更新&#xff0c;希望大家二级都能轻轻松松过啦&#xff0c;过了二级的大神也可以在评论区留言给点建议&#xff0c;感谢大家&#xff01;&#xff01; 文章目录 考题难点1cm25px…

python中采用opencv作常规的图片处理的方法~~~

在python中&#xff0c;我们经常会需要对图片做灰度/二值化/模糊等处理&#xff0c;这时候opencv就是我们的好帮手了&#xff0c;下面我来介绍一下相关用法: 首先&#xff0c;需要安装opencv-python库: 然后&#xff0c;在你的代码中引用: import cv2 最后就是代码了&#x…

deepseek在pycharm 中的配置和简单应用

对于最常用的调试python脚本开发环境pycharm&#xff0c;如何接入deepseek是我们窥探ai代码编写的第一步&#xff0c;熟悉起来总没坏处。 1、官网安装pycharm社区版&#xff08;免费&#xff09;&#xff0c;如果需要安装专业版&#xff0c;需要另外找破解码。 2、安装Ollama…

Redis数据结构,渐进式遍历,数据库管理

1.Redis的其他数据结构 前面我们主要讲述了Redis中比较常用的集中数据结构String&#xff0c;List&#xff0c;Hash&#xff0c;Set&#xff0c;Zset&#xff0c;但这并不代表Redis只用这几种数据结构还有如Streams&#xff0c;Geospatial&#xff0c;Hyperloglog&#xff0c;…

【够用就好006】如何从零开发游戏上架steam面向AI编程的godot独立游戏制作实录001流程

记录工作实践 这是全新的系列&#xff0c;一直有个游戏制作梦 感谢AI时代&#xff0c;让这一切变得可行 长欢迎共同见证&#xff0c;期更新&#xff0c;欢迎保持关注&#xff0c;待到游戏上架那一天&#xff0c;一起玩 面向AI编程的godot独立游戏制作流程实录001 本期是第…

LNK2038 检测到“RuntimeLibrary”的不匹配项: 值“MT_StaticRelease”不匹配值“MD_DynamicRelease”

vs2019中属性设置 报错&#xff1a; vs2019中属性设置为 报错&#xff1a; 设置为 报错&#xff1a; 设置为 报错&#xff1a; 原因&#xff1a;是由于ncnn和paddleLite的库同时使用会冲突。只能用其中之一。 后面部署降lite都换成了ncnn就可以了。 要么都用ncnn&a…

SpringBoot校园管理系统设计与实现

在现代校园管理中&#xff0c;一个高效、灵活的管理系统是不可或缺的。本文将详细介绍基于SpringBoot的校园管理系统的设计与实现&#xff0c;涵盖管理员、用户和院校管理员三大功能模块&#xff0c;以及系统的部署步骤和数据库配置。 管理员功能模块 管理员是系统的核心管理…

[QT]开发全解析:从概念到实战

文章目录 Qt 框架入门与应用开发指南一、Qt 框架概述1.1 什么是 Qt1.2 Qt 的发展史1.3 Qt 支持的平台1.4 Qt 版本1.5 Qt 的优点1.6 Qt 的应用场景1.7 Qt 的成功案例 二、Qt 的开发工具概述Qt CreatorVisual StudioEclipse 三、认识 Qt Creator3.1 Qt Creator 概览3.2 使用 Qt C…

【pyqt】(十二)文本框

控件-文本框 文本框主要有两类&#xff0c;为富文本框(QTextEdit)和纯文本框(QPlainTextEdit)&#xff0c;在学习新的控件的时候&#xff0c; 需要掌握的内容主要除了属性之外&#xff0c;其信号触发方法也非常重要。还可以利用Designer来辅助我们进行学习&#xff0c;尤其是利…

汽车免拆诊断案例 | 2023款丰田雷凌汽油版车行驶中偶尔出现通信故障

故障现象  一辆2023款丰田雷凌汽油版车&#xff0c;搭载1.5 L发动机&#xff0c;累计行驶里程约为4700 km。车主反映&#xff0c;行驶中偶尔组合仪表上的发动机转速信号丢失&#xff0c;转向变重&#xff0c;且有“闯车”感&#xff0c;同时车辆故障警报蜂鸣器鸣响。 故障诊断…

关于OceanBase与CDH适配的经验分享

CDH是Cloudera早期推出的一个开源平台版本&#xff0c;它实质上成为了Apache Hadoop生态系统内公认的安装与管理平台&#xff0c;专为企业级需求量身打造。CDH为用户提供了即装即用的企业级解决方案。通过整合Hadoop与另外十多项关键开源项目&#xff0c;Cloudera构建了一个功能…

基于国产芯片的AI引擎技术,打造更安全的算力生态 | 京东零售技术实践

近年来&#xff0c;随着国产AI芯片的日益崛起&#xff0c;基于国产AI芯片的模型适配、性能优化以及应用落地是国产AI应用的一道重要关卡。如何在复杂的京东零售业务场景下更好地使用国产AI芯片&#xff0c;并保障算力安全&#xff0c;是目前亟需解决的问题。对此&#xff0c;京…

HTML label 标签使用

点击 <label> 标签通常会使与之关联的表单控件获得焦点或被激活。 通过正确使用 <label> 标签&#xff0c;可以使表单更加友好和易于使用&#xff0c;同时提高整体的可访问性。 基本用法 <label> 标签通过 for 属性与 id 为 username 的 <input> 元素…

Linux和gcc/g++常用命令总结

目录 Linux命令总结 文件操作相关命令 ls cd pwd cp mv rm cat mkdir rmdir touch 文本处理操作命令 grep awk sed 进程管理操作相关命令 ps top htop kill pkill killall chmod chown 网络操作相关命令 ping ifconfig netstat ss lsof curl …

Sqoop从入门到使用

安装和配置 修改文件配置&#xff1a;修改文件名将&#xff08;sqoop-env-template.sh改为sqoop-env.sh&#xff09; 编辑sqoop-env.sh内部文本&#xff0c;修改调用文件位置 将sqoop-env.sh&#xff0c;配置到全局变量中&#xff0c;方便调用。 查看正常运用 第一类&#xff1…

【数据结构】堆(挑战从零基础到进阶)

我们从概念开始一步步来学习堆&#xff0c;下面我们来从零基础来解剖该种数据结构。先提前透明&#xff1a;实现堆其实就是基于数组来实现一个完全二叉树而已 &#xff01; 目录 堆的概念 堆的性质 堆的物理逻辑&思维逻辑 堆的节点对应关系 堆的核心操作 &#xff08…

阿里 DataWorks:数据治理、安全中心、数据质量核心功能梳理

文章目录 阿里 DataWorks&#xff1a;云原生数据治理与安全一体化实践指南一、数据治理中心1.1 数据治理体系1.2 产品架构全图1.3 概要使用路径1.4 治理现状评估数据治理健康分评估模型 1.5 检查项 & 治理项(1) 检查项(2) 治理项 1.6 治理工具箱1.7 治理结果查看 二、安全中…

DeepSeek精品课分享 清北

AI淘金潮上热搜&#xff01;有人已经靠DeepSeek日入过万了&#xff01; 北大清华等高校也相继出品DeepSeek高质量精品课程&#xff0c;在网上传疯。帮助学者高效学习AI从入门到精通&#xff01; 完整版资料已经帮大家整理好了&#xff0c;免费领&#xff01; 资料链接: htt…