注明:本人原创翻译,原版为Essential Image Optimization电子书,这里将其拆分为几篇文章发布。另外,文中部分链接可能会因为“网络”原因无法打开。不必着急,我会慢慢将其中一些比较好的内容翻译过来发表,都会在这个“Web图像技术深究”专题中。
目录
- 介绍
- 如何判断我的图像是否需要优化?
- 如何选择正确的图像格式?
- “素人”JPEG
- JPEG的压缩模式
-
什么是WebP?
- WebP的表现如何?
- 谁在生产环境中使用WebP?
- WebP编码如何执行?
- WebP的浏览器支持
- 如何将我的图像转换为WebP?
- 如何在我的操作系统上查看WebP图像?
- 如何提供WebP?
- SVG优化
- 避免使用有损编解码器重复压缩图像
-
减少不必要的图像解码和尺寸调整带来的损耗
- 使用srcset提供HiDPI图像
- 艺术化的响应
- 颜色管理
- 图像拼合技术
- 延迟加载非关键图像
- 避免<code>display: none;</code>的陷阱
- 图像CDN服务对你有意义吗?
- 缓存图像资源
- 预加载关键图像资源
- 图像的网络性能预算
- 最后的建议
- 附注
正文:
什么是WebP?
WebP是一个来自Google的新型图像格式,它旨在以可接受的视觉质量提供较低文件大小的无损和有损压缩。另外,WebP还包括了对alpha通道透明度和动画的支持。
在过去一年中,WebP在有损和无损模式下减少了10%的压缩体积,并且提高了10%的压缩速度。WebP并不是一个能够用于所有目的的工具,但它在图像压缩社区中已经具有了一定的地位和不断增长的用户群。那么,我们来看看为什么。
WebP:不同质量级别下文件体积和相似度对比。
WebP的表现如何?
有损压缩
根据WebP团队的描述,使用VP8或VP9视频关键帧编码进行处理的WebP压缩文件平均比JPEG文件小了25-34%。
在较低质量设置(0~50)下,WebP具有比JPEG更大的优势,因为它可以消除丑陋的块状伪影;在中等质量设置(-m 4 -q 75)下,WebP则是速度与体积平衡的默认选择;而在较高质量设置(80-99)时,WebP的优势则在缩小。WebP被推荐应用在速度比质量更重要的场景中。
无损压缩
WebP无损文件的体积比PNG文件小了26%;同时,WebP无损压缩图片的加载时间与PNG相比减少了3%。也就是说,您通常不会想在网络上为您的用户提供无损压缩的图像。另外,无损和锐利边缘(如non-JPEG)是不同的。无损模式的WebP可能更适合于档案内容。
透明度
WebP具有一个无损8位透明度通道,而只比PNG多出22%的字节。它还支持有损的RGB透明度,这是WebP独有的功能。
元数据
WebP文件格式支持EXIF照片元数据和XMP数字文档元数据,它还包含了一个ICC颜色配置文件。
WebP提供了更好的压缩,但代价是更多的CPU开销。在2013年,WebP的压缩速度会比JPEG慢10倍,但是现在已经可以忽略不计了(有些图像可能会减慢2倍)。当WebP用于生产作为你应用构建一部分的静态图像时,这不应该是一个大问题。然而,作为动态的图像生产工具,就可能会导致可察觉的CPU开销,这将是您需要考量的问题。
注意:WebP有损质量设置百分比,与JPEG的质量百分比并不能直接比较。因为WebP通过丢弃更多数据来实现更小的文件体积,因此“70%质量”的JPEG将与“70%质量”的WebP图像完全不同。
谁在生产环境中使用WebP?
许多大型公司正在生产环境中使用WebP,来降低成本并减少网页的加载时间。
Google的报告表明,以一天提供430亿图像请求来计算,使用WebP有损压缩将比其他有损压缩解决方案节省30%~35%的存储空间,而使用无损压缩则是节省26%。这种空间的节省无疑是非常重要的。而如果浏览器对WebP支持更好、更广泛,节省将会更大。Google已经将WebP应用于Google Play和YouTube等网站的生产环境。
Netflix、亚马逊、Quora、雅虎、沃尔玛、Ebay、“卫报”、“财富”和“今日美国”均是为已经支持格式的浏览器提供了WebP。VoxMedia 通过给他们使用Chrome的用户提供WebP,将The Verge网站(一个美国科技媒体网站) 减少了1~3倍的加载时间。500px则表示,通过切换为WebP提供给自己的Chrome用户,在保持类似或更好的图像质量的同时将文件的体积平均降低的25%。
这个样本列表显示,有很多的公司都使用WebP。
WebP在Google的应用:在YouTube、Google Play、Chrome的Data Saver以及G+(Google+,Google的社交网络服务)上,每日响应430亿的WebP请求。
WebP编码如何执行?
WebP的有损编码被设计用于与JPEG静态图像进行竞争。它有三个关键流程:
宏块分解:将图像分解成一个16×16亮度像素(宏)块集合和两个8×8色度像素块集合。这可能听起来很像JPEG的方法,通过色彩空间转换、色度通道下采样和图像细分来处理。
预测:宏块的每个4×4子块都具有一个预测模型,可以有效地进行滤波。它定义了一个块周围的两组像素,分别为A(上面的行)和L(左侧的列)。编码器会使用这两个像素块A和L,尝试填充4x4像素的测试块,并确定哪个像素块创建的测试块最接近原始块的值。Colt McAnlis在他的文章“WebP有损耗模式的工作原理”中更深入地讨论了这一点。
最后会使用离散余弦变换(DCT)执行几步类似于JPEG编码的过程。之间的一个关键区别是,这里会使用一个算术压缩器,不同于JPEG的霍夫曼编码。
如果您想深入了解WebP的压缩技术,Google开发人员的文章“ WebP压缩技术”将帮助你。
WebP的浏览器支持
不是所有的浏览器都支持WebP,然而根据CanIUse.com的统计,WebP的浏览器用户支持在全球约为74%。Chrome和Opera本地支持它。Safari,Edge和Firefox已经尝试了它,但没有在官方发行版中发布。这就将为用户获取WebP图片的任务移交给了前端开发人员,这个稍后再说。
以下是主要的浏览器和WebP的支持情况:
- Chrome:Chrome在第23版开始全面支持。
- Chrome for Android:自Chrome 50起。
- Android:自Android 4.2起。
- Opera: 从12.1版本起。
- Opera Mini:所有版本。
- Firefox:一些beta支持。
- Edge:一些beta支持。
- Internet Explorer:不支持。
- Safari:一些beta支持。
WebP不是没有缺点的。它缺乏全分辨率的颜色空间选项,并且不支持逐行解码(渐进式)。总的来说,WebP工具是一个适合的、浏览器支持的(写作时仅限于Chrome和Opera浏览器)、可能会覆盖足够的用户的值得你去考虑的压缩选项。
怎样将图片转换为WebP格式?
一些商业和开源的图像编辑处理软件都支持WebP格式。其中有个特别有用的应用叫做XnConvert,一个免费的、跨平台的批量图片转换器。
注意: 一定要避免将低质量或一般质量的JPEG转换为WebP。这是一个很常见的错误,它会导致生成的WebP图片带有JPEG压缩产生的虚影效果。还会使保存的WebP图片效果变差和失真,甚至损失的质量会翻倍。作为转换初始的图像文件,一定要是高质量的,或者原图。
XnConvert能够批量的进行图像处理,并兼容500多种图像格式。你可以组合超过80种的独立操作,以多种方式转换或编辑的图像。
XnConvert支持批量的图像优化,允许原图到WebP或其他格式的直接转换。除了压缩,XnConvert还可以执行图像元数据剥离、裁剪、颜色深度定制以及其他转换等操作。
下面是XnView网站上列出的XnConvert的一些选项,包括:
- 元数据:编辑
- 转换:旋转、裁剪、调整尺寸
- 调整:亮度、对比度、饱和度
- 过滤器:模糊、浮雕、锐化
- 效果:屏蔽、水印、渐晕
使用XnConvert,你可以导出为大约70种不同的文件格式,包括WebP。它支持Linux、Mac以及Windows操作系统。因此,我们强烈推荐XnConvert,它特别适合小企业。
Node模块
Imagemin是一个非常流行的Node.js的图像缩小模块,它还包含了一个WebP转换插件(imagemin-webp)。支持有损和无损两种模式。
要安装imagemin和imagemin-webp,需要运行:
> npm install --save imagemin imagemin-webp
然后,我们可以使用require()调用这两个模块,并且运行它们处理在项目目录中的任意图片(如JPEG)。下面是使用Imagemin,有损压缩并批量生成质量为60的WebP图片:
const imagemin = require('imagemin');
const imageminWebp = require('imagemin-webp');
imagemin(['images/*.{jpg}'], 'images', {
use: [
imageminWebp({quality: 60})
]
}).then(() => {
console.log('Images optimized');
});
与JPEG类似,要注意到输出后的压缩效果。评估什么样质量设置,对你的图像才是有意义的。Imagemin-webp还可通过传递lossless: true
选项,来生成无损压缩的WebP图像(支持24位颜色和全透明度):
const imagemin = require('imagemin');
const imageminWebp = require('imagemin-webp');
imagemin(['images/*.{jpg,png}'], 'build/images', {
use: [
imageminWebp({lossless: true})
]
}).then(() => {
console.log('Images optimized');
});
这里还有一个由Sindre Sorhus基于imagemin-webp构建的Gulp的WebP插件;当然,也包括WebPack的插件。Gulp插件可以接收imagemin的任何选项设置,如有损压缩:
const gulp = require('gulp');
const webp = require('gulp-webp');
gulp.task('webp', () =>
gulp.src('src/*.jpg')
.pipe(webp({
quality: 80,
preset: 'photo',
method: 6
}))
.pipe(gulp.dest('dist'))
);
或无损压缩:
const gulp = require('gulp');
const webp = require('gulp-webp');
gulp.task('webp-lossless', () =>
gulp.src('src/*.jpg')
.pipe(webp({
lossless: true
}))
.pipe(gulp.dest('dist'))
);
使用Bash批量优化图像
XNConvert支持批量的图像压缩,但是如果你希望避免使用一个应用程序或者一套构建系统,那么可以使用bash命令和图像优化二进制文件,它们同样使压缩变得简单。
你可以使用cwebp命令,将图像批量转换为WebP:
find ./ -type f -name '*.jpg' -exec cwebp -q 70 {} -o {}.webp \;
或者,使用jpeg-recompress采用MozJPEG编码,批量优化您的原图:
find ./ -type f -name '*.jpg' -exec jpeg-recompress {} {} \;
并且,使用svgo优化SVG(我们稍后将介绍):
find ./ -type f -name '*.svg' -exec svgo {} \;
Jeremy Wagner有一篇文章《使用Bash优化图像》比较全面的讨论这个问题,同时还有个姊妹篇《使用Bash快速优化图像》也值得读一下。
其他的WebP图像处理和编辑应用程序包括:
- Leptonica — 一个开源图像处理和图像分析的应用网站。
- Sketch支持直接导出WebP格式
- GIMP — 免费、开源的Photoshop替代品。一个图像编辑器。
- ImageMagick — 用于创建、设计、转换或编辑位图图像,一个免费的命令行应用。
- Pixelmator — 适用于Mac的商用图像编辑器。
- Photoshop的WebP插件 — 免费的,支持图像导入和导出,来自于Google。
Android: 您可以使用Android Studio将现有的BMP、JPG、PNG或静态GIF图像转换为WebP格式。有关更多信息,请参阅使用Android Studio创建WebP图像。
如何在我的操作系统上浏览WebP图像?
当你将WebP图像拖放到基于Blink的浏览器(Chrome、Opera、Brave)中进行预览时,你还可以使用Mac或Windows的附加组件直接从操作系统预览它们。
几年前,当Facebook试验WebP格式时发现,用户将WebP图片通过右键另存到本地磁盘后,无法通过浏览器以外的程序打开浏览。这其中主要有三个主要问题:
- “另存为”但无法在本地浏览WebP图片。这个可以通过将Chrome注册为“.webp”的打开应用来解决。
- “另存为”并将图片加入邮件中分享给不适用Chrome的其他人。Facebook通过引入一个醒目的“下载”按钮来解决这个问题,这个按钮点击时会返回JPEG给用户。
- 右键 > 复制链接 -> 分享链接到网络上。这个最后通过HTTP通讯协议中的content-type来解决。
这些问题可能对你的用户来说不太重要,但是对于WebP图片的通用性,Facebook的试验过程可谓是一个有趣的注解。值得庆幸的是,现在不同的操作系统上,都有用于查看和使用WebP的实用程序了。
在Mac上,可以使用Quick Look的WebP插件(qlImageSize)。它工作的很好:
如何提供WebP?
在不支持WebP的浏览器中,WebP图像最终不会显示,这明显不是我们想要的。为了避免这种情况,我们可以使用几种策略根据浏览器支持情况有条件地提供WebP图像服务。
Chrome的开发者工具中的网络面板中“类型”一栏显示,网站对Blink内核的浏览器返回了WebP格式。
可以看到Google Play对Blink内核浏览器返回WebP的同时,对于像Firefox这样不支持WebP的浏览器返回JPEG。
以下是从服务端返回WebP给你的用户的几个方案:
使用 .htaccess配置来提供WebP的副本
下面将说明当在服务器上存在与JPEG或PNG图像相匹配的.webp版本时,如何使用.htaccess文件将WebP文件提供给支持的浏览器。
Vincent Orback推荐使用如下方法:
浏览器可以通过Header中指定Accept来显式的指定WebP支持。通过这个标识,你就可以控制你的服务端,返回图像的WebP版本(如果这个WebP图像已经储存在磁盘上,而不是JPEG或PNG格式)。这个方法并不总是有效(例如,对于静态化的网站,如Github或S3),所以在选择这种方案时请先检查下它对于你的网站是否有效。
以下是Apache Web服务器的.htaccess文件示例:
<IfModule mod_rewrite.c>
RewriteEngine On
# Check if browser support WebP images
RewriteCond %{HTTP_ACCEPT} image/webp
# Check if WebP replacement image exists
RewriteCond %{DOCUMENT_ROOT}/$1.webp -f
# Serve WebP image instead
RewriteRule (.+)\.(jpe?g|png)$ $1.webp [T=image/webp,E=accept:1]
</IfModule>
<IfModule mod_headers.c>
Header append Vary Accept env=REDIRECT_accept
</IfModule>
AddType image/webp .webp
如果页面上显示的.webp图像有问题,那么请确保在服务器上启用了image/webp类型支持。开启方法如下:
Apache:将以下代码添加到.htaccess文件中:
AddType image/webp .webp
Nginx:将以下代码添加到您的mime.types文件中:
image/webp webp;
注意:Vincent Orback提供了一个htaccess配置示例,可以作为参考;Ilya Grigorik维护一组用于为WebP提供服务配置脚本。
使用 <picture>
标签
浏览器本身能够通过使用<picture>
标签,来选择要显示的图像格式。<picture>
标签利用多个<source>
和一个<img>
来设置显示的图像,其中<img>
是包含了图像的、真实的DOM元素。浏览器会循环遍历<source>
提供的链接,并检索到第一个匹配的结果。如果用户的浏览器中不支持<picture>
,浏览器将会将它渲染为一个<div>
,并使用其中的<img>
。
注意: 注意
<source>
的排列顺序。不要将image/webp的格式放在旧格式的后面,而是将它们放在前面。浏览器将会先解析到它们并得到匹配,而不会解析到其他支持更广泛的格式。如果物理尺寸相同(不使用media
属性),也可以按照文件大小的顺序放置图像。一般来说,解析的顺序就是摆放的顺序。
以下是一些HTML示例:
<picture>
<source srcset="/path/to/image.webp" type="image/webp">
![](/path/to/image.jpg)
</picture>
<picture>
<source srcset='paul_irish.jxr' type='image/vnd.ms-photo'>
<source srcset='paul_irish.jp2' type='image/jp2'>
<source srcset='paul_irish.webp' type='image/webp'>
![](paul_irish.jpg)
</picture>
<picture>
<source srcset="photo.jxr" type="image/vnd.ms-photo">
<source srcset="photo.jp2" type="image/jp2">
<source srcset="photo.webp" type="image/webp">
![](photo.jpg)
</picture>
使用自动化的CDN转换WebP
一些CDN支持将图像自动转换为WebP,可以使用Client Hints来让后端尽可能地提供WebP图像。请检查您的CDN,查看服务中是否包含了WebP支持。你可能有一个简单的解决方案,只是等待着你去寻找。
WordPress的WebP支持
Jetpack — Jetpack是一款流行的WordPress插件,它包括一个名为Photon的CDN映像服务。使用Photon,你就可以获得无缝的WebP图像支持。这个叫Photon的CDN服务是包含在Jetpack的免费清单中的,因此这是一个很棒很有效的实现。不过,缺点是Photon会调整您的图像大小,将一个查询字符串放在您的URL中,并且每个图像都需要额外的DNS查找。
Cache Enabler and Optimizer — 如果您使用的是WordPress,那么你至少有一个半开源的选项。WordPress的开源插件Cache Enabler有一个菜单复选框可以勾选,用于缓存WebP图像,如果当前用户的浏览器支持它就会提供给用户。这使得WebP图像服务变得容易。但是,这个插件有一个缺点:Cache Enabler需要使用一个名为Optimizer的姐妹程序,而它则是需要支付年费的。这对于一个需要真正的开源解决方案的情况来说,显然是不合适的。
Short Pixel — Cache Enabler的另一个搭配选择是使用Short Pixel,它的功能和Optimizer很像,也是付费的。但是,Short Pixel可以每个月免费优化100张图片。
最好使用<video>
压缩GIF动画
动画GIF使用依然广泛,尽管这是一个功能非常有限的格式。虽然从社交网络到流行的媒体网站都大量嵌入了动画GIF,但是其实这个格式从未被设计用于视频或动画存储。事实上,GIF89a规范一个在提示“GIF不是作为动画的平台”。格式中颜色、图层和纬度的数量都影响GIF动画文件的体积,切换到视频格式可以提供最大的空间节省。
动画GIF对比视频:同等质量下不同文件格式的文件大小对比。
提供相同内容和质量的MP4文件可能会在文件体积上节省达到80%或更多。GIF通常不仅会浪费大量的带宽,而且加载时间较长、只支持较少的颜色,因此只能使网站提供的用户体验大打折扣。您可能已经注意到,上传到Twitter的动画GIF在Twitter上的表现是要优于其他网站的。这是因为,Twitter上的动画GIF实际上并不是GIF。为了提高用户体验和减少带宽占用,上传到Twitter的动画GIF实际上是被转换成为了视频。同样,Imgur也将上传的GIF转换为了静音的MP4视频。
为什么GIF多数情况下要大很多?因为,动画GIF将每个帧存储为了无损GIF图像 - 是的,无损。我们经常遇到的GIF的质量下降,其实是因为GIF受限于它的256色调色板。GIF格式下文件通常很大,因为它不像H.264这样的视频编解码器会考虑压缩相邻帧。MP4视频将每个关键帧存储为有损的JPEG,并其丢弃一些原始数据以实现更好的压缩。
如果您可以切换到视频
ffmpeg -i animated.gif -movflags faststart -pix_fmt yuv420p -vf "scale=trunc(iw/2)*2:trunc(ih/2)*2" video.mp4
- ImageOptim的API还支持转换动画GIF为WebM/H.264视频,另外还可以从GIF中消除抖动,从而帮助视频编解码器压缩视频到更小。
如果您必须使用动画GIF
- 可以使用像Gifsicle这样的工具,清除元数据和未使用的调色板条目,并最小化帧之间的变化。
- 考虑使用一个有损的GIF编码器。Gifsicle派生的Giflossy支持一个
—lossy
命令标识,可以删除掉60%~65%文件体积。还有一个很好的基于它的工具,称为Gifify。对于非动画GIF,将其转换为PNG或WebP。
有关更多信息,请查阅Rigor编写的关于GIF的电子书。