前言:
ID作為一款以IM為基礎(chǔ)的辦公軟件逐哈,在用戶使用過程中,經(jīng)常會遇到一些超大的或者超高分辨率的圖片(以下統(tǒng)一稱:大圖)攒庵〔坜龋基于
SDWebImage
為基礎(chǔ)的圖片加載控件几睛,在遇到此情況時(shí),并沒有提供十分有效的解決方法(如果你谷歌或者百度粤攒,有很多回答所森,但實(shí)際并未能解決此問題)。曾經(jīng)一度困擾許久『唤樱現(xiàn)在將我的解決方式寫下來焕济,希望可以對你有所幫助。
參考:
作為IM軟件的領(lǐng)軍盔几,QQ與微信無疑給IM行業(yè)樹立了一個(gè)很好的榜樣晴弃。那我們就來看看它們是如何處理的(以下簡單描述,自己可以實(shí)際體驗(yàn)):
QQ:
點(diǎn)擊大圖瀏覽時(shí)逊拍,會有一個(gè)轉(zhuǎn)圈等待操作上鞠,對圖片放大的大小無限制。在放大過程中芯丧,圖片會模糊芍阎,停止操作后,一張清晰的高清圖渲染出來缨恒。如果圖片過大并分辨率超高(上萬)谴咸,會出現(xiàn)崩潰。微信:
點(diǎn)擊大圖瀏覽時(shí)骗露,直接展示岭佳。但是對圖片展示大小有限制。放大到一定程度椒袍,無法繼續(xù)放大查看驼唱。做為辦公軟件藻茂,無需解釋驹暑,很明顯QQ的方式更符合需求玫恳。
實(shí)現(xiàn):
對于大圖,壓縮肯定使我們需要的优俘,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), ^{
CGSize compressSize = 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];
[self resetSize];
});
});
}
else {
//直接使用
self.showImageView.image = cacheImage;
}
通過以上方式,加上參考QQ的交互方式折晦,此時(shí)钥星,一張分辨率有限的大圖在經(jīng)過短暫壓縮處理后,已經(jīng)可以非常安全的在app中展示瀏覽了(緩存壓縮圖片避免重復(fù)壓縮)满着。但是谦炒,壓縮過的圖片放大后,模糊不清了风喇!這不能忍宁改,繼續(xù)搞。
當(dāng)在QQ中瀏覽圖片進(jìn)行放大時(shí)魂莫,可以很輕易的發(fā)現(xiàn)还蹲,此時(shí)的圖片也是模糊的(這就印證了轉(zhuǎn)圈過程中對圖片的壓縮操作),然而當(dāng)我們停止放大操作后耙考,當(dāng)前展示的模糊圖被重新渲染展示給我們秽誊,清晰,完美琳骡!
此時(shí)锅论,如果你遇到過這個(gè)問題,并且嘗試過解決楣号,你肯定找到了蘋果官方提供的Demo以及一些分塊加載的方式最易。這個(gè)成本太高,不建議炫狱。
思來想去藻懒,一個(gè)新的方式出現(xiàn)了:用戶在這個(gè)大圖中,關(guān)注的只有當(dāng)前屏幕中展示的這一區(qū)域的圖片视译,當(dāng)用戶不操作圖片時(shí)嬉荆,拿到圖片在手機(jī)屏幕上的元素覆蓋展示出來。用戶操作時(shí)酷含,移除覆蓋圖層鄙早,停止后重新操作汪茧。裁剪圖片:
裁剪當(dāng)前屏幕中展示對應(yīng)原圖中的位置
- (void)didCutImage {
if (_orImage) {
if (self.scrollView.contentSize.width >= kScreenWidth &&
self.scrollView.contentSize.height >= kScreenHeight) {
CGFloat multipleF = _orImage.size.width/self.scrollView.contentSize.width;
CGFloat width = kScreenWidth*multipleF;
CGFloat height = 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];
}
//裁剪展示視圖
CGImageRef cgRef = _orImage.CGImage;
CGImageRef imageRef = CGImageCreateWithImageInRect(cgRef, CGRectMake(self.scrollView.contentOffset.x *multipleF ,self.scrollView.contentOffset.y *multipleF, width, height));
UIImage *thumbScale = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);
self.bigCupImageView.image = thumbScale;
}
}
}
在這個(gè)過程中舱污,仍需要注意的是,何時(shí)展示與隱藏剪切出來的圖片弥虐。
覆蓋圖片的添加與移除:
添加:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
[NSObject cancelPreviousPerformRequestsWithTarget:self];
[self performSelector:@selector(didCutImage) withObject:nil afterDelay:.5];
}
移除:
- (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(nullable UIView *)view {
if (_bigCupImageView) {
[_bigCupImageView removeFromSuperview];
_bigCupImageView = nil;
}
}
結(jié)語:
此解決方式在實(shí)現(xiàn)上非常簡單扩灯,開始只是困于思路。如果你有其他的方式霜瘪,那我們就開始一段愉快的交流吧珠插!