iOS - GIF图的完美拆解、合成、显示
来源:互联网 发布:综艺花字用什么软件做 编辑:程序博客网 时间:2024/04/30 13:46
最近由于项目需要,需要先把gif图拆解开,然后在每一张图片上添加一些图片和文字,最后再合成gif文件;写了一个工具类可以每一帧画面并遵循每一帧所对应的显示时间进行播放,并且可以用多张图片指定每一帧播放时间来合成gif图。下面是使用方法和工具类:(需要添加framework : ImageIO、QuartzCore、MobileCoreServices)
NSDate *date = [NSDate date]; //读取本地GIF图中每一帧图像的信息 NSURL *fileUrl = [[NSBundle mainBundle] URLForResource:@"demo" withExtension:@"gif"]; NSDictionary *dic = [GifView getGifInfo:fileUrl]; NSMutableArray *imageArray = [NSMutableArray array]; //在gif图的每一帧上面添加一段文字 for(int index=0;index<[dic[@"images"] count];index++) { //绘制view 已GIf图中的某一帧为背景并在view上添加文字 UIView *tempView = [[UIView alloc] initWithFrame:CGRectFromString(dic[@"bounds"])]; tempView.backgroundColor = [UIColor colorWithPatternImage:dic[@"images"][index]]; UILabel *tempLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 10, 80, 20)]; tempLabel.text = @"GIF测试"; tempLabel.textColor = [UIColor redColor]; tempLabel.backgroundColor = [UIColor clearColor]; tempLabel.font = [UIFont boldSystemFontOfSize:20]; [tempView addSubview:tempLabel]; //将UIView转换为UIImage UIGraphicsBeginImageContextWithOptions(tempView.bounds.size, NO, tempView.layer.contentsScale); [tempView.layer renderInContext:UIGraphicsGetCurrentContext()]; UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); [imageArray addObject:image]; UIGraphicsEndImageContext(); } //生成GIF图 -- loopCount 为0表示无限播放 NSString *path = [GifView exportGifImages:[imageArray copy] delays:dic[@"delays"] loopCount:0]; //在页面上展示合成之后的GIF图 GifView *gifView = [[GifView alloc] initWithCenter:self.view.center fileURL:[NSURL fileURLWithPath:path]]; [self.view addSubview:gifView]; NSLog(@"合成GIF图用时:%f秒",[[NSDate date] timeIntervalSinceDate:date]);
//GifView.h
#import <UIKit/UIKit.h>@interface GifView : UIView/* * @brief desingated initializer */- (id)initWithCenter:(CGPoint)center fileURL:(NSURL*)fileURL;- (void)initFileURL:(NSURL*)fileURL;/* * @brief start Gif Animation */- (void)startGif;- (void)startGifAnimation;/* * @brief stop Gif Animation */- (void)stopGif;/* * @brief get frames image(CGImageRef) in Gif */+ (NSDictionary *)getGifInfo:(NSURL *)fileURL;+ (NSString *)exportGifImages:(NSArray *)images delays:(NSArray *)delays loopCount:(NSUInteger)loopCount;@end
//GifView.m
//// GifView.m//// Created by marujun on 13-11-7.// Copyright (c) 2013年 极致. All rights reserved.//#import "GifView.h"#import <ImageIO/ImageIO.h>#import <QuartzCore/QuartzCore.h>#import <MobileCoreServices/MobileCoreServices.h>@interface GifView() { NSMutableArray *_frames; NSMutableArray *_frameDelayTimes; CGPoint frameCenter; CADisplayLink *displayLink; int frameIndex; double frameDelay; NSUInteger _loopCount; NSUInteger _currentLoop; CGFloat _totalTime; // seconds CGFloat _width; CGFloat _height;}@end@implementation GifView- (id)initWithCenter:(CGPoint)center fileURL:(NSURL*)fileURL;{ self = [super initWithFrame:CGRectZero]; if (self) { _frames = [[NSMutableArray alloc] init]; _frameDelayTimes = [[NSMutableArray alloc] init]; _width = 0; _height = 0; frameCenter = center; [self initFileURL:fileURL]; } return self;}- (void)initFileURL:(NSURL*)fileURL{ if (fileURL) { getFrameInfo((__bridge CFURLRef)fileURL, _frames, _frameDelayTimes, &_totalTime, &_width, &_height, _loopCount); } self.frame = CGRectMake(0, 0, _width, _height); self.center = frameCenter; self.backgroundColor = [UIColor clearColor]; if(_frames && _frames[0]){ self.layer.contents = (__bridge id)([_frames[0] CGImage]); }}//使用displayLink播放- (void)startGif{ frameIndex = 0; _currentLoop = 1; frameDelay =[_frameDelayTimes[0] doubleValue]; [self stopGif]; displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(updateDisplay:)]; [displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];}//每秒60帧刷新视图- (void)updateDisplay:(CADisplayLink *)link{ if(frameDelay<=0){ frameIndex ++; if(_loopCount!=0){ if (_currentLoop>=_loopCount) { [self stopGif]; }else{ _currentLoop ++; } } if(frameIndex>=_frames.count){ frameIndex = 0; } frameDelay = [_frameDelayTimes[frameIndex] doubleValue]+frameDelay; self.layer.contents = (__bridge id)([_frames[frameIndex] CGImage]); } frameDelay -= fmin(displayLink.duration, 1); //To avoid spiral-o-death}- (void)willMoveToSuperview:(UIView *)newSuperview{ if(newSuperview){ [self startGif]; }else{ [self stopGif]; //视图将被移除 }}//使用Animation方式播放Gif- (void)startGifAnimation{ [self stopGif]; CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"contents"]; NSMutableArray *times = [NSMutableArray arrayWithCapacity:3]; CGFloat currentTime = 0; int count = _frameDelayTimes.count; for (int i = 0; i < count; ++i) { [times addObject:[NSNumber numberWithFloat:(currentTime / _totalTime)]]; currentTime += [[_frameDelayTimes objectAtIndex:i] floatValue]; } [animation setKeyTimes:times]; NSMutableArray *images = [NSMutableArray arrayWithCapacity:3]; for (int i = 0; i < count; ++i) { [images addObject:(__bridge id)[[_frames objectAtIndex:i] CGImage]]; } [animation setValues:images]; [animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]]; animation.duration = _totalTime; animation.delegate = self; if(_loopCount<=0){ animation.repeatCount = INFINITY; }else{ animation.repeatCount = _loopCount; } [self.layer addAnimation:animation forKey:@"gifAnimation"];}- (void)stopGif{ [self.layer removeAllAnimations]; [self removeDisplayLink]; if(_frames && _frames[0]){ self.layer.contents = (__bridge id)([_frames[0] CGImage]); }}- (void)removeDisplayLink{ [displayLink removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; [displayLink invalidate]; displayLink = nil;}// remove contents when animation end- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{ if(_frames && _frames[0]){ self.layer.contents = (__bridge id)([_frames[0] CGImage]); }}/* * @brief 获取gif图中每一帧的信息 */+ (NSDictionary *)getGifInfo:(NSURL *)fileURL{ NSMutableArray *frames = [NSMutableArray arrayWithCapacity:3]; NSMutableArray *delays = [NSMutableArray arrayWithCapacity:3]; NSUInteger loopCount = 0; CGFloat totalTime; // seconds CGFloat width; CGFloat height; getFrameInfo((__bridge CFURLRef)fileURL, frames, delays, &totalTime, &width, &height, loopCount); NSDictionary *gifDic = @{@"images":frames, //图片数组 @"delays":delays, //每一帧对应的延迟时间数组 @"duration":@(totalTime), //GIF图播放一遍的总时间 @"loopCount":@(loopCount), //GIF图播放次数 0-无限播放 @"bounds": NSStringFromCGRect(CGRectMake(0, 0, width, height))}; //GIF图的宽高 return gifDic;}/* * @brief 指定每一帧播放时长把多张图片合成gif图 */+ (NSString *)exportGifImages:(NSArray *)images delays:(NSArray *)delays loopCount:(NSUInteger)loopCount{ NSString *fileName = [NSString stringWithFormat: @"%.0f.%@", [NSDate timeIntervalSinceReferenceDate] * 1000.0, @"gif"]; NSString *filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:fileName]; CGImageDestinationRef destination = CGImageDestinationCreateWithURL((__bridge CFURLRef)[NSURL fileURLWithPath:filePath], kUTTypeGIF, images.count, NULL); if(!loopCount){ loopCount = 0; } NSDictionary *gifProperties = @{ (__bridge id)kCGImagePropertyGIFDictionary: @{ (__bridge id)kCGImagePropertyGIFLoopCount: @(loopCount), // 0 means loop forever } }; float delay = 0.1; //默认每一帧间隔0.1秒 for (int i=0; i<images.count; i++) { UIImage *itemImage = images[i]; if(delays && i<delays.count){ delay = [delays[i] floatValue]; } //每一帧对应的延迟时间 NSDictionary *frameProperties = @{(__bridge id)kCGImagePropertyGIFDictionary: @{ (__bridge id)kCGImagePropertyGIFDelayTime: @(delay), // a float (not double!) in seconds, rounded to centiseconds in the GIF data } }; CGImageDestinationAddImage(destination,itemImage.CGImage, (__bridge CFDictionaryRef)frameProperties); } CGImageDestinationSetProperties(destination, (__bridge CFDictionaryRef)gifProperties); if (!CGImageDestinationFinalize(destination)) { NSLog(@"failed to finalize image destination"); } CFRelease(destination); return filePath;}/* * @brief resolving gif information */void getFrameInfo(CFURLRef url, NSMutableArray *frames, NSMutableArray *delayTimes, CGFloat *totalTime,CGFloat *gifWidth, CGFloat *gifHeight,NSUInteger loopCount){ CGImageSourceRef gifSource = CGImageSourceCreateWithURL(url, NULL); //获取gif的帧数 size_t frameCount = CGImageSourceGetCount(gifSource); //获取GfiImage的基本数据 NSDictionary *gifProperties = (__bridge NSDictionary *) CGImageSourceCopyProperties(gifSource, NULL); //由GfiImage的基本数据获取gif数据 NSDictionary *gifDictionary =[gifProperties objectForKey:(NSString*)kCGImagePropertyGIFDictionary]; //获取gif的播放次数 0-无限播放 loopCount = [[gifDictionary objectForKey:(NSString*)kCGImagePropertyGIFLoopCount] integerValue]; CFRelease((__bridge CFTypeRef)(gifProperties)); for (size_t i = 0; i < frameCount; ++i) { //得到每一帧的CGImage CGImageRef frame = CGImageSourceCreateImageAtIndex(gifSource, i, NULL); [frames addObject:[UIImage imageWithCGImage:frame]]; CGImageRelease(frame); //获取每一帧的图片信息 NSDictionary *frameDict = (__bridge NSDictionary*)CGImageSourceCopyPropertiesAtIndex(gifSource, i, NULL); //获取Gif图片尺寸 if (gifWidth != NULL && gifHeight != NULL) { *gifWidth = [[frameDict valueForKey:(NSString*)kCGImagePropertyPixelWidth] floatValue]; *gifHeight = [[frameDict valueForKey:(NSString*)kCGImagePropertyPixelHeight] floatValue]; } //由每一帧的图片信息获取gif信息 NSDictionary *gifDict = [frameDict valueForKey:(NSString*)kCGImagePropertyGIFDictionary]; //取出每一帧的delaytime [delayTimes addObject:[gifDict valueForKey:(NSString*)kCGImagePropertyGIFDelayTime]]; if (totalTime) { *totalTime = *totalTime + [[gifDict valueForKey:(NSString*)kCGImagePropertyGIFDelayTime] floatValue]; } CFRelease((__bridge CFTypeRef)(frameDict)); } CFRelease(gifSource);}- (void)dealloc{ NSLog(@"%s",__FUNCTION__);}@end
参考:http://stackoverflow.com/questions/14915138/create-and-and-export-an-animated-gif-via-ios
- iOS - GIF图的完美拆解、合成、显示
- iOS - GIF图的完美拆解、合成、显示
- GIF图的合成
- 图片合成gif图 iOS
- ios gif图显示
- gif图片的合成
- IOS gif图片的显示
- iOS中GIF图片的解析+合成
- 完美解决android显示gif
- iOS学习笔记--gif图片合成
- 【python图像处理】gif动态图的解析与合成
- iOS 中 GIF 图片的显示方法
- IOS显示GIF图片
- iOS gif显示
- Android gif图片的解码与合成
- IOS:如何使用多张图片合成GIF
- iOS GIF合成有透明通道图片重叠问题
- IOS中如何显示Gif
- 王垠:清华梦的粉碎—写给清华大学的退学申请(来自shredderyin 的博客)
- 一切皆为 JavaScript
- 2-2:栈的基本操作
- Java线程学习
- 如何看一个企业的成功?
- iOS - GIF图的完美拆解、合成、显示
- 禁止火狐浏览器缓存input标签
- Android 加载布局文件的几种方式
- 关于paypal设置问题
- 简单九步,完成Ubuntu(BackTrack5)下Fcitx中文输入法的安装
- 2-3:stack or queue
- Oil Deposits
- Android gallery 3D效果(扩展Gallery)
- 谈谈对于企业级系统架构的理解