Linux編程 —— framebuffer

一、framebuffer概念

framebuffer:幀緩沖,幀緩存技術

????????????????????????Linux內核專門為圖形化顯示提供的一套應用程序接口。

?二、基本操作步驟

1. 打開顯示設備(/dev/fb0)
2. 獲取顯示設備相關參數(分辨率,像素格式)---》ioctl
3. 建立顯存空間和用戶空間的內存映射
4. 向映射的用戶空間寫入RGB顏色值
5. 解除映射關系
6. 關閉顯示設備

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;
}
#ifndef __FRAMEBUFFER_H__
#define __FRAMEBUFFER_H__#define RGB_FMT_888 32
#define RGB_FMT_565 16
#define PI   3.14
#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_horizontal_line(int x1,int x2,int y,unsigned int col);
extern void draw_y_line(int x,int y,int ymax,unsigned int col);
extern void draw_face(int x1,int x2 ,int y1,int y2,int col);
extern void draw_Circle(int x, int y, int r, unsigned int col);
extern int get_bmp_head_info(const char *bmpname, Bmp_file_head_t *pheadinfo, Bmp_info_t *pbmpinfo);
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);
#endif

注:此為函數接口頭文件

三、mmap函數接口

void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);
功能:建立內存映射
參數:
addr :映射的用戶空間首地址 ?
NULL:讓操作系統自己分配用戶空間
length:要映射的空間大小
prot: 操作權限
PROT_READ ?Pages may be read.
PROT_WRITE Pages may be written
flag : MAP_SHARED
fd:顯示設備文件描述符
offset:偏移量
0:從顯存開頭映射
返回值:
成功:映射的用戶空間首地址
失敗:MAP_FAILED((void *)-1)

int uninit_fb()
{//5. 解除映射關系//6. 關閉顯示設備size_t len = vinfo.xres_virtual * vinfo.yres_virtual * vinfo.bits_per_pixel/8;munmap(pmem, len);close(fb);}

四、基本操作及算法? ? ? ? ? ?

1.畫一個點

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

注:虛擬界面視圖大于實際視圖? ? ? ? ?

①要保持起始點在視圖范圍內

②bits_per_pixel:表示每個像素所占用的位數(bit),它決定了圖像的顏色深度和顯示質量。數值越高,能夠表示的顏色數量越多,圖像的色彩表現越豐富。

RGB888:每個像素占8位,及一個字節?,RGB888占3個字節,但在C中沒有可以存儲三字節的整形變量,它就會自動補為四字節,并將高位置零

RGB565:紅色占5位,綠色占6位,藍色占7位,? RGB565占2個字節

③pmem在建立內存映射時指向了顯存,而我們不能直接對顯存直接進行操做,所以定義相應的指針與pemp指向的地址相同,也可以理解為強轉pemp,利用強轉的pemp對顯存所映射的用戶空間進行操作? ?

2.畫一條橫線

void draw_horizontal_line(int x1,int x2,int y,unsigned int col)
{if(x1 >= vinfo.xres || x2 >=  vinfo.xres || y >= vinfo.yres){return ;}if(x1 > x2){int t = x1;x1 = x2;x2 = x1;}for(int i = 0;i <= x2 - x1 ; ++i ){if (vinfo.bits_per_pixel == RGB_FMT_888){unsigned int *p = pmem;*(p+vinfo.xres_virtual*y+(x1+i)) = col;}else if (vinfo.bits_per_pixel == RGB_FMT_565){unsigned short *p = pmem;*(p+vinfo.xres_virtual*y+(x1+i)) = col;}}
}

思想(點成面):畫一條橫線,橫坐標改變,縱坐標不變,即繪制一條x1至x2的橫線

3.畫一條豎線

void draw_y_line(int x,int y,int ymax,unsigned int col)
{if(x >= vinfo.xres || y >=  vinfo.yres || ymax>= vinfo.yres){return ;}for(int i = 0;i <= ymax - y; ++i ){if (vinfo.bits_per_pixel == RGB_FMT_888){unsigned int *p = pmem;*(p+vinfo.xres_virtual*(y+i)+x) = col;}else if (vinfo.bits_per_pixel == RGB_FMT_565){unsigned short *p = pmem;*(p+vinfo.xres_virtual*(y+i)+x) = col;}}
}

4.繪制一個面?

void draw_face(int x1,int x2 ,int y1,int y2,int col)
{if(x1 > x2){int t = x1;x1 = x2;x2 = t;}if(y1 > y2){int t = y1;y1 = y2;y2 = t;}if(x1 >= vinfo.xres ||x2 >=vinfo.xres|| y1 >=  vinfo.yres || y2 >= vinfo.yres){return ;}int i = 0; if (vinfo.bits_per_pixel == RGB_FMT_888){for(i = 0;i < y2 - y1;++i){draw_horizontal_line(x1,x2,y1+i,col);draw_horizontal_line(x1,x2,y2+i,col);}       }else if (vinfo.bits_per_pixel == RGB_FMT_565){ for(i = 0;i < y2 - y1;++i){draw_horizontal_line(x1,x2,y1+i,col);draw_horizontal_line(x1,x2,y2+i,col);}}if (vinfo.bits_per_pixel == RGB_FMT_888){for(i = 0;i < x2 -x1;++i){   draw_y_line(x1 + 1,y1,y2,col);draw_y_line(x2 + 1,y1,y2,col);}}else if (vinfo.bits_per_pixel == RGB_FMT_565){for(i = 0;i < x2 -x1;++i){   draw_y_line(x1 + 1,y1,y2,col);draw_y_line(x2 + 1,y1,y2,col);}}
}

思想(線成面)

6.繪制一個圓?

void draw_Circle(int x, int y, int r, unsigned int col)
{int x0 = 0;int y0 = 0;int si = 0;for (si = 0; si <= 360; si++){x0 = r * sin(PI * 2 / 360 * si) + x; y0 = r * cos(PI * 2 / 360 * si) + y;draw_point(x0, y0, col);}
}

思想:x,y為圓心坐標,圓周上任意一點為(x0,y0)

sin(PI * 2 / 360 * si) ,cos(PI * 2 / 360 * si)?是將角度轉化為弧度

7,繪制一個bmp圖

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(bmpname, &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);}

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? ?get_bmp_head_info(const char *bmpname, Bmp_file_head_t *pheadinfo, Bmp_info_t *pbmpinfo)

算法思想:

文件操作:

以只讀模式打開BMP文件,失敗時返回錯誤。

頭信息讀取:

使用 fread 讀取BMP文件頭(Bmp_file_head_t)到 pheadinfo。

繼續讀取BMP信息頭(Bmp_info_t)到 pbmpinfo。

資源釋放:關閉文件句柄,返回成功狀態。

draw_bmp(int x, int y, char *bmpname)

算法思想:

頭信息解析:調用 get_bmp_head_info 獲取BMP的寬、高、位深等信息。

像素數據加載:

打開文件并跳過54字節的文件頭和信息頭。

根據BMP信息頭中的圖像尺寸和位深(如 biWidth × biHeight × biBitCount/8),分配緩沖區 buff 并讀取像素數據。

像素繪制:

BMP像素順序:BMP文件存儲順序為從下到上,需反向遍歷行(j 從 biHeight-1 到 0)。

顏色轉換:

對于 RGB888格式屏幕:將BGR像素數據(BMP格式)轉換為RGB888,合并為 unsigned int 后調用 draw_point。

對于 RGB565格式屏幕:將RGB分量壓縮為5-6-5位,合并為 unsigned short。

繪制每個像素到屏幕坐標 (x + i, y + j)。

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?8.繪制一個字

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

? ?

思想:

字模數據解析:

字模數據 pword 為 w × h 的字節數組,每個字節表示8個水平像素點(1位1像素)。

逐行逐像素繪制:

外層循環遍歷行(j 從 0 到 h-1)。

內層循環遍歷列(i 從 0 到 w-1):

獲取當前字節 tmp = pword[i + j * w]。

對字節的8個位(從高位到低位):

若某位為 1,調用 draw_point(x + i*8 + k, y + j, col) 繪制像素。

若為 0,跳過(透明或背景)。

效果:

將1位字模數據按指定顏色展開為8倍寬度的字符圖形。

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? ? ? ? ? ? ? ? ? ? ?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/92959.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/92959.shtml
英文地址,請注明出處:http://en.pswp.cn/web/92959.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

文件編輯html

<!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>文件行內容編輯器</title><script src&…

具有熔斷能力和活性探測的服務負載均衡解決方案

一、整體架構設計 1.核心組件 負載均衡器&#xff1a;負責選擇可用的服務節點健康檢查器&#xff1a;定期檢測服務節點的可用性服務節點管理&#xff1a;維護所有可用節點的狀態信息 2.負載均衡策略 輪詢(Round Robin)隨機(Random)加權輪詢(Weighted Round Robin)最少連接(Leas…

技術演進中的開發沉思-62 DELPHI VCL系列:VCL下的設計模式

今天聊聊設計模式&#xff0c;當然這個章節目前僅限于DELPHI VCL,因為接下來梳理的Factory/Factory Method、Bootstrap 和 ForEach 這三種設計樣例&#xff0c;看似獨立&#xff0c;卻在實際開發中相互配合&#xff0c;共同構建起高效、靈活的程序架構。在 DELPHI VCL 開發的技…

Docker 101:面向初學者的綜合教程

掌握 Docker 已成為軟件開發中的一項關鍵技能。本教程探討了容器化的世界&#xff0c;包括其核心概念、優缺點&#xff0c;以及開始使用容器化的分步指南。 無論是 Docker 的新手&#xff0c;還是希望復習基礎知識的更有經驗的開發人員&#xff0c;本指南都能滿足需求。 什么…

RTOS YAFFS

在 YAFFS (Yet Another Flash File System) 的語境中&#xff0c;“Check Point” 并不是一個標準的、核心的官方術語。它更可能是對 YAFFS 關鍵機制 Summary 或 Checkpointing 功能的非正式表述或理解偏差。其核心含義是指 YAFFS 在特定時刻保存文件系統關鍵元數據的狀態&…

【SpringBoot系列-02】自動配置機制源碼剖析

【SpringBoot系列-02】自動配置機制源碼剖析 咱們天天用Spring Boot&#xff0c;一個SpringBootApplication注解扔進去&#xff0c;啥配置都不用寫&#xff0c;項目就跑起來了。你有沒有過這種疑惑&#xff1a;那些DispatcherServlet、DataSource是從哪冒出來的&#xff1f;今天…

51單片機-51單片機最小系統

本章概述思維導圖&#xff1a;51單片機最小系統51單片機最小系統是51系列單片機&#xff08;如AT89C51、STC89C52等&#xff09;能夠獨立工作的最簡電路配置&#xff0c;它為單片機提供了運行所需的基本條件。51單片機最小系統板是嵌入式系統開發的基礎平臺&#xff0c;集成了單…

git學習1

目錄引入版本控制集中式和分布式版本控制git工作機制代碼托管中心Git常用命令設置用戶簽名初始化本地庫查看庫狀態add和提交版本穿梭git分支操作分支定義分支好處分支操作查看分支創建分支切換分支分支合并&#x1f495;?&#x1fa77;合并沖突git團隊協作團隊內協作跨團隊協作…

redis原理篇--Dict

Dict數據結構一、Redis字典的核心組件Redis字典由三部分構成&#xff1a;dictht&#xff08;哈希表&#xff09;&#xff1a;存儲桶數組與元數據dictEntry&#xff08;哈希節點&#xff09;&#xff1a;存儲鍵值對dict&#xff08;字典主體&#xff09;&#xff1a;包含雙哈希表…

靜態路由主備切換

在網絡中&#xff0c;靜態路由的主備切換是實現網絡冗余的基礎方案之一&#xff0c;通過配置不同優先級的靜態路由&#xff0c;確保主用路徑故障時&#xff0c;流量能自動切換到備用路徑&#xff0c;提升網絡可靠性。以下從知識講解和實驗配置兩部分詳細說明。一、靜態路由主備…

PDF處理控件Aspose.PDF教程:在C#、Java、Python中快速縮小PDF

如果您的PDF太大&#xff0c;無法通過電子郵件發送&#xff0c;或者在線加載時間過長&#xff0c;您可以在幾秒鐘內縮小 PDF 大小。本教程介紹了借助Aspose.PDF使用 C#、Java 和 Python 編程快速縮小PDF的方法。 Aspose.PDF官方試用版下載 通過編程縮小 PDF 尺寸 如果您需要…

AWS EKS 常用命令大全:從基礎管理到高級運維

前言 Amazon Elastic Kubernetes Service (EKS) 是 AWS 提供的托管 Kubernetes 服務,大大簡化了 K8s 集群的部署和管理工作。作為 EKS 管理員或開發者,熟練掌握 kubectl 命令是日常工作的基礎。本文將詳細介紹 EKS 環境中常用的 kubectl 命令,涵蓋集群管理、工作負載操作、…

GitHub Browser-Use 的部署失敗記錄:失敗了,失敗了。。。。

一、項目背景與核心作用 browser-use 是一個開源的瀏覽器自動化工具&#xff0c;通過集成 AI 智能體&#xff08;如 GPT、Claude、DeepSeek 等大型語言模型&#xff09;&#xff0c;實現用自然語言控制瀏覽器操作。其核心目標是 簡化網頁交互自動化&#xff0c;尤其適合復雜、…

調用springboot接口返回403,問題定位及總結

背景在一次與前端聯調后端接口時前端返回接口返回狀態碼是403&#xff0c;前端返回說已經帶了請求token。排查 查看后端控制臺沒有出現任何錯誤信息。自己postman手動調用接口&#xff0c;發現接口正常。仔細核對前端調用接口與postman請求的區別&#xff0c;沒有發現任何問題。…

布隆過濾器原理分析、應用場景、與redis使用案例

一、核心結構與工作原理1.1 數據結構布隆過濾器由以下兩部分組成&#xff1a;位數組&#xff08;Bit Array&#xff09;&#xff1a;一個長度為 m 的二進制數組&#xff0c;初始所有位為0。哈希函數組&#xff1a;k 個獨立的哈希函數&#xff0c;每個函數將輸入元素映射到位數組…

異步并發×編譯性能:Dart爬蟲的實戰突圍

Dart憑借其高效的異步并發模型、AOT編譯性能和現代化的語法&#xff0c;正成為爬蟲開發中值得關注的新選擇。特別是對于Flutter應用開發者而言&#xff0c;Dart提供了一種"全棧同語言"的獨特優勢。 本文我將通過實戰代碼展示如何利用Dart的核心優勢——包括基于Futur…

Day 8: 深度學習綜合實戰與進階技術 - 從優化到部署的完整流程

Day 8: 深度學習綜合實戰與進階技術 - 從優化到部署的完整流程 ?? 學習目標: 掌握深度學習模型優化、調試、遷移學習等工業級技能,能夠構建高性能的深度學習應用 ?? 核心概念概覽 核心概念解釋: 模型優化: 通過正則化、學習率調度等技術提升模型性能和泛化能力 為什么需…

特征工程--機器學習

1、特征工程1.1 概念特征工程&#xff08;Feature Engineering&#xff09;是機器學習項目中非常關鍵的一步&#xff0c;它是指通過領域知識來選擇、創建或修改能夠使機器學習模型更好地工作的特征&#xff08;即輸入變量&#xff09;。特征工程的目標是提高模型的性能&#xf…

支持任意 MCP 協議的客戶端

支持任意 MCP 協議的客戶端&#xff08;如&#xff1a;Cursor、Claude、Cline&#xff09;可方便使用高德地圖 MCP server。目前支持Streamable HTTP, SSE 和 Node.js I/O 三種接入方式(推薦用戶使用Streamable HTTP)。 快速接入-MCP Server|高德地圖API

【線性代數】目錄

【線性代數】線性方程組與矩陣——&#xff08;1&#xff09;線性方程組與矩陣初步【線性代數】線性方程組與矩陣——行列式【線性代數】線性方程組與矩陣——&#xff08;2&#xff09;矩陣與線性方程組的解【線性代數】線性方程組與矩陣——&#xff08;3&#xff09;線性方程…