mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-07-25 15:05:20 +00:00
Target image byte size across platforms
This commit is contained in:
@@ -14,6 +14,7 @@ enum ImageUtilsError: Error {
|
|||||||
|
|
||||||
enum ImageUtils {
|
enum ImageUtils {
|
||||||
private static let compressionQuality: CGFloat = 0.85
|
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 {
|
static func processImage(at url: URL, maxDimension: CGFloat = 512) throws -> URL {
|
||||||
let data = try Data(contentsOf: url)
|
let data = try Data(contentsOf: url)
|
||||||
@@ -29,9 +30,15 @@ enum ImageUtils {
|
|||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
static func processImage(_ image: UIImage, maxDimension: CGFloat = 512) throws -> URL {
|
static func processImage(_ image: UIImage, maxDimension: CGFloat = 512) throws -> URL {
|
||||||
let scaled = scaledImage(image, maxDimension: maxDimension)
|
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
|
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()
|
let outputURL = try makeOutputURL()
|
||||||
try jpegData.write(to: outputURL, options: .atomic)
|
try jpegData.write(to: outputURL, options: .atomic)
|
||||||
return outputURL
|
return outputURL
|
||||||
@@ -73,21 +80,17 @@ enum ImageUtils {
|
|||||||
guard let cgImage = context.makeImage() else {
|
guard let cgImage = context.makeImage() else {
|
||||||
throw ImageUtilsError.encodingFailed
|
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()
|
let outputURL = try makeOutputURL()
|
||||||
guard let destination = CGImageDestinationCreateWithURL(outputURL as CFURL, UTType.jpeg.identifier as CFString, 1, nil) else {
|
try jpegData.write(to: outputURL, options: .atomic)
|
||||||
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
|
|
||||||
}
|
|
||||||
return outputURL
|
return outputURL
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,6 +109,25 @@ enum ImageUtils {
|
|||||||
scaledImage.unlockFocus()
|
scaledImage.unlockFocus()
|
||||||
return scaledImage
|
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
|
#endif
|
||||||
|
|
||||||
private static func makeOutputURL() throws -> URL {
|
private static func makeOutputURL() throws -> URL {
|
||||||
|
|||||||
Reference in New Issue
Block a user