iOS

来源:互联网 发布:淘宝宠物店铺介绍 编辑:程序博客网 时间:2024/06/05 17:12

不论做什么项目,基本都会遇到上传图片的问题,比如:修改用户头像,或者类似于微信朋友圈发布说说。如果不对图片进行压缩,图片太大,那么用户等待时间过长,严重影响用户的体验,而且造成用户流量浪费。

图片压缩的概念
1:压” 是指文件体积变小,但是像素数不变,长宽尺寸不变,那么质量可能下降。
2:缩” 是指文件的尺寸变小,也就是像素数减少,而长宽尺寸变小,文件体积同样会减小。

图片压的处理
对于“压”的功能,我们可以使用如下两个方法:

public func UIImagePNGRepresentation(_ image: UIImage) -> Data? // return image as PNG. May return nil if image has no CGImageRef or invalid bitmap formatpublic func UIImageJPEGRepresentation(_ image: UIImage, _ compressionQuality: CGFloat) -> Data? // return image as JPEG. May return nil if image has no CGImageRef or invalid bitmap format. compression is 0(most)..1(least)

下面看一个测试例子,从本地相册库获取图片,然后压缩图片对比压缩之后的数据情况

   func presentation(_ image: UIImage) {        guard let pngData = UIImagePNGRepresentation(image)  else {            return        }        print("\(pngData.count / 1024)kb") //10964kb                //图片的引用和压缩系数        guard let jpgData = UIImageJPEGRepresentation(image, 1.0)  else {            return        }        print("\(jpgData.count / 1024)kb") //6427kb                guard let data1 = UIImageJPEGRepresentation(image, 0.5)  else {            return        }        print("\(data1.count / 1024)kb") //1025kb                        guard let data2 = UIImageJPEGRepresentation(image, 0.3)  else {            return        }        print("\(data2.count / 1024)kb") //569kb                        guard let data3 = UIImageJPEGRepresentation(image, 0.1)  else {            return        }        print("\(data3.count / 1024)kb") //389kb    }

可以看到,同样的一张照片, 使用UIImagePNGRepresentation(image)返回的数据量大小为10964kb,使用UIImageJPEGRepresentation(image, 1.0)返回的数据量大小只有6427kb,比前者少了非常多。所以如果对图片的清晰度要求不是极高,建议使用UIImageJPEGRepresentation,可以大幅度降低图片数据量.而且实际开发过程中经常使用UIImageJPEGRepresentation来进行压缩文件大小。可根据自己的实际使用场景,设置压缩系数,进一步降低图片数据量大小。

常用压缩文件大小的方法:

 /// 压到指定大小    ///    /// - Parameters:    ///   - image: 图片    ///   - fileSize: 指定文件大小    /// - Returns: 压缩后的图片    func compressImage(_ image: UIImage, fileSize: Int) -> UIImage {        let minCompression: CGFloat = 0.3        var compression: CGFloat = 1.0        var imageData = Data()        guard let data = UIImageJPEGRepresentation(image, compression) else {            return image        }        imageData = data        while ((imageData.count > fileSize) && (compression > minCompression)) {            compression -= 0.1            guard let data = UIImageJPEGRepresentation(image, compression) else {                return UIImage(data: imageData)!            }            imageData = data        }        return UIImage(data: imageData)!    }

还可以为UIImage进行extension,方便简单使用,原文内容

extension UIImage {    enum JPEGQuality: CGFloat {        case lowest  = 0        case low     = 0.25        case medium  = 0.5        case high    = 0.75        case highest = 1    }        /// Returns the data for the specified image in PNG format    /// If the image object’s underlying image data has been purged, calling this function forces that data to be reloaded into memory.    /// - returns: A data object containing the PNG data, or nil if there was a problem generating the data. This function may return nil if the image has no data or if the underlying CGImageRef contains data in an unsupported bitmap format.    var png: Data? { return UIImagePNGRepresentation(self) }        /// Returns the data for the specified image in JPEG format.    /// If the image object’s underlying image data has been purged, calling this function forces that data to be reloaded into memory.    /// - returns: A data object containing the JPEG data, or nil if there was a problem generating the data. This function may return nil if the image has no data or if the underlying CGImageRef contains data in an unsupported bitmap format.    func jpeg(_ quality: JPEGQuality) -> Data? {        return UIImageJPEGRepresentation(self, quality.rawValue)    }}

图片缩的处理


对于图片的缩,我们经常是指定图片的大小进行绘制图片。下面提供一些常用方法:

等比缩放功能,设置图片的缩放比

 func equalScaleImage(_ image: UIImage, _ scaleSize: CGFloat) -> UIImage {        let targetWidth = image.size.width * scaleSize        let targetHeight = image.size.height * scaleSize        UIGraphicsBeginImageContext(CGSize(width: targetWidth , height: targetHeight))        image.draw(in: CGRect(x: 0, y: 0, width: targetWidth, height: targetHeight))        let scaledImage = UIGraphicsGetImageFromCurrentImageContext()        UIGraphicsEndImageContext()        return scaledImage!    }

直接缩放图片

 func scaleTo(image: UIImage, _ newSize: CGSize) -> UIImage {        UIGraphicsBeginImageContextWithOptions(newSize, false, 0.0)        image.draw(in: CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height))        let newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()!        UIGraphicsEndImageContext()        return newImage    }

也看到了某些博主写了关于微信的图片转换规则,有兴趣的可以看看。如果上传图片之前需要固定图片的方向,可以看这里。


但是目前都只是单方面的对图片进行操作,有时候是能够满足我们的需求,如果既要压缩文件大小,也要压缩尺寸呢?那么就把两者结合起来处理,先缩小图片尺寸,然后压缩图片质量,下面是借用安卓中鲁班算法中计算图片缩放比的内容所做的图片缩放功能,对于安卓的鲁班算法,可以看这里,这边也有对应的iOS版本。 

private func computeSacle(_ image: UIImage) -> Int {    var srcWidth = image.size.width    var srcHeight = image.size.height    srcWidth =  srcWidth.truncatingRemainder(dividingBy: 2) == 1 ? srcWidth + 1 : srcWidth    srcHeight = srcHeight.truncatingRemainder(dividingBy: 2) == 1 ? srcHeight + 1 : srcHeight        let longSide = max(srcWidth, srcHeight)    let shortSide = min(srcWidth, srcHeight)        let scale = shortSide / longSide    if (scale <= 1 && scale > 0.5625) {        if longSide < 1664 {            return 1        } else if (longSide >= 1664 && longSide < 4990) {            return 2        } else if longSide > 4990 && longSide < 10240 {            return 4        } else {            return ((longSide / 1280) == 0) ? 1 : Int(longSide / 1280)        }    } else if (scale <= 0.5625 && scale > 0.5) {        return longSide / 1280 == 0 ? 1 : Int(longSide / 1280)    } else {        return  Int(longSide / (1280.0 / scale))    }}/// 压缩图片////// - Parameter image: 原图/// - Returns: 压缩后的图片func compressImage(_ image: UIImage, _ imageFileSize: Int) -> UIImage {    let resizeImage = resizeImagesize(image, CGFloat(computeSacle(image)))    return compressImageQuality(resizeImage, fileSize: imageFileSize)}private func resizeImagesize(_ image: UIImage, _ scaleSize: CGFloat) -> UIImage {    let targetWidth = image.size.width * (1 / scaleSize)    let targetHeight = image.size.height *  (1 / scaleSize)    UIGraphicsBeginImageContext(CGSize(width: targetWidth , height: targetHeight))    image.draw(in: CGRect(x: 0, y: 0, width: targetWidth, height: targetHeight))    let scaledImage = UIGraphicsGetImageFromCurrentImageContext()    UIGraphicsEndImageContext()    return scaledImage!}private func compressImageQuality(_ image: UIImage, fileSize: Int) -> UIImage {    var compression: CGFloat = 1.0    var imageData = Data()    guard let data = UIImageJPEGRepresentation(image, compression) else {        return image    }    imageData = data    while (imageData.count > fileSize && compression > 0.06 ) {        compression -= 0.06        guard let imgData = UIImageJPEGRepresentation(image, compression) else {            return UIImage(data: imageData)!        }        if imageData == imgData {            return UIImage(data: imageData)!        }        imageData = imgData    }    return UIImage(data: imageData)!}
上面代码很简单,只需要传入要压缩的图片,和文件大小,即可压缩。但是这里要注意一点,使用UIImageJPEGRepresentation(image,0.5)对于每张图片进行压缩,其实有一个最小值,此后无论再怎么改小压缩系数都无济于事。这个情况自己确实遇到了,所以在不能够再压缩的情况下直接返回当前大小的图片。而且第二个参数是压缩系数,它的设置并不能保证图片的大小,因为压缩之后的大小和图片的内容也有关系,比如你的图片的的颜色相似的话压缩之后图片的大小就会小点。

推荐文章

Image Resizing Techniques




原创粉丝点击