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

前言:

前面我们已经把显示系统,输入系统的框架搭建好了,那么有了输入和显示,显示的内容应该是什么呢?这节就要让我们一起对显示的内容,文字系统进行搭建。

目录

一、数据结构抽象

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

2.描述一个字库操作:

3.font_manager.h

二、实现Freetype代码

freetype.c

 三、文字管理

font_manager.c

四、单元测试 

1.font_test.c 

2.disp_manager.c

3.disp_manager.h 

4. common.h

5.unittest下的Makefile

6.font下的Makefile

7.顶层的Makefile 

五、上板测试


 

一、数据结构抽象

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

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

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

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

Linux基础项目开发1:量产工具——文字系统(四)_第2张图片

2.描述一个字库操作:

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

Linux基础项目开发1:量产工具——文字系统(四)_第3张图片 

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

Linux基础项目开发1:量产工具——文字系统(四)_第4张图片Linux基础项目开发1:量产工具——文字系统(四)_第5张图片

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

3.font_manager.h

#ifndef _FONT_MANAGER_H
#define _FONT_MANAGER_H


#include 


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 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include 
#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行:描述一个文字的位图

Linux基础项目开发1:量产工具——文字系统(四)_第6张图片

void FreetypeRegister(void)

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

 三、文字管理

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

Linux基础项目开发1:量产工具——文字系统(四)_第7张图片

font_manager.c


#include 
#include 


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行:将找到的字体设置位图

四、单元测试 

Linux基础项目开发1:量产工具——文字系统(四)_第8张图片

1.font_test.c 

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#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<   \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)

Linux基础项目开发1:量产工具——文字系统(四)_第9张图片

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 
#include 


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

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

运行效果:

Linux基础项目开发1:量产工具——文字系统(四)_第10张图片

你可能感兴趣的:(Linux项目开发,linux,文字系统,文字管理,Linux应用开发,位图,字库操作,Freetype)