[英]How can I get the optical bounds of an NSAttributedString?
我需要屬性字符串的光學范圍。 我知道我可以調用.size()方法並讀取其寬度,但這顯然給了我印刷范圍,在右邊有額外的空間。
我的字符串都非常短,僅包含1-3個字符,因此每個字符串都將恰好包含一個glyphrun。
我找到了函數CTRunGetImageBounds,並且按照注釋中鏈接的提示進行操作之后,我能夠提取運行並獲得界限,但是顯然,這並沒有給我想要的結果。
以下Swift 4代碼可在XCode9 Playground中使用:
import Cocoa
import PlaygroundSupport
public func getGlyphWidth(glyph: CGGlyph, font: CTFont) -> CGFloat {
var glyph = glyph
var bBox = CGRect()
CTFontGetBoundingRectsForGlyphs(font, .default, &glyph, &bBox, 1)
return bBox.width
}
class MyView: NSView {
init(inFrame: CGRect) {
super.init(frame: inFrame)
}
required init?(coder decoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func draw(_ rect: CGRect) {
// setup context properties
let context: CGContext = NSGraphicsContext.current!.cgContext
context.setStrokeColor(CGColor.black)
context.setTextDrawingMode(.fill)
// prepare variables and constants
let alphabet = ["A","B","C","D","E","F","G","H","I","J","K","L"]
let font = CTFontCreateWithName("Helvetica" as CFString, 48, nil)
var glyphX: CGFloat = 10
// draw alphabet as single glyphs
for letter in alphabet {
var glyph = CTFontGetGlyphWithName(font, letter as CFString)
var glyphPosition = CGPoint(x: glyphX, y: 80)
CTFontDrawGlyphs(font, &glyph, &glyphPosition, 1, context)
glyphX+=getGlyphWidth(glyph: glyph, font: font)
}
let textStringAttributes: [NSAttributedStringKey : Any] = [
NSAttributedStringKey.font : font,
]
glyphX = 10
// draw alphabet as attributed strings
for letter in alphabet {
let textPosition = NSPoint(x: glyphX, y: 20)
let text = NSAttributedString(string: letter, attributes: textStringAttributes)
let line = CTLineCreateWithAttributedString(text)
let runs = CTLineGetGlyphRuns(line) as! [CTRun]
let width = (CTRunGetImageBounds(runs[0], nil, CFRange(location: 0,length: 0))).maxX
text.draw(at: textPosition)
glyphX += width
}
}
}
var frameRect = CGRect(x: 0, y: 0, width: 400, height: 150)
PlaygroundPage.current.liveView = MyView(inFrame: frameRect)
該代碼在游樂場實時視圖的上一行中,將A-L中的單個字母繪制為單個字形。 水平位置將在每個字母之后按字母寬度前進,該寬度通過getGlyphWidth函數獲取。
然后,它使用相同的字母從中創建屬性字符串,然后將其用於首先創建CTLine,從中提取(唯一的)CTRun,最后測量其寬度。 結果在實時視圖的第二行中顯示。
第一行是期望的結果:width函數精確返回每個字母的寬度,從而使它們彼此接觸。
我希望屬性字符串版本具有相同的結果,但是在這里ImageBounds似乎添加了我想避免的其他填充。
如何測量給定文本從最左邊到最右邊像素的確切寬度?
並且有沒有那么笨拙的方法來實現此目標而不必強制轉換四次(NSAtt.Str-> CTLine-> CTRun-> CGRect-> maxX)?
好的,我自己找到了答案:
使用CTRunGetImageBounds的.width參數而不是.maxX可帶來正確的結果
CTLine也存在相同的功能:CTLineGetImageBounds
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.