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

    }
}

绘制文字

相关推荐
小生不才yz2 分钟前
shell编程 - 数据流指南
linux
lisanmengmeng8 分钟前
添加ceph节点
linux·服务器·ceph
Tinyundg11 分钟前
Linux系统分区
linux·运维·服务器
要做一个小太阳14 分钟前
华为Atlas 900 A3 SuperPoD 超节点网络架构
运维·服务器·网络·华为·架构
江畔何人初19 分钟前
service发现
linux·运维·云原生
life码农25 分钟前
Linux系统清空文件内容的几种方法
linux·运维·chrome
zbguolei30 分钟前
虚拟机安装Ubuntu后无法登录
linux·运维·ubuntu
UP_Continue33 分钟前
Linux--基础IO
linux·运维·服务器
驱动探索者37 分钟前
linux hwspinlock 学习
linux·运维·学习
FJW02081437 分钟前
使用HAProxy实现动静分离
linux·服务器