2012-06-23 10 views
12

Angenommen, ich habe eine benutzerdefinierte Schriftart "Foo", die ich in meiner iOS App verwende. Ich habe es zu meinem Projekt, Plist usw. hinzugefügt und bin in der Lage, UILabel s und so mit ihm gut zu machen.Pfad zum Verfolgen eines Zeichens in einem iOS UIFont

Jetzt, wenn ich eine Folge von Punkten herausfinden möchte, die den Buchstaben "P" in dieser Schriftart "ausfindig machen" würde, wie würde ich diese Abfolge von Punkten bekommen? Angenommen, ich wollte einen CGPath verwenden, um den Buchstaben 'P' langsam wie einen Plotter zu zeichnen ...

Ich brauche nur eine Sequenz von CGPoints in einem Array, das, wenn es als Pfad gezeichnet würde, ein 'P zeichnen würde ".

Ich weiß, dass für einige Buchstaben wie "T" dies keinen Sinn ergibt, da der Stift angehoben werden müsste, um das "T" zu überqueren. Also brauche ich vielleicht eine Sequenz von CGPath s ...

Hinweise, wie dies zu erreichen?

Danke!

+1

[Was haben Sie versucht?] (Http://whathaveyoutried.com) – EmilioPelaez

Antwort

29

Der Übergang vom Buchstaben "P" zu einer Folge von Punkten umfasst mehrere Schritte. Sie müssen Core Text verwenden.

  1. Erstellen Sie eine CTFont. Seit iOS 7 können Sie einen UIFont verwenden, wo ein CTFont benötigt wird (sie sind "gebührenfrei überbrückt"). Sie können auch eine CTFont direkt von einer CGFont mit der -Funktion oder mit dem Namen CTFontCreateWithName (oder mit ein paar anderen Methoden) erstellen.

  2. Die Glyphen für den Buchstaben mit der Funktion CTFontGetGlyphsForCharacters abrufen. Für den Buchstaben "P" sollte es nur eine Glyphe geben. Für einige Zeichen in nicht-englischen Skripten können Sie mehrere (kombinierte) Zeichen erhalten.

  3. Verwenden Sie die CTFontCreatePathForGlyph Funktion, um eine CGPath für die Glyphe zu erhalten.

  4. Verwenden Sie CGPathApply, um die Elemente des Pfads aufzuzählen.

  5. Konvertieren Sie jede Linie, Quad-Kurve und kubische Kurvenelement des Pfades in eine Folge von Punkten. Apple stellt dafür keine öffentliche API zur Verfügung. Sie müssen es selbst tun. Für geradlinige Elemente ist es einfach. Für Kurvenelemente müssen Sie etwas recherchieren, wenn Sie nicht bereits wissen, wie eine Bézier-Kurve gerendert wird. Siehe zum Beispiel convert bezier curve to polygonal chain?.

Wir mit diesem leicht in einem Swift Spielplatz experimentieren:

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])") 
} 

Ergebnis:

<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

Vielen Dank! Ich gebe es eine Chance und melde mich wieder ... – Joel

+0

@RobMayoff Excellent answer!Genau das, wonach ich gesucht habe! Da Sie Ihre CGPaths zu kennen scheinen, wissen Sie, wie ich dem gerade erstellten Pfad eine Zeile hinzufügen könnte? Sprich zurück zum Ausgangspunkt. Einfach hinzufügen: 'let pathP = CGPathCreateMutableCopy (CGPathCreateMutableCopy (cgpath)) CGPathAddLineToPoint (pathP, nil, 0, 0)' scheint nicht zu funktionieren. – user594883

+0

Was bedeutet "scheint nicht zu funktionieren"? Sie müssen eine neue Frage mit Ihrem Code, der Ausgabe (des Dumpings des geänderten Pfads) und der Erklärung, was mit der Ausgabe falsch ist, posten. –

2

Für diejenigen, die die gleiche Lösung in Objective C suchen sind

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 
    } 
Verwandte Themen