mirror of
https://github.com/oxen-io/session-ios.git
synced 2023-12-13 21:30:14 +01:00
Refactored the SignalApp class to Swift Fixed a horizontal alignment issue in the ConversationTitleView Fixed an issue where expiration timer update messages weren't migrated or rendering correctly Fixed an issue where expiring messages weren't migrated correctly Fixed an issue where closed groups which had been left were causing migration failures (due to data incorrectly being assumed to be required) Shifted the Legacy Attachment types into the 'SMKLegacy' namespace Moved all of the NSCoding logic for the TSMessage
133 lines
5.1 KiB
Swift
133 lines
5.1 KiB
Swift
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
|
|
|
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
|
|
}
|