您的位置:首页 > 移动开发 > IOS开发

ios播放gif图片

2016-06-23 13:28 387 查看
 


ios播放gif图片

2015-03-01 14:11 3689人阅读 评论(0) 收藏 举报


 分类:
 

ios(7) 


版权声明:本文为博主原创文章,未经博主允许不得转载。

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

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

[objc] view
plain copy

 





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上下载的别人的代码 地址已经不记得了。删除了其他的部分 只留下了跟播放动画相关的地方  贴出来参考:

[objc] view
plain copy

 





//  

//  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 <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) {  

                // 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 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) {  

        // 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  

另外也可以通过动画来播放。这样可能不会像上面出现特殊情况下大量重复的桢。不过现实中gif间隔一般都是固定的。所以上面就够用了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: