我正在使用CoreGraphics在CGContext中与原语一起绘制单个字形。以下代码在XCode 9.2的快速操场上工作。在操场上启动时,操场liveView中的给定坐标处将出现一个带有两个字母A的小矩形。
import Cocoa
import PlaygroundSupport
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)
context.setFillColor(CGColor(red: 0.99, green: 0.99, blue: 0.85, alpha: 1))
context.beginPath()
context.addRect(rect)
context.fillPath()
context.setFillColor(.black)
// prepare variables and constants
var font = CTFontCreateWithName("Helvetica" as CFString, 48, nil)
var glyph = CTFontGetGlyphWithName(font, "A" as CFString)
var glyph1Position = CGPoint(x: self.frame.minX, y: self.frame.maxY/2)
var glyph2Position = CGPoint(x: self.frame.minX+150, y: self.frame.maxY/2)
let text = "Hello"
var textOrigin = NSPoint(x: self.frame.minX+50, y: self.frame.maxY/2)
// draw one character
CTFontDrawGlyphs(font, &glyph, &glyph1Position, 1, context)
// *** *** when the next line is uncommented the bug appears *** ***
// text.draw(at: textOrigin)
CTFontDrawGlyphs(font, &glyph, &glyph2Position, 1, context)
}
}
var frameRect = CGRect(x: 0, y: 0, width: 200, height: 100)
PlaygroundPage.current.liveView = MyView(inFrame: frameRect)
现在,我想在相同的上下文中绘制常规文本。但是,当通过其自身的绘制方法在两个字形的图形之间绘制文本字符串时,当前上下文似乎被弄乱了,第二个字形将不会显示。在同时绘制两个字形之后绘制文本时,一切都很好。
显然,绘制文本似乎对当前的CGContext产生了影响,但是我无法确定到底发生了什么。我尝试过用saveGstate()方法绘制字符串并随后还原,但没有成功。
我还尝试使用CoreText方法使用CTFramesetterCreateWithAttributedString创建一个属性字符串,并使用CTFramesetterCreateFrame显示它,它也不起作用,这里创建框架设置器后,上下文混乱了。
我的实际游乐场更加复杂,字形并没有完全消失,而是以错误的垂直位置显示,但是基本问题-和问题相同:
在后台对上下文进行任何其他更改的情况下,如何将文本绘制到currentContext中?
答案 0 :(得分:2)
您需要设置文本矩阵(应用于文本绘图的变换)。您应该始终在绘制文本之前进行设置,因为它不是图形状态的一部分,并且可能会被其他绘制代码(例如AppKit的字符串绘制扩展名)所破坏。
在致电CTFontDrawGlyphs
之前添加以下内容:
context.textMatrix = .identity
这应该在上下文的初始设置中调用,因为在调用drawRect
之前无法保证文本矩阵将是标识。然后,每当您调用修改文本矩阵的对象时,都需要将其重新设置为所需的对象(在这种情况下,是同一性,但是如果您想以精美的方式进行绘制,则可能是其他事情)。 / p>
修改文本矩阵并不总是很明显。 AppKit绘图功能几乎总是起作用(尽管我不知道有任何文档表明这一点)。修改上下文的Core Text函数(例如CTFrameDraw
和CTLineDraw
)通常会使用以下语句来记录这一事实:
此调用可以使上下文保持任何状态,并且在绘制操作之后不会刷新上下文。
类似地CTFontDrawGlyphs
警告:
如果以字体指定了这些属性,则此功能会修改图形状态,包括字体,文本大小和文本矩阵。这些属性不会恢复。
通常我不鼓励混合使用文本绘图系统。使用AppKit或Core Text,但不要混合使用。如果您选择一个并坚持下去,那么通常就没有问题(只要您在drawRect
的顶部初始化一次矩阵)。例如,如果您使用CTFontDrawGlyphs
完成了所有绘图,则无需每次都重置矩阵。您将停留在“核心文字”矩阵中就可以了(这就是为什么当您注释掉draw(at:)
调用后此方法有效的原因。)