通过 CTFontRef 或 CGFontRef 对象中的字形索引获取 unicode 字符

cxa*_*cxa 6 objective-c core-text

CTFontRef 提供了很好的方法,例如CTFontGetGlyphsForCharacters将字符映射到字形。我的问题是,是否有任何反转映射的方法?也就是说,我可以通过给定的字形获得字符吗?由于我发现有一个CTFontCopyCharacterSet用于获取所有支持的字符,我认为会有一些不错的解决方案。

Joe*_*Joe 6

TLDR:CTFont/CTFontRef/CTGlyph 是不够的 - CTLine 和 CTRun 需要参与;即便如此,它也只有在您有权访问原始 String->Glyph 映射时才有意义。

我会晚几年回来,以防其他人最终遇到这个问题。正如 alastair 所指出的,没有办法将字形一般映射回字符。简单示例 - 'space' 有多个 unicode 字符,通常映射到相同的字形。'micro' 和希腊语 'mu' 通常也是如此。

但是,有时(通常?)情况是您拥有原始字符串,而您真正想要的是知道它是如何映射到字形的。换句话说 - 我有我的字符串,我有结果的字形 - 对于每个字形索引,它所贡献的字符串中的字符索引是什么。我写了这个示例来演示一种方法来做到这一点。(旁白:经验教训 - Swift 在使用某些 Core Foundation API 时会变得有些粗糙)

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)
Run Code Online (Sandbox Code Playgroud)

如果你在没有参数的情况下运行它,然后在命令行中使用 /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
Run Code Online (Sandbox Code Playgroud)

我添加了 Ligature 选项以帮助形象化字形和字符很容易不是 1 比 1。这是两个字符串的视觉表示: 在此处输入图片说明


ala*_*air 4

我认为您最终可能必须自己解析 font\xe2\x80\x99s 映射表。您可以使用以下命令获取对表的访问权限CGFontCopyTableForTag():您要查找的表是“ cmap\”表,其格式记录如下:

\n\n

http://www.microsoft.com/typography/otspec/cmap.htm

\n\n

还有这里:

\n\n

http://developer.apple.com/fonts/TTRefMan/RM06/Chap6cmap.html

\n\n

不幸的是,正如您\xe2\x80\x99通过阅读这些内容会发现的那样,将字符映射到字形的工作绝对不是微不足道的,此外任何给定的字体可能有多个映射表(即使用给定的字形可能取决于您选择的映射表格式\xe2\x80\x94或渲染器\xe2\x80\x94)。

\n\n

此外,OpenType 或 AAT 等高级字体技术可能会导致存在无法字符直接映射的字形,但由于智能字体技术进行替换,这些字形仍然存在于输出中。反转 OpenType 或 AAT 替换机制会很棘手,并且也可能不会导致单个 Unicode 代码点(或者实际上甚至不会导致单个字素簇)。

\n