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

iphone ios core-graphics uifont cgpath

4510 просмотра

3 ответа

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

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

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

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

Любые советы о том, как этого добиться?

Спасибо!

Автор: Joel Источник Размещён: 13.11.2019 11:31

Ответы (3)


35 плюса

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

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

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

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

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

  5. Преобразуйте каждую линию, квадратичную кривую и элемент кубической кривой пути в последовательность точек. 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 глиф путь

Автор: rob mayoff Размещён: 23.06.2012 08:00

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
    }
Автор: PrafulD Размещён: 27.09.2016 11:43

0 плюса

Обновленный ответ Роба для быстрого 4 + вертикальное отражение для CoreGraphics использует инвертированную систему координат:

    var unichars = [UniChar]("P".utf16)
    var glyphs = [CGGlyph](repeating: 0, count: unichars.count)
    let gotGlyphs = CTFontGetGlyphsForCharacters(font, &unichars, &glyphs, unichars.count)
    if gotGlyphs {
        let cgpath = CTFontCreatePathForGlyph(font, glyphs[0], nil)!
        var inverse = CGAffineTransform(scaleX: 1, y: -1).translatedBy(x: 0, y: -cgpath.boundingBox.height - 1)
        let path = UIBezierPath(cgPath: cgpath.copy(using: &inverse)!)
        print(path)
Автор: floydaddict Размещён: 01.03.2019 03:02
Вопросы из категории :
32x32