本章主要内容如下:

  • 1)矢量字体原理
  • 2)使用freetype库实现矢量字体显示

1. 矢量字体原理

将汉字的笔划边缘用直线段描述成封闭的曲线,并将线段各端点的坐标经压缩存储,如下图所示:

由于每个汉字的笔划不一样,从而每个汉字数据长度也不同,所以只能采用索引的方法。因而每种矢量字库都是由两部分组成,一部分是汉字的索引信息,一部分是汉字的字形(glyph)数据.

当显示文字时,便提取出各端点,并通过贝塞尔曲线来连接各个坐标,最后填充封闭空间.

接下来便使用freetype库制作矢量字体

2. freetype-2.4.10库

freetype库是一个开源的字体引擎,支持多种字符集编码(utf-8等).

freetype库下载: https://sourceforge.net/projects/freetype/files/freetype2/2.4.10/

freetyoe英文参考文档下载:https://sourceforge.net/projects/freetype/files/freetype-docs/2.4.10/

FreeType 中文使用参考:

http://wenku.baidu.com/view/2d24be10cc7931b765ce155b.html

https://wenku.baidu.com/view/e7149f6748d7c1c708a14574.html

2.1如何来使用freetype

1)包含头文件:

#include <ft2build.h>
#include FT_FREETYPE_H

2) 初始化库:

使用FT_Init_FreeType()函数初始化一个FT_Library类型的变量,例如:

FT_LIBRARY library;                         //库的句柄

error = FT_Init_FreeType( &library );
if ( error )
{
//初始化失败
} ... ...

3)加载face对象:

通过FT_NEW_Face()打开一个字体文件,然后提取该文件的一个FT_Face类型的face变量,

例如:

FT_LIBRARY library;                         //库的句柄

FT_Face face;                        /* face对象的句柄 */

error = FT_Init_FreeType ( &library );
if ( error )
{... ...} ... ... error = FT_New_Face( library,
"/usr/share/fonts/truetype/arial.ttf", //字形文件
,
&face );

4)设置字体大小(参考freetype-2.4.10/docs/reference/ft2-base_interface.html):

方法1:

FT_Set_Char_Size( FT_Face     face,

                  FT_F26Dot6  char_width,  //字符宽度,单位为1/64点

                  FT_F26Dot6  char_height, //字符高度,单位为1/64点

                  FT_UInt     horz_resolution, //水平分辨率

                  FT_UInt     vert_resolution ); //垂直分辨率

字符宽度和高度以1/64点为单位表示。点是物理上的距离,一个点代表1/72英寸(2.54cm)

分辨率以dpi(dots per inch)为单位表示,表示一个英寸有多少个像素

例如:

error = FT_Set_Char_Size( face,  * , ,,  );    //0表示与另一个尺寸值相等。 

得出:

字符物理大小为: 50*64* (1/64) * (1/72)英寸

字符的像素为: 50*64* (1/64) * (1/72)*100

方法2:

FT_Set_Pixel_Sizes(   FT_Face  face,
FT_UInt pixel_width, //像素宽度
FT_UInt pixel_height ); //像素高低

例如:

error = FT_Set_Pixel_Sizes( face, ,);      //把字符像素设置为16*16像素, 0表示与另一个尺寸值相等。

5)设置字体位置,以及旋转度数(不设置的话表示原点位于0,0):

error = FT_Set_Transform(

face, /* 目标face对象 */

&matrix, /* 指向2x2矩阵的指针,写0表示不旋转,使用正矩形 */

&delta ); /*字体坐标位置(用的笛卡尔坐标),以1/64像素为单位表示,写0表示原点是(0,0) */

由于我们LCD的坐标原点是位于左上方

笛卡尔坐标:表示坐标原点位于左下方(与LCD的y轴相反)

所以转换之前填写坐标时,需要转换一下y轴值(总高度-y)

转换成功后还需要转换回来(总高度-y)

比如,旋转25,并在(300,200)处显示:

FT_Vector     pen;                    /*   */
FT_Matrix matrix; /* transformation matrix */ angle = ( 25.0 / ) * 3.14159 * ; /* use 25 degrees */ /*将该文字坐标转为笛卡尔坐标*/
pen.x = * ;
pen.y = ( target_height - ) * ; // target_height: LCD总高度 //设置 矩形参数
matrix.xx = (FT_Fixed)( cos( angle ) * 0x10000L );
matrix.xy = (FT_Fixed)(-sin( angle ) * 0x10000L );
matrix.yx = (FT_Fixed)( sin( angle ) * 0x10000L );
matrix.yy = (FT_Fixed)( cos( angle ) * 0x10000L ); FT_Set_Transform( face, &matrix, &pen );

6)加载字形图像

a.获取编码的索引

通过FT_Get_Char_Inde()函数将字符编码转换为一个字形(glyph)索引   (Freetype默认是utf-16编码类型)

例如:

glyph_index = FT_Get_Char_Index( face, charcode );        

若glyph_index为NULL,表示没找到字形(glyph)索引

如果使用其它字符编码,则通过FT_Select_Charmap()来获取,例如获取big5编码:

error = FT_Select_Charmap(
face, /* 目标face对象 */
FT_ENCODING_BIG5 ); /* big5编码 */ //FT_ENCODING_BIG5枚举定义在FT_FREETYPE_H中
//FT_ENCODING_GB2312 :GB2312编码
//该函数头文件位于:FT_FREETYPE_H (freetype/freetype.h).

b.通过索引,从face中加载字形

获得字形索引后,接下来便根据字形索引,来将字形图像存储到字形槽(glyph slot)中.

字形槽:每次只能存储一个字形图像,每个face对象都有一个字形槽,位于face->glyph

通过FT_Load_Glyph()来加载一个字形图像到字形槽:

error = FT_Load_Glyph(

face, /* face对象的句柄 */

glyph_index, /* 字形索引 */

load_flags ); /* 装载标志,一般填FT_LOAD_DEFAULT*/

并更新face->glyph下的其它成员,比如:

    FT_Int            bitmap_left;            //该字形图像的最左边的X值
FT_Int bitmap_top; //该字形图像的最上边的Y值

c.转为位图

通过FT_Render_Glyph()函数,将字形槽的字形图像转为位图,并存到 face->glyph->bitmap->buffer[]里

error = FT_Render_Glyph( face->glyph, /* 字形槽 */

render_mode ); /* 渲染模式 */

render_mode标志可以设为以下几种:

FT_RENDER_MODE_NORMAL:表示生成位图每个像素是RGB888的

FT_RENDER_MODE_MONO :表示生成位图每个像素是1位的(黑白图)

并更新face->glyph->bitmap下的其它成员,比如:

int             rows;         //该位图总高度,有多少行
int width; //该位图总宽度,有多少列像素点
int pitch: //指一行的数据跨度(字节数),比如对于24位(3字节)的24*30汉字,则pitch=24*3 char pixel_mode //像素模式,1 指单色的,8 表示反走样灰度值 unsigned char* buffer //glyph 的点阵位图内存绶冲区

d.也可以直接使用FT_Load_Char()代替FT_Get_Char_Index()、FT_Get_Load_Glyph()和FT_Render_Glyph().

例如:

error = FT_Load_Char( face, charcode, FT_LOAD_RENDER );

其中FT_LOAD_RENDER:表示直接将图像转为位图,所以不需要使用FT_Render_Glyph()函数

该函数默认生成的位图是默认生成的FT_RENDER_MODE_NORMAL类型,RGB888的

若想生成FT_RENDER_MODE_MONO(黑白图)类型,操作如下:

error = FT_Load_Char( face, charcode, FT_LOAD_RENDER | FT_LOAD_MONOCHROME );

生成出来的位图像素,每8个像素点便表示 face->glyph->bitmap->buffer[]里的一个字节.

2.2参考example1.c例程

example1.c位于freetype-doc-2.4.10.tar.bz2\freetype-2.4.10\docs\tutorial下

3.在PC虚拟机里编译例程:example1.c

3.1安装freetype到/usr/local/里(拿给PC用)

tar -xjf freetype-2.4..tar.bz2

mv freetype-2.4.   freetype-2.4.10_pc

cd freetype-2.4.10_pc/

./configure                                 //配置

make                                        //编译

sudo make install                           //直接将库安装到根目录/usr/local/里,所以需要加sudo

由于example1.c的打印范围是640*480,而我们secureCRT没有那么大,所以修改example1.c.

将:

#define WIDTH   640
#define HEIGHT 480

改为:

#define WIDTH   80
#define HEIGHT 80

然后将119行处的文字显示坐标:

  pen.x =  * ;
pen.y = ( target_height - ) * ;

改为:

  pen.x =  * ;                                //在坐标(0,40)处显示
pen.y = ( target_height - ) * ;

3.2 编译运行

gcc -o example1 example1.c

编译出错:

通过ls,发现又有这个文件:

所以通过-I,直接指定头文件目录:

gcc -o example1 example1.c  -I /usr/local/include/freetype2/

编译再次出错:

发现这些出错的都是函数,其中FT开头的是freetype库的函数,cos等都是数学库的函数,

freetype库的文件名是 libfreetype.so

数学库的文件名是libm.so

所以编译时,加上-l,指定库文件:

gcc -o example1 example1.c  -I /usr/local/include/freetype2/   -lfreetype  -lm

3.3 运行example1

将C:\Windows\Fonts下的simsun.ttc(宋体)字体文件拷到虚拟机里,输入./example1   simsun.ttc  agf,发现是斜的:

这是因为example1.c里通过FT_Set_Transform()设置了字体旋转

3.4 继续修改example1.c

关闭字体旋转,将

FT_Set_Transform( face, &matrix, &pen );

改为

FT_Set_Transform( face, , &pen );

修改字体大小,将

error = FT_Set_Char_Size( face,  * , , ,  );

改为:

error = FT_Set_Pixel_Sizes( face, ,  );             //24*24像素

编译运行:

3.5 显示汉字

如果用char存储汉字英文等,则还需要判断数据类型,而wchar_t刚好可以放一个unicode字符。

注意:wchar_t在windows占2byte,在linux4bytes.

宽字符:wchar_t

头文件: #include<wchar.h>

通过wcslen()判断wchar_t数组大小

修改example1.c

...
#include<wchar.h> //添加此行 ...
int main( int argc,char** argv )
{
... ...
wchar_t *chinese_str=L"韦东山g"; //添加此行 ... ...
for ( n = ; n <wcslen(chinese_str); n++ ) //修改此行
{
FT_Set_Transform( face, , &pen ); //字体转换 /* load glyph image into the slot (erase previous one) */
error = FT_Load_Char( face, chinese_str[n], FT_LOAD_RENDER ); //修改此行
... ... }
return ;
}

通过另存为文件,来看看文件本身是什么编码格式

如下图所示,看到是ANSI编码, 对于中文PC,ANSI编码对应的是GBK编码:

linux默认是utf-8编码,所以编译时,需要指定字符集:

gcc -o example1 example1.c  -I /usr/local/include/freetype2/   -lfreetype  -lm -finput-charset=GBK  -fexec-charset=utf-
// -finput-charset:告诉编译器,文件里的字符是GBK格式
//-fexec-charset:告诉编译器,需要先将里面的内容转换为utf-8格式后,再来编译

运行代码:

添加坐标打印信息:

发现,我们打印坐标是在(40,0),为什么文字坐标还会超过原点?,参考以下图所示:

advance: 位于face->glyph-> advance,用来存放每个文字之间的间隔信息,每当加载一个新的图像时,系统便会更新该数据.

3.6 获取位图文字的信息

当我们每次将新的字形图像(face->glyph)转为位图后,而存放的前一个字形图像就会被删除.

当有时候,有可能需要提取字形图像的坐标,该怎么做?

1)首先添加头文件:

#include FT_GLYPH_H

2)通过FT_Get_Glyph()将一个字形图像(face->glyph)存到FT_Glyph类型的变量里,例如:

FT_Glyph  glyph;    /* a handle to the glyph image */
... error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NORMAL );
//通过字符编码,获取字形图像存到face->glyph里,并转为位图存到face->glyph->bitmap->buffer[]里 if ( error ) { ... } error = FT_Get_Glyph( face->glyph, &glyph ); //将字形图像(face->glyph)存到glyph里
if ( error ) { ... }

3) 通过FT_Glyph_Get_CBox()获取文字的xMin, xMax, yMin, yMax坐标信息

参考: /freetype-2.4.10/docs/reference/ft2-index.html

FT_Glyph_Get_CBox( FT_Glyph  glyph,                 //该值通过FT_Get_Glyph()来获取
FT_UInt bbox_mode, //模式,填入FT_GLYPH_BBOX_TRUNCATE即可
FT_BBox *acbox ); //用来存放获取到的xMin, xMax, yMin, yMax信息

其中FT_GLYPH_BBOX_TRUNCATE表示:获取的坐标信息是像素坐标,而不是点坐标

修改example1.c,使它能打印每个汉字的坐标信息:

#include FT_GLYPH_H      //添加此行
... ... int main( int argc, char** argv )
{
FT_Glyph glyph;
FT_BBox acbox;
... ... for ( n = ; n < wcslen(chinese_str); n++ )
{
... ... error = FT_Load_Char( face,chinese_str[n], FT_LOAD_RENDER );
if ( error )
continue; /* ignore errors */ error = FT_Get_Glyph( face->glyph, &glyph ); //添加此行
FT_Glyph_Get_CBox( glyph,FT_GLYPH_BBOX_TRUNCATE,&acbox ); //添加此行
printf("0x%x:xMin=%ld,xMax=%ld,yMin=%ld,yMax=%ld\n",chinese_str[n],acbox.xMin,acbox.xMax,acbox.yMin,acbox.yMax); //添加此行 ... ...

编译运行:

表示韦字(97e6)的笛卡尔坐标 :  X坐标在0~23,y坐标在37~60,是个24*24字体.

由于笛卡尔坐标的原点坐标位于左下方.

所以对应韦字(97e6)的LCD坐标: X坐标在0~23 ,y坐标为20~43

4.在LCD上显示矢量文字

安装freetype到交叉编译目录里(供arm-linux-gcc编译)

4.1首先查看,需要安装到哪个lib和include目录

1)通过$PATH找到arm-linu-gcc交叉编译位于:

/work/tools/arm-linux-gcc-4.3./usr/local/arm/4.3./bin

然后进入.../arm/4.3.2/目录,通过find查找stdio.h文件,找到:

所以编译出来的头文件应该放入:

/work/tools/arm-linux-gcc-4.3.2/usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/usr/include

2)通过find查找lib,找到:

由于ARM9属于ARMv4T架构,所以编译出来的库文件应该放入:

/work/tools/arm-linux-gcc-4.3.2/usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/armv4t/lib

4.2安装

参考:freetype-2.4.10/docs/INSTALL.CROSS

tar -xjf freetype-2.4..tar.bz2
mv freetype-2.4. freetype-2.4.10_arm
cd freetype-2.4.10_arm
mkdir tmp //创建安装的临时目录,后面会拷贝到交叉编译目录里
./configure --host=arm-linux --prefix=$PWD/tmp //配置交叉编译,安装前缀
make
make install cd tmp/ cp ./include/* /work/tools/arm-linux-gcc-4.3./usr/local/arm/4.3./arm-none-linux-gnueabi/libc/usr/include/ -rfd
//将include下的头文件拷贝到交叉编译里去 cp lib/* /work/tools/arm-linux-gcc-4.3./usr/local/arm/4.3./arm-none-linux-gnueabi/libc/armv4t/lib/ -rfd
//将lib下的库文件拷贝到交叉编译里去 cp lib/ * /work/nfs_root/.4_fs_mini_mdev/lib/ -rfd
//将lib下的库文件拷贝到nfs文件系统去

为什么不拷贝头文件? 因为编译好了freetype程序后,头文件会被gcc展开存到可执行文件里,所以运行时,只会用到库文件.

4.3写代码(参考上章代码和example1.c)

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <string.h>
#include <linux/fb.h>
#include <math.h>
#include<wchar.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_GLYPH_H unsigned char *fbmem;
unsigned char *hzkmem; struct fb_var_screeninfo fb_var;
struct fb_fix_screeninfo fb_fix; unsigned int screensize;
#define FONTDATAMAX 4096 static const unsigned char fontdata_8x16[FONTDATAMAX] = {
//ASCII码点阵太长,省略...
};
/*rgb565*/
void pixel_show(int x,int y, unsigned int color)
{
unsigned int red,green,blue;
switch(fb_var.bits_per_pixel) //rgb 像素
{
case :
{
unsigned int *addr=(unsigned int *)fbmem+(fb_var.xres*y+x);
*addr=color;
break;
}
case :
{
unsigned int *addr=(unsigned int *)fbmem+(fb_var.xres*y+x);
*addr=color;
break;
}
case : //将RGB888 转为RGB565
{
unsigned short *addr=(unsigned short *)fbmem+(fb_var.xres*y+x);
red = (color >> ) & 0xff;
green = (color >> ) & 0xff;
blue = (color >> ) & 0xff;
color = ((red >> ) << ) | ((green >> ) << ) | (blue >> );
*addr = color;
break;
}
case :
{
unsigned char *addr=(unsigned char *)fbmem+(fb_var.xres*y+x);
*addr = (unsigned char)color;
break;
} default:
{
printf("can't surport %dbpp \n",fb_var.bits_per_pixel);
break;
}
}
} /*显示ascii码*/
void lcd_put_char(int x,int y, unsigned char s)
{
unsigned char *index=(unsigned char *)&fontdata_8x16[s*];
unsigned char i,j;
for(i=;i<;i++) //8*16
for(j=;j<;j++)
{
//从高位到低
if(index[i]&(<<(-j))) //亮
pixel_show(x+j,y+i, 0xffffff); //白色
else //灭
pixel_show(x+j,y+i, 0x0); //黑色
}
} /*显示GBK码*/
void lcd_put_chinese(int x,int y, unsigned char *s)
{
unsigned char i,j,k;
//将编码转为区码
unsigned int index=(s[]-0xA1)*+(s[]-0xA1); //转为点阵码(每个汉字32字节)
unsigned char *dots=hzkmem+index*; for(i=;i<;i++) //16*16
for(k=;k<;k++)
for(j=;j<;j++)
{
if((dots[i*+k]>>(-j))&0X01) //亮
pixel_show(x+*k+j,y+i, 0xffffff); //白色 else //灭
pixel_show(x+*k+j,y+i, 0x0); //黑色
}
} void lcd_put(int x,int y, unsigned char *s)
{
while(*s)
{
if(*s<0xA1) //ASCII码8*16
{
printf("ASCII %x \r\n",*s );
lcd_put_char(x,y,*s);
s+=;
x+=;
}
else //GB2313 16*16
{
printf("GBK %x %x\r\n",*s, *(s+));
lcd_put_chinese(x,y,s);
s+=;
x+=;
}
}
} void draw_bitmap( FT_Bitmap* bitmap,
FT_Int x,
FT_Int y)
{
FT_Int i, j, p, q;
FT_Int x_max = x + bitmap->width; //x:当前X位置, bitmap->width:该字宽度
FT_Int y_max = y + bitmap->rows; for ( i = x, p = ; i < x_max; i++, p++ ) //i:lcd的x轴
{
for ( j = y, q = ; j < y_max; j++, q++ ) //j:lcd的y轴
{
if ( i < || j < ||
i >= fb_var.xres || j >= fb_var.yres )
continue;
pixel_show( i, j, bitmap->buffer[q * bitmap->width + p]);
}
}
} void lcd_vector_show(char *argv,wchar_t *str)
{
FT_Library library;
FT_Face face;
FT_GlyphSlot slot;
FT_Vector pen; /* untransformed origin */
unsigned char error;
unsigned char n,font_size;
error = FT_Init_FreeType( &library ); /* initialize library */
if(error)
{
printf("FT_Init_FreeType ERROR\n");
return ;
} error = FT_New_Face( library, argv, , &face ); /* create face object */
if(error)
{
printf("FT_New_Face ERROR\n");
return ;
} slot = face->glyph; /*显示坐标(从LCD中间显示)
*x=fb_var.xres /2
*y=fb_var.yres-fb_var.yres/2-16 (减16,是因为笛卡尔坐标以左下方开始计算坐标值的)
*/
pen.x = fb_var.xres /* ;
pen.y = ( fb_var.yres/-) * ; for ( n = ; n < wcslen(str); n++ )
{
font_size=(n%)*+; // 20*20 24*24 28*28 32*32 36*36 40*40 error = FT_Set_Pixel_Sizes( face, ,font_size); /* set character size */ FT_Set_Transform( face, , &pen ); error = FT_Load_Char( face,str[n], FT_LOAD_RENDER );
if ( error )
{
printf("FT_Load_Char ERROR\n");
continue;
} draw_bitmap( &slot->bitmap,
slot->bitmap_left,
fb_var.yres- slot->bitmap_top ); pen.x += slot->advance.x;
pen.y += slot->advance.y;
}
FT_Done_Face( face );
FT_Done_FreeType( library );
} int main(int argc,char **argv)
{
int fd_fb,fd_hzk;
struct stat hzk_start; //HZK16文件信息 unsigned char s[]="abc 中国chinese";
wchar_t *chinese_str=L"韦东山g h "; if ( argc != )
{
printf ("usage: %s font_file \n", argv[] );
return ;
} fd_hzk=open("HZK16",O_RDONLY);
if(fd_hzk<)
{
printf("can't open HZK16 \n");
return ;
} if(fstat(fd_hzk,&hzk_start)<) //获取HZK16文件信息
{
printf("can't get fstart \n");
return ;
} hzkmem =(unsigned char *)mmap(NULL,hzk_start.st_size, PROT_READ,MAP_SHARED,
fd_hzk, ); //映射HZK16文件
if(!hzkmem)
{
printf("can't map HZK16 \n");
return ;
} fd_fb=open("/dev/fb0", O_RDWR);
if(fd_fb<)
{
printf("can't open /dev/fb0 \n");
return ;
} if(ioctl(fd_fb,FBIOGET_VSCREENINFO,&fb_var)<)
{
printf("can't get var \n");
return ;
} if(ioctl(fd_fb,FBIOGET_FSCREENINFO,&fb_fix)<)
{
printf("can't get fix \n");
return ;
} screensize=fb_var.xres*fb_var.yres*(fb_var.bits_per_pixel/); //显存大小 fbmem =(unsigned char *)mmap(NULL,screensize, PROT_READ|PROT_WRITE,MAP_SHARED,
fd_fb, ); //映射fb0 if(!fbmem)
{
printf("can't map /dev/fb0 \n");
return ;
}
memset(fbmem, , screensize); //清屏黑色 /*显示数据*/
lcd_put(,fb_var.yres/,s); /*显示矢量文字*/
lcd_vector_show(argv[], chinese_str); munmap(hzkmem,hzk_start.st_size);
munmap(fbmem,screensize);
return ;
}

4.4编译程序

编译报错: 56:38: error: freetype/config/ftheader.h: No such file or directory

通过find找到ftheader.h的位置是位于:../include/freetype2/freetype/config/ftheader.h

输入:

cd ./arm-none-linux-gnueabi/libc/usr/include/freetype2
mv freetype/ ../freetype //将freetype2下的freetype移到include目录下

编译:

arm-linux-gcc -o show_font show_font.c  -lfreetype  -lm -finput-charset=GBK  -fexec-charset=GBK

运行:

(发现,显示16*16字体时,会乱码, 新宋字体simsun不支持16点阵大小的字体)

下章学习:4.数码相框-freetype多行显示,居中显示

3.数码相框-通过freetype库实现矢量显示的更多相关文章

  1. NeHe OpenGL教程 第四十三课:FreeType库

    转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...

  2. 图像处理---《在图片上打印文字 FreeType库》

    图像处理---<在图片上打印文字 FreeType库> 目的:想在处理之后的图像上打印输出结果.方法: (1)只在图像上打印 数字.字母的话:                1.Mat格式 ...

  3. WordPress使用淘宝IP地址库的API显示评论者的位置信息(二)

    1 淘宝IP地址库的接口说明 在上一篇文章<WordPress使用淘宝IP地址库的API显示评论者的位置信息(一)>中,vfhky使用了新浪工具提供的这个IP接口显示博客评论者的位置信息. ...

  4. 【OpenGL】使用FreeType库加载字体并在GL中绘制文字

    FreeType用起来比较麻烦,这里写了一份简单的示例代码,仅供参考. 实现了FT库生成字符位图,并上传到GL纹理. 实现了字符位图缓存功能,多个字符图像保存在同一个纹理中. 实现了简单的字体管理框架 ...

  5. QT+OpenGL(04)—freetype库的编译

    1.freetype库的下载 https://www.freetype.org/download.html freetype-2.10.0.tar.bz2 2.解压 3.进入  freetype-2. ...

  6. libgdx学习记录9——FreeType,ttf中文显示

    前面讲到使用Hireo创建的BitmapFont以显示中文字体.这种方式效率很高,当所要显示的字的总数较少,并且大小比较固定时,可以采用这种方式. 但是这种也有弊端: (1)字体大小不能随意设置,当放 ...

  7. android studio依赖库工程Activity显示问题及库工程设置

    android studio引用库工程其实不难,直接添加依赖module即可,但是我在操作过程中出现一些奇怪的问题,苦扰我一整天,为了祭奠这苦命的一天特别mark一下. 首先描述一下我的错误现象: s ...

  8. 在Qt中调用Mupdf库进行pdf显示

    2018.5.10 更新内存对齐说明 感谢知乎网友@孤独子狮 指出QImage处需要考虑内存对齐的问题.因为本人缺乏跨平台.图形库开发经验,所以在调试成功后就没有深入探究. 主要修改了QImage的构 ...

  9. C++晋升之std中vector的实现原理(标准模板动态库中矢量的实现原理)

    我们实现的数据结构是为了解决在执行过程中动态的开辟空间使用(比如我们不停的输入,输入的多少我们不确定) 假设当你看到这篇文章的话,就当作是零食咀嚼,营养没有有BUG,能够直接看我博客中文章:CPU对内 ...

随机推荐

  1. Java多线程之线程的同步

    Java多线程之线程的同步 实际开发中我们也经常提到说线程安全问题,那么什么是线程安全问题呢? 线程不安全就是说在多线程编程中出现了错误情况,由于系统的线程调度具有一定的随机性,当使用多个线程来访问同 ...

  2. finally中关闭资源

    对finally中关闭资源是否还要使用try...catch老是感到迷惑,现在存个例子,省的忘了 public StringBuilder readTxtFile(File file){ String ...

  3. restful 风格的理解

    rest   其实就是representation    status   transfer(表现层状态转换) restful 风格的API具有如下特征: 1. 每个URI  包含一种资源,而且URI ...

  4. 【nginx】nginx解决跨域详解

    使用场景:本地运行一个项目,但是要访问外域的api接口,存在跨域问题,解决方式有很多,但我尝试用nginx解决,搜索了网上文章后再加上尝试终于成功, 其中一些注意事项和大家分享一下. 一.window ...

  5. GlusterFS最佳实践

    标签(linux): glusterfs 笔者Q:972581034 交流群:605799367.有任何疑问可与笔者或加群交流 今天我们来从实战中学习glusterfs 环境准备: gluster-s ...

  6. Hibernate的五个主要接口

    Hibernate作为持久成中间件,它的具体实现对与上层调用是透明的,即上层通过接口来调用Hibernate的具体实现,所以对于入门级别的讨论来说,自然应该先从接口开始了.

  7. Spring MVC NoClassDefFoundError 问题的解决方法。

    这种情况在有些项目中出现过,但是不是所有项目都会有这种问题,具体原因不详. 解决方法:如果某个pom的类出现这个异常,首先看看父级POM文件是否有这个dependency,然后再看看启动的网站web ...

  8. 不使用Math.random实现随机数

    不使用Math.random实现随机数 var rand = (function(){ var today = new Date(); var seed = today.getTime(); func ...

  9. MySQL笔记-语句的执行顺序

    在一次查询线上问题时发现有以下两条同样的SQL,执行后数据的顺序不一样: SELECT * FROM nns_assists_item AS asset WHERE asset.nns_assist_ ...

  10. SAS SATA SSD基本介绍

    SATA硬盘采用新的设计结构,数据传输快,节省空间,相对于IDE硬盘具有很多优势: 1 .SATA硬盘比IDE硬盘传输速度高.目前SATA可以提供150MB/s的高峰传输速率.今后将达到300 MB/ ...