mirror of
https://github.com/Dimillian/IceCubesApp.git
synced 2025-02-18 02:35:15 +00:00
Fix the upload of heavy avatar or header image (#2103)
* Compressor: allows custom parameters for compressing image (maxSize, maxHeight, maxWidth) * Account: configures the maximum image size for uploading avatar and header
This commit is contained in:
parent
02a8cb12e9
commit
aaeb9eaa36
2 changed files with 66 additions and 17 deletions
|
@ -51,17 +51,19 @@ import SwiftUI
|
||||||
didSet {
|
didSet {
|
||||||
if let item = mediaPickers.first {
|
if let item = mediaPickers.first {
|
||||||
Task {
|
Task {
|
||||||
if let data = await getItemImageData(item: item) {
|
|
||||||
if isChangingAvatar {
|
if isChangingAvatar {
|
||||||
_ = await uploadAvatar(data: data)
|
if let data = await getItemImageData(item: item, for: .avatar) {
|
||||||
|
_ = await uploadAvatar(data: data)
|
||||||
|
}
|
||||||
|
isChangingAvatar = false
|
||||||
} else if isChangingHeader {
|
} else if isChangingHeader {
|
||||||
_ = await uploadHeader(data: data)
|
if let data = await getItemImageData(item: item, for: .header) {
|
||||||
|
_ = await uploadHeader(data: data)
|
||||||
|
}
|
||||||
|
isChangingHeader = false
|
||||||
}
|
}
|
||||||
await fetchAccount()
|
await fetchAccount()
|
||||||
isChangingAvatar = false
|
|
||||||
isChangingHeader = false
|
|
||||||
mediaPickers = []
|
mediaPickers = []
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -140,16 +142,48 @@ import SwiftUI
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func getItemImageData(item: PhotosPickerItem) async -> Data? {
|
private func getItemImageData(item: PhotosPickerItem, for type: ItemType) async -> Data? {
|
||||||
guard let imageFile = try? await item.loadTransferable(type: StatusEditor.ImageFileTranseferable.self) else { return nil }
|
guard let imageFile = try? await item.loadTransferable(type: StatusEditor.ImageFileTranseferable.self) else { return nil }
|
||||||
|
|
||||||
let compressor = StatusEditor.Compressor()
|
let compressor = StatusEditor.Compressor()
|
||||||
|
|
||||||
guard let compressedData = await compressor.compressImageFrom(url: imageFile.url),
|
guard let compressedData = await compressor.compressImageFrom(url: imageFile.url),
|
||||||
let image = UIImage(data: compressedData),
|
let image = UIImage(data: compressedData),
|
||||||
let uploadData = try? await compressor.compressImageForUpload(image)
|
let uploadData = try? await compressor.compressImageForUpload(
|
||||||
else { return nil }
|
image,
|
||||||
|
maxSize: 2 * 1024 * 1024, // 2MB
|
||||||
|
maxHeight: type.maxHeight,
|
||||||
|
maxWidth: type.maxWidth
|
||||||
|
)
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
return uploadData
|
return uploadData
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension EditAccountViewModel {
|
||||||
|
private enum ItemType {
|
||||||
|
case avatar
|
||||||
|
case header
|
||||||
|
|
||||||
|
var maxHeight: CGFloat {
|
||||||
|
switch self {
|
||||||
|
case .avatar:
|
||||||
|
400
|
||||||
|
case .header:
|
||||||
|
500
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var maxWidth: CGFloat {
|
||||||
|
switch self {
|
||||||
|
case .avatar:
|
||||||
|
400
|
||||||
|
case .header:
|
||||||
|
1500
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -57,30 +57,45 @@ public extension StatusEditor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func compressImageForUpload(_ image: UIImage) async throws -> Data {
|
public func compressImageForUpload(
|
||||||
|
_ image: UIImage,
|
||||||
|
maxSize: Int = 10 * 1024 * 1024,
|
||||||
|
maxHeight: Double = 5000,
|
||||||
|
maxWidth: Double = 5000
|
||||||
|
) async throws -> Data {
|
||||||
var image = image
|
var image = image
|
||||||
if image.size.height > 5000 || image.size.width > 5000 {
|
|
||||||
image = image.resized(to: .init(width: image.size.width / 4,
|
if image.size.height > maxHeight || image.size.width > maxWidth {
|
||||||
height: image.size.height / 4))
|
let heightFactor = image.size.height / maxHeight
|
||||||
|
let widthFactor = image.size.width / maxWidth
|
||||||
|
let maxFactor = max(heightFactor, widthFactor)
|
||||||
|
|
||||||
|
image = image.resized(to: .init(width: image.size.width / maxFactor,
|
||||||
|
height: image.size.height / maxFactor))
|
||||||
}
|
}
|
||||||
|
|
||||||
guard var imageData = image.jpegData(compressionQuality: 0.8) else {
|
guard var imageData = image.jpegData(compressionQuality: 0.8) else {
|
||||||
throw CompressorError.noData
|
throw CompressorError.noData
|
||||||
}
|
}
|
||||||
|
|
||||||
let maxSize = 10 * 1024 * 1024
|
var compressionQualityFactor: CGFloat = 0.8
|
||||||
|
|
||||||
if imageData.count > maxSize {
|
if imageData.count > maxSize {
|
||||||
while imageData.count > maxSize {
|
while imageData.count > maxSize && compressionQualityFactor >= 0 {
|
||||||
guard let compressedImage = UIImage(data: imageData),
|
guard let compressedImage = UIImage(data: imageData),
|
||||||
let compressedData = compressedImage.jpegData(compressionQuality: 0.8)
|
let compressedData = compressedImage.jpegData(compressionQuality: compressionQualityFactor)
|
||||||
else {
|
else {
|
||||||
throw CompressorError.noData
|
throw CompressorError.noData
|
||||||
}
|
}
|
||||||
|
|
||||||
imageData = compressedData
|
imageData = compressedData
|
||||||
|
compressionQualityFactor -= 0.1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if imageData.count > maxSize && compressionQualityFactor <= 0 {
|
||||||
|
throw CompressorError.noData
|
||||||
|
}
|
||||||
|
|
||||||
return imageData
|
return imageData
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue