UIImage在分配到UIImageView或者UIButton中的时候,系统会自动进行解码,因为缓冲区将图片渲染到屏幕前就需要进行解码,也就是转成位图数据然后显示,例如:
1,imageView.image = xxx;
2,[button setImage:[UIImage imageNamed:@”xxx”] forState:0];
系统进行解码是在主线程进行操作的,解码操作比较耗时,而且需要手动进行解码压缩成位图。
//解码且压缩
- (nullable UIImage *)decodedImageWithImage:(nullable UIImage *)image {
if (image == nil) {
return image;
}
// autorelease 防止内存某一时刻过高,以及内存警告时释放内存
@autoreleasepool{
CGImageRef imageRef = image.CGImage;
//颜色空间
CGColorSpaceRef colorspaceRef = CGColorSpaceCreateDeviceRGB();
size_t width = CGImageGetWidth(imageRef);
size_t height = CGImageGetHeight(imageRef);
//计算出每行行的像素数
size_t bytesPerRow = 4 * width;
// kCGImageAlphaNone is not supported in CGBitmapContextCreate.这里创建的contexts是没有透明因素的(位图图形上下文),为了防止渲染控件的时候直接忽略掉其下方的图层
CGContextRef context = CGBitmapContextCreate(NULL,width,height,8,bytesPerRow,colorspaceRef,kCGBitmapByteOrderDefault|kCGImageAlphaNoneSkipLast);
if (context == NULL) {
CGColorSpaceRelease(colorspaceRef);
return image;
}
// Draw the image into the context and retrieve the new bitmap image without alpha
CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
CGImageRef imageRefWithoutAlpha = CGBitmapContextCreateImage(context);
//image.imageOrientation由于使用CoreGraphics绘制图片的Y坐标和UIKit的Y坐标相反,这时要要把图片正古来
UIImage *imageWithoutAlpha = [UIImage imageWithCGImage:imageRefWithoutAlpha scale:image.scale orientation:image.imageOrientation];
CGColorSpaceRelease(colorspaceRef);
CGContextRelease(context);
CGImageRelease(imageRefWithoutAlpha);
return imageWithoutAlpha;
}
}
//分配到异步线程去执行
- (void)settingImageWithSourceImg:(UIImage *)img complate:(void(^)(UIImage *pImg))complate
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
UIImage *cImg = [self decodedImageWithImage:img];
dispatch_async(dispatch_get_main_queue(), ^{
if(complate) complate(cImg);
});
});
}
//demo
UIImage *sourceImg = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"IMG_0017" ofType:@"JPG"]];
UIImageView *imgv = [[UIImageView alloc]initWithFrame:CGRectMake(50, 100, 80, 80)];
imgv.backgroundColor = [UIColor redColor];
[self.view addSubview:imgv];
[self settingImageWithSourceImg:sourceImg complate:^(UIImage *pImg) {
imgv.image = pImg;
}];
如果直接给ImageView分配image,那么它的内存为:

如果手动压缩:

测试了一下, 效率快了百分之20左右,可以封装成一个类别,扩展到image里边,遇到本地大图可以进行调用,但是像素比较小的就没必要了,因为内存的大小为:
width*scale*height*scale/tkBytesPerPixel
scale为图像缩放比例,tkBytesPerPixel为RGBA的值,如果不修改图片的色值和透明度,那么RGBA为4。
扩展:
//
// UIImage+Decode.h
//
//
// Created by xxxxx on 2020/11/13.
//
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
typedef NS_ENUM(NSInteger , IMAGE_GET_TYPE)
{
NamedGetType= 1,
ResourceGetType,
};
@interface UIImage (Decode)
+ (void)decodeImageWithNamed:(NSString *)named complated:(void(^)(UIImage * outImage))complated;
+ (void)decodeImageWithResource:(NSString *)resource ofType:(NSString *)type complated:(void(^)(UIImage * outImage))complated;
@end
@interface NSImageName : NSObject
@property (nonatomic,assign)IMAGE_GET_TYPE getType;
@property (nonatomic,copy)NSString *named;
@property (nonatomic,copy)NSString *suffix;
@end
NS_ASSUME_NONNULL_END
//
// UIImage+Decode.m
//
//
// Created by xxxxx on 2020/11/13.
//
#import "UIImage+Decode.h"
@implementation UIImage (Decode)
+ (void)decodeImageWithNamed:(NSString *)named complated:(void(^)(UIImage * outImage))complated
{
NSImageName *nameObj = [NSImageName new];
nameObj.named = named;
nameObj.getType = NamedGetType;
[self asyncDrawImageWithGetNamedObj:nameObj drawComplated:complated];
}
+ (void)decodeImageWithResource:(NSString *)resource ofType:(NSString *)type complated:(void(^)(UIImage * outImage))complated
{
NSImageName *nameObj = [NSImageName new];
nameObj.named = resource;
nameObj.suffix = type;
nameObj.getType = ResourceGetType;
[self asyncDrawImageWithGetNamedObj:nameObj drawComplated:complated];
}
+ (void)asyncDrawImageWithGetNamedObj:(NSImageName *)nameObj drawComplated:(void(^)(UIImage *cImage))drawComplated
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
UIImage *sourceImage = [UIImage imageNamed:nameObj.named];
switch (nameObj.getType) {
case ResourceGetType:
sourceImage = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:nameObj.named ofType:nameObj.suffix]];
break;
//....other
default:
break;
}
UIImage *cImg = [self decodedImageWithImage:sourceImage];
dispatch_async(dispatch_get_main_queue(), ^{
if(drawComplated) drawComplated(cImg);
});
});
}
+ (nullable UIImage *)decodedImageWithImage:(nullable UIImage *)image {
if (image == nil) {
return image;
}
// autorelease 防止内存某一时刻过高,以及内存警告时释放内存
@autoreleasepool{
CGImageRef imageRef = image.CGImage;
//颜色空间
CGColorSpaceRef colorspaceRef = CGColorSpaceCreateDeviceRGB();
size_t width = CGImageGetWidth(imageRef);
size_t height = CGImageGetHeight(imageRef);
//计算出每行行的像素数
size_t bytesPerRow = 4 * width;
// kCGImageAlphaNone is not supported in CGBitmapContextCreate.这里创建的contexts是没有透明因素的(位图图形上下文),为了防止渲染控件的时候直接忽略掉其下方的图层
CGContextRef context = CGBitmapContextCreate(NULL,width,height,8,bytesPerRow,colorspaceRef,kCGBitmapByteOrderDefault|kCGImageAlphaNoneSkipLast);
if (context == NULL) {
CGColorSpaceRelease(colorspaceRef);
return image;
}
// Draw the image into the context and retrieve the new bitmap image without alpha
CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
CGImageRef imageRefWithoutAlpha = CGBitmapContextCreateImage(context);
//image.imageOrientation由于使用CoreGraphics绘制图片的Y坐标和UIKit的Y坐标相反,这时要要把图片正古来
UIImage *imageWithoutAlpha = [UIImage imageWithCGImage:imageRefWithoutAlpha scale:image.scale orientation:image.imageOrientation];
CGColorSpaceRelease(colorspaceRef);
CGContextRelease(context);
CGImageRelease(imageRefWithoutAlpha);
return imageWithoutAlpha;
}
}
@end
@implementation NSImageName
@end


牛叉叉