Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >【硬核】韦东山:使用freetype显示一行文字

【硬核】韦东山:使用freetype显示一行文字

作者头像
韦东山
发布于 2020-09-30 03:24:46
发布于 2020-09-30 03:24:46
2K01
代码可运行
举报
文章被收录于专栏:韦东山嵌入式韦东山嵌入式
运行总次数:1
代码可运行

6.6 使用freetype显示一行文字 使用GIT下载所有源码后,本节源码位于如下目录: 01_all_series_quickstart 04_嵌入式Linux应用开发基础知识\source\10_freetype 04_show_line\show_line.c

Git下载地址: https://e.coding.net/weidongshan/01_all_series_quickstart.git

本节的目的: 在LCD上指定一个左上角坐标(x, y),把一行文字显示出来。下图中,文字的外框用虚线表示,外框的左上角坐标就是(x, y)。

6.6.1 笛卡尔坐标系 在LCD的坐标系中,原点在屏幕的左上角。对于笛卡尔坐标系,原点在左下角。freetype使用笛卡尔坐标系,在显示时需要转换为LCD坐标系。

从下图可知,X方向坐标值是一样的。 在Y方向坐标值需要换算,假设LCD的高度是V。 在LCD坐标系中坐标是(x, y),那么它在笛卡尔坐标系中的坐标值为(x, V-y)。 反过来也是一样的,在笛卡尔坐标系中坐标是(x, y),那么它在LCD坐标系中坐标值为(x, V-y)。

6.6.2 每个字符的大小可能不同 在使用FT_Set_Pixel_Sizes函数设置字体大小时,这只是“期望值”。比如“百问网www.100ask.net”,如果把“.”显示得跟其他汉字一样大,不好看。

所以在显示一行文字时,后面文字的位置会受到前面文字的影响。 幸好,freetype帮我们考虑到了这些影响。

对于freetype字体的尺寸(freetype Metrics),需要参考下图这个文档:

上述文档中列出了一个图,摘录如下:

在显示一行文字时,这些文字会基于同一个基线来绘制位图:baseline。 在baseline上,每一个字符都有它的原点(origin),比如上图中baseline左边的黑色圆点就是字母“g”的原点。当前origin加上advance就可以得到下一个字符的origin,比如上图中baseline右边的黑色圆点。在显示一行中多个文件字时,后一个文字的原点依赖于前一个文字的原点及advance。 字符的位图是有可能越过baseline的,比如上图中字母“g”在baseline下方还有图像。

上图中红色方框内就是字母“g”所点据的位图,它的四个角落不一定与原点重合。

上图中那些xMin、xMax、yMin、yMax如何获得?可以使用

FT_Glyph_Get_CBox函数获得一个字体的这些参数,将会保存在一个FT_BBox结构体中,以后想计算一行文字的外框时要用到这些信息:

6.6.3 怎么在指定位置显示一行文字 要显示一行文字时,每一个字符都有自己外框:xMin、xMax、yMin、yMax。把这些字符的xMin、yMin中的最小值取出来,把这些字符的xMax、yMax中的最大值取出来,就可以确定这行文字的外框了。 要想在指定位置(x, y)显示一行文字,步骤如下图所示:

① 先指定第1个字符的原点pen坐标为(0, 0),计算出它的外框 ② 再计算右边字符的原点,也计算出它的外框 把所有字符都处理完后就可以得到一行文字的整体外框:假设外框左上角坐标为(x’, y’)。 ③ 想在(x, y)处显示这行文字,调整一下pen坐标即可

怎么调整? pen为(0, 0)时对应左上角(x’, y’); 那么左上角为(x, y)时就可以算出pen为(x-x’, y-y’)。

6.6.4 freetype的几个重要数据结构 要想形象地理解程序,需要先介绍一下freetype中几个数据结构:

  1. FT_Library 对应freetype库,使用freetype之前要先调用以下代码:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
FT_Library  library; /* 对应freetype库 */
error = FT_Init_FreeType( &library ); /* 初始化freetype库 */
  1. FT_Face 它对应一个矢量字体文件,在源码中使用FT_New_Face函数打开字体文件后,就可以得到一个face。 为什么称之为face? 估计是文字都是写在二维平面上的吧,正对着人脸?不用管原因了,总之认为它对应一个字体文件就可以。 代码如下:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
error = FT_New_Face(library, font_file, 0, &face ); /* 加载字体文件 */
  1. FT_GlyphSlot 插槽?用来保存字符的处理结果:比如转换后的glyph、位图,如下图:

一个face中有很多字符,生成一个字符的点阵位图时,位图保存在哪里?保存在插槽中:face->glyph。 生成第1个字符位图时,它保存在face->glyph中;生成第2个字符位图时,也会保存在face->glyph中,会覆盖第1个字符的位图。 代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
FT_GlyphSlot  slot = face->glyph; /* 插槽: 字体的处理结果保存在这里 */
  1. FT_Glyph 字体文件中保存有字符的原始关键点信息,使用freetype的函数可以放大、缩小、旋转,这些新的关键点保存在插槽中(注意:位图也是保存在插槽中)。 新的关键点使用FT_Glyph来表示,可以使用这样的代码从slot中获得glyph:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
error = FT_Get_Glyph(slot , &glyph);
  1. FT_BBox FT_BBox结构体定义如下,它表示一个字符的外框,即新glyph的外框:

可以使用以下代码从glyph中获得这些信息:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_TRUNCATE, &bbox );

针对上述流程,示例代码如下:

6.6.5 计算一行文字的外框 前面提到过,一行文字中:后一个字符的原点=前一个字符的原点+advance。 所以要计算一行文字的外框,需要按照排列顺序处理其中的每一个字符。 代码如下,注释写得很清楚了:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
102 int compute_string_bbox(FT_Face       face, wchar_t *wstr, FT_BBox  *abbox)
103 {
104     int i;
105     int error;
106     FT_BBox bbox;
107     FT_BBox glyph_bbox;
108     FT_Vector pen;
109     FT_Glyph  glyph;
110     FT_GlyphSlot slot = face->glyph;
111
112     /* 初始化 */
113     bbox.xMin = bbox.yMin = 32000;
114     bbox.xMax = bbox.yMax = -32000;
115
116     /* 指定原点为(0, 0) */
117     pen.x = 0;
118     pen.y = 0;
119
120     /* 计算每个字符的bounding box */
121     /* 先translate, 再load char, 就可以得到它的外框了 */
122     for (i = 0; i < wcslen(wstr); i++)
123     {
124         /* 转换:transformation */
125         FT_Set_Transform(face, 0, &pen);
126
127         /* 加载位图: load glyph image into the slot (erase previous one) */
128         error = FT_Load_Char(face, wstr[i], FT_LOAD_RENDER);
129         if (error)
130         {
131             printf("FT_Load_Char error\n");
132             return -1;
133         }
134
135         /* 取出glyph */
136         error = FT_Get_Glyph(face->glyph, &glyph);
137         if (error)
138         {
139             printf("FT_Get_Glyph error!\n");
140             return -1;
141         }
142
143         /* 从glyph得到外框: bbox */
144         FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_TRUNCATE, &glyph_bbox);
145
146         /* 更新外框 */
147         if ( glyph_bbox.xMin < bbox.xMin )
148             bbox.xMin = glyph_bbox.xMin;
149
150         if ( glyph_bbox.yMin < bbox.yMin )
151             bbox.yMin = glyph_bbox.yMin;
152
153         if ( glyph_bbox.xMax > bbox.xMax )
154             bbox.xMax = glyph_bbox.xMax;
155
156         if ( glyph_bbox.yMax > bbox.yMax )
157             bbox.yMax = glyph_bbox.yMax;
158
159         /* 计算下一个字符的原点: increment pen position */
160         pen.x += slot->advance.x;
161         pen.y += slot->advance.y;
162     }
163
164     /* return string bbox */
165     *abbox = bbox;
166 }

6.6.6 调整原点并绘制 代码如下,也不复杂:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
169 int display_string(FT_Face     face, wchar_t *wstr, int lcd_x, int lcd_y)
170 {
171     int i;
172     int error;
173     FT_BBox bbox;
174     FT_Vector pen;
175     FT_Glyph  glyph;
176     FT_GlyphSlot slot = face->glyph;
177
178     /* 把LCD坐标转换为笛卡尔坐标 */
179     int x = lcd_x;
180     int y = var.yres - lcd_y;
181
182     /* 计算外框 */
183     compute_string_bbox(face, wstr, &bbox);
184
185     /* 反推原点 */
186     pen.x = (x - bbox.xMin) * 64; /* 单位: 1/64像素 */
187     pen.y = (y - bbox.yMax) * 64; /* 单位: 1/64像素 */
188
189     /* 处理每个字符 */
190     for (i = 0; i < wcslen(wstr); i++)
191     {
192         /* 转换:transformation */
193         FT_Set_Transform(face, 0, &pen);
194
195         /* 加载位图: load glyph image into the slot (erase previous one) */
196         error = FT_Load_Char(face, wstr[i], FT_LOAD_RENDER);
197         if (error)
198         {
199             printf("FT_Load_Char error\n");
200             return -1;
201         }
202
203         /* 在LCD上绘制: 使用LCD坐标 */
204         draw_bitmap( &slot->bitmap,
205                         slot->bitmap_left,
206                         var.yres - slot->bitmap_top);
207
208         /* 计算下一个字符的原点: increment pen position */
209         pen.x += slot->advance.x;
210         pen.y += slot->advance.y;
211     }
212
213     return 0;
214 }

6.6.7 上机实验 编译命令(如果你使用的交叉编译链前缀不是arm-buildroot-linux-gnueabihf,请自行修改命令):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ arm-buildroot-linux-gnueabihf-gcc  -o  show_line  show_line.c   -lfreetype 

将编译好的show_line文件与simsun.ttc字体文件拷贝至开发板,这2个文件放在同一个目录下,然后执行以下命令(其中的3个数字分别表示LCD的X坐标、Y坐标、字体大小):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[root@board:~]# ./show_line ./simsun.ttc 10 200 80
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020/08/13 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Linux应用开发:嵌入式Linux下矢量字体运用
FreeType库是一个完全免费(开源)的、高质量的且可移植的字体引擎,它提供统一的接口来访问多种字体格式文件,可以非常方便我们开发字体显示相关的程序功能。它支持单色位图、反走样位图的渲染。FreeType库是高度模块化的程序库,虽然它是使用ANSI C开发,但是采用面向对象的思想,因此,FreeType的用户可以灵活地对它进行裁剪。关于freetype的详细信息可以参考freetype的官方网站:https://www.freetype.org/来获取更多相关的信息。
DS小龙哥
2022/01/12
4.6K0
Linux应用开发:嵌入式Linux下矢量字体运用
百问LCD Framebuffer应用开发 - freetype搭建与使用
​ 由于100ask开发板已经有freetype相关的库和头文件,因此不需要移植,如果开发板没有freetype库和头文件就需要按以下方法移植
阿志小管家
2024/11/26
1150
百问LCD Framebuffer应用开发 - freetype搭建与使用
嵌入式Linux下LCD应用编程: 读取摄像头画面完成本地视频监控画面显示
完整项目代码下载地址(包含矢量字库源码和编译安装方法): https://download.csdn.net/download/xiaolong1126626497/16680219
DS小龙哥
2022/01/12
2.3K0
嵌入式Linux下LCD应用编程: 读取摄像头画面完成本地视频监控画面显示
freetype的交叉编译及在嵌入式linux上的简单使用及改变字体背景和颜色
FreeType库是一个完全免费(开源)的、高质量的且可移植的字体引擎,它提供统一的接口来访问多种字体格式文件,包括TrueType, OpenType, Type1, CID, CFF, Windows FON/FNT, X11 PCF等。它支持单色位图、反走样位图的渲染。FreeType库是高度模块化的程序库,虽然它是使用ANSI C开发,但是采用面向对象的思想,因此,FreeType的用户可以灵活地对它进行裁剪。关于freetype的详细信息可以参考freetype的官方网站:https://www.freetype.org/来获取更多相关的信息。
杨永贞
2020/12/16
5.3K0
freetype的交叉编译及在嵌入式linux上的简单使用及改变字体背景和颜色
Linux应用开发【第一章】Framebuffer应用开发
​ LCD Framebuffer 就是一块显存,在嵌入式系统中,显存是被包含在内存中。LCD Framebuffer里的若干字节(根据驱动程序对LCD控制器的配置而定)表示LCD屏幕中的一个像素点,一一对应整个LCD屏幕。举个例子,LCD屏幕是800*600的分辨率,即LCD屏幕存在480000个像素点,若每个像素点4个字节表示,那么LCD Framebuffer显存大小为480000 *4=960000字节,即1.92MB。因此我们的内存将会分割至少1.92MB的空间用作显存。具体地址在哪里,这个就是又驱动程序去定,应用程序只需直接使用即可,硬件相关操作已由驱动程序封装好。
韦东山
2021/12/15
1.9K0
Linux应用开发【第一章】Framebuffer应用开发
OpenGL ES 文字渲染
在音视频或 OpenGL 开发中,文字渲染是一个高频使用的功能,比如制作一些酷炫的字幕、为视频添加水印、设置特殊字体等等。
字节流动
2021/06/24
1.9K0
OpenGL ES 文字渲染
Linux小项目-数码相册设计
这是基于Linux系统开发板设计一个小项目-数码相册,在LCD屏上可以显示完成常见的图片显示,翻页、旋转、缩放等功能。
DS小龙哥
2022/05/11
1.4K0
Linux小项目-数码相册设计
OpenGL ES 文字渲染进阶--渲染中文字体
旧文 OpenGL ES 文字渲染方式有几种? 一文中分别介绍了 OpenGL 利用 Canvas 和 FreeType 绘制文字的方法。 无论采用哪种方式进行渲染,本质上原理都是纹理贴图:将带有文字的图像上传到纹理,然后进行贴图。
字节流动
2021/07/05
1.4K0
OpenGL ES 文字渲染进阶--渲染中文字体
38.opengl-字体渲染
早期的文本渲染,是将需要的字符集放到一个大纹理中,这个纹理称为“位图字体”,渲染某个字符时,通过查找坐标,找到该字符对应的区域并渲染出来,再启动混合,让字符纹理的背景保持透明,非常容易理解。
公号sumsmile
2020/10/10
1.8K0
38.opengl-字体渲染
Web 中文字体性能优化实践
Web 项目中,使用一个适合的字体能给用户带来良好的体验。但是字体文件这么多,如果设计师或者开发人员想要查询字体,只能一个个打开,非常影响工作效率。我负责的平台项目刚好需要实现一个功能,能够支持根据固定文字以及用户输入预览字体。在实现这一功能的过程中主要解决两个问题:
winty
2020/09/24
2.4K0
Web 中文字体性能优化实践
身份证识别——生成身份证号和汉字
该文介绍了利用基于深度学习的中文字符切分方法,该方法采用CNN提取字符的特征,并用SVM进行分类,最后用生成模型进行字符的切分。同时,该文还介绍了如何使用卷积神经网络来提取字符的上下文信息,以提高切分准确率。
MachineLP
2018/01/09
15.3K0
Matlab中axis函数使用
坐标轴范围,指定为包含 4 个、6 个或 8 个元素的向量。对于笛卡尔坐标区,以下列形式之一指定范围:
全栈程序员站长
2022/09/02
3.7K0
Matlab中axis函数使用
Matlab系列之二维图形(上)
上一篇已经对图形的属性有过介绍,在此基础上来进行二维以及后续三维图形的操作(注:没接触过其他维度的操作,就不折腾相关的内容了),将会更容易理解这些属性的用法,当然,全部的属性使用都来一遍,感觉就不太实际了,大可不必~
狂人V
2021/03/10
1.9K0
Python验证码识别
最近在做爬虫的时候发现手动输入验证码算是比较烦了,就网上搜了一下,结果发现真的有现成的,作者:老板丶鱼丸粗面,写的很完整,看一下。所有源码点击阅读原文。
我被狗咬了
2019/09/23
2.9K0
Python验证码识别
woff字体图元结构剖析,自定义字体的制作与匹配和识别
前面我在2万字硬核剖析网页自定义字体解析(css样式表解析、字体点阵图绘制与本地图像识别等)一文中,讲解了通过图像识别来解析自定义字体,但是图像识别的缺点在于准确率并不能达到100%,还需要二次修改。
Python进阶者
2021/12/17
8K0
woff字体图元结构剖析,自定义字体的制作与匹配和识别
口罩检测识别率惊人,这个Python项目开源了
昨天在 GitHub 上看到一个有趣的开源项目,它能检测我们是否有戴口罩,跑起程序测试后,发现识别率挺高的,也适应不同环境,于是分享给大家。
AI科技大本营
2020/03/10
3.4K1
口罩检测识别率惊人,这个Python项目开源了
【目标检测】数据增强:YOLO官方数据增强实现/imgaug的简单使用
由于自己的数据比较少,因此想采用数据增强的方式来扩充自己的数据集,对于目标检测任务而言,除了需要改变原始图像外,还需要对目标框进行相应的变化。
zstar
2022/09/20
8.5K0
【目标检测】数据增强:YOLO官方数据增强实现/imgaug的简单使用
Matlab中的画图函数
之前在进行Matlab编程时,画图总是非常重要的一部分,在这里整理一下常用的绘图函数,以作备用。
全栈程序员站长
2022/11/06
3.5K0
Matlab中的画图函数
Python数据可视化-第3章-图表辅助元素的定制
图表的辅助元素是指除了根据数据绘制的图形之外的元素,常用的辅助元素包括坐标轴、标题、图例、网格、参考线、参考区域、注释文本和表格,它们都可以对图形进行补充说明。
用户2225445
2025/03/31
1140
Python数据可视化-第3章-图表辅助元素的定制
使用视觉语言模型(VLMs)进行目标检测
在过去,你必须自己训练模型,收集训练数据,但现在许多基础模型允许你在它们的基础上进行微调,以获得一个能够检测目标并与用户用自然语言互动的系统。有数百种模型和潜在应用场景,目标检测在这些场景中非常有用,尤其是随着小型语言模型的兴起,所以今天我们将尝试使用MLX上的Qwen2-VL-7B-Instruct-8bit。
小白学视觉
2024/12/05
2550
使用视觉语言模型(VLMs)进行目标检测
推荐阅读
相关推荐
Linux应用开发:嵌入式Linux下矢量字体运用
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验