ios播放gif图片

来源:互联网 发布:逃出克隆岛 知乎 编辑:程序博客网 时间:2024/05/16 09:26
 

ios播放gif图片

 3689人阅读 评论(0) 收藏 举报
 分类:
 

以前一直听说iOS不可以播放gif图片。也没取看看。其实想想有啥不能播放的。只是没有提供现成的api而已。最近看看资料以及别人的例子了解了一下实现原理 特记录一下:

gif 其实本来就是一系列的图片的集合 可以通过 imageIO 获取到图片数组。然后动画播放就ok了;先看一下 简单的例子:

[objc] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. NSURL *url = [[NSBundle mainBundle] URLForResource:@"pika.gif" withExtension:nil];  
  2. CGImageSourceRef csf = CGImageSourceCreateWithURL((__bridge CFTypeRef) url, NULL);  
  3. size_t const count = CGImageSourceGetCount(csf);  
  4. UIImage *frames[count];  
  5. CGImageRef images[count];  
  6. for (size_t i = 0; i < count; ++i) {  
  7.     images[i] = CGImageSourceCreateImageAtIndex(csf, i, NULL);  
  8.      UIImage *image =[[UIImage alloc] initWithCGImage:images[i]];  
  9.     frames[i] = image;  
  10.     CFRelease(images[i]);  
  11. }  
  12.   
  13. UIImage *const animation = [UIImage animatedImageWithImages:[NSArray arrayWithObjects:frames count:count] duration:0.1];  
  14.   
  15. [view2 setImage:animation];  
  16. NSLog(@"xxxx%zu",count);  
  17. CFRelease(csf);  

一个简单的播放gif的例子就出来了。不过毫无疑问。这么写有很大的问题。原因在于gif 每一桢之间的间隔时间是可以设置的。甚至可以不同。所以需要做些处理

有个人的实现原理是这样的:取出gif图片所有桢的时间。 取这些时间的最大公约数 作为显示的的桢的时间。 然后根据新的桢的间隔时间取对应的图片。 这样处理显示的帧数大于等于原始帧数。 如果原始桢的间隔时间太奇葩。 会导致大量的图片是重复的。不过正常使用还是很不错的。

下面是 从code4app上下载的别人的代码 地址已经不记得了。删除了其他的部分 只留下了跟播放动画相关的地方  贴出来参考:

[objc] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. //  
  2. //  ViewController.m  
  3. //  test4  
  4. //  
  5. //  Created by Aurora_sgbh on 15-2-6.  
  6. //  Copyright (c) 2015年 Aurora_sgbh. All rights reserved.  
  7. //  
  8. #if __has_feature(objc_arc)  
  9. #define toCF (__bridge CFTypeRef)  
  10. #define fromCF (__bridge id)  
  11. #else  
  12. #define toCF (CFTypeRef)  
  13. #define fromCF (id)  
  14. #endif  
  15.   
  16. #import "ViewController.h"  
  17. #import <ImageIO/ImageIO.h>  
  18. #pragma mark - UIImage Animated GIF  
  19.   
  20.   
  21. @implementation UIImage (animatedGIF)  
  22.   
  23. static int delayCentisecondsForImageAtIndex(CGImageSourceRef const source, size_t const i) {  
  24.     int delayCentiseconds = 1;  
  25.     CFDictionaryRef const properties = CGImageSourceCopyPropertiesAtIndex(source, i, NULL);  
  26.     if (properties) {  
  27.         CFDictionaryRef const gifProperties = CFDictionaryGetValue(properties, kCGImagePropertyGIFDictionary);  
  28.         if (gifProperties) {  
  29.             NSNumber *number = fromCF CFDictionaryGetValue(gifProperties, kCGImagePropertyGIFUnclampedDelayTime);  
  30.             if (number == NULL || [number doubleValue] == 0) {  
  31.                 number = fromCF CFDictionaryGetValue(gifProperties, kCGImagePropertyGIFDelayTime);  
  32.             }  
  33.             if ([number doubleValue] > 0) {  
  34.                 // Even though the GIF stores the delay as an integer number of centiseconds, ImageIO “helpfully” converts that to seconds for us.  
  35.                 delayCentiseconds = (int)lrint([number doubleValue] * 100);  
  36.                 NSLog(@"看看时间%d",delayCentiseconds);  
  37.             }  
  38.         }  
  39.         CFRelease(properties);  
  40.     }  
  41.     return delayCentiseconds;  
  42. }  
  43.   
  44. static void createImagesAndDelays(CGImageSourceRef source, size_t count, CGImageRef imagesOut[count], int delayCentisecondsOut[count]) {  
  45.     for (size_t i = 0; i < count; ++i) {  
  46.         imagesOut[i] = CGImageSourceCreateImageAtIndex(source, i, NULL);  
  47.         delayCentisecondsOut[i] = delayCentisecondsForImageAtIndex(source, i);  
  48.     }  
  49. }  
  50.   
  51. static int sum(size_t const count, int constconst *const values) {  
  52.     int theSum = 0;  
  53.     for (size_t i = 0; i < count; ++i) {  
  54.         theSum += values[i];  
  55.     }  
  56.     return theSum;  
  57. }  
  58.   
  59. //最大公约数  
  60. static int pairGCD(int a, int b) {  
  61.     if (a < b)  
  62.         return pairGCD(b, a);  
  63.     while (true) {  
  64.         int const r = a % b;  
  65.         if (r == 0)  
  66.             return b;  
  67.         a = b;  
  68.         b = r;  
  69.     }  
  70. }  
  71.   
  72. static int vectorGCD(size_t const count, int constconst *const values) {  
  73.     int gcd = values[0];  
  74.     for (size_t i = 1; i < count; ++i) {  
  75.         // Note that after I process the first few elements of the vector, `gcd` will probably be smaller than any remaining element.  By passing the smaller value as the second argument to `pairGCD`, I avoid making it swap the arguments.  
  76.         gcd = pairGCD(values[i], gcd);  
  77.     }  
  78.     return gcd;  
  79. }  
  80.   
  81. static NSArray *frameArray(size_t const count, CGImageRef const images[count], int const delayCentiseconds[count], int const totalDurationCentiseconds) {  
  82.     int const gcd = vectorGCD(count, delayCentiseconds);  
  83.     size_t const frameCount = totalDurationCentiseconds / gcd;  
  84.     UIImage *frames[frameCount];  
  85.     for (size_t i = 0, f = 0; i < count; ++i) {  
  86.         UIImage *const frame = [UIImage imageWithCGImage:images[i]];  
  87.         for (size_t j = delayCentiseconds[i] / gcd; j > 0; --j) {  
  88.             frames[f++] = frame;  
  89.         }  
  90.     }  
  91.     return [NSArray arrayWithObjects:frames count:frameCount];  
  92. }  
  93.   
  94. static void releaseImages(size_t const count, CGImageRef const images[count]) {  
  95.     for (size_t i = 0; i < count; ++i) {  
  96.         CGImageRelease(images[i]);  
  97.     }  
  98. }  
  99.   
  100. //xxx  
  101. static UIImage *animatedImageWithAnimatedGIFImageSource(CGImageSourceRef const source) {  
  102.     size_t const count = CGImageSourceGetCount(source);  
  103.     CGImageRef images[count];  
  104.     int delayCentiseconds[count]; // in centiseconds  
  105.     createImagesAndDelays(source, count, images, delayCentiseconds);  
  106.     int const totalDurationCentiseconds = sum(count, delayCentiseconds);  
  107.     NSArray *const frames = frameArray(count, images, delayCentiseconds, totalDurationCentiseconds);  
  108.     UIImage *const animation = [UIImage animatedImageWithImages:frames duration:(NSTimeInterval)totalDurationCentiseconds / 100.0];  
  109.     releaseImages(count, images);  
  110.     return animation;  
  111. }  
  112.   
  113. static UIImage *animatedImageWithAnimatedGIFReleasingImageSource(CGImageSourceRef CF_RELEASES_ARGUMENT source) {  
  114.     if (source) {  
  115.         UIImage *const image = animatedImageWithAnimatedGIFImageSource(source);  
  116.         CFRelease(source);  
  117.         return image;  
  118.     } else {  
  119.         return nil;  
  120.     }  
  121. }  
  122.   
  123. + (UIImage *)animatedImageWithAnimatedGIFData:(NSData *)data {  
  124.     return animatedImageWithAnimatedGIFReleasingImageSource(CGImageSourceCreateWithData(toCF data, NULL));  
  125. }  
  126.   
  127. + (UIImage *)animatedImageWithAnimatedGIFURL:(NSURL *)url {  
  128.     return animatedImageWithAnimatedGIFReleasingImageSource(CGImageSourceCreateWithURL((__bridge CFTypeRef) url, NULL));  
  129. }  
  130.   
  131. @end  
  132.   
  133. @interface ViewController ()  
  134.   
  135. @end  
  136.   
  137. @implementation ViewController  
  138.   
  139. - (void)viewDidLoad {  
  140.     [super viewDidLoad];  
  141.     UIImageView *view =[[UIImageView alloc]initWithFrame:CGRectMake(5050100100)];  
  142.       
  143.   
  144.     [view setImage:[UIImage animatedImageWithAnimatedGIFURL:[[NSBundle mainBundle] URLForResource:@"3.gif" withExtension:nil]]];  
  145.       
  146.     //mytest  
  147.       
  148. //    UIImageView *view2 =[[UIImageView alloc]initWithFrame:CGRectMake(50, 250, 100, 100)];  
  149. //    [view2 setBackgroundColor:[UIColor redColor]];  
  150. //    NSURL *url = [[NSBundle mainBundle] URLForResource:@"pika.gif" withExtension:nil];  
  151. //    CGImageSourceRef csf = CGImageSourceCreateWithURL((__bridge CFTypeRef) url, NULL);  
  152. //    size_t const count = CGImageSourceGetCount(csf);  
  153. //    UIImage *frames[count];  
  154. //    CGImageRef images[count];  
  155. //    for (size_t i = 0; i < count; ++i) {  
  156. //        images[i] = CGImageSourceCreateImageAtIndex(csf, i, NULL);  
  157. //         UIImage *image =[[UIImage alloc] initWithCGImage:images[i]];  
  158. //        frames[i] = image;  
  159. //        CFRelease(images[i]);  
  160. //    }  
  161. //      
  162. //    UIImage *const animation = [UIImage animatedImageWithImages:[NSArray arrayWithObjects:frames count:count] duration:0.1];  
  163. //     
  164. //    [view2 setImage:animation];  
  165. //    NSLog(@"xxxx%zu",count);  
  166. //    CFRelease(csf);  
  167.   //  [self.view addSubview:view2];  
  168.       
  169.     [self.view addSubview:view];  
  170.       
  171. }  
  172.   
  173. - (void)didReceiveMemoryWarning {  
  174.     [super didReceiveMemoryWarning];  
  175.     // Dispose of any resources that can be recreated.  
  176. }  
  177.   
  178. @end  


另外也可以通过动画来播放。这样可能不会像上面出现特殊情况下大量重复的桢。不过现实中gif间隔一般都是固定的。所以上面就够用了。
0 0
原创粉丝点击