2015-03-01 14:11 3689人阅读 收藏 举报
以前一直听说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的例子就出来了。不过毫无疑问。这么写有很大的问题。原因在于gif 每一桢之间的间隔时间是可以设置的。甚至可以不同。所以需要做些处理
有个人的实现原理是这样的:取出gif图片所有桢的时间。 取这些时间的最大公约数 作为显示的的桢的时间。 然后根据新的桢的间隔时间取对应的图片。 这样处理显示的帧数大于等于原始帧数。 如果原始桢的间隔时间太奇葩。 会导致大量的图片是重复的。不过正常使用还是很不错的。
下面是 从code4app上下载的别人的代码 地址已经不记得了。删除了其他的部分 只留下了跟播放动画相关的地方 贴出来参考:
-
-
-
-
-
-
-
- #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 <ImageIO/ImageIO.h>
- #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) {
-
- 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 constconst *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 constconst *const values) {
- int gcd = values[0];
- for (size_t i = 1; i < count; ++i) {
-
- 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]);
- }
- }
-
-
- static UIImage *animatedImageWithAnimatedGIFImageSource(CGImageSourceRef const source) {
- size_t const count = CGImageSourceGetCount(source);
- CGImageRef images[count];
- int delayCentiseconds[count];
- 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]]];
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- [self.view addSubview:view];
-
- }
-
- - (void)didReceiveMemoryWarning {
- [super didReceiveMemoryWarning];
-
- }
-
- @end
另外也可以通过动画来播放。这样可能不会像上面出现特殊情况下大量重复的桢。不过现实中gif间隔一般都是固定的。所以上面就够用了。