如何将服务器图片压缩至500KB以适配KakaoTalk分享?
问题描述
需要通过UIActivityViewController向KakaoTalk分享图片,但KakaoTalk单张图片容量限制为500KB。目前从服务器获取的单张图片超过8MB,虽已尝试缩放及压缩处理,最终压缩后体积仍有633KB,无法满足要求,寻求可行优化方案。
现有代码
UIImage缩放扩展
func resized(to length: CGFloat) -> UIImage { let width = self.size.width let height = self.size.height let resizeLength: CGFloat = length var scale: CGFloat if height >= width { scale = width <= resizeLength ? 1 : resizeLength / width } else { scale = height <= resizeLength ? 1 :resizeLength / height } let newHeight = height * scale let newWidth = width * scale let size = CGSize(width: newWidth, height: newHeight) let render = UIGraphicsImageRenderer(size: size) let renderImage = render.image { _ in self.draw(in: CGRect(origin: .zero, size: size)) } return renderImage }
服务器图片获取方法
private func getImageFromURL(imageURL: String, completion: @escaping (UIImage) -> Void) { guard let url = URL(string: imageURL) else { return } DispatchQueue.global().async { [weak self] in if let data = try? Data(contentsOf: url) { print("⭐️data from server: \(data.count) bytes") if let image = UIImage(data: data) { completion(image) } } } }
分享代码
@objc func shareButtonTapped(_ sender: UIButton) { memoryViewModel.selectedDataArray = memoryViewModel.selectedImageDictionary.values.compactMap { image in // 可传输大小500KB let maxSizeInBytes = 500 * 1024 // 初始压缩率 var compressionQuality: CGFloat = 1.0 // 为缩小容量进行图片缩放 let resizedImage = image.resized(to: 1080) // 图片转jpeg(应用初始压缩率1.0) var imageData = resizedImage.jpegData(compressionQuality: compressionQuality) print("🟥 before compression: \(imageData)") while imageData?.count ?? 0 > maxSizeInBytes && compressionQuality > 0 { compressionQuality -= 0.1 imageData = image.jpegData(compressionQuality: compressionQuality) } print("🟩 after compression: \(imageData))") return image } let activityViewController = UIActivityViewController(activityItems: memoryViewModel.selectedDataArray, applicationActivities: nil) activityViewController.excludedActivityTypes = [UIActivity.ActivityType.addToReadingList] present(activityViewController, animated: true, completion: nil) activityViewController.completionWithItemsHandler = { (activity, completed, items, error) in if completed { // } else { // } } }
打印结果
⭐️data from server: 8338918 bytes 🟥 before compression: Optional(11474975 bytes) 🟩 after compression: Optional(633815 bytes))
优化方案
1. 修复核心代码bug
当前分享代码的循环压缩逻辑存在错误:循环内使用**原图片image**进行压缩,而非缩放后的resizedImage,导致缩放操作完全无效。修改后代码如下:
while imageData?.count ?? 0 > maxSizeInBytes && compressionQuality > 0 { compressionQuality -= 0.1 // 改为使用resizedImage进行压缩 imageData = resizedImage.jpegData(compressionQuality: compressionQuality) }
2. 进一步降低缩放尺寸
将缩放目标从1080px下调至720px甚至更低(比如480px),图片尺寸是影响体积的核心因素,缩小尺寸能大幅降低基础体积。修改缩放调用:
let resizedImage = image.resized(to: 720)
3. 优化压缩策略
- 使用更小的压缩步长(比如每次减0.05),避免跳过合适的压缩率,更精准控制体积;
- 改用二分法寻找满足体积要求的最低压缩率,效率更高:
var low: CGFloat = 0.0 var high: CGFloat = 1.0 var bestQuality: CGFloat = 0.0 while high - low > 0.01 { let mid = (low + high) / 2 if let data = resizedImage.jpegData(compressionQuality: mid), data.count <= maxSizeInBytes { bestQuality = mid low = mid } else { high = mid } } let imageData = resizedImage.jpegData(compressionQuality: bestQuality)
4. 尝试HEIC格式压缩
iOS支持HEIC图片格式,同等画质下体积仅为JPEG的一半左右,可尝试转换为HEIC格式(需确认KakaoTalk支持该格式):
// 需先添加UIImage的HEIC转换扩展 let imageData = resizedImage.heicData(compressionQuality: compressionQuality)
5. 转换色彩空间
部分服务器返回的图片可能使用宽色域色彩空间(如P3),转换为sRGB色彩空间可减小体积:
func convertToSRGB(_ image: UIImage) -> UIImage? { guard let cgImage = image.cgImage else { return nil } let colorSpace = CGColorSpace(name: CGColorSpace.sRGB)! let context = CGContext(data: nil, width: cgImage.width, height: cgImage.height, bitsPerComponent: 8, bytesPerRow: 0, space: colorSpace, bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue) context?.draw(cgImage, in: CGRect(x: 0, y: 0, width: cgImage.width, height: cgImage.height)) guard let convertedCGImage = context?.makeImage() else { return nil } return UIImage(cgImage: convertedCGImage) } // 在缩放前调用 let srgbImage = convertToSRGB(image) ?? image let resizedImage = srgbImage.resized(to: 720)
内容的提问来源于stack exchange,提问作者zooey
相关产品推荐
相关产品推荐

