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

《嵌入式Linux应用编程():Linux Framebuffer图形编程》

Framebuffer核心概念

本质与工作原理

  • 硬件抽象:通过/dev/fbX设备文件提供显存的软件接口。
  • 直接映射:使用mmap将显存映射到用户空间直接操作像素数据。
  • 像素格式
格式描述典型应用
RGB56516位(5红+6绿+5蓝)嵌入式LCD屏
ARGB888832位(含透明度通道)高性能图形

开发流程

打开显示设备/dev/fb0 
获取设备信息  
内存映射显存 
向映射的用户空间写入rgb颜色值 
解除映射  
关闭设备  


六类图形操作函数封装

绘制横线

绘制竖线

绘制矩形

绘制圆形

绘制BMP图片

绘制文字

.h
#ifndef __FRAMEBUFFER_H__
#define __FRAMEBUFFER_H__#define RGB_FMT_888 32
#define RGB_FMT_565 16#pragma pack(1)//bmp文件相关信息
typedef struct tagBITMAPFILEHEADER {short    bfType;         // 文件类型标志int      bfSize;         // 文件大小,单位为字节short    bfReserved1;    // 保留字节short    bfReserved2;    // 保留字节int      bfOffBits;      // 数据偏移量,即实际图像数据开始的位置
}Bmp_file_head_t;
//bmp图像信息
typedef struct tagBITMAPINFOHEADER {int   biSize;         // BITMAPINFOHEADER的大小,单位为字节int    biWidth;        // 位图的宽度,单位为像素int    biHeight;       // 位图的高度,单位为像素short    biPlanes;       // 目标设备的位平面数,必须为1short    biBitCount;     // 每像素位数(颜色深度)int   biCompression;  // 图像压缩类型int   biSizeImage;    // 图像大小,单位为字节int    biXPelsPerMeter;// 水平分辨率,单位为像素/米int    biYPelsPerMeter;// 垂直分辨率,单位为像素/米int   biClrUsed;      // 实际使用颜色数int   biClrImportant; // 重要颜色数
}Bmp_info_t;
#pragma pack()extern int init_fb(char *devname);
extern int uninit_fb();
extern void draw_point(int x, int y, unsigned int col);
extern void draw_bmp(int x, int y, char *bmpname);
extern void draw_word(int x, int y, unsigned char *pword, int w, int h, unsigned int col);
extern void draw_line(int x, int y, int len_x, unsigned int col);
extern void draw_vertical(int x, int y, int len_y, unsigned int col);
extern void draw_rectangle(int x, int y, int width, int height, unsigned int col);
extern void draw_circle(int center_x, int center_y, int radius, unsigned int col);
#endif
fun.c
#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"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);}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_line(int x, int y, int len_x, unsigned int col)
{if (x >= vinfo.xres || y >= vinfo.yres){return ;}int x_star = x;int x_end = x + len_x;if (x_end > vinfo.xres) {x_end = vinfo.xres;  // 限制最大x为屏幕宽度}if (vinfo.bits_per_pixel == RGB_FMT_888){for(x_star; x_star <= x_end; x_star++){unsigned int *p = pmem;*(p + vinfo.xres_virtual * y + x_star) = col;}}else if (vinfo.bits_per_pixel == RGB_FMT_565){  for(x_star; x_star <= x_end; x_star++){unsigned short *p = pmem;*(p + vinfo.xres_virtual * y + x_star) = col;}}
}// 画竖线
void draw_vertical(int x, int y, int len_y, unsigned int col)
{if (x >= vinfo.xres || y >= vinfo.yres){return ;}int y_star = y;int y_end = y + len_y;if (y_end > vinfo.yres) {y_end = vinfo.yres;  // 限制最大x为屏幕宽度}if (vinfo.bits_per_pixel == RGB_FMT_888){for(y_star; y_star <= y_end; y_star++){unsigned int *p = pmem;*(p + vinfo.xres_virtual * y_star + x) = col;} }else if (vinfo.bits_per_pixel == RGB_FMT_565){  for(y_star; y_star <= y_end; y_star++){unsigned short *p = pmem;*(p + vinfo.xres_virtual * y_star + x) = col;}}
}
// 画矩形
void draw_rectangle(int x, int y, int width, int height, unsigned int col)
{// 检查起始点是否超出屏幕范围if (x >= vinfo.xres || y >= vinfo.yres){return ;}// 计算矩形的边界int x_start = x;int x_end = x + width;int y_start = y;int y_end = y + height;// 限制矩形在屏幕范围内if (x_end > vinfo.xres) {x_end = vinfo.xres;}if (y_end > vinfo.yres) {y_end = vinfo.yres;}// 绘制上下两条水平线draw_line(x_start, y_start, x_end - x_start, col);draw_line(x_start, y_end - 1, x_end - x_start, col);// 绘制左右两条垂直线draw_vertical(x_start, y_start + 1, y_end - y_start - 2, col);draw_vertical(x_end - 1, y_start + 1, y_end - y_start - 2, col);
}
// 画圆
//
void draw_circle(int center_x, int center_y, int radius, unsigned int col)
{// 检查圆是否完全在屏幕外if (center_x + radius < 0 || center_x - radius >= vinfo.xres ||center_y + radius < 0 || center_y - radius >= vinfo.yres){return;}// 使用中点圆算法绘制空心圆int x = radius;int y = 0;int err = 0;while (x >= y){// 绘制8个对称点(圆的轮廓)if (center_x + x < vinfo.xres && center_y + y < vinfo.yres)draw_point(center_x + x, center_y + y, col);if (center_x + y < vinfo.xres && center_y + x < vinfo.yres)draw_point(center_x + y, center_y + x, col);if (center_x - y >= 0 && center_y + x < vinfo.yres)draw_point(center_x - y, center_y + x, col);if (center_x - x >= 0 && center_y + y < vinfo.yres)draw_point(center_x - x, center_y + y, col);if (center_x - x >= 0 && center_y - y >= 0)draw_point(center_x - x, center_y - y, col);if (center_x - y >= 0 && center_y - x >= 0)draw_point(center_x - y, center_y - x, col);if (center_x + y < vinfo.xres && center_y - x >= 0)draw_point(center_x + y, center_y - x, col);if (center_x + x < vinfo.xres && center_y - y >= 0)draw_point(center_x + x, center_y - y, col);// 中点圆算法迭代if (err <= 0){y++;err += 2 * y + 1;}if (err > 0){x--;err -= 2 * x + 1;}}
}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;}}}
}
main.c
#include <stdio.h>
#include "framebuffer.h"/*
1. 打开显示设备(/dev/fb0)
2. 获取显示设备相关参数(分辨率,像素格式)
3. 建立显存空间和用户空间的内存映射
4. 向映射的用户空间写入RGB颜色值
5. 解除映射关系
6. 关闭显示设备
*/unsigned char A[2*19] = {
/*--  文字:  A  --*/
/*--  仿宋14;  此字体下对应的点阵为:宽x高=10x19   --*/
/*--  宽度不是8的倍数,现调整为:宽度x高度=16x19  --*/
0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x00,0x1C,0x00,0x1C,0x00,0x3E,0x00,0x3E,0x00,
0x36,0x00,0x36,0x00,0x7F,0x00,0x7F,0x00,0x67,0x00,0x63,0x00,0xE3,0x80,0xE7,0xC0,
0x00,0x00,0x00,0x00,0x00,0x00
};unsigned char pu[3*21] = {
/*--  文字:  普  --*/
/*--  仿宋16;  此字体下对应的点阵为:宽x高=22x21   --*/
/*--  宽度不是8的倍数,现调整为:宽度x高度=24x21  --*/
0x00,0x04,0x00,0x03,0x0E,0x00,0x01,0x8E,0x00,0x01,0xCC,0x00,0x0F,0xFF,0xC0,0x1F,
0xFB,0x00,0x0C,0xDB,0x80,0x06,0xDB,0x00,0x07,0xDE,0x00,0x03,0xDF,0xE0,0x7F,0xFF,
0xE0,0x3C,0x02,0x00,0x07,0xFF,0x00,0x03,0xF7,0x00,0x03,0x16,0x00,0x03,0xFE,0x00,
0x03,0x06,0x00,0x03,0xFE,0x00,0x07,0xFE,0x00,0x03,0x06,0x00,0x00,0x00,0x00
};int main(void)
{int ret = init_fb("/dev/fb0");if (ret < 0){return -1;}//4. 向映射的用户空间写入RGB颜色值draw_point(400, 300, 0x00FF0000);draw_line(0, 0, 800, 0x00FF0000);draw_vertical(0, 0, 600, 0xFF0000);draw_rectangle(100,100,100,100,0x00FF0000);draw_circle(400, 300, 100, 0x00FF0000);//draw_bmp(0, 0, "./1.bmp");//draw_word(200, 300, A, 2, 19, 0x00FF0000);//draw_word(100,200, pu, 3, 21, 0x00FF0000);uninit_fb();return 0;
}

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

相关文章:

  • Win11和Mac设置环境变量
  • 机器学习阶段性总结:对深度学习本质的回顾 20250813
  • Html5-canvas动态渐变背景
  • mac 安卓模拟器 blueStacks
  • MacOS字体看起来比在 Windows 上更好?
  • 367. 有效的完全平方数
  • Spring Boot + MyBatis
  • Python 元类基础:从理解到应用的深度解析
  • [CSCCTF 2019 Qual]FlaskLight
  • [AI React Web] 包与依赖管理 | `axios`库 | `framer-motion`库
  • Spring cloud集成ElastictJob分布式定时任务完整攻略(含snakeyaml报错处理方法)
  • 使用TexLive与VScode排版论文
  • 从0开始配置conda环境并在PyCharm中使用
  • Node.js浏览器引擎+Python大脑的智能爬虫系统
  • 低成本扩展方案:S7-200SMART作为S7-1500分布式IO从站的上位机配置指南
  • Linux网络性能调优终极指南:深度解析与实践
  • 初识c语言————排序方法
  • 【新手入门】Android Studio 项目结构拆解,快速理解文件作用!
  • 【Linux】常用命令(三)
  • 数据结构:用数组实现队列(Implementing Queue Using Array)
  • Python实现点云概率ICP(GICP)配准——精配准
  • 8.13打卡 DAY 41 简单CNN
  • 多模态RAG赛题实战之策略优化--Datawhale AI夏令营
  • 桌面运维如何深造
  • MySQL表约束
  • Spring Boot项目中线程池的全面教程
  • 中高级餐饮服务食品安全员考试核心知识点汇总
  • Spring Boot初级概念及自动配置原理
  • Spring Boot 3 连接池最大连接数设置建议
  • sample_kol里配置为 deep sleep mode,则系统进入 STR