我想通过带有 UIActivityViewController 的 KakaoTalk 应用发送图片。但是,KakaoTalk 应用程序有每张图片 500kB 的容量限制。目前我从服务器收到的照片每张超过8MB,只好降容,好几天了都没有解决
虽然图像大小已经调整大小和压缩,但无论执行多少压缩都很难减少到 500 kB 或更小的容量。我想知道另一种方式。
下面是调整图像大小的 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)
}
}
}
}
我通过 UIActivityViewController 分享图片
@objc func shareButtonTapped(_ sender: UIButton) {
memoryViewModel.selectedDataArray = memoryViewModel.selectedImageDictionary.values.compactMap { image in
// 전송 가능한 사이즈 500KB
let maxSizeInBytes = 500 * 1024
// 최초 압축률
var compressionQuality: CGFloat = 1.0
// 용량을 줄이기 위한 이미지 resize
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))
我怎样才能把我从服务器拿到的图片改成我想要的尺寸?
主要问题是您的
resized
方法。您的用途:
let render = UIGraphicsImageRenderer(size: size)
依赖于默认格式,默认格式为图像提供与当前设备相同的比例。您生成的大小以磅为单位。因此,以像素为单位的实际图像是点大小乘以图像比例。对于大多数设备,这将使图像的大小增加 4 倍或 9 倍。
请注意,您的图像从 8MB 开始,然后在您缩放它(应该是更小的尺寸)之后,图像会膨胀到 11MB。然后,您尝试生成越来越低质量的 JPEG 根本无法使图像数据大小足够小。
要解决此问题,请使用 1.0 比例设置图像渲染,而不是依赖默认比例。
更新您的代码如下:
var fmt = UIGraphicsImageRendererFormat.default()
fmt.scale = 1.0
let render = UIGraphicsImageRenderer(size: size, format: fmt)
这将导致调整大小后的图像在点和像素上的大小相同,这将提供更小的初始 JPEG。在您达到 0.1 的压缩因子之前,您的其余逻辑现在应该导致大小低于您所需的最大值 500kB。
这是完整的
resized
方法,并进行了小的改动:
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)
// Setup the format with a scale of 1.0
var fmt = UIGraphicsImageRendererFormat.default()
fmt.scale = 1.0
let render = UIGraphicsImageRenderer(size: size, format: fmt)
let renderImage = render.image { _ in
self.draw(in: CGRect(origin: .zero, size: size))
}
return renderImage
}