由于項(xiàng)目中有大量的上傳圖片绰筛,之前圖片的處理方式直接就用了UIImageJPEGRepresentation方式來處理,也用了很長(zhǎng)的一段時(shí)間描融,后面由于權(quán)限的開放铝噩,從相冊(cè)選擇的使用頻率變高,由于圖片的來源不一窿克,所以相片的質(zhì)量不一樣薄榛,有的是客戶從其他渠道傳輸過來的,肯定也經(jīng)過了壓縮的處理让歼,所以再經(jīng)過我們這邊統(tǒng)一的方法再去壓縮的話,將會(huì)導(dǎo)致上傳的圖片失真丽啡,不清晰谋右。針對(duì)以上痛點(diǎn),于是有了下面的處理方式.
壓縮方式1:
循環(huán)壓縮法
/// 壓縮圖片數(shù)據(jù)-不壓尺寸
///
/// - Parameters:
/// - maxLength: 最大長(zhǎng)度
/// - Returns:
func compressImageOnlength(maxLength: Int) -> Data? {
guard let vData = UIImageJPEGRepresentation(self, 1) else { return nil }
XYJLog(message: "壓縮前kb: \( Double((vData.count)/1024))")
if vData.count < maxLength {
return vData
}
var compress:CGFloat = 0.9
guard var data = UIImageJPEGRepresentation(self, compress) else { return nil }
while data.count > maxLength && compress > 0.01 {
XYJLog(message: "壓縮比: \(compress)")
compress -= 0.02
data = UIImageJPEGRepresentation(self, compress)!
}
XYJLog(message: "壓縮后kb: \(Double((data.count)/1024))")
return data
}
由于我們的需求是最多可以五張圖片拼接處理补箍,最后壓縮的時(shí)候改执,采用此方法,可能會(huì)導(dǎo)致壓縮時(shí)間比較久坑雅,用戶體驗(yàn)不友好辈挂,于是采用了方式二
壓縮方式2:
二分壓縮法
//二分壓縮法
func compressImageMid(maxLength: Int) -> Data? {
var compression: CGFloat = 1
guard var data = UIImageJPEGRepresentation(self, 1) else { return nil }
XYJLog(message: "壓縮前kb: \( Double((data.count)/1024))")
if data.count < maxLength {
return data
}
print("壓縮前kb", data.count / 1024, "KB")
var max: CGFloat = 1
var min: CGFloat = 0
for _ in 0..<6 {
compression = (max + min) / 2
data = UIImageJPEGRepresentation(self, compression)!
if CGFloat(data.count) < CGFloat(maxLength) * 0.9 {
min = compression
} else if data.count > maxLength {
max = compression
} else {
break
}
}
var resultImage: UIImage = UIImage(data: data)!
if data.count < maxLength {
return data
}
方式一、二調(diào)用的方式如下
// 壓縮到1M 以內(nèi)
var imageData = uploadsizeImg?.compressImageMid(maxLength: 1024*1024)
采用二分壓縮法在效率上有一定的提升裹粤,但是對(duì)于五張圖片合成后终蒂,如果尺寸越大,越越容易導(dǎo)致內(nèi)存出現(xiàn)問題,嚴(yán)重的將會(huì)導(dǎo)致崩潰拇泣,所以在壓縮數(shù)據(jù)前我們需要對(duì)合成的圖片做尺寸上的壓縮
尺寸壓縮法
/// 根據(jù)尺寸重新生成圖片
///
/// - Parameter size: 設(shè)置的大小
/// - Returns: 新圖
public func imageWithNewSize(size: CGSize) -> UIImage? {
if self.size.height > size.height {
let width = size.height / self.size.height * self.size.width
let newImgSize = CGSize(width: width, height: size.height)
UIGraphicsBeginImageContext(newImgSize)
self.draw(in: CGRect(x: 0, y: 0, width: newImgSize.width, height: newImgSize.height))
let theImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
guard let newImg = theImage else { return nil}
return newImg
} else {
let newImgSize = CGSize(width: size.width, height: size.height)
UIGraphicsBeginImageContext(newImgSize)
self.draw(in: CGRect(x: 0, y: 0, width: newImgSize.width, height: newImgSize.height))
let theImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
guard let newImg = theImage else { return nil}
return newImg
}
}
圖片合成問題補(bǔ)充
1. 合成圖片:由于上傳確認(rèn)頁面的圖片可以點(diǎn)擊進(jìn)去編輯圖片噪叙,或者添加圖片,如果這里每添加一張圖片或者合成一張圖片的話霉翔,會(huì)相當(dāng)?shù)暮馁M(fèi)性能睁蕾,所以合成圖片的操作放在點(diǎn)擊上傳按鈕那里
點(diǎn)擊上傳調(diào)用合成圖片方法,合成圖片方法主要分兩步债朵,實(shí)現(xiàn)思路如下:
(1)創(chuàng)建一個(gè)contentView用來裝多個(gè)ImageView子眶,根據(jù)圖片數(shù)組的數(shù)量for循環(huán)來添加imageview,imageview設(shè)置圖片的時(shí)候先對(duì)圖片進(jìn)行數(shù)據(jù)壓縮處理序芦,然后再對(duì)尺寸進(jìn)行壓縮處理,下面是壓縮處理規(guī)則:
if imagedata.count < 0.8M {
不壓縮
} else if imagedata.count > 0.8M && imagedata.count <1M {
壓縮系數(shù)0.8獲取圖像
} else if imagedata.count > 1M && imagedata.count <2M {
壓縮系數(shù)0.3獲取圖像
} else {
壓縮系數(shù)0.1獲取圖像
}
壓縮完數(shù)據(jù)以后再進(jìn)行尺寸壓縮
if 圖片寬度>兩倍屏幕寬 || 圖片高度>兩倍屏幕高 {
圖片大小縮放系數(shù)0.5處理
}
縮放之后設(shè)置到imageView上
(2)通過for循環(huán)來獲取contentView上的imageView上的圖片臭杰,根據(jù)已經(jīng)處理好的image來設(shè)置imageview的frame,排好版面到contentView上芝加,最后就是將contentView轉(zhuǎn)化成image硅卢,并且賦值給合成圖片變量composeImage
以上兩個(gè)for循環(huán)中的內(nèi)容置于autoreleasepool中
整個(gè)上傳流程
點(diǎn)擊上傳 ->進(jìn)入合成圖片方法,顯示正在加載的圈圈藏杖,延時(shí)1.5秒進(jìn)入上傳方法 -> 二分法壓縮圖片數(shù)據(jù)到1M以內(nèi)将塑,圖片大于3張延時(shí)3秒,否則2秒蝌麸,延時(shí)之后執(zhí)行隱藏壓縮圈圈方法点寥,發(fā)起正式上傳網(wǎng)絡(luò)請(qǐng)求 -> 上傳成功之后,圖片變量置為nil,移除圖片數(shù)組元素来吩,返回上一級(jí)敢辩,查看deinit打印執(zhí)行
測(cè)試與分析
6測(cè)試---這里還是之前的合成圖片后,再對(duì)合成圖片壓縮尺寸
如果一進(jìn)入上傳頁面頁面顯示且繪制合成圖片51 -> 61 大概增加10M到150M
五張合成后再縮放圖片:大概增加100 到150M
單獨(dú)測(cè)試壓縮方法 增加大概100M
單獨(dú)測(cè)試壓縮方法加上傳 增加大概110M
縮放圖片尺寸加壓縮 測(cè)試大概增加150M
縮放 壓縮 上傳一氣呵成大概也是增加150M左右
綜上最耗內(nèi)存的兩個(gè)方法 一個(gè)是縮放尺寸(會(huì)進(jìn)行繪制) 一個(gè)是壓縮
大小手機(jī)測(cè)試:
5s 上傳7+拍的5張照片 整個(gè)上傳過程 最高出現(xiàn)增加350M
5s 上傳自己拍的5張 最高出現(xiàn)增加240M
分析:
1.在幾個(gè)for循環(huán)里面加個(gè)自動(dòng)釋放池感覺沒有緩解什么弟疆,幾M的區(qū)別
2.縮放的的圖片被壓縮成data后戚长,馬上置為nil 整個(gè)上傳過程增加100-130 所以這里有一定的作用
3. 有的圖片的長(zhǎng)寬高達(dá)屏幕的5,6倍怠苔,所以在合成之前同廉,我們可以把每一張圖片縮放一半,后面整張合成的圖片將不再進(jìn)行縮放柑司,經(jīng)測(cè)試這樣合成圖片迫肖,再去上傳圖片,我用5s上傳7+拍的圖片大概增加120M攒驰,相比以前的240蟆湖,350節(jié)約一大半的內(nèi)存,可以有效防止內(nèi)存不足閃退玻粪。
總結(jié):經(jīng)過以上的方法處理隅津,圖片的質(zhì)量和內(nèi)存有了很大的改善诬垂,值得注意的是,我們?cè)谔幚韴D片的時(shí)候饥瓷,一定要注意測(cè)試內(nèi)存剥纷,如果內(nèi)存沒有釋放,將隨著拍攝次數(shù)的增多呢铆,內(nèi)存逐漸增大晦鞋,最后的結(jié)果就是崩潰,可能客戶跟你反饋棺克,你還會(huì)一臉懵逼悠垛,當(dāng)然知道這個(gè)問題就好辦了,這種情況一般是圖片沒有釋放娜谊,或者代碼里有循環(huán)引用所致确买,解決好就可以了。