iOS如何實現圖片壓縮
本文講解"iOS怎么實現圖片壓縮",用于解決相關問題。
兩種壓縮圖片的方法:壓縮圖片質量(),壓縮圖片尺寸(Size)。
壓縮圖片質量
NSData?*data?=?UIImageJPEGRepresentation(image,?compression); UIImage?*resultImage?=?[UIImage?imageWithData:data];
通過 和 的相互轉化,減小 JPEG 圖片的質量來壓縮圖片。ation:: 第二個參數 取值 0.0~1.0,值越小表示圖片質量越低,圖片文件自然越小。
壓縮圖片尺寸
UIGraphicsBeginImageContext(size); [image?drawInRect:CGRectMake(0,?0,?size.width,?size.height)]; resultImage?=?UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext();
給定所需的圖片尺寸 size, 即為原圖 image 繪制為 size 大小的圖片。
壓縮圖片使圖片文件小于指定大小
如果對圖片清晰度要求不高,要求圖片的上傳、下載速度快的話,上傳圖片前需要壓縮圖片。壓縮到什么程度要看具體情況,但一般會設定一個圖片文件最大值,例如 100 KB??梢杂蒙显V兩種方法來壓縮圖片。假設圖片轉化來的 對象為 data,通過data.即可得到圖片的字節大小。
壓縮圖片質量
比較容易想到的方法是ios是否會壓縮jpg格式,通過循環來逐漸減小圖片質量,直到圖片稍小于指定大小()。
+?(UIImage?*)compressImageQuality:(UIImage?*)image?toByte:(NSInteger)maxLength?{ ?CGFloat?compression?=?1; ?NSData?*data?=?UIImageJPEGRepresentation(image,?compression); ?while?(data.length?>?maxLength?&&?compression?>?0)?{ ?compression?-=?0.02; ?data?=?UIImageJPEGRepresentation(image,?compression);?//?When?compression?less?than?a?value,?this?code?dose?not?work ?} ?UIImage?*resultImage?=?[UIImage?imageWithData:data]; ?return?resultImage; }
這樣循環次數多,效率低,耗時長。
可以通過二分法來優化。
+?(UIImage?*)compressImageQuality:(UIImage?*)image?toByte:(NSInteger)maxLength?{ ?CGFloat?compression?=?1; ?NSData?*data?=?UIImageJPEGRepresentation(image,?compression); ?if?(data.length??maxLength)?{ ?max?=?compression; ?}?else?{ ?break; ?} ?} ?UIImage?*resultImage?=?[UIImage?imageWithData:data]; ?return?resultImage; }
當圖片大小小于 ,大于 * 0.9 時,不再繼續壓縮。最多壓縮 6 次,1/(2^6) = 0. < 0.02,也能達到每次循環 減小 0.02 的效果。這樣的壓縮次數比循環減小 少,耗時短。需要注意的是,當圖片質量低于一定程度時,繼續壓縮沒有效果。也就是說, 繼續減小,data 也不再繼續減小。壓縮圖片質量的優點在于,盡可能保留圖片清晰度,圖片不會明顯模糊;缺點在于ios是否會壓縮jpg格式,不能保證圖片壓縮后小于指定大小。
壓縮圖片尺寸
與之前類似,比較容易想到的方法是,通過循環逐漸減小圖片尺寸,直到圖片稍小于指定大小()。具體代碼省略。同樣的問題是循環次數多,效率低,耗時長??梢杂枚址▉硖岣咝?,具體代碼省略。這里介紹另外一種方法,比二分法更好,壓縮次數少,而且可以使圖片壓縮后剛好小于指定大小(不只是 < , > * 0.9)。
+?(UIImage?*)compressImageSize:(UIImage?*)image?toByte:(NSUInteger)maxLength?{ ?UIImage?*resultImage?=?image; ?NSData?*data?=?UIImageJPEGRepresentation(resultImage,?1); ?NSUInteger?lastDataLength?=?0; ?while?(data.length?>?maxLength?&&?data.length?!=?lastDataLength)?{ ?lastDataLength?=?data.length; ?CGFloat?ratio?=?(CGFloat)maxLength?/?data.length; ?CGSize?size?=?CGSizeMake((NSUInteger)(resultImage.size.width?*?sqrtf(ratio)),?(NSUInteger)(resultImage.size.height?*?sqrtf(ratio)));?//?Use?NSUInteger?to?prevent?white?blank ?UIGraphicsBeginImageContext(size); ?//?Use?image?to?draw?(drawInRect:),?image?is?larger?but?more?compression?time ?//?Use?result?image?to?draw,?image?is?smaller?but?less?compression?time ?[resultImage?drawInRect:CGRectMake(0,?0,?size.width,?size.height)]; ?resultImage?=?UIGraphicsGetImageFromCurrentImageContext(); ?UIGraphicsEndImageContext(); ?data?=?UIImageJPEGRepresentation(resultImage,?1); ?} ?return?resultImage; }
[ :(0, 0, size.width, size.)];是用新圖 繪制,也可以用原圖 image 來繪制。用原圖繪制,壓縮后圖片更接近指定大小,但是壓縮次數較多,耗時較長。一張大小為 6064 KB 的圖片,壓縮圖片尺寸,原圖繪制與新圖繪制結果如下
指定大小(KB)原圖繪制壓縮后大小(KB)原圖繪制壓縮次數新圖繪制壓縮后大小(KB)新圖繪制壓縮次數
500
498
6
498
3
300
299
4
296
3
100
99
5
98
3
50
49
6
48
3
兩種繪制方法壓縮后大小很接近,與指定大小也很接近,但原圖繪制壓縮次數可達到新圖繪制壓縮次數的兩倍。建議使用新圖繪制,減少壓縮次數。壓縮后圖片明顯比壓縮質量模糊。
需要注意的是繪制尺寸的代碼
size = (()(.size.width * sqrtf(ratio)), ()(.size. * sqrtf(ratio)));,每次繪制的尺寸 size,要把寬 width 和 高 轉換為整數,防止繪制出的圖片有白邊。
壓縮圖片尺寸可以使圖片小于指定大小,但會使圖片明顯模糊(比壓縮圖片質量模糊)。
兩種圖片壓縮方法結合
如果要保證圖片清晰度,建議選擇壓縮圖片質量。如果要使圖片一定小于指定大小,壓縮圖片尺寸可以滿足。對于后一種需求,還可以先壓縮圖片質量,如果已經小于指定大小,就可得到清晰的圖片,否則再壓縮圖片尺寸。
+?(UIImage?*)compressImage:(UIImage?*)image?toByte:(NSUInteger)maxLength?{ ?//?Compress?by?quality ?CGFloat?compression?=?1; ?NSData?*data?=?UIImageJPEGRepresentation(image,?compression); ?if?(data.length??maxLength)?{ ?max?=?compression; ?}?else?{ ?break; ?} ?} ?UIImage?*resultImage?=?[UIImage?imageWithData:data]; ?if?(data.length??maxLength?&&?data.length?!=?lastDataLength)?{ ?lastDataLength?=?data.length; ?CGFloat?ratio?=?(CGFloat)maxLength?/?data.length; ?CGSize?size?=?CGSizeMake((NSUInteger)(resultImage.size.width?*?sqrtf(ratio)),?(NSUInteger)(resultImage.size.height?*?sqrtf(ratio)));?//?Use?NSUInteger?to?prevent?white?blank ?UIGraphicsBeginImageContext(size); ?[resultImage?drawInRect:CGRectMake(0,?0,?size.width,?size.height)]; ?resultImage?=?UIGraphicsGetImageFromCurrentImageContext(); ?UIGraphicsEndImageContext(); ?data?=?UIImageJPEGRepresentation(resultImage,?compression); ?} ?return?resultImage; }
下面看下iOS圖片壓縮上傳的實現方法
需求
很多時候我們上傳圖片經常遇到一些問題,要不就是圖片質量變差,要不就是圖片太大等等問題。這里,我找到了一個算是目前比較符合需求的解決方案。在原有基礎上增加了動態壓縮系數,改寫成Swift版本。
實現思路
先調整分辨率,分辨率可以自己設定一個值,大于的就縮小到這分辨率,小余的就保持原本分辨率。然后再根據圖片最終大小來設置壓縮比,比如傳入 = 30KB,最終計算大概這個大小的壓縮比。基本上最終出來的圖片數據根據當前分辨率能保持差不多的大小同時不至于太模糊,跟微信,微博最終效果應該是差不多的,代碼仍然有待優化!
實現代碼
.0之前舊版本壓縮模式
//?MARK:?-?降低質量 ?func?resetSizeOfImageData(source_image:?UIImage,?maxSize:?Int)?->?NSData?{ ??//先調整分辨率 ??var?newSize?=?CGSize(width:?source_image.size.width,?height:?source_image.size.height) ??let?tempHeight?=?newSize.height?/?1024 ??let?tempWidth?=?newSize.width?/?1024 ??if?tempWidth?>?1.0?&&?tempWidth?>?tempHeight?{ ???newSize?=?CGSize(width:?source_image.size.width?/?tempWidth,?height:?source_image.size.height?/?tempWidth) ??} ??else?if?tempHeight?>?1.0?&&?tempWidth?=1;?i--?{ ???value?=?CGFloat(i)*avg ???compressionQualityArr.addObject(value) ??} ??//調整大小 ??//說明:壓縮系數數組compressionQualityArr是從大到小存儲。 ??//思路:折半計算,如果中間壓縮系數仍然降不到目標值maxSize,則從后半部分開始尋找壓縮系數;反之從前半部分尋找壓縮系數 ??finallImageData?=?UIImageJPEGRepresentation(newImage,?CGFloat(compressionQualityArr[125]?as!?NSNumber)) ??if?Int(Int64((UIImageJPEGRepresentation(newImage,?CGFloat(compressionQualityArr[125]?as!?NSNumber))?.length)!)/1024)?>?maxSize?{ ???//拿到最初的大小 ???finallImageData?=?UIImageJPEGRepresentation(newImage,?1.0) ???//從后半部分開始 ???for?idx?in?126..<250?{ ????let?value?=?compressionQualityArr[idx] ????let?sizeOrigin?=?Int64((finallImageData?.length)!) ????let?sizeOriginKB?=?Int(sizeOrigin?/?1024) ????print("當前降到的質量:\(sizeOriginKB)") ????if?sizeOriginKB?>?maxSize?{ ?????print("\(idx)----\(value)") ?????finallImageData?=?UIImageJPEGRepresentation(newImage,?CGFloat(value?as!?NSNumber)) ????}?else?{ ?????break ????} ???} ??}?else?{ ???//拿到最初的大小 ???finallImageData?=?UIImageJPEGRepresentation(newImage,?1.0) ???//從前半部分開始 ???for?idx?in?0..<125?{ ????let?value?=?compressionQualityArr[idx] ????let?sizeOrigin?=?Int64((finallImageData?.length)!) ????let?sizeOriginKB?=?Int(sizeOrigin?/?1024) ????print("當前降到的質量:\(sizeOriginKB)") ????if?sizeOriginKB?>?maxSize?{ ?????print("\(idx)----\(value)") ?????finallImageData?=?UIImageJPEGRepresentation(newImage,?CGFloat(value?as!?NSNumber)) ????}?else?{ ?????break ????} ???} ??} ??return?finallImageData! ?}
.0版本二分法壓縮模式
//?MARK:?-?降低質量 func?resetSizeOfImageData(source_image:?UIImage!,?maxSize:?Int)?->?NSData?{ ?//先判斷當前質量是否滿足要求,不滿足再進行壓縮 ?var?finallImageData?=?UIImageJPEGRepresentation(source_image,1.0) ?let?sizeOrigin??=?finallImageData?.count ?let?sizeOriginKB?=?sizeOrigin!?/?1024 ?if?sizeOriginKB?<=?maxSize?{ ??return?finallImageData!?as?NSData ?} ?//先調整分辨率 ?var?defaultSize?=?CGSize(width:?1024,?height:?1024) ?let?newImage?=?self.newSizeImage(size:?defaultSize,?source_image:?source_image) ?finallImageData?=?UIImageJPEGRepresentation(newImage,1.0); ?//保存壓縮系數 ?let?compressionQualityArr?=?NSMutableArray() ?let?avg?=?CGFloat(1.0/250) ?var?value?=?avg ?var?i?=?250 ?repeat?{ ??i?-=?1 ??value?=?CGFloat(i)*avg ??compressionQualityArr.add(value) ?}?while?i?>=?1 ?/* ??調整大小 ??說明:壓縮系數數組compressionQualityArr是從大到小存儲。 ??*/ ?//思路:使用二分法搜索 ?finallImageData?=?self.halfFuntion(arr:?compressionQualityArr.copy()?as!?[CGFloat],?image:?newImage,?sourceData:?finallImageData!,?maxSize:?maxSize) ?//如果還是未能壓縮到指定大小,則進行降分辨率 ?while?finallImageData?.count?==?0?{ ??//每次降100分辨率 ??if?defaultSize.width-100?<=?0?||?defaultSize.height-100?<=?0?{ ???break ??} ??defaultSize?=?CGSize(width:?defaultSize.width-100,?height:?defaultSize.height-100) ??let?image?=?self.newSizeImage(size:?defaultSize,?source_image:?UIImage.init(data:?UIImageJPEGRepresentation(newImage,?compressionQualityArr.lastObject?as!?CGFloat)!)!) ??finallImageData?=?self.halfFuntion(arr:?compressionQualityArr.copy()?as!?[CGFloat],?image:?image,?sourceData:?UIImageJPEGRepresentation(image,1.0)!,?maxSize:?maxSize) ?} ?return?finallImageData!?as?NSData } //?MARK:?-?調整圖片分辨率/尺寸(等比例縮放) func?newSizeImage(size:?CGSize,?source_image:?UIImage)?->?UIImage?{ ?var?newSize?=?CGSize(width:?source_image.size.width,?height:?source_image.size.height) ?let?tempHeight?=?newSize.height?/?size.height ?let?tempWidth?=?newSize.width?/?size.width ?if?tempWidth?>?1.0?&&?tempWidth?>?tempHeight?{ ??newSize?=?CGSize(width:?source_image.size.width?/?tempWidth,?height:?source_image.size.height?/?tempWidth) ?}?else?if?tempHeight?>?1.0?&&?tempWidth??Data??{ ?var?tempFinallImageData?=?finallImageData ?var?tempData?=?Data.init() ?var?start?=?0 ?var?end?=?arr.count?-?1 ?var?index?=?0 ?var?difference?=?Int.max ?while?start?<=?end?{ ??index?=?start?+?(end?-?start)/2 ??tempFinallImageData?=?UIImageJPEGRepresentation(image,?arr[index])! ??let?sizeOrigin?=?tempFinallImageData.count ??let?sizeOriginKB?=?sizeOrigin?/?1024 ??print("當前降到的質量:\(sizeOriginKB)\n\(index)----\(arr[index])") ??if?sizeOriginKB?>?maxSize?{ ???start?=?index?+?1 ??}?else?if?sizeOriginKB?關于 "iOS怎么實現圖片壓縮" 就介紹到此。希望多多支持編程寶庫。
下一節:JVM類的加載機制原理是什么編程技術 和 程序設計
本文講解"JVM類的加載機制原理是什么",用于解決相關問題。一、JVM 類加載機制JVM 類加載機制分為五個部分:加載,驗證,準備,解析,初始化,下面我們就分別來看一下這五個過程。1. 加載:加載是類加載過 ...