当今互联网,无论网页还是APP,流量占用最大的,多数都是因为图片,越是良好的用户体验,对图片的依赖度越高。但是图片是一把双刃剑,带来了用户体验,吸引了用户注意,却影响了性能,因为网络请求时间会相对比较长。

图片分很多种,比较主流的就是:位图(BMP),jpg(JPEG,有损压缩格式),png(无损压缩格式)等,这三种,按照图片大小和清晰度来看,依次是:BMP > png > jpg。因为jpg是有损压缩格式,所以jpg图片相对最小。iOS普遍选择的是png来作为最优先选择的图片(苹果官方也是这样建议的)。

不过,有一种图片格式,在大小上比png小,图片质量上跟png差不多,就是WebP。

什么是WebP?

简单描述一下,WebP是google创造出的一种图片格式,图片的压缩和解码都由google提供的API完成(各种语言都有,不过目前好像没看到js可以解码WebP的),在无损压缩的情况下,比png要小28%左右。

现在已经被各大浏览器厂商兼容(如:Chrome,Firefox等),不过苹果的Safri还没有兼容这种格式,所以如果UIWebView里面含有WebP的图片的话,就会显示不出来(但是我们可以通过NSUrlProtocol来做处理)。如果要在APP中使用得话,我们需要引入SDWebImage这个第三方库。

SDWebImage使用WebP

这个第三方库封装得很好,使用起来与我们以前用他来加载网络图片方式一样,如下:

[p_w_picpathView sd_setImageWithURL:[NSURL URLWithString:图片路径] placeholderImage:[UIImage p_w_picpathNamed:@"默认图片"] completed:^(UIImage *p_w_picpath, NSError *error, SDImageCacheType cacheType, NSURL *p_w_picpathURL) { }];

不过,我们要深入看看他究竟是怎么实现的。

我们打开:

SDWebImageDownloaderOperation

这个类继承了NSOperation,主要使用NSUrlSession来下载网络图片,我们来看他下载完成的委托方法:

- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error

我们截取部分代码块来集中分析一下:

UIImage *p_w_picpath = [UIImage sd_p_w_picpathWithData:self.p_w_picpathData];调试进去:UIImage *p_w_picpath;NSString *p_w_picpathContentType = [NSData sd_contentTypeForImageData:data]; //根据数据流的前8位来判断图片类型if ([p_w_picpathContentType isEqualToString:@"p_w_picpath/gif"]) {p_w_picpath = [UIImage sd_animatedGIFWithData:data];}#ifdef SD_WEBP    else if ([p_w_picpathContentType isEqualToString:@"p_w_picpath/webp"]){p_w_picpath = [UIImage sd_p_w_picpathWithWebPData:data]; //将WebP解码成相应的格式(可能是jpg,png等)}#endifelse {p_w_picpath = [[UIImage alloc] initWithData:data];UIImageOrientation orientation = [self sd_p_w_picpathOrientationFromImageData:data];        if (orientation != UIImageOrientationUp) {p_w_picpath = [UIImage p_w_picpathWithCGImage:p_w_picpath.CGImagescale:p_w_picpath.scaleorientation:orientation];}}

  • 我们来说下sd_contentTypeForImageData 这个方法,如下:

+ (NSString *)sd_contentTypeForImageData:(NSData *)data {uint8_t c;[data getBytes:&c length:1];    switch (c) {        case 0xFF:            return @"p_w_picpath/jpeg";        case 0x89:            return @"p_w_picpath/png";        case 0x47:            return @"p_w_picpath/gif";        case 0x49:        case 0x4D:            return @"p_w_picpath/tiff";        case 0x52:            // R as RIFF for WEBPif ([data length] < 12) {                return nil;}NSString *testString = [[NSString alloc] initWithData:[data subdataWithRange:NSMakeRange(0, 12)] encoding:NSASCIIStringEncoding];            if ([testString hasPrefix:@"RIFF"] && [testString hasSuffix:@"WEBP"]) {                return @"p_w_picpath/webp";}            return nil;}    return nil;
}

里面的uint8_t就是取NSData的前8位,因为图片变换成NSData后,是使用得ASCII码来表示的,每种图片都含有固定的头信息块。

png是:89 50 4E 47 0D 0A 1A 0A

bmp是:42 4D

jpg是:FF D8 FF

webp是:52 49 46 46 中间4个字符不定 57 45 42 50(翻译过来就是:RIFF 其他4个字符 WEBP)

这样来看,上面代码的含义就比较清楚了。

如果想深入了解一下图片格式及组成,这里有一篇不错的文章:

http://blog.csdn.net/hherima/article/details/45846901

  • 我们再来看看 sd_p_w_picpathWithWebPData 这个方法

里面封装了将WebP解码成其他格式图片的过程。WebP是采用VP8的编码格式。有兴趣可以研究一下具体的算法实现过程,这里有几篇文章介绍WebP的压缩算法。

https://developers.google.com/speed/webp/docs/compression

http://blog.csdn.net/leixiaohua1020/article/details/12760173

  • 提醒

SDWebImage在对WebP做存储的时候,存的是未解码的NSData,而不是解码后的NSData,如下代码:

SDWebImageManager 里面的if (options & SDWebImageRefreshCached && p_w_picpath && !downloadedImage) {                        // Image refresh hit the NSURLCache cache, do not call the completion block}                    else if (downloadedImage && (!downloadedImage.p_w_picpaths || (options & SDWebImageTransformAnimatedImage))) {dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{UIImage *transformedImage = [self transformDownloadedImage:downloadedImage p_w_picpathData:data withURL:url];   //存储以前,是否要将nsdata转换为其他格式的图片对象if (transformedImage && finished) {BOOL p_w_picpathWasTransformed = ![transformedImage isEqual:downloadedImage];[self.p_w_picpathCache storeImage:transformedImage recalculateFromImage:p_w_picpathWasTransformed p_w_picpathData:(p_w_picpathWasTransformed ? nil : data) forKey:key toDisk:cacheOnDisk];}dispatch_main_sync_safe(^{                                if (strongOperation && !strongOperation.isCancelled) {completedBlock(transformedImage, nil, SDImageCacheTypeNone, finished, url);}});});}                    else {                        if (downloadedImage && finished) {[self.p_w_picpathCache storeImage:downloadedImage recalculateFromImage:NO p_w_picpathData:data forKey:key toDisk:cacheOnDisk];    //WebP的存储走的是这一步}dispatch_main_sync_safe(^{                            if (strongOperation && !strongOperation.isCancelled) {completedBlock(downloadedImage, nil, SDImageCacheTypeNone, finished, url);}});}

里面提供了一个委托:

UIImage *transformedImage = [self transformDownloadedImage:downloadedImage p_w_picpathData:data withURL:url];

也算是用心良苦,因为可能考虑到WebP的解码会耗费一些时间(测试下来发现,120k左右的WebP,解码会耗时30ms左右),所以提供一个委托,可以选择将WebP的NSData转换为png或者jpg之后,再存储到内存,再存储到磁盘。

不过,时间与空间就像鱼和熊掌,不可兼得,如果选择节省时间,就不可避免的要占用更大的空间。到底选时间还是选空间,仁者见仁智者见智吧。

WebP的劣势

把WebP说得这么天花乱坠,但是WebP也是有自己的劣势的:

  1. 压缩时间长,大概是png的8倍左右(不过一般都是在服务端压缩,客户端解码,所以服务端可以做个预压缩)

  2. 解码时间比png长,大概几十毫秒。WebP是节省了流量(图片小),增加了解码时间,换句话说就是:同样的图片,网络越快(图片更小的WebP就没有明显优势),图片越多(WebP要解码),WebP比png要慢。

  3. UIWebView,WKWebView都不支持WebP。(UIWebView可以用NSUrlProtocol来解决,但是WKWebView还没有太完美的办法,谁知道的请告诉我下)

  4. 不支持流式解压缩(即图片加载的时候会由模糊慢慢变清晰的过程,WebP貌似不支持这种解压缩方式)

最后

关于WebP和jpg的图片大小来比较的话,因为WebP是支持无损和有损压缩的,而jpg是有损压缩的格式,所以如果同样的图片都做有损压缩,WebP是比jpg要小的。

转载于:https://blog.51cto.com/huyusheng/1924137

iOS性能之WebP相关推荐

  1. iOS 客户端基于 WebP 图片格式的流量优化(下)

    在iOS 客户端基于 WebP 图片格式的流量优化(上)这篇文章中,已经介绍了WebP格式图片的下载使用,仅仅只有这样还远远不够,还需要对已经下载的图片数据进行缓存. 曾经有句名言『计算机世界有两大难 ...

  2. iOS 性能优化总结

    原文链接:https://github.com/skyming/iOS-Performance-Optimization 关于 iOS 性能优化梳理: 基本工具.业务优化.内存优化.卡顿优化.布局优化 ...

  3. IOS性能调优系列:使用Time Profiler发现性能瓶颈

    硬广:<IOS性能调优系列>第五篇,预计会有二十多篇,持续更新,欢迎关注. 之前四篇都是关注于内存方面,分析了内存泄漏.僵尸对象.内存分配,本篇介绍Time Profiler工具的使用,开 ...

  4. iOS性能优化之耗电量

    iOS性能优化之耗电量 前言 最近在测试App的时候,发现手机特别容易发烫,我们都知道 ,如果手机容易发烫,那么耗电量肯定会相当大,手机电量使用的时间也会相对少:对此,我在工作之余抽了点时间,对手机的 ...

  5. 处理器最新排行_最新 iOS 性能排行榜,你的设备落伍了吗?

    iOS性能排行 近日国内知名跑分软件安兔兔,发布了三月份的 iOS 设备性能排行榜,虽然安兔兔的跑分一直被人质疑不准确,很娱乐. 但毕竟是国内最大且唯一的老牌跑分软件,其得出的综合跑分还是值得参考的. ...

  6. 苹果处理器排行_最新 iOS 性能排行榜,你的设备落伍了吗?

    iOS性能排行 近日国内知名跑分软件安兔兔,发布了三月份的 iOS 设备性能排行榜,虽然安兔兔的跑分一直被人质疑不准确,很娱乐. 但毕竟是国内最大且唯一的老牌跑分软件,其得出的综合跑分还是值得参考的. ...

  7. iOS 性能监控(一)—— CPU功耗监控

    前言 最近,在看戴铭老师关于 "性能监控" 相关的技术分享,感觉收获很多.基于最近的学习,总结了一些性能监控相关的实践,并计划落地一系列 "性能监控" 相关的文 ...

  8. 使用纯 python 实现 Instruments 协议,跨平台 (win,mac,linux) 获取 iOS 性能数据

    原文由YueChen发表于TesterHome社区网站,点击原文链接可与YueChen交流. 前言 获取 iOS 性能数据,一直都是比较麻烦的事情,之前在构建测试框架&平台的时候,获取 iOS ...

  9. IOS性能调优系列:使用Zombies动态分析内存中的僵尸对象

    硬广:<IOS性能调优系列>第四篇,预计会有二十多篇,持续更新,欢迎关注. 前两篇<IOS性能调优系列:Analyze静态分析>.<IOS性能调优系列:使用Instrum ...

最新文章

  1. 读书笔记之《程序员必读的职业规划书》
  2. mysql math.max_Math.max.apply()用法
  3. 从远程服务器拷贝文件命令,远程拷贝文件命令Scp的使用
  4. iOS开发,轻松获取根控制器当前控制器的正确方式
  5. fastclick.js插件使用简单说明
  6. NetBeans Support Weblog
  7. DoIP(三)—— 通信流程
  8. Spring Cloud 快速入门指南(二)
  9. 计算机网络笔记2 应用层
  10. const T 与T const(const T vs.T const的翻译 Dan Saks)
  11. 华为手机信息不弹屏了为什么_华为手机验证码不弹出是怎么回事
  12. 开机弹框显示IGCCTray.exe异常的修复方式
  13. IDEA 一直卡在Buil(编译 write classes)报错资源不足
  14. php 网址尾部带斜杠和不带区别,网址中带斜杠和不带斜杠的区别
  15. 如何解决App inventor和AI伴侣无法连接的问题
  16. 还在为不会做PPT而担忧嘛,有这个PPT神器,从此秒变王者!
  17. 用R检验配对股票的协整性
  18. Catch fox game 抓狐狸Python代码实现
  19. SpringBoot实现多数据源(二)【Mybatis插件】
  20. linux设备巡检指令,Linux系统巡检常用命令

热门文章

  1. Android UI设计与开发】第03期:引导界面(三)仿微信引导界面以及动画效果
  2. swift_021(Swift 的方法)
  3. [计划]二〇〇七年年度计划
  4. MyBatis基于注解的使用
  5. java中static、final、static final的区别
  6. 主要的窗体控件的概述
  7. Alpha冲刺Day4
  8. 2017.10.9 JVM入门学习
  9. PAT 10-2 删除字符串中的子串
  10. 未能加载类型“URLRewriter.ModuleRewriter”。 解决方法