I am attempting to output a CIImage to disk, and am looking for the most efficient way possible. I found this question, which suggests using the writeJPEGRepresentation
/writePNGRepresentation
methods of CIContext. However, whenever I attempt to use those methods, they produce blank images.
In the case of JPEG, it produces a pure black image. PNG produces a pure transparent image. The HEIF method also produced a pure black image. Same result if I use the jpegRepresentation
or pngRepresentation
methods which generate a Data
, instead of writing directly to disk.
If I instead render these objects using createCGImage
, and then write out the data from the CGImage, they look fine.
Any ideas why this might be happening?
Here's a simple example that illustrates the problem:
let ciImage = CIImage(contentsOf: photoURL, options: [CIImageOption.applyOrientationProperty: true])!
let context = CIContext()
try! context.writeJPEGRepresentation(of: ciImage, to: FileManager.default.temporaryDirectory.appendingPathComponent("testFromCIImage.jpeg"), colorSpace: CGColorSpace(name: CGColorSpace.sRGB)!, options: [:])
let cgImage: CGImage = context.createCGImage(ciImage, from: ciImage.extent)!
let uiImage = UIImage(cgImage: cgImage)
try! uiImage.jpegData(compressionQuality: 1.0)!.write(to: FileManager.default.temporaryDirectory.appendingPathComponent("testFromUIImage.jpeg"))
testFromCIImage.jpeg
appears as a blank image, with the same size as the original input image. testFromUIImage.jpeg
appears identical to the input image.
I have created a sample project that illustrates the issue, along with a few sample images.
Update
I have found only one condition where the image outputs correctly - when the source image is a PNG, and the colorSpace
parameter of writeJPEGRepresentation
matches the color space of the source image. I have not had success with any JPEG, even when the color space matches.
As you said, this seems to be an issue exclusive to the Simulator. However, I did some more digging and found the following:
When inspecting what Core Image is doing (by setting the CI_PRINT_TREE
environment variable) I found that the tree looks normal (though the resulting image is black). However, for the working configurations nothing was printed at all! That seems to me that Core Image is not actually doing any rendering but maybe Image I/O is used directly for writing the JPG.
Which led me to try forcing Core Image to use the software renderer (instead of its default Metal renderer) by passing CIContextOption.useSoftwareRenderer
on context creation. However, this is totally ignored. The resulting context is still a Metal context...
So yeah, it seems the only feasible workaround is via CGImage
right now. It would be great if you would file a bug with Apple.