图片尺寸变换在App里常用的一个功能,特别是对于图片处理较为频繁的项目,所以对图片处理常用的几个方式进行了性能测试,找到空间和时间最优的方式来处理图片尺寸问题;
我们测试使用的是XCTest进行的,主要测量的指标是时间和空间,即耗时及内存;
图片压缩方式一:
func normalizedImageScale(toMaxLength maxLength:CGFloat) -> UIImage {
let realSize = CGSize.init(width: Int(size.width * scale), height: Int(size.height * scale))
let fMaxLength = CGFloat(maxLength)
var targetSize : CGSize
if realSize.width < fMaxLength && realSize.height < fMaxLength {
targetSize = size
} else{
if realSize.width > realSize.height {
targetSize = CGSize.init(width: Int(maxLength), height: Int(realSize.height / (realSize.width / maxLength)))
} else{
targetSize = CGSize.init(width: Int(realSize.width / (realSize.height / maxLength)), height: Int(maxLength))
}
}
UIGraphicsBeginImageContext(targetSize)
draw(in: CGRect.init(origin: .zero, size:targetSize))
let normalizedImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return normalizedImage ?? UIImage()
}
图片压缩方式二:
func resizeImage(with image: UIImage, targetSize: CGSize) -> UIImage {
let render = UIGraphicsImageRenderer(bounds: CGRect(origin: .zero, size: targetSize))
let result = render.image { (context) in
image.draw(in: CGRect(origin: .zero, size: CGSize(width: 480, height: 640)))
}
return result
}
图片压缩方式三:
#import "UIImage+Resize.h"
- (UIImage *)resizedImage:(CGSize)newSize interpolationQuality:(CGInterpolationQuality)quality {
BOOL drawTransposed;
switch ( self.imageOrientation )
{
case UIImageOrientationLeft:
case UIImageOrientationLeftMirrored:
case UIImageOrientationRight:
case UIImageOrientationRightMirrored:
drawTransposed = YES;
break;
default:
drawTransposed = NO;
}
CGAffineTransform transform = [self transformForOrientation:newSize];
CGFloat scale = MAX(1.0f, self.scale);
CGRect newRect = CGRectIntegral(CGRectMake(0, 0, newSize.width*scale, newSize.height*scale));
CGRect transposedRect = CGRectMake(0, 0, newRect.size.height, newRect.size.width);
CGImageRef imageRef = self.CGImage;
// Fix for a colorspace / transparency issue that affects some types of
// images. See here: http://vocaro.com/trevor/blog/2009/10/12/resize-a-uiimage-the-right-way/comment-page-2/#comment-39951
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef bitmap = CGBitmapContextCreate(
NULL,
newRect.size.width,
newRect.size.height,
8, /* bits per channel */
(newRect.size.width * 4), /* 4 channels per pixel * numPixels/row */
colorSpace,
kCGImageAlphaPremultipliedLast
);
CGColorSpaceRelease(colorSpace);
// Rotate and/or flip the image if required by its orientation
CGContextConcatCTM(bitmap, transform);
// Set the quality level to use when rescaling
CGContextSetInterpolationQuality(bitmap, quality);
// Draw into the context; this scales the image
CGContextDrawImage(bitmap, drawTransposed ? transposedRect : newRect, imageRef);
// Get the resized image from the context and a UIImage
CGImageRef newImageRef = CGBitmapContextCreateImage(bitmap);
UIImage *newImage = [UIImage imageWithCGImage:newImageRef scale:self.scale orientation:UIImageOrientationUp];
// Clean up
CGContextRelease(bitmap);
CGImageRelease(newImageRef);
return newImage;
}
测试一张图片(2400*3200, 1.5M),压缩100次平均值:
| 方案 | 时间 | 内存 |
|---|---|---|
| 方案一 | 23.3ms | 13.8k |
| 方案二 | 46.2ms | 10.7k |
| 方案三 | 19.2ms | 9.42k |
测试100张图片,压缩5次平均值:
| 方案 | 时间 | 内存 |
|---|---|---|
| 方案一 | 2.86s | 573k |
| 方案二 | 5.38s | 362k |
| 方案三 | 2.44s | 593k |
由上述测试结果可知:
在处理图片数量较少时,方案三略优于方案一,都优于方案二;当处理图片较多时,方案二的内存占用更低,但是耗时大概是另外两种方案2倍。
注:以上测试都跑在iPhone11模拟器上。
除此之外,还有其他图片压缩方案,这里不再列举,可参考文章: Image Resizing Techniques