From 3cc589851f5d045387b596ff2c0980a40c03e4a7 Mon Sep 17 00:00:00 2001 From: Thomas Ricouard Date: Thu, 23 Feb 2023 21:21:21 +0100 Subject: [PATCH] Composer: Scale down image that are too big for upload --- .../StatusEditorUTTypeSupported.swift | 38 +++++++++++-------- .../Status/Editor/StatusEditorViewModel.swift | 31 +++++++++------ 2 files changed, 43 insertions(+), 26 deletions(-) diff --git a/Packages/Status/Sources/Status/Editor/Components/StatusEditorUTTypeSupported.swift b/Packages/Status/Sources/Status/Editor/Components/StatusEditorUTTypeSupported.swift index 524fb8e5..451870c3 100644 --- a/Packages/Status/Sources/Status/Editor/Components/StatusEditorUTTypeSupported.swift +++ b/Packages/Status/Sources/Status/Editor/Components/StatusEditorUTTypeSupported.swift @@ -14,20 +14,20 @@ enum StatusEditorUTTypeSupported: String, CaseIterable { case jpeg = "public.jpeg" case png = "public.png" case tiff = "public.tiff" - + case video = "public.video" case movie = "public.movie" case mp4 = "public.mpeg-4" case gif = "public.gif" case gif2 = "com.compuserve.gif" case quickTimeMovie = "com.apple.quicktime-movie" - + case uiimage = "com.apple.uikit.image" - + static func types() -> [UTType] { [.url, .text, .plainText, .image, .jpeg, .png, .tiff, .video, .mpeg4Movie, .gif, .movie, .quickTimeMovie] } - + var isVideo: Bool { switch self { case .video, .movie, .mp4, .quickTimeMovie: @@ -36,7 +36,7 @@ enum StatusEditorUTTypeSupported: String, CaseIterable { return false } } - + var isGif: Bool { switch self { case .gif, .gif2: @@ -45,7 +45,7 @@ enum StatusEditorUTTypeSupported: String, CaseIterable { return false } } - + func loadItemContent(item: NSItemProvider) async throws -> Any? { let result = try await item.loadItem(forTypeIdentifier: rawValue) if isVideo, let transferable = await getVideoTransferable(item: item) { @@ -79,7 +79,7 @@ enum StatusEditorUTTypeSupported: String, CaseIterable { return nil } } - + private func getVideoTransferable(item: NSItemProvider) async -> MovieFileTranseferable? { return await withCheckedContinuation { continuation in _ = item.loadTransferable(type: MovieFileTranseferable.self) { result in @@ -92,7 +92,7 @@ enum StatusEditorUTTypeSupported: String, CaseIterable { } } } - + private func getGifTransferable(item: NSItemProvider) async -> GifFileTranseferable? { return await withCheckedContinuation { continuation in _ = item.loadTransferable(type: GifFileTranseferable.self) { result in @@ -105,7 +105,7 @@ enum StatusEditorUTTypeSupported: String, CaseIterable { } } } - + private func getImageTansferable(item: NSItemProvider) async -> ImageFileTranseferable? { return await withCheckedContinuation { continuation in _ = item.loadTransferable(type: ImageFileTranseferable.self) { result in @@ -140,7 +140,7 @@ struct MovieFileTranseferable: Transferable { } } } - + static var transferRepresentation: some TransferRepresentation { FileRepresentation(contentType: .movie) { movie in SentTransferredFile(movie.url) @@ -152,11 +152,10 @@ struct MovieFileTranseferable: Transferable { struct ImageFileTranseferable: Transferable { let url: URL - + lazy var data: Data? = try? Data(contentsOf: url) - lazy var compressedData: Data? = image?.jpegData(compressionQuality: 0.80) lazy var image: UIImage? = UIImage(data: data ?? Data()) - + static var transferRepresentation: some TransferRepresentation { FileRepresentation(contentType: .image) { image in SentTransferredFile(image.url) @@ -168,11 +167,11 @@ struct ImageFileTranseferable: Transferable { struct GifFileTranseferable: Transferable { let url: URL - + var data: Data? { try? Data(contentsOf: url) } - + static var transferRepresentation: some TransferRepresentation { FileRepresentation(contentType: .gif) { gif in SentTransferredFile(gif.url) @@ -197,3 +196,12 @@ public extension URL { } } } + + +extension UIImage { + func resized(to size: CGSize) -> UIImage { + UIGraphicsImageRenderer(size: size).image { _ in + draw(in: CGRect(origin: .zero, size: size)) + } + } +} diff --git a/Packages/Status/Sources/Status/Editor/StatusEditorViewModel.swift b/Packages/Status/Sources/Status/Editor/StatusEditorViewModel.swift index 964ae5ea..6c591d16 100644 --- a/Packages/Status/Sources/Status/Editor/StatusEditorViewModel.swift +++ b/Packages/Status/Sources/Status/Editor/StatusEditorViewModel.swift @@ -572,17 +572,26 @@ public class StatusEditorViewModel: NSObject, ObservableObject { mediasImages[index] = newContainer do { if let index = indexOf(container: newContainer) { - if let image = originalContainer.image, - let data = image.jpegData(compressionQuality: 0.90) - { - let uploadedMedia = try await uploadMedia(data: data, mimeType: "image/jpeg") - mediasImages[index] = .init(image: mode.isInShareExtension ? originalContainer.image : nil, - movieTransferable: nil, - gifTransferable: nil, - mediaAttachment: uploadedMedia, - error: nil) - if let uploadedMedia, uploadedMedia.url == nil { - scheduleAsyncMediaRefresh(mediaAttachement: uploadedMedia) + if let image = originalContainer.image { + let data: Data? + // Mastodon API don't support images over 5K + if image.size.height > 5000 || image.size.width > 5000 { + data = image.resized(to: .init(width: image.size.width / 4, + height: image.size.height / 4)) + .jpegData(compressionQuality: 0.80) + } else { + data = image.jpegData(compressionQuality: 0.80) + } + if let data { + let uploadedMedia = try await uploadMedia(data: data, mimeType: "image/jpeg") + mediasImages[index] = .init(image: mode.isInShareExtension ? originalContainer.image : nil, + movieTransferable: nil, + gifTransferable: nil, + mediaAttachment: uploadedMedia, + error: nil) + if let uploadedMedia, uploadedMedia.url == nil { + scheduleAsyncMediaRefresh(mediaAttachement: uploadedMedia) + } } } else if let videoURL = await originalContainer.movieTransferable?.compressedVideoURL, let data = try? Data(contentsOf: videoURL)