Получить символ юникода по индексу глифа в объекте CTFontRef или CGFontRef - PullRequest
3 голосов
/ 12 февраля 2011

CTFontRef предоставляет отличный метод, такой как CTFontGetGlyphsForCharacters, для сопоставления символа (символов) с глифом (ами).У меня вопрос, есть ли способ для обратного отображения?То есть, могу ли я получить символы с данным глифом?Поскольку я обнаружил, что есть CTFontCopyCharacterSet для получения всех поддерживаемых символов, я думаю, что будут некоторые хорошие решения.

Ответы [ 2 ]

3 голосов
/ 14 апреля 2015

TLDR: CTFont / CTFontRef / CTGlyph недостаточно - необходимо задействовать CTLine и CTRun;и даже тогда это имеет смысл только в том случае, если у вас есть доступ к исходному отображению String-> Glyph.

Я вернусь к этому на несколько лет позже, если другие в конечном итоге зададут этот вопрос.Как заметил Аластер, нет никакого способа для общего сопоставления глифов с символами.Простые примеры - есть несколько символов Юникода для «пробела», часто сопоставляемых одному и тому же символу.То же самое часто бывает верно для «микро» и греческого «му».

Однако иногда (часто?) Бывает, что у вас есть исходная строка, и вам действительно нужно знать, как она была отображена.глифам.Другими словами - у меня есть моя строка, и у меня есть полученные глифы - для каждого индекса глифа, каков индекс символа в строке, в которую он вносит свой вклад.Я написал этот пример, чтобы продемонстрировать способ сделать это.(Помимо: извлеченный урок - Swift становится немного грубым при работе с некоторыми API Core Foundation)

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. Вот визуальное представление двух строк: enter image description here

3 голосов
/ 08 апреля 2011

Я думаю, что вам, возможно, придется самостоятельно анализировать таблицы сопоставления шрифтов. Вы можете получить доступ к таблицам, используя CGFontCopyTableForTag(); таблица, за которой вы следите, является таблицей 'cmap', формат которой задокументирован здесь:

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

, а также здесь:

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

К сожалению, как вы обнаружите, прочитав их, задача преобразования символов в глифы решительно нетривиальна, и, кроме того, любой данный шрифт может иметь более одной таблицы отображения (то есть набор символов, которые используют данный глиф может зависеть от того, какой формат таблицы сопоставления вы выберете - или средство визуализации -).

Кроме того, передовые технологии шрифтов, такие как OpenType или AAT, могут привести к существованию глифов, для которых нет прямого сопоставления из символов, но которые тем не менее присутствуют в выходных данных в результате подстановок, сделанных технология интеллектуальных шрифтов. Инвертировать механизмы замещения OpenType или AAT было бы непросто, и это также может не привести к единой кодовой точке Unicode (или даже к одному кластеру графем).

...