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

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

运行效果:


目录
相关文章
|
6天前
|
Linux
在 Linux 系统中,“cd”命令用于切换当前工作目录
在 Linux 系统中,“cd”命令用于切换当前工作目录。本文详细介绍了“cd”命令的基本用法和常见技巧,包括使用“.”、“..”、“~”、绝对路径和相对路径,以及快速切换到上一次工作目录等。此外,还探讨了高级技巧,如使用通配符、结合其他命令、在脚本中使用,以及实际应用案例,帮助读者提高工作效率。
25 3
|
6天前
|
监控 安全 Linux
在 Linux 系统中,网络管理是重要任务。本文介绍了常用的网络命令及其适用场景
在 Linux 系统中,网络管理是重要任务。本文介绍了常用的网络命令及其适用场景,包括 ping(测试连通性)、traceroute(跟踪路由路径)、netstat(显示网络连接信息)、nmap(网络扫描)、ifconfig 和 ip(网络接口配置)。掌握这些命令有助于高效诊断和解决网络问题,保障网络稳定运行。
19 2
|
6天前
|
安全 网络协议 Linux
本文详细介绍了 Linux 系统中 ping 命令的使用方法和技巧,涵盖基本用法、高级用法、实际应用案例及注意事项。
本文详细介绍了 Linux 系统中 ping 命令的使用方法和技巧,涵盖基本用法、高级用法、实际应用案例及注意事项。通过掌握 ping 命令,读者可以轻松测试网络连通性、诊断网络问题并提升网络管理能力。
24 3
|
9天前
|
安全 Linux 数据安全/隐私保护
在 Linux 系统中,查找文件所有者是系统管理和安全审计的重要技能。
在 Linux 系统中,查找文件所有者是系统管理和安全审计的重要技能。本文介绍了使用 `ls -l` 和 `stat` 命令查找文件所有者的基本方法,以及通过文件路径、通配符和结合其他命令的高级技巧。还提供了实际案例分析和注意事项,帮助读者更好地掌握这一操作。
26 6
|
9天前
|
Linux
在 Linux 系统中,`find` 命令是一个强大的文件查找工具
在 Linux 系统中,`find` 命令是一个强大的文件查找工具。本文详细介绍了 `find` 命令的基本语法、常用选项和具体应用示例,帮助用户快速掌握如何根据文件名、类型、大小、修改时间等条件查找文件,并展示了如何结合逻辑运算符、正则表达式和排除特定目录等高级用法。
35 6
|
6月前
|
缓存 Linux 测试技术
安装【银河麒麟V10】linux系统--并挂载镜像
安装【银河麒麟V10】linux系统--并挂载镜像
1696 0
|
6月前
|
关系型数据库 MySQL Linux
卸载、下载、安装mysql(Linux系统centos7)
卸载、下载、安装mysql(Linux系统centos7)
232 0
|
1月前
|
Linux
手把手教会你安装Linux系统
手把手教会你安装Linux系统
|
2月前
|
Ubuntu Linux 网络安全
从头安装Arch Linux系统
本文记录了作者安装Arch Linux系统的过程,包括安装成果展示和遇到的疑难点及其解决方法,如硬盘不足、下载失败、设置时区、安装微码和配置无密码登录等。
从头安装Arch Linux系统
|
4月前
|
Linux 虚拟化 数据安全/隐私保护
部署05-VMwareWorkstation中安装CentOS7 Linux操作系统, VMware部署CentOS系统第一步,下载Linux系统,/不要忘, CentOS -7-x86_64-DVD
部署05-VMwareWorkstation中安装CentOS7 Linux操作系统, VMware部署CentOS系统第一步,下载Linux系统,/不要忘, CentOS -7-x86_64-DVD