1.简介
将汉字的笔划边缘用直线段描述成封闭的曲线,并将线段各端点的坐标经压缩存储 矢量字库由两部分组成,一部分是汉字的索引信息,一部分是汉字的字形(glyph)数据 当显示文字时,便取出各端点,并通过贝塞尔曲线连接各坐标,最后填充封闭空间
2.freetype在电脑上的体验
PC上安装到(/usr/local/)
1.解压 tar -xjf freetype-2.4.10.tar.bz2 2.重命名 mv freetype-2.4.10 freetype-2.4.10_pc 3.配置 cd freetype-2.4.10_pc ./configure 4.编译 make 5.安装到根目录 sudo make install //直接将库安装到根目录/usr/local/里,所以需要加sudo
编译文件时
eg:编译例程:example1.c(关于freetype的代码) gcc -o example1 example1.c -I /usr/local/include/freetype2/ -lfreetype -lm 解析: -I /usr/local/include/freetype2/ 指定头文件目录 -lfreetype -lm 链接文件,链接freetype库中的函数;链接数学库中的函数
运行
eg: ./example1 simsun.ttc agf /* 运行example1,使用宋体。显示agf */ 宋体:链接:https://pan.baidu.com/s/12c8IR4phYh2ZITTGojSfHg
提取码:82wo
3.安装freetype到交叉编译目录中去(供arm-linux-gcc编译)
1.查看arm-linux-gcc的位置
a.通过$PATH找到arm-linu-gcc交叉编译位于: /work/tools/arm-linux-gcc-4.3.2/usr/local/arm/4.3.2/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 b.通过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
2.安装
1.解压
mkdir freetype-2.4.10_arm tar -xjf freetype-2.4.10.tar.bz2 -C ./freetype-2.4.10_arm 注: -C 指定目录
2.配置
cd freetype-2.4.10_arm mkdir tmp // 创建安装的临时目录,后面会拷贝到交叉编译目录里 ./configure --host=arm-linux --prefix=$PWD/tmp //配置交叉编译,安装前缀 注: --host=arm-linux 编译出来的程序是在arm-linux下使用 --prefix=$PWD/tmp --prefix指定安装路径。配置交叉编译器安装前缀
3.编译安装
make make DESTDIR=$PWD/tmp install
4.拷贝
cd tmp/ cp ./include/* /work/tools/arm-linux-gcc-4.3.2/usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/usr/include/ -rfd //将include下的头文件拷贝到交叉编译里去 cp lib/* /work/tools/arm-linux-gcc-4.3.2/usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/armv4t/lib/ -rfd //将lib下的库文件拷贝到交叉编译里去 cp lib/ * /work/nfs_root/3.4_fs_mini_mdev/lib/ -rfd //将lib下的库文件拷贝到nfs文件系统去
2.如何使用freetype
1.包含头文件 2.加载初始化库 3.加载face对象 4.设置字体的大小,位置等 5.1获取编码 5.2通过编码获取到字符图像,存到字形槽glygph slot 字形槽:每次只能存储一个图像 每个face对象都有一个字形槽,位于face->glyph 6.转换位图
1.包含头文件
#include <ft2build.h> #include FT_FREETYPE_H
2.加载初始化库
使用FT_Init_FreeType()函数初始化一个FT_Library类型的变量 eg: FT_Library library; // 库的句柄 error = FT_Init_FreeType(&library); if(error) { /* 初始化失败 */ }
3.加载face对象
通过FT_New_Face()打开一个字体文件,然后提取该文件的一个FT_Face类型的Face变量 eg: FT_Library library; // 库的句柄 FT_Face face; // face对象的句柄 error = FT_Init_FreeTyte(&library) if(error) { ... } ... error = FT_New_Face(library, "usr/share/fonts/truetype/arial.ttf", 0, &face); 注释:usr/share/fonts/truetype/arial.ttf。这里是字形文件。这里我们是上传的自己找到的字体文件
4.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英寸。1/64像素,所以乘64表示一个点 分辨率以dpi为单位表示,表示一个英寸有多少像素 eg: error = FT_Set_Char_Size( face, 50 * 64, 0,100, 0 ); //0表示与另一个尺寸值相等 解析: 字符的物理大小为:50 * 64 *(1/64)*(1/72) 字符与的像素位:50 * 64*(1/64)*(1/72)*100 方法二: FT_Set_Pixel_Sizes( FT_Face face, FT_UInt pixel_width, //像素宽度 FT_UInt pixel_height ); //像素高低 eg: error = FT_Set_Pixel_Sizes( face, 0,16); //把字符像素设置为16*16像素, 0表示与另一个尺寸值相等。
4.2设置字体的位置,以及旋转度数(不设置的话,表示远点位于(0,0))
error = FT_Set_Transform(face /* 目标face对象*/ &matrix, /* 指向2*2矩阵的指针,写0表示不旋转,使用正矩形 */ &delta ); /* 字体坐标位置(使用的是笛卡尔坐标),以1/64像素为单位表示,写0表示原点是(0,0) */ 注意: 因为我们的LCD坐标原点位于左上方,笛卡尔坐标位于左下方所以转化之前填写坐标需要转换下 eg:旋转25度,在(300,200)处显示 FT_Vector pen; FT_Matrix matrix; angle = ( 25.0 / 360 ) * 3.14159 * 2; /* use 25 degrees,转换为弧度制 */ /* 将文字坐标转化为笛卡尔坐标 */ pen.x = 300 * 64; pen.y = ( target_height - 200 ) * 64; // 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 )
5.1获取编码
通过FT_Get_Char_Inde()函数将字符编码转换为一个字形(glyph)索引 (Freetype默认是utf-16编码类型) eg: 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).
5.2通过编码索引从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值
6.转换位图
通过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 的点阵位图内存绶冲区
也可以直接使用FT_Load_Char()来代替FT_Get_Char_Index()、FT_Get_Load_Glyph()和FT_Render_Glyph().
eg: 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[]里的一个字节.
7.多行显示
1.从左上角开始显示
流程
1.先在左上角上显示第一行 2.显示时保留y轴最大和最小值 3.根据y轴的最大,最小值可以确定第二行的原点
简析
x坐标我们可以用一个字符的advance的x计算,y的坐标我们需要计算上一行字符advance的最大值(或者使用最小值)来确定。使用FT_Get_Glyph( face->glyph, &glyph )将face对象槽中的形状保存到glyph ; FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_TRUNCATE, &bbox )从glyph中提取信息到bbox 。
2.居中显示
简析
先计算字符长度,然后计算出原点的位置
流程
1.通过要显示的str填充的具体编码,外观(矢量信息),位置信息基于(0,0),统一用glyohs[]进行管理 2.遍历所有外观,计算最大最小的框架信息 3.计算居中的位置 4.绘图 5.内存销毁
注:
这里需要调整两次位置信息, 1.第一次是在保持全局数组的外观是,产生行数据是基于pen在(0,0的位置) 2.第二次是实际转换为图前,将实际的pen的位置与之前的位置计算偏移
8.代码解析
1.居中显示一个矢量字体
#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 <stdlib.h> #include <ft2build.h> #include FT_FREETYPE_H #include FT_GLYPH_H #define FONTDATAMAX 4096 static const unsigned char fontdata_8x16[FONTDATAMAX] = { /* ASCII编码 */ }; int fd_fb; struct fb_var_screeninfo var; /* Current var */ struct fb_fix_screeninfo fix; /* Current fix */ int screen_size; unsigned char *fbmem; unsigned int line_width; unsigned int pixel_width; int fd_hzk16; struct stat hzk_stat; unsigned char *hzkmem; /* color : 0x00RRGGBB */ void lcd_put_pixel(int x, int y, unsigned int color) { unsigned char *pen_8 = fbmem+y*line_width+x*pixel_width; unsigned short *pen_16; unsigned int *pen_32; unsigned int red, green, blue; pen_16 = (unsigned short *)pen_8; pen_32 = (unsigned int *)pen_8; switch (var.bits_per_pixel) { case 8: { *pen_8 = color; break; } case 16: { /* 565 */ red = (color >> 16) & 0xff; green = (color >> 8) & 0xff; blue = (color >> 0) & 0xff; color = ((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3); *pen_16 = color; break; } case 32: { *pen_32 = color; break; } default: { printf("can't surport %dbpp\n", var.bits_per_pixel); break; } } } 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 */ lcd_put_pixel(x+7-b, y+i, 0xffffff); /* 白 */ } else { /* hide */ lcd_put_pixel(x+7-b, y+i, 0); /* 黑 */ } } } } void lcd_put_chinese(int x, int y, unsigned char *str) { unsigned int area = str[0] - 0xA1; unsigned int where = str[1] - 0xA1; unsigned char *dots = hzkmem + (area * 94 + where)*32; unsigned char byte; int i, j, b; for (i = 0; i < 16; i++) for (j = 0; j < 2; j++) { byte = dots[i*2 + j]; for (b = 7; b >=0; b--) { if (byte & (1<<b)) { /* show */ lcd_put_pixel(x+j*8+7-b, y+i, 0xffffff); /* 白 */ } else { /* hide */ lcd_put_pixel(x+j*8+7-b, y+i, 0); /* 黑 */ } } } } /* Replace this function with something useful. */ 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; FT_Int y_max = y + bitmap->rows; //printf("x = %d, y = %d\n", x, y); for ( i = x, p = 0; i < x_max; i++, p++ ) { for ( j = y, q = 0; j < y_max; j++, q++ ) { if ( i < 0 || j < 0 || i >= var.xres || j >= var.yres ) continue; //image[j][i] |= bitmap->buffer[q * bitmap->width + p]; //bitmap->buffer[q * bitmap->width + p 颜色 lcd_put_pixel(i, j, bitmap->buffer[q * bitmap->width + p]); } } } int main(int argc, char **argv) { unsigned char str[] = "中"; /* wchar_t 和L一起使用。 * wchar为宽字符对字母和汉字都采用两字节去保存 * 使用时就会跟加方便,不必去区分到底为字符还是汉字 */ wchar_t *chinese_str = L"繁"; FT_Library library; FT_Face face; int error; FT_Vector pen; FT_GlyphSlot slot; FT_Matrix matrix; /* transformation matrix */ double angle; if (argc != 3) { printf("Usage : %s <font_file> <angle>\n", argv[0]); return -1; } fd_fb = open("/dev/fb0", O_RDWR); if (fd_fb < 0) { printf("can't open /dev/fb0\n"); return -1; } if (ioctl(fd_fb, FBIOGET_VSCREENINFO, &var)) { printf("can't get var\n"); return -1; } if (ioctl(fd_fb, FBIOGET_FSCREENINFO, &fix)) { printf("can't get fix\n"); return -1; } line_width = var.xres * var.bits_per_pixel / 8; pixel_width = var.bits_per_pixel / 8; screen_size = var.xres * var.yres * var.bits_per_pixel / 8; fbmem = (unsigned char *)mmap(NULL , screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0); if (fbmem == (unsigned char *)-1) { printf("can't mmap\n"); return -1; } fd_hzk16 = open("HZK16", O_RDONLY); if (fd_hzk16 < 0) { printf("can't open HZK16\n"); return -1; } if(fstat(fd_hzk16, &hzk_stat)) { printf("can't get fstat\n"); return -1; } hzkmem = (unsigned char *)mmap(NULL , hzk_stat.st_size, PROT_READ, MAP_SHARED, fd_hzk16, 0); if (hzkmem == (unsigned char *)-1) { printf("can't mmap for hzk16\n"); return -1; } /* 清屏: 全部设为黑色 */ memset(fbmem, 0, screen_size); lcd_put_ascii(var.xres/2, var.yres/2, 'A'); printf("chinese code: %02x %02x\n", str[0], str[1]); lcd_put_chinese(var.xres/2 + 8, var.yres/2, str); /* 显示矢量字体 */ error = FT_Init_FreeType( &library ); /* initialize library */ /* error handling omitted */ /* 加载字体文件到face,argv[1]为字体文件名 */ error = FT_New_Face( library, argv[1], 0, &face ); /* create face object */ /* error handling omitted */ /* 保存字形 */ slot = face->glyph; FT_Set_Pixel_Sizes(face, 24, 0); /* 确定座标: * lcd_x = var.xres/2 + 8 + 16 * lcd_y = var.yres/2 + 16 * 笛卡尔座标系: * x = lcd_x = var.xres/2 + 8 + 16 * y = var.yres - lcd_y = var.yres/2 - 16 */ pen.x = (var.xres/2 + 8 + 16) * 64; pen.y = (var.yres/2 - 16) * 64; /* string to unsigned long */ angle = ( 1.0 * strtoul(argv[2], NULL, 0) / 360 ) * 3.14159 * 2; /* use 25 degrees */ /* set up matrix */ 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 ); /* set transformation */ FT_Set_Transform( face, &matrix, &pen); /* load glyph image into the slot (erase previous one) */ error = FT_Load_Char( face, chinese_str[0], FT_LOAD_RENDER ); if (error) { printf("FT_Load_Char error\n"); return -1; } /* 左上角的点 */ draw_bitmap( &slot->bitmap, slot->bitmap_left, var.yres - slot->bitmap_top); return 0; }
测试:
arm-linux-gcc -finput-charset=GBK -fexec-charset=GBK -o show_font show_font.c -lfreetype -lm 这里指定输入和输出都是GBK码。 因为unsigned char str[] = "中"; //输入的是GBK,输出的也是GBK;后面代码也是使用的GBK编码的方式进行解码的 wchar_t chinese_str[] = L"繁"; //输入的是GBK,输出的是UTF-8;
2.从左上角开始显示多行文字
#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 <ft2build.h> #include FT_FREETYPE_H #include FT_GLYPH_H int fd_fb; struct fb_var_screeninfo var; /* Current var */ struct fb_fix_screeninfo fix; /* Current fix */ int screen_size; unsigned char *fbmem; unsigned int line_width; unsigned int pixel_width; /* color : 0x00RRGGBB */ void lcd_put_pixel(int x, int y, unsigned int color) { unsigned char *pen_8 = fbmem+y*line_width+x*pixel_width; unsigned short *pen_16; unsigned int *pen_32; unsigned int red, green, blue; pen_16 = (unsigned short *)pen_8; pen_32 = (unsigned int *)pen_8; switch (var.bits_per_pixel) { case 8: { *pen_8 = color; break; } case 16: { /* 565 */ red = (color >> 16) & 0xff; green = (color >> 8) & 0xff; blue = (color >> 0) & 0xff; color = ((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3); *pen_16 = color; break; } case 32: { *pen_32 = color; break; } default: { printf("can't surport %dbpp\n", var.bits_per_pixel); break; } } } /* Replace this function with something useful. */ 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; FT_Int y_max = y + bitmap->rows; //printf("x = %d, y = %d\n", x, y); for ( i = x, p = 0; i < x_max; i++, p++ ) { for ( j = y, q = 0; j < y_max; j++, q++ ) { if ( i < 0 || j < 0 || i >= var.xres || j >= var.yres ) continue; //image[j][i] |= bitmap->buffer[q * bitmap->width + p]; lcd_put_pixel(i, j, bitmap->buffer[q * bitmap->width + p]); } } } int main(int argc, char **argv) { wchar_t *wstr1 = L"百问网gif"; wchar_t *wstr2 = L"www.100ask.net"; FT_Library library; FT_Face face; int error; FT_Vector pen; FT_GlyphSlot slot; int i; FT_BBox bbox; FT_Glyph glyph; int line_box_ymin = 10000; int line_box_ymax = 0; if (argc != 2) { printf("Usage : %s <font_file>\n", argv[0]); return -1; } fd_fb = open("/dev/fb0", O_RDWR); if (fd_fb < 0) { printf("can't open /dev/fb0\n"); return -1; } if (ioctl(fd_fb, FBIOGET_VSCREENINFO, &var)) { printf("can't get var\n"); return -1; } if (ioctl(fd_fb, FBIOGET_FSCREENINFO, &fix)) { printf("can't get fix\n"); return -1; } line_width = var.xres * var.bits_per_pixel / 8; pixel_width = var.bits_per_pixel / 8; screen_size = var.xres * var.yres * var.bits_per_pixel / 8; fbmem = (unsigned char *)mmap(NULL , screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0); if (fbmem == (unsigned char *)-1) { printf("can't mmap\n"); return -1; } /* 清屏: 全部设为黑色 */ memset(fbmem, 0, screen_size); /* 显示矢量字体 */ error = FT_Init_FreeType( &library ); /* initialize library */ /* error handling omitted */ error = FT_New_Face( library, argv[1], 0, &face ); /* create face object */ /* error handling omitted */ slot = face->glyph; FT_Set_Pixel_Sizes(face, 24, 0); /* 确定座标: * lcd_x = 0 * lcd_y = 24 * 笛卡尔座标系: * x = lcd_x = 0 * y = var.yres - lcd_y = var.yres - 24 */ pen.x = 0 * 64; pen.y = (var.yres - 24) * 64; for (i = 0; i < wcslen(wstr1); i++) { /* set transformation */ FT_Set_Transform( face, 0, &pen); /* load glyph image into the slot (erase previous one) */ error = FT_Load_Char( face, wstr1[i], FT_LOAD_RENDER ); if (error) { printf("FT_Load_Char error\n"); return -1; } error = FT_Get_Glyph( face->glyph, &glyph ); if (error) { printf("FT_Get_Glyph error!\n"); return -1; } FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_TRUNCATE, &bbox ); if (line_box_ymin > bbox.yMin) line_box_ymin = bbox.yMin; if (line_box_ymax < bbox.yMax) line_box_ymax = bbox.yMax; draw_bitmap( &slot->bitmap, slot->bitmap_left, var.yres - slot->bitmap_top); /* increment pen position */ pen.x += slot->advance.x; //pen.y += slot->advance.y; } /* 确定座标: * lcd_x = 0 * lcd_y = line_box_ymax - line_box_ymin + 24 * 笛卡尔座标系: * x = lcd_x = 0 * y = var.yres - lcd_y = var.yres - (line_box_ymax - line_box_ymin + 24) */ pen.x = 0 * 64; pen.y = (var.yres - (line_box_ymax - line_box_ymin + 24)) * 64; for (i = 0; i < wcslen(wstr2); i++) { /* set transformation */ FT_Set_Transform( face, 0, &pen); /* load glyph image into the slot (erase previous one) */ error = FT_Load_Char( face, wstr2[i], FT_LOAD_RENDER ); if (error) { printf("FT_Load_Char error\n"); return -1; } error = FT_Get_Glyph( face->glyph, &glyph ); if (error) { printf("FT_Get_Glyph error!\n"); return -1; } FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_TRUNCATE, &bbox ); if (line_box_ymin > bbox.yMin) line_box_ymin = bbox.yMin; if (line_box_ymax < bbox.yMax) line_box_ymax = bbox.yMax; draw_bitmap( &slot->bitmap, slot->bitmap_left, var.yres - slot->bitmap_top); /* increment pen position */ pen.x += slot->advance.x; //pen.y += slot->advance.y; } return 0; }
3.居中显示多行文字
#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 <ft2build.h> #include FT_FREETYPE_H #include FT_GLYPH_H typedef struct TGlyph_ { FT_UInt index; /* glyph index */ FT_Vector pos; /* glyph origin on the baseline */ FT_Glyph image; /* glyph image */ } TGlyph, *PGlyph; #define MAX_GLYPHS 100 int fd_fb; struct fb_var_screeninfo var; /* Current var */ struct fb_fix_screeninfo fix; /* Current fix */ int screen_size; unsigned char *fbmem; unsigned int line_width; unsigned int pixel_width; /* color : 0x00RRGGBB */ void lcd_put_pixel(int x, int y, unsigned int color) { unsigned char *pen_8 = fbmem+y*line_width+x*pixel_width; unsigned short *pen_16; unsigned int *pen_32; unsigned int red, green, blue; pen_16 = (unsigned short *)pen_8; pen_32 = (unsigned int *)pen_8; switch (var.bits_per_pixel) { case 8: { *pen_8 = color; break; } case 16: { /* 565 */ red = (color >> 16) & 0xff; green = (color >> 8) & 0xff; blue = (color >> 0) & 0xff; color = ((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3); *pen_16 = color; break; } case 32: { *pen_32 = color; break; } default: { printf("can't surport %dbpp\n", var.bits_per_pixel); break; } } } /* Replace this function with something useful. */ 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; FT_Int y_max = y + bitmap->rows; //printf("x = %d, y = %d\n", x, y); for ( i = x, p = 0; i < x_max; i++, p++ ) { for ( j = y, q = 0; j < y_max; j++, q++ ) { if ( i < 0 || j < 0 || i >= var.xres || j >= var.yres ) continue; //image[j][i] |= bitmap->buffer[q * bitmap->width + p]; lcd_put_pixel(i, j, bitmap->buffer[q * bitmap->width + p]); } } } /* 把wstr中的字,从字体文件中取出其字形 * 并把其存在数组中 */ int Get_Glyphs_Frm_Wstr(FT_Face face, wchar_t * wstr, TGlyph glyphs[]) { int n; PGlyph glyph = glyphs; int pen_x = 0; int pen_y = 0; int error; FT_GlyphSlot slot = face->glyph;; for (n = 0; n < wcslen(wstr); n++) { glyph->index = FT_Get_Char_Index( face, wstr[n]); /* store current pen position */ glyph->pos.x = pen_x; glyph->pos.y = pen_y; /* load时是把glyph放入插槽face->glyph */ error = FT_Load_Glyph(face, glyph->index, FT_LOAD_DEFAULT); if ( error ) continue; /* 注意加载和get */ error = FT_Get_Glyph(face->glyph, &glyph->image ); if ( error ) continue; /* translate the glyph image now * 这使得glyph->image里含有位置信息 * 把原来在(x,y)的字形数据变换为现在glyph->pos中地址的位置 */ FT_Glyph_Transform(glyph->image, 0, &glyph->pos ); pen_x += slot->advance.x; /* 1/64 point */ /* increment number of glyphs */ glyph++; } /* count number of glyphs loaded */ return (glyph - glyphs); } /* 计算x.min, x.max, y.min, y.max */ void compute_string_bbox(TGlyph glyphs[], FT_UInt num_glyphs, FT_BBox *abbox ) { FT_BBox bbox; int n; bbox.xMin = bbox.yMin = 32000; bbox.xMax = bbox.yMax = -32000; for ( n = 0; n < num_glyphs; n++ ) { FT_BBox glyph_bbox; FT_Glyph_Get_CBox(glyphs[n].image, FT_GLYPH_BBOX_TRUNCATE, &glyph_bbox ); if (glyph_bbox.xMin < bbox.xMin) bbox.xMin = glyph_bbox.xMin; if (glyph_bbox.yMin < bbox.yMin) bbox.yMin = glyph_bbox.yMin; if (glyph_bbox.xMax > bbox.xMax) bbox.xMax = glyph_bbox.xMax; if (glyph_bbox.yMax > bbox.yMax) bbox.yMax = glyph_bbox.yMax; } *abbox = bbox; } void Draw_Glyphs(TGlyph glyphs[], FT_UInt num_glyphs, FT_Vector pen) { int n; int error; for (n = 0; n < num_glyphs; n++) { /* 把原来在原点的字形数据变换为现在pen中地址的位置 */ FT_Glyph_Transform(glyphs[n].image, 0, &pen); /* convert glyph image to bitmap (destroy the glyph copy!) * 把字形转化为位图 */ error = FT_Glyph_To_Bitmap(&glyphs[n].image, FT_RENDER_MODE_NORMAL, 0, /* no additional translation */ 1 ); /* destroy copy in "image" */ if ( !error ) { /* 得到位图 */ FT_BitmapGlyph bit = (FT_BitmapGlyph)glyphs[n].image; draw_bitmap(&bit->bitmap, bit->left, var.yres - bit->top); /* 释放空间 */ FT_Done_Glyph(glyphs[n].image ); } } } int main(int argc, char **argv) { wchar_t *wstr1 = L"百问网gif"; wchar_t *wstr2 = L"www.100ask.net"; FT_Library library; FT_Face face; int error; FT_Vector pen; FT_GlyphSlot slot; int i; FT_BBox bbox; int line_box_ymin = 10000; int line_box_ymax = 0; int line_box_width; int line_box_height; TGlyph glyphs[MAX_GLYPHS]; /* glyphs table */ FT_UInt num_glyphs; if (argc != 2) { printf("Usage : %s <font_file>\n", argv[0]); return -1; } fd_fb = open("/dev/fb0", O_RDWR); if (fd_fb < 0) { printf("can't open /dev/fb0\n"); return -1; } if (ioctl(fd_fb, FBIOGET_VSCREENINFO, &var)) { printf("can't get var\n"); return -1; } if (ioctl(fd_fb, FBIOGET_FSCREENINFO, &fix)) { printf("can't get fix\n"); return -1; } line_width = var.xres * var.bits_per_pixel / 8; pixel_width = var.bits_per_pixel / 8; screen_size = var.xres * var.yres * var.bits_per_pixel / 8; fbmem = (unsigned char *)mmap(NULL , screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0); if (fbmem == (unsigned char *)-1) { printf("can't mmap\n"); return -1; } /* 清屏: 全部设为黑色 */ memset(fbmem, 0, screen_size); /* 显示矢量字体 */ error = FT_Init_FreeType( &library ); /* initialize library */ /* error handling omitted */ error = FT_New_Face( library, argv[1], 0, &face ); /* create face object */ /* error handling omitted */ slot = face->glyph; FT_Set_Pixel_Sizes(face, 24, 0); /* wstr1 */ num_glyphs = Get_Glyphs_Frm_Wstr(face, wstr1, glyphs); compute_string_bbox(glyphs, num_glyphs, &bbox); line_box_width = bbox.xMax - bbox.xMin; line_box_height = bbox.yMax - bbox.yMin; /* 最后的坐标计算 */ pen.x = (var.xres - line_box_width)/2 * 64; pen.y = (var.yres - line_box_height)/2 * 64; /* 画图像 */ Draw_Glyphs(glyphs, num_glyphs, pen); /* wstr2 */ num_glyphs = Get_Glyphs_Frm_Wstr(face, wstr2, glyphs); compute_string_bbox(glyphs, num_glyphs, &bbox); line_box_width = bbox.xMax - bbox.xMin; line_box_height = bbox.yMax - bbox.yMin; /* 计算坐标 */ pen.x = (var.xres - line_box_width)/2 * 64; pen.y = pen.y - 24 * 64; Draw_Glyphs(glyphs, num_glyphs, pen); return 0; }
来源:https://www.cnblogs.com/huangdengtao/p/12297247.html