Swift图片压缩处理

由于项目中有大量的上传图片,之前图片的处理方式直接就用了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节约一大半的内存,可以有效防止内存不足闪退。

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,402评论 6 499
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,377评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,483评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,165评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,176评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,146评论 1 297
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,032评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,896评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,311评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,536评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,696评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,413评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,008评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,659评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,815评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,698评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,592评论 2 353

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 172,072评论 25 707
  • 1、确图片的压缩的概念: “压” 是指文件体积变小,但是像素数不变,长宽尺寸不变,那么质量可能下降。“缩” 是指文...
    HOULI阅读 18,924评论 7 34
  • iOS图片压缩,想必这是一个比较大切值得深入的一个研究。所以太深入的这里我也不会去讲,之所以写这篇,是因为我们在开...
    淇水朱华阅读 14,976评论 24 46
  • 首先,我们必须明确图片的压缩其实是两个概念: “压” 是指文件体积变小,但是像素数不变,长宽尺寸不变,那么质量可能...
    李sir35阅读 11,617评论 1 17
  • 有多久,没有打开键盘去敲打一些文字与心情? 有多久,任由自己很多时候的情绪就那样流逝,回首已怅然。 人生,总是在这...
    夏知了阅读 149评论 0 0