SLImage.m 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. //
  2. // SLImage.m
  3. // WSLImageView
  4. //
  5. // Created by 王双龙 on 2018/10/26.
  6. // Copyright © 2018年 https://www.jianshu.com/u/e15d1f644bea. All rights reserved.
  7. //
  8. #import "SLImage.h"
  9. @interface SLImage () {
  10. NSUInteger _bytesPerFrame; //每一帧图片的字节大小
  11. dispatch_semaphore_t _preloadedLock; //预加载锁
  12. SLImageDecoder * _imageDecoder; //解码工具
  13. NSArray <SLImageFrame *> * _preloadedFrames; //预加载的图片帧
  14. }
  15. @end
  16. @implementation SLImage
  17. //减少内存的占用
  18. + (SLImage *)imageNamed:(NSString *)name{
  19. if (name.length == 0) return nil;
  20. if ([name hasSuffix:@"/"]) return nil;
  21. //从文件的最后一部分删除扩展名
  22. NSString *res = name.stringByDeletingPathExtension;
  23. //提取其文件扩展名
  24. NSString *ext = name.pathExtension;
  25. NSString *path = nil;
  26. CGFloat scale = 1;
  27. NSArray *exts = ext.length > 0 ? @[ext] : @[@"", @"png", @"jpeg", @"jpg", @"gif", @"webp", @"apng"];
  28. NSArray *scales = [SLImage preferredScales];
  29. for (int s = 0; s < scales.count; s++) {
  30. scale = ((NSNumber *)scales[s]).floatValue;
  31. // FLT_EPSILON = 1.192092896e-07F 大于0的最小浮点数
  32. NSString *scaledName = (fabs(scale - 1) <= __FLT_EPSILON__ || res == 0 ) ? res : [res stringByAppendingFormat:@"@%@x", @(scale)];
  33. for (NSString *e in exts) {
  34. path = [[NSBundle mainBundle] pathForResource:scaledName ofType:e];
  35. if (path) break;
  36. }
  37. if (path) break;
  38. }
  39. if (path.length == 0) return nil;
  40. NSData *data = [NSData dataWithContentsOfFile:path];
  41. if (data.length == 0) return nil;
  42. return [[self alloc] initWithData:data scale:scale];
  43. }
  44. + (NSArray *)preferredScales{
  45. NSArray *scales;
  46. //像素分辨率,首先取当前分辨率的图片,没有的话取其他的
  47. CGFloat screenScale = [UIScreen mainScreen].scale;
  48. if (screenScale <= 1) {
  49. scales = @[@1,@2,@3];
  50. } else if (screenScale <= 2) {
  51. scales = @[@2,@3,@1];
  52. } else {
  53. scales = @[@3,@2,@1];
  54. }
  55. return scales;
  56. }
  57. + (SLImage *)imageWithContentsOfFile:(NSString *)path {
  58. return [[self alloc] initWithContentsOfFile:path];
  59. }
  60. + (SLImage *)imageWithData:(NSData *)data{
  61. return [[self alloc] initWithData:data];
  62. }
  63. + (SLImage *)imageWithData:(NSData *)data scale:(CGFloat)scale {
  64. return [[self alloc] initWithData:data scale:scale];
  65. }
  66. - (instancetype)initWithContentsOfFile:(NSString *)path {
  67. NSData *data = [NSData dataWithContentsOfFile:path];
  68. return [self initWithData:data scale:[UIScreen mainScreen].scale];
  69. }
  70. - (instancetype)initWithData:(NSData *)data {
  71. return [self initWithData:data scale:[UIScreen mainScreen].scale];
  72. }
  73. - (instancetype)initWithData:(NSData *)data scale:(CGFloat)scale {
  74. if (data.length == 0) return nil;
  75. if (scale <= 0) scale = [UIScreen mainScreen].scale;
  76. //信号量
  77. _preloadedLock = dispatch_semaphore_create(1);
  78. //创建一个自动释放池 ,有大量中间临时变量产生时,避免内存使用峰值过高,及时释放内存的场景 https://blog.csdn.net/z040145/article/details/69398768
  79. @autoreleasepool {
  80. _imageDecoder = [[SLImageDecoder alloc] init];
  81. [_imageDecoder decoderWithData:data scale:[UIScreen mainScreen].scale];
  82. _imageType = _imageDecoder.imageType;
  83. _frameCount = _imageDecoder.frameCount;
  84. UIImage * imageFrame = [_imageDecoder imageAtIndex:0];
  85. if (!imageFrame) return nil;
  86. self = [self initWithCGImage:imageFrame.CGImage scale:scale orientation:UIImageOrientationUp];
  87. if (!self) return nil;
  88. _bytesPerFrame = CGImageGetBytesPerRow(imageFrame.CGImage) * CGImageGetHeight(imageFrame.CGImage);
  89. _animatedImageMemorySize = _bytesPerFrame * _imageDecoder.frameCount;
  90. }
  91. return self;
  92. }
  93. /**
  94. 是否预解码所有的帧
  95. */
  96. - (void)setPreloadAllAnimatedImageFrames:(BOOL)preloadAllAnimatedImageFrames{
  97. _preloadAllAnimatedImageFrames = preloadAllAnimatedImageFrames;
  98. if (_preloadAllAnimatedImageFrames && _imageDecoder.frameCount > 0) {
  99. NSMutableArray *frames = [NSMutableArray new];
  100. for (NSUInteger i = 0, max = _imageDecoder.frameCount; i < max; i++) {
  101. SLImageFrame *imageFrame = [_imageDecoder imageFrameAtIndex:i];
  102. if (imageFrame) {
  103. [frames addObject:imageFrame];
  104. } else {
  105. [frames addObject:[NSNull null]];
  106. }
  107. }
  108. dispatch_semaphore_wait(_preloadedLock, DISPATCH_TIME_FOREVER);
  109. _preloadedFrames = frames;
  110. dispatch_semaphore_signal(_preloadedLock);
  111. }else if(!_preloadAllAnimatedImageFrames){
  112. dispatch_semaphore_wait(_preloadedLock, DISPATCH_TIME_FOREVER);
  113. _preloadedFrames = nil;
  114. dispatch_semaphore_signal(_preloadedLock);
  115. }
  116. }
  117. #pragma mark - 帧信息
  118. - (SLImageFrame *)imageFrameAtIndex:(NSInteger)index {
  119. if (index >= _imageDecoder.frameCount) return nil;
  120. dispatch_semaphore_wait(_preloadedLock, DISPATCH_TIME_FOREVER);
  121. SLImageFrame *imageFrame = _preloadedFrames[index];
  122. dispatch_semaphore_signal(_preloadedLock);
  123. if (imageFrame) return imageFrame == (id)[NSNull null] ? nil : imageFrame;
  124. return [_imageDecoder imageFrameAtIndex:index];
  125. }
  126. - (UIImage *)imageAtIndex:(NSUInteger)index {
  127. if (index >= _imageDecoder.frameCount) return nil;
  128. dispatch_semaphore_wait(_preloadedLock, DISPATCH_TIME_FOREVER);
  129. SLImageFrame *imageFrame = _preloadedFrames[index];
  130. dispatch_semaphore_signal(_preloadedLock);
  131. if (imageFrame.image) return imageFrame.image == (id)[NSNull null] ? nil : imageFrame.image;
  132. return [_imageDecoder imageAtIndex:index];
  133. }
  134. /**
  135. 某一帧持续时长
  136. */
  137. - (NSTimeInterval)imageDurationAtIndex:(NSUInteger)index{
  138. if (index >= _imageDecoder.frameCount) return 0;
  139. dispatch_semaphore_wait(_preloadedLock, DISPATCH_TIME_FOREVER);
  140. SLImageFrame *imageFrame = _preloadedFrames[index];
  141. dispatch_semaphore_signal(_preloadedLock);
  142. if (imageFrame.duration) return imageFrame.duration == 0 ? 0 : imageFrame.duration;
  143. return [_imageDecoder imageDurationAtIndex:index];
  144. }
  145. /**
  146. 每一帧的字节
  147. */
  148. - (NSUInteger)imageFrameBytes{
  149. return _bytesPerFrame;
  150. }
  151. /**
  152. 循环次数
  153. */
  154. - (NSInteger)loopCount{
  155. return _imageDecoder.loopCount;
  156. }
  157. /// 循环一次的时长
  158. - (NSTimeInterval)totalTime {
  159. return _imageDecoder.totalTime;
  160. }
  161. @end