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

1. UI 技术简介

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

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


2. 帧缓冲基础

分辨率

800 × 600

像素格式

格式 字节数 说明
RGB888 3 → 4 每个像素 3 个字节,通常对齐到 4 字节
RGB565 2 每个像素 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 图片

cs 复制代码
#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;
            }
        }

    }
}

绘制文字

相关推荐
一乐小哥几秒前
Docker 拉取镜像超时?别再瞎抄配置了!亲测 3 个有效镜像源 + 避坑指南
linux·docker
the sun347 分钟前
从内核数据结构的角度理解socket
linux·运维·服务器
GDAL26 分钟前
Docker pull拉取镜像命令的入门教程
运维·docker·容器
Fanmeang1 小时前
MP-BGP Hub-Spoken实验案例+通信过程(超详细)
运维·网络·华为·mpls·vpn·mpbgp·hubspoke
羊子雄起2 小时前
GitHub宕机时的协作方案
运维·vscode·github·visual studio
wanhengidc2 小时前
大带宽服务器具体是指什么?
运维·服务器
it_laozhu2 小时前
ESXI 6.7服务器时间错乱问题
运维·服务器
辉视5622 小时前
融合服务器助力下的电视信息发布直播点播系统革新
运维·服务器
阿群今天学习了吗2 小时前
label studio 服务器端打开+xshell端口转发设置
linux·运维·服务器·笔记·python