获取在iOS UIFont中追踪字符的path

假设我在我的iOS应用程序中使用了自定义字体“Foo”。 我已经将它添加到我的项目,plist等等,我能够渲染UILabel s等。

现在,如果我想找出一系列可以“追踪”字母“P”的点,那么我将如何得到这个点的序列呢? 例如,假设我想用CGPath像绘图仪那样缓慢地绘制字母“P”…

我只需要一个数组中的CGPoints序列,如果绘制为一个path将绘制一个“P”。

我意识到,对于一些像“T”这样的字母来说,这可能是没有意义的,因为笔必须被提起才能越过“T”。 所以也许我需要一个CGPath序列…

有关如何完成此任何提示?

谢谢!

从字母“P”到点序列包括几个步骤。 你需要使用核心文本。

  1. 创build一个CTFont 。 从iOS 7开始,可以使用需要UIFontCTFont (它们是“免费桥接”)。 您也可以使用CTFontCreateWithGraphicsFont函数直接从CGFont创buildCTFont ,或者使用CTFontCreateWithName (或使用其他几个方法)通过名称创buildCTFontCreateWithName

  2. 使用CTFontGetGlyphsForCharacters函数获取字母的字形。 字母“P”应该只有一个字形。 对于非英文脚本中的某些字符,您可能会获得多个(组合)字形。

  3. 使用CTFontCreatePathForGlyph函数为字形获取CGPath

  4. 使用CGPathApply来枚举path的元素。

  5. 将path中的每条线,四条曲线和三次曲线元素转换为一系列点。 苹果公司没有提供任何公共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字形路径

对于那些在Objective C中寻找同样解决scheme的人来说

  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 }