mirror of
https://github.com/Dimillian/IceCubesApp.git
synced 2024-12-25 00:20:45 +00:00
Rework image compression / upload
This commit is contained in:
parent
0d2454886e
commit
f172d6d4a6
4 changed files with 105 additions and 14 deletions
50
Packages/Status/Package.resolved
Normal file
50
Packages/Status/Package.resolved
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
{
|
||||||
|
"pins" : [
|
||||||
|
{
|
||||||
|
"identity" : "emojitext",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/divadretlaw/EmojiText",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "b5b0a30933a6dcb6601ad3625690a823fa3f6965",
|
||||||
|
"version" : "2.6.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "keychain-swift",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/evgenyneu/keychain-swift",
|
||||||
|
"state" : {
|
||||||
|
"branch" : "master",
|
||||||
|
"revision" : "c1fde55798b164cad44b5e23cfa2f0f1ebcd76af"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "nuke",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/kean/Nuke",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "6241e100294a2aa70d1811641585ab7da780bd0f",
|
||||||
|
"version" : "12.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "swiftsoup",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/scinfu/SwiftSoup.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "f707b8680cddb96dc1855632340a572ef37bbb98",
|
||||||
|
"version" : "2.5.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "swiftui-shimmer",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/markiv/SwiftUI-Shimmer",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "965a7cbcbf094cbcf22b9251a2323bdc3432e171",
|
||||||
|
"version" : "1.1.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"version" : 2
|
||||||
|
}
|
|
@ -7,7 +7,49 @@ actor StatusEditorCompressor {
|
||||||
case noData
|
case noData
|
||||||
}
|
}
|
||||||
|
|
||||||
func compressImage(_ image: UIImage) async throws -> Data {
|
func compressImageFrom(url: URL) async -> Data? {
|
||||||
|
return await withCheckedContinuation{ continuation in
|
||||||
|
let sourceOptions = [kCGImageSourceShouldCache: false] as CFDictionary
|
||||||
|
guard let source = CGImageSourceCreateWithURL(url as CFURL, sourceOptions) else {
|
||||||
|
continuation.resume(returning: nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let downsampleOptions = [
|
||||||
|
kCGImageSourceCreateThumbnailFromImageAlways: true,
|
||||||
|
kCGImageSourceCreateThumbnailWithTransform: true,
|
||||||
|
kCGImageSourceThumbnailMaxPixelSize: 4096,
|
||||||
|
] as CFDictionary
|
||||||
|
|
||||||
|
guard let cgImage = CGImageSourceCreateThumbnailAtIndex(source, 0, downsampleOptions) else {
|
||||||
|
continuation.resume(returning: nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let data = NSMutableData()
|
||||||
|
guard let imageDestination = CGImageDestinationCreateWithData(data, UTType.jpeg.identifier as CFString, 1, nil) else {
|
||||||
|
continuation.resume(returning: nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let isPNG: Bool = {
|
||||||
|
guard let utType = cgImage.utType else { return false }
|
||||||
|
return (utType as String) == UTType.png.identifier
|
||||||
|
|
||||||
|
}()
|
||||||
|
|
||||||
|
let destinationProperties = [
|
||||||
|
kCGImageDestinationLossyCompressionQuality: isPNG ? 1.0 : 0.75
|
||||||
|
] as CFDictionary
|
||||||
|
|
||||||
|
CGImageDestinationAddImage(imageDestination, cgImage, destinationProperties)
|
||||||
|
CGImageDestinationFinalize(imageDestination)
|
||||||
|
|
||||||
|
continuation.resume(returning: data as Data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func compressImageForUpload(_ image: UIImage) async throws -> Data {
|
||||||
var image = image
|
var image = image
|
||||||
if image.size.height > 5000 || image.size.width > 5000 {
|
if image.size.height > 5000 || image.size.width > 5000 {
|
||||||
image = image.resized(to: .init(width: image.size.width / 4,
|
image = image.resized(to: .init(width: image.size.width / 4,
|
||||||
|
|
|
@ -61,12 +61,14 @@ enum StatusEditorUTTypeSupported: String, CaseIterable {
|
||||||
func loadItemContent(item: NSItemProvider) async throws -> Any? {
|
func loadItemContent(item: NSItemProvider) async throws -> Any? {
|
||||||
// Many warnings here about non-sendable type `[AnyHashable: Any]?` crossing
|
// Many warnings here about non-sendable type `[AnyHashable: Any]?` crossing
|
||||||
// actor boundaries. Many Radars have been filed.
|
// actor boundaries. Many Radars have been filed.
|
||||||
let result = try await item.loadItem(forTypeIdentifier: rawValue)
|
|
||||||
if isVideo, let transferable = await getVideoTransferable(item: item) {
|
if isVideo, let transferable = await getVideoTransferable(item: item) {
|
||||||
return transferable
|
return transferable
|
||||||
} else if isGif, let transferable = await getGifTransferable(item: item) {
|
} else if isGif, let transferable = await getGifTransferable(item: item) {
|
||||||
return transferable
|
return transferable
|
||||||
|
} else if let transferable = await getImageTansferable(item: item) {
|
||||||
|
return transferable
|
||||||
}
|
}
|
||||||
|
let result = try await item.loadItem(forTypeIdentifier: rawValue)
|
||||||
if self == .jpeg || self == .png || self == .tiff || self == .image || self == .uiimage || self == .adobeRawImage {
|
if self == .jpeg || self == .png || self == .tiff || self == .image || self == .uiimage || self == .adobeRawImage {
|
||||||
if let image = result as? UIImage {
|
if let image = result as? UIImage {
|
||||||
return image
|
return image
|
||||||
|
@ -79,8 +81,6 @@ enum StatusEditorUTTypeSupported: String, CaseIterable {
|
||||||
let image = UIImage(data: data)
|
let image = UIImage(data: data)
|
||||||
{
|
{
|
||||||
return image
|
return image
|
||||||
} else if let transferable = await getImageTansferable(item: item) {
|
|
||||||
return transferable
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let url = result as? URL {
|
if let url = result as? URL {
|
||||||
|
@ -149,9 +149,6 @@ struct MovieFileTranseferable: Transferable {
|
||||||
struct ImageFileTranseferable: Transferable {
|
struct ImageFileTranseferable: Transferable {
|
||||||
let url: URL
|
let url: URL
|
||||||
|
|
||||||
lazy var data: Data? = try? Data(contentsOf: url)
|
|
||||||
lazy var image: UIImage? = UIImage(data: data ?? Data())
|
|
||||||
|
|
||||||
static var transferRepresentation: some TransferRepresentation {
|
static var transferRepresentation: some TransferRepresentation {
|
||||||
FileRepresentation(contentType: .image) { image in
|
FileRepresentation(contentType: .image) { image in
|
||||||
SentTransferredFile(image.url)
|
SentTransferredFile(image.url)
|
||||||
|
|
|
@ -379,6 +379,7 @@ public class StatusEditorViewModel: NSObject, ObservableObject {
|
||||||
let handledItemType = StatusEditorUTTypeSupported(rawValue: identifier)
|
let handledItemType = StatusEditorUTTypeSupported(rawValue: identifier)
|
||||||
{
|
{
|
||||||
do {
|
do {
|
||||||
|
let compressor = StatusEditorCompressor()
|
||||||
let content = try await handledItemType.loadItemContent(item: item)
|
let content = try await handledItemType.loadItemContent(item: item)
|
||||||
if let text = content as? String {
|
if let text = content as? String {
|
||||||
initialText += "\(text) "
|
initialText += "\(text) "
|
||||||
|
@ -388,9 +389,9 @@ public class StatusEditorViewModel: NSObject, ObservableObject {
|
||||||
gifTransferable: nil,
|
gifTransferable: nil,
|
||||||
mediaAttachment: nil,
|
mediaAttachment: nil,
|
||||||
error: nil))
|
error: nil))
|
||||||
} else if var content = content as? ImageFileTranseferable,
|
} else if let content = content as? ImageFileTranseferable,
|
||||||
let image = content.image
|
let compressedData = await compressor.compressImageFrom(url: content.url),
|
||||||
{
|
let image = UIImage(data: compressedData) {
|
||||||
mediasImages.append(.init(image: image,
|
mediasImages.append(.init(image: image,
|
||||||
movieTransferable: nil,
|
movieTransferable: nil,
|
||||||
gifTransferable: nil,
|
gifTransferable: nil,
|
||||||
|
@ -532,7 +533,6 @@ public class StatusEditorViewModel: NSObject, ObservableObject {
|
||||||
Task {
|
Task {
|
||||||
var medias: [StatusEditorMediaContainer] = []
|
var medias: [StatusEditorMediaContainer] = []
|
||||||
for media in selectedMedias {
|
for media in selectedMedias {
|
||||||
print(media.supportedContentTypes)
|
|
||||||
var file: (any Transferable)?
|
var file: (any Transferable)?
|
||||||
|
|
||||||
if file == nil {
|
if file == nil {
|
||||||
|
@ -545,8 +545,10 @@ public class StatusEditorViewModel: NSObject, ObservableObject {
|
||||||
file = try? await media.loadTransferable(type: ImageFileTranseferable.self)
|
file = try? await media.loadTransferable(type: ImageFileTranseferable.self)
|
||||||
}
|
}
|
||||||
|
|
||||||
if var imageFile = file as? ImageFileTranseferable,
|
let compressor = StatusEditorCompressor()
|
||||||
let image = imageFile.image
|
if let imageFile = file as? ImageFileTranseferable,
|
||||||
|
let compressedData = await compressor.compressImageFrom(url: imageFile.url),
|
||||||
|
let image = UIImage(data: compressedData)
|
||||||
{
|
{
|
||||||
medias.append(.init(image: image,
|
medias.append(.init(image: image,
|
||||||
movieTransferable: nil,
|
movieTransferable: nil,
|
||||||
|
@ -602,7 +604,7 @@ public class StatusEditorViewModel: NSObject, ObservableObject {
|
||||||
if let index = indexOf(container: newContainer) {
|
if let index = indexOf(container: newContainer) {
|
||||||
let compressor = StatusEditorCompressor()
|
let compressor = StatusEditorCompressor()
|
||||||
if let image = originalContainer.image {
|
if let image = originalContainer.image {
|
||||||
let imageData = try await compressor.compressImage(image)
|
let imageData = try await compressor.compressImageForUpload(image)
|
||||||
let uploadedMedia = try await uploadMedia(data: imageData, mimeType: "image/jpeg")
|
let uploadedMedia = try await uploadMedia(data: imageData, mimeType: "image/jpeg")
|
||||||
mediasImages[index] = .init(image: mode.isInShareExtension ? originalContainer.image : nil,
|
mediasImages[index] = .init(image: mode.isInShareExtension ? originalContainer.image : nil,
|
||||||
movieTransferable: nil,
|
movieTransferable: nil,
|
||||||
|
|
Loading…
Reference in a new issue