Creating thumbnail from local video in swift
IosSwiftIphoneVideo CaptureIos Problem Overview
How to create thumbnail in swift from a local video file ?
For example if the video file path is located here :
file:///Users/Dev/Library/Developer/CoreSimulator/Devices/F33222DF-D8F0-448B-A127-C5B03C64D0DC/data/Containers/Data/Application/4BC62DBF-0108-453C-9324-5BC0E356FE24/tmp/trim.059D11E6-F0EF-43DB-9E97-CA4F1F95D6B6.MOV
Thank you.
Ios Solutions
Solution 1 - Ios
Translated with some edits from:
https://stackoverflow.com/questions/10221242/first-frame-of-a-video-using-avfoundation
var err: NSError? = nil
let asset = AVURLAsset(URL: NSURL(fileURLWithPath: "/that/long/path"), options: nil)
let imgGenerator = AVAssetImageGenerator(asset: asset)
let cgImage = imgGenerator.copyCGImageAtTime(CMTimeMake(0, 1), actualTime: nil, error: &err)
// !! check the error before proceeding
let uiImage = UIImage(CGImage: cgImage)
let imageView = UIImageView(image: uiImage)
// lay out this image view, or if it already exists, set its image property to uiImage
Solution 2 - Ios
BaseZen's answer translated Swift 3 / Swift 4
You need to set the location of the video you want to make a thumbnail of as the url asset path, like:
Don't forget to import AVFoundation
func generateThumbnail(path: URL) -> UIImage? {
do {
let asset = AVURLAsset(url: path, options: nil)
let imgGenerator = AVAssetImageGenerator(asset: asset)
imgGenerator.appliesPreferredTrackTransform = true
let cgImage = try imgGenerator.copyCGImage(at: CMTimeMake(value: 0, timescale: 1), actualTime: nil)
let thumbnail = UIImage(cgImage: cgImage)
return thumbnail
} catch let error {
print("*** Error generating thumbnail: \(error.localizedDescription)")
return nil
}
}
For everyone having issues with this I have created the following drop in example hosted on Github
Solution 3 - Ios
This is a cleaned up version of David's answer and tested against iOS 11 / Swift 4.x.
Please note the different calls for handling the initial time based on which version of Swift you are using.
func generateThumbnail(url: URL) -> UIImage? {
do {
let asset = AVURLAsset(url: url)
let imageGenerator = AVAssetImageGenerator(asset: asset)
imageGenerator.appliesPreferredTrackTransform = true
// Select the right one based on which version you are using
// Swift 4.2
let cgImage = try imageGenerator.copyCGImage(at: .zero,
actualTime: nil)
// Swift 4.0
let cgImage = try imageGenerator.copyCGImage(at: kCMTimeZero,
actualTime: nil)
return UIImage(cgImage: cgImage)
} catch {
print(error.localizedDescription)
return nil
}
}
- Creates an
AVURLAsset
from the providedURL
- Creates an
AVAssetImageGenerator
using the newly createdAVURLAsset
, is responsible for making the thumbnail - appliesPreferredTrackTransform informs the generator to apply the matrix to the thumbnail generation. The default value is false.
- Attempts to create a
CGImage
at the first frame of the video track - Creates a
UIImage
using the newly created CGImage & returns it - If the image generation step fails, an error is caught and presented to the console along with a nil UIImage
Solution 4 - Ios
BaseZen's answer translated to Swift 2:
import UIKit
import AVFoundation
do {
let asset = AVURLAsset(URL: NSURL(fileURLWithPath: "/that/long/path"), options: nil)
let imgGenerator = AVAssetImageGenerator(asset: asset)
imgGenerator.appliesPreferredTrackTransform = true
let cgImage = try imgGenerator.copyCGImageAtTime(CMTimeMake(0, 1), actualTime: nil)
let uiImage = UIImage(CGImage: cgImage)
let imageView = UIImageView(image: uiImage)
// lay out this image view, or if it already exists, set its image property to uiImage
} catch let error as NSError {
print("Error generating thumbnail: \(error)")
}
Solution 5 - Ios
It's better to write less and simple code for understanding. This is what I convert the solutions in Swift (3.1 ... 5.2)
import AVFoundation
func imagePreview(from moviePath: URL, in seconds: Double) -> UIImage? {
let timestamp = CMTime(seconds: seconds, preferredTimescale: 60)
let asset = AVURLAsset(url: moviePath)
let generator = AVAssetImageGenerator(asset: asset)
generator.appliesPreferredTrackTransform = true
guard let imageRef = try? generator.copyCGImage(at: timestamp, actualTime: nil) else {
return nil
}
return UIImage(cgImage: imageRef)
}
Hope it will help someone.
Solution 6 - Ios
Swift 5.3
As an alternative to other answers, with slight modification I decided to make an URL extension.
import AVFoundation
extension URL {
func generateThumbnail() -> UIImage? {
do {
let asset = AVURLAsset(url: self)
let imageGenerator = AVAssetImageGenerator(asset: asset)
imageGenerator.appliesPreferredTrackTransform = true
// Swift 5.3
let cgImage = try imageGenerator.copyCGImage(at: .zero,
actualTime: nil)
return UIImage(cgImage: cgImage)
} catch {
print(error.localizedDescription)
return nil
}
}
}
Usage:
let image = someURL.generateThumbnail()
Solution 7 - Ios
Here is how you generate a thumbnail (first frame) of a video in swift 5:
import UIKit
import AVFoundation
class ViewController: UIViewController {
@IBOutlet weak var imageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
let video = AVURLAsset(url: URL(fileURLWithPath: Bundle.main.path(forResource: "sampleVideo", ofType: "mov")!))
let thumbnailGenerator = AVAssetImageGenerator(asset: video)
do
{
let cgImage = try thumbnailGenerator.copyCGImage(at: CMTimeMake(value: 0, timescale: 1), actualTime: nil)
let UiImage = UIImage(cgImage: cgImage)
imageView.image = UiImage
}
catch
{ print(error) }
}
}
In this example the video name is sampleVideo.mov (change the file url to the name of your video file), make sure you import the video into your local Xcode project and add it to your app's target.
I have make a youtube explaining this here
Solution 8 - Ios
func saveImageDocumentDirectoryWithDate(tempImage:UIImage, block : @escaping (_ url: URL?) -> Void ){
let documentsDirectoryURL = try! FileManager().url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
let random : String = randomString(length: 5)
let fileURL = documentsDirectoryURL.appendingPathComponent(String(format:"CPImage%@.png",random))
do { try tempImage.pngData()?.write(to: fileURL) }
catch { block(nil) }
block(fileURL)}