Skip to content

Instantly share code, notes, and snippets.

@warpling
Last active January 10, 2023 05:22
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save warpling/95b18be18a48150569ad9953dd717758 to your computer and use it in GitHub Desktop.
Save warpling/95b18be18a48150569ad9953dd717758 to your computer and use it in GitHub Desktop.
AttributedString to UIBezierPath
extension UIBezierPath {
// Source: https://github.com/aderussell/string-to-CGPathRef/blob/0bd9350dc2100029f3ddb8d9667384841549ecd6/ARCGPathFromString/ARCGPathFromString.m
convenience init(attributedString: NSAttributedString) {
let letters = CGMutablePath()
let line = CTLineCreateWithAttributedString(attributedString as CFAttributedString)
let runArray = CTLineGetGlyphRuns(line)
// for each RUN
for runIndex in 0..<CFArrayGetCount(runArray) {
// Get FONT for this run
let run = unsafeBitCast(CFArrayGetValueAtIndex(runArray, runIndex), to: CTRun.self)
let runFontValue = CFDictionaryGetValue(CTRunGetAttributes(run), unsafeBitCast(kCTFontAttributeName, to: UnsafeRawPointer.self))
let runFont = unsafeBitCast(runFontValue, to: CTFont.self)
// for each GLYPH in run
for runGlyphIndex in 0..<CTRunGetGlyphCount(run) {
// get Glyph & Glyph-data
let thisGlyphRange = CFRangeMake(runGlyphIndex, 1)
var glyph: CGGlyph = CGGlyph()
var position: CGPoint = .zero
CTRunGetGlyphs(run, thisGlyphRange, &glyph)
CTRunGetPositions(run, thisGlyphRange, &position)
// Get PATH of outline
do {
var glyphTransform = CGAffineTransform(translationX: position.x, y: position.y)
if let letter = CTFontCreatePathForGlyph(runFont, glyph, &glyphTransform) {
// The glyph will initially be upsidedown because CoreText works in an inverted coordinate system.
// After flipping we need to move the glyph back down.
let t = CGAffineTransform(scaleX: 1, y: -1).translatedBy(x: 0, y: -letter.boundingBoxOfPath.height)
// Because we flipped the text with a transform the drawing direction of the path is unexpectedly reversed
// This will reverse it back to make evenOdd binary path operations behave as expected
let reverseWindingLetter = UIBezierPath(cgPath: letter).reversing().cgPath
letters.addPath(reverseWindingLetter, transform: t)
}
}
}
}
self.init(cgPath: letters.copy()!)
}
}
@niteshjha2619
Copy link

How to use this? Can you please explain ??

@warpling
Copy link
Author

warpling commented Jan 4, 2023

@niteshjha2619 which part is confusing? You pass it an attributed string and it returns its bezier path

@niteshjha2619
Copy link

I tried but not created path. Can you please share how to use?

@niteshjha2619
Copy link

` let myAttribute = [ NSAttributedString.Key.foregroundColor: UIColor.blue, NSAttributedString.Key.font: UIFont.systemFont(ofSize: 50) ]
let myAttrString = NSAttributedString(string: "A", attributes: myAttribute)

    let path = UIBezierPath(attributedString: myAttrString)
    print(path)
    let pathLayer = CAShapeLayer()
    pathLayer.frame = self.viewLayer.bounds
    pathLayer.bounds = path.cgPath.boundingBox
    pathLayer.backgroundColor = UIColor.red.cgColor
    pathLayer.isGeometryFlipped = false
    self.viewLayer.layer.addSublayer(pathLayer)`
    
    
    I used this code

@warpling
Copy link
Author

warpling commented Jan 5, 2023

Perhaps you need to set fillColor instead of backgroundColor for it to show up?

@niteshjha2619
Copy link

Not working By using fill color and stroke color both I used but not showing path

@warpling
Copy link
Author

warpling commented Jan 9, 2023

I don't know why I didn't notice it the first time but you aren't assigning the path to the layer's path!! 😆

pathLayer.path = path.cgPath

@warpling
Copy link
Author

warpling commented Jan 9, 2023

You might notice once you get it working that the font baseline isn't working correctly. I don't use this code anymore and don't have the time to figure out how to fix this but if you do please let me know!
image

@niteshjha2619
Copy link

Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment