1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 | ============================================================================================ 一、FreeType使用详解 参考来源: 1、freetype-doc-2.10.1.tar/freetype-doc-2.10.1/freetype-2.10.1/docs/tutorial/step1.html(文字说明) 2、freetype-2.10.1.tar/freetype-2.10.1/docs/reference/site/ft2-base_interface.html(函数定义) 3、韦东山视频:freetype介绍。 4、项目1数目相框_笔记\04\freetype-doc-2.10.1.tar\freetype-doc-2.10.1\freetype-2.10.1\docs\tutorial\example1.c(freetype-2.10.1工程自带的C代码)。 技巧:如果想更好地理解代码每个函数的定义,可以在source insight添加freetype-2.10.1.tar工程, 结合对应文档进行理解 ============================================================================================ I. Simple Glyph Loading(简单字形加载) 1. Header Files(头文件) Include the file named ft2build.h.(包含头文件 ) #include <ft2build.h> #include FT_FREETYPE_H 2. Library Initialization(库初始化) To initialize the FreeType library, create a variable of type FT_Library named, for example, library, and call the function FT_Init_FreeType. 用法:为了初始化FreeType library。需要的创建一个FT_Library类型的变量,比如library。然后调用函数FT_Init_FreeType。 FT_Init_FreeType的用法:{FT_Init_FreeType( &library );}返回值:0表示成功。返回错误码见fterrdef.h. 3. Loading a Font Face(用三种方式,1、从一个字库文件创建Face对象;2、从From Memory创建一个Face对象;3、其他方式) a. From a Font File(通过调用FT_New_Face打开一个字库文件从而创建一个新的face(这个可以理解为一个平面)对象,其代表一个字体文件。)调用函数FT_New_Face{FT_New_Face( library, "/usr/share/fonts/truetype/arial.ttf", 0, &face )}参数1:FT_Library类型的变量;参数2:字库文件路径();参数3:经常使用0;参数4:为一指针,用来描述face这一个对象。返回值:成功为0.其他看对应文档 要知道给定字体文件包含多少个面,可以将第三参数设置为-1,然后检查face->num_faces的值,该值指示字体文件中嵌入了多少个面。 b. From Memory(不常使用) 调用函数FT_New_Memory_Face( library, buffer, /* first byte in memory */ size, /* size in bytes */ 0, /* face_index */ &face ); 4. Accessing the Face Data(访问Face对象中数据) 可以使用的face?>num_glyphs等等一些成员.方式访问其中的数据。 5. Setting the Current Pixel Size(设置当前像素大小,即填充生成Face) a、使用到的函数(设置一个字符宽和高各多少像素点)定义: FT_Set_Char_Size( FT_Face face, FT_F26Dot6 char_width, FT_F26Dot6 char_height, FT_UInt horz_resolution, FT_UInt vert_resolution ); 参数1: 之前得到的Face;参数2:字符的高度:参数3:字符宽度;参数4:水平方向分辨率;参数5:竖直方向分辨率 参数2、3如何设置: The character widths and heights are specified in 1/64th of points,A point is a physical distance, equaling 1/72th of an inch。也就是说字符高度和宽度的单位是的1/64*1/72英寸。如果第二个参数的值是0,则表明宽度和高度相等。 参数4、5如何设置: The horizontal and vertical device resolutions are expressed in dots-per-inch, or dpi。也就是说每英寸里面存在多少像素。如果第二个参数0,则表明水平和竖直相等。 If both values are zero, 72 dpi is used for both dimensions.如果都为0,表明都使用72dpi。 如何计算一个字符里面包含多少个像素点呢: 举例说明: char_width= 100 char_height= 100 horz_resolution= 200 vert_resolution= 200 计算一个字符宽度由几个像素组成:100*1/64*1/72*200=4.3像素:同理计算字符高度需要多少像素。 b、如果我们不想使用FT_Set_Char_Size,我们可以使用FT_Set_Pixel_Sizes 函数定义: FT_Set_Pixel_Sizes( FT_Face face, FT_UInt pixel_width, FT_UInt pixel_height ); 因为使用FT_Set_Char_Size最终是得到了一个字符需要多少个像素组成,而对于使用FT_Set_Pixel_Sizes我们可以直接使用这个函数设置pixel_width和pixel_height。 6. Loading a Glyph Image a. Converting a Character Code Into a Glyph Index 知识点: 如果我们想要得到一个字符的glyph(关键信息),我们就需要提供这个字符的(唯一的)字符码(ascii、unicode、GBK等等。)。每一个字库文件中都存在一个charmap表。我可以通过这个表把提供字符码(可能是ascii也有点可能是unicode)作为索引在字库文件中找到该字符对应的glyph。 使用的函数: FT_Get_Char_Index( FT_Face face, FT_ULong charcode ); b. Loading a Glyph From the Face 说明: 1、加载找到的The glyph image到 face->glyph插槽中即slot中; The glyph image is always stored in a special object called a glyph slot,Each face object has a single glyph slot object that can be accessed as face->glyph.每一个Face都有一个slot object,slot object用来的存储The glyph image Loading a glyph image into the slot is performed by calling FT_Load_Glyph.加载一个a glyph image到这个插槽对象中,用法如下: 函数:FT_Load_Glyph( FT_Face face, FT_UInt glyph_index, FT_Int32 load_flags ); 2、将slot(face->glyph)中The glyph image转化为位图(真正的图像,也就是字符点阵) The field face?>glyph?>format describes the format used for storing the glyph image in the slot. If it is not FT_GLYPH_FORMAT_BITMAP, one can immediately convert it to a bitmap through FT_Render_Glyph. 说明:如果face?>glyph?>format里面图像格式不是FT_GLYPH_FORMAT_BITMAP,那就立即将slot(face->glyph)中的图像立即的转化为a bitmap(位图),需要使用的函数: FT_Render_Glyph( FT_GlyphSlot slot, FT_Render_Mode render_mode ); 参数1:face->glyph变量。 参数2:位图的呈现模式 c. Using Other Charmaps 在6.a步骤中,如果我们不想使用face中charmap表格默认的索引(unicode),我们提供可能是其他编码,我们可以通过相应的函数修该对应的charmaps 函数:error = FT_Select_Charmap( face, /* target face object */ FT_ENCODING_BIG5 ); /* encoding 参数2含义:指定使用编码,这里是FT_ENCODING_BIG5 那么如何确定已经打开的字库文件中包含多少charmaps,可以用以下代码: for ( n = 0; n < face->num_charmaps; n++ ) { charmap = face->charmaps[n]; if ( charmap->platform_id == my_platform_id && charmap->encoding_id == my_encoding_id ) { found = charmap; break; } d. Glyph Transformations 如果的我们需要将显示字符做一个平移或者旋转,就需要使用一个函数: FT_Set_Transform( FT_Face face, FT_Matrix* matrix, FT_Vector* delta ); 参数介绍: 参数2:指向一个matrix的指针,首先定义一个FT_Matrix的变量。对该变量进行初始化(旋转多少度。)。 参数3:这个字符基点(原点)在定义的显示区域的位置。 设置参数3有一个知识点: 字库文件中的字符基点(原点)使用的是笛卡尔坐标(位于左下角)。而对于LCD而言话,其坐标原点位于屏幕的左上角,因此设置FT_Vector类型变量时。需要将字符位置进行一个转换。矢量坐标表示为1/64个像素(也称为26.6个定点数,因此需要乘以一个64)。 7. Simple Text Rendering The idea is to create a loop that loads one glyph image on each iteration, converts it to a pixmap, draws it on the target surface, then increments the current pen position.(其思想是创建一个循环,在每次迭代中加载一个字形图像,将其转换为像素图,在目标表面绘制它,然后增加当前笔的位置。) ======================================================================================================== a. Basic Code(基本的代码) ======================================================================================================== ... initialize library ... ... create face object ... ... set character size ... pen_x = 300; //字符显示的位置 pen_y = 200; for ( n = 0; n < num_chars; n++ ) //使用一个循环遍历整个所要显示的字符 { FT_UInt glyph_index; /* retrieve glyph index from character code */ glyph_index = FT_Get_Char_Index( face, text[n] ); //循环内step1 寻找第n个字符对应的index /* load glyph image into the slot (erase previous one):将的生成的image放进slot */ error = FT_Load_Glyph( face, glyph_index, FT_LOAD_DEFAULT ); //循环内step2,根据index找到其对应的字形轮廓 if ( error ) continue; /* ignore errors */ /* convert to an anti-aliased bitmap:转化为位图(位图是点阵吗?) */ error = FT_Render_Glyph( face->glyph, FT_RENDER_MODE_NORMAL ); //循环内step3,将字形轮廓转化为位图 if ( error ) continue; /* now, draw to our target surface */ //循环内step4 my_draw_bitmap( &slot->bitmap, pen_x + slot->bitmap_left, pen_y - slot->bitmap_top ); /* increment pen position */ pen_x += slot->advance.x >> 6; //循环内step5 pen_y += slot->advance.y >> 6; /* not useful for now */ } 总结: 这一快代码是循环体内最基本代码,目前我的疑惑: my_draw_bitmap函数如何实现(看了源码现在也不太懂(目前不知道slot->bitmap放的是什么,点阵?,那应该是一堆的0和1。但是结合后面调用的show image函数中的{putchar( image[i][j] == 0 ? ' ' : image[i][j] < 128 ? '+' : '*' );},又好像不对 。现在无法解决。)) ======================================================================================================= b.Refined code(精简的代码)建议使用为什么有这一部分b呢(主要是与a进行对比,不同在for循环体内) ======================================================================================================== for ( n = 0; n < num_chars; n++ ) { /* load glyph image into the slot (erase previous one) */ error = FT_Load_Char( face, text[n], FT_LOAD_RENDER ); //step1 if ( error ) continue; /* ignore errors */ /* now, draw to our target surface */ my_draw_bitmap( &slot->bitmap, pen_x + slot->bitmap_left, pen_y - slot->bitmap_top ); /* increment pen position */ pen_x += slot->advance.x >> 6; } 总结:对比a. Basic Code(基本的代码)和bRefined code(精简的代码) a中循环内step1~step3被b中step1替代同样可以达到效果(将得到的glyph转化为位图) ============================================================================================ 二、使用韦老师提供的freetype-2.4.10源码进行编译安装 freetype,然后运行韦老师的代码 ============================================================================================ 因为编写的代码代码需要调用的安装freetype所生成的库文件(包括头文件,函数的定义等等)。 自己的体会: 1、如何安装freetype。可从源码根目录中READM出发,查看安装的过程。 2、安装freetype之后,就会在/user/local(默认)下面的目录(环境变量)中生成库文件。安装文档中也有讲。 3、下面就是执行韦老师的程序了 gcc -o example1 example1.c 出错信息:/usr/local/include/ft2build.h:56:38: fatal error: freetype/config/ftheader.h: No such file or directory 但是经过查看/usr/local/include/ft2build.h中56行 #include <freetype/config/ftheader.h>。在进行查看发现/usr/local/include/freetype2/freetype/config/ftheader.h存在头文件。这表示程序未找到对应路径因此需要指定路径:gcc -o example1 example1.c -I /usr/local/include/freetype2/。也就是说在freetype2/然后执行#include <freetype/config/ftheader.h>。执行发现 example1.c:(.text+0x25b): undefined reference to `FT_Init_FreeType' example1.c:(.text+0x284): undefined reference to `FT_New_Face' example1.c:(.text+0x29d): undefined reference to `FT_Set_Pixel_Sizes' example1.c:(.text+0x2c4): undefined reference to `cos' example1.c:(.text+0x2f5): undefined reference to `sin' example1.c:(.text+0x332): undefined reference to `sin' example1.c:(.text+0x363): undefined reference to `cos' example1.c:(.text+0x3b6): undefined reference to `FT_Set_Transform' example1.c:(.text+0x3de): undefined reference to `FT_Load_Char' example1.c:(.text+0x465): undefined reference to `FT_Done_Face' example1.c:(.text+0x471): undefined reference to `FT_Done_FreeType' 提示是未定义,但是,我们已经包含了对应的头文件,因此程序链接的时候未找到安装freetype生成的库文件,因此的需要指定生成的库文件(注意:去掉lib前缀): gcc -o example1 example1.c -I /usr/local/include/freetype2/ -lfreetype 执行发现: example1.c:(.text+0x2c4): undefined reference to `cos' example1.c:(.text+0x2f5): undefined reference to `sin' example1.c:(.text+0x332): undefined reference to `sin' example1.c:(.text+0x363): undefined reference to `cos' 表明链接的时候未找到对应的数学库,因此执行(不能加-lmath而是加-lm): gcc -o example1 example1.c -I /usr/local/include/freetype2/ -lfreetype -lm 成功 然后执行./example1 BROADW.TTF abc. 执行成功 ============================================================================================ 三、使用韦老师提供的freetype-2.4.10源码进行编译安装 freetype,然后运行自己写的代码 ============================================================================================ 自己写的代码,是可以运行出结果,只能显示单个字符,如果是多个字符的话,就会导致,字符存在重合,我的代码里面已经使用 pen.x += slot->advance.x; pen.y += slot->advance.y; 者这句代码,但是实验的结果,表明第二字符之后origin(原点仍然没用移动),后面解决这个问题。 |