UIImagePickerControllerを使うと静止画を選択することができます。それだけではなく動画も選択することが可能です。選択した静止画(または動画)はPHAssetオブジェクトの形でデータを扱うこととなります。
本記事では、取得したPHAssetオブジェクトからサムネイル画像を生成する方法をご紹介します。
動画からサムネイル画像を生成する
UIImagePickerControllerを起動して、静止画と動画を選択できるようにする。
let vc = UIImagePickerController() vc.mediaTypes = [ "public.image", "public.movie" ] vc.sourceType = UIImagePickerController.SourceType.photoLibrary vc.delegate = self self?.present(vc, animated: true, completion: nil)
ユーザーが選択したコンテンツのPHAssetを取得する
ユーザーがコンテンツを選択すると UIImagePickerControllerDelegate#imagePickerController(_, didFinishPickingMediaWithInfo:)
が呼ばれるので、この中で 選択したコンテンツから表示すべき静止画を取得します。
静止画の場合はそのままオリジナル画像を取得しても良いが、動画の場合は選択された動画からサムネイル画像を生成する。
// MARK: - UIImagePickerControllerDelegate func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) { //コンテンツタイプを取得する guard let mediaType = info[.mediaType] as? String else { return } // コンテンツタイプによって処理を分ける switch mediaType.lowercased() { case "public.image": guard let image = (info[.originalImage] as? UIImage) else { return } // 静止画の場合は、そのままオリジナル画像を取得する case "public.movie": guard let asset = info[.phAsset] as? PHAsset else { return } guard let image = VideoUtil.loadThumbnail(asset: asset, longSideSize: 1024) else { return } // 動画の場合は、選択した動画からサムネイル画像を生成する default: return } }
PHAssetの動画からサムネイル画像を生成する
最近のiPhoneデバイスでは高画質の動画を扱うことも増えてきました。UITableViewなどでリストのサムネイルとして使う場合、オリジナル動画サイズのサムネイル画像を生成するのは負荷面を考えると避けるべきです。
長辺を指定した上で、動画からサムネイル画像を生成する方法をご紹介します。
import UIKit import Photos class VideoUtil { /// サムネイルを取得する static func loadThumbnail(asset: PHAsset, longSideSize: CGFloat? = nil) -> UIImage? { let size = calcAspectSize(width: asset.pixelWidth, height: asset.pixelHeight, longSideSize: longSideSize) var thumbnailImage: UIImage? = nil let option = PHImageRequestOptions() option.isSynchronous = true option.isNetworkAccessAllowed = true option.progressHandler = { (progress, error, stop, info) in print("load thumbnail: \(progress)") } //NOTE: PHImageManagerMaximumSizeと使うと画質が悪化してしまう let manager = PHImageManager.default() manager.requestImage(for: asset, targetSize: size, contentMode: .aspectFit, options: option) { (result, info) in if let error = info?[PHImageErrorKey] as? NSError { print("fail to load thumbnail: \(info)") print(error.debugDescription) } thumbnailImage = result } return thumbnailImage } /// 長辺をlongSideSize合わせにして縮小したサイズを求める static func calcAspectSize(width: Int, height: Int, longSideSize: CGFloat?) -> CGSize { guard let longSize = longSideSize else { return CGSize(width: width, height: height) } let w: CGFloat let h: CGFloat if (width >= height) { //横長 let scale = (longSize / CGFloat(width)) w = longSize h = CGFloat(height) * scale } else { //縦長 let scale = (longSize / CGFloat(height)) w = CGFloat(width) * scale h = longSize } return CGSize(width: w, height: h) } }
PHImageManager#requestImage(for:targetSize:contentMode:options:resultHandler:)
を使う上で注意する点としては、iCloudにアップロード済みの動画は isNetworkAccessAllowed = true
にしておかないとサムネイルの生成ができません。iOSシミュレータで処理が成功してるのに実機でサムネイルが生成できない時はこのプロパティをご確認ください。
また、PHImageManagerMaximumSize
と使うと画質が悪化してしまうのが気になるところです。
動作確認環境
- iOS 13.4
- Xcode 11.4.1
関連記事
iOSアプリ開発Tips/動画編集にて関連した記事をまとめています。
それ以外にも iOSアプリ開発で役立つ情報をまとめています。