Reputation: 3218
I'm currently trying to convert a letter and/or multiple of them to a CGPathRef for manually drawing them into a custom UIView. I tried the way over CoreText and Framesetters including this little snippet but it doesn't seem to work.
NSAttributedString *stringToDraw = [[NSAttributedString alloc] initWithString:content
attributes:nil];
// now for the actual drawing
CGContextRef context = UIGraphicsGetCurrentContext();
// flip the coordinate system
// draw
CTFramesetterRef frameSetter = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef)stringToDraw);
CTFrameRef frame = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0, 0), NULL, NULL);
return CTFrameGetPath(frame);
Upvotes: 4
Views: 3844
Reputation: 41
this is the working function which create
This function is transforming a string of text into a set of vector paths, each representing a single glyph. The paths are stored in a CGMutablePath, which can later be used for drawing or rendering the text in a custom way
func textToPath(text: String, font: UIFont) -> CGPath? {
let attributedString = NSAttributedString(string: text, attributes: [.font: font])
let line = CTLineCreateWithAttributedString(attributedString)
let runArray = CTLineGetGlyphRuns(line) as NSArray
let path = CGMutablePath()
for run in runArray {
let run = run as! CTRun
let count = CTRunGetGlyphCount(run)
for index in 0..<count {
let range = CFRangeMake(index, 1)
var glyph: CGGlyph = 0
var position: CGPoint = .zero
CTRunGetGlyphs(run, range, &glyph)
CTRunGetPositions(run, range, &position)
if let glyphPath = CTFontCreatePathForGlyph(font, glyph, nil) {
var transform = CGAffineTransform(translationX: position.x, y: position.y)
transform = transform.scaledBy(x: 1, y: -1)
path.addPath(glyphPath, transform: transform)
}
}
}
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5, execute: {
cgPath = path
})
return path
}
Upvotes: 0
Reputation: 299565
CTFrameGetPath
returns the path the circumscribes the CTFrame
, not the path generated by drawing the frame. I assume that you're doing the above because you are caching the paths to improve later drawing performance? (Since CTFrame
can easily draw itself into a custom view).
If you really want to get CGPath
, you need to drill all the way down to the CGGlyph
and then use CTFontCreatePathForGlyph
. If you just want to quickly redraw text, I'd probably draw this into a CGLayer
(not CALayer
) with CTFrameDraw
for later reuse.
If you still really want the CGPath
for the glyphs, take a look at Low-level text rendering. The code you need is in there.
Upvotes: 8