前言

  • 电商网站中,为保证商品图细节完美展示,图片分辨率总会匹配大屏终端(如 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
#!/bin/bash
# 可采用 homebrew 安装 imagemagick 及 wget

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";