Im wondering what's the best and most reliable way to get RAW image files using PHImageManager.default().requestImage and getting the full resolution?
I have some code that needs to loop through a set of images. For JPG, TIF, PNG etc, everything works fine. For any RAW images taken from an another camera, it works fine but only if I leave the device to do some kind of processing to the RAW files for a few minutes first. If I try to read the images straight after import, a low res version is nearly always loaded. I only ever need one image at a time so once I've used the PHPicker they go into a loop with autorelease too.
So far I have tried both "PHImageManager.default().requestImage" and "PHImageManager.default().requestImageDataAndOrientation"
With .requestImage, everything is perfect with the exception of newly imported raw files...
With .requestImageDataAndOrientation, it seems to load the full RAW image data immediately after import but it can randomly returns nil for photos in an iCloud Photo Library (regardless of being optimised or not) and photos in a shared album. I know that this method is better suited to images stored on device but I know that wont always be the case.
I have got my PHImageRequestOptions showing like this:
let options = PHImageRequestOptions()
options.isSynchronous = true
options.isNetworkAccessAllowed = true
options.resizeMode = .exact
options.version = .unadjusted
options.deliveryMode = .highQualityFormat
options.progressHandler = { [self] (progress, error, stop, info) in
titleProgress(txt: "\(Int(loopNo - 1)) of \(Int(c - 1)) - (Downloading \(Int(progress * 100))%)")
}
And im getting the image using this:
let theAsset = PHAsset.fetchAssets(withLocalIdentifiers:
[imgArray[n].assetID],
options: nil)[0]
PHImageManager.default().requestImage(for: theAsset,
targetSize: CGSize(width: theAsset.pixelWidth,
height: theAsset.pixelHeight), contentMode: PHImageContentMode.aspectFill, options: options, resultHandler: { [self]
(image, info) in
if image != nil {
So if I imported say 50 images from an SD card into the library and ran the app, maybe 5 images would load full res. If I leave it another 2 mins roughly half would load full res. A few more mins and all of them load full resolution and look totally fine. But every image that loads whether full res or low res will always give a 0 for info![PHImageResultIsDegradedKey]! which doesn't make sense to me.
So another option I have explored is using .requestImage to reliably pull the image from the cloud (or just load it even if photo library is set to download originals) and then .requestImageDataAndOrientation to get the RAW image at full resolution.
let theAsset = PHAsset.fetchAssets(withLocalIdentifiers: [imgArray[n].assetID], options: nil)[0]
PHImageManager.default().requestImage(for: theAsset, targetSize: CGSize(width: theAsset.pixelWidth, height: theAsset.pixelHeight), contentMode: PHImageContentMode.aspectFill, options: options, resultHandler: { [self]
(image, info) in
if image != nil {
PHImageManager.default().requestImageDataAndOrientation(for: theAsset, options: options) { (data, _, _, _) in
let imageData = UIImage(data: data!)!
Doing this does actually allow me to get the full resolution RAW files immediately after import but the line...
let imageData = UIImage(data: data!)!
will occasionally fail with the error "Fatal error: Unexpectedly found nil while unwrapping an Optional value" even though "data" at this point is never nil. For some reason it wont convert to a UIImage.
So as it stands, I think my only option is to check if the file is RAW, and advise the user to wait a minute or so for the device to process the images in a way they can be correctly read.
Is there a better practice to reading RAW files as soon as they are on device that i've just totally missed or am I just doing something wrong in my code?
Many thanks!