mirror of
https://github.com/oxen-io/session-ios.git
synced 2023-12-13 21:30:14 +01:00
d56cee8234
Created the ThemeManager and the system to control the dynamic theming Started updating the main settings screens Added the AppearanceViewController and connected it to the ThemeManager Started adding theme values Started applying theme values throughout
132 lines
5 KiB
Swift
132 lines
5 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.maxFileSize }
|
|
@objc
|
|
public static var kMaxFileSizeImage: UInt { SNUtilitiesKitConfiguration.maxFileSize }
|
|
@objc
|
|
public static var kMaxFileSizeVideo: UInt { SNUtilitiesKitConfiguration.maxFileSize }
|
|
@objc
|
|
public static var kMaxFileSizeAudio: UInt { SNUtilitiesKitConfiguration.maxFileSize }
|
|
@objc
|
|
public static var kMaxFileSizeGeneric: UInt { SNUtilitiesKitConfiguration.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
|
|
}
|