如何将 CIImage 保存为 P3 颜色 space 完整的照片?
How do I save a CIImage to Photos with its P3 color space intact?
我正在构建一个相机应用程序,它以 BGRA 格式拍摄照片,并在将其保存到照片应用程序之前对其应用 Core Image 滤镜。在 iPhone 7 Plus 上,输入照片是显示 P3 颜色 space,但输出是 sRGB 颜色 space:
如何防止这种情况发生?
这是我的代码:
let sampleBuffer: CMSampleBuffer = ...
let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)!
let metadata = CMCopyDictionaryOfAttachments(nil, self, kCMAttachmentMode_ShouldPropagate)!
let ciImage = CIImage(cvImageBuffer: pixelBuffer,
options:[kCIImageProperties: metadata])
NSLog("\(ciImage.colorSpace)")
let context = CIContext()
let data = context.jpegRepresentation(of: ciImage,
colorSpace: ciImage.colorSpace!,
options: [:])!
// Save this using PHPhotoLibrary.
这会打印:
Optional(<CGColorSpace 0x1c40a8a60> (kCGColorSpaceICCBased; kCGColorSpaceModelRGB; Display P3))
(在我的实际代码中,我对 CIImage 应用了一个过滤器,它创建了另一个 CIImage,我保存了它。但是即使使用原始 CIImage 我也可以重现这个问题,所以我已经删除了过滤器。)
如何将 Core Image 滤镜应用到 P3 图像并将其保存为 P3 图像,而不是 sRGB?
备注:
(1) 这是 iPhone 7 加 运行 iOS 11.
(2) 我使用的是广角镜头,不是长焦、双镜头或前置镜头。
(3) 如果我要求 AVFoundation 给我一个 JPEG 编码的图像而不是 BGRA,并在不涉及 Core Image 的情况下保存它,这个问题就不会发生——颜色 space 不会减少到 sRGB。
(4) 我尝试使用 kCIImageColorSpace,但没有任何区别:
let p3 = CGColorSpace(name: CGColorSpace.displayP3)!
let ciImage = CIImage(
cvImageBuffer: pixelBuffer,
options:[kCIImageProperties: metadata,
kCIImageColorSpace: p3])
(5) 除了上述之外,我尝试使用 kCIContextOutputColorSpace 作为创建 CIContext 时的参数,但它再次没有任何区别。
(6) 获取数据并将其保存到 PHPhotoLibrary 的代码不是问题,因为它适用于上述情况 (2)。
let context = CIContext(options: [kCIContextOutputColorSpace: CGColorSpace.p3])
如何将 Core Image 滤镜应用到 P3 图像并将其保存为 P3 图像,而不是 sRGB?
我遇到了同样的问题,我认为这可能是 context.jpegRepresentation(..) 的错误。
我使用 ImageIO 创建 JPEG 数据取得了更多成功,如下面的 createJPEGData 函数所示。例如:
let eaglContext = EAGLContext(api: .openGLES2)
let options = [kCIContextWorkingColorSpace: CGColorSpace(name: CGColorSpace.extendedSRGB)!,
kCIContextOutputPremultiplied: true,
kCIContextUseSoftwareRenderer: false] as [String : Any]
let ciContext = CIContext(eaglContext: eaglContext, options: options)
let colorSpace = CGColorSpace(name: CGColorSpace.displayP3)!
guard let imageData = createJPEGData(from: image,
jpegQuality: 0.9,
outputColorSpace: colorSpace,
context: ciContext) else {
return
}
PHPhotoLibrary.shared().performChanges({ () -> Void in
let creationRequest = PHAssetCreationRequest.forAsset()
creationRequest.addResource(with: .photo,
data: imageData,
options: nil)
}, completionHandler: { (success: Bool, error : Error?) -> Void in
// handle errors, etc
})
func createJPEGData(from image: CIImage,
jpegQuality: Float,
outputColorSpace: CGColorSpace,
context: CIContext) -> Data? {
let jpegData: CFMutableData = CFDataCreateMutable(nil, 0)
if let destination = CGImageDestinationCreateWithData(jpegData, kUTTypeJPEG, 1, nil) {
if let cgImage = context.createCGImage(image,
from: image.extent,
format: kCIFormatRGBA8,
colorSpace: outputColorSpace) {
CGImageDestinationAddImage(destination, cgImage, image.properties as CFDictionary?)
if CGImageDestinationFinalize(destination) {
return jpegData as Data
}
}
}
}
我正在构建一个相机应用程序,它以 BGRA 格式拍摄照片,并在将其保存到照片应用程序之前对其应用 Core Image 滤镜。在 iPhone 7 Plus 上,输入照片是显示 P3 颜色 space,但输出是 sRGB 颜色 space:
如何防止这种情况发生?
这是我的代码:
let sampleBuffer: CMSampleBuffer = ...
let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)!
let metadata = CMCopyDictionaryOfAttachments(nil, self, kCMAttachmentMode_ShouldPropagate)!
let ciImage = CIImage(cvImageBuffer: pixelBuffer,
options:[kCIImageProperties: metadata])
NSLog("\(ciImage.colorSpace)")
let context = CIContext()
let data = context.jpegRepresentation(of: ciImage,
colorSpace: ciImage.colorSpace!,
options: [:])!
// Save this using PHPhotoLibrary.
这会打印:
Optional(<CGColorSpace 0x1c40a8a60> (kCGColorSpaceICCBased; kCGColorSpaceModelRGB; Display P3))
(在我的实际代码中,我对 CIImage 应用了一个过滤器,它创建了另一个 CIImage,我保存了它。但是即使使用原始 CIImage 我也可以重现这个问题,所以我已经删除了过滤器。)
如何将 Core Image 滤镜应用到 P3 图像并将其保存为 P3 图像,而不是 sRGB?
备注:
(1) 这是 iPhone 7 加 运行 iOS 11.
(2) 我使用的是广角镜头,不是长焦、双镜头或前置镜头。
(3) 如果我要求 AVFoundation 给我一个 JPEG 编码的图像而不是 BGRA,并在不涉及 Core Image 的情况下保存它,这个问题就不会发生——颜色 space 不会减少到 sRGB。
(4) 我尝试使用 kCIImageColorSpace,但没有任何区别:
let p3 = CGColorSpace(name: CGColorSpace.displayP3)!
let ciImage = CIImage(
cvImageBuffer: pixelBuffer,
options:[kCIImageProperties: metadata,
kCIImageColorSpace: p3])
(5) 除了上述之外,我尝试使用 kCIContextOutputColorSpace 作为创建 CIContext 时的参数,但它再次没有任何区别。
(6) 获取数据并将其保存到 PHPhotoLibrary 的代码不是问题,因为它适用于上述情况 (2)。
let context = CIContext(options: [kCIContextOutputColorSpace: CGColorSpace.p3])
如何将 Core Image 滤镜应用到 P3 图像并将其保存为 P3 图像,而不是 sRGB?
我遇到了同样的问题,我认为这可能是 context.jpegRepresentation(..) 的错误。
我使用 ImageIO 创建 JPEG 数据取得了更多成功,如下面的 createJPEGData 函数所示。例如:
let eaglContext = EAGLContext(api: .openGLES2)
let options = [kCIContextWorkingColorSpace: CGColorSpace(name: CGColorSpace.extendedSRGB)!,
kCIContextOutputPremultiplied: true,
kCIContextUseSoftwareRenderer: false] as [String : Any]
let ciContext = CIContext(eaglContext: eaglContext, options: options)
let colorSpace = CGColorSpace(name: CGColorSpace.displayP3)!
guard let imageData = createJPEGData(from: image,
jpegQuality: 0.9,
outputColorSpace: colorSpace,
context: ciContext) else {
return
}
PHPhotoLibrary.shared().performChanges({ () -> Void in
let creationRequest = PHAssetCreationRequest.forAsset()
creationRequest.addResource(with: .photo,
data: imageData,
options: nil)
}, completionHandler: { (success: Bool, error : Error?) -> Void in
// handle errors, etc
})
func createJPEGData(from image: CIImage,
jpegQuality: Float,
outputColorSpace: CGColorSpace,
context: CIContext) -> Data? {
let jpegData: CFMutableData = CFDataCreateMutable(nil, 0)
if let destination = CGImageDestinationCreateWithData(jpegData, kUTTypeJPEG, 1, nil) {
if let cgImage = context.createCGImage(image,
from: image.extent,
format: kCIFormatRGBA8,
colorSpace: outputColorSpace) {
CGImageDestinationAddImage(destination, cgImage, image.properties as CFDictionary?)
if CGImageDestinationFinalize(destination) {
return jpegData as Data
}
}
}
}