LCD屏幕显示PNG图像

news/2024/11/15 23:39:34/文章来源:https://www.cnblogs.com/cyMessi/p/18391698

正点原子LCD屏幕显示PNG图像

本文概要

这段时间在学习正点原子的IMX6ULL开发板,在应用编程中有一个代码练习是需要在LCD屏幕上显示PNG图像,但由于我的屏幕参数和教程中的有些出入,于是经过自己查阅和修改,终于成功在自己的LCD屏幕上显示PNG图像。

LCD 屏幕参数

我的LCD参数如下所示:

这里面出现一个问题,我的屏幕参数显示的是32位,但是实际上RGBA的位数只有24位。那么多出来的8位是什么呢?起初我以为是透明度A,但是参数显示的是透明度所占位数为0。

后面我猜测这8位可能不是RGBA中的一种,而是用来数据对齐的一种方式。由于和我们的代码主体无关,所以后面也就不管它了。

总而言之,这几个参数就是LCD显示中最重要的参数:

屏幕分辨率:1024*600

像素深度:32位

像素格式:RGB888

代码流程

zlib和libpng库

zlib和libpng库是PNG图像的解析库,在Linux系统中直接下载源码然后编译移植到开发板文件系统即可。

zlib库下载地址: https://www.zlib.net/fossils/

libpng库下载地址:https://github.com/glennrp/libpng/releases

其中libpng也有帮助文档:http://www.libpng.org/pub/png/libpng-1.4.0-manual.pdf

这里我使用的是zlib-1.2.10 和 libpng-1.6.35,版本根据自己的需求选择。

解析图像流程

使用libpng库解析图像的流程基本是固定的,无非就是:

  1. 获取文件描述符:打开PNG图像文件获取文件描述符

  2. 解码对象:使用png_create_read_struct函数创建png_structp结构体指针,即为解码对象。解码对象在后续操作中就相当于一个句柄的作用;

  3. 图像信息对象:使用png_create_info_struct函数创建png_infop结构体指针,即为图像信息对象,用于存储图像的宽、高等属性;

  4. 错误处理:使用setjmp(png_jmpbuf(png_ptr))设置错误处理,这里setjmp函数的作用就是设置错误跳点,当发送错误时就跳到这里来执行后续函数;

  5. 指定数据源:使用png_init_io函数设置数据源,表明我们要解码的就是这个图像文件;

  6. 读取图像信息:这里使用png_read_png()函数来直接读取PNG图像信息,这个函数会自动开辟一个内存空间用来存储图像信息。因为这个内存信息和png_structp结构体对象绑定了,所以后续可以用png_get_rows()函数来获取该内存地址;

  7. 获取图像数据: 使用png_get_rows()函数获取图像数据,并返回一个png_bytep类型的指针,指向的是图像数据中每一行的地址,所以该指针指向的是一个数组,数组每个元素是图像数据中一行的数据,元素大小为image_width*bytes_per_pixel/8

  8. 转换为RGB888格式:这里外层循环的作用是遍历图像数据的每一行,内存循环的作用是遍历图像数据的每一列。并且用指针png_bytep px指向图像数据中每3个数据为一组的地址,指针unsigned char *dst 指向图像显存地址中每4个数据为一组的地址,然后对RGB进行数据转换,这里为什么是将RGB的顺序互换,我也不太清楚,可能与图片原先的RGB格式有关,反正只要转换为LCD屏幕的RGB格式就好;

点击查看代码
/* 将24位RGB图像转换为32位RGB888格式 */
for (int y = 0; y < image_height; y++) {for (int x = 0; x < image_width; x++) {png_bytep px = &(row_pointers[y][x * 3]);unsigned char *dst = &image_data[(y * image_width + x) * 4];dst[0] = px[2]; // Rdst[1] = px[1]; // Gdst[2] = px[0]; // Bdst[3] = 0xFF; // A (Alpha channel set to 255)}
}
  1. 分配内存并写入显存:使用malloc()函数分配内存,并使用memcpy()函数将图像数据写入内存中;
点击查看代码
/* 将图像数据写入显存 */
for (int y = 0; y < image_height && y < screen_height; y++) {memcpy(screen_base + y * line_length, image_data + y * image_width * 4, image_width * 4);
}
  1. 释放内存:使用free()函数释放内存。

最终显示效果

显示效果如下:

总结与对比

相较于教程的代码流程,卡住我的主要就是理解我的LCD屏幕为32位的含义所在,不是RGBA,而是有8位作为数据对齐。以及还有转化为RGB888格式的代码,但是这个我是交给Copilot自动生成了,在这里狠狠安利一波Copilot!!

其实理解了代码的含义也不难,最重要的就是掌握好libpng库的使用框架和API,当然还有图像的存储方式:图像的image_width和image_height指的是图像的宽和高分别有多少个像素点,而图像的存储是按行优先排列的,所以用png_get_rows()函数获取的是指向图像数据一行一行地址的指针,其实可以当作是一个二维矩阵来看,所以通过两层循环也就可以遍历图像数据了。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

文档管理神器大搜罗!10款热门工具深度评测

市面上常见的 10 款文档管理工具对比:PingCode;Worktile;飞书文档;腾讯文档;石墨文档;语雀;M-Files;DocuWare;MasterControl;Contentverse;DocuSign 。在今天的数字化时代,文档管理变得越来越重要,无论是对于初创企业还是大型企业。一个常见的挑战是如何找到一个既…

北京交通大学交通运输学院2024级迎新大会

一、主持二、会上提到了几个会议:ICTTS、ISROR、RailBeijing三、就业单位四、各实验室的视频。这句话也可以用一用五、关于新生班主任六、关于代表学生发言 这是第八个年头了,说来惭愧,我既没有大脑班本身的论文,也没有卷王班满记的成绩,但转念一想,我这一路走来有许多的…

智慧工地扬尘监测系统

智慧工地扬尘监测系统剖析,智能化当场烟尘监管系统全自动剖析和鉴别视频图像信息内容,不用人工控制;智慧工地扬尘监测系统自动检测施工工地等监管范围的烟尘,立即预警信息,合理帮助管理者解决。与此同时,还能够查询当场视频,查看,提升企业信息管理水准,完成建筑工地的…

建筑工地扬尘监测系统

建筑工地扬尘监测系统剖析,施工工地烟尘监测系统选用专业的线上监测技术,全自动剖析和鉴别视频图像信息内容.建筑工地扬尘监测系统全天候综合性监测烟尘噪音污染,全自动上传入监测核心;数据信息全自动声光报警器,短消息提醒有关工作人员,立即预警信息,合理帮助管理者解决…

视野修炼-技术周刊第99期 | Rspack 1.0

① Rspack 1.0 发布公告 ② 通过绘图评论 ③ Coolify - 开源应用运行平台 ④ Tagger - 标签选择组件 ⑤ npm 依赖更新检查工具 ⑥ 使用 CSS 实现页面弹性效果 ⑦ 10大Git 技巧 ⑧ Emoji 搜索欢迎来到第 99 期的【视野修炼 - 技术周刊】,下面是本期的精选内容简介 🔥强烈推荐…

洛谷 P1328 [NOIP2014 提高组] 生活大爆炸版石头剪刀布

题目大意 小A和小B,要进行 \(N\) 次猜拳,每次按照一定周期出拳,胜负情况如下:求出小A和小B分别赢了几次。 思路 枚举 \(N\) 次猜拳,每次比较 \(a[powera]\) 与 \(b[powerb]\) (poewra 与 powerb 是 a 和 b 数组的索引,详见代码)。 CODE #include<bits/stdc++.h> …

【JAVA系列】java命令注入科普

名词科普原理科普注入科普原创 medi0cr1ty Medi0cr1ty这里只讨论使用java执行命令的情况(Runtime/ProcessBuilder),结合之前挖过过的一些case或者群里见到过的case来讲。 名词科普 命令解释器shell:是一种软件程序(可视作一门编程语言的代码解释器),它接收用户在命令行界面输…

ubuntu重新分配根目录存储空间-将根目录空间缩小腾出给别的位置

我有个1t的固态,上面装了双系统,分了四分之一给windows,四分之三给ubuntu,现在出了黑神话悟空,我想玩一玩,黑神话悟空需要130g的存储,但是我的windows空间只剩50g,而且我又不想使用机械硬盘,毕竟太慢了。于是,我想把我的ubuntu再分出四分之一给windows,相当于两个系…

Kubernetes利用Volume挂载ConfigMap与Secret

1、概述在Kubernetes集群中,应用的配置管理是一个关键且复杂的任务。随着应用的扩展和微服务架构的普及,传统的配置文件管理方式已经难以满足动态、灵活的配置需求。幸运的是,Kubernetes提供了强大的配置管理能力,其中ConfigMap和Secret结合Volume挂载的方式是实现这一目标…

章10——面向对象编程(高级部分)——类名类方法

类变量/静态(static)变量/静态属性 特点: 由该类的全体对象实例共享,该变量只占同一块内存空间。 其标志是关键字static修饰。 在类加载的时候便生成了。类加载的时机如下图:public static int count = 0; 类变量可以由类名来访问。 System.out.println("共有" + …

Redis组件介绍(四)

今天继续学习后面的知识写在前面 今天继续学习后面的知识。 Redis 操作命令 操作 List 相关 APILPUSH说明: 将某个值加入到一个 key 列表的头部。当列表不存在时会创建。 语法: LPUSH key value [value ...] 返回值: 成功返回列表的元素个数,失败返回 0。LPUSHX说明: 与 LPUSH…

随笔9/1(一)

软件工程 计科22级12班作业要求 第一次作业要求作业目标 对学习课程进行了解并探索相应内容介绍自己 --> 我叫肖商,第一次与电脑结缘是20年疫情期间,学校教学转为网络教学时,第一次接触编程,虽然什么都不懂,但当时感觉编程很奇妙。 后来有了学习计算机的想法,大学志愿…