This snippet can be used for drawing CGGlyphs
with a CGContext
:
//drawing
let coreGraphicsFont = CTFontCopyGraphicsFont(coreTextFont, nil)
CGContextSetFont(context, coreGraphicsFont);
CGContextSetFontSize(context, CTFontGetSize(coreTextFont))
CGContextSetFillColorWithColor(context, Color.blueColor().CGColor)
CGContextShowGlyphsAtPositions(context, glyphs, positions, length)
But how do I obtain the CGGlyph
s from a Swift string which contains emoji symbols like flags or accented characters?
let string = "swift: \u{1F496} \u{65}\u{301} \u{E9}\u{20DD} \u{1F1FA}\u{1F1F8}"
Neither of the below approaches shows the special characters, even though they are correctly printed to the console. Note that this first approach returns NSGlyph
but CGGlyph
s are required for drawing:
var progress = CGPointZero
for character in string.characters
{
let glyph = font.glyphWithName(String(character))
glyphs.append(CGGlyph(glyph))
let advancement = font.advancementForGlyph(glyph)
positions.append(progress)
progress.x += advancement.width
}
or this second approach which requires casting to NSString
:
var buffer = Array<unichar>(count: length, repeatedValue: 0)
let range = NSRange(location: 0, length: length)
(string as NSString).getCharacters(&buffer, range: range)
glyphs = Array<CGGlyph>(count: length, repeatedValue: 0)
CTFontGetGlyphsForCharacters(coreTextFont, &buffer, &glyphs, length)
//glyph positions
advances = Array<CGSize>(count: length, repeatedValue: CGSize.zero)
CTFontGetAdvancesForGlyphs(ctFont, CTFontOrientation.Default, glyphs, &advances, length)
positions = []
var progress = CGPointZero
for advance in advances
{
positions.append(progress)
progress.x += advance.width
}
Some of the characters are drawn as empty boxes with either approach. Kinda stuck here, hoping you can help.
Edit:
Using CTFontDrawGlyphs
renders the glyphs correctly, but setting the font, size and text matrix directly before calling CGContextShowGlyphsAtPositions
draws nothing. I find that rather odd.
If you generate glyphs yourself, you also need to perform font substitution yourself. When you use Core Text or TextKit to lay out and draw the text, they perform font substitution for you. For example:
Output:
We can see here that Core Text recognized that the default font (Helvetica) doesn't have glyphs for the emoji or the arrow, so it split the line into three runs, each with the needed font.
The Core Text Programming Guide says this:
Your best bet is to use
CTLineCreateWithAttributedString
to generate glyphs and choose fonts. Then, if you want to adjust the position of the glyphs, useCTLineGetGlyphRuns
to get the runs out of the line, and then ask the run for the glyphs, the font, and whatever else you need.If you want to handle font substitution yourself, I think you're going to want to look into “font cascading”.