iOS图片压缩
一般图片压缩的需求
- 压缩到指定宽高(例如:微信图片压缩,宽或者高不超过 1280 )
- 压缩到指定大小(例如:微信小程序分享,图片不超过 32kb)
常规的图片压缩方法
一、质量压缩
UIImageJPEGRepresentation(image, compression);
这是苹果爸爸提供的质量压缩API:第一个参数是 目标image,第二个参数 compression 取值 0.0 ~ 1.0,理论上值越小表示图片质量越低,图片文件自然越小。
但这里有个注意点,并不是 compression 取 0,就是0b大小,取 1 就是原图:
a.首先:图片的大小是根据(图片的宽 * 图片的高 * 每一个色彩的深度)来获取的,
图片只会按照你的手机像素的分辨率 [UIScreen mainScreen].scale 来读取值。
b.其次:对于大图片来说,即使你的 compression 选的很小很小,
比如:0.0000000(n个0)001,无论多小都没有用,因为达到
一定阈值之后,就再也压不下去了,但是得到的结果还是很大,
DEMO中例子:一张13M左右的图片,处理后极限大小为551kb左右。
循环压缩的方法:
+ (UIImage *)compressImageQualityNormal:(UIImage *)image toByte:(NSInteger)maxLength
{
CGFloat compression = 1;
NSUInteger count = 0;
NSData *data = UIImageJPEGRepresentation(image, compression);
while (data.length > maxLength && compression > 0) {
compression -= 0.01;
count++;
// 当压缩到某个阈值的时候,这句代码就没有效果了
data = UIImageJPEGRepresentation(image, compression);
NSLog(@"%@", [NSString stringWithFormat:@"压缩次数:%zd,压缩比例:%f,压缩后的图片大小:%f kb", count, compression, data.length / 1000.0]);
}
UIImage *resultImage = [UIImage imageWithData:data];
return resultImage;
}
以下是压缩数据:
图片的原始大小:13362 kb
压缩次数 | 压缩比例 | 压缩后的图片大小 |
---|---|---|
1 | 0.990000 | 5984.280000 kb |
2 | 0.980000 | 5818.233000 kb |
3 | 0.970000 | 5663.514000 kb |
… | … | … |
37 | 0.630000 | 2726.441000 kb |
38 | 0.620000 | 2659.856000 kb |
39 | 0.610000 | 2594.750000 kb |
… | … | … |
67 | 0.330000 | 925.446000 kb |
68 | 0.320000 | 886.675000 kb |
69 | 0.310000 | 867.404000 kb |
… | … | … |
90 | 0.100000 | 562.138000 kb |
91 | 0.090000 | 561.355000 kb |
92 | 0.080000 | 553.827000 kb |
93 | 0.070000 | 553.236000 kb |
94 | 0.060000 | 551.402000 kb |
95 | 0.050000 | 551.402000 kb |
96 | 0.040000 | 551.402000 kb |
97 | 0.030000 | 551.402000 kb |
98 | 0.020000 | 551.402000 kb |
99 | 0.010000 | 551.402000 kb |
100 | -0.000000 | 551.402000 kb |
换句话来说,如果要实现压缩到指定大小(比如 32k),如果是小图倒是不会有什么问题,多试几次应该能得到想要的结果,如果大图(比如 13M)只用压缩质量的方式,是办不到的,达到一定阈值之后(压缩比例:小于0.060000),就再也压不下去了。
当然,这个方法是有问题的,总共压缩了 100 次,循环次数过多,效率低,耗时长。
如果你得到的图片压缩的需求,是保证尺寸不变的情况下,尽可能压到最小,自然只需要循环压缩就好,不过有更好的实现方式,那就是 二分法。
+ (UIImage *)compressImageQualityDichotomy:(UIImage *)image toByte:(NSInteger)maxLength
{
CGFloat compression = 1;
NSData *data = UIImageJPEGRepresentation(image, compression);
if (data.length < maxLength) return image;
CGFloat max = 1;
CGFloat min = 0;
// 二分最大10次,区间范围精度最大可达0.00097657;第6次,精度可达0.015625,10次,0.000977
for (int i = 0; i < 10; ++i) {
compression = (max + min) / 2;
NSLog(@"%@", [NSString stringWithFormat:@"压缩精度:%f", compression]);
data = UIImageJPEGRepresentation(image, compression);
if (data.length < maxLength * 0.9) {
min = compression;
} else if (data.length > maxLength) {
max = compression;
} else {
break;
}
}
UIImage *resultImage = [UIImage imageWithData:data];
return resultImage;
}
二分最大10次即可,既可以达到压缩到阈值
的效果,又能节约性能,区间范围精度最大可达0.00097657
;第6次,精度可达0.015625
,10次,0.000977
使用二分法进行处理,比for循环依次递减**“高效”很多,而且也合理**很多,第10次就达到了单纯的for循环的99次的效果。
次数 | 压缩比例 |
---|---|
1 | 0.500000 |
2 | 0.250000 |
3 | 0.125000 |
4 | 0.062500 |
5 |