123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134 |
- //
- // SeMobGIFImageView.m
- // SeMob
- //
- // Created by yangbin on 2017/8/10.
- //
- #import "SeMobGIFImageView.h"
- #import <ImageIO/ImageIO.h>
- @interface SeMobGIFImageView()
- @property (nonatomic) CGImageSourceRef sourceRef;
- @property (nonatomic) NSUInteger currentIndex;
- @property (nonatomic) NSUInteger maxImageCount;
- @end
- @implementation SeMobGIFImageView
- + (SeMobGIFImageView *)imageViewWithGIFData:(NSData *)data
- {
- SeMobGIFImageView *view = [[SeMobGIFImageView alloc] init];
- view.gifData = data;
- return view;
- }
- - (void)dealloc
- {
- if (_sourceRef) {
- CFRelease(_sourceRef);
- }
- self.sourceRef = NULL;
- }
- - (void)didMoveToWindow
- {
- if (self.window == nil) {
- [self stopAnimating];
- }
- }
- - (void)startAnimating
- {
- [self stopAnimating];
- if (!_gifData) {
- return;
- }
- _currentIndex = 0;
- CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)_gifData, NULL);
- self.sourceRef = source;
- size_t count = CGImageSourceGetCount(source);
- self.maxImageCount = count;
-
- if (count <= 1) {
- UIImage *animatedImage = [[UIImage alloc] initWithData:_gifData];
- self.image = animatedImage;
- return;
- } else {
- [self loadNextImage];
- }
- }
- - (void)stopAnimating
- {
- if (_sourceRef) {
- CFRelease(_sourceRef);
- }
- self.sourceRef = NULL;
- self.maxImageCount = 0;
- self.currentIndex = 0;
- }
- - (void)loadNextImage
- {
- if (_sourceRef == NULL) {
- return;
- }
- CGImageRef image = CGImageSourceCreateImageAtIndex(_sourceRef, _currentIndex, NULL);
-
- float duration = [self semobGIF_frameDurationAtIndex:_currentIndex source:_sourceRef];
-
- UIImage *imgCurrent = [UIImage imageWithCGImage:image scale:[UIScreen mainScreen].scale orientation:UIImageOrientationUp];
-
- CGImageRelease(image);
- self.image = imgCurrent;
- __weak typeof(self) weakSelf = self;
- CGImageSourceRef current = _sourceRef;
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(duration * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
- if (weakSelf == nil || weakSelf.sourceRef == NULL) {
- return ;
- }
- if (current != weakSelf.sourceRef) {
- return;
- }
- weakSelf.currentIndex += 1;
- if (weakSelf.currentIndex >= weakSelf.maxImageCount) {
- weakSelf.currentIndex = 0;
- }
- [weakSelf loadNextImage];
- });
- }
- - (float)semobGIF_frameDurationAtIndex:(NSUInteger)index source:(CGImageSourceRef)source
- {
- float frameDuration = 0.1f;
- CFDictionaryRef cfFrameProperties = CGImageSourceCopyPropertiesAtIndex(source, index, nil);
- NSDictionary *frameProperties = (__bridge NSDictionary *)cfFrameProperties;
- NSDictionary *gifProperties = frameProperties[(NSString *)kCGImagePropertyGIFDictionary];
-
- NSNumber *delayTimeUnclampedProp = gifProperties[(NSString *)kCGImagePropertyGIFUnclampedDelayTime];
- if (delayTimeUnclampedProp) {
- frameDuration = [delayTimeUnclampedProp floatValue];
- }
- else {
-
- NSNumber *delayTimeProp = gifProperties[(NSString *)kCGImagePropertyGIFDelayTime];
- if (delayTimeProp) {
- frameDuration = [delayTimeProp floatValue];
- }
- }
-
- // Many annoying ads specify a 0 duration to make an image flash as quickly as possible.
- // We follow Firefox's behavior and use a duration of 100 ms for any frames that specify
- // a duration of <= 10 ms. See <rdar://problem/7689300> and <http://webkit.org/b/36082>
- // for more information.
-
- if (frameDuration < 0.011f) {
- frameDuration = 0.100f;
- }
-
- CFRelease(cfFrameProperties);
- return frameDuration;
- }
- @end
|