mirror of https://github.com/oxen-io/session-ios
				
				
				
			
			You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			131 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			Swift
		
	
			
		
		
	
	
			131 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			Swift
		
	
| import Foundation
 | |
| import AVFoundation
 | |
| 
 | |
| public enum OWSMediaError: Error {
 | |
|     case failure(description: String)
 | |
| }
 | |
| 
 | |
| @objc public class OWSMediaUtils: NSObject {
 | |
| 
 | |
|     @available(*, unavailable, message:"do not instantiate this class.")
 | |
|     private override init() {
 | |
|     }
 | |
| 
 | |
|     @objc public class func thumbnail(forImageAtPath path: String, maxDimension: CGFloat) throws -> UIImage {
 | |
|         SNLog("thumbnailing image: \(path)")
 | |
| 
 | |
|         guard FileManager.default.fileExists(atPath: path) else {
 | |
|             throw OWSMediaError.failure(description: "Media file missing.")
 | |
|         }
 | |
|         guard NSData.ows_isValidImage(atPath: path) else {
 | |
|             throw OWSMediaError.failure(description: "Invalid image.")
 | |
|         }
 | |
|         guard let originalImage = UIImage(contentsOfFile: path) else {
 | |
|             throw OWSMediaError.failure(description: "Could not load original image.")
 | |
|         }
 | |
|         guard let thumbnailImage = originalImage.resized(withMaxDimensionPoints: maxDimension) else {
 | |
|             throw OWSMediaError.failure(description: "Could not thumbnail image.")
 | |
|         }
 | |
|         return thumbnailImage
 | |
|     }
 | |
| 
 | |
|     @objc public class func thumbnail(forVideoAtPath path: String, maxDimension: CGFloat) throws -> UIImage {
 | |
|         SNLog("thumbnailing video: \(path)")
 | |
| 
 | |
|         guard isVideoOfValidContentTypeAndSize(path: path) else {
 | |
|             throw OWSMediaError.failure(description: "Media file has missing or invalid length.")
 | |
|         }
 | |
| 
 | |
|         let maxSize = CGSize(width: maxDimension, height: maxDimension)
 | |
|         let url = URL(fileURLWithPath: path)
 | |
|         let asset = AVURLAsset(url: url, options: nil)
 | |
|         guard isValidVideo(asset: asset) else {
 | |
|             throw OWSMediaError.failure(description: "Invalid video.")
 | |
|         }
 | |
| 
 | |
|         let generator = AVAssetImageGenerator(asset: asset)
 | |
|         generator.maximumSize = maxSize
 | |
|         generator.appliesPreferredTrackTransform = true
 | |
|         let time: CMTime = CMTimeMake(value: 1, timescale: 60)
 | |
|         let cgImage = try generator.copyCGImage(at: time, actualTime: nil)
 | |
|         let image = UIImage(cgImage: cgImage)
 | |
|         return image
 | |
|     }
 | |
| 
 | |
|     @objc public class func isValidVideo(path: String) -> Bool {
 | |
|         guard isVideoOfValidContentTypeAndSize(path: path) else {
 | |
|             SNLog("Media file has missing or invalid length.")
 | |
|             return false
 | |
|         }
 | |
| 
 | |
|         let url = URL(fileURLWithPath: path)
 | |
|         let asset = AVURLAsset(url: url, options: nil)
 | |
|         return isValidVideo(asset: asset)
 | |
|     }
 | |
| 
 | |
|     private class func isVideoOfValidContentTypeAndSize(path: String) -> Bool {
 | |
|         guard FileManager.default.fileExists(atPath: path) else {
 | |
|             SNLog("Media file missing.")
 | |
|             return false
 | |
|         }
 | |
|         let fileExtension = URL(fileURLWithPath: path).pathExtension
 | |
|         guard let contentType = MIMETypeUtil.mimeType(forFileExtension: fileExtension) else {
 | |
|             SNLog("Media file has unknown content type.")
 | |
|             return false
 | |
|         }
 | |
|         guard MIMETypeUtil.isSupportedVideoMIMEType(contentType) else {
 | |
|             SNLog("Media file has invalid content type.")
 | |
|             return false
 | |
|         }
 | |
| 
 | |
|         guard let fileSize = OWSFileSystem.fileSize(ofPath: path) else {
 | |
|             SNLog("Media file has unknown length.")
 | |
|             return false
 | |
|         }
 | |
|         return fileSize.uintValue <= kMaxFileSizeVideo
 | |
|     }
 | |
| 
 | |
|     private class func isValidVideo(asset: AVURLAsset) -> Bool {
 | |
|         var maxTrackSize = CGSize.zero
 | |
|         for track: AVAssetTrack in asset.tracks(withMediaType: .video) {
 | |
|             let trackSize: CGSize = track.naturalSize
 | |
|             maxTrackSize.width = max(maxTrackSize.width, trackSize.width)
 | |
|             maxTrackSize.height = max(maxTrackSize.height, trackSize.height)
 | |
|         }
 | |
|         if maxTrackSize.width < 1.0 || maxTrackSize.height < 1.0 {
 | |
|             SNLog("Invalid video size: \(maxTrackSize)")
 | |
|             return false
 | |
|         }
 | |
|         if maxTrackSize.width > kMaxVideoDimensions || maxTrackSize.height > kMaxVideoDimensions {
 | |
|             SNLog("Invalid video dimensions: \(maxTrackSize)")
 | |
|             return false
 | |
|         }
 | |
|         return true
 | |
|     }
 | |
| 
 | |
|     // MARK: Constants
 | |
| 
 | |
|     /**
 | |
|      * Media Size constraints from Signal-Android
 | |
|      *
 | |
|      * https://github.com/signalapp/Signal-Android/blob/master/src/org/thoughtcrime/securesms/mms/PushMediaConstraints.java
 | |
|      */
 | |
|     @objc
 | |
|     public static var kMaxFileSizeAnimatedImage: UInt { SNUtilitiesKitConfiguration.shared.maxFileSize }
 | |
|     @objc
 | |
|     public static var kMaxFileSizeImage: UInt { SNUtilitiesKitConfiguration.shared.maxFileSize }
 | |
|     @objc
 | |
|     public static var kMaxFileSizeVideo: UInt { SNUtilitiesKitConfiguration.shared.maxFileSize }
 | |
|     @objc
 | |
|     public static var kMaxFileSizeAudio: UInt { SNUtilitiesKitConfiguration.shared.maxFileSize }
 | |
|     @objc
 | |
|     public static var kMaxFileSizeGeneric: UInt { SNUtilitiesKitConfiguration.shared.maxFileSize }
 | |
| 
 | |
|     @objc
 | |
|     public static let kMaxVideoDimensions: CGFloat = 3 * 1024
 | |
|     @objc
 | |
|     public static let kMaxAnimatedImageDimensions: UInt = 1 * 1024
 | |
|     @objc
 | |
|     public static let kMaxStillImageDimensions: UInt = 8 * 1024
 | |
| }
 |