美文网首页图形控件
Swift图片压缩处理

Swift图片压缩处理

作者: 星星点灯0_0 | 来源:发表于2017-11-27 09:33 被阅读0次

    由于项目中有大量的上传图片,之前图片的处理方式直接就用了UIImageJPEGRepresentation方式来处理,也用了很长的一段时间,后面由于权限的开放,从相册选择的使用频率变高,由于图片的来源不一,所以相片的质量不一样,有的是客户从其他渠道传输过来的,肯定也经过了压缩的处理,所以再经过我们这边统一的方法再去压缩的话,将会导致上传的图片失真,不清晰。针对以上痛点,于是有了下面的处理方式.

    压缩方式1:

    循环压缩法

       /// 压缩图片数据-不压尺寸
        ///
        /// - Parameters:
        ///   - maxLength: 最大长度
        /// - Returns:
        func compressImageOnlength(maxLength: Int) -> Data? {
            
            guard let vData = UIImageJPEGRepresentation(self, 1) else { return nil }
            XYJLog(message: "压缩前kb: \( Double((vData.count)/1024))")
            if vData.count < maxLength {
                return vData
            }
            var compress:CGFloat = 0.9
            guard var data = UIImageJPEGRepresentation(self, compress) else { return nil }
            while data.count > maxLength && compress > 0.01 {
                XYJLog(message: "压缩比: \(compress)")
                compress -= 0.02
                data = UIImageJPEGRepresentation(self, compress)!
            }
            XYJLog(message: "压缩后kb: \(Double((data.count)/1024))")
            return data
        }
    

    由于我们的需求是最多可以五张图片拼接处理,最后压缩的时候,采用此方法,可能会导致压缩时间比较久,用户体验不友好,于是采用了方式二

    压缩方式2:

    二分压缩法

         //二分压缩法
         func compressImageMid(maxLength: Int) -> Data? {
            var compression: CGFloat = 1
            guard var data = UIImageJPEGRepresentation(self, 1) else { return nil }
            XYJLog(message: "压缩前kb: \( Double((data.count)/1024))")
            if data.count < maxLength {
                return data
            }
            print("压缩前kb", data.count / 1024, "KB")
            var max: CGFloat = 1
            var min: CGFloat = 0
            for _ in 0..<6 {
                compression = (max + min) / 2
                data = UIImageJPEGRepresentation(self, compression)!
                if CGFloat(data.count) < CGFloat(maxLength) * 0.9 {
                    min = compression
                } else if data.count > maxLength {
                    max = compression
                } else {
                    break
                }
            }
            var resultImage: UIImage = UIImage(data: data)!
            if data.count < maxLength {
                return data
            }
    

    方式一、二调用的方式如下

    // 压缩到1M 以内
     var  imageData = uploadsizeImg?.compressImageMid(maxLength: 1024*1024)
    

    采用二分压缩法在效率上有一定的提升,但是对于五张图片合成后,如果尺寸越大,越越容易导致内存出现问题,严重的将会导致崩溃,所以在压缩数据前我们需要对合成的图片做尺寸上的压缩

    尺寸压缩法

       /// 根据尺寸重新生成图片
        ///
        /// - Parameter size: 设置的大小
        /// - Returns: 新图
        public func imageWithNewSize(size: CGSize) -> UIImage? {
        
            if self.size.height > size.height {
                
                let width = size.height / self.size.height * self.size.width
                
                let newImgSize = CGSize(width: width, height: size.height)
                
                UIGraphicsBeginImageContext(newImgSize)
                
                self.draw(in: CGRect(x: 0, y: 0, width: newImgSize.width, height: newImgSize.height))
                
                let theImage = UIGraphicsGetImageFromCurrentImageContext()
                
                UIGraphicsEndImageContext()
                
                guard let newImg = theImage else { return  nil}
                
                return newImg
                
            } else {
                
                let newImgSize = CGSize(width: size.width, height: size.height)
                
                UIGraphicsBeginImageContext(newImgSize)
                
                self.draw(in: CGRect(x: 0, y: 0, width: newImgSize.width, height: newImgSize.height))
                
                let theImage = UIGraphicsGetImageFromCurrentImageContext()
                
                UIGraphicsEndImageContext()
                
                guard let newImg = theImage else { return  nil}
                
                return newImg
            }
        
        }
    

    图片合成问题补充

    1.  合成图片:由于上传确认页面的图片可以点击进去编辑图片,或者添加图片,如果这里每添加一张图片或者合成一张图片的话,会相当的耗费性能,所以合成图片的操作放在点击上传按钮那里
    点击上传调用合成图片方法,合成图片方法主要分两步,实现思路如下:
    (1)创建一个contentView用来装多个ImageView,根据图片数组的数量for循环来添加imageview,imageview设置图片的时候先对图片进行数据压缩处理,然后再对尺寸进行压缩处理,下面是压缩处理规则:
    if imagedata.count <  0.8M   {  
    不压缩
    } else if imagedata.count >  0.8M && imagedata.count <1M {  
    压缩系数0.8获取图像
    } else if imagedata.count >  1M && imagedata.count <2M {  
    压缩系数0.3获取图像
    } else {
    压缩系数0.1获取图像
    }
    
    压缩完数据以后再进行尺寸压缩
    if 图片宽度>两倍屏幕宽 || 图片高度>两倍屏幕高 {
     图片大小缩放系数0.5处理
    }
    缩放之后设置到imageView上
    (2)通过for循环来获取contentView上的imageView上的图片,根据已经处理好的image来设置imageview的frame,排好版面到contentView上,最后就是将contentView转化成image,并且赋值给合成图片变量composeImage
    以上两个for循环中的内容置于autoreleasepool中
    整个上传流程
    点击上传 ->进入合成图片方法,显示正在加载的圈圈,延时1.5秒进入上传方法 -> 二分法压缩图片数据到1M以内,图片大于3张延时3秒,否则2秒,延时之后执行隐藏压缩圈圈方法,发起正式上传网络请求 -> 上传成功之后,图片变量置为nil,移除图片数组元素,返回上一级,查看deinit打印执行
    
    
    测试与分析
    6测试---这里还是之前的合成图片后,再对合成图片压缩尺寸
    如果一进入上传页面页面显示且绘制合成图片51 -> 61  大概增加10M到150M
    五张合成后再缩放图片:大概增加100 到150M
    单独测试压缩方法  增加大概100M
    单独测试压缩方法加上传 增加大概110M
    缩放图片尺寸加压缩 测试大概增加150M
    缩放 压缩  上传一气呵成大概也是增加150M左右
    综上最耗内存的两个方法 一个是缩放尺寸(会进行绘制)   一个是压缩
    大小手机测试:
    5s 上传7+拍的5张照片 整个上传过程 最高出现增加350M
    5s 上传自己拍的5张  最高出现增加240M   
    
    分析:
    1.在几个for循环里面加个自动释放池感觉没有缓解什么,几M的区别
    2.缩放的的图片被压缩成data后,马上置为nil 整个上传过程增加100-130  所以这里有一定的作用
    3.  有的图片的长宽高达屏幕的5,6倍,所以在合成之前,我们可以把每一张图片缩放一半,后面整张合成的图片将不再进行缩放,经测试这样合成图片,再去上传图片,我用5s上传7+拍的图片大概增加120M,相比以前的240,350节约一大半的内存,可以有效防止内存不足闪退。
    
    

    总结:经过以上的方法处理,图片的质量和内存有了很大的改善,值得注意的是,我们在处理图片的时候,一定要注意测试内存,如果内存没有释放,将随着拍摄次数的增多,内存逐渐增大,最后的结果就是崩溃,可能客户跟你反馈,你还会一脸懵逼,当然知道这个问题就好办了,这种情况一般是图片没有释放,或者代码里有循环引用所致,解决好就可以了。

    相关文章

      网友评论

        本文标题:Swift图片压缩处理

        本文链接:https://www.haomeiwen.com/subject/lolrbxtx.html