化繁为简、性能提升 -- 在WPF程序中,使用Freetype库心得
本人使用WPF开发了一款OFD阅读器,显示字体是阅读器中最重要的功能。处理字体显示有多种方案,几易其稿,最终选用Freetype方案。本文对WPF中如何使用Freetype做简单描述。
OFD中有两种字体:嵌入字体和非嵌入字体。1) 非嵌入字体就是只提供字体名称,不提供字体对应的文件。2)嵌入字体:提供字体文件,字体名称是啥并不影响显示。由于阅读器中需要显示大量文本,必须采用最优的方式显示,否则性能难以满足要求。
WPF字体显示有多种方案。 通常可以将文本呈现分为三层:
- 直接使用 Glyphs 和 GlyphRun 对象。
- 使用 FormattedText 对象。
- 使用高级控件,如 TextBlock 和 FlowDocument 对象。
第三种方案,显然不合适,可行的只有第一和第二种方案。对于嵌入字体,必须采用第一种方案;非嵌入字体可以采用第一和第二种方案。总之,可以采用第三种方案解决一切字体问题。
但是,本人在使用GlyphRun 过程中,遇到很多奇怪的问题,有两方面原因导致的:
1)越底层的功能使用的人越少,缺少相应资料。
2)微软在开放底层功能上犹抱琵琶半遮面,导致使用过程中不知所以然,遇到问题难以解决。
本人开发的OFD阅读器最初采用了WPF自带字体方案,遇到很多坑,还有一些坑无论如何也解决不了。痛定思痛,决定采用Freetype库显示字体;经过一番折腾,终于成功了。
历经曲折,获得一番感悟:微软为了使开发者开发更方便,屏蔽了太多底层的东西;这导致开发人员遇到问题时无所适从。不要紧盯着微软不放;另辟蹊径,反而柳暗花明又一村。
使用Freetype显示字体前,需要弄明白字体的本质;字体的本质就是一系列曲线和对应的unicode编码;显示字体就是画曲线,和画一条直线、圆等没有区别。 unicode编码是为了交互用的,从阅读器上复制一行字,其实就是复制字体的unicode编码。字体除了这些属性以外,还有很多概念:字体高度、行间距、baseline、原点等。
使用Freetype,就需要获取每个字体对应的曲线和字体相关的一些列属性。但是,Freetype是用c语言开发的,导出的函数接口难以与c#交互,需要在Freetype的基础上再次封装,以方便c#调用。以获取字体对应的曲线为例,阐述如何进一步封装Freetype。
我们见到的曲线多种多样;但是从底层来看,所有的曲线可分为两类:直线和贝塞尔曲线。这些恰好对应OFD的图形对象(PathObject),看下图:

OFD文件中一段图形对象:

阅读器处理PathObject时,就需要解析这些字符串,生成对应的曲线。Freetype也需要从字库中解析出曲线,其对应的函数是非常复杂的,摘录一段函数:

很显然,c#无法直接使用;考虑PathObject的描述方式,本人眼前一亮,何不将字体曲线描述为PathObject方式,对外输出字符串。函数接口定义如下:
extern "C" FREETYPELIB_EXPORT INT32 Freetype_GetTextPath(UINT64 handle,
UINT32 nGlyphIndex, INT32 fontSize, char* textPath, INT32 textPathLen);
textPath包含曲线信息,其格式与OFD中的PathObject规范一致,我们就可以用处理PathObject的方式处理字体。
WPF显示曲线使用PathGeometry,需要将textPath转换为PathGeometry。再而,我们就可以使用WPF类DrawingContext画出曲线
class DrawingContext
{
public abstract void DrawGeometry(Brush brush, Pen pen, Geometry geometry);
......
}
至此,字体就可以显示出来了。通过这一番操作,我们也对字体的本质有更加深刻的了解。前文只是简单对显示字体做了讲述,要正确处理字体还有大量的工作要做。
Freetype性能如何?
功能正常了,下一步关心的问题就是性能。为了提高性能,从FreeType获取字体的PathGeometry时做缓冲;同一个字体,下次显示时,直接使用上次的字体生成的PathGeometry,不再从Freetype获取字体。
本人做了简单的对比测试,Freetype性能要高于使用FormattedText方案,性能大概提升三倍;与GlyphRun方案没做对比。
总结: 使用FreeType库,可以使我们更好的理解底层处理逻辑,更好的理解字体的本质。抓住了本质,就能直面问题,解决问题就顺畅很多。不同的库、不同函数都有它的应用场景;当微软提供的库不再适合当前应用时,大胆的使用新库,反而可能使我们快速走出困局!
化繁为简、性能提升 -- 在WPF程序中,使用Freetype库心得的更多相关文章
- 理解性能的奥秘——应用程序中慢,SSMS中快(4)——收集解决参数嗅探问题的信息
本文属于<理解性能的奥秘--应用程序中慢,SSMS中快>系列 接上文:理解性能的奥秘--应用程序中慢,SSMS中快(3)--不总是参数嗅探的错 前面已经提到过关于存储过程在SSMS中运行很 ...
- 在WPF程序中使用摄像头兼谈如何使用AForge.NET控件(转)
前言: AForge.NET 是用C#写的一个关于计算机视觉和人工智能领域的框架,它包括图像处理.神经网络.遗传算法和机器学习等.在C#程序中使用摄像头,我习惯性使用AForge.NET提供的类库.本 ...
- WPF 程序中启动和关闭外部.exe程序
当需要在WPF程序启动时,启动另一外部程序(.exe程序)时,可以按照下面的例子来: C#后台代码如下: using System; using System.Collections.Generic; ...
- 如何在WPF程序中使用ArcGIS Engine的控件
原文 http://www.gisall.com/html/47/122747-4038.html WPF(Windows Presentation Foundation)是美国微软公司推出.NET ...
- 理解性能的奥秘——应用程序中慢,SSMS中快(6)——SQL Server如何编译动态SQL
本文属于<理解性能的奥秘--应用程序中慢,SSMS中快>系列 接上文:理解性能的奥秘--应用程序中慢,SSMS中快(5)--案例:如何应对参数嗅探 我们抛开参数嗅探的话题,回到了本系列的最 ...
- 理解性能的奥秘——应用程序中慢,SSMS中快(5)——案例:如何应对参数嗅探
本文属于<理解性能的奥秘--应用程序中慢,SSMS中快>系列 接上文:理解性能的奥秘--应用程序中慢,SSMS中快(4)--收集解决参数嗅探问题的信息 首先我们需要明白,参数嗅探本身不是问 ...
- 理解性能的奥秘——应用程序中慢,SSMS中快(3)——不总是参数嗅探的错
本文属于<理解性能的奥秘--应用程序中慢,SSMS中快>系列 接上文:理解性能的奥秘--应用程序中慢,SSMS中快(2)--SQL Server如何编译存储过程 在我们开始深入研究如何处理 ...
- 理解性能的奥秘——应用程序中慢,SSMS中快(2)——SQL Server如何编译存储过程
本文属于<理解性能的奥秘--应用程序中慢,SSMS中快>系列 接上文:理解性能的奥秘--应用程序中慢,SSMS中快(1)--简介 本文介绍SQL Server如何编译存储过程并使用计划缓存 ...
- 理解性能的奥秘——应用程序中慢,SSMS中快(1)——简介
本文属于<理解性能的奥秘--应用程序中慢,SSMS中快>系列 在工作中发现有不少类似的现象,有幸看到国外大牛写的一篇文章,由于已经完善得不能再添油加醋,所以决定直接翻译,原文出处:http ...
- WPF程序中App.Config文件的读与写
WPF程序中的App.Config文件是我们应用程序中经常使用的一种配置文件,System.Configuration.dll文件中提供了大量的读写的配置,所以它是一种高效的程序配置方式,那么今天我就 ...
随机推荐
- att&ack学习笔记6
att&ck攻击能力和防御能力的可量化可衡量的标准,是否防得住,是否检测的了,和同行的对比攻击行为(网络威胁分析,研究,行业报告)----->ATT&CK(对抗模型,对抗流程细分 ...
- 《刚刚问世》系列初窥篇-Java+Playwright自动化测试-4-启动浏览器-基于Maven(详细教程)
1.简介 上一篇文章,宏哥已经在搭建的java项目环境中添加jar包实践了如何启动浏览器,今天就在基于maven项目的环境中给小伙伴们或者童鞋们演示一下如何启动浏览器. 2.eclipse中新建mav ...
- HTTP相关返回值异常如何解决(下篇)
今天我们讲讲HTTP相关返回值异常如何解决(实例持续更新中) 一.4xx客户端错误状态码 这些状态码表示请求有问题,通常是由于客户端的错误引起的. 1.1 400 Bad Request: 请求 ...
- 使用WebRTC技术搭建小型的视频聊天页面
目录 目录 参考资料 什么是WebRTC? 能做什么? 架构图 个人理解(类比) 核心知识点 核心知识点类比 ICE框架 STUN(协议) NAT(网络地址转换) TURN SDP(会话描述协议) W ...
- 连接数据库报错的异常可以用mysqli_report来捕获
有时候数据库密码改了或者数据库删了,就会有一个mysqli的链接报错,是因为直接使用了类似代码 $connection = new mysqli('127.0.0.1', 'test_user', ' ...
- 设计模式之中介者模式(Mediator)
一.初识中介者模式 那些年,我们一起上过的大学,班级里有班长,有团书记.想一想如果没有QQ这种通讯工具的话,那么班长或者团支书该怎样下达消息呢??同时,班级上两个同学之间也可惜沟通啊,沟通一下,院里哪 ...
- Konva.js
1.前言 简介:Konva.js - 适用于桌面/移动端应用的 HTML5 2d canvas 库 个人体验:原生的canvas只支持绘制基本的直线,矩形,文字,图片,扇形等,如果要支持更复杂的功能, ...
- Sortable.js笔记
1.前言 SortableJS是功能强大的JavaScript 拖拽库,更多配置项:Sortable.js中文网|配置 引入插件 <script src="https://cdn.bo ...
- Spring AOP基础、快速入门
介绍 AOP,面向切面编程,作为面向对象的一种补充,将公共逻辑(事务管理.日志.缓存.权限控制.限流等)封装成切面,跟业务代码进行分离,可以减少系统的重复代码和降低模块之间的耦合度.切面就是那些与业务 ...
- 前端必须知道的手机调试工具vConsole
在日常业务中我相信大家多多少少都有移动端的项目,移动端的项目需要真机调试的很多东西看不到调试起来也比较麻烦,今天给大家分享一个我认为比较好用的调试第三方库VConsole ,有了这个库咱们就在手机上看 ...