「UIImageを絶対にnKB以下のJPEGで送らないといけない!」ということがあり、作りました。
コード
import UIKit
extension UIImage {
func compressedJpegData(toKB:Int) -> Data? {
guard let resized = self.resized(withPercentage: 0.75) else { return nil }
guard var data = resized.jpegData(compressionQuality: 0.9) else { return nil }
let byte = [UInt8](data)
if (byte.count / 1024) >= toKB {
// toKBを超えてた時
guard let againImage = UIImage(data: data) else { return nil }
guard let rescalingData = againImage.compressedJpegData(toKB: toKB) else { return nil }
data = rescalingData
}
return data
}
func resized(withPercentage percentage: CGFloat) -> UIImage? {
let canvas = CGSize(width: size.width * percentage, height: size.height * percentage)
return UIGraphicsImageRenderer(size: canvas, format: imageRendererFormat).image {
_ in draw(in: CGRect(origin: .zero, size: canvas))
}
}
}
やっていること
func compressedJpetgData(toKB:Int) -> Data?
これは、指定したサイズ(容量的な)まで縮めるメソッドです。
toKBに指定したサイズに収まるまで再帰的に呼ばれます。
guard let resized = self.resized(withPercentage: 0.75) else { return nil }
guard var data = resized.jpegData(compressionQuality: 0.9) else { return nil }
まずサイズ(見た目的な)を縮小し、JPEGにエンコードします。
self.resized(withPercentage: 0.75)は以下のような処理になっています。
func resized(withPercentage percentage: CGFloat) -> UIImage? {
let canvas = CGSize(width: size.width * percentage, height: size.height * percentage)
return UIGraphicsImageRenderer(size: canvas, format: imageRendererFormat).image {
_ in draw(in: CGRect(origin: .zero, size: canvas))
}
}
↑で、縮小率を指定してUIImageを縮小することが出来ます。アスペクト比は保持されます。
let byte = [UInt8](data)
if (byte.count / 1024) >= toKB {
// toKBを超えてた時
guard let againImage = UIImage(data: data) else { return nil }
guard let rescalingData = againImage.compressedJpegData(toKB: toKB) else { return nil }
data = rescalingData
}
return data
JPEG化したDataをバイト配列に入れ、サイズを見ます。
byte.count
はJPEGのバイト数を表しています。今回はKBで計算したいので1024で割ります。
割った結果がtoKB
を下回っていればそのままdata
を返し、超えていた場合は再度UIImageにして圧縮処理します。
以上の流れを、サイズがtoKB
を下回るまで行います。
もしよかったら使っていただけるとありがたいです。いいねも押していただけると喜びます。
不明点、不足点、改善点など、何でもコメントしてください。
ありがとうございました。