转载自:https://blog.csdn.net/tianyuan521521/article/details/46273407

前言
最近在做一款激光打标控制的产品,我的思路是将所有的图元矢量化,但是当做到文字矢量化的时候,真是让我想破了脑袋,后来搜索得知了GetGlyphOutline,就是一个WINAPI,众所周知,WINAPI大都需要一个HDC,但是我使用的Qt,这样就出现了几个问题:

Qt中的控件有些是直接渲染的,很难直接获取控件句柄-
不跨平台,以后这一块还是要重写
VC的各种变量类型写在Qt里面,调试起来真是一团糟
做了些实验以后,发现这种方法实在是缘木求鱼,然后轻易地搜索到了freeType这一款优秀的字体引擎,下面我们就开始对freetype的探索。

所需基本知识点
trueType字体的一些基本概念
字体(font):不同字符图像的集合

字体外观(font face):一个外观对应一个(.ttf)文件,但是一个字体家族可能占用多个字体文件,因为它包括多种外观,比如字体族Arial,它包括两种外观,于是就有 arial.ttf对应Arial Regular外观,ariali.ttf对应Arial Italic外观,我们习惯把Arial Regular也称为一种字体,实际上它只是一种字体外观

字体文件的基本结构:一般里面有一个或多个字符图(charmap),不同的字符图一般标识不同的平台,所以在一种平台上一般只有一种字符图,这个字符图可以宏观简单的理解为一个key-value,key-字符索引一般就是字符对应编码的编码值,value(字符构成)在truetype一般是对其矢量图形的描述,我们只要将字符编码对应的矢量图形描述得到,就可以进行随心所欲的处理了

trueType字体的基本构成
首现说一下字体轮廓,拿我自己解析出来的一个例子来说吧(这是俺的大名:)): 
 
渲染出来的矢量还是不错的! 
轮廓线就是字体轮廓中一条条的封闭曲线: 
 
红色箭头标注的就是字体轮廓线,共有两条;每条轮廓线又由其他直线或曲线组成:

直线
二次Bezier曲线
freetype官方说明字体曲线可能包含有(三次Bezier曲线),但经过我的实验以及其他官方资料,truetype字体并不含有三次Bezier曲线
besier曲线定义
由于此处只用到一次贝塞尔(有界直线)和二次贝塞尔曲线 
给定点P0、P1,线性bezier曲线只是一条两点之间的直线。这条线由下式给出,且其等同于线性插值。 
 
二次方bezier曲线的路径由给定点P0、P1、P2的函数B(t)追踪: 
 
按照上述插值规则,如果t分割的足够密,就可以得到平滑的曲线

freetype对trueType的解析
解析基本步骤
开始
freetype字体初始化
设置字符编码方式
获取字符对应的编码值
查charmap表获取编码值的索引
根据索引获取轮廓描述
对获取到的轮廓数据进行补偿
相关渲染和处理
结束
freetype字体库初始化(省略了变量声明)
int  error = FT_Init_FreeType( &library );
    if(error)
    {
        printf("load freetype errror!");
    }
    error = FT_New_Face(library,fontFilePath.toStdString().c_str() ,0,&face);
    if ( error == FT_Err_Unknown_File_Format )
        {
        printf("FT_Err_Unknown_File_Format");
    }
    else if(error)
    {
        printf(" another error code means that the font file could not  or simply that it is broken...");
    }
    error = FT_Set_Pixel_Sizes(face, /* handle to face object */
                                      0, /* pixel_width */
                                   8 );/* pixel_height */
    if(error)
    {
        printf("char size set error");
    }

设置字体编码方式
只需一句代码

FT_Select_Charmap(face,FT_ENCODING_UNICODE);

获取字符编码值
wchar_t charX= L'元';

对字体轮廓进行解析
这里我们需要先对FT_Outline这个freetype内置结构体做一个说明: 
FT_Outline

n_points:轮廓中的点数
n_contours 轮廓中轮廓线数
points 点坐标数组
contours 轮廓线端点索引数组
tags 点标记数组
注意:下方全程高能 
这里,points是一个FT_Vector记录数组的指针,用来存储每个轮廓点的向量坐标。它表示为一个象素1/64,也叫做26.6固定浮点格式。 
contours是一组点索引,用来划定轮廓的轮廓线。例如,第一个轮廓线总是从0点开始,以contours[0]点结束。第二个轮廓线从contours[0]+1点开始,以contours[1]结束,等等。 
注意,每条轮廓线都是封闭的,n_points应该和contours[n_controus-1]+1相同。最后,tags是一组字节,用来存放每个轮廓的点标记。 
从这儿,大家可能就会感觉以下的步骤很麻烦了!是的,至少会需要两层循环,这还不算完,最难处理的是下面这一堆规定:

轮廓内部点规则描述
每条弧由一系列起点、终点和控制点描述,轮廓的每个点有一个特定的标记,表示它用来描述一个线段还是一条弧。这个标记可以有以下值:
FT_Curve_Tag_On 当点在曲线上,这对应线段和弧的起点和终点。其他标记叫做“Off”点,即它不在轮廓线上,但是作为Bezier弧的控制点。
FT_Curve_Tag_Conic 一个Off点,控制一个conic Bezier弧
FT_Curve_Tag_Cubic 一个Off点,控制一个cubic Bezier弧
下面的规则应用于将轮廓点分解成线段和弧 z 两个相邻的“on”点表示一条线段;
弧z 一个conic Off(二次bezier曲线控制点)在两个on点之间表示一个conic Bezier(二次bezier)弧,off点是控制点,on点是起点和终点;
两个相邻的cubic off(三次bezier曲线控制点)点在两个on点之间表示一个cubic Bezier(三次bezier)弧,它必须有两个cubic控制点和两个on 
点。
两个相邻的conic off(二次bezier曲线控制点)强制在它们正中间创建一个虚拟的on点(坐标为两者中点)。这大大方便定义连续的conic弧。TrueType规范就是这么定义的。
轮廓端点规则描述
如果轮廓的首尾点均为FT_Curve_Tag_On,则不需做任何处理
如果轮廓首点为FT_Curve_Tag_Conic,尾点为FT_Curve_Tag_On,就将尾点作为第一条bezier曲线的首点
如果轮廓首点为FT_Curve_Tag_On,尾点为FT_Curve_Tag_Conic,就将首点作为最后一条bezier曲线的尾点
如果首尾点均为FT_Curve_Tag_Conic,则取两者平均值分别作为第一条bezier曲线的首点和最后一条曲线的尾点。
规则总结
这一串规则看起来非常复杂晦涩,其实总结一下就是,每个轮廓点就是是一个’圆环’的点集,当出现相邻的bezier控制点后,就补偿一个中值。最后,我们’拆环’就可以了

解析算法描述
获取outline中的各个值
单个轮廓线首尾索引值获取
首端点补偿
中点连续的控制点的中值补偿
尾端点补偿
拆分成一段段独立bezier曲线
结束
单个轮廓线首尾索引值获取
单个轮廓线首尾索引值获取
第几条轮廓线
是否是第0条 ?
索引值 0~outline->contours[0]
处理完毕
索引值 outline->contours[contourIndex -1] +1~outline->contours[contourIndex]
yes
no
首尾端点补偿
按照上述规则即可,具体看附件工程
1
中值补偿
也是按照上述规则

很多东西看代码比较直接,附上大家最想要的完整工程,记得改一下pro文件里面的lib目录路径:

国内首篇利用freetype的跨平台truetype字体真正轮廓(非位图)获取相关推荐

  1. 国内首篇介绍JanOS物联网操作系统的文章 - 如何把你的手机主板打造成物联网

    天地会珠海分舵注:如无意外,您现在正在看的将是国内首篇且是唯一一篇介绍炙手可热的物联网的操作系统JanOS的文章!不信你去百度!希望大家能喜欢.但本文只是引言,更多信息请还是访问JanOS的官网:ht ...

  2. 国内首篇云厂商 Serverless 论文入选全球顶会:突发流量下,如何加速容器启动?

    简介:USENIX ATC (USENIX Annual Technical Conference) 学术会议是计算机系统领域的顶级会议,入选中国计算机协会(CCF)推荐 A 类国际会议列表:本次会议 ...

  3. [ 攻防演练演示篇 ] 利用通达OA 文件上传漏洞上传webshell获取主机权限

  4. 武大上交发布首篇「图像匹配」大领域综述!涵盖 8 个子领域,汇总近 20年经典方法

    原文链接:https://bbs.cvmart.net/topics/3176 专注计算机视觉前沿资讯和技术干货 微信公众号:极市平台 官网:https://www.cvmart.net/ 武汉大学和 ...

  5. 国内首个违反GPL的案件介绍

    <几种常见的软件开源协议介绍>文章中我们提到了几种常见的软件开源协议,碰巧的是,CSDN的这篇<违反GPL协议赔偿50万,国内首例!>文章就介绍了一个因为违反GPL协议的案例, ...

  6. 关注Android安全 手机锁屏勒索国内首现身

    觉得这篇文章不错,咱也能看懂,就转载过来了,要转载别的网站文章,上传图片好蛋疼.O(∩_∩)O哈哈~,希望看完这篇文章能让我们对Android安全有点思考. 原文链接 手机锁屏勒索国内首现身 by 张 ...

  7. 听见丨苹果发表首篇公开披露自动驾驶技术的论文 「怪兽充电」再获 2 亿元新一轮融资

    苹果发表首篇公开披露自动驾驶技术的论文 据路透社报道,两名正在研究自动驾驶技术的苹果计算机科学家最近在网上分享了一篇描述自驾车如何使用更少的传感器来发现骑车人和行人的研究论文.论文作者是 Yin Zh ...

  8. 国内首场高规格AIGC峰会盛况出圈!万字干货热聊GPT-4时代,浓缩21位大牛演讲

    智东西(公众号:zhidxcom) 作者 | 程茜.李水青 编辑 | 心缘 智东西3月24日报道,今日,GTIC 2023中国AIGC创新峰会在北京圆满举行! 正值GPT-4时代的大幕被一把拉开,本届 ...

  9. AI+Science系列(二):国内首个基于AI框架的CFD工具组件!赛桨v1.0 Beta API介绍以及典型案例分享!

    AI for Science被广泛认为是下一代科研范式,可以有效处理多维度.多模态.多场景下的模拟和真实数据,解决复杂推演计算问题,加速新科学问题发现[1] .百度飞桨科学计算工具组件赛桨Paddle ...

最新文章

  1. select,poll,epoll区别。
  2. url传参参数编码的解码问题
  3. Lambda 表达式的应用
  4. webservice axis1.4生成客户端
  5. Byte Cup 2018机器学习大赛进入冲刺阶段,最全资料帮你快速上手!
  6. 职称计算机应用能力考试模拟题,2016年职称计算机考试模拟题
  7. 重磅官宣:Nacos2.0性能提升10倍
  8. js中判断值不等于undefined
  9. byte[]、sbyte[]、int[]以及Array的故事
  10. 【python】输出到文件, f.write与print
  11. android listview动态添加viewpager,向 ViewPager 中添加 包含 ListView 的 Fragment
  12. Unity Shaders and Effects Cookbook (3-4) 使用高光贴图
  13. C#调用c++Dll结构体数组指针的问题
  14. Mybatis源码分析之Mapper文件解析
  15. Java电商项目-5.内容管理cms系统
  16. navicat8 for mysql注册码
  17. macd是什么意思?散户股民如何使用MACD应对证券牛市市场
  18. PyCharm下载和安装教程
  19. python函数写法_python函数的写法和调用
  20. 浏览器-点击预览视频文件(自动播放、循环播放)

热门文章

  1. 全同态加密 (FHE) 框架
  2. 2021年移动开发者未来的出路在哪里,年薪50W
  3. 火狐浏览器使用拼写检查
  4. EMC 共模电感选型
  5. 电脑之间如何迁移数据?数据迁移方法描述
  6. 在合并单元格设置编号—“count-a函数”的使用
  7. bootstrap图片叠加_详解Bootstrap四种图片样式
  8. spring cloud alibaba整合sentinel
  9. 【NLP】Python NLTK 走进大秦帝国
  10. 土壤湿度传感器YL69使用