CoreGraphics绘制NSView导出PNG时像素精度异常(1pt线宽变2px)
问题原因
你的导出结果线宽翻倍是因为macOS Retina屏幕的backingScaleFactor 缩放机制:当前主流Mac设备默认缩放因子为2,即1个逻辑点对应2个物理像素。你使用bitmapImageRepForCachingDisplay生成位图时,会自动匹配当前屏幕的缩放因子,所以1.0点的线宽最终渲染为2像素。
另外你贴出的draw方法中仅创建了路径,没有调用currentContext?.stroke()执行描边操作,属于代码遗漏,请先补上。
解决方案
根据你的像素精度需求,可选两种方案:
方案1:强制导出1x分辨率(点与像素1:1对应)
该方案可以保证你代码中设置的尺寸和导出的像素尺寸完全一致,最符合像素精度要求。替换getImage方法实现如下:
func getImage() -> NSImage? { let size = bounds.size // 强制1倍缩放,1点=1像素 let scale: CGFloat = 1.0 let pixelSize = CGSize(width: size.width * scale, height: size.height * scale) guard let context = CGContext( data: nil, width: Int(pixelSize.width), height: Int(pixelSize.height), bitsPerComponent: 8, bytesPerRow: 0, space: CGColorSpaceCreateDeviceRGB(), bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue ) else { return nil } context.scaleBy(x: scale, y: scale) // 直接调用draw方法渲染到自定义上下文 layer?.render(in: context) guard let cgImage = context.makeImage() else { return nil } let image = NSImage(cgImage: cgImage, size: size) return image }
方案2:保留Retina分辨率,动态调整线宽
如果你需要导出和屏幕显示效果一致的2x分辨率图片,只需要将线宽按当前缩放因子动态调整即可:
在draw方法中修改线宽设置:
// 获取当前窗口的缩放因子 let scale = window?.backingScaleFactor ?? 1.0 // 线宽设置为1像素对应的点大小 currentContext?.setLineWidth(1.0 / scale)
如果需要保证线条完全对齐像素避免抗锯齿,可对路径坐标做0.5点偏移(1x场景):
currentContext?.move(to: CGPoint(x: 0.5, y: 0.5)) currentContext?.addLine(to: CGPoint(x: self.frame.width - 0.5, y: self.frame.height - 0.5))
内容的提问来源于stack exchange,提问作者metal_man
相关产品推荐
相关产品推荐

