1 import ABI49_0_0ExpoModulesCore
2 import AVFoundation
3 import UIKit
4 import CoreGraphics
5 
6 public class VideoThumbnailsModule: Module {
definitionnull7   public func definition() -> ModuleDefinition {
8     Name("ExpoVideoThumbnails")
9 
10     AsyncFunction("getThumbnail", getVideoThumbnail).runOnQueue(.main)
11   }
12 
getVideoThumbnailnull13   internal func getVideoThumbnail(sourceFilename: URL, options: VideoThumbnailsOptions) throws -> [String: Any] {
14     if sourceFilename.isFileURL {
15       guard let fileSystem = self.appContext?.fileSystem else {
16         throw Exceptions.FileSystemModuleNotFound()
17       }
18 
19       guard fileSystem.permissions(forURI: sourceFilename).contains(.read) else {
20         throw FileSystemReadPermissionException(sourceFilename.absoluteString)
21       }
22     }
23 
24     let asset = AVURLAsset.init(url: sourceFilename, options: ["AVURLAssetHTTPHeaderFieldsKey": options.headers])
25     let generator = AVAssetImageGenerator.init(asset: asset)
26 
27     generator.appliesPreferredTrackTransform = true
28     generator.requestedTimeToleranceBefore = CMTime.zero
29     generator.requestedTimeToleranceAfter = CMTime.zero
30 
31     let time = CMTimeMake(value: options.time, timescale: 1000)
32     let imgRef = try generator.copyCGImage(at: time, actualTime: nil)
33     let thumbnail = UIImage.init(cgImage: imgRef)
34     let savedImageUrl = try saveImage(image: thumbnail, quality: options.quality)
35 
36     return [
37       "uri": savedImageUrl.absoluteString,
38       "width": thumbnail.size.width,
39       "height": thumbnail.size.height
40     ]
41   }
42 
43   /**
44   Saves the image as a file.
45   */
saveImagenull46   internal func saveImage(image: UIImage, quality: Double) throws -> URL {
47     guard let fileSystem = self.appContext?.fileSystem else {
48       throw Exceptions.FileSystemModuleNotFound()
49     }
50 
51     let directory = URL(fileURLWithPath: fileSystem.cachesDirectory).appendingPathComponent("VideoThumbnails")
52     let fileName = UUID().uuidString.appending(".jpg")
53     let fileUrl = directory.appendingPathComponent(fileName)
54 
55     fileSystem.ensureDirExists(withPath: directory.path)
56 
57     guard let data = image.jpegData(compressionQuality: CGFloat(quality)) else {
58       throw CorruptedImageDataException()
59     }
60 
61     do {
62       try data.write(to: fileUrl, options: .atomic)
63     } catch let error {
64       throw ImageWriteFailedException(error.localizedDescription)
65     }
66 
67     return fileUrl
68   }
69 }
70