CoreText 概述

为个人阅读快速翻译, 难免有误, 见谅, 原文(Apple 文档)

Core Text 概述

Core Text 是一种强大的底层文本布局和处理字体的技术, Core Text 直接使用 Core Graphics(CG), 通常也叫做 Quartz, 是iOS 和 OSX 底层的高速二维图像渲染引擎.

注意: Core Text 是为上层文本处理所开发的框架, 普通开发者在 iOS 中应该使用 Text Kit, OSX 中应该使用 Cocoa text system
译者注: 言外之意就是普通玩家用封装好的Text Kit, 高玩可尝试, 不推荐低端用户使用~

Core Text 协调了文本布局, 上层字体框架, Quartz 提供的底层文本和字体框架.
Quartz 框架负责字形和位置. Core Text 负责从字符到字体的映射, 在调用Quartz 渲染这些文本之前, 它会分离出样式, 字体和其他一些属性. Quartz 是唯一的底层图形绘制方法. 因为 Core Text 已经以一定格式提供给Quartz 所有需要的信息. 这样结能够有很高的文本渲染性能.

多线程 : Core Text 支持多线程,是线程安全的, 前提是不在线程之间改变任何参数, 比如共享属性字符串(attributed string)

Core Text 是一系列 C语言平台无关的 API

iOS 和 OS X 平台上 Core Text API 基本一致, 到那时 OS X 版本提供了更为丰富的字体管理 API, 包括可变的字体集合. 但是, UIKit 和 AppKit 在不同平台上有很大区别. 比如, 你必须有一个Quartz图形上下文来渲染 Core Text 生成的图形, 和在不同平台上获取的图像上下文也不一样. 在 iOS 平台上, 一个视图对应的是 UIView的子类, 而在 OS X平台上, 一个视图对应的是NSView 的子类. 你必须清楚, CGRect 对象传给 UIView 的 drawRect:方法, 而 OS X 传递的是一个NSRect对象. 你可以使用NSRectToCGRect方法来讲 NSRect转换成CGRect.

图形上下文由 UIViewUIGraphicsGetCurrentContext 方法返回. 这个上下文是由 Quartz图形上下文未经修改上下翻转过来的(UIView 返回的上下文原点在左上角), 所以在 iOS 中你必须将其翻转过来, OS X 不需要翻转, 详情可以去Listing 2-1 查看一些示例代码.

译者注: Quartz 和 OS X 原点在窗口左下角, 而 iOS 的原点在左上角, 所以需要翻转

Core Text 尽可能的使用系统数据类型和服务, 所以你也可以使用 OS X 或者 iOS 的核心框架. 比如, Core Text 使用 Core Foundation 对象作为输入输出参数, 所以你当然可以将其存到 Core Foundation 集合类里面. 其他Core Text使用的对象比如 CGPath, 是由 Core Graphics 框架提供.

Core Text 对象是一系列 C语言不透明类型(Opaque Types)

在 OS X 和 iOS 中, 许多底层库为了速度和简洁,使用了纯 C 编写. 当你使用 Core Text 的时, 你使用一系列 C 函数, 比如CTFramesetterCreateWithAttributedStringCTFramesetterCreateFrame 来替代 Objective-C 类和方法.

Core Text 不透明类型(Opaque Types)

Core Text 布局引擎经常跟属性字符串(CFAttributedStringRef)和图形路径(CGPathRef)打交道. 属性字符串对象将一个用于显示的文本和一些定义格式样式的属性封装起来, 比如字体和颜色. Core Text 使用属性字符串里的信息来执行字符到图像的转换.

图形路径定义一帧文本的形状. 在 OS X 10.7和 iOS 3.2及更新版本, 这个路径可以不是矩形

CFAttributedString 的引用类型 CFAttributedStringRef, 和 Foundation 中的 NSAttributedString 是 toll-free bridged的. 这就意味着 Core Foundation 类型在函数或方法中可以和bridged Foundation 对象互相替换的. 因此, 在一个方法中, NSAttributedString *参数是可以传入一个CFAttributedStringRef类型. 反之, 在CFAttributedStringRef 参数可以传入一个NSAttributedString 实例(可能需要转换类型来消除编译器警告) 这个同样适用于NSAttributedString的子类.

属性本质就是一系列键值对, 定义部分字符的属性特征, 使用相同属性的字符根据range 进行分组. 属性使用CFDictionary对象传入属性字符串,而后被取出来. 应用一个样式到一个图像运行器(CTRun 对象), 创建一个CFDictionary对象来存储你想要应用的属性., 然后创建一个属性字符串, 把这个字典作为参数传入. 或者, 你可以应用这些属性到一个已经存在的CFMutableAttributedString对象中. 即使CFDictionaryRefNSDictionary 是toll-free bridged, 但字典中存储的属性对象可能并不是.

图 1-1显示了Core Text 对象运行时层级. 最上层是一个framesetter对象(CTFramesetterRef). 一个属性字符串和一个图像路径作为输入, framesetter可以生成一个或多个帧文本(CTFrameRef). 每个CTFrame对象代表着一个段落.

图 1-1 Core Text 布局引擎架构

framesetter 调用一个typesetter对象生成 frame, 在 frame 中放置文本, framesetter将段落样式应用到这个 frame 上, 包括对齐方式, 制表符, 行间距, 缩进和断句模式. typesetter 将属性字符串中的字符转换成字形, 并将字形填充到文本框的行中

每个 CTFrame 对象包括段落的行对象(CTLine). 每个行对象代表着一行文本. 一个 CTFrame对象可能只包含一行很长的CTLine 对象或者很多行. 在framesetting操作过程中, 会创建行对象. 这些行对象跟 frame 一样, 可以直接将自己绘制到图像上下文中.

每个行对象包含一个数组的glyph run(CTRun)对象. 一个glyph run 每一行对象都包含一系列连续不断的字形,这些字形都包含相同的属性和方向. typesetter会在从字符产生行时创建glyph run对象. 这就意味着, 一个行对象是由一个或多个glyphs run 构成. glyphs run 可以将自己绘入图像上下文中, 若非必要时,大多数客户端不需要直接跟 glyph run 打交道.

字体对象

字体对象为字形之间的布局提供支持, 然后将当前字体绘入图像上下文. Core Text 字体不透明对象, CTFont, 是一个特殊的字体实例, 封装了许多实例. CTFontRef为其引用类型, 和 iOS 中的 UIFont, OS X 的 NSFont 是 oll-free bridged, 你可以指定字体大小和变换矩阵, 给这字体实例具体特征. 对于大小特定的字体, 你可以从字体对象中查询到很多关于字体相关的信息, 比如字符到字形的映射, 编码, 字体度量信息, 和字形信息等等. 字体度量是一些参数, 比如, 升序, 降序, 开头, 头高等等. 字形信息包含参数比如, 矩形边界和字形步进.

Core Text 字体对象是不可变的, 所以可以被多个操作, 工作队列或者线程使用. 有很多方式创建字体对象. 首选方法是从一个字体描述符创建一个字体对象CTFontCreateWithFontDescriptor, 还有其他很多方便的 API, 具体使用哪个要看你的目的. 比如, 你可以使用字形的 PostScript 名字(CTFontCreateWithName
)或者 一个 Core Graphics 字体引用(CTFontCreateWithGraphicsFont
), CTFontCreateUIFontForLanguage 在所使用的应用本地创建一个用户接口字体引用.

Core Text 字体引用提供了一个复杂的自动字体替换机制, 叫做字体串联.
根据字体的特征挑选合适的字体来替换一个找不到的字体, 字体串联基于串联的列表, 是一系列有序的字体描述符. 在一个字体创建的时候, 会指定一个系统默认的串联列表(根据用户的语言设置和当前字体有不同的表现)和一个字体串联列表. 串联机制可以使用字体描述符的信息, 根据样式为字符匹配字体 CTFontCreateForString 函数可以使用串联列表来挑选合适的字体去编码对应的字符串. 使用kCTFontCascadeListAttribute 属性来指定和检索字体串联列表.

字体描述符

字体描述符, 用CTFontDescriptor 不透明类型表示, 提供了完全从一个属性字典描述字体的机制, 和易用的创建新字体的设施. 你可以根据字体描述符创建字体, 也可以从一个字体对象中获取字体描述符, 然后用其来创建一个新的字体对象. 你可以创建字体描述符来部分创建字体, 比如, 只是字体簇名称或者比重, 然后就可以找到系统中与之匹配的所有字体.iOS 中的UIFontDescriptor , OS X 中的NSFontDescriptorCTFontDescriptorRef 类型是toll-free bridged.

我们使用创建一个包含PostScript 名字, font family, 样式以及其他特性(比如, 粗体或斜体)等的字体属性字典来作为CTFontDescriptor 对象. 你可以使用字体描述符创建一个CTFont 对象. 字体描述符可以被序列化并存储到文档中来进行持久化.
图 1- 2描述了字体系统使用字体描述符创建指定字体实例

图 1-2 从字体描述符创建字体

你可以认为字体描述符就是字体系统中的查询条件, 你可以创建一个不完整的字体描述符, 属性字典里只是一部分的值. 比如, 如果你指定了 font family, 不指定字体的所有特性, 你就能获取到该 font family 的所有字体, 但是如果你指定了kCTFontTraitsAttribute的值为kCTFontTraitBold, 那么就能查询到该 font family 下的所有粗体. 通过CTFontDescriptorCreateMatchingFontDescriptors提供可以提供一个跟查询匹配的完整的字体描述符列表.

在 iOS 6.0及以后版本, 应用可以使用CTFontDescriptorMatchFontDescriptorsWithProgressHandler下载所需未安装的字体, 下载的字体并不是安装后永远不变的, 系统可能会在一定情况下将其移除, 支持下载的字体被列在iOS 6: Font listiOS 7: Font list. DownloadFont(在 iOS 开发库中)说明了下载技术. 在 OS X 中, 按需下载字体不是必须的, 因为所有可用字体都已经安装到系统中了.

字体集合

字体集合是一系列字体组成的组作为一个单独的对象. CTFontCollection不透明来行代表一个字体集合. 字体集合提供字体枚举, 访问全局和自定义字体集合, 以及访问包含该字体集合的字体描述符的能力. 举个例子, 通过CTFontCollectionCreateFromAvailableFonts创建一个包含所有可用字体描述符的集合, 你可以使用这个集合获取所有字体描述符.

.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,165评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,720评论 1 298
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,849评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,245评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,596评论 3 288
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,747评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,977评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,708评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,448评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,657评论 2 249
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,141评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,493评论 3 258
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,153评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,108评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,890评论 0 198
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,799评论 2 277
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,685评论 2 272

推荐阅读更多精彩内容