iOS猫狗图像分类PoC迁移macOS:NSImage转CVPixelBuffer遇阻
macOS下NSImage转CVPixelBuffer的修复方案
错误原因解析
- CGImage获取方式错误:NSImage没有iOS中UIImage的直接
cgImage属性,需通过cgImage(forProposedRect:context:hints:)方法获取,该方法返回可选类型CGImage?,因此必须用可选绑定处理。 - 坐标系与API差异:macOS的NSImage坐标原点在左下角,与CVPixelBuffer(和iOS一致)的左上角原点不同,直接绘制会导致图像颠倒;另外无需直接访问
dataProvider,通过CGContext绘制即可完成像素数据写入。
修复后的完整代码
import Cocoa import CoreVideo import CoreGraphics extension NSImage { func toCVPixelBuffer() -> CVPixelBuffer? { let imageSize = self.size let attributes = [ kCVPixelBufferCGImageCompatibilityKey: kCFBooleanTrue, kCVPixelBufferCGBitmapContextCompatibilityKey: kCFBooleanTrue ] as CFDictionary var pixelBuffer: CVPixelBuffer? let status = CVPixelBufferCreate( kCFAllocatorDefault, Int(imageSize.width), Int(imageSize.height), kCVPixelFormatType_32BGRA, attributes, &pixelBuffer ) guard status == kCVReturnSuccess, let buffer = pixelBuffer else { return nil } // 获取NSImage对应的CGImage var proposedRect = CGRect(origin: .zero, size: imageSize) guard let cgImage = self.cgImage(forProposedRect: &proposedRect, context: nil, hints: nil) else { return nil } CVPixelBufferLockBaseAddress(buffer, []) defer { CVPixelBufferUnlockBaseAddress(buffer, []) } // 创建CGContext并处理坐标系翻转 guard let context = CGContext( data: CVPixelBufferGetBaseAddress(buffer), width: Int(imageSize.width), height: Int(imageSize.height), bitsPerComponent: 8, bytesPerRow: CVPixelBufferGetBytesPerRow(buffer), space: CGColorSpaceCreateDeviceRGB(), bitmapInfo: CGImageAlphaInfo.premultipliedFirst.rawValue ) else { return nil } // 翻转坐标系,匹配CVPixelBuffer的原点规则 context.translateBy(x: 0, y: imageSize.height) context.scaleBy(x: 1.0, y: -1.0) // 将CGImage绘制到CVPixelBuffer context.draw(cgImage, in: CGRect(origin: .zero, size: imageSize)) return buffer } }
关键修改点
- CGImage获取:使用
cgImage(forProposedRect:context:hints:)方法,通过可选绑定确保获取有效CGImage实例。 - 坐标系适配:通过CGContext的
translateBy和scaleBy方法翻转坐标系,避免图像上下颠倒。 - 安全处理:所有可能返回nil的步骤均用
guard let校验,保证代码稳定性。
内容的提问来源于stack exchange,提问作者Andrew P.
相关产品推荐
相关产品推荐

