web-dev-qa-db-fra.com

PHAsset to UIImage

J'essaie de créer un UIImage (comme une vignette ou quelque chose de ce genre) à partir d'un PHAsset afin de pouvoir le transférer dans quelque chose qui prend un UIImage. J'ai essayé d'adapter les solutions que j'ai trouvées sur SO (puisqu'elles passent toutes directement dans une table, par exemple), mais je n'ai aucun succès (probablement parce que je ne le fais pas correctement).

func getAssetThumbnail(asset: PHAsset) -> UIImage {
    var retimage = UIImage()
    println(retimage)
    let manager = PHImageManager.defaultManager()
    manager.requestImageForAsset(asset, targetSize: CGSize(width: 100.0, height: 100.0), contentMode: .AspectFit, options: nil, resultHandler: {(result, info)->Void in
            retimage = result
    })
    println(retimage)
    return retimage
}

Les imprimeurs me disent que la ligne manager.request ne fait rien pour le moment. Comment puis-je l'obtenir pour me donner l'actif en tant que UIImage.

Merci.

44
dcheng

Cela a fait ce que je devais faire, au cas où quelqu'un en aurait aussi besoin.

func getAssetThumbnail(asset: PHAsset) -> UIImage {
    let manager = PHImageManager.defaultManager()
    let option = PHImageRequestOptions()
    var thumbnail = UIImage()
    option.synchronous = true
    manager.requestImageForAsset(asset, targetSize: CGSize(width: 100.0, height: 100.0), contentMode: .AspectFit, options: option, resultHandler: {(result, info)->Void in
            thumbnail = result!
    })
    return thumbnail
}

Edit: mise à jour Swift 3

func getAssetThumbnail(asset: PHAsset) -> UIImage {
    let manager = PHImageManager.default()
    let option = PHImageRequestOptions()
    var thumbnail = UIImage()
    option.isSynchronous = true
    manager.requestImage(for: asset, targetSize: CGSize(width: 100, height: 100), contentMode: .aspectFit, options: option, resultHandler: {(result, info)->Void in
        thumbnail = result!
    })
    return thumbnail
}
75
dcheng

essayez cela cela fonctionne pour moi, j'espère que cela vous aide aussi,

func getUIImage(asset: PHAsset) -> UIImage? {

    var img: UIImage?
    let manager = PHImageManager.default()
    let options = PHImageRequestOptions()
    options.version = .original
    options.isSynchronous = true
    manager.requestImageData(for: asset, options: options) { data, _, _, _ in

        if let data = data {
            img = UIImage(data: data)
        }
    }
    return img
}
20
Patel Jigar

Pour Swift 3.0.1:

func getAssetThumbnail(asset: PHAsset, size: CGFloat) -> UIImage {
    let retinaScale = UIScreen.main.scale
    let retinaSquare = CGSize(width: size * retinaScale, height: size * retinaScale)//(size * retinaScale, size * retinaScale)
    let cropSizeLength = min(asset.pixelWidth, asset.pixelHeight)
    let square = CGRect(x:0, y: 0,width: CGFloat(cropSizeLength),height: CGFloat(cropSizeLength))
    let cropRect = square.applying(CGAffineTransform(scaleX: 1.0/CGFloat(asset.pixelWidth), y: 1.0/CGFloat(asset.pixelHeight)))

    let manager = PHImageManager.default()
    let options = PHImageRequestOptions()
    var thumbnail = UIImage()

    options.isSynchronous = true
    options.deliveryMode = .highQualityFormat
    options.resizeMode = .exact
    options.normalizedCropRect = cropRect

    manager.requestImage(for: asset, targetSize: retinaSquare, contentMode: .aspectFit, options: options, resultHandler: {(result, info)->Void in
        thumbnail = result!
    })
    return thumbnail
}

Ressources: https://Gist.github.com/lvterry/f062cf9ae13bca76b0c6#file-getassetthumbnail-Swift

7
Sour LeangChhean

Je suggérerais d'utiliser PHCachingImageManager d'Apple (qui hérite de PHImageManager):

Un objet PHCachingImageManager récupère ou génère des données d'image pour des éléments photo ou vidéo.

En outre, PHCachingImageManager prend en charge un meilleur mécanisme de mise en cache.

Exemple de récupération d'une miniature synchrone:

let options = PHImageRequestOptions()
options.deliveryMode = .HighQualityFormat
options.synchronous = true // Set it to false for async callback

let imageManager = PHCachingImageManager()
imageManager.requestImageForAsset(YourPHAssetVar,
                                  targetSize: CGSizeMake(CGFloat(160), CGFloat(160)),
                                  contentMode: .AspectFill,
                                  options: options,
                                  resultHandler: { (resultThumbnail : UIImage?, info : [NSObject : AnyObject]?) in

                                                   // Assign your thumbnail which is the *resultThumbnail*
                                                  }

De plus, vous pouvez utiliser PHCachingImageManager pour mettre en cache vos images pour une réponse plus rapide de l'interface utilisateur:

Pour utiliser un gestionnaire d'images en cache:

  1. Créez une instance de PHCachingImageManager. (Cette étape remplace l'utilisation de l'instance PHImageManager partagée Partagée.)

  2. Utilisez les méthodes de classe PHAsset pour récupérer les actifs qui vous intéressent.

  3. Pour préparer des images pour ces éléments, appelez le startCachingImagesForAssets: targetSize: contentMode: options: method avec la taille cible, le mode de contenu et les options que vous prévoyez d'utiliser quand demander plus tard des images pour chaque élément individuel.

  4. Lorsque vous avez besoin d’une image pour un élément individuel, appelez le requestImageForAsset: targetSize: contentMode: options: resultHandler: méthode, et transmettez les mêmes paramètres que vous avez utilisés lors de la préparation de cette atout.

Si l'image que vous demandez fait partie de celles déjà préparées, le fichier L'objet PHCachingImageManager renvoie immédiatement cette image . Sinon, Photos prépare l'image à la demande et la met en cache pour plus tard utilisation.

Dans notre exemple:

var phAssetArray : [PHAsset] = []

for i in 0..<assets.count
{
  phAssetArray.append(assets[i] as! PHAsset)
}

let options = PHImageRequestOptions()
options.deliveryMode = .Opportunistic
options.synchronous = false

self.imageManager.startCachingImagesForAssets(phAssetArray,
                                              targetSize: CGSizeMake(CGFloat(160), CGFloat(160)),
                                              contentMode: .AspectFill,
                                              options: options)
6
OhadM

Solution simple (Swift 4.2)  

Méthode 1:

extension PHAsset {

    var image : UIImage {
        var thumbnail = UIImage()
        let imageManager = PHCachingImageManager()
        imageManager.requestImage(for: self, targetSize: CGSize(width: 100, height: 100), contentMode: .aspectFit, options: nil, resultHandler: { image, _ in
            thumbnail = image!
        })
        return thumbnail
    }
}                          

let image = asset.image 

Utilisez cette méthode si vous avez uniquement besoin de UIImage à partir de PHAsset.

OU

extension PHAsset {
    func image(targetSize: CGSize, contentMode: PHImageContentMode, options: PHImageRequestOptions?) -> UIImage {
        var thumbnail = UIImage()
        let imageManager = PHCachingImageManager()
        imageManager.requestImage(for: self, targetSize: targetSize, contentMode: contentMode, options: options, resultHandler: { image, _ in
            thumbnail = image!
        })
        return thumbnail
    }
}

let image = asset.image(targetSize: CGSize, contentMode: PHImageContentMode, options: PHImageRequestOptions?)

Utilisez cette méthode pour votre UIImage désirée.

OU

extension PHAsset {

    func image(completionHandler: @escaping (UIImage) -> ()){
        var thumbnail = UIImage()
        let imageManager = PHCachingImageManager()
        imageManager.requestImage(for: self, targetSize: CGSize(width: 100, height: 100), contentMode: .aspectFit, options: nil, resultHandler: { img, _ in
            thumbnail = img!
        })
        completionHandler(thumbnail)
    }
}

let image = asset.image(completionHandler: {(img) in
    print("Finished")
})

Utilisez cette méthode pour notifier après la fin.

Méthode 2:

extension PHAsset {
    var data : (UIImage, [AnyHashable : Any]) {
        var img = UIImage(); var information = [AnyHashable : Any](); let imageManager = PHCachingImageManager()
        imageManager.requestImage(for: self, targetSize: CGSize(width: 100, height: 100), contentMode: .aspectFit, options: nil, resultHandler: { image,info in
            img = image!
            information = info!
        })
        return (img,information)
    }
} 


let image_withData : (UIImage, [AnyHashable : Any]) = asset.data

Utilisez cette méthode si vous souhaitez UIImage et les informations de résultat de PHAsset

OU

extension PHAsset {

    func data(targetSize: CGSize, contentMode: PHImageContentMode, options: PHImageRequestOptions?) -> (UIImage, [AnyHashable : Any]) {
        var img = UIImage(); var information = [AnyHashable : Any](); let imageManager = PHCachingImageManager()
        imageManager.requestImage(for: self, targetSize: targetSize, contentMode: contentMode, options: options, resultHandler: { image,info in
            img = image!
            information = info!
        })
        return (img,information)
    }
}

let data = asset?.data(targetSize: CGSize, contentMode: PHImageContentMode, options: PHImageRequestOptions?)

Utilisez cette méthode pour les données souhaitées.

5
ZAFAR007

Le problème est que requestImageForAsset est un resultHandler et que ce bloc de code se produit ultérieurement lorsque vos fonctions ont déjà été imprimées et ont renvoyé la valeur que vous attendiez. Je suis venu des changements pour vous montrer ce qui se passe et suggère également des solutions simples. 

func getAssetThumbnail(asset: PHAsset) {
    var retimage = UIImage()
    println(retimage)
    let manager = PHImageManager.defaultManager()
    manager.requestImageForAsset(asset, targetSize: CGSize(width: 100.0, height: 100.0), contentMode: .AspectFit, options: nil, resultHandler: {
    (result, info)->Void in
            retimage = result
      println("This happens after")
      println(retimage)
      callReturnImage(retimage) // <- create this method
    })
    println("This happens before")
}

En savoir plus sur les fermetures, la gestion des travaux d’achèvement et les fonctions asynchrones à Documentation Apple

J'espère que ça vous aide!

4
Icaro

Swift 4.

resizeMode, deliveryMode - Ces options peuvent être définies en fonction des besoins de l'utilisateur.

isNetworkAccessAllowed - définissez ceci sur "true" pour récupérer des images du nuage

imageSize- taille d'image requise

func getImageFromAsset(asset:PHAsset,imageSize:CGSize, callback:@escaping (_ result:UIImage) -> Void) -> Void{

    let requestOptions = PHImageRequestOptions()
    requestOptions.resizeMode = PHImageRequestOptionsResizeMode.fast
    requestOptions.deliveryMode = PHImageRequestOptionsDeliveryMode.highQualityFormat
    requestOptions.isNetworkAccessAllowed = true
    requestOptions.isSynchronous = true
    PHImageManager.default().requestImage(for: asset, targetSize: imageSize, contentMode: PHImageContentMode.default, options: requestOptions, resultHandler: { (currentImage, info) in
        callback(currentImage!)
    })
}
4
Thomas Paul

Version du code Objective-c basée sur dcheng answer. 

-(UIImage *)getAssetThumbnail:(PHAsset * )asset {

    PHImageRequestOptions *options = [[PHImageRequestOptions alloc]init];
    options.synchronous = true;

    __block UIImage *image;
    [PHCachingImageManager.defaultManager requestImageForAsset:asset targetSize:CGSizeMake(100, 100) contentMode:PHImageContentModeAspectFit options:options resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) {
        image = result;
    }];
    return image;
  }
0
Saikiran K