Déterminer la plus grande taille d’image PHAsset disponible sur les appareils iOS

Comment puis-je déterminer la taille d’image PHAsset la plus grande disponible sur un appareil iOS, où “disponible” signifie “actuellement” sur l’appareil, ne nécessitant aucun téléchargement réseau depuis iCloud Photo Library?

J’ai développé une application où une collection de vignettes est affichée dans un UICollectionView (un peu comme l’application Photos), puis un utilisateur peut sélectionner une image pour la voir en taille réelle. Si nécessaire, l’image en taille réelle est téléchargée depuis iCloud. Cependant, je veux montrer à l’utilisateur la plus grande version possible de l’image jusqu’à ce que la taille complète soit disponible.

Le fonctionnement du framework de photos est plutôt étrange:

Dans la vue de collection, j’utilise un PHCachingImageManager pour mettre en cache (et demander plus tard) des images avec une targetSize de 186×186 pixels (doubler les dimensions UICollectionViewCell raison de la mise à l’échelle de la rétine).

Cela fonctionne très bien, avec un défilement très rapide et aucun décalage dans le remplissage des cellules avec des images. En vérifiant la taille des images renvoyées, elles représentent environ 342×256 pixels. C’est sur mon iPhone 6 avec iCloud Photo Library activé et «Optimiser le stockage» activé, de sorte que seules les petites vignettes sont stockées sur le périphérique pour la plupart des images.

Cependant, la partie étrange est que si je demande ensuite la version pleine grandeur (ou beaucoup plus grande) de n’importe quelle image, avec PHCachingImageManager ou PHImageManager.defaultManager() utilisant l’option PHImageRequestOptionsDeliveryMode.Opportunistic , la première image renvoyée est un minuscule timbre postal de 60 x 45 pixels qui semble horrible en plein écran, jusqu’à ce que l’image en taille réelle soit téléchargée pour la remplacer.

De toute évidence, il existe déjà des vignettes plus grandes (342×256) sur l’appareil, telles qu’elles apparaissaient dans la vue des collections! Alors pourquoi ne les renvoie-t-il pas comme la première image de «qualité médiocre» tant que la taille complète n’a pas été téléchargée? Juste pour m’assurer que les images 342×256 étaient réellement sur l’appareil, j’ai exécuté le code en mode avion, donc aucun access au réseau n’était en cours.

Ce que j’ai trouvé, c’est que si je demandais une taille allant jusqu’à 256×256, je récupérerais les images 342×256. Dès que je suis devenu plus grand (même 1 pixel), il me serait d’abord renvoyé des images 60×45, puis j’ai essayé de télécharger l’image en taille réelle.

J’ai changé mon code pour faire une demande 256×256 en premier, suivi d’une requête en taille réelle avec PHImageRequestOptionsDeliveryMode.HighQualityFormat (qui ne renvoie pas une petite image intermédiaire), et cela fonctionne parfaitement. C’est aussi ce que l’application iOS Photos doit faire car elle affiche des vignettes de qualité relativement élevée tout en téléchargeant l’image complète.

Alors, avec ce contexte, comment puis-je savoir quelle est la taille d’image la plus importante pour un PHAsset ? 256×256 est-il un nombre magique, ou dépend-il de la façon dont iCloud Photo Library optimise l’espace (en fonction de la taille de la bibliothèque et de l’espace de stockage disponible)?

Cela semble certainement être un bogue que Photos Framework ne retourne pas la plus grande image actuellement disponible (lorsqu’on lui demande une taille supérieure à sa taille actuelle), et que pour obtenir la plus grande taille possible, vous devez demander cette taille ou la plus petite. parce que si vous demandez plus gros, vous obtiendrez une miniature 60×45! Bizarre.

MISE À JOUR: Rapport de bogue soumis à Apple: https://openradar.appspot.com/25181601
Exemple de projet qui illustre le bogue: https://github.com/mluisbrown/PhotoKitBug

En utilisant l’exemple de projet affiché dans la question, j’ai pu reproduire le problème dans le simulateur, mais lorsque j’ai apporté la modification suivante, je ne recevais que la plus grande image:

 let targetSize = PHImageManagerMaximumSize 

En fait, je ne connais pas la raison pour laquelle Apple renverrait l’image 45 * 60 dégradée avec PHImageResultIsDegradedKey = 1. Pour moi, je demande tout d’abord l’image 256 * 256 avec deliveryMode PHImageRequestOptionsDeliveryModeHighQualityFormat, puis j’utilise l’autre PHImageRequestOptions pour demander une image en taille réelle comme ci-dessous:

 PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init]; options.networkAccessAllowed = YES; options.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat; options.progressHandler = ^(double progress, NSError *error, BOOL *stop, NSDictionary *info){ // code to update the iCloud download progress }); [[PHImageManager defaultManager] requestImageForAsset:asset targetSize:PHImageManagerMaximumSize contentMode:PHImageContentModeAspectFit options:options resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) { // code to update UIImageView or something else. }); 

Et je pense, Instagram peut être utiliser cette solution similaire pour gérer l’image de iCloud.

 [imageManager requestImageForAsset:asset targetSize: PHImageManagerMaximumSize contentMode:PHImageContentModeAspectFill options:nil resultHandler:^(UIImage *result, NSDictionary *info) { result; }];