SeMobGIFImageView.m 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. //
  2. // SeMobGIFImageView.m
  3. // SeMob
  4. //
  5. // Created by yangbin on 2017/8/10.
  6. //
  7. #import "SeMobGIFImageView.h"
  8. #import <ImageIO/ImageIO.h>
  9. @interface SeMobGIFImageView()
  10. @property (nonatomic) CGImageSourceRef sourceRef;
  11. @property (nonatomic) NSUInteger currentIndex;
  12. @property (nonatomic) NSUInteger maxImageCount;
  13. @end
  14. @implementation SeMobGIFImageView
  15. + (SeMobGIFImageView *)imageViewWithGIFData:(NSData *)data
  16. {
  17. SeMobGIFImageView *view = [[SeMobGIFImageView alloc] init];
  18. view.gifData = data;
  19. return view;
  20. }
  21. - (void)dealloc
  22. {
  23. if (_sourceRef) {
  24. CFRelease(_sourceRef);
  25. }
  26. self.sourceRef = NULL;
  27. }
  28. - (void)didMoveToWindow
  29. {
  30. if (self.window == nil) {
  31. [self stopAnimating];
  32. }
  33. }
  34. - (void)startAnimating
  35. {
  36. [self stopAnimating];
  37. if (!_gifData) {
  38. return;
  39. }
  40. _currentIndex = 0;
  41. CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)_gifData, NULL);
  42. self.sourceRef = source;
  43. size_t count = CGImageSourceGetCount(source);
  44. self.maxImageCount = count;
  45. if (count <= 1) {
  46. UIImage *animatedImage = [[UIImage alloc] initWithData:_gifData];
  47. self.image = animatedImage;
  48. return;
  49. } else {
  50. [self loadNextImage];
  51. }
  52. }
  53. - (void)stopAnimating
  54. {
  55. if (_sourceRef) {
  56. CFRelease(_sourceRef);
  57. }
  58. self.sourceRef = NULL;
  59. self.maxImageCount = 0;
  60. self.currentIndex = 0;
  61. }
  62. - (void)loadNextImage
  63. {
  64. if (_sourceRef == NULL) {
  65. return;
  66. }
  67. CGImageRef image = CGImageSourceCreateImageAtIndex(_sourceRef, _currentIndex, NULL);
  68. float duration = [self semobGIF_frameDurationAtIndex:_currentIndex source:_sourceRef];
  69. UIImage *imgCurrent = [UIImage imageWithCGImage:image scale:[UIScreen mainScreen].scale orientation:UIImageOrientationUp];
  70. CGImageRelease(image);
  71. self.image = imgCurrent;
  72. __weak typeof(self) weakSelf = self;
  73. CGImageSourceRef current = _sourceRef;
  74. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(duration * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  75. if (weakSelf == nil || weakSelf.sourceRef == NULL) {
  76. return ;
  77. }
  78. if (current != weakSelf.sourceRef) {
  79. return;
  80. }
  81. weakSelf.currentIndex += 1;
  82. if (weakSelf.currentIndex >= weakSelf.maxImageCount) {
  83. weakSelf.currentIndex = 0;
  84. }
  85. [weakSelf loadNextImage];
  86. });
  87. }
  88. - (float)semobGIF_frameDurationAtIndex:(NSUInteger)index source:(CGImageSourceRef)source
  89. {
  90. float frameDuration = 0.1f;
  91. CFDictionaryRef cfFrameProperties = CGImageSourceCopyPropertiesAtIndex(source, index, nil);
  92. NSDictionary *frameProperties = (__bridge NSDictionary *)cfFrameProperties;
  93. NSDictionary *gifProperties = frameProperties[(NSString *)kCGImagePropertyGIFDictionary];
  94. NSNumber *delayTimeUnclampedProp = gifProperties[(NSString *)kCGImagePropertyGIFUnclampedDelayTime];
  95. if (delayTimeUnclampedProp) {
  96. frameDuration = [delayTimeUnclampedProp floatValue];
  97. }
  98. else {
  99. NSNumber *delayTimeProp = gifProperties[(NSString *)kCGImagePropertyGIFDelayTime];
  100. if (delayTimeProp) {
  101. frameDuration = [delayTimeProp floatValue];
  102. }
  103. }
  104. // Many annoying ads specify a 0 duration to make an image flash as quickly as possible.
  105. // We follow Firefox's behavior and use a duration of 100 ms for any frames that specify
  106. // a duration of <= 10 ms. See <rdar://problem/7689300> and <http://webkit.org/b/36082>
  107. // for more information.
  108. if (frameDuration < 0.011f) {
  109. frameDuration = 0.100f;
  110. }
  111. CFRelease(cfFrameProperties);
  112. return frameDuration;
  113. }
  114. @end