张东轩的博客

合抱之木,生于毫末;九层之台,起于累土;千里之行,始于足下。

0%

iOS 图片压缩

最近在解决Share Extension发送大图导致爆内存的问题,测试用27M的图片,用的是iPhone 7P,系统分配给Share Extension的内存应该有100M,一步步debug发现问题出在压缩的过程。

问题

在缩小图片的时候用了下面的代码:

1
2
3
4
5
6
7
UIGraphicsBeginImageContext(imgSize);

[self drawInRect:CGRectMake(0, 0, imgSize.width, imgSize.height)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();

UIGraphicsEndImageContext();
return newImage;

运行到drawInRect的时候程序直接退出了,可见drawInRect是比较吃内存的。
于是在网上搜索关键字uiimage drawinrect memory warning,但是貌似都是关于memory not release的帖子,解决方法是添加autoreleasepool,
很显然无法解决爆内存的问题。

解决方法

后来同事推荐使用ImageIO来解决这个问题:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
CGFloat maxPixelSize = 100;
CGImageSourceRef sourceRef = CGImageSourceCreateWithData((__bridge CFDataRef)data, nil);

CFDictionaryRef options = (__bridge CFDictionaryRef) @{
(id) kCGImageSourceCreateThumbnailWithTransform : @YES,
(id) kCGImageSourceCreateThumbnailFromImageAlways : @YES,
(id) kCGImageSourceThumbnailMaxPixelSize : @(maxPixelSize)
};

UIImage *result = nil;
CGImageRef imageRef = CGImageSourceCreateThumbnailAtIndex(sourceRef, 0, options);

if (imageRef) {
result = [UIImage imageWithCGImage:imageRef scale:scale orientation:orientation];
CGImageRelease(imageRef);
}

if (sourceRef) {
CFRelease(sourceRef);
}

return result;

使用改代码对测试用的27M的图片进行压缩,内存在执行CGImageSourceCreateThumbnailAtIndex的时候只上升了20M。

如下是对一个9.2M的图片进行压缩的内存变化图

图中1是将图片读入内存导致的内存增加,在使用ImageIO进行压缩的过程中内存没有出现明显的变化,2是使用drawInRect进行压缩,可见内存飙升到了38.8。

参考:
[Resizing High Resolution Images on iOS Without Memory Issues][1]
[UIImage vs. CIImage vs. CGImage][2]
[1]:http://pulkitgoyal.in/resizing-high-resolution-images-on-ios-without-memory-issues/
[2]:https://medium.com/@ranleung/uiimage-vs-ciimage-vs-cgimage-3db9d8b83d94