iOS优秀的图片压缩处理方案

背景:

        最近遇到一个图片压缩的问题,项目需求压缩图片500k以内上传服务器,还要求图片要清晰一点。事实证明500k的图片肉眼识别已经是很清晰,那就没办法了,硬着头皮上了。下面是我的一些心得体会,以及考虑到的一些方向,拿出来以供大家参考。

 

思路:

        本来以为很简单的问题,自己随意写了一个UIImageJPEGRepresentation的方法进行一个循环压缩不就搞定了?后来事实证明这个想法是错的,有太多东西不是你想当然的。

问题:

1.为什么不提UIImagePNGRepresentation(<#UIImage * _Nonnull image#>)?

回复:据说这个读取图片的大小会比较大,因为是png格式,读取的内容会有多图层的的问题导致读取的会显示比较大,而且比较耗时间。网上有人做过测试:同样是读取摄像头拍摄的同样景色的照片,UIImagePNGRepresentation() 返回的数据量大小为199K,而 UIImageJPEGRepresentation(UIImage* image, 1.0) 返回的数据量大小只为 140KB,比前者少了50多KB。如果对图片的清晰度要求不高,还可以通过设置 UIImageJPEGRepresentation 函数的第二个参数,来降低图片数据量。

       如果还有什么问题可以继续百度,这里不进行过多赘述。

 

2.首先第一个参数是我们都知道的图片image,但是第二个参数scale,一个0~1的浮点型比率,你以为0就是没有,压缩到0b大小,1.0就是原图大小?

       答案是:错!首先你的图片的大小是根据(图片的宽*图片的高*每一个色彩的深度,这个和手机的硬件有关,一般是4)。其次,第二个参数苹果官方并没有明确说明这个参数的具体意义。对于大图片来说,即使你的scale选的很小,比如:0.0000000(n个0)001,但是得到的结果还是很大,这里做了一个实验:一个10M左右的图片,处理后大小为2M多。有点像是“压不动”的感觉。当然如果是小图片的话那就是没问题,能满足你的希望的压缩到的大小。

        

        既然是循环压,那么就要说一下算法。考虑到递归,二分法,后来发现网上也是有的,二分法处理:更快一点压缩图片到指定的大小。先看一段代码:

//二分最大10次,区间范围精度最大可达0.00097657;最大6次,精度可达0.015625
        for (int i = 0; i < 10; ++i) {
            compression = (max + min) / 2;
            imageData = UIImageJPEGRepresentation(image, compression);
            //容错区间范围0.9~1.0
            if (imageData.length < fImageBytes * 0.9) {
                min = compression;
            } else if (imageData.length > fImageBytes) {
                max = compression;
            } else {
                break;
            }
        }

     上面就是使用二分法进行处理,比for循环依次递减“高效”很多,而且也合理很多。

     这样压缩到“极致”(一般我们不用进行太多的for循环,个人觉得参数到0.05已经可以了如果还是比你想要的大很多那就不要用UIImageJPEGRepresentation了),劳民伤财,劳的是cpu的高速运转,伤的是手机老化加快。哈哈,皮一下!

 

3.上面也提到了压缩“压不动”怎么办?

      我们其实可以换一个方式,进行尺寸压缩:

      提到尺寸压缩,你会不会很失望,看你的文章,原来也是使用UIGraphicsBeginImageContextWithOptions然后drawInRect绘制一个图片大小。

       代码类似如下:

/* 根据 dWidth dHeight 返回一个新的image**/
- (UIImage *)drawWithWithImage:(UIImage *)imageCope Size:(CGSize)size {
//这里设置为0,意为自动设置清晰度,图片可以是别的传过来的图片信息
    UIGraphicsBeginImageContextWithOptions(size, NO,0);
    [imageCope drawInRect:CGRectMake(0, 0, size.width, size.height)];
    imageCope = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return imageCope;
}

 

 

       首先我需要说一下这个绘制很耗内存性能的,[UIImage drawInRect:]在绘制时,先解码图片,再生成原始分辨率大小的bitmap,这是很耗内存的,并且还有位数对齐等耗时操作。如果在一个方法中循环压缩比例进行代码的比例压缩,那么这种使用UIKit类进行图片绘制的话是需要先把图片读入内存然后在进行绘制,那么势必会给内存中占用大量的临时内存bitmap,而这个如果再加上循环,那么内存占有将是不可估量的。

 

4.你可能会说,我加一个自动释放池@autoreleasepool,不就好了?

        错:首

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值