CGContext.makeImage创建的图像与原文不同

问题描述 投票:0回答:1

我想使用文本创建蒙版,并且需要将文本转换为图像。但转换后发现与原文不完全吻合。我进行了以下测试。

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()
}

有什么解决办法吗? 谢谢。

swift macos cocoa cgcontext quartz-2d
1个回答
0
投票

尝试打印

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)
}
© www.soinside.com 2019 - 2024. All rights reserved.