2018-08-15 iOS展示超大图片或超高分辨率图片崩溃解决方法

转载:https://blog.csdn.net/u014544904/article/details/76439259

前言:

ID作为一款以IM为基础的办公软件,在用户使用过程中,经常会遇到一些超大的或者超高分辨率的图片(以下统一称:大图)。基于SDWebImage为基础的图片加载控件,在遇到此情况时,并没有提供十分有效的解决方法(如果你谷歌或者百度,有很多回答,但实际并未能解决此问题)。曾经一度困扰许久。现在将我的解决方式写下来,希望可以对你有所帮助。

参考:

作为IM软件的领军,QQ与微信无疑给IM行业树立了一个很好的榜样。那我们就来看看它们是如何处理的(以下简单描述,自己可以实际体验):

QQ:

点击大图浏览时,会有一个转圈等待操作,对图片放大的大小无限制。在放大过程中,图片会模糊,停止操作后,一张清晰的高清图渲染出来。如果图片过大并分辨率超高(上万),会出现崩溃。

微信:

点击大图浏览时,直接展示。但是对图片展示大小有限制。放大到一定程度,无法继续放大查看。

做为办公软件,无需解释,很明显QQ的方式更符合需求。

实现:

对于大图,压缩肯定使我们需要的,QQ转圈等待同样我猜测也是压缩操作。

压缩:

压缩图片我们希望可以保证压缩的速度够快及内存消耗的尽可能小。在此感谢github上的OTLargeImageReader的作者,压缩过程中内存控制和速度都很好。

关键代码:

//先从内存中查找,查找不到再解码,避免重复解码

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的交互方式,此时,一张分辨率有限的大图在经过短暂压缩处理后,已经可以非常安全的在app中展示浏览了(缓存压缩图片避免重复压缩)。但是,压缩过的图片放大后,模糊不清了!这不能忍,继续搞。

当在QQ中浏览图片进行放大时,可以很轻易的发现,此时的图片也是模糊的(这就印证了转圈过程中对图片的压缩操作),然而当我们停止放大操作后,当前展示的模糊图被重新渲染展示给我们,清晰,完美!

此时,如果你遇到过这个问题,并且尝试过解决,你肯定找到了苹果官方提供的Demo以及一些分块加载的方式。这个成本太高,不建议。

思来想去,一个新的方式出现了:用户在这个大图中,关注的只有当前屏幕中展示的这一区域的图片,当用户不操作图片时,拿到图片在手机屏幕上的元素覆盖展示出来。用户操作时,移除覆盖图层,停止后重新操作。

裁剪图片:

裁剪当前屏幕中展示对应原图中的位置

- (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;

    }

}

结语:

此解决方式在实现上非常简单,开始只是困于思路。如果你有其他的方式,那我们就开始一段愉快的交流吧!

你可能感兴趣的:(2018-08-15 iOS展示超大图片或超高分辨率图片崩溃解决方法)