Подтвердить что ты не робот

Получить путь для отслеживания символа в iOS UIFont

Предположим, у меня есть пользовательский шрифт "Foo", который я использую в своем приложении iOS. Я добавил его в свой проект, plist и т.д., И я могу отображать UILabel и т.д. С ним просто отлично.

Теперь, если я хочу узнать последовательность точек, которые будут "прослеживать" букву "P" в этом шрифте, как бы получить эту последовательность точек? Например, предположим, что я хотел использовать CGPath, чтобы нарисовать букву "P" медленно, как плоттер...

Мне нужна последовательность CGPoints в массиве, которая, если рисовать как путь, будет рисовать 'P'.

Я понимаю, что для некоторых букв, таких как "Т", это может не иметь смысла, поскольку перо нужно снять, чтобы пересечь "Т". Поэтому, возможно, мне нужна последовательность CGPath...

Любые подсказки о том, как это сделать?

Спасибо!

4b9b3361

Ответ 1

Переход от буквы "P" к последовательности точек включает в себя несколько шагов. Вам нужно будет использовать Core Text.

  • Создайте CTFont. Начиная с iOS 7, вы можете использовать UIFont, где требуется CTFont (они являются "бесплатными мостами" ). Вы также можете создать CTFont непосредственно из CGFont с помощью функции CTFontCreateWithGraphicsFont или по имени с помощью CTFontCreateWithName (или с помощью нескольких других методов).

  • Получите глифы для буквы, используя функцию CTFontGetGlyphsForCharacters. Для буквы "P" должен быть только один символ. Для некоторых символов в неанглийских сценариях вы можете получить несколько (комбинирующих) глифов.

  • Используйте функцию CTFontCreatePathForGlyph, чтобы получить CGPath для глифа.

  • Используйте CGPathApply для перечисления элементов пути.

  • Преобразуйте каждую строку, четырехмерную кривую и кубическую кривую элемента пути в последовательность точек. Apple не предоставляет публичный API для этого. Вам нужно будет сделать это самостоятельно. Для элементов прямой линии это легко. Для элементов кривой вам нужно будет провести некоторое исследование, если вы еще не знаете, как визуализировать кривую Безье. Например, см. преобразовать кривую Безье в полигональную цепочку?.

Мы можем поэкспериментировать с этим легко на игровой площадке Swift:

import UIKit
import CoreText
import XCPlayground

let font = UIFont(name: "HelveticaNeue", size: 64)!

var unichars = [UniChar]("P".utf16)
var glyphs = [CGGlyph](count: unichars.count, repeatedValue: 0)
let gotGlyphs = CTFontGetGlyphsForCharacters(font, &unichars, &glyphs, unichars.count)
if gotGlyphs {
    let cgpath = CTFontCreatePathForGlyph(font, glyphs[0], nil)!
    let path = UIBezierPath(CGPath: cgpath)
    print(path)
    XCPlaygroundPage.currentPage.captureValue(path, withIdentifier: "glyph \(glyphs[0])")
}

Результат:

<UIBezierPath: 0x7fbc89e0d370; <MoveTo {11.072000000000001, 23.808}>,
 <LineTo {11.072000000000001, 40.576000000000001}>,
 <LineTo {22.975999999999999, 40.576000000000001}>,
 <QuadCurveTo {30.560000000000002, 38.432000000000002} - {28.16, 40.576000000000001}>,
 <QuadCurveTo {32.960000000000001, 32.192} - {32.960000000000001, 36.288000000000004}>,
 <QuadCurveTo {30.560000000000002, 25.920000000000002} - {32.960000000000001, 28.096}>,
 <QuadCurveTo {22.975999999999999, 23.808} - {28.16, 23.744}>,
 <Close>,
 <MoveTo {4.992, 45.695999999999998}>,
 <LineTo {4.992, 0}>,
 <LineTo {11.072000000000001, 0}>,
 <LineTo {11.072000000000001, 18.687999999999999}>,
 <LineTo {25.024000000000001, 18.687999999999999}>,
 <QuadCurveTo {35.488, 22.208000000000002} - {31.936, 18.623999999999999}>,
 <QuadCurveTo {39.039999999999999, 32.192} - {39.039999999999999, 25.792000000000002}>,
 <QuadCurveTo {35.488, 42.143999999999998} - {39.039999999999999, 38.591999999999999}>,
 <QuadCurveTo {25.024000000000001, 45.695999999999998} - {31.936, 45.695999999999998}>,
 <Close>

P glyph path

Ответ 2

Для тех, кто ищет одно и то же решение в Objective C

    UIFont *font = [UIFont fontWithName:@"HelveticaNeue" size:64];
    CGFontRef fontref = CGFontCreateWithFontName((__bridge CFStringRef)font.fontName);
    NSString *unichars = @"I";
    CFStringRef yourFriendlyCFString = (__bridge CFStringRef)unichars;
    CGGlyph glyphs = CGFontGetGlyphWithGlyphName(fontref, yourFriendlyCFString);
    CTFontRef fontCT = CTFontCreateWithName((__bridge CFStringRef)font.fontName, font.pointSize, NULL);
    CGPathRef cgpath = CTFontCreatePathForGlyph(fontCT, glyphs, nil);
    UIBezierPath *path = [UIBezierPath bezierPathWithCGPath:cgpath];
    NSLog(@"Complete path For p is %@", path);
    CGPathApply(cgpath, (__bridge void * _Nullable)(bezierPoints), MyCGPathApplierFunc);
    NSLog(@"Points on path %@", bezierPoints);
    for(NSValue *point in bezierPoints){

       //Do your work
    }