Obtener ruta para rastrear un personaje en un UIFont de iOS

Supongamos que tengo una fuente personalizada “Foo” que estoy usando en mi aplicación de iOS. Lo he agregado a mi proyecto, plist, etc. y puedo renderizar UILabel y UILabel con él.

Ahora, si quiero descubrir una secuencia de puntos que “trace” la letra “P” en esa fuente, ¿cómo obtendré esa secuencia de puntos? Por ejemplo, supongamos que quisiera usar un CGPath para dibujar la letra ‘P’ lentamente como lo haría un trazador …

Solo necesito una secuencia de CGPoints en una matriz que si se dibuja como una ruta dibujaría una ‘P’.

Me doy cuenta de que para algunas letras como ‘T’, esto puede no tener sentido, ya que la pluma tendría que ser levantada para cruzar la ‘T’. Entonces tal vez necesito una secuencia de CGPath s …

¿Alguna pista sobre cómo lograr esto?

¡Gracias!

    Pasar de la letra “P” a una secuencia de puntos implica varios pasos. Tendrá que usar Core Text.

    1. Crea un CTFont . Desde iOS 7, puede usar un UIFont donde se necesita un CTFont (son “sin conexión de puente”). También puede crear un CTFont directamente desde un CGFont usando la función CTFontCreateWithGraphicsFont , o por nombre usando CTFontCreateWithName (o usando algunos otros métodos).

    2. Obtenga los glifos para la letra usando la función CTFontGetGlyphsForCharacters . Para la letra “P” debería haber solo un glifo. Para algunos caracteres en scripts que no están en inglés, puede obtener múltiples glifos (combinados).

    3. Utilice la función CTFontCreatePathForGlyph para obtener un CGPath para el glifo.

    4. Use CGPathApply para enumerar los elementos de la ruta.

    5. Convierta cada línea, curva cuádruple y elemento de curva cúbica de la ruta en una secuencia de puntos. Apple no proporciona ninguna API pública para hacer esto. Tendrás que hacerlo tú mismo. Para los elementos de línea recta es fácil. Para los elementos de curva, tendrá que investigar un poco si aún no sabe cómo renderizar una curva de Bézier. Por ejemplo, ver convert bezier curve to polygonal chain? .

    Podemos experimentar con esto fácilmente en un patio 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])") } 

    Resultado:

     , , , , , , , , , , , , , , , , ,  

    P glyph path

    Para aquellos que buscan la misma solución en 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 }