前言
最近要求做一个类似抖音将短视频生成动图在列表进行展示的需求,生成动图最大的好处是用户在列表能够最直观地预览到短视频的大致内容,虽然这个是个用户体验的加分项,但是如果我们不能处理好图片占用空间及清晰度问题,也会带来副作用。
那么,我们该如何权衡呢?
Gif or Webp?
要想使用动图并且图片足够小,当然是用Webp了,图1是gif和webp的对比,可见webp节省了不少空间!这里有篇介绍Webp的经典文章,有兴趣的朋友可以了解下:浓缩的精华!从零开始带你认识最新的图片格式WEBP。
截取视频帧
截取视频一帧关键代码如下:
AVAssetImageGenerator *generator = [[AVAssetImageGenerator alloc] initWithAsset:asset];
generator.appliesPreferredTrackTransform = YES;
//下面两个值设为0表示精确取帧,否则系统会有优化取出来的帧时间间隔不对等
generator.requestedTimeToleranceAfter = kCMTimeZero;
generator.requestedTimeToleranceBefore = kCMTimeZero;
生成Webp
这里推荐一个功能强大的iOS 图像框架:YYImage。
使用YYImageEncoder可以很方便的生成gif或webp动图,实例代码:
YYImageEncoder *gifEncoder = [[YYImageEncoder alloc] initWithType:YYImageTypeWebP];
gifEncoder.loopCount=0;
gifEncoder.quality=0.8;
[gifEncoder addImage:img duration:0.1];
[gifEncoder encodeToFile:filePath];
至此,2个关键技术点讲完了,不妨试试截取几帧生成一个webp试试手......
当你惊喜的发现图片已经生成的同时,也会惊讶的发现图片占用空间依然很大啊。
继续优化
要想尽可能的优化图片空间,只有从两个方面入手:
1、尽可能减少图片帧数
2、尽可能压缩图片
针对第一点,以及参考抖音的效果,我的方案如下:
总共截取9帧图片,前5帧从视频的0.5秒开始,每间隔0.1秒截取一帧;然后倒序再截取4帧,从而形成倒序播放的效果。
针对第二点,首先对图片大小按比例进行裁剪,以最大边长不超过480为依据进行等比压缩,然后设置0.8的有损压缩。
最终方案:
- (void)saveToWebpByVideoPath:(NSURL*)videoUrl webpFilePath:(NSString*)webpFilePath{
YYImageEncoder *gifEncoder = [[YYImageEncoder alloc] initWithType:YYImageTypeWebP];
gifEncoder.loopCount=0;
gifEncoder.quality=0.8;
AVURLAsset*asset = [[AVURLAssetalloc]initWithURL:videoUrloptions:nil];
int64_t scale = asset.duration.timescale;
AVAssetImageGenerator *generator = [[AVAssetImageGenerator alloc] initWithAsset:asset];
generator.appliesPreferredTrackTransform = YES;
//下面两个值设为0表示精确取帧,否则系统会有优化取出来的帧时间间隔不对等
generator.requestedTimeToleranceAfter = kCMTimeZero;
generator.requestedTimeToleranceBefore = kCMTimeZero;
for(inti =0; i <=4; i++) {
CGFloatstarttime = i*0.1+0.5;
CMTimetime =CMTimeMakeWithSeconds(starttime, (int)scale);
NSError*error =nil;
CMTimeactualTime;
CGImageRefimage = [generatorcopyCGImageAtTime:timeactualTime:&actualTimeerror:&error];
UIImage* img = [UIImageimageWithCGImage:image];
img = [selfresizeToMaxHeight:480img:img];
[gifEncoderaddImage:imgduration:0.1];
CGImageRelease(image);
}
for(inti=3; i>=0; i--) {
CGFloatstarttime = i*0.1+0.5;
CMTimetime =CMTimeMakeWithSeconds(starttime, (int)scale);
NSError*error =nil;
CMTimeactualTime;
CGImageRefimage = [generatorcopyCGImageAtTime:timeactualTime:&actualTimeerror:&error];
UIImage* img = [UIImageimageWithCGImage:image];
img = [selfresizeToMaxHeight:480img:img];
[gifEncoderaddImage:imgduration:0.1];
CGImageRelease(image);
}
[gifEncoderencodeToFile:webpFilePath];
NSLog(@"生成webp成功!");
}
- (UIImage*)resizeToMaxHeight:(CGFloat)height img:(UIImage*)img{
if(img.size.width
if(img.size.height>height) {
CGSizenewSize =CGSizeMake(height*1.0*img.size.width/img.size.height, height);
img = [imgyy_imageByResizeToSize:newSize contentMode:UIViewContentModeScaleToFill];
}
}
else{
if(img.size.width>height) {
CGSizenewSize =CGSizeMake(height,img.size.height*height*1.0/img.size.width);
img = [imgyy_imageByResizeToSize:newSize contentMode:UIViewContentModeScaleToFill];
}
}
returnimg;
}