Swift中compressionQuality与调整图片宽高的区别及单操作影响
图片压缩:调整尺寸 vs 降低JPEG压缩质量的原理与效果分析
这个问题问得很到位!咱们来拆解这两种图片压缩方式的核心原理、单独使用时的实际效果,再结合你给出的Swift代码看看具体的实现逻辑。
一、两种压缩方式的核心原理
1. 调整图片宽高(尺寸压缩)
这种方式的本质是减少图片的总像素数量:通过重新绘制图片到更小的画布上,用系统内置的插值算法(比如双线性插值)计算出新尺寸下的像素值,直接降低图片的分辨率。
举个例子:一张4000×3000的原图(1200万像素),缩放到1000×750后,像素总数降到75万,相当于直接丢弃了93.75%的原始像素信息。
2. 降低compressionQuality(JPEG质量压缩)
JPEG是一种有损压缩格式,compressionQuality参数控制的是有损压缩的强度:它不会改变图片的宽高和像素总数,而是通过合并相似颜色、丢弃高频细节(比如纹理的细微变化、边缘的噪点)来减少文件体积。
压缩质量越高,保留的细节越多;质量越低,丢弃的细节越多,文件体积也越小。
二、单独使用每种方式的效果
仅调整图片宽高(不修改compressionQuality)
- 优势:文件体积下降幅度非常明显(和像素数减少的比例大致成正比),只要缩放算法合理,视觉上不会出现JPEG特有的“压缩失真”(比如色块、模糊边缘),适合需要严格控制图片分辨率的场景(比如适配移动端屏幕、限制上传图片的最大尺寸)。
- 劣势:如果缩放过小,会导致图片的精细细节丢失(比如小文字、复杂纹理变得模糊),而且像素一旦被丢弃,无法恢复原始的高清细节。
- 体积变化:相同压缩质量下,图片体积和像素总数大致呈线性关系——比如像素数降到原来的1/4,体积也会降到原来的约1/4。
仅降低compressionQuality(不调整尺寸)
- 优势:完全保留原始图片的宽高和像素总数,适合需要保留高清分辨率但要减小文件体积的场景(比如需要打印或后期编辑的图片)。
- 劣势:当压缩质量过低时,会出现明显的JPEG压缩伪影(比如大面积色块、边缘模糊、色彩断层),视觉体验大幅下降;而且体积下降有上限,即使把质量调到0,也无法无限缩小(因为要保留基本的颜色框架信息)。
- 体积变化:体积和压缩质量大致正相关,但不是线性的——比如从1.0降到0.75,体积可能下降30%左右;但从0.25降到0,体积的下降幅度会非常小。
三、你的代码中两种方式的结合逻辑
你的compressImage()方法采用了先尺寸压缩、再质量压缩的组合策略,逻辑非常贴合移动端图片上传的需求:
- 先判断原图是否超过预设的最大尺寸(1136×640),如果超过则按比例缩放到限制范围内,保证图片尺寸不会过大;
- 根据是否进行了尺寸压缩,调整
compressionQuality:超过尺寸时用high(0.75),未超过则用highest(1.0); - 最后将缩放后的图片转换为JPEG数据,返回压缩后的
UIImage。
这种组合方式既控制了图片的分辨率(避免超大图占用过多带宽),又通过质量压缩进一步减小了文件体积,同时尽量保证了视觉效果,是非常实用的移动端图片上传压缩方案。
func compressImage() -> UIImage? { enum JPEGQuality: CGFloat { case lowest = 0 case low = 0.25 case medium = 0.5 case high = 0.75 case highest = 1 } // Reducing file size to a 10th var actualHeight: CGFloat = self.size.height var actualWidth: CGFloat = self.size.width print("DEBUG: actualHeight \(actualHeight)") print("DEBUG: actualWidth \(actualWidth)") //For iphone 5s let maxHeight: CGFloat = 1136.0 let maxWidth: CGFloat = 640.0 var imgRatio: CGFloat = actualWidth/actualHeight let maxRatio: CGFloat = maxWidth/maxHeight var compressionQuality: CGFloat = JPEGQuality.highest.rawValue if actualHeight > maxHeight || actualWidth > maxWidth { compressionQuality = JPEGQuality.high.rawValue if imgRatio < maxRatio { //adjust width according to maxHeight imgRatio = maxHeight / actualHeight actualWidth = imgRatio * actualWidth actualHeight = maxHeight print("DEBUG: actualHeight after compression \(actualHeight)") print("DEBUG: actualWidth after compression \(actualWidth)") } else if imgRatio > maxRatio { //adjust height according to maxWidth imgRatio = maxWidth / actualWidth actualHeight = imgRatio * actualHeight actualWidth = maxWidth print("DEBUG: actualHeight after compression \(actualHeight)") print("DEBUG: actualWidth after compression \(actualWidth)") } else { actualHeight = maxHeight actualWidth = maxWidth compressionQuality = JPEGQuality.highest.rawValue print("DEBUG: actualHeight after compression \(actualHeight)") print("DEBUG: actualWidth after compression \(actualWidth)") } } let rect = CGRect(x: 0.0, y: 0.0, width: actualWidth, height: actualHeight) UIGraphicsBeginImageContext(rect.size) self.draw(in: rect) guard let img = UIGraphicsGetImageFromCurrentImageContext() else { return nil } UIGraphicsEndImageContext() guard let imageData = img.jpegData(compressionQuality: compressionQuality) else { return nil } print("DEBUG: IMAGE DATA IS \(imageData)") return UIImage(data: imageData) }
内容的提问来源于stack exchange,提问作者Ios Developer
相关产品推荐
相关产品推荐

