gif动图如何裁剪出需要的frame

在如今的项目中纯展示类的项目中如果没有做支持gif的,恐怕连一个demo都不算,更别说做成一个项目了。

现在对很多类库都有成熟的资源,最为常见的sdwebimage都有支持gif的展示问题。可是千变万化的需求不是有限的资源库所能够解决的,例如我们今天的要求,sdwebimage虽然可以展示,但是需要剪切固定frame就不是简单的一句代码可以解决的了。
要做成gif的动图展示需要将动图下载下来,然后将动图按帧取出来。每一帧包含一个image以及每一个image需要战士的time。这样的组合起来的动图就是最初的gif动图。好了,接下来讲讲如何做。

先从网上找来一张gif动图,static NSString *gifUrlStr =@"http://images11.app.happyjuzi.com/content/201607/13/5785f5636cf38.gif";定义出来gif的路径用来下载动图。
然后声明需要展示动图的imageview。

    self.originGif = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 260)];
    _originGif.image = [UIImage imageWithData:gifData];
    [self.view addSubview:_originGif];

上面的gifdata就是需要下载的gif资源了。这里为了展示,就不做代码优化(异步线程下载+硬盘以及内存缓存处理)了。

    NSURL *gifUrl = [NSURL URLWithString:gifUrlStr];
    NSData *gifData= [NSData dataWithContentsOfURL:gifUrl options:NSDataReadingMappedIfSafe error:nil];
    //下面会单独出这个方法
    [self decodeWithData:gifData];

在下载完动图以后我们需要拆分gif,这个时候就需要之前说的存放image和time的两个数组了。

    self.imageSource = [NSMutableArray new];
    self.delayTimeSource = [NSMutableArray new];

接下来才是最重要的,拆分gif

-(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的播放次数
            _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];
                    //在这里可以对单张imageframe做处理然后放到_imageSource数组里面,那么新的gif就会生成。
                    [_imageSource addObject:frameImage];
                    //获取每一帧的图片信息
                    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];
                        [_delayTimeSource addObject:[NSNumber numberWithFloat:delayTime]];
                        //TODO 这里可以实现边解码边回调播放或者把每一帧image和delayTime存储起来
                        CFRelease(frameProperties);
                    }
                    CGImageRelease(img);
                }
            }
            CFRelease(gifProperties);
        }
        CFRelease(src);
        //这个方法是处理展示类型的(例如是否循环,循环次数)
        [self playImageWithIndex];
    }    
}

而在展示动图显示类型里面就用到了一个循环调用的方法。我这里写两种方式,一种可以取消但是必须在主线程操作,一种是使用GCD但是一旦开启就无法取消。

-(void)playImageWithIndex
{
    CGFloat playOneTime = 0;
     __block typeof (self) weakSelf = self;
    playOneTime = [_delayTimeSource[0] floatValue];
//    //GCD方式延迟调用(无法取消)
//    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(playOneTime * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
//        UIImage *image = _imageSource[index];
//        [_originGif setImage:image];
//        
//        NSInteger newIndex = index;
//        if (index<_imageSource.count-1) {
//            newIndex++;
//        }
//        else
//        {
//            newIndex =0;
//        }
//        [weakSelf playImageWithIndex:newIndex];
//    });
    //nstimer的方式调用(可以取消,但必须在主线程调用)
    [timer invalidate];
    timer = nil;
    timer = [NSTimer scheduledTimerWithTimeInterval:playOneTime target:weakSelf selector:@selector(playImageWithIndex) userInfo:nil repeats:NO];
}

以上就是循环调用展示动图,并将动图剪切之后再重新封装成需要的gif的简单代码。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值