02内存映射与bmp解码

一、mmap 内存映射        

        内存映射的作用是把硬件设备的地址,映射到应用层的内存空间,这样用户就可以跨越系统层访问linux的硬件设备。

1、man 2 mmap 查看映射函数接口

NAME
       mmap, munmap - map or unmap    files or devices into memory
                      映射   解除映射  文件  或 设备     到   内存                       
SYNOPSIS
       #include <sys/mman.h>

       void *mmap(void *addr,  //内存首地址,NULL 系统自动选择 
               size_t length,  //映射空间的大小,必须大于0
                    int prot,  //👉 PROT_READ | PROT_WRITE
                   int flags,  // MAP_SHARED 其他进程可见     MAP_PRIVATE  其他进程不可见
                      int fd,  // 文件描述符 
                off_t offset); // 偏移量 ,默认为  0 即可 
        
          返回值: 成功   映射地址,void *万能指针,用于后续用户强制转换类型! 
                 失败    MAP_FAILED        
                                      
prot操作权限:
PROT_EXEC  可执行

PROT_READ  可读

PROT_WRITE 可写

PROT_NONE  没有权限                
     
⭐映射LCD设备 
void *mmap(NULL,800*480*4,PROT_READ | PROT_WRITE,MAP_SHARED ,lcd_fd,0)      
                                   
                                                                                                                                                       
//解除映射                     
int munmap(void *addr, size_t length);
addr:映射地址 
length:映射内存的大小 

2、内存映射demo

#include <stdio.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{

    int lcd_fd = open("/dev/fb0", O_RDWR);
    if (lcd_fd < 0)
    {
        printf("LCD设备打开失败\n");
        return -1;
    }

    // 映射LCD设备
    void *p = mmap(NULL, 800 * 480 * 4, PROT_READ | PROT_WRITE, MAP_SHARED, lcd_fd, 0);
    if (p == MAP_FAILED)
    {
        printf("映射失败\n");
        return -1;
    }
    else
    {
        printf("映射成功\n");
    }
}

3、映射地址与LCD关系

#if ONE
    // 把映射地址强制转换
    int *lcd = p;
    while (1)
    {
        // 一个一个像素点赋值到LCD设备中
        for (int x = 0; x < 800 * 480; x++)
        {
            lcd[x] = 0x0000ff;
        }
        sleep(1);
        for (int x = 0; x < 800 * 480; x++)
        {
            lcd[x] = 0x00ff00;
        }
        sleep(1);
    }
#endif

#if TWO
    // 把映射地址强制转换
    int(*lcd)[800] = p;

    for (int y = 0; y < 480; y++)
    {
        for (int x = 0; x < 800; x++)
        {
            lcd[y][x] = 0xff00ff;
        }
    }

#endif

二、lcd显示bmp图片

1、计算机常见的图片格式

JPG(JPEG)、PNG和BMP是常见的图像文件格式,它们各有特点和适用场景:
JPG(JPEG)
压缩方式:JPEG使用有损压缩,这意味着在压缩过程中会丢失一些图像数据,尤其是当压缩比率较高时。
适用场景:由于有损压缩,JPEG文件通常比PNG和BMP文件小,适合网络传输和存储空间有限的情况。它非常适合照片和复杂图像,因为这些图像的微小失真通常人眼难以察觉。
颜色深度:JPEG支持最高为24位的颜色深度。
透明度:JPEG不支持透明背景。
PNG(Portable Network Graphics)
压缩方式:PNG使用无损压缩,它可以在不损失任何图像数据的情况下压缩图像。
适用场景:PNG非常适合网页设计、图标和其他需要高保真度图像的场合。它的文件大小通常比JPEG大,但比BMP小。
颜色深度:PNG支持最高达48位的真彩色,并且支持灰度图像、索引颜色图像。
透明度:PNG支持透明背景和半透明效果,这是它的一大优势。
BMP(Bitmap)
压缩方式:BMP通常不使用压缩,它直接存储每个像素的颜色信息,因此文件大小通常很大。
适用场景:BMP格式因其简单和直接性在某些特定场合(如Windows系统中的图标)被使用,但由于文件体积大,不适合网络传输。
颜色深度:BMP支持多种颜色深度,包括24位和32位真彩色。
透明度:标准的BMP格式不支持透明度,但Windows位图可以包含alpha通道来支持透明度。
总结来说,选择哪种格式取决于图像的使用场景和对图像质量的要求。如果需要小文件体积且可以接受一定的质量损失,JPEG是不错的选择;如果需要高保真度和透明度支持,PNG是更好的选择;而BMP由于文件体积大,通常只在特定场合使用。

2、BMP 图片格式

通过上述方法调整图片的格式。

bmp文件头

//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));

用户在读取像素数据之前,应该把上述的54个字节先读取出来,再读取像素数据! 
__attribute__((packed)); 把结构体压实,不进行任何的字节对齐方式!  
bmp头数据处理demo
#include <stdio.h>
#include <sys/types.h> //在该头文件中定义了  int16_t  int32_t
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

// 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));

int main()
{
    printf("sizeof(struct bitmap_header)=%ld\n", sizeof(struct bitmap_header)); // 12
    printf("sizeof(struct bitmap_info)=%ld\n", sizeof(struct bitmap_info));     // 40

    // 1.打开图片文件
    int bmp_fd = open("tm.bmp", 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("大小 %d 宽度 %d 高度 %d 色深 %d\n", head.size, widht, height, bbp);
}

3、bmp 像素数据处理

// 像素缓存区
char rgb[widht * 3 * height];
read(bmp_fd, rgb, sizeof(rgb));

// 把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、LCD 映射显示argb数据

#include <stdio.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

// 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));

int main()
{

    int lcd_fd = open("/dev/fb0", O_RDWR);
    if (lcd_fd < 0)
    {
        printf("LCD设备打开失败\n");
        return -1;
    }

    // 映射LCD设备
    void *p = mmap(NULL, 800 * 480 * 4, PROT_READ | PROT_WRITE, MAP_SHARED, lcd_fd, 0);
    if (p == MAP_FAILED)
    {
        printf("映射失败\n");
        return -1;
    }
    else
    {
        printf("映射成功\n");
    }

    // 1.打开图片文件
    int bmp_fd = open("tm.bmp", 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("大小 %d 宽度 %d 高度 %d 色深 %d\n", head.size, widht, height, bbp);

    // 像素缓存区
    char rgb[widht * 3 * height];
    read(bmp_fd, rgb, sizeof(rgb));

    // 把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;
    }

    // 转换映射地址
    char *lcd = p;
    for (int i = 0; i < 800 * 4 * 480; i++)
    {
        lcd[i] = argb[i]; // 把argb这些数据放入LCD映射地址
    }

    // 关闭图片
    close(bmp_fd);
    close(lcd_fd);
    // 解除映射
    munmap(lcd, 800 * 4 * 480);
}

至此,希望看完这篇文章的你有所收获,我是Bardb,译音八分贝,道友,下期见!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

I2C驱动(九) -- i2c_adapter控制器驱动框架编写

相关文章 I2C驱动(一) – I2C协议 I2C驱动(二) – SMBus协议 I2C驱动(三) – 驱动中的几个重要结构 I2C驱动(四) – I2C-Tools介绍 I2C驱动(五) – 通用驱动i2c-dev.c分析 I2C驱动(六) – I2C驱动程序模型 I2C驱动(七) – 编写I2C设备驱动之i2c_driver I2C驱动(八) – 编写I2C…

分布式系统核心基石:CAP定理、BASE理论与一致性算法深度解析

一、CAP定理&#xff1a;分布式系统的设计边界 1.1 核心定义与经典三角 CAP定理&#xff08;Brewers Theorem&#xff09;指出&#xff0c;在分布式系统中&#xff0c;一致性&#xff08;Consistency&#xff09;、可用性&#xff08;Availability&#xff09;、分区容错性&a…

3 算法1-4 过河卒

题目描述 棋盘上 A 点有一个过河卒&#xff0c;需要走到目标 B 点。卒行走的规则&#xff1a;可以向下、或者向右。同时在棋盘上 C 点有一个对方的马&#xff0c;该马所在的点和所有跳跃一步可达的点称为对方马的控制点。因此称之为“马拦过河卒”。 棋盘用坐标表示&#xff…

AutoMQ:无需 Cruise Control 实现 Kafka 的自动分区再平衡

导读&#xff1a;AutoMQ是一款贯彻云优先理念来设计的 Kafka 替代产品。AutoMQ 创新地对 Apache Kafka 的存储层进行了基于云的重新设计&#xff0c;在 100% 兼容 Kafka 的基础上通过将持久性分离至 EBS 和 S3 带来了 10x 的成本降低以及 100x 的弹性能力提升&#xff0c;并且相…

论文阅读之基于Syn2Real域的侧扫声纳类水雷目标探测

摘要 由于现实世界数据的稀缺性&#xff0c;基于深度学习的水下水雷探测受到了限制。这种稀缺性导致过拟合&#xff0c;即模型在训练数据上表现良好&#xff0c;但在未见数据上表现不佳。本文提出了一种使用扩散模型的Syn2Real &#xff08;Synthetic to Real&#xff09;域泛…

如何使用Docker搭建哪吒监控面板程序

哪吒监控(Nezha Monitoring)是一款自托管、轻量级的服务器和网站监控及运维工具,旨在为用户提供实时性能监控、故障告警及自动化运维能力。 文档地址:https://nezha.wiki/ 本章教程,使用Docker方式安装哪吒监控面板,在此之前,你需要提前安装好Docker. 我当前使用的操作系…

微服务学习(1):RabbitMQ的安装与简单应用

目录 RabbitMQ是什么 为什么要使用RabbitMQ RabbitMQ的安装 RabbitMQ架构及其对应概念 队列的主要作用 交换机的主要作用 RabbitMQ的应用 通过控制面板操作&#xff08;实现收发消息&#xff09; RabbitMQ是什么 RabbitMQ是一个开源的消息队列软件&#xff08;消息代理…

综合实验处理表格

新建excel表格&#xff0c;输入信息&#xff0c;另存为csv文件。 利用notepad打开csv文件&#xff0c;可以观察格式 目标&#xff1a;通过编程处理文件&#xff0c;实现对数据的处理&#xff0c;成绩求和以及评价 对数据逐行处理&#xff0c;读一行&#xff0c;处理一行&#…

【leetcode hot 100 560】和为K的子数组

解法一&#xff1a;用左右指针寻找字串&#xff0c;如果和>k&#xff0c;则减少一个数&#xff08;left&#xff09;&#xff1b;如果和<k&#xff0c;则加上一个数&#xff08;right&#xff09;。 class Solution {public int subarraySum(int[] nums, int k) {int nu…

STM32CubeMx DRV8833驱动

一、DRV8833驱动原理 ​ STBY口接单片机的IO口&#xff0c;STBY置0电机全部停止&#xff0c;置1才能工作。STBY置1后通过AIN1、AIN2、BIN1、BIN2 来控制正反转。 AIN1AIN2电机状态00停止1speed反转speed1正转11停止 其中A端&#xff08;AIN1与AIN2&#xff09;只能控制AO1与…

Android 图片压缩详解

在 Android 开发中,图片压缩是一个重要的优化手段,旨在提升用户体验、减少网络传输量以及降低存储空间占用。以下是几种主流的图片压缩方法,结合原理、使用场景和优缺点进行详细解析。 效果演示 直接先给大家对比几种图片压缩的效果 质量压缩 质量压缩:根据传递进去的质…

JavaWeb后端基础(3)

原打算把Mysql操作数据库的一些知识写进去&#xff0c;但是感觉没必要&#xff0c;要是现在会的都是简单的增删改查&#xff0c;所以&#xff0c;这一篇&#xff0c;我直接从java操作数据库开始写&#xff0c;所以这一篇大致就是记一下JDBC、MyBatis、以及SpringBoot的配置文件…

ArcGIS Pro技巧实战:高效矢量化天地图地表覆盖图

在地理信息系统&#xff08;GIS&#xff09;领域&#xff0c;地表覆盖图的矢量化是一项至关重要的任务。天地图作为中国国家级的地理信息服务平台&#xff0c;提供了丰富且详尽的地表覆盖数据。然而&#xff0c;这些数据通常以栅格格式存在&#xff0c;不利于进行空间分析和数据…

TP-LINK路由器如何设置网段、网关和DHCP服务

目标 ①将路由器的网段由192.168.1.XXX改为192.168.5.XXX ②确认DHCP是启用的&#xff0c;并将DHCP的IP池的范围设置为排除自己要手动指定的IP地址&#xff0c;避免IP冲突。 01-复位路由器 路由器按住复位键10秒以上进行重置操作 02-进入路由器管理界面 电脑连接到路由器&…

基于Spring Boot的供应商管理系统设计与实现(LW+源码+讲解)

专注于大学生项目实战开发,讲解,毕业答疑辅导&#xff0c;欢迎高校老师/同行前辈交流合作✌。 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;…

大模型WebUI:Gradio全解12——LangChain原理、架构和组件(3)

大模型WebUI:Gradio全解12——LangChain原理、架构和组件(3) 前言本篇摘要12. LangChain原理及agents构建Gradio UI12.3 LangChain架构12.3.1 LangChain12.3.2 Integration Packages1. 概念2. 示例12.3.3 LangGraph1. 概念2. 示例12.3.4 LangGraph Platform1. 概览2. 优势分…

通过 PromptTemplate 生成干净的 SQL 查询语句并执行SQL查询语句

问题描述 在使用 LangChain 和 Llama 模型生成 SQL 查询时&#xff0c;遇到了 sqlite3.OperationalError 错误。错误信息如下&#xff1a; OperationalError: (sqlite3.OperationalError) near "sql SELECT Name FROM MediaType LIMIT 5; ": syntax error [SQL: …

【每天认识一个漏洞】url重定向

&#x1f31d;博客主页&#xff1a;菜鸟小羊 &#x1f496;专栏&#xff1a;Linux探索之旅 | 网络安全的神秘世界 | 专接本 | 每天学会一个渗透测试工具 常见应用场景 主要是业务逻辑中需要进行跳转的地方。比如登录处、注册处、访问用户信息、订单信息、加入购物车、分享、收…

SQL命令详解之数据的查询操作

目录 1 简介 2 基础查询 2.1 基础查询语法 2.2 基础查询练习 3 条件查询 3.1 条件查询语法 3.2 条件查询练习 4 排序查询 4.1 排序查询语法 4.2 排序查询练习 5 聚合函数 5.1 一般语法&#xff1a; 5.2 聚合函数练习 6 分组查询 6.1 分组查询语法 6.2 分组查询…

IDEA集成DeepSeek,通过离线安装解决无法安装Proxy AI插件问题

文章目录 引言一、安装Proxy AI1.1 在线安装Proxy AI1.2 离线安装Proxy AI 二、Proxy AI中配置DeepSeek2.1 配置本地部署的DeepSeek&#xff08;Ollama方式&#xff09;2.2 通过第三方服务商提供的API进行配置 三、效果测试 引言 许多开发者尝试通过安装Proxy AI等插件将AI能力…