自学内容网 自学内容网

Linux基础项目开发day03:量产工具——文字系统

一、数据结构抽象

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

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

1、描述一个文字的位图结构体

在这里插入图片描述
这个Region结构体定义在disp_manager.h中有声明!

2、描述一个字库操作

在这里插入图片描述
使用点阵绘制文字时:每个文字的大小一样,前后文件互不影响 ,使用Freetype绘制文字时:大小可能不同,前面文字会影响后面文字
在这里插入图片描述
在这里插入图片描述
我们要抽象出一个结构体FontBitMap,能描述一个“字符”:位置、大小、位图,我们还要抽象出一个结构体FontOpr,能描述字体的操作,比如Freetype的操作、固定点阵字体的操作

3、font_manager.h

#ifndef _FONT_MANAGER_H
#define _FONT_MANAGER_H

//一些通用头文件,里面定义了一些结构体
#include <common.h>

typedef struct FontBitMap {
Region tRegion;
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

二、实现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

//储存FreeType库中的字体面(face)
static FT_Face g_tFace;
//默认字体大小
static int g_iDefaultFontSize = 12;

/* 初始化FreeType字体库 */
static int FreeTypeFontInit(char *aFineName)
{
    FT_Library    library;
    int error;

    //初始化FreeType库
    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_GlyphSlot slot = g_tFace->glyph;

    //设置当前光标位置,单位为1/64像素
    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,
};

//注册FreeType字体操作结构体
void FreetypeRegister(void)
{
RegisterFont(&g_tFreetypeOpr);
}


三、文字管理

我们可能要用到的字体有多种,那么怎么选择用哪个字符呢,所以我们要编写一个程序管理多种字符。
在这里插入图片描述
这里是去实现这几个管理函数:
在这里插入图片描述

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

//注册字体操作系统,这里显示注册了FreeType字体
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);
}



四、单元测试

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 <disp_manager.h>
#include <font_manager.h>

#define FONTDATAMAX 4096

//此处忽略了点阵数据
static const unsigned char fontdata_8x16[FONTDATAMAX] = {};




/**********************************************************************
 * 函数名称: lcd_put_ascii
 * 功能描述: 在LCD指定位置上显示一个8*16的字符
 * 输入参数: x坐标,y坐标,ascii码
 * 输出参数: 无
 * 返 回 值: 无
 * 修改日期        版本号     修改人      修改内容
 * -----------------------------------------------
 * 2020/05/12     V1.0  zh(angenao)      创建
 ***********************************************************************/ 
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= "www.100ask.net";
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])
{

tFontBitMap.iCurOriginX = lcd_x;
tFontBitMap.iCurOriginY = lcd_y;
/* get bitmap 获得字符位图*/
error = GetFontBitMap(str[i], &tFontBitMap);
if (error)
{
printf("SelectAndInitFont err\n");
return -1;
}

/* draw on buffer */
DrawFontBitMap(&tFontBitMap, 0xff0000);

/* flush to lcd/web */
FlushDisplayRegion(&tFontBitMap.tRegion, ptBuffer);


lcd_x = tFontBitMap.iNextOriginX;//移动光标,进行下一个字符的描绘
lcd_y = tFontBitMap.iNextOriginY;//移动光标,进行下一个字符的描绘
i++;
}

return 0;
}

2、font_test.c中的DrawFontBitMap函数

这个函数定义在disp_manager.c中,当然,也要在disp_manager.h中包含一下
在这里插入图片描述

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、common.h

因为在显示系统和文字系统中都用到了区域结构体,所以我们干脆就单独把它拿出来放在一个h头文件里面,名为一个公共头文件!



#ifndef _COMMON_H
#define _COMMON_H

#ifndef NULL
#define NULL (void *)0
#endif

typedef struct Region {
int iLeftUpX;  //区域左上角的X坐标
int iLeftUpY;  //区域左上角的Y坐标
int iWidth;    //区域宽度
int iHeigh;    //区域高度
}Region, *PRegion;

#endif

4、unittest下的Makefile

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

5、font下的Makefile

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

五、上板子测试

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

在这里插入图片描述


原文地址:https://blog.csdn.net/2302_80169672/article/details/142928382

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!