iOS由ImageIO.framework實現gif的系統解碼

首先先簡單介紹一下gif的幾個算是術語吧:async

frame(幀):一個gif能夠簡單認爲是多張image組成的動畫,一幀就是其中一張圖片image.oop

frameCount(幀數): 就是一個gif有多少幀學習

loopCount(播放次數):有些gif播放到必定次數就中止了,若是爲0就表明gif一直循環播放。動畫

delayTime(延遲時間):每一幀播放的時間,也就是說這幀顯示到delayTime就轉到下一幀。url

 

因此gif播放主要就是把每一幀image解析出來,而後每一幀顯示它對應的delaytime,而後再顯示下一張。如此循環下去。spa

 

下面是純粹實現由系統提供的解碼:code

-(void)decodeWithFilePath:(NSString *)filePath

{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^() {

        NSData *data = [NSData dataWithContentsOfFile:self.path];

        [self decodeWithData:data];

    });

}

-(void)decodeWithData:(NSData *)data
{
    CGImageSourceRef src = CGImageSourceCreateWithData((CFDataRef) data, NULL);
    if (src)
    {
        //獲取gif的幀數
        NSUInteger frameCount = CGImageSourceGetCount(src);
        //獲取GfiImage的基本數據
        NSDictionary *gifProperties = (NSDictionary *) CGImageSourceCopyProperties(src, NULL);
        if(gifProperties)
        {
            //由GfiImage的基本數據獲取gif數據
            NSDictionary *gifDictionary =[gifProperties objectForKey:(NSString*)kCGImagePropertyGIFDictionary];
            //獲取gif的播放次數
            NSUInteger loopCount = [[gifDictionary objectForKey:(NSString*)kCGImagePropertyGIFLoopCount] integerValue];
            for (NSUInteger i = 0; i < frameCount; i++)
            {
                 //獲得每一幀的CGImage
                CGImageRef img = CGImageSourceCreateImageAtIndex(src, (size_t) i, NULL);
                if (img)
                {
                    //把CGImage轉化爲UIImage
                    UIImage *frameImage = [UIImage imageWithCGImage:img];
                    //獲取每一幀的圖片信息
                    NSDictionary *frameProperties = (NSDictionary *) CGImageSourceCopyPropertiesAtIndex(src, (size_t) i, NULL);
                    if (frameProperties)
                    {
                        //由每一幀的圖片信息獲取gif信息
                        NSDictionary *frameDictionary = [frameProperties objectForKey:(NSString*)kCGImagePropertyGIFDictionary];
                        //取出每一幀的delaytime
                        CGFloat delayTime = [[frameDictionary objectForKey:(NSString*)kCGImagePropertyGIFDelayTime] floatValue];
//TODO 這裏能夠實現邊解碼邊回調播放或者把每一幀image和delayTime存儲起來 CFRelease(frameProperties); } CGImageRelease(img); } } CFRelease(gifProperties); } CFRelease(src); } }

 

 

上面咱們能夠看到系統解碼已經把每一幀的image和delayTime解析出來,而且能知道gif一共的幀數和播放次數。因此咱們實現gif播放就是啓動一個timer,能夠以一個適當的時間運行,若是發現time激活的時間間隔大於這一幀的delayTime,就把image換成下一幀。如此循環,固然,若是loopCount大於0,而且播放次數大於loopCount,就把timer中止就好了。這樣是能夠實現變解碼邊播放的,而且都是調用系統解碼,效率也不錯。blog

 

因項目須要,模仿了SDWebImage實現了一個UIImageView的category,只須要提供一個路徑就能實現gif的邊解碼邊播放,而不用考慮timer或者其餘處理事件,而且由於是category,因此不直接用UIImageView便可。插一句,SDWebImage這個開源庫的封轉方法是蠻值得學習的。事件

@interface UIImageView(GifImageView)<GifPlayerDelegate>

- (void)setGifFilePath:(NSString*)filePath;
- (void)setGifFilePath:(NSString*)filePath placeholderImage:(UIImage *)placeholder;
- (void)setGifFilePath:(NSString*)filePath placeholderImage:(UIImage *)placeholder failure:(GifPlayerError)error;

- (void)setGifUrlString:(NSString*)urlString;
- (void)setGifUrlString:(NSString*)urlString placeholderImage:(UIImage *)placeholder;
- (void)setGifUrlString:(NSString*)urlString placeholderImage:(UIImage *)placeholder failure:(GifPlayerError)error;

-(void)gifPasue;
-(void)gifResume;
-(void)gifStop;

 

僅供參考。代碼整理一下再貼出來。圖片

相關文章
相關標籤/搜索