3

After switching to iCloud Photo, it seems that some of the images returned by UIImagePickerController are very blur. It looks like the image are taken from iCloud Photo.

Am I able to retrieve the original image, or filter off iCloud Photo images, or do I have to switch to other frameworks to do what UIImagePickerController do?

Shruti Thombre
  • 989
  • 4
  • 11
  • 27
Lim Thye Chean
  • 8,704
  • 9
  • 49
  • 88
  • I think this is related to this other question I posted: https://stackoverflow.com/q/60254076/1765629 -- I assume you have "Optimize iPhone Storage" under your Photos Settings? Try switching to "Download and Keep Originals" just for testing. If it fixes the issue, then we "just" need to find another way to get hold of the originals, if possible at all... – endavid Feb 17 '20 at 23:16

1 Answers1

3

From the symptoms, I'm going to assume you are using something like this to load your images:

    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
        if let image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage {
            loadImageInMemory(image)
        }
        picker.dismiss(animated: true, completion: nil)
        self.presentingViewController?.dismiss(animated: true, completion: nil)
    }

where loadImageInMemory is a function where you process the image.

It turns out that if you use that method, images stored over iCloud may be retrieved in lower quality than the original. A way to verify that this is the case is to change your Photos settings. From the Settings app:

Settings -> Photos -> Download and Keep Originals

This would fix the issue, but of course it's not desirable. If you want to keep using Photos, instead of implementing your own iCloud solution, while keeping the Optimize iPhone Storage setting, you can use PhotoKit to retrieve the original image.

Use this code instead:

import Photos

// ...

    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
        // it will be loaded asynchronously
        loadImageFromPicker(info: info)
        picker.dismiss(animated: true, completion: nil)
        self.presentingViewController?.dismiss(animated: true, completion: nil)
    }

    private func loadImageFromPicker(info: [UIImagePickerController.InfoKey : Any]) {
        var phAsset: PHAsset?
        if #available(iOS 11.0, *) {
            phAsset = info[UIImagePickerController.InfoKey.phAsset] as? PHAsset
        } else {
            // Fallback on earlier versions
            if let referenceURL = info[UIImagePickerController.InfoKey.referenceURL] as? URL {
                let fetchResult = PHAsset.fetchAssets(withALAssetURLs: [referenceURL], options: nil)
                phAsset = fetchResult.firstObject
            }
        }
        guard let asset = phAsset else {
            return
        }
        // size doesn't matter, because resizeMode = .none
        let size = CGSize(width: 32, height: 32)
        let options = PHImageRequestOptions()
        options.version = .original
        options.deliveryMode = .highQualityFormat
        options.resizeMode = .none
        options.isNetworkAccessAllowed = true
        PHImageManager.default().requestImage(for: asset, targetSize: size, contentMode: .aspectFit, options: options) { [weak self] (image, info) in
            if let s = self, let image = image {
                s.loadImageInMemory(image)
            }
        }
    }

This code will work with both local images and iCloud images.

This has fixed a similar problem I experienced working with small PNG images with alpha. See this other post for reference.

Community
  • 1
  • 1
endavid
  • 1,781
  • 17
  • 42
  • Is there a reason you are using the `referenceURL` from the info dictionary to fetch the `PHAsset`, instead of directly accessing the `phAsset` value of that dictionary? See https://developer.apple.com/documentation/uikit/uiimagepickercontroller/infokey/2890963-phasset – strnmn Oct 13 '20 at 15:30
  • @strnmn I've edited my answer with your suggestion. That's for iOS 11 or greater. You still need the old referenceURL if you are supporting older versions of iOS. The earliest version I support is iOS9. – endavid Oct 29 '20 at 23:24