Linux基础项目开发1:量产工具——文字系统(四)

简介: Linux基础项目开发1:量产工具——文字系统(四)

一、数据结构抽象

描述字符的方式:1.位置、大小   2.点阵

       点阵可以从固定大小的点阵字体文件中获得,也可以从Freetype的矢量字体文件中获得,所以我们需要抽象出一个结构体用来描述这些字符,一个结构体描述一个文字的位图,一个结构体描述一个字库操作。

1.描述一个文字的位图:

2.描述一个字库操作:

       使用点阵绘制文字时:每个文字的大小一样,前后文件互不影响 ,使用Freetype绘制文字时:大小可能不同,前面文字会影响后面文字

对于单个Freetype字符,格式如下

        我们要抽象出一个结构体FontBitMap,能描述一个“字符”:位置、大小、位图,我们还要抽象出一个结构体FontOpr,能描述字体的操作,比如Freetype的操作、固定点阵字体的操作

3.font_manager.h

#ifndef _FONT_MANAGER_H
#define _FONT_MANAGER_H
 
 
#include <common.h>
 
 
typedef struct FontBitMap {
  int iLeftUpX;
  int iLeftUpY;
  int iWidth;
  int iRows;
  int iCurOriginX;
  int iCurOriginY;
  int iNextOriginX;
  int iNextOriginY;
  unsigned char *pucBuffer;
}FontBitMap, *PFontBitMap;
 
typedef struct FontOpr {
  char *name;
  int (*FontInit)(char *aFineName);
  int (*SetFontSize)(int iFontSize);
  int (*GetFontBitMap)(unsigned int dwCode, PFontBitMap ptFontBitMap);
  struct FontOpr *ptNext;
}FontOpr, *PFontOpr;
 
void RegisterFont(PFontOpr ptFontOpr);
 
void FontsRegister(void);
 
int SelectAndInitFont(char *aFontOprName, char *aFontFileName);
int SetFontSize(int iFontSize);
int GetFontBitMap(unsigned int dwCode, PFontBitMap ptFontBitMap);
 
 
#endif
 
 
 
 

第28行:链表

第30行:注册单个字符库 ,从链表里挑出想要的字库

第32行:在g_ptFonts链表里面挑出来你想要的字体文件

第33行:将找到的字体设置字体大小

第34行:将找到的字体设置位图

为了方便后续使用区域,我们进行如下操作,将区域定义到一个结构体上Region tRegion;

typedef struct FontBitMap {
  Region tRegion;
  int iCurOriginX;
  int iCurOriginY;
  int iNextOriginX;
  int iNextOriginY;
  unsigned char *pucBuffer;
}FontBitMap, *PFontBitMap;

这个 tRegiondisp manager.h中有声明

typedef struct Region {
  int iLeftUpX;
  int iLeftUpY;
  int iWidth;
  int iHeigh;
}Region, *PRegion;

二、实现Freetype代码

freetype.c

#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <linux/fb.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <wchar.h>
#include <sys/ioctl.h>
#include <font_manager.h>
 
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_GLYPH_H
 
 
static FT_Face g_tFace;
static int g_iDefaultFontSize = 12;
 
static int FreeTypeFontInit(char *aFineName)
{
    FT_Library    library;
    int error;
 
    error = FT_Init_FreeType( &library );                 /* initialize library */    
  if (error)
  {
    printf("FT_Init_FreeType err\n");
    return -1;
  }
  
    error = FT_New_Face(library, aFineName, 0, &g_tFace ); /* create face object */
  if (error)
  {
    printf("FT_New_Face err\n");
    return -1;
  }
 
    FT_Set_Pixel_Sizes(g_tFace, g_iDefaultFontSize, 0);
 
  return 0;
}
 
static int FreeTypeSetFontSize(int iFontSize)
{
    FT_Set_Pixel_Sizes(g_tFace, iFontSize, 0);
  return 0;
}
 
static int FreeTypeGetFontBitMap(unsigned int dwCode, PFontBitMap ptFontBitMap)
{
  int error;
    FT_Vector pen;
    FT_Glyph  glyph;
    
 
    pen.x = ptFontBitMap->iCurOriginX * 64; /* 单位: 1/64像素 */
    pen.y = ptFontBitMap->iCurOriginY * 64; /* 单位: 1/64像素 */
 
  /* 转换:transformation */
  FT_Set_Transform(g_tFace, 0, &pen);
 
  /* 加载位图: load glyph image into the slot (erase previous one) */
  error = FT_Load_Char(g_tFace, dwCode, FT_LOAD_RENDER);
  if (error)
  {
    printf("FT_Load_Char error\n");
    return -1;
  }
 
  ptFontBitMap->pucBuffer = slot->bitmap.buffer;
  
  ptFontBitMap->tRegion.iLeftUpX = slot->bitmap_left;
  ptFontBitMap->tRegion.iLeftUpY = ptFontBitMap->iCurOriginY*2 - slot->bitmap_top;
  ptFontBitMap->tRegion.iWidth   = slot->bitmap.width;
  ptFontBitMap->tRegion.iHeigh   = slot->bitmap.rows;
  ptFontBitMap->iNextOriginX = ptFontBitMap->iCurOriginX + slot->advance.x / 64;
  ptFontBitMap->iNextOriginY = ptFontBitMap->iCurOriginY;
 
  return 0;
}
 
 
static FontOpr g_tFreetypeOpr = {
  .name          = "freetype",
  .FontInit      = FreeTypeFontInit,
  .SetFontSize   = FreeTypeSetFontSize,
  .GetFontBitMap = FreeTypeGetFontBitMap,
};
 
void FreetypeRegister(void)
{
  RegisterFont(&g_tFreetypeOpr);
}
 
static FontOpr g_tFreetypeOpr

第86~91行:实现FontOpr这个结构体里面的函数

       第87行:之后可以通过freetype这个名字找到FontOpr这个结构体

       第88行:初始化函数

       第89行:自定义设置字符大小

       第90行:得到位图并且设置坐标值

第19行:对应字体文件

第20行:对应字体大小

static int FreeTypeFontInit(char *aFineName)

第22~44行:进行初始化

       第27行:初始化freetype库

       第34行:加载字体文件

       第41行:设置默认的字体大小

static int FreeTypeSetFontSize(int iFontSize)

第 46~50行:自定义设置字符大小

给一个字符的编码值如何得到它的位图呢?

static int FreeTypeGetFontBitMap(unsigned int dwCode, PFontBitMap ptFontBitMap)

第52~83行:得到位图并且设置坐标值

       第55行:pen用来反推原点

       第57行:记录点阵

       第59、60行:根据位图原点的X和Y坐标反推原点

       第63行:转换

       第66行:加载位图

       第73行:存放点阵

       第75~80行:描述一个文字的位图

void FreetypeRegister(void)

第93~96行: 进行注册,上层font_manager.c提供

三、文字管理

       我们可能要用到的字体有多种,那么怎么选择用哪个字符呢,所以我们要编写一个程序管理多种字符。

font_manager.c

 
#include <font_manager.h>
#include <string.h>
 
 
static PFontOpr g_ptFonts = NULL;
static PFontOpr g_ptDefaulFontOpr = NULL;
 
 
void RegisterFont(PFontOpr ptFontOpr)
{
  ptFontOpr->ptNext = g_ptFonts;
  g_ptFonts = ptFontOpr;
}
 
void FontsRegister(void)
{
  extern void FreetypeRegister(void);
  FreetypeRegister();
}
 
int SelectAndInitFont(char *aFontOprName, char *aFontFileName)
{
  PFontOpr ptTmp = g_ptFonts;
  while (ptTmp)
  {
    if (strcmp(ptTmp->name, aFontOprName) == 0)
      break;
    ptTmp = ptTmp->ptNext;
  }
 
  if (!ptTmp)
    return -1;
 
  g_ptDefaulFontOpr = ptTmp;
  return ptTmp->FontInit(aFontFileName);
}
 
int SetFontSize(int iFontSize)
{
  return g_ptDefaulFontOpr->SetFontSize(iFontSize);
}
 
int GetFontBitMap(unsigned int dwCode, PFontBitMap ptFontBitMap)
{
  return g_ptDefaulFontOpr->GetFontBitMap(dwCode, ptFontBitMap);
}
 
 

实现这四个函数

第6行: 注册的单个字库链表头放到g_ptFonts

第7行:将22~37行找到的字库名字保存在g_ptDefaulFontOpr

void RegisterFont(PFontOpr ptFontOpr)

第10~14行:实现与freetype.c链接的链表

void FontsRegister(void)

第16~20行:实现多个字体的注册

       第18行:调用底层代码提供一个注册函数,注册单个字库,从链表里挑出想要的字库

假设你有多个字库,你要选择某一个,要提供一个SelectAndInitFont字体文件

int SelectAndInitFont(char *aFontOprName, char *aFontFileName)

第22~37行:首先在g_ptFonts链表里面挑出来你想要的字体文件

       aFontOprName表示字库操作的名字,aFontFileName表示字体文件的名字

       第24行:在链表里面挑出来

       第27行:表示已经找到了

       第29行:没有找到,继续在链表里的下一个位置找

       第32行:表示不存在

       第35行:如果存在则调用初始化函数

int SetFontSize(int iFontSize)

第39~42行:将找到的字体设置字体大小

int GetFontBitMap(unsigned int dwCode, PFontBitMap ptFontBitMap)

第44~47行:将找到的字体设置位图

四、单元测试

1.font_test.c

#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <linux/fb.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <font_manager.h>
#include <disp_manager.h>
 
#define FONTDATAMAX 4096
 
static const unsigned char fontdata_8x16[FONTDATAMAX] = {
  //此处点阵省略
    .........
 
};
 
/**********************************************************************
 * 函数名称: lcd_put_ascii
 * 功能描述: 在LCD指定位置上显示一个8*16的字符
 * 输入参数: x坐标,y坐标,ascii码
 * 输出参数: 无
 * 返 回 值: 无
 ***********************************************************************/ 
void lcd_put_ascii(int x, int y, unsigned char c)
{
  unsigned char *dots = (unsigned char *)&fontdata_8x16[c*16];
  int i, b;
  unsigned char byte;
 
  for (i = 0; i < 16; i++)
  {
    byte = dots[i];
    for (b = 7; b >= 0; b--)
    {
      if (byte & (1<<b))
      {
        /* show */
        PutPixel(x+7-b, y+i, 0xffffff); /* 白 */
      }
      else
      {
        /* hide */
        PutPixel(x+7-b, y+i, 0); /* 黑 */
      }
    }
  }
}
 
int main(int argc, char **argv)
{
 
  PDispBuff ptBuffer;
  int error;
 
  FontBitMap tFontBitMap;
  char *str= "Hello Linux";
  int i = 0;
  int lcd_x;
  int lcd_y;
  int font_size;
    
 
  if (argc != 5)
  {
    printf("Usage: %s <font_file> <lcd_x> <lcd_y> <font_size>\n", argv[0]);
    return -1;
  }
 
  lcd_x = strtol(argv[2], NULL, 0);
  lcd_y = strtol(argv[3], NULL, 0);
  
  font_size  = strtol(argv[4], NULL, 0);
  
    
  DisplayInit();
 
  SelectDefaultDisplay("fb");
 
  InitDefaultDisplay();
 
  ptBuffer = GetDisplayBuffer();
 
  FontsRegister();
  
  error = SelectAndInitFont("freetype", argv[1]);
  if (error)
  {
    printf("SelectAndInitFont err\n");
    return -1;
  }
  
  SetFontSize(font_size);
 
  while (str[i])
  {
    /* get bitmap */
    tFontBitMap.iCurOriginX = lcd_x;
    tFontBitMap.iCurOriginY = lcd_y;
    error = GetFontBitMap(str[i], &tFontBitMap);
    if (error)
    {
      printf("SelectAndInitFont err\n");
      return -1;
    }
 
    /* draw on buffer */    
    DrawFontBitMap(&tFontBitMap,0xff0000);//0xff0000为红色
 
    /* flush to lcd/web */    
    FlushDisplayRegion(&tFontBitMap.tRegion, ptBuffer);
    
 
    lcd_x = tFontBitMap.iNextOriginX;
    lcd_y = tFontBitMap.iNextOriginY; 
    i++;
  }
  
  return 0; 
}
 
 

第60行:保存字符位图

第61行:想要显示的字符串

第68~72行:打印出具体用法    

                                    字体文件

                           显示的位置  

                                  字体的大小

第74、75行:将字符串转化成整数传入到lcd_xlcd_y

第77行:将字符串转化成整数传入到 font_size

第86行:获得显示的设备

第88行:FontsRegister()注册单个字符库 ,从链表里挑出想要的字库

第90行:SelectAndInitFont("freetype", argv[1])去选择freetype字库操作,传入argv[1]字体文件

第97行:SetFontSize设置字体大小

第102、103行:绘制图像的原点

第104行:GetFontBitMap得到字符位图

第112行:把位图绘制出来,绘制到默认设备中

第115行:绘制的内容刷到LCD或者web上

第118、119行:绘制完后取下一个位图的坐标

2.disp_manager.c

disp_manager.c中实现位图绘制

void DrawFontBitMap(PFontBitMap ptFontBitMap, unsigned int dwColor)

void DrawFontBitMap(PFontBitMap ptFontBitMap, unsigned int dwColor)
{
    int i, j, p, q;
  int x = ptFontBitMap->tRegion.iLeftUpX;
  int y = ptFontBitMap->tRegion.iLeftUpY;
    int x_max = x + ptFontBitMap->tRegion.iWidth;
    int y_max = y + ptFontBitMap->tRegion.iHeigh;
  int width = ptFontBitMap->tRegion.iWidth;
  unsigned char *buffer = ptFontBitMap->pucBuffer;
 
    //printf("x = %d, y = %d\n", x, y);
 
    for ( j = y, q = 0; j < y_max; j++, q++ )
    {
        for ( i = x, p = 0; i < x_max; i++, p++ )
        {
            if ( i < 0      || j < 0       ||
                i >= g_tDispBuff.iXres || j >= g_tDispBuff.iYres )
            continue;
 
            //image[j][i] |= bitmap->buffer[q * bitmap->width + p];
            if (buffer[q * width + p])
              PutPixel(i, j, dwColor);
        }
    }
  
}

3.disp_manager.h

声明函数DrawFontBitMap

void DrawFontBitMap(PFontBitMap ptFontBitMap, unsigned int dwColor);

头文件包含#include

#ifndef _DISP_MANAGER_H
#define _DISP_MANAGER_H
 
#include <common.h>
#include <font_manager.h>
 
 
typedef struct DispBuff {
  int iXres;
  int iYres;
  int iBpp;
  char *buff;
}DispBuff, *PDispBuff;
 
 
 
typedef struct DispOpr {
  char *name;
  int (*DeviceInit)(void);
  int (*DeviceExit)(void);
  int (*GetBuffer)(PDispBuff ptDispBuff);
  int (*FlushRegion)(PRegion ptRegion, PDispBuff ptDispBuff);
  struct DispOpr *ptNext;
}DispOpr, *PDispOpr;
 
void RegisterDisplay(PDispOpr ptDispOpr);
 
void DisplayInit(void);
int SelectDefaultDisplay(char *name);
int InitDefaultDisplay(void);
int PutPixel(int x, int y, unsigned int dwColor);
int FlushDisplayRegion(PRegion ptRegion, PDispBuff ptDispBuff);
PDispBuff GetDisplayBuffer(void);
void DrawFontBitMap(PFontBitMap ptFontBitMap, unsigned int dwColor);
 
 
#endif
 

4. common.h

       因为显示系统和文字系统都需要用到这个区域结构体,所以我们直接把它拿出来定义成一个公共的头文件

#ifndef _COMMON_H
#define _COMMON_H
 
#ifndef NULL
#define NULL (void *)0
#endif
 
typedef struct Region {
  int iLeftUpX;
  int iLeftUpY;
  int iWidth;
  int iHeigh;
}Region, *PRegion;
 
#endif
 

5.unittest下的Makefile

EXTRA_CFLAGS  := 
CFLAGS_file.o := 
 
#obj-y += disp_test.o
#obj-y += input_test.o
obj-y += font_test.o

6.font下的Makefile

EXTRA_CFLAGS  := 
CFLAGS_file.o := 
 
obj-y += font_manager.o
obj-y += freetype.o

7.顶层的Makefile

 
CROSS_COMPILE ?= 
AS    = $(CROSS_COMPILE)as
LD    = $(CROSS_COMPILE)ld
CC    = $(CROSS_COMPILE)gcc
CPP   = $(CC) -E
AR    = $(CROSS_COMPILE)ar
NM    = $(CROSS_COMPILE)nm
 
STRIP   = $(CROSS_COMPILE)strip
OBJCOPY   = $(CROSS_COMPILE)objcopy
OBJDUMP   = $(CROSS_COMPILE)objdump
 
export AS LD CC CPP AR NM
export STRIP OBJCOPY OBJDUMP
 
CFLAGS := -Wall -O2 -g
CFLAGS += -I $(shell pwd)/include
 
LDFLAGS := -lts -lpthread -lfreetype
 
export CFLAGS LDFLAGS
 
TOPDIR := $(shell pwd)
export TOPDIR
 
TARGET := test
 
 
obj-y += display/
obj-y += input/
obj-y += font/
obj-y += unittest/
 
all : start_recursive_build $(TARGET)
  @echo $(TARGET) has been built!
 
start_recursive_build:
  make -C ./ -f $(TOPDIR)/Makefile.build
 
$(TARGET) : built-in.o
  $(CC) -o $(TARGET) built-in.o $(LDFLAGS)
 
clean:
  rm -f $(shell find -name "*.o")
  rm -f $(TARGET)
 
distclean:
  rm -f $(shell find -name "*.o")
  rm -f $(shell find -name "*.d")
  rm -f $(TARGET)

第20行:链接库

LDFLAGS := -lts -lpthread -lfreetype

第30~33行:打开这四个文件夹进行make

obj-y += display/
obj-y += input/
obj-y += font/
obj-y += unittest/

五、上板测试

book@100ask:17_font_unittest_ok$ make
book@100ask:17_font_unittest_ok$ cp -r 17_font_unittest_ok/ ~/nfs_rootfs/
[root@100ask:~]#  mount -t nfs -o nolock,vers=3 192.168.5.11:/home/book/nfs_rootfs /mnt
[root@100ask:~]# cd /mnt/
[root@100ask:/mnt/17_font_unittest_ok]# ./test ./simsun.ttc 100 400 100

注意:编译时候要将字库文件一起上传上去

运行效果:


目录
相关文章
|
4月前
|
Ubuntu Linux Anolis
Linux系统禁用swap
本文介绍了在新版本Linux系统(如Ubuntu 20.04+、CentOS Stream、openEuler等)中禁用swap的两种方法。传统通过注释/etc/fstab中swap行的方式已失效,现需使用systemd管理swap.target服务或在/etc/fstab中添加noauto参数实现禁用。方法1通过屏蔽swap.target适用于新版系统,方法2通过修改fstab挂载选项更通用,兼容所有系统。
349 3
Linux系统禁用swap
|
4月前
|
安全 Linux Shell
四、Linux核心工具:Vim, 文件链接与SSH
要想在Linux世界里游刃有余,光会“走路”还不够,还得配上几样“高级装备”。首先是Vim编辑器,它像一把瑞士军刀,让你能在命令行里高效地修改文件。然后要懂“软硬链接”,软链接像个快捷方式,硬链接则是给文件起了个别名。最后,SSH是你的“传送门”,不仅能让你安全地远程登录服务器,还能用scp轻松传输文件,设置好密钥更能实现免-密登录,极大提升效率。
419 4
|
4月前
|
Linux
Linux系统修改网卡名为eth0、eth1
在Linux系统中,可通过修改GRUB配置和创建Udev规则或使用systemd链接文件,将网卡名改为`eth0`、`eth1`等传统命名方式,适用于多种发行版并支持多网卡配置。
690 3
|
Ubuntu Linux 网络安全
Linux系统初始化脚本
一款支持Rocky、CentOS、Ubuntu、Debian、openEuler等主流Linux发行版的系统初始化Shell脚本,涵盖网络配置、主机名设置、镜像源更换、安全加固等多项功能,适配单/双网卡环境,支持UEFI引导,提供多版本下载与持续更新。
457 0
Linux系统初始化脚本
|
4月前
|
Unix Linux 程序员
Linux文本搜索工具grep命令使用指南
以上就是对Linux环境下强大工具 `grep` 的基础到进阶功能介绍。它不仅能够执行简单文字查询任务还能够处理复杂文字处理任务,并且支持强大而灵活地正则表达规范来增加查询精度与效率。无论您是程序员、数据分析师还是系统管理员,在日常工作中熟练运用该命令都将极大提升您处理和分析数据效率。
357 16
|
4月前
|
安全 Linux iOS开发
SonarQube Server 2025 Release 5 (macOS, Linux, Windows) - 代码质量、安全与静态分析工具
SonarQube Server 2025 Release 5 (macOS, Linux, Windows) - 代码质量、安全与静态分析工具
239 0
SonarQube Server 2025 Release 5 (macOS, Linux, Windows) - 代码质量、安全与静态分析工具
|
4月前
|
安全 Linux Shell
Linux系统提权方式全面总结:从基础到高级攻防技术
本文全面总结Linux系统提权技术,涵盖权限体系、配置错误、漏洞利用、密码攻击等方法,帮助安全研究人员掌握攻防技术,提升系统防护能力。
397 1
|
缓存 Linux 测试技术
安装【银河麒麟V10】linux系统--并挂载镜像
安装【银河麒麟V10】linux系统--并挂载镜像
6672 0
|
关系型数据库 MySQL Linux
卸载、下载、安装mysql(Linux系统centos7)
卸载、下载、安装mysql(Linux系统centos7)
473 0
|
Linux
手把手教会你安装Linux系统
手把手教会你安装Linux系统
255 0