在 LCD 上显示字符-I.MX6U嵌入式Linux C应用编程学习笔记基于正点原子阿尔法开发板

在 LCD 上显示字符

在这里插入图片描述

原始方式:取模显示字符

LCD显示字符方法

  • 通过字符取模,在LCD屏上显示字符

  • 字符取模生成字符点阵,表示哪些像素点填充颜色

字符点阵表示

  • 字符点阵用二维数组表示,每个小方块对应一个bit位

    • 字符点阵图
  • 例子:宽64,高86的字符点阵,用unsigned char arr[86][8]表示

    • 就是一个 86 行 8 列的 unsigned char 类型数组

    • 字符点阵中的每一个小方块对应一个 bit 位,因为一行一共有 64 个小方块、也就对应 8 个字节(8 * 8 = 64

字符取模软件

  • 使用软件获取字符的子模,在LCD屏上显示

  • 简单但不适用于复杂应用

示例代码

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <string.h>
#include <errno.h>
#include <string.h>
#include <sys/mman.h>
#include <linux/fb.h>

#define FB_DEV      "/dev/fb0"      //LCD设备节点

static int width;                       //LCD宽度
static int height;                      //LCD高度
static unsigned short *screen_base = NULL;//LCD显存基地址

static unsigned char ch_char1[86][8] = {
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0xF0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x07},
{0xF0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x07},
{0xF0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x07},
{0xF0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x07},
{0xF0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x07},
{0xF0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x07},
{0xF0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x07},
{0xF0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x07},
{0xF0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x07},
{0x00,0x00,0x00,0xC0,0x7F,0x00,0x00,0x00},
{0x00,0x00,0x00,0xC0,0x7F,0x00,0x00,0x00},
{0x00,0x00,0x00,0xC0,0x7F,0x00,0x00,0x00},
{0x00,0x00,0x00,0xC0,0x7F,0x00,0x00,0x00},
{0x00,0x00,0x00,0xC0,0x7F,0x00,0x00,0x00},
{0x00,0x00,0x00,0xC0,0x7F,0x00,0x00,0x00},
{0x00,0x00,0x00,0xC0,0x7F,0x00,0x00,0x00},
{0x00,0xFC,0x07,0xC0,0x7F,0x00,0x00,0x00},
{0x00,0xFC,0x07,0xC0,0x7F,0x00,0x00,0x00},
{0x00,0xFC,0x07,0xC0,0x7F,0x00,0x00,0x00},
{0x00,0xFC,0x07,0xC0,0x7F,0x00,0x00,0x00},
{0x00,0xFC,0x07,0xC0,0x7F,0x00,0x00,0x00},
{0x00,0xFC,0x07,0xC0,0x7F,0x00,0x00,0x00},
{0x00,0xFC,0x07,0xC0,0xFF,0xFF,0xFF,0x01},
{0x00,0xFC,0x07,0xC0,0xFF,0xFF,0xFF,0x01},
{0x00,0xFC,0x07,0xC0,0xFF,0xFF,0xFF,0x01},
{0x00,0xFC,0x07,0xC0,0xFF,0xFF,0xFF,0x01},
{0x00,0xFC,0x07,0xC0,0xFF,0xFF,0xFF,0x01},
{0x00,0xFC,0x07,0xC0,0xFF,0xFF,0xFF,0x01},
{0x00,0xFC,0x07,0xC0,0xFF,0xFF,0xFF,0x01},
{0x00,0xFC,0x07,0xC0,0xFF,0xFF,0xFF,0x01},
{0x00,0xFC,0x07,0xC0,0xFF,0xFF,0xFF,0x01},
{0x00,0xFC,0x07,0xC0,0x7F,0x00,0x00,0x00},
{0x00,0xFC,0x07,0xC0,0x7F,0x00,0x00,0x00},
{0x00,0xFC,0x07,0xC0,0x7F,0x00,0x00,0x00},
{0x00,0xFC,0x07,0xC0,0x7F,0x00,0x00,0x00},
{0x00,0xFC,0x07,0xC0,0x7F,0x00,0x00,0x00},
{0x00,0xFC,0x07,0xC0,0x7F,0x00,0x00,0x00},
{0x00,0xFC,0x07,0xC0,0x7F,0x00,0x00,0x00},
{0x00,0xFC,0x07,0xC0,0x7F,0x00,0x00,0x00},
{0x00,0xFC,0x07,0xC0,0x7F,0x00,0x00,0x00},
{0x00,0xFC,0x07,0xC0,0x7F,0x00,0x00,0x00},
{0x00,0xFC,0x07,0xC0,0x7F,0x00,0x00,0x00},
{0x00,0xFC,0x07,0xC0,0x7F,0x00,0x00,0x00},
{0x00,0xFC,0x07,0xC0,0x7F,0x00,0x00,0x00},
{0x00,0xFC,0x07,0xC0,0x7F,0x00,0x00,0x00},
{0x00,0xFC,0x07,0xC0,0x7F,0x00,0x00,0x00},
{0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x1F},
{0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x1F},
{0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x1F},
{0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x1F},
{0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x1F},
{0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x1F},
{0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x1F},
{0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x1F},
{0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x1F},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"正",0*/
};

static unsigned char ch_char2[86][8] = {
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0xFC,0x07,0x00,0x00,0x00},
{0x00,0x00,0x00,0xFC,0x07,0x00,0x00,0x00},
{0x00,0x00,0x00,0xFC,0x07,0x00,0x00,0x00},
{0x00,0x00,0x00,0xFC,0x07,0x00,0x00,0x00},
{0x00,0x00,0x00,0xFC,0x07,0x00,0x00,0x00},
{0x00,0x00,0x00,0xFC,0xFF,0xFF,0xFF,0x0F},
{0x00,0x00,0x00,0xFC,0xFF,0xFF,0xFF,0x0F},
{0x00,0x00,0x00,0xFC,0xFF,0xFF,0xFF,0x0F},
{0x00,0x00,0x00,0xFC,0xFF,0xFF,0xFF,0x0F},
{0x00,0x00,0x00,0xFC,0xFF,0xFF,0xFF,0x0F},
{0x00,0x00,0x00,0xFC,0xFF,0xFF,0xFF,0x0F},
{0x00,0x00,0x00,0xFC,0xFF,0xFF,0xFF,0x0F},
{0x00,0x00,0x00,0xFC,0xFF,0xFF,0xFF,0x0F},
{0x00,0x00,0x00,0xFC,0x07,0x00,0x00,0x00},
{0x00,0x00,0x00,0xFC,0x07,0x00,0x00,0x00},
{0x00,0x00,0x00,0xFC,0x07,0x00,0x00,0x00},
{0x00,0x00,0x00,0xFC,0x07,0x00,0x00,0x00},
{0x00,0x00,0x00,0xFC,0x07,0x00,0x00,0x00},
{0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,0x00},
{0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,0x00},
{0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,0x00},
{0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,0x00},
{0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,0x00},
{0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,0x00},
{0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,0x00},
{0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,0x00},
{0x00,0xFF,0x01,0x00,0x00,0xC0,0x7F,0x00},
{0x00,0xFF,0x01,0x00,0x00,0xC0,0x7F,0x00},
{0x00,0xFF,0x01,0x00,0x00,0xC0,0x7F,0x00},
{0x00,0xFF,0x01,0x00,0x00,0xC0,0x7F,0x00},
{0x00,0xFF,0x01,0x00,0x00,0xC0,0x7F,0x00},
{0x00,0xFF,0x01,0x00,0x00,0xC0,0x7F,0x00},
{0x00,0xFF,0x01,0x00,0x00,0xC0,0x7F,0x00},
{0x00,0xFF,0x01,0x00,0x00,0xC0,0x7F,0x00},
{0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,0x00},
{0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,0x00},
{0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,0x00},
{0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,0x00},
{0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,0x00},
{0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,0x00},
{0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,0x00},
{0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00},
{0x00,0x01,0x00,0x00,0xC0,0x00,0x7C,0x00},
{0x00,0x0F,0x00,0x03,0xF8,0x00,0x7F,0x00},
{0x80,0x3F,0xF0,0x03,0xFF,0x81,0xFF,0x00},
{0x80,0xFF,0xFC,0x03,0xFE,0x81,0xFF,0x00},
{0xC0,0x7F,0xFC,0x07,0xFE,0x03,0xFF,0x01},
{0xC0,0x7F,0xF8,0x07,0xFC,0x03,0xFF,0x01},
{0xE0,0x3F,0xF8,0x0F,0xFC,0x07,0xFE,0x01},
{0xE0,0x3F,0xF0,0x0F,0xFC,0x07,0xFE,0x03},
{0xF0,0x1F,0xF0,0x0F,0xF8,0x07,0xFE,0x03},
{0xF0,0x1F,0xF0,0x1F,0xF8,0x0F,0xFC,0x07},
{0xF8,0x0F,0xE0,0x1F,0xF8,0x0F,0xFC,0x07},
{0xF8,0x0F,0xE0,0x1F,0xF0,0x0F,0xF8,0x0F},
{0xFC,0x07,0xE0,0x3F,0xF0,0x1F,0xF8,0x0F},
{0xFC,0x07,0xE0,0x3F,0xF0,0x1F,0xF0,0x1F},
{0xFC,0x03,0xC0,0x0F,0xE0,0x03,0xF0,0x07},
{0xF0,0x03,0xC0,0x00,0x60,0x00,0xE0,0x01},
{0xE0,0x01,0x00,0x00,0x00,0x00,0x20,0x00},
{0x80,0x01,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"点",1*/
};

static unsigned char ch_char3[86][8] = {
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x80,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x1F},
{0x80,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x1F},
{0x80,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x1F},
{0x80,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x1F},
{0x80,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x1F},
{0x80,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x1F},
{0x80,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x1F},
{0x80,0x7F,0x00,0x80,0xFF,0x00,0x00,0x00},
{0x80,0x7F,0x00,0xC0,0x7F,0x00,0x00,0x00},
{0x80,0x7F,0x00,0xC0,0x7F,0x00,0x00,0x00},
{0x80,0x7F,0x00,0xC0,0x3F,0x00,0x00,0x00},
{0x80,0x7F,0x00,0xE0,0x3F,0x00,0x00,0x00},
{0x80,0x7F,0xF8,0xFF,0xFF,0xFF,0xFF,0x01},
{0x80,0x7F,0xF8,0xFF,0xFF,0xFF,0xFF,0x01},
{0x80,0x7F,0xF8,0xFF,0xFF,0xFF,0xFF,0x01},
{0x80,0x7F,0xF8,0xFF,0xFF,0xFF,0xFF,0x01},
{0x80,0x7F,0xF8,0xFF,0xFF,0xFF,0xFF,0x01},
{0x80,0x7F,0xF8,0xFF,0xFF,0xFF,0xFF,0x01},
{0x80,0x7F,0xF8,0x07,0x00,0x00,0xFE,0x01},
{0x80,0x7F,0xF8,0x07,0x00,0x00,0xFE,0x01},
{0x80,0x7F,0xF8,0x07,0x00,0x00,0xFE,0x01},
{0x80,0x7F,0xF8,0x07,0x00,0x00,0xFE,0x01},
{0x80,0x7F,0xF8,0xFF,0xFF,0xFF,0xFF,0x01},
{0x80,0x7F,0xF8,0xFF,0xFF,0xFF,0xFF,0x01},
{0x80,0x7F,0xF8,0xFF,0xFF,0xFF,0xFF,0x01},
{0x80,0x7F,0xF8,0xFF,0xFF,0xFF,0xFF,0x01},
{0x80,0x7F,0xF8,0xFF,0xFF,0xFF,0xFF,0x01},
{0x80,0x7F,0xF8,0xFF,0xFF,0xFF,0xFF,0x01},
{0x80,0x7F,0xF8,0x07,0x00,0x00,0xFE,0x01},
{0x80,0x7F,0xF8,0x07,0x00,0x00,0xFE,0x01},
{0x80,0x7F,0xF8,0x07,0x00,0x00,0xFE,0x01},
{0x80,0x7F,0xF8,0x07,0x00,0x00,0xFE,0x01},
{0xC0,0x7F,0xF8,0xFF,0xFF,0xFF,0xFF,0x01},
{0xC0,0x7F,0xF8,0xFF,0xFF,0xFF,0xFF,0x01},
{0xC0,0x7F,0xF8,0xFF,0xFF,0xFF,0xFF,0x01},
{0xC0,0x7F,0xF8,0xFF,0xFF,0xFF,0xFF,0x01},
{0xC0,0x7F,0xF8,0xFF,0xFF,0xFF,0xFF,0x01},
{0xC0,0x7F,0xF8,0xFF,0xFF,0xFF,0xFF,0x01},
{0xC0,0x3F,0x00,0x00,0xFC,0x07,0x06,0x00},
{0xC0,0x3F,0x80,0x00,0xFC,0x07,0x07,0x00},
{0xC0,0x3F,0x80,0x03,0xFC,0x87,0x0F,0x00},
{0xE0,0x3F,0xC0,0x07,0xFC,0xE7,0x1F,0x00},
{0xE0,0x3F,0xE0,0x1F,0xFC,0xF7,0x3F,0x00},
{0xE0,0x3F,0xF0,0x3F,0xFC,0xE7,0x7F,0x00},
{0xE0,0x1F,0xF0,0x3F,0xFC,0xE7,0xFF,0x00},
{0xF0,0x1F,0xF8,0x1F,0xFC,0xC7,0xFF,0x00},
{0xF0,0x1F,0xFC,0x0F,0xFC,0x87,0xFF,0x01},
{0xF0,0x1F,0xFE,0x0F,0xFC,0x07,0xFF,0x03},
{0xF0,0x1F,0xFF,0x07,0xFC,0x07,0xFF,0x07},
{0xF8,0x8F,0xFF,0x03,0xFC,0x07,0xFE,0x0F},
{0xF8,0x8F,0xFF,0x01,0xFE,0x07,0xFC,0x0F},
{0xFC,0xCF,0xFF,0xFF,0xFF,0x07,0xF8,0x1F},
{0xFC,0xE7,0xFF,0xFE,0xFF,0x07,0xF8,0x0F},
{0xFE,0xC7,0x7F,0xFE,0xFF,0x03,0xF0,0x07},
{0xFE,0x83,0x3F,0xFC,0xFF,0x03,0xE0,0x03},
{0xF8,0x03,0x1F,0xFC,0xFF,0x03,0xE0,0x00},
{0xF0,0x03,0x0E,0xFC,0xFF,0x01,0x40,0x00},
{0xE0,0x01,0x04,0xFC,0xFF,0x00,0x00,0x00},
{0xC0,0x00,0x00,0xFC,0x3F,0x00,0x00,0x00},
{0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"原",2*/
};

static unsigned char ch_char4[86][8] = {
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0xC0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00},
{0xC0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00},
{0xC0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00},
{0xC0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00},
{0xC0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00},
{0xC0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00},
{0xC0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00},
{0xC0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00},
{0x00,0x00,0x00,0x00,0x00,0xFE,0xFF,0x00},
{0x00,0x00,0x00,0x00,0x00,0xFF,0x3F,0x00},
{0x00,0x00,0x00,0x00,0xC0,0xFF,0x1F,0x00},
{0x00,0x00,0x00,0x00,0xF0,0xFF,0x07,0x00},
{0x00,0x00,0x00,0x00,0xF8,0xFF,0x03,0x00},
{0x00,0x00,0x00,0x00,0xFE,0xFF,0x00,0x00},
{0x00,0x00,0x00,0x80,0xFF,0x7F,0x00,0x00},
{0x00,0x00,0x00,0xC0,0xFF,0x1F,0x00,0x00},
{0x00,0x00,0x00,0xF0,0xFF,0x07,0x00,0x00},
{0x00,0x00,0x00,0xF8,0xFF,0x03,0x00,0x00},
{0x00,0x00,0x00,0xF8,0xFF,0x00,0x00,0x00},
{0x00,0x00,0x00,0xF8,0x7F,0x00,0x00,0x00},
{0x00,0x00,0x00,0xF8,0x1F,0x00,0x00,0x00},
{0x00,0x00,0x00,0xF8,0x1F,0x00,0x00,0x00},
{0x00,0x00,0x00,0xF8,0x1F,0x00,0x00,0x00},
{0x00,0x00,0x00,0xF8,0x1F,0x00,0x00,0x00},
{0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x1F},
{0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x1F},
{0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x1F},
{0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x1F},
{0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x1F},
{0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x1F},
{0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x1F},
{0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x1F},
{0x00,0x00,0x00,0xF8,0x1F,0x00,0x00,0x00},
{0x00,0x00,0x00,0xF8,0x1F,0x00,0x00,0x00},
{0x00,0x00,0x00,0xF8,0x1F,0x00,0x00,0x00},
{0x00,0x00,0x00,0xF8,0x1F,0x00,0x00,0x00},
{0x00,0x00,0x00,0xF8,0x1F,0x00,0x00,0x00},
{0x00,0x00,0x00,0xF8,0x1F,0x00,0x00,0x00},
{0x00,0x00,0x00,0xF8,0x1F,0x00,0x00,0x00},
{0x00,0x00,0x00,0xF8,0x1F,0x00,0x00,0x00},
{0x00,0x00,0x00,0xF8,0x1F,0x00,0x00,0x00},
{0x00,0x00,0x00,0xF8,0x1F,0x00,0x00,0x00},
{0x00,0x00,0x00,0xF8,0x1F,0x00,0x00,0x00},
{0x00,0x00,0x00,0xF8,0x1F,0x00,0x00,0x00},
{0x00,0x00,0x00,0xF8,0x1F,0x00,0x00,0x00},
{0x00,0x00,0x00,0xF8,0x0F,0x00,0x00,0x00},
{0x00,0x00,0x00,0xFC,0x0F,0x00,0x00,0x00},
{0x00,0x10,0x00,0xFE,0x0F,0x00,0x00,0x00},
{0x00,0xF0,0xFF,0xFF,0x0F,0x00,0x00,0x00},
{0x00,0xF0,0xFF,0xFF,0x0F,0x00,0x00,0x00},
{0x00,0xE0,0xFF,0xFF,0x0F,0x00,0x00,0x00},
{0x00,0xE0,0xFF,0xFF,0x07,0x00,0x00,0x00},
{0x00,0xE0,0xFF,0xFF,0x07,0x00,0x00,0x00},
{0x00,0xE0,0xFF,0xFF,0x03,0x00,0x00,0x00},
{0x00,0xC0,0xFF,0xFF,0x01,0x00,0x00,0x00},
{0x00,0xC0,0xFF,0xFF,0x00,0x00,0x00,0x00},
{0x00,0xC0,0xFF,0x3F,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"子",3*/
};

#define argb8888_to_rgb565(color)   ({ \
            unsigned int temp = (color); \
            ((temp & 0xF80000UL) >> 8) | \
            ((temp & 0xFC00UL) >> 5) | \
            ((temp & 0xF8UL) >> 3); \
            })

/********************************************************************
 * 函数名称: lcd_draw_character
 * 功能描述: 在LCD屏指定位置处(x, y)画字符, 参数color指定字符的颜色
              指针ch指向字符对应的子模数组、参数w、h分别表示字符的宽度和高度
 * 输入参数: color
 * 返 回 值: 无
 ********************************************************************/
static void lcd_draw_character(unsigned int x, unsigned int y,
            const unsigned char *ch, unsigned int w,
            unsigned int h, unsigned int color)
{
    unsigned short rgb565_color = argb8888_to_rgb565(color);//得到RGB565颜色值
    unsigned long temp;
    unsigned int end_x, end_y;
    int j;
    int columns;

    /**
    计算出二维数组有多少列
    参数w表示的是字符的宽度,1个宽度表示的是1个bit位
    并不是一个字节,这里要注意,如果宽度不是byte单位的整数倍
    通常会补零
    **/
    columns = w / 8;    //1byte=8bit
    if (0 != w % 8) columns++;

    /* 对参数进行限定 */
    if (w < 1 || h < 1) return;
    if (x >= width || y >= height) return;

    /* 计算出结束坐标位置 */
    end_x = x + w - 1;
    end_y = y + h - 1;

    /* 对结束坐标位置进行限定 */
    if (end_x >= width)
        end_x = width - 1;
    if (end_y >= height)
        end_y = height - 1;

    /* 计算有效宽度 */
    h = end_y - y + 1;
    w = end_x - x + 1;

    /* 打点 */
    temp = y * width + x; //定位到起点
    for (y = 0; y < h; y++, temp += width) {

        for (x = 0, j = 0; x < w; ) { // 对字符的宽度进行循环

            // 判断当前位是否需要绘制,如果需要则将对应显存位置的像素设置为指定的颜色
            // *(ch + y * columns + j) 取得点阵图数据中对应位置的一个字节
            // x % 8 取得当前像素在字节中的位置(0到7)
            // 0x1 << (x % 8) 将1左移 (x % 8) 位,以便生成一个掩码,用于检测当前像素在字节中的位置
            // 通过按位与操作,检查当前字节的相应位是否为1。
            // 如果当前位为1,则表示在点阵图中该位置需要绘制,否则不绘制
            if (*(ch + y * columns + j) & (0x1 << (x % 8))) 
                screen_base[temp + x] = rgb565_color;
            x++;// 移动到下一个像素
            if (0 == x % 8) j++; // 每移动8个像素,j递增1,表示到下一个字节
        }
    }
}

int main(void)
{
    struct fb_var_screeninfo fb_var = {0};
    struct fb_fix_screeninfo fb_fix = {0};
    unsigned long screen_size;
    int fd;

    /* 打开framebuffer设备 */
    fd = open(FB_DEV, O_RDWR);
    if (0 > fd) {
        fprintf(stderr, "open error: %s: %s\n", FB_DEV, strerror(errno));
        exit(EXIT_FAILURE);
    }

    /* 获取framebuffer设备信息 */
    ioctl(fd, FBIOGET_VSCREENINFO, &fb_var);
    ioctl(fd, FBIOGET_FSCREENINFO, &fb_fix);

    screen_size = fb_fix.line_length * fb_var.yres;
    width = fb_var.xres;
    height = fb_var.yres;

    /* 内存映射 */
    screen_base = mmap(NULL, screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if (MAP_FAILED == (void *)screen_base) {
        perror("mmap error");
        close(fd);
        exit(EXIT_FAILURE);
    }

    /* LCD背景刷白 */
    memset(screen_base, 0xFF, screen_size);

    /* 显示字符 */
    int x = width * 0.5 - 128; // 计算字符“正”在LCD屏幕上的X坐标,将字符中心对齐到屏幕水平中心位置,并向左偏移128像素
    int y = height * 0.5 - 43; // 计算字符“正”在LCD屏幕上的Y坐标,将字符中心对齐到屏幕垂直中心位置,并向上偏移43像素
    lcd_draw_character(x, y, (unsigned char *)ch_char1, 64, 86, 0xFF00FF); // 画字符“正”
    lcd_draw_character(x + 64, y, (unsigned char *)ch_char2, 64, 86, 0xFF00FF);
    lcd_draw_character(x + 128, y, (unsigned char *)ch_char3, 64, 86, 0xFF00FF);
    lcd_draw_character(x + 192, y, (unsigned char *)ch_char4, 64, 86, 0xFF00FF);

    /* 退出程序 */
    munmap(screen_base, screen_size);
    close(fd);
    return 0;
}
  • 大致流程

    • 初始化并打开framebuffer设备

    • 获取设备的分辨率信息和显存地址

    • 清空屏幕,设置背景颜色

    • 在指定位置绘制字符

    • 清理资源并退出程序

  • 执行测试程序

操作系统字体文件

  • 字体文件存储字符的位图数据

  • 常见字体文件格式:otf、ttf、ttc等

    • Linux 系统中,字体文件通常会放在/usr/share/fonts 目录下,有了字体文件之后,我们就不需要再对字符
      进行取模了,它们已经编码进了字体文件中,我们只需要解析字体文件、访问字体文件,从字体文件中读取
      出字符的位图数据即可
  • 使用开源字体引擎(如freetype)解析字体文件,读取字符位图数据

freetype 简介

FreeType 是一个开源的字体引擎库

该库设计小巧、高效、高度可定制且可移植

提供了统一的接口来访问多种不同格式的字体文件

接口简单、易用,简化了访问字体文件内容的任务

FreeType 也称为 “FreeType 2”,区别于已弃用的 “FreeType 1”,FreeType 1 库已不再维护和支持

freetype 移植

下载 FreeType 源码

  • 下载链接 https://download.savannah.gnu.org/releases/freetype/

    • 选择 freetype-2.8.tar.gz 压缩文件

交叉编译 FreeType 源码

  • 在 tools 目录下创建一个名为 freetype 的目录,把它作为 FreeType 的安装目录

  • tar -xzf freetype-2.8.tar.gz

  • 关于FreeType库的一些特点和使用方法

    • FreeType库采用模块化设计,可以根据需要裁剪功能模块,以减小库文件的大小

    • FreeType库提供了多个配置选项,可以进行自定义配置或裁剪

    • 可以参考FreeType源码目录下的docs/CUSTOMIZE文档,详细了解如何进行配置和裁剪

    • 建议查看其他说明文档,如docs目录下的其他文档,以获取更多信息

    • 简单地配置一下

      • vi include/freetype/config/ftoption.h

      • 打开以下两个配置宏

        • #define FT_CONFIG_OPTION_SYSTEM_ZLIB
          #define FT_CONFIG_OPTION_USE_PNG
  • 对 FreeType 工程源码进行配置

    • ./configure --prefix=/home/alientek/tools/freetype/ --host=arm-poky-linux-gnueabi --with-zlib=yes --with-bzip2=no --with-png=yes --with-harfbuzz=no ZLIB_CFLAGS=“-I/home/alientek/tools/zlib/include -L/home/alientek/tools/zlib/lib” ZLIB_LIBS=-lz LIBPNG_CFLAGS=“-I/home/alientek/tools/png/include -L/home/alientek/tools/png/lib” LIBPNG_LIBS=-lpng

    • -prefix 选项指定 FreeType 库的安装目录

    • –host 选项设置为交叉编译器名称的前缀

    • –with-zlib=yes 表示使用 zlib

    • –with-bzip2=no 表示不使用 bzip2 库

    • ZLIB_CFLAGS 选项用于指定 zlib 的头文件路径和库文件路径,根据实际安装路径填写

    • ZLIB_LIBS 选项指定链接的 zlib 库的名称

    • LIBPNG_CFLAGS 选项用于指定 libpng 的头文件路径和库文件路径,根据实际安装路径填写

    • LIBPNG_LIBS 选项用于指定链接的 libpng 库的名称

  • make 编译

  • make install 安装

安装目录下的文件

  • 同样有 bin 目录、include 目录以及 lib 目录

  • 在应用程序源码中需要包含include/freetype2目录下的ft2build.h头文件,还需要包含一个名为FT_FREETYPE_H的宏定义头文件,实际上就是include/freetype2/freetype/freetype.h头文件

    • 在应用程序中通常会这样写:
      #include <ft2build.h>
      #include FT_FREETYPE_H

移植到开发板

  • 删除原有的 FreeType 库文件

    • m -rf /usr/lib/libfreetype.*
  • 编译得到的库文件拷贝到开发板/usr/lib 目录下

freetype 库的使用

资料

  • FreeType 官方

    • https://www.freetype.org/freetype2/docs/tutorial/step1.html
      https://www.freetype.org/freetype2/docs/tutorial/step2.html
      https://www.freetype.org/freetype2/docs/reference/index.html
  • 中文参考资料

    • https://www.doc88.com/p-7178359224563.html?r=1

基础概念

  • 字形(glyph):字符的不同书写风格,如宋体和微软雅黑的“国”

  • 字形索引:通过字符编码(如 ASCII、Unicode)转换得到

  • 像素点(pixel)、点(point)以及 dpi

    • 像素点:
      LCD 分辨率为 800*480 表示水平方向有 800 个像素点,垂直方向有 480 个像素点

    • “点”(point):
      点是物理单位,一个点等于 1/72 英寸(1 英寸等于 25.4 毫米)

    • dpi(dots per inch):
      dpi 表示每英寸的像素点数,如 300*400dpi 表示水平方向每英寸有 300 个像素点,垂直方向有 400 个像素点

    • 像素点数计算公式:

像素点数 = 点数 * dpi / 72。

	- 计算示例:

假设设备水平 dpi 为 300,点数为 50,则像素点数为 50 * 300 / 72 = 208

  • 字形布局

    • 用图描述,原点和基准线用于定位字形

    • 水平布局

    • 垂直布局

  • 基准线和原点

    • 水平布局和垂直布局都有一个原点(origin)

    • 水平线(X轴)和垂直线(Y轴)称为基准线

    • 水平布局:垂直基线在字形左边

    • 垂直布局:水平基线在字形上方

  • 字形的定位

    • 原点和基准线用于定位字形

    • 不同布局方式使用不同的约束来放置字形

  • 字形的宽度和高度

    • 每个字形有自己的宽度(width)和高度(height)

    • 不同字符的字形宽高可能不同

  • bearingX 和 bearingY

    • bearingX:从垂直基线到字形轮廓最左边的距离

    • bearingY:从水平基线到字形轮廓最上边的距离

  • xMin/xMax、yMin/yMax

    • xMin 和 xMax 表示字形轮廓的左右边界

    • yMin 和 yMax 表示字形轮廓的上下边界

    • 这些参数构成字形的边界框(bounding box)

  • advance

    • 表示步进宽度,即相邻两个原点位置的距离

    • 水平布局:advanceX

    • 垂直布局:advanceY

  • 字形的位图数据

    • FreeType 访问字体文件获取字形的位图数据

    • 位图数据存储在 buffer 中,每个点用一个字节表示

  • 字符显示的对齐

    • 字符显示时通过水平基线和垂直基线保证对齐

    • 不同字符的基线到轮廓的距离不同

    • 水平基线用于垂直方向对齐,垂直基线用于水平方向对齐

  • 绘制字符时的定位

    • 通过 bearingX 和 bearingY 确定字符显示的左上角位置

    • 例:原点 (100, 100),字符左上角位置为 (100+bearingX, 100-bearingY)

初始化 FreeType 库

  • 在使用 FreeType 库函数之前,必须进行初始化

  • FT_Init_FreeType() 函数

    • 定义一个 FT_Library 类型变量

    • 调用 FT_Init_FreeType() 函数并传递该变量的指针作为参数

  • 使用示例

    • FT_Library library;
      FT_Error error;
      error = FT_Init_FreeType(&library);
      if (error)
      fprintf(stderr, “Error: failed to initialize FreeType library object\n”);
  • FT_Init_FreeType() 的操作

    • 创建一个 FreeType 库对象

    • 返回值:成功返回 0,失败返回非零值错误码

加载 face 对象

  • 使用 FT_New_Face() 函数创建一个新的 face 对象,加载字体文件

    • 调用 FT_New_Face()函数前,我们需要定义一个 FT_Face 类型变量,使用示例如下所示:
      FT_Library library; //库对象的句柄
      FT_Face face; //face 对象的句柄
      FT_Error error;
      FT_Init_FreeType(&library);
      error = FT_New_Face(library, “/usr/share/fonts/font.ttf”, 0, &face);
      if (error) {
      /* 发生错误、进行相关处理 */
      }
  • face 对象的定义

    • face 描述了特定的字体样式和风格
  • FT_New_Face() 函数原型

    • FT_Error FT_New_Face(FT_Library library, const char *filepathname,
      FT_Long face_index, FT_Face *aface);

      • library:FreeType 库对象的句柄

      • filepathname:字库文件路径名

      • face_index:索引,指示要加载的 face,通常设置为 0

      • aface:指向新建 face 对象的指针,失败时值为 NULL

      • 返回值:
        调用成功返回 0。
        失败返回非零值错误码

设置字体大小

  • 设置字体的大小有两种方式:FT_Set_Char_Size()和 FT_Set_Pixel_Sizes()

  • FT_Set_Pixel_Sizes() 函数

    • 用于设置字体的宽度和高度,以像素为单位

    • 示例:
      FT_Set_Pixel_Sizes(face, 50, 50);

      • 第一个参数:face 句柄

      • 第二个参数和第三个参数:字体的宽度和高度,以像素为单位

    • 设置为 0 的参数

      • 可以将宽度或高度中的任意一个参数设置为 0

      • 设置为 0 的参数将等于另一个参数的值

      • FT_Set_Pixel_Sizes(face, 50, 0);

        • 字体高度设置为 0,意味着字体高度将等于字体宽度 50
  • FT_Set_Char_Size()函数

    • 用于设置字体大小

    • 示例:
      error = FT_Set_Char_Size(
      face, // face 对象的句柄
      1664, // 以 1/64 点为单位的字体宽度
      16
      64, // 以 1/64 点为单位的字体高度
      300, // 水平方向上每英寸的像素点数
      300 // 垂直方向上每英寸的像素点数
      );
      // 垂直方向上每英寸的像素点数
      );

      • 宽度和高度以 1/64 点为单位,一个点是 1/72 英寸

      • 宽度或高度可以设置为 0,表示该参数将等于另一个参数的值

      • dpi 参数设置为 0 时,表示使用默认值 72dpi

加载字形图像

示例代码

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <string.h>
#include <errno.h>
#include <sys/mman.h>
#include <linux/fb.h>
#include <math.h>       //数学库函数头文件

#include <wchar.h>
#include <ft2build.h>
#include FT_FREETYPE_H

#define FB_DEV      "/dev/fb0"      //LCD设备节点

#define argb8888_to_rgb565(color)   ({ \
            unsigned int temp = (color); \
            ((temp & 0xF80000UL) >> 8) | \
            ((temp & 0xFC00UL) >> 5) | \
            ((temp & 0xF8UL) >> 3); \
            })

static unsigned int width;                       //LCD宽度
static unsigned int height;                      //LCD高度
static unsigned short *screen_base = NULL;//LCD显存基地址 RGB565
static unsigned long screen_size;
static int fd = -1;

static FT_Library library;
static FT_Face face;

static int fb_dev_init(void)
{
    struct fb_var_screeninfo fb_var = {0};
    struct fb_fix_screeninfo fb_fix = {0};

    /* 打开framebuffer设备 */
    fd = open(FB_DEV, O_RDWR);
    if (0 > fd) {
        fprintf(stderr, "open error: %s: %s\n", FB_DEV, strerror(errno));
        return -1;
    }

    /* 获取framebuffer设备信息 */
    ioctl(fd, FBIOGET_VSCREENINFO, &fb_var);
    ioctl(fd, FBIOGET_FSCREENINFO, &fb_fix);

    screen_size = fb_fix.line_length * fb_var.yres;
    width = fb_var.xres;
    height = fb_var.yres;

    /* 内存映射 */
    screen_base = mmap(NULL, screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if (MAP_FAILED == (void *)screen_base) {
        perror("mmap error");
        close(fd);
        return -1;
    }

    /* LCD背景刷成黑色 */
    memset(screen_base, 0xFF, screen_size);
    return 0;
}

static int freetype_init(const char *font, int angle)
{
    FT_Error error; //存储FreeType库函数的返回值
    FT_Vector pen;  //表示绘制文本时的起点位置
    FT_Matrix matrix;//表示变换矩阵
    float rad;      //旋转角度

    /* FreeType初始化 */
    FT_Init_FreeType(&library);

    /* 加载face对象 */
    error = FT_New_Face(library, font, 0, &face);
    if (error) {
        fprintf(stderr, "FT_New_Face error: %d\n", error);
        exit(EXIT_FAILURE);
    }

    /* 原点坐标 */
    pen.x = 0 * 64;
    pen.y = 0 * 64;     //原点设置为(0, 0)

    /* 2x2矩阵初始化 */
    rad = (1.0 * angle / 180) * M_PI;   //(角度转换为弧度)M_PI是圆周率
#if 0       //非水平方向
    matrix.xx = (FT_Fixed)( cos(rad) * 0x10000L);
    matrix.xy = (FT_Fixed)(-sin(rad) * 0x10000L);
    matrix.yx = (FT_Fixed)( sin(rad) * 0x10000L);
    matrix.yy = (FT_Fixed)( cos(rad) * 0x10000L);
#endif

#if 1       //斜体  水平方向显示的
    matrix.xx = (FT_Fixed)( cos(rad) * 0x10000L);// 水平方向的缩放和旋转
    //变换矩阵的水平缩放和旋转分量。cos(rad) * 0x10000L 将弧度 rad 的余弦值放大 65536 倍(0x10000L 是 2^16),以便于定点数表示
    matrix.xy = (FT_Fixed)( sin(rad) * 0x10000L);// 水平和垂直方向的旋转
    matrix.yx = (FT_Fixed)( 0 * 0x10000L);       // 垂直方向的倾斜(这里为0,表示没有倾斜)
    matrix.yy = (FT_Fixed)( 1 * 0x10000L);       // 垂直方向的缩放
#endif

    /* 设置 */
    FT_Set_Transform(face, &matrix, &pen);
    //FT_Set_Transform:FreeType库中的一个函数,用于设置变换矩阵和原点
    //face:已经加载的字体面对象
    //&matrix:指向变换矩阵的指针。这个矩阵用于在渲染字符之前对其进行变换(例如旋转、缩放、斜切等)
    //&pen:指向原点位置的指针。这个原点位置用于设置文本的起始位置

    FT_Set_Pixel_Sizes(face, 50, 0);    //设置字体大小

    return 0;
}

static void lcd_draw_character(int x, int y,
            const wchar_t *str, unsigned int color)
{
    unsigned short rgb565_color = argb8888_to_rgb565(color);//得到RGB565颜色值
    FT_GlyphSlot slot = face->glyph;//将当前字体面对象的字形槽指针赋值给变量 slot
    size_t len = wcslen(str);   //计算字符的个数  wcslen 函数计算宽字符字符串的长度,即字符的个数,不包括终止的空字符(L'\0')
    long int temp;
    int n;
    int i, j, p, q;
    int max_x, max_y, start_y, start_x;

    // 循环加载各个字符
    for (n = 0; n < len; n++) {

        // 加载字形、转换得到位图数据

        //加载并准备渲染一个字符。它会将字符的字形数据加载到字形槽(glyph slot)中
        //FT_LOAD_RENDER: 这是一个标志,指定要渲染字符图像。它意味着不仅要加载字形数据,还要生成一个位图或矢量图形来表示这个字符
        //如果函数调用失败(即返回非零值)
        if (FT_Load_Char(face, str[n], FT_LOAD_RENDER))
            continue;

        start_y = y - slot->bitmap_top; //计算字形轮廓上边y坐标起点位置 注意是减去bitmap_top(字形位图顶部相对于基线的垂直距离)
        if (0 > start_y) {//如果为负数 如何处理??
            q = -start_y;//计算q为start_y的绝对值。这表示字形位图顶部在目标图像中的垂直偏移量
            temp = 0;
            j = 0;
        }
        else {      // 正数又该如何处理??
            q = 0;
            temp = width * start_y;
            j = start_y;
        }

        max_y = start_y + slot->bitmap.rows;//计算字形轮廓下边y坐标结束位置  slot->bitmap.rows 是字形位图的高度
        if (max_y > (int)height)
            max_y = height;

        for (; j < max_y; j++, q++, temp += width) {

            start_x = x + slot->bitmap_left;  //起点位置要加上左边空余部分长度
            if (0 > start_x) {
                p = -start_x;
                i = 0;
            }
            else {
                p = 0;
                i = start_x;
            }

            max_x = start_x + slot->bitmap.width;
            if (max_x > (int)width)
                max_x = width;

            for (; i < max_x; i++, p++) {

                // 如果数据不为0,则表示需要填充颜色
                if (slot->bitmap.buffer[q * slot->bitmap.width + p])
                    screen_base[temp + i] = rgb565_color;
            }
        }

        //调整到下一个字形的原点
        x += slot->advance.x / 64;  //26.6固定浮点格式
        y -= slot->advance.y / 64;
    }
}

int main(int argc, char *argv[])
{
    

    /* LCD初始化 */
    if (fb_dev_init())
        exit(EXIT_FAILURE);

    /* freetype初始化 */
    if (freetype_init(argv[1], atoi(argv[2])))
        exit(EXIT_FAILURE);

    /* 在LCD上显示中文 */
    int y = height * 0.25;
    lcd_draw_character(50, 100, L"路漫漫其修远兮,吾将上下而求索", 0x000000);
    lcd_draw_character(50, y+100, L"莫愁前路无知己,天下谁人不识君", 0x9900FF);
    lcd_draw_character(50, 2*y+100, L"君不见黄河之水天上来,奔流到海不复回", 0xFF0099);
    lcd_draw_character(50, 3*y+100, L"君不见高堂明镜悲白发,朝如青丝暮成雪", 0x9932CC);

    /* 退出程序 */
    FT_Done_Face(face);
    FT_Done_FreeType(library);
    munmap(screen_base, screen_size);
    close(fd);
    exit(EXIT_SUCCESS);
}

调用fb_dev_init函数初始化LCD设备,如果失败则退出程序

  • 定义局部变量fb_var和fb_fix,用于存储可变和固定的屏幕信息

  • 打开framebuffer设备/dev/fb0,获取文件描述符fd

    • 如果打开失败,打印错误信息并返回-1
  • 使用ioctl函数获取framebuffer设备的可变和固定信息

  • 计算screen_size、width和height

  • 使用mmap函数将framebuffer设备映射到内存

    • 如果映射失败,打印错误信息,关闭文件描述符并返回-1
  • 使用memset函数将LCD背景刷成黑色

  • 返回0表示初始化成功

调用freetype_init函数初始化FreeType库和加载字体文件,如果失败则退出程序

  • 定义局部变量error、pen、matrix和rad

  • 初始化FreeType库,创建library对象

  • 加载字体文件,创建face对象

    • 如果加载字体失败,打印错误信息并退出程序
  • 设置字符绘制的原点坐标(0, 0)

  • 计算旋转角度angle转换为弧度rad

  • 初始化变换矩阵matrix,包括水平和垂直方向的缩放和旋转

  • 使用FT_Set_Transform函数设置变换矩阵和原点位置

  • 使用FT_Set_Pixel_Sizes函数设置字体大小

  • 返回0表示初始化成功

计算要绘制字符的起始位置y

调用lcd_draw_character函数多次绘制不同的中文字符串到LCD上

  • 将ARGB8888颜色转换为RGB565颜色

  • 获取当前字体面对象的字形槽指针slot

  • 计算要绘制的字符串的长度

  • 循环处理每个字符

    • 加载并渲染字符到字形槽

    • 计算字符起始位置start_y。根据start_y是否为负数,进行不同的处理

    • 计算字符结束位置max_y。如果max_y超过LCD高度,将其限制在LCD高度范围内

    • 绘制字符

      • 计算每行的起始位置start_x。根据start_x是否为负数,进行不同的处理

      • 计算字符的宽度结束位置max_x。如果max_x超过LCD宽度,将其限制在LCD宽度范围内

      • 逐像素绘制字符位图到LCD显存,非零像素填充颜色

    • 更新下一个字符的绘制起点x和y

释放资源

  • 调用FT_Done_Face函数释放字体面对象

  • 调用FT_Done_FreeType函数释放FreeType库对象

  • 调用munmap函数解除内存映射

  • 关闭文件描述符fd

退出程序,返回成功状态

开发板验证

./testApp SIMSUN.TTC 50

  • SIMSUN.TTC为字库,需要给权限

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

木木不迷茫(˵¯͒¯͒˵)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值