itsfaraaz
itsfaraaz

Reputation: 191

How to get thumbnail for video from PHAsset?

I am trying to populate aa UICollectionView with thumbnails of videos and photos extracted from the user's camera roll. I loaded all the media from the camera roll in the form of PHAsset inside the array images as declared here:

var images = [PHAsset]()

The if-then loop checks to see if the PHAsset is either a image or a video. If it is a image, it simply adds it to the collection view. However, I am not sure how I would add a thumbnail of a video to the collection view. Any help is appreciated.

  func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "PhotoLibraryCollectionViewCell", for: indexPath) as! PhotoLibraryCollectionViewCell
    let asset = images[indexPath.row]

    if asset.mediaType == PHAssetMediaType.image {
        let manager = PHImageManager.default()
        let option = PHImageRequestOptions()
        var thumbnail = UIImage()
        option.isSynchronous = true
        manager.requestImage(for: asset, targetSize: CGSize(width: 138, height: 138), contentMode: .aspectFit, options: option, resultHandler: {(result, info)->Void in
            thumbnail = result!
        })
        cell.imageView.image = thumbnail
    } else {
        // code to add the thumbnail of the video to the collection view
    }

    return cell
  }

Edit: I tried removing the if-then method but the collection view shows no thumbnail for the videos at all.

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "PhotoLibraryCollectionViewCell", for: indexPath) as! PhotoLibraryCollectionViewCell

    let asset = images[indexPath.row]
    let manager = PHImageManager.default()
    let option = PHImageRequestOptions()
    var thumbnail = UIImage()
    option.isSynchronous = true
    option.isNetworkAccessAllowed = true
    manager.requestImage(for: asset, targetSize: CGSize(width: 138, height: 138), contentMode: .aspectFit, options: option, resultHandler: {(result, info)->Void in
        thumbnail = result!
    })
    cell.imageView.image = thumbnail

    return cell
}

If you look at the link below, I clearly have a video in my camera roll but it doesn't show up in the collection view: https://i.sstatic.net/EIP8W.jpg

Upvotes: 1

Views: 7010

Answers (2)

ahbou
ahbou

Reputation: 4918

When using PHAsset requestImage(for:targetSize:contentMode:options:resultHandler:) works for both Photos and Videos.

From Apple documentation:

You can use this method for both photo and video assets for a video asset, an image request provides a thumbnail image or poster frame.

So just drop the if statement and call request the thumbnail for both types.

let manager = PHImageManager.default()
        let option = PHImageRequestOptions()
        var thumbnail = UIImage()
        option.isSynchronous = true
        manager.requestImage(for: asset, targetSize: CGSize(width: 138, height: 138), contentMode: .aspectFit, options: option, resultHandler: {(result, info)->Void in
            thumbnail = result!
        })
        cell.imageView.image = thumbnail

Edit: Make sure network access is allowed

options.isNetworkAccessAllowed = true

Upvotes: 8

zombie
zombie

Reputation: 5259

you can try to use PHCachingImageManager as in Apple sample project

let cachingImageManager = PHCachingImageManager()

and somewhere before loading the items call try to load the caches

func updateCache() {
    //Update the size here
    let size: CGSize = CGSize(width: 138, height: 138)

    cachingImageManager.startCachingImages(for: images, targetSize: size, contentMode: .aspectFit, options: nil)
}

then loading the thumbnail for images and videos would be like this

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "PhotoLibraryCollectionViewCell", for: indexPath) as! PhotoLibraryCollectionViewCell

    let asset = images[indexPath.row]

    let size = CGSize(width: 138, height: 138)

    let option = PHImageRequestOptions()
    option.isSynchronous = true

    cachingImageManager.requestImage(for: asset, targetSize: size, contentMode: .aspectFit, options: option) { image, info in
        cell.imageView.image = image
    }

    return cell
}

Note: loading the images from the PHAsset without cacheing might lead to a memory issue

you might need to create another PHCachingImageManager in case of items change in the images array

Upvotes: 1

Related Questions