silence-cnblogs

SDWebImage 加载显示 WebP 与性能问题

本文包含自定义下载操作 SDWebImageDownloaderOperation 与编码器 SDWebImageCoder。SDWebImage 的版本为 4.2.3。

静态图片

对于静态图片来说,WebP 比 PNG 体积小,可以省流量,但是解码时间长。如果不需要 WebP 的原图数据,可以把 WebP 静态图片保存为 PNG 或 JPEG,加快解码速度。这一步可以通过自定义下载操作 SDWebImageDownloaderOperation 实现。

SDWebImageDownloaderOperation 的 URLSession:task:didCompleteWithError: 方法会把下载好的原图数据 imageData 通过 callCompletionBlocksWithImage:imageData:error:finished: 方法传给上层的回调 SDWebImageDownloaderCompletedBlock。

可以自定义 SDWebImageDownloaderOperation,修改 URLSession:task:didCompleteWithError: 方法,在上图箭头所指处修改 imageData,把静态 WebP 图片数据转为 PNG 或 JPEG 图片数据。修改上述方法只需要添加一行代码

imageData = [[SDWebImageCodersManager sharedInstance] encodedDataWithImage:image format:SDImageFormatUndefined];

原图数据有 Alpha 信息就转为 PNG,否则转为 JPEG。

自定义的类是 ImageDownloaderOperation,使用这个类需要一行代码

[[SDWebImageManager sharedManager].imageDownloader setOperationClass:[ImageDownloaderOperation class]];

动态图片

WebP 格式支持动态图片。SDWebImageWebPCoder 的 decodedImageWithData: 负责解码,返回 UIImage。如果是动态图片,每一帧图片都会解码,用所有图片帧和总动画时长通过 animatedImageWithImages:duration: 方法生成 UIImage。这样做的好处是,节省 CPU 资源,不用重复解码。对小图片来说,比较合适。如果图片太大,就会占内存多。另外,如果原图的每一帧动画时长不相等,那么实际播放的动画就与原图动画不符。可以用 YYImage 和 YYAnimatedImageView 来显示动态 WebP。这样可以用 CPU 资源换取内存空间(YYImage 也可以预先解码所有图片帧),也可以根据原图的每一帧动画时长来播放动画。直接使用 YYWebImage 框架是最方便的方法。然而,如果项目中需要统一图片的下载、缓存管理等操作,最好只用一套图片下载库。这里介绍用 SDWebImage 下载、缓存,用 YYImage 显示 WebP 的方法。

YYImage 会对 WebP 进行解码,因此不需要 SDWebImageWebPCoder 解码所有图片帧。自定义编码器 SDWebImageCoder,只对第一帧图片进行解码,减少解码时间。修改 decodedImageWithData: 方法,在解码每一帧图片的 while 循环中 (下图箭头所指处) 添加 break 即可,解码成功一帧图片就退出循环。

自定义编码器的类是 FirstFrameWebPCoder,使用这个编码器

[SDWebImageCodersManager sharedInstance].coders = @[[SDWebImageImageIOCoder sharedCoder],
                                                    [FirstFrameWebPCoder sharedCoder]];

加载显示图片 (cell.imageView 是 YYAnimatedImageView)

cell.imageView.image = placeholder;
[[SDWebImageManager sharedManager] loadImageWithURL:url options:0 progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) {
    if ([image isKindOfClass:[YYImage class]]) {
        cell.imageView.image = image;
    } else if (data) {
        YYImage *yyimage = [YYImage imageWithData:data];
        cell.imageView.image = yyimage;
        NSString *key = [[SDWebImageManager sharedManager] cacheKeyForURL:url];
        [[SDWebImageManager sharedManager].imageCache storeImage:yyimage forKey:key toDisk:NO completion:nil];
    }
}];

代码已上传 GitHub:https://github.com/Silence-GitHub/WebPDemo

转载请注明出处:http://www.cnblogs.com/silence-cnblogs/p/8319917.html

分类:

技术点:

iOS

相关文章: