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
牛叉叉