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

Linux Framebuffer(帧缓冲)与基本 UI 绘制技术

1. UI 技术简介

UI(User Interface):用户界面技术,用于实现图形化交互。

在 Linux 中,**framebuffer(帧缓冲/帧缓存)**是内核提供的一套图形显示接口,使用户程序可以直接操作显存实现显示效果。


2. 帧缓冲基础

分辨率

800 × 600

像素格式

格式字节数说明
RGB8883 → 4每个像素 3 个字节,通常对齐到 4 字节
RGB5652每个像素 2 个字节

显存访问示例

unsigned int *pmem;

*(pmem + 800 * y + x) = 0x00FF0000; // 将 (x,y) 位置像素设为红色


3. framebuffer 使用流程

  1. 打开显示设备

int fd = open("/dev/fb0", O_RDWR);

  1. 获取显示参数

ioctl(fd, FBIOGET_VSCREENINFO, &vinfo); // 获取分辨率、像素格式等信息

  1. 建立显存和用户空间的内存映射

void *addr = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);

参数说明

  • addr:用户空间首地址,NULL 由系统分配

  • length:映射长度

  • prot:访问权限,如 PROT_READ | PROT_WRITE

  • flags:映射类型,如 MAP_SHARED

  • fd:设备文件描述符

  • offset:从显存的偏移量,一般为 0

返回值

  • 成功:映射的用户空间首地址

  • 失败:MAP_FAILED ((void *)-1)

  1. 写入像素数据

    • 向映射的内存写入颜色值即可实现绘图

    • 示例:*(pmem + 800*y + x) = 0x00FF0000;

  2. 解除映射

munmap(addr, length);

  1. 关闭显示设备

close(fd);


4. 基本绘图封装函数

  1. 绘制横线

  2. 绘制竖线

  3. 绘制矩形

  4. 绘制圆

  5. 绘制 BMP 图片

  6. #include <stdio.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <sys/ioctl.h>
    #include <linux/fb.h>
    #include <sys/mman.h>
    #include "framebuffer.h"
    #include <math.h>void *pmem = NULL;
    int fb;
    struct fb_var_screeninfo vinfo;int init_fb(char *devname)
    {//1. 打开显示设备(/dev/fb0)fb = open(devname, O_RDWR);if (-1 == fb){perror("open fb error");return -1;}//2. 获取显示设备相关参数(分辨率,像素格式)int ret = ioctl(fb, FBIOGET_VSCREENINFO, &vinfo);if (ret < 0){perror("ioctl error");return -1;}printf("xres = %d, yres = %d\n", vinfo.xres, vinfo.yres);printf("xres_virtual = %d, yres_virtual = %d\n", vinfo.xres_virtual, vinfo.yres_virtual);printf("bits_per_pixel = %d\n", vinfo.bits_per_pixel);//3. 建立显存空间和用户空间的内存映射size_t len = vinfo.xres_virtual * vinfo.yres_virtual * vinfo.bits_per_pixel/8;pmem = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, fb, 0);if (pmem == MAP_FAILED){perror("mmap error");return -1;}return 0;
    }int uninit_fb()
    {//5. 解除映射关系//6. 关闭显示设备size_t len = vinfo.xres_virtual * vinfo.yres_virtual * vinfo.bits_per_pixel/8;munmap(pmem, len);close(fb);return 0;
    }void draw_point(int x, int y, unsigned int col)
    {if (x >= vinfo.xres || y >= vinfo.yres){return ;}if (vinfo.bits_per_pixel == RGB_FMT_888){unsigned int *p = pmem;*(p+vinfo.xres_virtual *y+x) = col;}else if (vinfo.bits_per_pixel == RGB_FMT_565){unsigned short *p = pmem;*(p+vinfo.xres_virtual*y+x) = col;}
    }void draw_row_line(int x, int y, unsigned int col)
    {if (x >= vinfo.xres || y >= vinfo.yres){return ;}if (vinfo.bits_per_pixel == RGB_FMT_888){unsigned int *p = pmem;while(x != 799){*(p+vinfo.xres_virtual *y+x) = col;++x;}}else if (vinfo.bits_per_pixel == RGB_FMT_565){unsigned short *p = pmem;while(x != 799){*(p+vinfo.xres_virtual*y+x) = col;++x;}}
    }void draw_clos_line(int x, int y, unsigned int col)
    {if (x >= vinfo.xres || y >= vinfo.yres){return ;}if (vinfo.bits_per_pixel == RGB_FMT_888){unsigned int *p = pmem;while(y != 599){// *(p+vinfo.xres_virtual*y+x) = col;// ++x;*(p+vinfo.xres_virtual*y+x) = col;++y;}}else if (vinfo.bits_per_pixel == RGB_FMT_565){unsigned short *p = pmem;while(y != 599){// *(p+vinfo.xres_virtual*y+x) = col;// ++x;*(p+vinfo.xres_virtual*y+x) = col;++y;}}
    }void draw_round(int cx, int cy, int r,unsigned int col)
    {if (cx >= vinfo.xres || cy >= vinfo.yres){return ;}if(r > cx || r > cy || r + cx > vinfo.xres || r + cy > vinfo.yres){return ;}double PI = 3.1415926;if (vinfo.bits_per_pixel == RGB_FMT_888){for(double angle = 0;angle <2 * PI;angle += 0.01){int x = (int)(cx + r * cos(angle));int y = (int)(cy + r * sin(angle));draw_point(x, y, col);}}else if (vinfo.bits_per_pixel == RGB_FMT_565){for(double angle = 0;angle < 2 * PI;angle += 0.01){int x = (int)(cx + r * cos(angle));int y = (int)(cy + r * sin(angle));draw_point(x, y, col);}}
    }int get_bmp_head_info(const char *bmpname, Bmp_file_head_t *pheadinfo, Bmp_info_t *pbmpinfo)
    {FILE *fp = fopen(bmpname, "r");if (NULL == fp){perror("fopen error");return -1;}fread(pheadinfo, sizeof(Bmp_file_head_t), 1, fp);fread(pbmpinfo, sizeof(Bmp_info_t), 1, fp);fclose(fp);return 0;
    }void draw_bmp(int x, int y, char *bmpname)
    {Bmp_file_head_t headinfo;Bmp_info_t bmpinfo;get_bmp_head_info("./1.bmp", &headinfo, &bmpinfo);int fd = open(bmpname, O_RDONLY);if (-1 == fd){perror("open bmp error");return ;}lseek(fd, 54, SEEK_SET);unsigned char *buff = malloc(bmpinfo.biHeight*bmpinfo.biWidth*bmpinfo.biBitCount/8);read(fd, buff, bmpinfo.biHeight*bmpinfo.biWidth*bmpinfo.biBitCount/8);close(fd);unsigned char *p = buff;unsigned char r, g, b;for (int j = bmpinfo.biHeight-1; j >= 0; j--){for (int i = 0; i < bmpinfo.biWidth; i++){b = *p;++p;g = *p;++p;r = *p;++p;if (vinfo.bits_per_pixel == RGB_FMT_888){unsigned int col = (r << 16) | (g << 8) | (b << 0);draw_point(i+x, j+y, col);}else if  (vinfo.bits_per_pixel == RGB_FMT_565){unsigned short col = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);draw_point(i+x, j+y, col);}}}free(buff);}//w = 2, h = 19
    void draw_word(int x, int y, unsigned char *pword, int w, int h, unsigned int col)
    {for (int j = 0; j < h; j++){for (int i = 0; i < w; i++){unsigned char tmp = pword[i+j*w];for (int k = 0; k < 8; k++){if (tmp & 0x80){draw_point(x+i*8+k, y+j, col);}else{}tmp = tmp << 1;}}}
    }

    绘制文字

http://www.lryc.cn/news/620112.html

相关文章:

  • 【R语言】RStudio 中的 Source on Save、Run、Source 辨析
  • 认知系统的架构: 认知残余三角形、认知主体意识 和认知演进金字塔
  • 【docker①】在VS Code中使用Docker容器
  • 从零用 NumPy 实现单层 Transformer 解码器(Decoder-Only)
  • 未来AI:微算法科技(NASDAQ:MLGO)开发基于忆阻器网络储层计算MemristorPattern虚拟平台
  • 通过限制网络访问来降低服务器被攻击风险的方法
  • 云原生技术k8s部署prometheus
  • 面向Python/C#开发者入门Java与Bukkit API
  • C# 反射和特性(元数据和反射)
  • Mysql——如何做到Redolog崩溃后恢复的
  • NLP学习之Transformer(1)
  • 算法题——哈希表
  • 洛谷 P2607 [ZJOI2008] 骑士-提高+/省选-
  • 从 Web 开发到数据科学:全栈基础技术总结
  • nm命令和nm -D命令参数
  • 互联网大厂Java求职面试实录:Spring Boot到微服务与AI的技术问答
  • 《量子雷达》第2章 从量子信息到量子雷达 预习2025.8.13
  • Canal解析MySQL Binlog原理与应用
  • RC4算法实现
  • 一键自动化:Kickstart无人值守安装指南
  • 如何优雅地实现API接口每 10秒轮询请求?
  • 力扣面试150题--三角形最小路径和 最小路径和 不同路径 最长回文子串
  • RagFlow启动源码说明
  • 前后端分离项目在云服务器的部署
  • 【系统安装】虚拟机中安装win10企业版系统记录
  • CSS保持元素宽高比,固定元素宽高比
  • 用 mock 把 ES 单元测试@elastic/elasticsearch-mock 上手
  • Python 环境隔离实战:venv、virtualenv 与 conda 的差异与最佳实践
  • 变分自编码器VAE的Pytorch实现
  • day39_2025-08-13