Post

Replies

Boosts

Views

Activity

Core Text calculate letter AND ruby annotation frames in iOS with Swift
How can I get the bounding box for each ruby annotation character (or furigana) in a CTFrame text rendered by CoreText and CoreGraphics in iOS? (iOS 11, 12 or 13) I made a swift version program that encloses each character in a red box but I wasn't able to get the bounding boxes for the ruby annotation characters, *aka furigana*. I painted in green the ruby character boxes for the purpose of this question. (Please see the image in the GitHub link) How can I achieve that? Any Ideas? Edit: For clarity, the green boxes were painted by hand in an illustration software. I need to draw the green boxes by code. The full source is in GitHub https://github.com/huse360/LetterFrame This is the main source code: override func draw(_ rect: CGRect) { &#9;&#9;&#9;&#9;guard let context = UIGraphicsGetCurrentContext() else { return } &#9;&#9;&#9; &#9;&#9;&#9;&#9; &#9;&#9;&#9; context.textMatrix = .identity &#9;&#9;&#9; context.translateBy(x: 0, y: self.bounds.size.height) &#9;&#9;&#9; context.scaleBy(x: 1.0, y: -1.0) &#9;&#9;&#9; &#9;&#9;&#9;&#9; &#9;&#9;&#9; let string = "|優勝《ゆうしょう》の|懸《か》かった|試合《しあい》。|Test《テスト》.\nThe quick brown fox jumps over the lazy dog. 12354567890 @#-+" &#9; &#9;&#9;&#9;&#9; &#9;&#9;&#9; let attributedString = Utility.sharedInstance.furigana(String: string) &#9;&#9;&#9; &#9;&#9;&#9; let range = attributedString.mutableString.range(of: attributedString.string) &#9;&#9;&#9; attributedString.addAttribute(.font, value: font, range: range) &#9;&#9;&#9; &#9;&#9;&#9; let framesetter = attributedString.framesetter() &#9;&#9;&#9; &#9;&#9;&#9; let textBounds = self.bounds.insetBy(dx: 20, dy: 20) &#9;&#9;&#9; let frame = framesetter.createFrame(textBounds) &#9;&#9;&#9;&#9; //Draw the frame text: &#9;&#9;&#9; &#9;&#9;&#9; frame.draw(in: context) &#9;&#9;&#9;&#9;&#9;&#9;&#9; &#9;&#9;&#9; let origins = frame.lineOrigins() &#9;&#9;&#9; &#9;&#9;&#9; let lines = frame.lines() &#9;&#9;&#9;&#9;context.setStrokeColor(UIColor.red.cgColor) &#9;&#9;&#9;&#9;context.setLineWidth(0.7) &#9;&#9;&#9;&#9;for i in 0 ..< origins.count { &#9;&#9;&#9;&#9;&#9;&#9;let line = lines[i] &#9;&#9;&#9;&#9;&#9;&#9; &#9;&#9;&#9;&#9;&#9;&#9;for run in line.glyphRuns() { &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9; &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;let font = run.font &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;let glyphPositions = run.glyphPositions() &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;let glyphs = run.glyphs() &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9; &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;let glyphsBoundingRects =&#9;font.boundingRects(of: glyphs) &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9; //DRAW the bounding box for each glyph: &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9; &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;for k in 0 ..< glyphPositions.count { &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;let point = glyphPositions[k] &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;let gRect = glyphsBoundingRects [k] &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9; &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;var box = gRect &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;box.origin +=&#9;point + origins[i] + textBounds.origin &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;context.stroke(box) &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9; &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;}// for k &#9;&#9;&#9;&#9;&#9;&#9; &#9;&#9;&#9;&#9;&#9;&#9;}//for run &#9;&#9;&#9;&#9;&#9;&#9; &#9;&#9;&#9; }//for i &#9;&#9;&#9;&#9; &#9;&#9;}//func draw
2
0
774
Aug ’20