前言
- 电商网站中,为保证商品图细节完美展示,图片分辨率总会匹配大屏终端(如 iPhone 6 Plus)
- 若广告位只含一份大图,低分辨率终端需为之付出不必要流量,这延长了图片加载时间
- 此外,运营人员上架商品图时,常常忘记对其进行必要的压缩
- 于是,图片优化可从两方面入手:按需请求尺寸,图片格式压缩
WebP 格式
WebP 是 Google 在 2010 年发布的图片格式,希望以更高的压缩比替代 JPEG。它用 VP8 视频帧内编码作为其算法基础,取得了不错的压缩效果。它支持有损和无损压缩、支持完整的透明通道、也支持多帧动画,并且没有版权问题,是一种非常理想的图片格式。借由 Google 在网络世界的影响力,WebP 在几年的时间内已经得到了广泛的应用。看看你手机里的 App:微博、微信、QQ、淘宝、网易新闻等等,每个 App 里都有 WebP 的身影。Facebook 则更进一步,用 WebP 来显示聊天界面的贴纸动画。
—— 引用自 《ibireme - 移动端图片格式调研》
一些测试
这里,用 七牛云存储 - 图片基础处理,对首页 99 张广告位图片进行不同策略的下载测试
测试脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
|
downloadImage() { if [ ! -f "$2" ]; then wget "$1" -O "$2" fi }
folders=(JPG WEBP JPG750 WEBP750 JPG640 WEBP640 JPG1080 WEBP1080 JPG720 WEBP720)
for folder in ${folders[@]}; do mkdir -p "./${folder}" done
urlBase="http://qiniu.fangqk.com/TEST_IMG"
for i in `seq 0 98`; do fileName="${i}.jpg"
origJPG="./JPG/${fileName}" img_url="${urlBase}/${fileName}" downloadImage "${img_url}" "${origJPG}"
# 使用 identify 命令需安装 imagemagick width_orig=`identify -format "%w" ${origJPG}`
path1="./${folders[1]}/${fileName}" path2="./${folders[2]}/${fileName}" path3="./${folders[3]}/${fileName}" path4="./${folders[4]}/${fileName}" path5="./${folders[5]}/${fileName}" path6="./${folders[6]}/${fileName}" path7="./${folders[7]}/${fileName}" path8="./${folders[8]}/${fileName}" path9="./${folders[9]}/${fileName}"
width_750=$((${width_orig}*750/1242)) width_640=$((${width_orig}*640/1242)) width_1080=$((${width_orig}*1080/1242)) width_720=$((${width_orig}*720/1242))
downloadImage "${img_url}?imageView2/0/format/webp" ${path1} downloadImage "${img_url}?imageView2/2/w/${width_750}" ${path2} downloadImage "${img_url}?imageView2/2/w/${width_750}/format/webp" ${path3/%.jpg/.webp} downloadImage "${img_url}?imageView2/2/w/${width_640}" ${path4} downloadImage "${img_url}?imageView2/2/w/${width_640}/format/webp" ${path5/%.jpg/.webp} downloadImage "${img_url}?imageView2/2/w/${width_1080}" ${path6} downloadImage "${img_url}?imageView2/2/w/${width_1080}/format/webp" ${path7/%.jpg/.webp} downloadImage "${img_url}?imageView2/2/w/${width_720}" ${path8} downloadImage "${img_url}?imageView2/2/w/${width_720}/format/webp" ${path9/%.jpg/.webp} done
echo -e " JPG WEBP JPG750 WEBP750 JPG640 WEBP640 JPG1080 WEBP1080 JPG720 WEBP720" > report.txt echo -e "============================================================================" >> report.txt for folder in ${folders[@]}; do path="./${folder}" size=`du -h "${path}" | cut -f 1` echo -n "${size} " >> report.txt done
echo "" >> report.txt echo -e "============================================================================" >> report.txt for item in ${items}; do for folder in ${folders[@]}; do path="./${folder}/${item}" size=`du -h "${path}" | cut -f 1` echo -n "${size} " >> report.txt done
echo -e "" >> report.txt done
|
测试结果
文件夹 |
说明 |
总大小 |
JPG |
原图(以1242宽度屏幕为标准的JPG) |
7.1M |
WEBP |
同原图尺寸的WebP图片 |
3.6M |
JPG750 |
以750宽度屏幕为标准的JPG |
3.4 M |
WEBP750 |
以750宽度屏幕为标准的WebP |
2.1M |
JPG640 |
以640宽度屏幕为标准的JPG |
2.7M |
WEBP640 |
以640宽度屏幕为标准的WebP |
1.8M |
JPG1080 |
以1080宽度屏幕为标准的JPG |
5.5M |
WEBP1080 |
以1080宽度屏幕为标准的WebP |
3.2M |
JPG720 |
以720宽度屏幕为标准的JPG |
3.2M |
WEBP720 |
以720宽度屏幕为标准的WebP |
2.1M |
在默认压缩配置下,用 Chrome 预览同分辨率的 JPG 和 WebP 图片,肉眼看不出质量差别,体积上 WebP 比 JPG 要小 33%~50%
终端尺寸分布
下面是最近两月的我司应用终端使用汇总
iPhone 分辨率占比
分辨率(宽) |
累计启动次数占比 |
750 |
38.87% |
1242 |
25.98% |
640 |
27.27% |
其他 |
7.88% |
Android 分辨率占比
分辨率(宽) |
累计启动次数占比 |
(1080, ) |
8.52% |
(720, 1080] |
55.42% |
(0, 720] |
36.06% |
iOS 设备与 Android 设备启动次数比例约 17:10
基于上述设备分辨率占比数据,做一些粗略计算
客户端消耗流量 = (iOS平均消耗 x 17 + Android平均消耗 x 10) / 27
1 2 3 4 5 6 7
| JPG按需请求消耗 = ((JPG750 * 38.87% + JPG640 * 27.27% + JPG * 33.86%) * 17 + (JPG1080 * 55.42% + JPG720 * 36.06% + JPG * 8.52%) * 10) / 27 = ((3.4 * 38.87% + 2.7 * 27.27% + 7.1 * 33.86%) * 17 + (5.5 * 55.42% + 3.2 * 36.06% + 7.1 * 8.52%) * 10) / 27 = 4.58M
WebP按需请求消耗 = ((WEBP750 * 38.87% + WEBP640 * 27.27% + WEBP * 33.86%) * 17 + (WEBP1080 * 55.42% + WEBP720 * 36.06% + WEBP * 8.52%) * 10) / 27 = ((2.1 * 38.87% + 1.8 * 27.27% + 3.6 * 33.86%) * 17 + (3.2 * 55.42% + 2.1 * 36.06% + 3.6 * 8.52%) * 10) / 27 = 2.64M
|
客户端方案 |
所需流量 |
节省流量百分比 |
JPG |
7.1M |
0 |
WebP |
3.6M |
49% |
JPG 按需请求尺寸 |
4.58M |
35% |
WebP 按需请求尺寸 |
2.64M |
63% |
可见在 WebP 按需请求尺寸 的策略下效果显著
终端支持
iOS App
想要让原生支持 WebP 很简单,使用 SDWebImage 的基础上,再添加 SDWebImage/WebP
即可
1 2 3
| platform :ios, '6.1' pod 'SDWebImage', '~>3.7' pod 'SDWebImage/WebP'
|
按需请求尺寸,为了简洁的调用,建议对 NSString
做扩展,根据需要返回对应的 NSURL
,示例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| @implementation NSString (MyAdditions)
- (NSURL *)qiniu_imageURL:(int)width { return [NSURL URLWithString:[NSString stringWithFormat:@"%@?imageView2/2/w/%d/format/webp", self, width]]; }
- (NSURL *)qiniu_imageURLWithRatio:(float)ratio { int width = [UIScreen mainScreen].bounds.size.width * [UIScreen mainScreen].scale * ratio; return [self qiniu_imageURL:width]; }
@end
|
更多需要请参考 七牛文档 - 图片基本处理
Android App
Android 4.0+ 原生支持
按需请求尺寸的思路同上,将需要的宽高参数填充到 URL 中。
Web
网页访问跟浏览器核心相关,Android 4.0+ 大部分浏览器支持 WebP,iOS 则都不支持,前端可用以下代码检测其支持能力;对于不支持 WebP 的浏览器,转而请求裁剪后的 JPG 即可
1 2 3 4 5 6
| var webpCapability = false; var img = new Image(); img.onload = function () { webpCapability = (img.width > 0) && (img.height > 0); }; img.src = "data:image/webp;base64,UklGRiIAAABXRUJQVlA4IBYAAAAwAQCdASoBAAEADsD+JaQAA3AAAAAA";
|