• 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;

    仅供参考。代码整理一下再贴出来。

  • 相关阅读:
    pthread_once函数的简单示例
    pthread_join直接决定资源是否能够及时释放
    非分离线程未使用join函数例子:
    一个HTTP打趴80%面试者
    BM和KMP字符串匹配算法学习
    STL 几个容器的底层实现
    指针的引用(*&)与指针的指针(**)
    Maven 环境变量设置
    配置JAVA的环境变量
    Maven报错 解决方案。ERROR: No goals have been specified for this build. You must specify a valid lifecycle phase or a goal in the format <plugin-prefix>:<goal> or <plugin-group-id>:<plugin-artifact-id
  • 原文地址:https://www.cnblogs.com/vicstudio/p/3339944.html
Copyright © 2020-2023  润新知