2012-06-23 8 views
12

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 así sucesivamente.Obtener ruta para rastrear un personaje en un UIFont de iOS

Ahora, si yo quiero descubrir una secuencia de puntos que "trazar" la letra 'P' en ese tipo de letra, ¿cómo iba a conseguir que la secuencia de puntos? Por ejemplo, supongamos que quería utilizar un CGPath a dibujar la letra 'P' que poco a poco como un trazador haría ...

Sólo necesito una secuencia de CGPoints en una matriz que si dibujado como un camino a robar una 'P '.

que se dan cuenta de que para algunas letras como 'T', esto no tiene sentido, ya que la pluma tendría que ser levantado para cruzar la 'T'. Así que tal vez necesito una secuencia de CGPath s ...

¿Alguna pista sobre cómo lograr esto?

Gracias!

+1

[¿Qué has probado?] (Http://whathaveyoutried.com) – EmilioPelaez

Respuesta

29

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

  1. Crear un CTFont. Desde iOS 7, puede usar un UIFont donde se necesita CTFont (son "sin cargo puenteado"). También puede crear un CTFont directamente desde CGFont usando la función CTFontCreateWithGraphicsFont, o por nombre usando CTFontCreateWithName (o usando algunos otros métodos).

  2. Obtener los glifos de 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. Uso 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, vea convert bezier curve to polygonal chain?.

Podemos experimentar con esto fácilmente en un parque infantil 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:

<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

+0

¡Gracias! Le daré una oportunidad e informaré ... – Joel

+0

@RobMayoff ¡Excelente respuesta!¡Justo lo que también estaba buscando! Ya que parece conocer sus CGPaths, ¿sabe cómo podría agregar una línea a la ruta recién creada? Diga de vuelta al punto de partida, por ejemplo. Simplemente agregando: 'let pathP = CGPathCreateMutableCopy (CGPathCreateMutableCopy (cgpath)) CGPathAddLineToPoint (pathP, nil, 0, 0)' no parece funcionar. – user594883

+0

¿Qué significa "does not do work" significa? Debe publicar una nueva pregunta que contenga su código, la salida (de volcar su ruta modificada) y explicar qué es lo que está mal con la salida. –

2

Para aquellos que están buscando 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 
    } 
Cuestiones relacionadas