CTFontRef提供了出色的方法,例如CTFontGetGlyphsForCharacters
,用于将字符映射到字形。我的问题是,是否有任何反转映射方法?也就是说,我可以通过给定的字形获得字符吗?由于我发现有CTFontCopyCharacterSet
来获取所有支持的字符,我认为会有一些很好的解决方案。
答案 0 :(得分:3)
我想你最终可能不得不自己解析字体的映射表。您可以使用CGFontCopyTableForTag()
获取对表的访问权限。您所追求的表格是“cmap
”表格,其格式如下:
http://www.microsoft.com/typography/otspec/cmap.htm
也在这里:
http://developer.apple.com/fonts/TTRefMan/RM06/Chap6cmap.html
不幸的是,正如您将通过阅读这些来发现的那样,将字符映射到字形的业务显然是非平凡的,此外任何给定的字体都可能有多个映射表(即使用一个字符的字符集)给定的字形可能取决于您或渲染器选择的映射表格式。
此外,像OpenType或AAT这样的高级字体技术可能会导致字符的存在,而没有直接映射来自字符,但是由于替换而在输出中存在这些字形通过智能字体技术。反转OpenType或AAT替换机制会很棘手,也可能不会导致单个Unicode代码点(或者甚至是单个字形集群)。
答案 1 :(得分:3)
TLDR:CTFont / CTFontRef / CTGlyph还不够 - CTLine和CTRun需要参与其中;即使这样,只有你能访问原始的String->字形映射才有意义。
我迟到了几年,以防其他人最终提出这个问题。正如阿拉斯泰尔所指出的那样,没有办法将字形一般地映射回字符。简单示例 - 'space'有多个unicode字符,通常映射到同一个字形。对于'微'和希腊'mu'来说也是如此。
但是,有时(通常是?)你拥有原始字符串,你真正想要的是知道它是如何映射到字形的。换句话说 - 我有我的字符串,并且我得到了结果字形 - 对于每个字形索引,它所贡献的字符串中的字符索引是什么。我写了这个样本来演示这样做的方法。 (旁白:经验教训 - 使用某些Core Foundation API时,Swift有点粗糙)
import CoreText
import AppKit
func main(argc: Int, argv: [String])
{
var stringAttributes: [String: AnyObject] = [:]
var fontName = "Zapfino"
var fUseLigatures = false
var fontNameIndex = 0
if argc > 1
{
if argv[1] == "/lig"
{
fUseLigatures = true;
if (argc > 2) { fontNameIndex = 3 }
}
else { fontNameIndex = 2 }
}
if fontNameIndex > 0 { fontName = argv[fontNameIndex] }
if let font = NSFont(name:fontName, size:24.0)
{ stringAttributes[NSFontAttributeName] = font }
stringAttributes[NSLigatureAttributeName] = fUseLigatures ? 2 : 0
let string = NSAttributedString(
string:"This is \(fontName)!",
attributes: stringAttributes)
let line = CTLineCreateWithAttributedString(string) // CTLine
let runs = CTLineGetGlyphRuns(line) // CTRun[]
let nsRuns:Array<AnyObject> = runs as Array<AnyObject>
assert(nsRuns.count == 1)
let run = nsRuns[0] as! CTRun
let glyphCount = CTRunGetGlyphCount(run)
println("String: \(string.string)")
println("\tStrLen: \(count(string.string)), Count Of Glyphs: \(glyphCount)");
let clusters = UnsafeMutablePointer<CFIndex>.alloc(glyphCount)
CTRunGetStringIndices(run, CFRange(location:0, length:glyphCount), clusters)
for var idx = 0; idx < glyphCount; idx++
{
let idxString = clusters[idx];
println("Glyph @ \(idx) maps to String @ \(idxString)")
}
}
main(Process.arguments.count, Process.arguments)
如果你在没有参数的情况下运行它,然后在命令行使用/ lig,你将获得以下输出:
String: This is Zapfino!
StrLen: 16, Count Of Glyphs: 16
Glyph @ 0 maps to String @ 0
Glyph @ 1 maps to String @ 1
Glyph @ 2 maps to String @ 2
Glyph @ 3 maps to String @ 3
Glyph @ 4 maps to String @ 4
Glyph @ 5 maps to String @ 5
Glyph @ 6 maps to String @ 6
Glyph @ 7 maps to String @ 7
Glyph @ 8 maps to String @ 8
Glyph @ 9 maps to String @ 9
Glyph @ 10 maps to String @ 10
Glyph @ 11 maps to String @ 11
Glyph @ 12 maps to String @ 12
Glyph @ 13 maps to String @ 13
Glyph @ 14 maps to String @ 14
Glyph @ 15 maps to String @ 15
joes-mac: Tue Apr 14, 10:26:00
~/Source/FontGlyph/./main /lig
String: This is Zapfino!
StrLen: 16, Count Of Glyphs: 7
Glyph @ 0 maps to String @ 0
Glyph @ 1 maps to String @ 2
Glyph @ 2 maps to String @ 4
Glyph @ 3 maps to String @ 5
Glyph @ 4 maps to String @ 7
Glyph @ 5 maps to String @ 8
Glyph @ 6 maps to String @ 15
我添加了Ligature选项,以帮助可视化字形和字符很容易不是1到1.这是两个字符串的直观表示: