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


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

frame(幀):一個gif可以簡單認為是多張image組成的動畫,一幀就是其中一張圖片image.

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

loopCount(播放次數):有些gif播放到一定次數就停止了,如果為0就代表gif一直循環播放。

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

 

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

 

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

-(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停止就行了。這樣是可以實現變解碼邊播放的,並且都是調用系統解碼,效率也不錯。

 

因項目需要,模仿了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;

 

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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM