轉(zhuǎn)載:https://blog.csdn.net/u014544904/article/details/76439259
ID作為一款以IM為基礎(chǔ)的辦公軟件卷要,在用戶使用過程中为牍,經(jīng)常會遇到一些超大的或者超高分辨率的圖片(以下統(tǒng)一稱:大圖)剿吻。基于SDWebImage為基礎(chǔ)的圖片加載控件洋魂,在遇到此情況時歧蕉,并沒有提供十分有效的解決方法(如果你谷歌或者百度委煤,有很多回答,但實際并未能解決此問題)棒卷。曾經(jīng)一度困擾許久」四酰現(xiàn)在將我的解決方式寫下來,希望可以對你有所幫助比规。
作為IM軟件的領(lǐng)軍岩齿,QQ與微信無疑給IM行業(yè)樹立了一個很好的榜樣。那我們就來看看它們是如何處理的(以下簡單描述苞俘,自己可以實際體驗):
QQ:
點(diǎn)擊大圖瀏覽時盹沈,會有一個轉(zhuǎn)圈等待操作,對圖片放大的大小無限制。在放大過程中乞封,圖片會模糊做裙,停止操作后,一張清晰的高清圖渲染出來肃晚。如果圖片過大并分辨率超高(上萬)锚贱,會出現(xiàn)崩潰。
微信:
點(diǎn)擊大圖瀏覽時关串,直接展示拧廊。但是對圖片展示大小有限制。放大到一定程度晋修,無法繼續(xù)放大查看吧碾。
做為辦公軟件,無需解釋墓卦,很明顯QQ的方式更符合需求倦春。
對于大圖,壓縮肯定使我們需要的落剪,QQ轉(zhuǎn)圈等待同樣我猜測也是壓縮操作睁本。
壓縮:
壓縮圖片我們希望可以保證壓縮的速度夠快及內(nèi)存消耗的盡可能小。在此感謝github上的OTLargeImageReader的作者忠怖,壓縮過程中內(nèi)存控制和速度都很好呢堰。
關(guān)鍵代碼:
//先從內(nèi)存中查找,查找不到再解碼凡泣,避免重復(fù)解碼
UIImage*cacheImage = [self.photoBrowser cacheImageWithPhoto:_photo];
if(cacheImage ==nil) {
//不存在枉疼,解碼
[self.photoBrowser showHUDWithSuperBigPhoto];
dispatch_async(dispatch_get_global_queue(0,0), ^{
CGSizecompressSize =CGSizeMake(XXPhotoCompressPixelMax, XXPhotoCompressPixelMax);
if(image.size.width > image.size.height) {
compressSize =CGSizeMake(XXPhotoCompressPixelMax, XXPhotoCompressPixelMax*image.size.height/image.size.width);
? ? ? ? }
else{
compressSize =CGSizeMake(XXPhotoCompressPixelMax*image.size.width/image.size.height, XXPhotoCompressPixelMax);
? ? ? ? }
UIImage*compressedImage = [image imageByScalingProportionallyToSize:compressSize];
dispatch_async(dispatch_get_main_queue(), ^{
[self.photoBrowser cacheImageWithPhoto:_photo image:compressedImage];
self.showImageView.image = compressedImage;
[self.photoBrowser hideHUDWithSuperBigPhoto];
[selfresetSize];
? ? ? ? });
? ? });
}
else{
//直接使用
self.showImageView.image = cacheImage;
}
通過以上方式,加上參考QQ的交互方式问麸,此時往衷,一張分辨率有限的大圖在經(jīng)過短暫壓縮處理后,已經(jīng)可以非常安全的在app中展示瀏覽了(緩存壓縮圖片避免重復(fù)壓縮)严卖。但是席舍,壓縮過的圖片放大后,模糊不清了哮笆!這不能忍来颤,繼續(xù)搞。
當(dāng)在QQ中瀏覽圖片進(jìn)行放大時稠肘,可以很輕易的發(fā)現(xiàn)福铅,此時的圖片也是模糊的(這就印證了轉(zhuǎn)圈過程中對圖片的壓縮操作),然而當(dāng)我們停止放大操作后项阴,當(dāng)前展示的模糊圖被重新渲染展示給我們滑黔,清晰,完美!
此時略荡,如果你遇到過這個問題庵佣,并且嘗試過解決,你肯定找到了蘋果官方提供的Demo以及一些分塊加載的方式汛兜。這個成本太高巴粪,不建議耙箍。
思來想去多律,一個新的方式出現(xiàn)了:用戶在這個大圖中,關(guān)注的只有當(dāng)前屏幕中展示的這一區(qū)域的圖片活鹰,當(dāng)用戶不操作圖片時漏策,拿到圖片在手機(jī)屏幕上的元素覆蓋展示出來派哲。用戶操作時,移除覆蓋圖層哟玷,停止后重新操作狮辽。
裁剪圖片:
裁剪當(dāng)前屏幕中展示對應(yīng)原圖中的位置
- (void)didCutImage {
if(_orImage) {
if(self.scrollView.contentSize.width >= kScreenWidth &&
self.scrollView.contentSize.height >= kScreenHeight) {
CGFloatmultipleF = _orImage.size.width/self.scrollView.contentSize.width;
CGFloatwidth = kScreenWidth*multipleF;
CGFloatheight = kScreenHeight *multipleF;
//如果剪切的尺寸過大一也,不處理
if(width > XXPhotoPixelMax ||
? ? ? ? ? ? ? ? height > XXPhotoPixelMax) {
return;
? ? ? ? ? ? }
//如果剪切的尺寸過大巢寡,不處理
//裁剪展示視圖
if(_bigCupImageView) {
_bigCupImageView.frame =CGRectMake(self.scrollView.contentOffset.x,self.scrollView.contentOffset.y, kScreenWidth, kScreenHeight);
? ? ? ? ? ? }
else{
[self.scrollView addSubview:self.bigCupImageView];
? ? ? ? ? ? }
//裁剪展示視圖
CGImageRefcgRef = _orImage.CGImage;
CGImageRefimageRef =CGImageCreateWithImageInRect(cgRef,CGRectMake(self.scrollView.contentOffset.x *multipleF? ,self.scrollView.contentOffset.y *multipleF, width, height));
UIImage*thumbScale = [UIImageimageWithCGImage:imageRef];
CGImageRelease(imageRef);
self.bigCupImageView.image = thumbScale;
? ? ? ? }
? ? }
}
在這個過程中,仍需要注意的是椰苟,何時展示與隱藏剪切出來的圖片抑月。
覆蓋圖片的添加與移除:
添加:
- (void)scrollViewDidScroll:(UIScrollView*)scrollView {
[NSObjectcancelPreviousPerformRequestsWithTarget:self];
[selfperformSelector:@selector(didCutImage) withObject:nilafterDelay:.5];
}
移除:
- (void)scrollViewWillBeginZooming:(UIScrollView*)scrollView withView:(nullableUIView*)view {
if(_bigCupImageView) {
? ? ? ? [_bigCupImageView removeFromSuperview];
_bigCupImageView =nil;
? ? }
}
此解決方式在實現(xiàn)上非常簡單,開始只是困于思路舆蝴。如果你有其他的方式谦絮,那我們就開始一段愉快的交流吧!