Search code examples
ioscore-text

CTFontGetGlyphsForCharacters always returns false


Please help me understand the problem with the following code:

NSString *fontName = @"ArialMT";
CGFloat fontSize = 20.0;
CTFontRef fontRef = CTFontCreateWithName((CFStringRef)fontName, fontSize, NULL);
NSString *characters = @"ABC";
NSUInteger count = characters.length;
CGGlyph glyphs[count];
if (CTFontGetGlyphsForCharacters(fontRef, (const unichar*)[characters cStringUsingEncoding:NSUTF8StringEncoding], glyphs, count) == false)
    NSLog(@"*** CTFontGetGlyphsForCharacters failed.");

Any help is appreciated.


Solution

  • You are getting a C string containing UTF-8 encoded characters and then casting it to unichar *. That won't work. A unichar is a 16-bit UTF-16-encoded character. A simple C cast won't convert the character encoding.

    You need to ask the string for its characters as an array of unichar. In Objective-C:

    NSString *fontName = @"ArialMT";
    CGFloat fontSize = 20.0;
    CTFontRef fontRef = CTFontCreateWithName((CFStringRef)fontName, fontSize, NULL);
    NSString *string = @"ABC";
    NSUInteger count = string.length;
    unichar characters[count];
    [string getCharacters:characters range:NSMakeRange(0, count)];
    CGGlyph glyphs[count];
    if (CTFontGetGlyphsForCharacters(fontRef, characters, glyphs, count) == false) {
        NSLog(@"*** CTFontGetGlyphsForCharacters failed.");
    }
    

    In Swift, you can get the UTF-16 encoding of a String by asking for its utf16 property. That returns a UTF16View, which you then need to convert to an Array.

    import Foundation
    import CoreText
    
    extension CTFont {
        func glyphs(for string: String) -> [CGGlyph]? {
            let utf16 = Array(string.utf16)
            var glyphs = [CGGlyph](repeating: 0, count: utf16.count)
            guard CTFontGetGlyphsForCharacters(font, utf16, &glyphs, utf16.count) else {
                return nil
            }
            return glyphs
        }
    }
    
    let font = CTFontCreateWithName("ArialMT" as CFString, 20, nil)
    print(font.glyphs(for: "Hello"))