以前一直听说ios不可以播放gif图片。也没取看看。其实想想有啥不能播放的。只是没有提供现成的api而已。最近看看资料以及别人的例子了解了一下实现原理 特记录一下:
gif 其实本来就是一系列的图片的集合 可以通过 imageIO 获取到图片数组。然后动画播放就ok了;先看一下 简单的例子:
NSURL *url = [[NSBundle mainBundle] URLForResource:@"pika.gif" withExtension:nil];
CGImageSourceRef csf = CGImageSourceCreateWithURL((__bridge CFTypeRef) url, NULL);
size_t const count = CGImageSourceGetCount(csf);
UIImage *frames[count];
CGImageRef images[count];
for (size_t i = 0; i < count; ++i) {
images[i] = CGImageSourceCreateImageAtIndex(csf, i, NULL);
UIImage *image =[[UIImage alloc] initWithCGImage:images[i]];
frames[i] = image;
CFRelease(images[i]);
}
UIImage *const animation = [UIImage animatedImageWithImages:[NSArray arrayWithObjects:frames count:count] duration:0.1];
[view2 setImage:animation];
NSLog(@"xxxx%zu",count);
CFRelease(csf);
有个人的实现原理是这样的:取出gif图片所有桢的时间。 取这些时间的最大公约数 作为显示的的桢的时间。 然后根据新的桢的间隔时间取对应的图片。 这样处理显示的帧数大于等于原始帧数。 如果原始桢的间隔时间太奇葩。 会导致大量的图片是重复的。不过正常使用还是很不错的。
下面是 从code4app上下载的别人的代码 地址已经不记得了。删除了其他的部分 只留下了跟播放动画相关的地方 贴出来参考:
//
// ViewController.m
// test4
//
// Created by Aurora_sgbh on 15-2-6.
// Copyright (c) 2015年 Aurora_sgbh. All rights reserved.
//
#if __has_feature(objc_arc)
#define toCF (__bridge CFTypeRef)
#define fromCF (__bridge id)
#else
#define toCF (CFTypeRef)
#define fromCF (id)
#endif
#import "ViewController.h"
#import
#pragma mark - UIImage Animated GIF
@implementation UIImage (animatedGIF)
static int delayCentisecondsForImageAtIndex(CGImageSourceRef const source, size_t const i) {
int delayCentiseconds = 1;
CFDictionaryRef const properties = CGImageSourceCopyPropertiesAtIndex(source, i, NULL);
if (properties) {
CFDictionaryRef const gifProperties = CFDictionaryGetValue(properties, kCGImagePropertyGIFDictionary);
if (gifProperties) {
NSNumber *number = fromCF CFDictionaryGetValue(gifProperties, kCGImagePropertyGIFUnclampedDelayTime);
if (number == NULL || [number doubleValue] == 0) {
number = fromCF CFDictionaryGetValue(gifProperties, kCGImagePropertyGIFDelayTime);
}
if ([number doubleValue] > 0) {
// Even though the GIF stores the delay as an integer number of centiseconds, ImageIO “helpfully” converts that to seconds for us.
delayCentiseconds = (int)lrint([number doubleValue] * 100);
NSLog(@"看看时间%d",delayCentiseconds);
}
}
CFRelease(properties);
}
return delayCentiseconds;
}
static void createImagesAndDelays(CGImageSourceRef source, size_t count, CGImageRef imagesOut[count], int delayCentisecondsOut[count]) {
for (size_t i = 0; i < count; ++i) {
imagesOut[i] = CGImageSourceCreateImageAtIndex(source, i, NULL);
delayCentisecondsOut[i] = delayCentisecondsForImageAtIndex(source, i);
}
}
static int sum(size_t const count, int const *const values) {
int theSum = 0;
for (size_t i = 0; i < count; ++i) {
theSum += values[i];
}
return theSum;
}
//最大公约数
static int pairGCD(int a, int b) {
if (a < b)
return pairGCD(b, a);
while (true) {
int const r = a % b;
if (r == 0)
return b;
a = b;
b = r;
}
}
static int vectorGCD(size_t const count, int const *const values) {
int gcd = values[0];
for (size_t i = 1; i < count; ++i) {
// 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.
gcd = pairGCD(values[i], gcd);
}
return gcd;
}
static NSArray *frameArray(size_t const count, CGImageRef const images[count], int const delayCentiseconds[count], int const totalDurationCentiseconds) {
int const gcd = vectorGCD(count, delayCentiseconds);
size_t const frameCount = totalDurationCentiseconds / gcd;
UIImage *frames[frameCount];
for (size_t i = 0, f = 0; i < count; ++i) {
UIImage *const frame = [UIImage imageWithCGImage:images[i]];
for (size_t j = delayCentiseconds[i] / gcd; j > 0; --j) {
frames[f++] = frame;
}
}
return [NSArray arrayWithObjects:frames count:frameCount];
}
static void releaseImages(size_t const count, CGImageRef const images[count]) {
for (size_t i = 0; i < count; ++i) {
CGImageRelease(images[i]);
}
}
//xxx
static UIImage *animatedImageWithAnimatedGIFImageSource(CGImageSourceRef const source) {
size_t const count = CGImageSourceGetCount(source);
CGImageRef images[count];
int delayCentiseconds[count]; // in centiseconds
createImagesAndDelays(source, count, images, delayCentiseconds);
int const totalDurationCentiseconds = sum(count, delayCentiseconds);
NSArray *const frames = frameArray(count, images, delayCentiseconds, totalDurationCentiseconds);
UIImage *const animation = [UIImage animatedImageWithImages:frames duration:(NSTimeInterval)totalDurationCentiseconds / 100.0];
releaseImages(count, images);
return animation;
}
static UIImage *animatedImageWithAnimatedGIFReleasingImageSource(CGImageSourceRef CF_RELEASES_ARGUMENT source) {
if (source) {
UIImage *const image = animatedImageWithAnimatedGIFImageSource(source);
CFRelease(source);
return image;
} else {
return nil;
}
}
+ (UIImage *)animatedImageWithAnimatedGIFData:(NSData *)data {
return animatedImageWithAnimatedGIFReleasingImageSource(CGImageSourceCreateWithData(toCF data, NULL));
}
+ (UIImage *)animatedImageWithAnimatedGIFURL:(NSURL *)url {
return animatedImageWithAnimatedGIFReleasingImageSource(CGImageSourceCreateWithURL((__bridge CFTypeRef) url, NULL));
}
@end
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
UIImageView *view =[[UIImageView alloc]initWithFrame:CGRectMake(50, 50, 100, 100)];
[view setImage:[UIImage animatedImageWithAnimatedGIFURL:[[NSBundle mainBundle] URLForResource:@"3.gif" withExtension:nil]]];
//mytest
// UIImageView *view2 =[[UIImageView alloc]initWithFrame:CGRectMake(50, 250, 100, 100)];
// [view2 setBackgroundColor:[UIColor redColor]];
// NSURL *url = [[NSBundle mainBundle] URLForResource:@"pika.gif" withExtension:nil];
// CGImageSourceRef csf = CGImageSourceCreateWithURL((__bridge CFTypeRef) url, NULL);
// size_t const count = CGImageSourceGetCount(csf);
// UIImage *frames[count];
// CGImageRef images[count];
// for (size_t i = 0; i < count; ++i) {
// images[i] = CGImageSourceCreateImageAtIndex(csf, i, NULL);
// UIImage *image =[[UIImage alloc] initWithCGImage:images[i]];
// frames[i] = image;
// CFRelease(images[i]);
// }
//
// UIImage *const animation = [UIImage animatedImageWithImages:[NSArray arrayWithObjects:frames count:count] duration:0.1];
//
// [view2 setImage:animation];
// NSLog(@"xxxx%zu",count);
// CFRelease(csf);
// [self.view addSubview:view2];
[self.view addSubview:view];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end