在这篇文章中提到了
使用 UIImage 的时候,创建的图片通常不会直接加载到内存,而是在渲染的时候再进行解压并加载到内存。这就会导致 UIImage 在渲染的时候效率上不是那么高效。
为了提高效率通过 decodedImageWithImage 方法把图片提前解压加载到内存,这样这张新图片就不再需要重复解压了,提高了渲染效率。这是一种空间换时间的做法。
在渲染的时候,把图层按像素叠加, 并且会对每一个像素进行 RGBA 的叠加计算。当某个 layer 的是不透明的,GPU 可以直接忽略掉其下方的图层,这就减少了很多工作量。这也是调用 CGBitmapContextCreate 时 bitmapInfo 参数设置为忽略掉 alpha 通道的原因。
/**
对传入的图片进行解码
@param image 传入的image
@return 解码后的image
*/
+ (nullable UIImage *)decodedImageWithImage:(nullable UIImage *)image {
if (![UIImage shouldDecodeImage:image]) {
return image;
}
// autorelease the bitmap context and all vars to help system to free memory when there are memory warning.
// on iOS7, do not forget to call [[SDImageCache sharedImageCache] clearMemory];
@autoreleasepool{
CGImageRef imageRef = image.CGImage;
CGColorSpaceRef colorspaceRef = [UIImage colorSpaceForImageRef:imageRef];
size_t width = CGImageGetWidth(imageRef);
size_t height = CGImageGetHeight(imageRef);
// 一个像素4字节
size_t bytesPerRow = kBytesPerPixel * width;
// CGBitmapContextCreate不支持kCGImageAlphaNone
// 当原图片没有alpha通道的时候使用kCGImageAlphaNoneSkipLast
// 创建不包含alpha通道的bitmap上下文
CGContextRef context = CGBitmapContextCreate(NULL,
width,
height,
kBitsPerComponent,
bytesPerRow,
colorspaceRef,
kCGBitmapByteOrderDefault|kCGImageAlphaNoneSkipLast);
if (context == NULL) {
return image;
}
// 将图片转换为上下文并且转换为不包含alpha通道的bitmap 图片
CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
CGImageRef imageRefWithoutAlpha = CGBitmapContextCreateImage(context);
UIImage *imageWithoutAlpha = [UIImage imageWithCGImage:imageRefWithoutAlpha
scale:image.scale
orientation:image.imageOrientation];
CGContextRelease(context);
CGImageRelease(imageRefWithoutAlpha);
return imageWithoutAlpha;
}
}
/**
判断是否需要解码
@param image 传入的图片
@return 判断是否需要解码
*/
+ (BOOL)shouldDecodeImage:(nullable UIImage *)image {
// Prevent "CGBitmapContextCreateImage: invalid context 0x0" error
if (image == nil) {
return NO;
}
// 不去解码images
if (image.images != nil) {
return NO;
}
CGImageRef imageRef = image.CGImage;
// 获取alpha通道
CGImageAlphaInfo alpha = CGImageGetAlphaInfo(imageRef);
BOOL anyAlpha = (alpha == kCGImageAlphaFirst ||
alpha == kCGImageAlphaLast ||
alpha == kCGImageAlphaPremultipliedFirst ||
alpha == kCGImageAlphaPremultipliedLast);
// do not decode images with alpha
// 存在alpha 不去解码
if (anyAlpha) {
return NO;
}
return YES;
}