iOS 13 - PHImageManager returns a downscaled image for My Photo Stream photos

384 views Asked by At

Since iOS 13 I can't get original-res versions of photos in My Photo Stream using PhotoKit. I've had several complaints from users over the last few months, so it's not anything specific to my own device or account. The following code always retreives very small images (e.g. 360 x 480).

PHPhotoLibrary.requestAuthorization({ status in
    DispatchQueue.main.async {
        if status == .authorized {

            // if iCloud Photo Library is disabled and Photo Stream is enabled this will give you My Photo Stream
            let photoStream = PHAssetCollection.fetchAssetCollections(with: .album, subtype: .albumMyPhotoStream, options: nil)
            if let photoStreamCollection = photoStream.firstObject {

                let res = PHAsset.fetchAssets(in: photoStreamCollection, options: nil)
                if let asset = res.firstObject {

                    let opts = PHImageRequestOptions()
                    opts.deliveryMode = .highQualityFormat
                    opts.isSynchronous = true
                    opts.isNetworkAccessAllowed = true
                    opts.resizeMode = .exact

                    print("asset size: \(asset.pixelWidth) x \(asset.pixelHeight)")

                    PHImageManager.default().requestImage(for: asset, targetSize: PHImageManagerMaximumSize, contentMode: .default, options: opts) { (img, info) in
                        if let img = img {
                            print("image size: \(img.size.width * img.scale) x \(img.size.height * img.scale)")
                        }
                    }

                    PHImageManager.default().requestImageDataAndOrientation(for: asset, options: opts) { (imgData, dateUTI, orientation, info) in
                        if let imgData = imgData {
                            if let img = UIImage(data: imgData) {
                                print("image size: \(img.size.width * img.scale) x \(img.size.height * img.scale)")
                            }
                        }
                    }
                }
            }
        }
    }
})

Console:
asset size: 1536 x 2048
2020-02-02 08:18:44.452620-0700 photostreamphoto[7370:2576203] [ImageManager] [RM]: 1-1-0 Failed to decode image
2020-02-02 08:18:44.468675-0700 photostreamphoto[7370:2576203] [ImageManager] [RM]: 1-1-0 Failed to decode image
2020-02-02 08:18:44.479691-0700 photostreamphoto[7370:2576203] [ImageManager] [RM]: 1-1-0 Failed to decode image
image size: 360.0 x 480.0
2020-02-02 08:18:44.485069-0700 photostreamphoto[7370:2576203] [ImageManager] [RM]: 1-2-0 Failed to load image from URL: file:///var/mobile/Media/PhotoStreamsData/267078714/100APPLE/IMG_0001.JPG
2020-02-02 08:18:44.490447-0700 photostreamphoto[7370:2576203] [ImageManager] [RM]: 1-2-0 Failed to load image from URL: file:///var/mobile/Media/PhotoStreamsData/267078714/100APPLE/IMG_0001.JPG
2020-02-02 08:18:44.501745-0700 photostreamphoto[7370:2576203] [ImageManager] [RM]: 1-2-0 Failed to load image from URL: file:///var/mobile/Media/PhotoStreamsData/267078714/100APPLE/IMG_0001.JPG
image size: 360.0 x 480.0

I've tried every conceivable combination of options in PHRequestOptions. Note that if I set opts.version = .original it gives me a nil image and nil image data.

I've also tried asset.requestContentEditingInput(...) to try to access the image URL directly:

let editingOpts = PHContentEditingInputRequestOptions()
editingOpts.isNetworkAccessAllowed = true
editingOpts.canHandleAdjustmentData = { data in
    return true
}
asset.requestContentEditingInput(with: editingOpts) { input, info in
    if let input = input, let url = input.fullSizeImageURL {
        let path = url.path
        let fm = FileManager.default
        if fm.fileExists(atPath: path) {
            // doesn't reach this
        }
    }
}

Console:

2020-02-02 08:26:49.641787-0700 photostreamphoto[7416:2578984] [PhotoKit] Asset resource file URL not reachable, may have been pruned, will attempt availability change request

Interestingly, UIImagePicker does retrieve the original-res image (e.g. 1536 x 2048). The Photos app also shows the full-res image. I wish I knew what black magic they're using.

If anyone knows of a workaround, please share.

0

There are 0 answers