Search code examples
swiftanimated-gifphassetavasset

Swift: PHAsset ImageDataRequest changes .GIF to .JPEG


I try to get the data of PHAssets (Videos, Images, Animated GIFs). Until today it worked relatively good to process the Videos with:

PHImageManager.default().requestAVAsset(forVideo: asset, options: option, resultHandler: self.requestAVVideoAsset)

then the Images with:

PHImageManager.default().requestImage(for: asset, targetSize: imageSize, contentMode: .aspectFill, options: option, resultHandler: self.requestAVImage)

And the GIFs with:

PHImageManager.default().requestImageData(for: asset, options: option, resultHandler: self.requestAVPhotoAsset)

I check with uniformTypeIdentifier if it is a GIF and with the PHAssetMediaType if it is an image or a video. This works as plant, but after the requestImageData the GIFs are converted to JPEGs and I only get an JPEG URL.

In the Photo app the GIFs are working fine. And the first few times the GIFs worked as expected, but after a few tests it stopped working.

Here my code:

var isGIF = false
let resources = PHAssetResource.assetResources(for: asset)
for resource in resources {
     if resource.uniformTypeIdentifier == (kUTTypeGIF as String) {
         isGIF = true // THIS WORKS
     }
}

if (asset.mediaType == .video) {
     let option = PHVideoRequestOptions()
     option.isNetworkAccessAllowed = true
     option.deliveryMode = PHVideoRequestOptionsDeliveryMode.highQualityFormat
                PHImageManager.default().requestAVAsset(forVideo: asset, options: option, resultHandler: self.requestAVVideoAsset)
} else {
     let option = PHImageRequestOptions()
     option.isSynchronous = false
     option.isNetworkAccessAllowed = true
     option.resizeMode = .exact
     option.deliveryMode = .highQualityFormat
     let imageSize = CGSize(width: asset.pixelWidth, height: asset.pixelHeight)

     if isGIF {
        // IS CALLED
        PHImageManager.default().requestImageData(for: asset, options: option, resultHandler: self.requestAVPhotoAsset)
     } else {
        PHImageManager.default().requestImage(for: asset, targetSize: imageSize, contentMode: .aspectFill, options: option, resultHandler: self.requestAVImage)
     }
}

And then in requestAVPhotoAsset:

func requestAVPhotoAsset(data: Data?, type: String?, orientation: UIImageOrientation, options: [AnyHashable: Any]?) {


    // THE TYPE IS HERE: "public.jpeg"

   ...
}

Thank you in advance!


Solution

  • I had a look at it again and I found the class member: "version" in the PHImageRequestOptions

    This can be set to "original", so now I have this:

    let option = PHImageRequestOptions()
    option.isSynchronous = false
    option.isNetworkAccessAllowed = true
    option.resizeMode = .exact
    option.deliveryMode = .highQualityFormat
    option.version = .original
    

    This works for me.

    I think the reason for this is that Apple converts GIFs to an array of Images since iOS 11 and so if I use the original version it takes the gif data. Please correct me if I am wrong, this is just an assumption!

    BTW. it also kind of works for a few GIFs to have "unadjusted" as version, but not for all PHAssets.