iOS - GIF图的完美拆解、合成、显示

来源:互联网 发布:阅读软件哪个看书免费 编辑:程序博客网 时间:2024/04/30 13:00

转:http://blog.csdn.net/marujunyy/article/details/14455699

最近由于项目需要,需要先把gif图拆解开,然后在每一张图片上添加一些图片和文字,最后再合成gif文件;写了一个工具类可以每一帧画面并遵循每一帧所对应的显示时间进行播放,并且可以用多张图片指定每一帧播放时间来合成gif图。下面是使用方法和工具类:(需要添加framework : ImageIO、QuartzCore、MobileCoreServices

[cpp] view plaincopy
  1. NSDate *date = [NSDate date];  
  2. //读取本地GIF图中每一帧图像的信息  
  3. NSURL *fileUrl = [[NSBundle mainBundle] URLForResource:@"demo" withExtension:@"gif"];  
  4. NSDictionary *dic = [GifView getGifInfo:fileUrl];  
  5.   
  6. NSMutableArray *imageArray = [NSMutableArray array];  
  7. //在gif图的每一帧上面添加一段文字  
  8. for(int index=0;index<[dic[@"images"] count];index++)  
  9. {  
  10.     //绘制view 已GIf图中的某一帧为背景并在view上添加文字  
  11.     UIView *tempView = [[UIView alloc] initWithFrame:CGRectFromString(dic[@"bounds"])];  
  12.     tempView.backgroundColor = [UIColor colorWithPatternImage:dic[@"images"][index]];  
  13.     UILabel *tempLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 10, 80, 20)];  
  14.     tempLabel.text = @"GIF测试";  
  15.     tempLabel.textColor = [UIColor redColor];  
  16.     tempLabel.backgroundColor = [UIColor clearColor];  
  17.     tempLabel.font = [UIFont boldSystemFontOfSize:20];  
  18.     [tempView addSubview:tempLabel];  
  19.   
  20.     //将UIView转换为UIImage  
  21.     UIGraphicsBeginImageContextWithOptions(tempView.bounds.size, NO, tempView.layer.contentsScale);  
  22.     [tempView.layer renderInContext:UIGraphicsGetCurrentContext()];  
  23.     UIImage *image = UIGraphicsGetImageFromCurrentImageContext();  
  24.     [imageArray addObject:image];  
  25.     UIGraphicsEndImageContext();  
  26. }  
  27. //生成GIF图 -- loopCount 为0表示无限播放  
  28. NSString *path = [GifView exportGifImages:[imageArray copy] delays:dic[@"delays"] loopCount:0];  
  29.   
  30. //在页面上展示合成之后的GIF图  
  31. GifView *gifView = [[GifView alloc] initWithCenter:self.view.center fileURL:[NSURL fileURLWithPath:path]];  
  32. [self.view addSubview:gifView];  
  33. NSLog(@"合成GIF图用时:%f秒",[[NSDate date] timeIntervalSinceDate:date]);  



//GifView.h

[cpp] view plaincopy
  1. #import <UIKit/UIKit.h>  
  2.   
  3. @interface GifView : UIView  
  4.   
  5. /* 
  6.  * @brief desingated initializer 
  7.  */  
  8. - (id)initWithCenter:(CGPoint)center fileURL:(NSURL*)fileURL;  
  9. - (void)initFileURL:(NSURL*)fileURL;  
  10.   
  11. /* 
  12.  * @brief start Gif Animation 
  13.  */  
  14. - (void)startGif;  
  15. - (void)startGifAnimation;  
  16.   
  17. /* 
  18.  * @brief stop Gif Animation 
  19.  */  
  20. - (void)stopGif;  
  21.   
  22. /* 
  23.  * @brief get frames image(CGImageRef) in Gif 
  24.  */  
  25. + (NSDictionary *)getGifInfo:(NSURL *)fileURL;  
  26. + (NSString *)exportGifImages:(NSArray *)images delays:(NSArray *)delays loopCount:(NSUInteger)loopCount;  
  27.   
  28. @end  


//GifView.m

[cpp] view plaincopy
  1. //  
  2. //  GifView.m  
  3. //  
  4. //  Created by marujun on 13-11-7.  
  5. //  Copyright (c) 2013年 极致. All rights reserved.  
  6. //  
  7.   
  8. #import "GifView.h"  
  9. #import <ImageIO/ImageIO.h>  
  10. #import <QuartzCore/QuartzCore.h>  
  11. #import <MobileCoreServices/MobileCoreServices.h>  
  12.   
  13.   
  14. @interface GifView() {  
  15.     NSMutableArray *_frames;  
  16.     NSMutableArray *_frameDelayTimes;  
  17.   
  18.     CGPoint frameCenter;  
  19.     CADisplayLink *displayLink;  
  20.     int frameIndex;  
  21.     double frameDelay;  
  22.   
  23.     NSUInteger _loopCount;  
  24.     NSUInteger _currentLoop;  
  25.     CGFloat _totalTime;         // seconds  
  26.     CGFloat _width;  
  27.     CGFloat _height;  
  28. }  
  29.   
  30. @end  
  31.   
  32. @implementation GifView  
  33.   
  34.   
  35. - (id)initWithCenter:(CGPoint)center fileURL:(NSURL*)fileURL;  
  36. {  
  37.     self = [super initWithFrame:CGRectZero];  
  38.     if (self) {  
  39.   
  40.         _frames = [[NSMutableArray alloc] init];  
  41.         _frameDelayTimes = [[NSMutableArray alloc] init];  
  42.   
  43.         _width = 0;  
  44.         _height = 0;  
  45.         frameCenter = center;  
  46.         [self initFileURL:fileURL];  
  47.     }  
  48.     return self;  
  49. }  
  50.   
  51. - (void)initFileURL:(NSURL*)fileURL  
  52. {  
  53.     if (fileURL) {  
  54.         getFrameInfo((__bridge CFURLRef)fileURL, _frames, _frameDelayTimes, &_totalTime, &_width, &_height, _loopCount);  
  55.     }  
  56.     self.frame = CGRectMake(0, 0, _width, _height);  
  57.     self.center = frameCenter;  
  58.     self.backgroundColor = [UIColor clearColor];  
  59.     if(_frames && _frames[0]){  
  60.         self.layer.contents = (__bridge id)([_frames[0] CGImage]);  
  61.     }  
  62. }  
  63.   
  64. //使用displayLink播放  
  65. - (void)startGif  
  66. {  
  67.     frameIndex = 0;  
  68.     _currentLoop = 1;  
  69.     frameDelay =[_frameDelayTimes[0] doubleValue];  
  70.   
  71.     [self stopGif];  
  72.     displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(updateDisplay:)];  
  73.     [displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];  
  74. }  
  75. //每秒60帧刷新视图  
  76. - (void)updateDisplay:(CADisplayLink *)link  
  77. {  
  78.     if(frameDelay<=0){  
  79.         frameIndex ++;  
  80.         if(_loopCount!=0){  
  81.             if (_currentLoop>=_loopCount) {  
  82.                 [self stopGif];  
  83.             }else{  
  84.                 _currentLoop ++;  
  85.             }  
  86.         }  
  87.         if(frameIndex>=_frames.count){  
  88.             frameIndex = 0;  
  89.         }  
  90.         frameDelay = [_frameDelayTimes[frameIndex] doubleValue]+frameDelay;  
  91.         self.layer.contents = (__bridge id)([_frames[frameIndex] CGImage]);  
  92.     }  
  93.     frameDelay -= fmin(displayLink.duration, 1);   //To avoid spiral-o-death  
  94. }  
  95.   
  96. - (void)willMoveToSuperview:(UIView *)newSuperview  
  97. {  
  98.     if(newSuperview){  
  99.         [self startGif];  
  100.     }else{  
  101.         [self stopGif];  //视图将被移除  
  102.     }  
  103. }  
  104.   
  105. //使用Animation方式播放Gif  
  106. - (void)startGifAnimation  
  107. {  
  108.     [self stopGif];  
  109.   
  110.     CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"contents"];  
  111.   
  112.     NSMutableArray *times = [NSMutableArray arrayWithCapacity:3];  
  113.     CGFloat currentTime = 0;  
  114.     int count = _frameDelayTimes.count;  
  115.     for (int i = 0; i < count; ++i) {  
  116.         [times addObject:[NSNumber numberWithFloat:(currentTime / _totalTime)]];  
  117.         currentTime += [[_frameDelayTimes objectAtIndex:i] floatValue];  
  118.     }  
  119.     [animation setKeyTimes:times];  
  120.   
  121.     NSMutableArray *images = [NSMutableArray arrayWithCapacity:3];  
  122.     for (int i = 0; i < count; ++i) {  
  123.         [images addObject:(__bridge id)[[_frames objectAtIndex:i] CGImage]];  
  124.     }  
  125.   
  126.     [animation setValues:images];  
  127.     [animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]];  
  128.     animation.duration = _totalTime;  
  129.     animation.delegate = self;  
  130.     if(_loopCount<=0){  
  131.         animation.repeatCount = INFINITY;  
  132.     }else{  
  133.         animation.repeatCount = _loopCount;  
  134.     }  
  135.     [self.layer addAnimation:animation forKey:@"gifAnimation"];  
  136. }  
  137.   
  138. - (void)stopGif  
  139. {  
  140.     [self.layer removeAllAnimations];  
  141.     [self removeDisplayLink];  
  142.   
  143.     if(_frames && _frames[0]){  
  144.         self.layer.contents = (__bridge id)([_frames[0] CGImage]);  
  145.     }  
  146. }  
  147.   
  148. - (void)removeDisplayLink  
  149. {  
  150.     [displayLink removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];  
  151.     [displayLink invalidate];  
  152.     displayLink = nil;  
  153. }  
  154.   
  155. // remove contents when animation end  
  156. - (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag  
  157. {  
  158.     if(_frames && _frames[0]){  
  159.         self.layer.contents = (__bridge id)([_frames[0] CGImage]);  
  160.     }  
  161. }  
  162.   
  163. /* 
  164.  * @brief 获取gif图中每一帧的信息 
  165.  */  
  166. + (NSDictionary *)getGifInfo:(NSURL *)fileURL  
  167. {  
  168.     NSMutableArray *frames = [NSMutableArray arrayWithCapacity:3];  
  169.     NSMutableArray *delays = [NSMutableArray arrayWithCapacity:3];  
  170.     NSUInteger loopCount = 0;  
  171.     CGFloat totalTime;         // seconds  
  172.     CGFloat width;  
  173.     CGFloat height;  
  174.   
  175.     getFrameInfo((__bridge CFURLRef)fileURL, frames, delays, &totalTime, &width, &height, loopCount);  
  176.     NSDictionary *gifDic = @{@"images":frames,          //图片数组  
  177.                              @"delays":delays,          //每一帧对应的延迟时间数组  
  178.                              @"duration":@(totalTime),  //GIF图播放一遍的总时间  
  179.                              @"loopCount":@(loopCount), //GIF图播放次数  0-无限播放  
  180.                              @"bounds": NSStringFromCGRect(CGRectMake(0, 0, width, height))}; //GIF图的宽高  
  181.     return gifDic;  
  182. }  
  183. /* 
  184.  * @brief 指定每一帧播放时长把多张图片合成gif图 
  185.  */  
  186. + (NSString *)exportGifImages:(NSArray *)images delays:(NSArray *)delays loopCount:(NSUInteger)loopCount  
  187. {  
  188.     NSString *fileName = [NSString stringWithFormat: @"%.0f.%@", [NSDate timeIntervalSinceReferenceDate] * 1000.0, @"gif"];  
  189.     NSString *filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:fileName];  
  190.     CGImageDestinationRef destination = CGImageDestinationCreateWithURL((__bridge CFURLRef)[NSURL fileURLWithPath:filePath],  
  191.                                                                         kUTTypeGIF, images.count, NULL);  
  192.     if(!loopCount){  
  193.         loopCount = 0;  
  194.     }  
  195.     NSDictionary *gifProperties = @{ (__bridge id)kCGImagePropertyGIFDictionary: @{  
  196.                                                (__bridge id)kCGImagePropertyGIFLoopCount: @(loopCount), // 0 means loop forever  
  197.                                                }  
  198.                                        };  
  199.     float delay = 0.1; //默认每一帧间隔0.1秒  
  200.     for (int i=0; i<images.count; i++) {  
  201.         UIImage *itemImage = images[i];  
  202.         if(delays && i<delays.count){  
  203.             delay = [delays[i] floatValue];  
  204.         }  
  205.         //每一帧对应的延迟时间  
  206.         NSDictionary *frameProperties = @{(__bridge id)kCGImagePropertyGIFDictionary: @{  
  207.                                                   (__bridge id)kCGImagePropertyGIFDelayTime: @(delay), // a float (not double!) in seconds, rounded to centiseconds in the GIF data  
  208.                                                   }  
  209.                                           };  
  210.         CGImageDestinationAddImage(destination,itemImage.CGImage, (__bridge CFDictionaryRef)frameProperties);  
  211.     }  
  212.     CGImageDestinationSetProperties(destination, (__bridge CFDictionaryRef)gifProperties);  
  213.     if (!CGImageDestinationFinalize(destination)) {  
  214.         NSLog(@"failed to finalize image destination");  
  215.     }  
  216.     CFRelease(destination);  
  217.     return filePath;  
  218. }  
  219.   
  220. /* 
  221.  * @brief resolving gif information 
  222.  */  
  223. void getFrameInfo(CFURLRef url, NSMutableArray *frames, NSMutableArray *delayTimes, CGFloat *totalTime,CGFloat *gifWidth, CGFloat *gifHeight,NSUInteger loopCount)  
  224. {  
  225.     CGImageSourceRef gifSource = CGImageSourceCreateWithURL(url, NULL);  
  226.   
  227.     //获取gif的帧数  
  228.     size_t frameCount = CGImageSourceGetCount(gifSource);  
  229.   
  230.     //获取GfiImage的基本数据  
  231.     NSDictionary *gifProperties = (__bridge NSDictionary *) CGImageSourceCopyProperties(gifSource, NULL);  
  232.     //由GfiImage的基本数据获取gif数据  
  233.     NSDictionary *gifDictionary =[gifProperties objectForKey:(NSString*)kCGImagePropertyGIFDictionary];  
  234.     //获取gif的播放次数 0-无限播放  
  235.     loopCount = [[gifDictionary objectForKey:(NSString*)kCGImagePropertyGIFLoopCount] integerValue];  
  236.     CFRelease((__bridge CFTypeRef)(gifProperties));  
  237.   
  238.     for (size_t i = 0; i < frameCount; ++i) {  
  239.         //得到每一帧的CGImage  
  240.         CGImageRef frame = CGImageSourceCreateImageAtIndex(gifSource, i, NULL);  
  241.         [frames addObject:[UIImage imageWithCGImage:frame]];  
  242.         CGImageRelease(frame);  
  243.   
  244.         //获取每一帧的图片信息  
  245.         NSDictionary *frameDict = (__bridge NSDictionary*)CGImageSourceCopyPropertiesAtIndex(gifSource, i, NULL);  
  246.   
  247.         //获取Gif图片尺寸  
  248.         if (gifWidth != NULL && gifHeight != NULL) {  
  249.             *gifWidth = [[frameDict valueForKey:(NSString*)kCGImagePropertyPixelWidth] floatValue];  
  250.             *gifHeight = [[frameDict valueForKey:(NSString*)kCGImagePropertyPixelHeight] floatValue];  
  251.         }  
  252.   
  253.         //由每一帧的图片信息获取gif信息  
  254.         NSDictionary *gifDict = [frameDict valueForKey:(NSString*)kCGImagePropertyGIFDictionary];  
  255.         //取出每一帧的delaytime  
  256.         [delayTimes addObject:[gifDict valueForKey:(NSString*)kCGImagePropertyGIFDelayTime]];  
  257.   
  258.         if (totalTime) {  
  259.             *totalTime = *totalTime + [[gifDict valueForKey:(NSString*)kCGImagePropertyGIFDelayTime] floatValue];  
  260.         }  
  261.         CFRelease((__bridge CFTypeRef)(frameDict));  
  262.     }  
  263.     CFRelease(gifSource);  
  264. }  
  265.   
  266. - (void)dealloc  
  267. {  
  268.     NSLog(@"%s",__FUNCTION__);  
  269. }  
  270.   
  271. @end  


参考:http://stackoverflow.com/questions/14915138/create-and-and-export-an-animated-gif-via-ios


0 0
原创粉丝点击