Remove old file
This commit is contained in:
parent
5e9cc430c6
commit
8ac3deb55a
|
@ -1,185 +0,0 @@
|
||||||
//
|
|
||||||
// CompositionAttachment.swift
|
|
||||||
// Tusker
|
|
||||||
//
|
|
||||||
// Created by Shadowfacts on 1/1/20.
|
|
||||||
// Copyright © 2020 Shadowfacts. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import UIKit
|
|
||||||
import Photos
|
|
||||||
import MobileCoreServices
|
|
||||||
|
|
||||||
enum CompositionAttachmentData {
|
|
||||||
case asset(PHAsset)
|
|
||||||
case image(UIImage)
|
|
||||||
case video(URL)
|
|
||||||
|
|
||||||
var type: AttachmentType {
|
|
||||||
switch self {
|
|
||||||
case let .asset(asset):
|
|
||||||
return asset.attachmentType!
|
|
||||||
case .image(_):
|
|
||||||
return .image
|
|
||||||
case .video(_):
|
|
||||||
return .video
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var isAsset: Bool {
|
|
||||||
switch self {
|
|
||||||
case .asset(_):
|
|
||||||
return true
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var canSaveToDraft: Bool {
|
|
||||||
switch self {
|
|
||||||
case .video(_):
|
|
||||||
return false
|
|
||||||
default:
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func getData(completion: @escaping (Data, String) -> Void) {
|
|
||||||
switch self {
|
|
||||||
case let .image(image):
|
|
||||||
completion(image.pngData()!, "image/png")
|
|
||||||
case let .asset(asset):
|
|
||||||
if asset.mediaType == .image {
|
|
||||||
let options = PHImageRequestOptions()
|
|
||||||
options.version = .current
|
|
||||||
options.deliveryMode = .highQualityFormat
|
|
||||||
options.resizeMode = .none
|
|
||||||
options.isNetworkAccessAllowed = true
|
|
||||||
PHImageManager.default().requestImageDataAndOrientation(for: asset, options: options) { (data, dataUTI, orientation, info) in
|
|
||||||
guard var data = data, let dataUTI = dataUTI else { fatalError() }
|
|
||||||
|
|
||||||
let mimeType: String
|
|
||||||
if dataUTI == "public.heic" {
|
|
||||||
// neither Mastodon nor Pleroma handles HEIC well, so convert to JPEG
|
|
||||||
let image = CIImage(data: data)!
|
|
||||||
let context = CIContext()
|
|
||||||
let colorSpace = image.colorSpace ?? CGColorSpace(name: CGColorSpace.sRGB)!
|
|
||||||
data = context.jpegRepresentation(of: image, colorSpace: colorSpace, options: [:])!
|
|
||||||
mimeType = "image/jpeg"
|
|
||||||
} else {
|
|
||||||
mimeType = UTTypeCopyPreferredTagWithClass(dataUTI as CFString, kUTTagClassMIMEType)!.takeRetainedValue() as String
|
|
||||||
}
|
|
||||||
|
|
||||||
completion(data, mimeType)
|
|
||||||
}
|
|
||||||
} else if asset.mediaType == .video {
|
|
||||||
let options = PHVideoRequestOptions()
|
|
||||||
options.deliveryMode = .automatic
|
|
||||||
options.isNetworkAccessAllowed = true
|
|
||||||
options.version = .current
|
|
||||||
PHImageManager.default().requestExportSession(forVideo: asset, options: options, exportPreset: AVAssetExportPresetHighestQuality) { (exportSession, info) in
|
|
||||||
guard let exportSession = exportSession else { fatalError("failed to create export session") }
|
|
||||||
CompositionAttachmentData.exportVideoData(session: exportSession, completion: completion)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
fatalError("assetType must be either image or video")
|
|
||||||
}
|
|
||||||
case let .video(url):
|
|
||||||
let asset = AVURLAsset(url: url)
|
|
||||||
guard let session = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetHighestQuality) else {
|
|
||||||
fatalError("failed to create export session")
|
|
||||||
}
|
|
||||||
CompositionAttachmentData.exportVideoData(session: session, completion: completion)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static func exportVideoData(session: AVAssetExportSession, completion: @escaping (Data, String) -> Void) {
|
|
||||||
session.outputFileType = .mp4
|
|
||||||
session.outputURL = FileManager.default.temporaryDirectory.appendingPathComponent("exported_video_\(UUID())").appendingPathExtension("mp4")
|
|
||||||
session.exportAsynchronously {
|
|
||||||
guard session.status == .completed else { fatalError("video export failed: \(String(describing: session.error))") }
|
|
||||||
do {
|
|
||||||
let data = try Data(contentsOf: session.outputURL!)
|
|
||||||
completion(data, "video/mp4")
|
|
||||||
} catch {
|
|
||||||
fatalError("Unable to load video: \(error)")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum AttachmentType {
|
|
||||||
case image, video
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension PHAsset {
|
|
||||||
var attachmentType: CompositionAttachmentData.AttachmentType? {
|
|
||||||
switch self.mediaType {
|
|
||||||
case .image:
|
|
||||||
return .image
|
|
||||||
case .video:
|
|
||||||
return .video
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension CompositionAttachmentData: Codable {
|
|
||||||
func encode(to encoder: Encoder) throws {
|
|
||||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
|
||||||
|
|
||||||
switch self {
|
|
||||||
case let .asset(asset):
|
|
||||||
try container.encode("asset", forKey: .type)
|
|
||||||
try container.encode(asset.localIdentifier, forKey: .assetIdentifier)
|
|
||||||
case let .image(image):
|
|
||||||
try container.encode("image", forKey: .type)
|
|
||||||
try container.encode(image.pngData()!, forKey: .imageData)
|
|
||||||
case .video(_):
|
|
||||||
throw EncodingError.invalidValue(self, EncodingError.Context(codingPath: [], debugDescription: "video CompositionAttachments cannot be encoded"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
init(from decoder: Decoder) throws {
|
|
||||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
|
||||||
|
|
||||||
switch try container.decode(String.self, forKey: .type) {
|
|
||||||
case "asset":
|
|
||||||
let identifier = try container.decode(String.self, forKey: .assetIdentifier)
|
|
||||||
guard let asset = PHAsset.fetchAssets(withLocalIdentifiers: [identifier], options: nil).firstObject else {
|
|
||||||
throw DecodingError.dataCorruptedError(forKey: .assetIdentifier, in: container, debugDescription: "Could not fetch asset with local identifier")
|
|
||||||
}
|
|
||||||
self = .asset(asset)
|
|
||||||
case "image":
|
|
||||||
guard let image = UIImage(data: try container.decode(Data.self, forKey: .imageData)) else {
|
|
||||||
throw DecodingError.dataCorruptedError(forKey: .imageData, in: container, debugDescription: "Could not decode UIImage from image data")
|
|
||||||
}
|
|
||||||
self = .image(image)
|
|
||||||
default:
|
|
||||||
throw DecodingError.dataCorruptedError(forKey: .type, in: container, debugDescription: "CompositionAttachment type must be one of 'image' or 'asset'")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum CodingKeys: CodingKey {
|
|
||||||
case type
|
|
||||||
case imageData
|
|
||||||
/// The local identifier of the PHAsset for this attachment
|
|
||||||
case assetIdentifier
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension CompositionAttachmentData: Equatable {
|
|
||||||
static func ==(lhs: CompositionAttachmentData, rhs: CompositionAttachmentData) -> Bool {
|
|
||||||
switch (lhs, rhs) {
|
|
||||||
case let (.asset(a), .asset(b)):
|
|
||||||
return a.localIdentifier == b.localIdentifier
|
|
||||||
case let (.image(a), .image(b)):
|
|
||||||
return a == b
|
|
||||||
case let (.video(a), .video(b)):
|
|
||||||
return a == b
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue