我想使用文本创建蒙版,并且需要将文本转换为图像。但转换后发现与原文不完全吻合。我进行了以下测试。
class MyView: NSView{
override func draw(_ dirtyRect: NSRect) {
guard let g = NSGraphicsContext.current?.cgContext else{ return }
let antialiasing = false //true or false is useless
g.setAllowsAntialiasing(antialiasing)
g.setShouldAntialias(antialiasing)
let text: NSString = "HELLO"
let pos: CGPoint = .init(x: 20, y: 20)
let font: NSFont = .init(name: "Arial Black", size: 96)!
var textAttr: [NSAttributedString.Key: Any] = [
.font : font
]
//Draw the blue text in new CGContext, generate an image, draw the image in current CGContext
let image = createImage(dirtyRect: dirtyRect) { g in
g.setAllowsAntialiasing(antialiasing)
g.setShouldAntialias(antialiasing)
textAttr[.foregroundColor] = NSColor.blue
text.draw(at: pos, withAttributes: textAttr)
}
g.draw(image!, in: dirtyRect, byTiling: false)
//Draw the yellow text with all same properties
let attr: [NSAttributedString.Key: Any] = [
.font : font,
.foregroundColor : NSColor.yellow
]
text.draw(at: pos, withAttributes: attr)
}
private func createImage(dirtyRect: NSRect, drawingHandler: ((_ g: CGContext) -> Void)?) -> CGImage?{
NSGraphicsContext.saveGraphicsState()
let g = CGContext(data: nil,
width: Int(dirtyRect.width),
height: Int(dirtyRect.height),
bitsPerComponent: 8,
bytesPerRow: 0,
space: CGColorSpaceCreateDeviceRGB(),
bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue)!
NSGraphicsContext.current = NSGraphicsContext(cgContext: g, flipped: false)
drawingHandler?(g)
let image = g.makeImage()
NSGraphicsContext.restoreGraphicsState()
return image
}
}
可以看到,两个文字堆叠后并不能完全重叠,下方的蓝色文字露出一圈边缘。
我尝试了其他
createImage
方法,例如创建一个NSImage
并在其上绘制文本,或者创建一个CGLayer
并在该图层上绘制文本然后创建图像,结果相似。
唯一完美的解决方案是使用当前的
CGContext
并禁用抗锯齿来生成文本图像。但这种方法的问题是,生成的图像将包含所有绘制的内容,其中一些对我来说可能不是必需的。
private func createImage(dirtyRect: NSRect, drawingHandler:((_ g: CGContext) -> Void)?) -> CGImage?{
drawingHandler?(NSGraphicsContext.current!.cgContext)
return NSGraphicsContext.current?.cgContext.makeImage()
}
有什么解决办法吗? 谢谢。
尝试打印
g
和 draw(_:)
中的 createImage
。它们属于不同的类型,因此它们的行为不同也就不足为奇了(尽管我无法确切地告诉您有什么区别)。
如果您使用
this 初始化程序绘制到
NSImage
中,则两个文本确实重叠,然后使用当前上下文将该图像转换为 CGImage
。
private func createImage(dirtyRect: NSRect, drawingHandler: @escaping (_ g: CGContext) -> Void) -> CGImage?{
let image = NSImage(size: dirtyRect.size, flipped: false) { _ in
guard let g = NSGraphicsContext.current?.cgContext els { return false }
drawingHandler(g)
return true
}
// presumably passing context: nil uses the current context,
// but you can also use context: NSGraphicsContext.current
return image.cgImage(forProposedRect: nil, context: nil, hints: nil)
}