Last active
January 10, 2023 05:22
-
-
Save warpling/95b18be18a48150569ad9953dd717758 to your computer and use it in GitHub Desktop.
AttributedString to UIBezierPath
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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()!) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks