iOS压缩 gif 图片

最近发现相册可以直接存储、浏览 gif,感觉苹果开始注意 gif,所以总结一下自己的使用方法。一般 gif 在内存比较大,在 cell 上展示会比较卡,所以做下压缩还是很有必要的。查找很多资料也没法下可以直接操作的 api,所有的压缩原理似乎都是对 gif 的每帧图片分别压缩,然后再合成 gif,所以我也是按照这个思路实现了一下。下面直接上代码:

+ (NSData *)scallGIFWithData:(NSData *)data scallSize:(CGSize)scallSize {
  if (!data) {
    return nil;
  }
  CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL);
  size_t count = CGImageSourceGetCount(source);
  
  // 设置 gif 文件属性 (0:无限次循环)
  NSDictionary *fileProperties = [self filePropertiesWithLoopCount:0];
  
  NSString *tempFile = [NSTemporaryDirectory() stringByAppendingString:@"scallTemp.gif"];
  NSFileManager *manager = [NSFileManager defaultManager];
  if ([manager fileExistsAtPath:tempFile]) {
    [manager removeItemAtPath:tempFile error:nil];
  }
  NSURL *fileUrl = [NSURL fileURLWithPath:tempFile];
  CGImageDestinationRef destination = CGImageDestinationCreateWithURL((__bridge CFURLRef)fileUrl, kUTTypeGIF , count, NULL);
  
  NSTimeInterval duration = 0.0f;
  for (size_t i = 0; i < count; i++) {
    CGImageRef imageRef = CGImageSourceCreateImageAtIndex(source, i, NULL);
    UIImage *image = [UIImage imageWithCGImage:imageRef];
    UIImage *scallImage = [self scallImageWidthScallSize:scallSize];
    
    NSTimeInterval delayTime = [self frameDurationAtIndex:i source:source];
    duration += delayTime;
    // 设置 gif 每针画面属性
    NSDictionary *frameProperties = [self framePropertiesWithDelayTime:delayTime];
    CGImageDestinationAddImage(destination, scallImage.CGImage, (CFDictionaryRef)frameProperties);
    CGImageRelease(imageRef);
  }
  CGImageDestinationSetProperties(destination, (CFDictionaryRef)fileProperties);
  // Finalize the GIF
  if (!CGImageDestinationFinalize(destination)) {
    NSLog(@"Failed to finalize GIF destination");
    if (destination != nil) {
      CFRelease(destination);
    }
    return nil;
  }
  CFRelease(destination);
  CFRelease(source);
  return [NSData dataWithContentsOfFile:tempFile];
}

按照 size 压缩每帧图片

- (UIImage *)scallImageWidthScallSize:(CGSize)scallSize{
  CGFloat width = self.size.width;
  CGFloat height = self.size.height;
  
  CGFloat scaleFactor = 0.0;
  CGFloat scaledWidth = scallSize.width;
  CGFloat scaledHeight = scallSize.height;
  CGPoint thumbnailPoint = CGPointMake(0.0,0.0);
  
  if (!CGSizeEqualToSize(self.size, scallSize))
  {
    CGFloat widthFactor = scaledWidth / width;
    CGFloat heightFactor = scaledHeight / height;
    
    scaleFactor = MAX(widthFactor, heightFactor);
    
    scaledWidth= width * scaleFactor;
    scaledHeight = height * scaleFactor;
    
    // center the image
    if (widthFactor > heightFactor)
    {
      thumbnailPoint.y = (scallSize.height - scaledHeight) * 0.5;
    }
    else if (widthFactor < heightFactor)
    {
      thumbnailPoint.x = (scallSize.width - scaledWidth) * 0.5;
    }
  }
  CGRect rect;
  rect.origin = thumbnailPoint;
  rect.size = CGSizeMake(scaledWidth, scaledHeight);
  UIGraphicsBeginImageContext(rect.size);
  [self drawInRect:rect];
  UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
  UIGraphicsEndImageContext();
  return  image;
}

读取帧率

+ (float)frameDurationAtIndex:(NSUInteger)index source:(CGImageSourceRef)source {
  float frameDuration = 0.1f;
  CFDictionaryRef cfFrameProperties = CGImageSourceCopyPropertiesAtIndex(source, index, nil);
  NSDictionary *frameProperties = (__bridge NSDictionary *)cfFrameProperties;
  NSDictionary *gifProperties = frameProperties[(NSString *)kCGImagePropertyGIFDictionary];
  
  NSNumber *delayTimeUnclampedProp = gifProperties[(NSString *)kCGImagePropertyGIFUnclampedDelayTime];
  if (delayTimeUnclampedProp) {
    frameDuration = [delayTimeUnclampedProp floatValue];
  }
  else {
    
    NSNumber *delayTimeProp = gifProperties[(NSString *)kCGImagePropertyGIFDelayTime];
    if (delayTimeProp) {
      frameDuration = [delayTimeProp floatValue];
    }
  }

  if (frameDuration < 0.011f) {
    frameDuration = 0.100f;
  }
  CFRelease(cfFrameProperties);
  frameDuration += 0.1;
  return frameDuration;
}

合成新的 gif, 设置播放属性

+ (NSDictionary *)filePropertiesWithLoopCount:(int)loopCount {
  return @{(NSString *)kCGImagePropertyGIFDictionary:
             @{(NSString *)kCGImagePropertyGIFLoopCount: @(loopCount)}
           };
}

+ (NSDictionary *)framePropertiesWithDelayTime:(NSTimeInterval)delayTime {
  
  return @{(NSString *)kCGImagePropertyGIFDictionary:
             @{(NSString *)kCGImagePropertyGIFDelayTime: @(delayTime)},
           (NSString *)kCGImagePropertyColorModel:(NSString *)kCGImagePropertyColorModelRGB
           };
}

demo

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 1、通过CocoaPods安装项目名称项目信息 AFNetworking网络请求组件 FMDB本地数据库组件 SD...
    阳明AGI阅读 16,009评论 3 119
  • 妈妈,早上好哇。 趁着临近母亲节之际,有些话我想写着送给你。现在你也找到了自己的工作啦,比起以前在家里带着我们,是...
    careful_beb2阅读 160评论 0 0
  • 2018年11.23 星期五 晴6° 文/辣条脸 亲爱的辣条: 嘿,早上好,想跟你说的是,我又迷迷糊...
    辣条脸XX阅读 350评论 4 2
  • 雨鞋是个怎样的存在? 雨鞋是个无敌的存在。 曾经我也有一双属于自己的雨鞋,可是,却早已将它遗忘在记忆的某个角落。此...
    沐梓茜阅读 342评论 0 0