Target image byte size across platforms

This commit is contained in:
jack
2025-10-15 00:37:40 +01:00
committed by islam
parent aa8b257e68
commit c179e34c43
+37 -15
View File
@@ -14,6 +14,7 @@ enum ImageUtilsError: Error {
enum ImageUtils {
private static let compressionQuality: CGFloat = 0.85
private static let targetImageBytes: Int = 60_000
static func processImage(at url: URL, maxDimension: CGFloat = 512) throws -> URL {
let data = try Data(contentsOf: url)
@@ -29,9 +30,15 @@ enum ImageUtils {
#if os(iOS)
static func processImage(_ image: UIImage, maxDimension: CGFloat = 512) throws -> URL {
let scaled = scaledImage(image, maxDimension: maxDimension)
guard let jpegData = scaled.jpegData(compressionQuality: compressionQuality) else {
var quality = compressionQuality
guard var jpegData = scaled.jpegData(compressionQuality: quality) else {
throw ImageUtilsError.encodingFailed
}
while jpegData.count > targetImageBytes && quality > 0.3 {
quality -= 0.1
guard let next = scaled.jpegData(compressionQuality: quality) else { break }
jpegData = next
}
let outputURL = try makeOutputURL()
try jpegData.write(to: outputURL, options: .atomic)
return outputURL
@@ -73,21 +80,17 @@ enum ImageUtils {
guard let cgImage = context.makeImage() else {
throw ImageUtilsError.encodingFailed
}
var quality = compressionQuality
guard var jpegData = encodeJPEG(from: cgImage, quality: quality) else {
throw ImageUtilsError.encodingFailed
}
while jpegData.count > targetImageBytes && quality > 0.3 {
quality -= 0.1
guard let next = encodeJPEG(from: cgImage, quality: quality) else { break }
jpegData = next
}
let outputURL = try makeOutputURL()
guard let destination = CGImageDestinationCreateWithURL(outputURL as CFURL, UTType.jpeg.identifier as CFString, 1, nil) else {
throw ImageUtilsError.encodingFailed
}
let options: [CFString: Any] = [
kCGImageDestinationLossyCompressionQuality: compressionQuality,
kCGImagePropertyExifDictionary: [:],
kCGImagePropertyTIFFDictionary: [:],
kCGImagePropertyIPTCDictionary: [:],
kCGImagePropertyOrientation: 1
]
CGImageDestinationAddImage(destination, cgImage, options as CFDictionary)
guard CGImageDestinationFinalize(destination) else {
throw ImageUtilsError.encodingFailed
}
try jpegData.write(to: outputURL, options: .atomic)
return outputURL
}
@@ -106,6 +109,25 @@ enum ImageUtils {
scaledImage.unlockFocus()
return scaledImage
}
private static func encodeJPEG(from cgImage: CGImage, quality: CGFloat) -> Data? {
let data = CFDataCreateMutable(nil, 0)
guard let destination = CGImageDestinationCreateWithData(data, UTType.jpeg.identifier as CFString, 1, nil) else {
return nil
}
let options: [CFString: Any] = [
kCGImageDestinationLossyCompressionQuality: quality,
kCGImagePropertyExifDictionary: [:],
kCGImagePropertyTIFFDictionary: [:],
kCGImagePropertyIPTCDictionary: [:],
kCGImagePropertyOrientation: 1
]
CGImageDestinationAddImage(destination, cgImage, options as CFDictionary)
guard CGImageDestinationFinalize(destination) else {
return nil
}
return data as Data
}
#endif
private static func makeOutputURL() throws -> URL {