下载Freetype源码 ----- 下载FreeType
以移植到Keil 的STM32工程为例
移植前的软件环境:
1,实现了内存分配函数
2,实现了文件系统
3,使用了TR-Theard操作系统
4,实现了GUI界面,并支持点阵字体的显示
5,实现了Unicode,GBK,UTF8字符编码的相互转换
解压源码压缩包得到如下文件
复制以下文件到单片机工程下
如图
设置包含路径
添加以下文件到工程中
修改include\freetype\config\ftoption.h
注释掉
//#define FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES
在include\ft2build.h文件中添加如下代码
#ifndef FT2BUILD_H_
#define FT2BUILD_H_
#ifndef FT2_BUILD_LIBRARY
#define FT2_BUILD_LIBRARY
#endif
#include
#endif /* FT2BUILD_H_ */
现在应该能编译通过了,如果不能通过则根据提示修改
在单片机环境下一般都是自己实现内存分配函数和文件操作函数,所以需要修改内存和文件操作的函数接口
在工程中新建以下文件:
其中ftdebug.c提供调试输出路径,如不需要调试则可以编写以下代码
#include
#include FT_FREETYPE_H
#include FT_INTERNAL_DEBUG_H
FT_BASE_DEF( void )
ft_debug_init( void )
{
/* nothing */
}
FT_BASE_DEF( FT_Int )
FT_Trace_Get_Count( void )
{
return 0;
}
FT_BASE_DEF( const char * )
FT_Trace_Get_Name( FT_Int idx )
{
FT_UNUSED( idx );
return NULL;
}
FT_BASE_DEF( void )
FT_Trace_Disable( void )
{
/* nothing */
}
/* documentation is in ftdebug.h */
FT_BASE_DEF( void )
FT_Trace_Enable( void )
{
/* nothing */
}
ftfile.c和ftfile.h文件根据具体的文件系统修改,在本例中使用了fats文件系统管理SD卡中的文件和使用自定义的文件系统管理FLASH,在这里封装统一的操作接口
在ftfile.h中添加如下代码:
#ifndef FT_FILE_H__
#define FT_FILE_H__
typedef struct
{
u32 addr;
u32 ptr;
u32 size;
}ft_flash_file;
typedef struct
{
FILINFO file_info;
FIL file;
ft_flash_file flash;
}ft_file_struct;
//打开文件
ft_file_struct *ft_if_fopen (const char *filename,const char *mode);
//关闭文件
int ft_if_fclose (ft_file_struct *file);
//读取文件
//缓冲指针,缓冲元素大小,元素个数
unsigned int ft_if_fread (void *ptr,unsigned int size,unsigned int nmemb, ft_file_struct *file);
//文件偏移
int ft_if_fseek (ft_file_struct *file,long int offset,int whence);
//返回相对与文件开头的偏移
long int ft_if_ftell (ft_file_struct *file);
#endif
在ftfile.c中添加如下代码:
#include "stm32f4xx.h"
#include "ff.h"
#include "flash_manager.h"
#include "ftfile.h"
#include "mymem.h"
#include
#include "freetype/config/ftstdlib.h"
//int fclose(FILE * /*stream*/)
//FILE *fopen(const char * __restrict /*filename*/,
// const char * __restrict /*mode*/)
//size_t fread(void * __restrict /*ptr*/,
// size_t /*size*/, size_t /*nmemb*/, FILE * __restrict /*stream*/)
//int fseek(FILE * /*stream*/, long int /*offset*/, int /*whence*/)
//long int ftell(FILE * /*stream*/)
//打开文件
ft_file_struct *ft_if_fopen (const char *filename,const char *mode)
{
ft_file_struct *file=mycalloc (sizeof (ft_file_struct));
u8 ret=0;
if (filename[0]=='0'&&filename[1]==':')
{
ret=f_stat (filename,&file->file_info);
if (ret==FR_OK)
{
f_open(&file->file,filename,FA_READ);
}
else
{
myfree(file);
file=0;
}
}
else
{
if (file->flash.addr= FLASH_FindFile((char *)filename,&file->flash.size),file->flash.addr==0)
{
myfree(file);
file=0;
}
}
return file;
}
//关闭文件
int ft_if_fclose (ft_file_struct *file)
{
if (file)
{
if (file->flash.size==0)
f_close(&file->file);
return 0;
}
return -1;
}
//读取文件
//缓冲指针,缓冲元素大小,元素个数
unsigned int ft_if_fread (void *ptr,unsigned int size,unsigned int nmemb, ft_file_struct *file)
{
if (file)
{
if (file->flash.size==0)
{
UINT rb=0;
f_read (&file->file,ptr,size*nmemb,&rb);
return rb;
}
else
{
u32 read_size=size*nmemb;
if (read_size>file->flash.size-file->flash.ptr)
read_size=file->flash.size-file->flash.ptr;
FLASH_ReadData(ptr,file->flash.ptr+file->flash.addr,size*nmemb);
file->flash.ptr+=read_size;
return read_size;
}
}
return 0;
}
//文件偏移
int ft_if_fseek (ft_file_struct *file,long int offset,int whence)
{
if (file)
{
if (file->flash.size==0)
{
//文件开头
if (SEEK_SET==whence)
{
if (f_lseek(&file->file,offset)==FR_OK)
return 0;
}
else if (SEEK_END==whence)
{
//这时offset为负数
offset=file->file_info.fsize+offset;
if (f_lseek(&file->file,offset)==FR_OK)
return 0;
}
}
else
{
//文件开头
if (SEEK_SET==whence)
{
if (file->flash.size>offset)
{
file->flash.ptr=offset;
return 0;
}
}
else if (SEEK_END==whence)
{
if (file->flash.size+offset>0)
{
file->flash.ptr=file->flash.size+offset;
return 0;
}
}
}
}
return -1;
}
//返回相对与文件开头的偏移
long int ft_if_ftell (ft_file_struct *file)
{
if (file)
{
if (file->flash.size==0)
{
return f_tell(&file->file);
}
else
{
return file->flash.ptr;
}
}
return -1;
}
如果没有自己实现malloc函数,则需要把堆空间设置大一点,
修改include\freetype\config\ftstdlib.h 文件,如下:
//..........省略无关代码..........
/**************************************************************************
*
* file handling
*
*/
#include "stm32f4xx.h"
#include
#include "ff.h"
#include "ftfile.h"
//#define FT_FILE FILE
//#define ft_fclose fclose
//#define ft_fopen fopen
//#define ft_fread fread
//#define ft_fseek fseek
//#define ft_ftell ftell
//#define ft_sprintf sprintf
#define FT_FILE ft_file_struct
#define ft_fclose ft_if_fclose
#define ft_fopen ft_if_fopen
#define ft_fread ft_if_fread
#define ft_fseek ft_if_fseek
#define ft_ftell ft_if_ftell
#define ft_sprintf sprintf
//..........省略无关代码..........
/**************************************************************************
*
* memory allocation
*
*/
//这里把接口设置为自己实现的内存分配函数
#include "mymem.h"
#define ft_scalloc mycalloc
#define ft_sfree myfree
#define ft_smalloc mymalloc
#define ft_srealloc myrealloc
接下来应该可以编译通过了,如不能通过则根据提示修改
在GUI界面初始化函数中添加如下代码:
#include "ft2build.h"
#include FT_FREETYPE_H
static FT_Library g_ft_library=0;
static FT_Face g_ft_face=0;
void WIN_FontInit (void)
{
FT_Error ft_error=FT_Init_FreeType (&g_ft_library);
if (ft_error)
{
ft_error=0;
}
else
{
ft_error=FT_New_Face (g_ft_library,"simfang.ttf",0,&g_ft_face);
//ft_error=FT_New_Face (g_ft_library,"0:/SYS/simfang.ttf",0,&g_ft_face);
if (ft_error)
{
ft_error=0;
}
}
}
修改获取字符点阵数据的函数:
由于FreeType使用的是Unicode编码,而Keil编译的文件是GBK编码,需要把GBK转为Unicode编码
//根据字体类型获取中文字模数据
int WIN_GetWordData(u8 type,unsigned char *buff, int word, int buff_size)
{
u32 addr=WIN_FindWordAddr(type);
unsigned long foffset=0;
u8 qh=word>>8;u8 ql=word&0xff;
u8 gbk[3]={0};
gbk[0]=word>>8;
gbk[1]=word&0xff;
u8 uni[3]={0};
//转换为Unicode编码
if (word>0x80)
gbk2uni_str(gbk,uni);
else
uni[1]=word;
if (g_ft_face)
{
FT_Set_Pixel_Sizes(g_ft_face, type, type);
FT_Load_Char (g_ft_face,(uni[0]<<8)|uni[1],FT_LOAD_RENDER|FT_LOAD_MONOCHROME);
FT_GlyphSlot slot = g_ft_face->glyph;
int w_byte=slot->bitmap.pitch;
u8 *buf=slot->bitmap.buffer;
mymemcpy (buff,buf,buff_size-5);
buff[buff_size-5]=slot->bitmap.width;
buff[buff_size-4]=slot->bitmap.rows;
buff[buff_size-3]=slot->bitmap.pitch;
buff[buff_size-2]=slot->bitmap_left;
buff[buff_size-1]=slot->bitmap_top;
return slot->bitmap.width;
}
else
{
buff[buff_size-5]=0;
buff[buff_size-4]=0;
buff[buff_size-3]=0;
buff[buff_size-2]=0;
buff[buff_size-1]=0;
return type;
}
}
修改绘制字符函数:
//-------------------------绘制字体回调函数--------------------------------------
//通用的绘制英文字符
static u32 WIN_DrawCharAtCommon (char c,int x,int y)
{
u8 type=WIN_GetWinStruct()->font.TxtType;
u8 wid=type/2;
u8 hit=type;
u8 off_left=0;
u8 off_up=0;
u8 w_byte=type/2/8+1;
if (type/2%8) w_byte++;
u8 h_byte=type;
u32 all_byte= w_byte*h_byte+5;
u32 ret=0;
u8 *buff=0;
//获取字模
if (g_font==0) g_font=WIN_CreatFontBuff(40);
buff=WIN_GetFontData(g_font,type,c,&all_byte);
off_up=(type-buff[all_byte-1]);
off_left=buff[all_byte-2];
w_byte=buff[all_byte-3];
hit=buff[all_byte-4];
wid=buff[all_byte-5];
//显示字模
for (int j=0;j<hit+0;j++)
{
for (int i=0;i<wid+0;i++)
{
WIN_DrawPointSafe (x+i+off_left,y+j+off_up,(buff[j*w_byte+i/8]<<(i%8))&0x80);
}
}
ret=WIN_GetFontWidth()/2;
return ret;
}
//通用的绘制中文字符
static u32 WIN_DrawWordAtCommon (char *c,int x,int y)
{
u8 type=WIN_GetWinStruct()->font.TxtType;
u8 wid=type;
u8 hit=type;
u8 off_left=0;
u8 off_up=0;
u8 w_byte=type/8+1;
if (type%8) w_byte++;
u8 h_byte=type;
u32 all_byte= w_byte*h_byte+5;
u32 ret=0;
u8 *buff=0;
//获取字模
if (g_font==0) g_font=WIN_CreatFontBuff(40);
buff=WIN_GetFontData(g_font,type,(c[0]<<8)|c[1],&all_byte);
off_up=(type-buff[all_byte-1]);
off_left=buff[all_byte-2];
w_byte=buff[all_byte-3];
hit=buff[all_byte-4];
wid=buff[all_byte-5];
//显示字模
for (int j=0;j<hit+0;j++)
{
for (int i=0;i<wid+0;i++)
{
WIN_DrawPointSafe (x+i+off_left,y+j+off_up,(buff[j*w_byte+i/8]<<(i%8))&0x80);
}
}
ret=WIN_GetFontWidth();
return ret;
}
FreeType会占用较大的栈空间,如果栈设置太小容易造成栈溢出
本例设置20KB的栈空间可以保证正常运行
ALIGN(RT_ALIGN_SIZE)
static rt_uint8_t rt_gui_tack[20*1024]={0};
static struct rt_thread rt_gui_thread={0};
rt_thread_init (&rt_gui_thread,"gui_task",gui_task,0,rt_gui_tack,sizeof (rt_gui_tack),20,20);
rt_thread_startup(&rt_gui_thread);
由于每次显示字符都要重新栅格化会消耗大量时间,本例实现了字形缓冲池来缓冲使用过的字形,提高重绘速度:
//-------------------------字形缓冲区--------------------------------------
typedef struct
{
u8 type;
int word;
u32 data_size;
u8 *data;
} _font_data;
typedef struct
{
u32 buff_size; //总大小
u32 buff_used; //使用了多少
u32 buff_tail; //尾部
_font_data *font_data;
}WIN_FontBuffStruct;
//创建一个指定大小的字形缓冲区
WIN_FontBuffStruct *WIN_CreatFontBuff (u32 size)
{
WIN_FontBuffStruct *ret=mycalloc( sizeof (WIN_FontBuffStruct));
if (ret==0) return ret;
ret->font_data=mycalloc (sizeof(_font_data)*size);
if (ret->font_data==0)
{
myfree(ret);
ret=0;
return ret;
}
ret->buff_size=size;
return ret;
}
//删除一个字形缓冲区
void WIN_DeleteFontBuff (WIN_FontBuffStruct *font)
{
if (font)
{
for (int i=0;i<font->buff_used;i++)
{
_font_data *font_data=&font->font_data[i];
if (font_data->data) myfree(font_data->data);
}
myfree(font);
}
}
//添加字形数据
int WIN_AddFontData (WIN_FontBuffStruct *font,u8 type,int word,u8 *buff,u32 buff_size)
{
if (font)
{
_font_data *font_data=0;
if (font->buff_used<font->buff_size)
{
font_data=&font->font_data[font->buff_used];
font->buff_used++;
}
else
{
//缓冲区已满
font_data=&font->font_data[font->buff_tail];
myfree(font_data->data);
if (font->buff_tail<font->buff_size-1)
font->buff_tail++;
else
font->buff_tail=0;
}
font_data->type=type;
font_data->word=word;
font_data->data=buff;
font_data->data_size=buff_size;
}
return 0;
}
//搜索缓冲区中的字形数据
u8 *WIN_SearchFontData (WIN_FontBuffStruct *font,u8 type,int word,u32 *buff_size)
{
u8 *ret=0;
if (font)
{
for (int i=0;i<font->buff_used;i++)
{
_font_data *font_data=&font->font_data[i];
if (font_data->type==type)
{
if (font_data->word==word)
{
ret=font_data->data;
if (buff_size) *buff_size=font_data->data_size;
}
}
}
}
return ret;
}
//获取字形数据,缓冲区有就提取缓冲区的数据
//缓冲区中没有就调用获取字形函数
u8 *WIN_GetFontData (WIN_FontBuffStruct *font,u8 type,int word,u32 *buff_size)
{
u8 *buff=0;
buff=WIN_SearchFontData(font,type,word,buff_size);
if (buff==0)
{
buff=mymalloc(*buff_size);
WIN_GetWordData (type,buff,word,*buff_size);
WIN_AddFontData (font,type,word,buff,*buff_size);
}
return buff;
}
static WIN_FontBuffStruct *g_font;