2012-06-23 9 views
12

Załóżmy, że mam niestandardową czcionkę "Foo", której używam w mojej aplikacji na iOS. Dodałem go do mojego projektu, plist, itp. I jestem w stanie renderować UILabel s i takie z nim w porządku.Uzyskaj ścieżkę do śledzenia znaku w iOS UIFont

Teraz, jeśli chcę znaleźć sekwencję punktów, które "prześlą" literę "P" w tej czcionce, w jaki sposób otrzymam tę sekwencję punktów? Na przykład, załóżmy, że chciałem użyć CGPath narysować literę powoli jak plotera „p” would ...

Muszę tylko sekwencję CGPoints w tablicy, że jeśli rysowane jako ścieżki byłoby narysować „P ".

Zdaję sobie sprawę, że w przypadku niektórych liter takich jak "T" może to nie mieć sensu, ponieważ długopis musiałby zostać podniesiony, aby przekroczyć "T". Więc może potrzebuję sekwencji CGPath s ...

Jakieś wskazówki, jak to osiągnąć?

Dzięki!

+1

[Co próbowaliście?] (Http://whathaveyoutried.com) – EmilioPelaez

Odpowiedz

29

Przejście od litery "P" do sekwencji punktów obejmuje kilka kroków. Musisz użyć Core Text.

  1. Utwórz CTFont. Od wersji iOS 7 można użyć numeru UIFont, w którym wymagany jest CTFont (są to "mosty bez opłat"). Można również utworzyć numer CTFont bezpośrednio z poziomu CGFont za pomocą funkcji CTFontCreateWithGraphicsFont lub według nazwy, używając CTFontCreateWithName (lub kilku innych metod).

  2. Uzyskaj glify do litery za pomocą funkcji CTFontGetGlyphsForCharacters. Dla litery "P" powinien być tylko jeden glif. W przypadku niektórych znaków w skryptach innych niż angielski można uzyskać wiele (łączących) glifów.

  3. Użyj funkcji CTFontCreatePathForGlyph, aby uzyskać CGPath dla glifu.

  4. Użyj CGPathApply, aby wyliczyć elementy ścieżki.

  5. Konwersja każdej linii, kwadratu i elementu krzywej sześciennej ścieżki do sekwencji punktów. Apple nie zapewnia żadnego publicznego interfejsu API do tego celu. Musisz to zrobić samodzielnie. Dla elementów prostych jest to łatwe. W przypadku elementów krzywych należy wykonać pewne badania, jeśli nie wiemy jeszcze, jak renderować krzywą Béziera. Na przykład zobacz convert bezier curve to polygonal chain?.

Możemy poeksperymentować z tym łatwo w Swift Playground:

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

Wynik:

<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

Dzięki! Dam ci szansę i zgłoś się ponownie ... – Joel

+0

@RobMayoff Doskonała odpowiedź!Właśnie tego szukałem! Ponieważ wydajesz się znać swoje CGPaths, czy wiesz, w jaki sposób mogę dodać linię do właśnie stworzonej ścieżki? Powiedz na przykład do punktu wyjścia. Po prostu dodając: 'niech pathP = CGPathCreateMutableCopy (CGPathCreateMutableCopy (cgpath)) CGPathAddLineToPoint (pathP, nil, 0, 0)' nie wydaje się work.' – user594883

+0

Co to znaczy „nie wydają się działać” oznacza? Musisz wysłać nowe pytanie zawierające twój kod, dane wyjściowe (zrzucenia zmodyfikowanej ścieżki) i wyjaśnienia, co jest nie tak z danymi wyjściowymi. –

2

Dla tych, którzy szukają tego samego rozwiązania w 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 
    } 
Powiązane problemy