123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181 |
- //
- // SLImage.m
- // WSLImageView
- //
- // Created by 王双龙 on 2018/10/26.
- // Copyright © 2018年 https://www.jianshu.com/u/e15d1f644bea. All rights reserved.
- //
- #import "SLImage.h"
- @interface SLImage () {
- NSUInteger _bytesPerFrame; //每一帧图片的字节大小
- dispatch_semaphore_t _preloadedLock; //预加载锁
- SLImageDecoder * _imageDecoder; //解码工具
- NSArray <SLImageFrame *> * _preloadedFrames; //预加载的图片帧
- }
- @end
- @implementation SLImage
- //减少内存的占用
- + (SLImage *)imageNamed:(NSString *)name{
-
- if (name.length == 0) return nil;
- if ([name hasSuffix:@"/"]) return nil;
-
- //从文件的最后一部分删除扩展名
- NSString *res = name.stringByDeletingPathExtension;
- //提取其文件扩展名
- NSString *ext = name.pathExtension;
- NSString *path = nil;
- CGFloat scale = 1;
-
- NSArray *exts = ext.length > 0 ? @[ext] : @[@"", @"png", @"jpeg", @"jpg", @"gif", @"webp", @"apng"];
- NSArray *scales = [SLImage preferredScales];
- for (int s = 0; s < scales.count; s++) {
- scale = ((NSNumber *)scales[s]).floatValue;
- // FLT_EPSILON = 1.192092896e-07F 大于0的最小浮点数
- NSString *scaledName = (fabs(scale - 1) <= __FLT_EPSILON__ || res == 0 ) ? res : [res stringByAppendingFormat:@"@%@x", @(scale)];
- for (NSString *e in exts) {
- path = [[NSBundle mainBundle] pathForResource:scaledName ofType:e];
- if (path) break;
- }
- if (path) break;
- }
- if (path.length == 0) return nil;
-
- NSData *data = [NSData dataWithContentsOfFile:path];
- if (data.length == 0) return nil;
- return [[self alloc] initWithData:data scale:scale];
- }
- + (NSArray *)preferredScales{
- NSArray *scales;
- //像素分辨率,首先取当前分辨率的图片,没有的话取其他的
- CGFloat screenScale = [UIScreen mainScreen].scale;
- if (screenScale <= 1) {
- scales = @[@1,@2,@3];
- } else if (screenScale <= 2) {
- scales = @[@2,@3,@1];
- } else {
- scales = @[@3,@2,@1];
- }
- return scales;
- }
- + (SLImage *)imageWithContentsOfFile:(NSString *)path {
- return [[self alloc] initWithContentsOfFile:path];
- }
- + (SLImage *)imageWithData:(NSData *)data{
- return [[self alloc] initWithData:data];
- }
- + (SLImage *)imageWithData:(NSData *)data scale:(CGFloat)scale {
- return [[self alloc] initWithData:data scale:scale];
- }
- - (instancetype)initWithContentsOfFile:(NSString *)path {
- NSData *data = [NSData dataWithContentsOfFile:path];
- return [self initWithData:data scale:[UIScreen mainScreen].scale];
- }
- - (instancetype)initWithData:(NSData *)data {
- return [self initWithData:data scale:[UIScreen mainScreen].scale];
- }
- - (instancetype)initWithData:(NSData *)data scale:(CGFloat)scale {
-
- if (data.length == 0) return nil;
- if (scale <= 0) scale = [UIScreen mainScreen].scale;
- //信号量
- _preloadedLock = dispatch_semaphore_create(1);
- //创建一个自动释放池 ,有大量中间临时变量产生时,避免内存使用峰值过高,及时释放内存的场景 https://blog.csdn.net/z040145/article/details/69398768
- @autoreleasepool {
- _imageDecoder = [[SLImageDecoder alloc] init];
- [_imageDecoder decoderWithData:data scale:[UIScreen mainScreen].scale];
- _imageType = _imageDecoder.imageType;
- _frameCount = _imageDecoder.frameCount;
- UIImage * imageFrame = [_imageDecoder imageAtIndex:0];
- if (!imageFrame) return nil;
- self = [self initWithCGImage:imageFrame.CGImage scale:scale orientation:UIImageOrientationUp];
- if (!self) return nil;
- _bytesPerFrame = CGImageGetBytesPerRow(imageFrame.CGImage) * CGImageGetHeight(imageFrame.CGImage);
- _animatedImageMemorySize = _bytesPerFrame * _imageDecoder.frameCount;
- }
- return self;
- }
- /**
- 是否预解码所有的帧
- */
- - (void)setPreloadAllAnimatedImageFrames:(BOOL)preloadAllAnimatedImageFrames{
- _preloadAllAnimatedImageFrames = preloadAllAnimatedImageFrames;
- if (_preloadAllAnimatedImageFrames && _imageDecoder.frameCount > 0) {
- NSMutableArray *frames = [NSMutableArray new];
- for (NSUInteger i = 0, max = _imageDecoder.frameCount; i < max; i++) {
- SLImageFrame *imageFrame = [_imageDecoder imageFrameAtIndex:i];
- if (imageFrame) {
- [frames addObject:imageFrame];
- } else {
- [frames addObject:[NSNull null]];
- }
- }
- dispatch_semaphore_wait(_preloadedLock, DISPATCH_TIME_FOREVER);
- _preloadedFrames = frames;
- dispatch_semaphore_signal(_preloadedLock);
- }else if(!_preloadAllAnimatedImageFrames){
- dispatch_semaphore_wait(_preloadedLock, DISPATCH_TIME_FOREVER);
- _preloadedFrames = nil;
- dispatch_semaphore_signal(_preloadedLock);
- }
- }
- #pragma mark - 帧信息
- - (SLImageFrame *)imageFrameAtIndex:(NSInteger)index {
- if (index >= _imageDecoder.frameCount) return nil;
- dispatch_semaphore_wait(_preloadedLock, DISPATCH_TIME_FOREVER);
- SLImageFrame *imageFrame = _preloadedFrames[index];
- dispatch_semaphore_signal(_preloadedLock);
- if (imageFrame) return imageFrame == (id)[NSNull null] ? nil : imageFrame;
- return [_imageDecoder imageFrameAtIndex:index];
- }
- - (UIImage *)imageAtIndex:(NSUInteger)index {
- if (index >= _imageDecoder.frameCount) return nil;
- dispatch_semaphore_wait(_preloadedLock, DISPATCH_TIME_FOREVER);
- SLImageFrame *imageFrame = _preloadedFrames[index];
- dispatch_semaphore_signal(_preloadedLock);
- if (imageFrame.image) return imageFrame.image == (id)[NSNull null] ? nil : imageFrame.image;
- return [_imageDecoder imageAtIndex:index];
- }
- /**
- 某一帧持续时长
- */
- - (NSTimeInterval)imageDurationAtIndex:(NSUInteger)index{
- if (index >= _imageDecoder.frameCount) return 0;
- dispatch_semaphore_wait(_preloadedLock, DISPATCH_TIME_FOREVER);
- SLImageFrame *imageFrame = _preloadedFrames[index];
- dispatch_semaphore_signal(_preloadedLock);
- if (imageFrame.duration) return imageFrame.duration == 0 ? 0 : imageFrame.duration;
- return [_imageDecoder imageDurationAtIndex:index];
- }
- /**
- 每一帧的字节
- */
- - (NSUInteger)imageFrameBytes{
- return _bytesPerFrame;
- }
- /**
- 循环次数
- */
- - (NSInteger)loopCount{
- return _imageDecoder.loopCount;
- }
- /// 循环一次的时长
- - (NSTimeInterval)totalTime {
- return _imageDecoder.totalTime;
- }
- @end
|