如何将服务器上的图片压缩到500kB?

问题描述 投票:0回答:1

我想通过带有 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))

我怎样才能把我从服务器拿到的图片改成我想要的尺寸?

ios swift uikit uiimage
1个回答
0
投票

主要问题是您的

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
}
© www.soinside.com 2019 - 2024. All rights reserved.