使用freetype显示一行汉字-学习记录

前提

这篇文章代码是韦东山老师Linux应用开发里的一个代码,具体是在01_all_series_quickstart\04_嵌入式Linux应用开发基础知识\source\10_freetype\04_show_line,以下是我的一些解析,主要包括自己遇到的一些疑问和相应的解决。建议多看几遍原视频。

初始化结构体变量等

代码:

wchar_t *wstr = L"百问网www.100ask.net";
  • wchar_t是一个unsigned short,两个字节
  • L:表示“”使用宽字符编码”,就是把你后面字符串的每个字符都用两个字节的unicode来存储

从这里直到后面调用FT_Init_FreeType,在视频里都讲过很多遍,我没什么问题,就不说了。现在直接跳转到调用FT_Init_FreeType函数这一块

初始化library变量

error = FT_Init_FreeType( &library );
这一块是freetype一定要加的,此处error的作用如下:

#include <ft2build.h>
#include FT_FREETYPE_H

FT_Library  library;
error = FT_Init_FreeType( &library );
if ( error )
{
  	//失败的逻辑处理
}
  • what: 初始化library结构体变量
  • error的取值:
    • 0(FT_Err_Ok): 成功
    • 其他值: 失败
      所以此处才用一个if判断是否为非0值,判断是否失败,失败会将library置为NULL

从字体文件中获取face

error = FT_New_Face( library, argv[1], 0, &face );
按官方文档,一个字体文件有多个face,通过调用FT_New_Face将face搞出来。face我粗浅地认为就是一个字体文件里的某些信息吧。
咱看一下声明中的参数:

 FT_New_Face( FT_Library   library,
               const char*  pathname,
               FT_Long      face_index,
               FT_Face*     aface )
  • 你干嘛: 通过调用FT_New_Face来获取字体文件中的face
  • 参数说明:
    • library: 之前所说的Library结构体
    • pathname:字体的路径
    • face_index:字体中的第几个face,0就是第一个,简单来说就是我不知道里面有几个face(官方文档说可以查),但是第一个总是存在的。那我就取第一个就得了。
    • aface :提取face后保存在哪里?保存在这个参数(指针)所指向的结构体那

总的来说就是初始化face,以后就用face去做些其他的东西。

设置字符的大小

FT_Set_Pixel_Sizes(face, font_size, 0);
看一下函数声明:

  FT_Set_Pixel_Sizes( FT_Face  face,
                      FT_UInt  pixel_width,
                      FT_UInt  pixel_height );

简单来说就是,设置face后面产生的字形的宽度和高度(单位是像素),此处如果宽度和高度有一个写为0,表示这个参数的值和另一个参数的值一样。

  if ( pixel_width == 0 )
      pixel_width = pixel_height;
    else if ( pixel_height == 0 )
      pixel_height = pixel_width;

所以此处就是设置宽度和高度都为font_size,然后这个font_size默认是24(main里的初始化),可以通过执行程序时的参数来修改。

    if (argc == 5)
       font_size = strtoul(argv[4], NULL, 0);   

stroul函数把char类型的数字变成int类型的数字。函数声明如下:

strtoul(
    _In_z_                   char const* _String,
    _Out_opt_ _Deref_post_z_ char**      _EndPtr,
    _In_                     int         _Radix
    );

第一个参数是要转化的字符串的指针,第二个参数直接NULL就行,第三个参数是进制,0表示默认,默认是10进制。stroul的具体可看这篇文章

display_string函数

接下来就是关于display_string函数的相关内容,主要做的就是循环地处理每个字形,然后获取每个字形的LCD坐标,调用draw_bitmap函数写到LCD映射的内存去,从而显示出来,主要是要掌握对坐标的理解还有对freetype函数的理解。

原点的坐标乘64

    pen.x = (x - bbox.xMin) * 64; /* 单位: 1/64像素 */
    pen.y = (y - bbox.yMax) * 64; /* 单位: 1/64像素 */

我一度很纠结这个东西,现在反正你别管,人家freetype就是要求你的像素,你的坐标要乘以64,你就乘吧。具体地话,因为freetype里边不止用像素这个单位,还有用pt(point)英镑等单位,可以表示更精细的东西,反正这就是freetype的设计,别纠结了,咱们只是用这个库而已。还有关于原点,这个视频里有讲。
此处这两行分别表示在LCD上的某个点,这个点的坐标使用的是笛卡尔坐标系,是一个绝对的坐标。主要是给后面FT_Set_Transform函数使用的。这个后面讲。

循环处理每个字形

for (i = 0; i < wcslen(wstr); i++)
    {
        /* 转换:transformation */
        FT_Set_Transform(face, 0, &pen);
        /* 加载位图: load glyph image into the slot (erase previous one) */
        error = FT_Load_Char(face, wstr[i], FT_LOAD_RENDER);
        if (error)
        {
            printf("FT_Load_Char error\n");
            return -1;
        }
        /* 在LCD上绘制: 使用LCD坐标 */
        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;
    }

一个一个函数来看:

FT_Set_Transform函数

FT_Set_Transform(face, 0, &pen);
老规矩,看函数声明

  FT_Set_Transform( FT_Face     face,
                    FT_Matrix*  matrix,
                    FT_Vector*  delta )
  • matrix: 一个矩阵,主要是做一些旋转啊什么的变化,我不懂不重要

  • delta: 原点怎么变化?原点定在哪里?
    此处的delta是指在LCD屏幕上,使用笛卡尔坐标系,原点的位置。
    传入这个原点在LCD上的坐标之后,freetyep才能够计算出某个字形的左上角边框在LCD坐标系里的坐标,不然freetype得到的只是某个字形基于原点的相对位置,而这个相对位置和LCD没关系,不能作为参数给draw_bitmap函数

    为什么要知道LCD左上角坐标? 因为我们的draw_bitmap函数(自己写的)的实现逻辑就是从位图的左上角开始写。

FT_Load_char函数

error = FT_Load_Char(face, wstr[i], FT_LOAD_RENDER);
先看声明吧:

FT_Load_Char( FT_Face   face,
                FT_ULong  char_code,
                FT_Int32  load_flags )

这个函数,做了一下几件事情

  1. 通过char_code(unicode)查找他所对应的字形
  2. 把字形用FT_LOAD_RENDER的模式绘制,这个FT_LOAD_RENDER表示加载位图的意思
  3. 把加载好的位图+相关信息放到face->glyph.bitmap(slot->bitmap)里去

draw_bitmap函数

       draw_bitmap( &slot->bitmap,
                        slot->bitmap_left, //边框的左上部分
                        var.yres - slot->bitmap_top);
  • 为什么突然出现了一个slot?我在前面没有处理过他啊?他的值又是怎么变化的?
    此处的slot是一个指针,类型是FT_GlyphSlot
    FT_GlyphSlot slot = face->glyph;
    这个类型是一个指针,指向FT_GlyphSlotRec_结构体: typedef struct FT_GlyphSlotRec_* FT_GlyphSlot;
    反正你只需要知道他是个指针,此处不是建立了一个新的结构体,而是建立一个指针指向原来face里的某个东西(glyphslot),这个东西里面有我们想要的bitmap。

此处的slot->bitmap_left和slot->bitmap_top,我存有疑惑,有谁知道还请解答下,根据官方文档所说的,

Note that bitmap_left is the horizontal distance from the current pen position to the leftmost border of the glyph bitmap, while bitmap_top is the vertical distance from the pen position (on the baseline) to the topmost border of the glyph bitmap. It is positive to indicate an upwards distance.

意思大概是说left是相对于原点的距离,top是相对于原点所在的基线的垂直距离,总而言之就是说他是相对于原点的距离,但是我在调试的过程中发现他是一个绝对距离,指向的是一个字符边框的左上角。这里我就不太理解了,望大神解答。

同时需要注意这个坐标(slot->bitmap_left,slot->bitmap_top)是笛卡尔坐标系,要给lcd显示函数当参数要转为lcd的坐标系,所以使用var.yres(lcd上纵坐标上的像素点)减掉slot->bitmap_top得到实际的适用于lcd坐标系的坐标。

参考

参考文档:freetype官方教程
【硬核】韦东山:使用freetype显示一行文字
px pt sp dp dip dpi ppi ,不再傻傻分不清
pt和px有什么区别?pt和px如何转换?

  • 18
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值