Linux学习-UI技术

发布于:2025-08-16 ⋅ 阅读:(16) ⋅ 点赞:(0)

UI技术:User interface

framebuffer:帧缓冲,帧缓存技术,Linux内核专门为图形化显示提供的一套应用程序接口

mmap

void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);

功能

建立内存映射,将文件/设备内容映射到进程虚拟地址空间,实现高效数据读写。

参数

-addr  :期望映射到的用户空间首地址,填  NULL  让操作系统自动分配合适地址 
 -length  :要映射的空间大小(字节为单位,需合理规划,避免越界) 
 -prot  :内存保护权限(可组合,如 `PROT_READ ,PROT_WRITE)
 -flags  :映射类型,常用  MAP_SHARED (修改映射区会回写文件/设备,共享变更) 
 -fd  :待映射的文件/设备的文件描述符(需提前  open  打开) 
 -offset  :映射起始偏移(通常填  0 ,从文件/设备起始位置开始;需是页大小整数倍) 

返回值

- 成功:返回实际映射到的用户空间首地址( void*  类型,可强转为需求指针)
- 失败:返回  MAP_FAILED (本质是  (void *)-1 ,需用  perror  等排查错误)

munmap

int munmap(void *addr, size_t length);  

解除映射

功能

- 释放  mmap  建立的内存映射关系,回收映射的虚拟地址空间,避免内存泄漏。
- 调用后,原映射区域的指针( addr  起始的  length  空间)不可再访问,否则会触发段错误。

参数

 addr   mmap  :返回的映射首地址(必须精准匹配,否则可能导致未定义行为) 
 length  :映射的空间大小(需与  mmap  时传入的  length  一致,确保完整解除) 

返回值

- 成功:返回  0 
- 失败:返回  -1 ,可通过  errno  查具体错误(如非法地址、权限问题等)

头文件

#ifndef __FRAMEBUFF_H__
#define __FRAMEBUFF_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;       // 目标设备的位平面数,必须为1
  short 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 int DrawXLine(int x, int y, int len, unsigned int col);
extern int DrawYLine(int x, int y, int len, unsigned int col);
extern int DrawRect(int x, int y, int high, int wide, unsigned int col);
extern int DrawCircle(int x, int y, int r, 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);
#endif

配置framebuffer

#include "framebuff.h"
#include <fcntl.h>
#include <linux/fb.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.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;
    }
}

绘制横线

int DrawXLine(int x, int y, int len, unsigned int col)
{
  int i = 0;

  for (i = 0; i < len; i++)
    {
      draw_point(x + i, y, col);
    }

  return 0;
}

绘制竖线

int DrawYLine(int x, int y, int len, unsigned int col)
{
  int i = 0;

  for (i = 0; i < len; i++)
    {
      draw_point(x, y + i, col);
    }

  return 0;
}

绘制矩形框

int DrawRect(int x, int y, int high, int wide, unsigned int col)
{
  DrawXLine(x, y, wide, col);
  DrawYLine(x, y, high, col);
  DrawYLine(x + wide, y, high, col);
  DrawXLine(x, y + high, wide, col);
  return 0;
}

绘制圆

int DrawCircle(int x, int y, int r, unsigned int col)
{
  int i, a, b;
  for (i = 0; i < 360; ++i)
    {
      a = x + r * cos(i / 180.0 * M_PI);
      b = y + r * sin(i / 180.0 * M_PI);
      draw_point(a, b, col);
    }
}

绘制图片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("./1.txt.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);
}

绘制文字(需要取模软件)

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

主函数调用

#include <stdio.h>
#include "framebuff.h"

/*
1. 打开显示设备(/dev/fb0)
2. 获取显示设备相关参数(分辨率,像素格式)
3. 建立显存空间和用户空间的内存映射
4. 向映射的用户空间写入RGB颜色值
5. 解除映射关系
6. 关闭显示设备
*/
unsigned char p[4 * 33] = {
    /*--  文字:  辉  --*/
    /*--  仿宋24;  此字体下对应的点阵为:宽x高=32x33   --*/
    /*--  文字:  辉  --*/
    /*--  仿宋24;  此字体下对应的点阵为:宽x高=32x33   --*/
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xC0,
    0x00, 0x00, 0x00, 0xE0, 0x00, 0x18, 0x00, 0xE1, 0x80, 0x3C,
    0x00, 0xCD, 0xFF, 0xFC, 0x00, 0xCD, 0xFF, 0xF8, 0x1C, 0xCF,
    0x98, 0x70, 0x0E, 0xDF, 0x9C, 0x60, 0x0E, 0xDB, 0x9C, 0x00,
    0x07, 0xF8, 0x19, 0xE0, 0x06, 0xF1, 0xFF, 0xF0, 0x00, 0xC1,
    0xFC, 0x00, 0x00, 0xFF, 0x7C, 0x00, 0x3F, 0xFF, 0x7E, 0x00,
    0x3F, 0xF0, 0xEE, 0x00, 0x03, 0xF0, 0xEF, 0xE0, 0x03, 0xF1,
    0xFF, 0xF0, 0x03, 0xF1, 0xFE, 0x00, 0x03, 0x70, 0x8E, 0x00,
    0x07, 0x70, 0x0E, 0x00, 0x07, 0x76, 0x1F, 0xFC, 0x07, 0x7F,
    0xFF, 0xFC, 0x06, 0x79, 0xCE, 0x00, 0x0E, 0x78, 0x0E, 0x00,
    0x0C, 0x70, 0x0E, 0x00, 0x1C, 0x20, 0x0E, 0x00, 0x18, 0x00,
    0x0E, 0x00, 0x30, 0x00, 0x0E, 0x00, 0x20, 0x00, 0x0E, 0x00,
    0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 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);

  // DrawXLine(200, 200, 400, 0x00ff0000);
  // DrawYLine(200, 200, 400, 0x00ff0000);
  // DrawRect(0, 0, 400, 400, 0x00FF0000);
  // DrawCircle(200, 200, 200, 0x00FF0000);

  draw_bmp(0, 0, "./1.txt.bmp");
  draw_word(400, 300, p, 4, 33, 0x00FFff00);

  uninit_fb();

  return 0;
}

补充:

perror函数可打印系统给出的错误信息


网站公告

今日签到

点亮在社区的每一天
去签到