合成絵文字用のCGGlyphの取得

CTFontの CTFontGetGlyphsForCharacters(::::) API を使って合成絵文字のCGGlyphを取得しようと試みたのですが、うまくいきません。

CGGlyphの生成には、CTRunからの取得とCTFonからの取得の2方法あります。

CTRunからだとうまく合成絵文字のCGGlyphを取得できます。

以下CTRunの CTRunGetGlyphs(::_:) APIからの生成

// 👩‍👩‍👧‍👦
let str = "\u{0001F469}\u{200D}\u{0001F469}\u{200D}\u{0001F467}\u{200D}\u{0001F466}"
print("Inputed: \(str)")

let run = makeRuns(from: str)[0]

let attributes = CTRunGetAttributes(run) as! [String :Any]
let font = attributes["NSFont"] as! CTFont
let fontName = CTFontCopyDisplayName(font)
print("font = \(fontName)")

let glyphs = makeGlyphs(from: run)
print(glyphs) // [1289]

gist

合成絵文字(👩‍👩‍👧‍👦)から一つのCGGlyphが生成できています。

一方 CTFontの CTFontGetGlyphsForCharacters(::::) APIからだとうまくいきません。

// 👩‍👩‍👧‍👦
let str: NSString = "\u{0001F469}\u{200D}\u{0001F469}\u{200D}\u{0001F467}\u{200D}\u{0001F466}"
print("Inputed: \(str)")
let unichars = makeUnichars(from: str)

var font = CTFontCreateWithName("AppleColorEmoji" as CFString, 17.0, nil)
font = CTFontCreateForString(font, str, CFRange(location: 0, length: str.length))

let fontName = CTFontCopyDisplayName(font)
print("font = \(fontName)")

var glyphs: [CGGlyph] = Array(repeating: 0, count: str.length)

if (CTFontGetGlyphsForCharacters(font, unichars, &glyphs, str.length)) {
    print("succeed in generating glyph")
    print("glyphs = \(glyphs)")
} else {
    print("failed in generating glyph")
}

/* output
Inputed: 👩‍👩‍👧‍👦
font = Apple Color Emoji
succeed in generating glyph
glyphs = [1164, 0, 43, 1164, 0, 43, 1056, 0, 43, 1050, 0]     
*/

gist

合成絵文字のグリフではなく、それぞれの絵文字のCGGlyphが返ってきます。

CTRunからだとFontの選定も自動で行ってくれるので、CTFontからではなく、CTRunを使ったほうが便利ですね。