WebP是由Google在2010年基于VP8视频格式开发的开放图像格式。从那时起,使用WebP格式的网站和移动应用程序的数量迅速增长。Google Chrome和Opera本身都支持WebP格式,这些浏览器占网络流量的大约74%,因此如果网站使用WebP格式的图像,用户可以更快地访问网站。
WebP格式支持有损和无损图像压缩,包括动画。与Web上使用的其他图像格式相比,它的主要优势在于它的文件大小要小得多,这使得网页加载速度更快,并减少了带宽使用。使用WebP图像可以显着提高页面速度。如果您的应用或网站遇到性能问题或流量增加的情况,转换图片可能有助于优化网页性能。
在本教程中,您将使用命令行工具cwebp将图像转换为WebP格式,创建在特定目录中监视和转换图像的脚本。最后,您将探索两种向访问者提供WebP图像的方法。
使用WebP图像不需要特定的分发,但我们将演示如何在Ubuntu和CentOS上使用相关软件。要学习本教程,您需要:
sudo
命令的非root账号的CentOS服务器,并且已开启防火墙。没有服务器的同学可以在这里购买,不过我个人更推荐您使用免费的腾讯云开发者实验室进行试验,学会安装后在购买服务器。mod_rewrite
。在本节中,我们将安装软件来转换图像并创建一个包含图像的目录作为测试措施。
在Ubuntu上,您可以通过输入以下命令来安装cwebp
。
sudo apt-get update
sudo apt-get install webp
在CentOS 7上输入:
sudo yum install libwebp-tools
要创建在Apache Web根目录中调用的新映像目录webp(默认情况下位于/var/www/html
),请输入:
sudo mkdir /var/www/html/webp
将此目录的所有权更改为非root用户sammy:
sudo chown sammy: /var/www/html/webp
要测试命令,您可以用wget下载免费的JPEG和PNG图像。默认情况下,此工具安装在Ubuntu上; 如果您使用的是CentOS 7,可以输入以下命令安装:
sudo yum install wget
接下来,使用以下命令下载测试图像:
wget -c "https://upload.wikimedia.org/wikipedia/commons/2/24/Junonia_orithya-Thekkady-2016-12-03-001.jpg?download" -O /var/www/html/webp/image1.jpg
wget -c "https://upload.wikimedia.org/wikipedia/commons/5/54/Mycalesis_junonia-Thekkady.jpg" -O /var/www/html/webp/image2.jpg
wget -c "https://cdn.pixabay.com/photo/2017/07/18/15/39/dental-care-2516133_640.png" -O /var/www/html/webp/logo.png
注意:这些图像可在Creative Commons Attribution-ShareAlike许可和Public Domain Dedication下使用和再分发。
您在下一步中的大多数工作都将在/var/www/html/webp
目录中,您可以通过输入以下内容来进入:
cd /var/www/html/webp
有了测试图像,Apache Web服务器mod_rewrite
和cwebp
也已安装,您就可以继续转换图像了。
向网站访问者提供.webp
图像需要.webp
图像文件。在此步骤中,您将用cwebp
把JPEG和PNG图像转换为.webp
使用的格式。该命令的一般语法如下所示:
cwebp image.jpg -o image.webp
-o
选项指定WebP文件的路径。
因为仍然在/var/www/html/webp
目录中,你可以运行下面的命令将image1.jp
g转换到image1.webp
,将image2.jpg
转换到image2.webp
:
cwebp -q 100 image1.jpg -o image1.webp
cwebp -q 100 image2.jpg -o image2.webp
将品质因数-q
设置为100
可保持100%的图像质量;如果未指定,则默认值为75。
接下来,使用ls
命令检查JPEG和WebP图像的大小。-l
选项将显示长列表格式,其中包括文件的大小,-h
选项将确保ls
输出可读的大小:
ls -lh image1.jpg image1.webp image2.jpg image2.webp
-rw-r--r-- 1 sammy sammy 7.4M Oct 28 23:36 image1.jpg
-rw-r--r-- 1 sammy sammy 3.9M Feb 18 16:46 image1.webp
-rw-r--r-- 1 sammy sammy 16M Dec 18 2016 image2.jpg
-rw-r--r-- 1 sammy sammy 7.0M Feb 18 16:59 image2.webp
ls
命令的输出显示image1.jpg
的大小为7.4M,而image1.webp
的大小为3.9M。image2.jpg
的大小为16M,而image2.webp
的大小为7M。这些文件几乎是原始大小的一半!
要在压缩过程中保存完整的原始图像数据,您可以使用-lossless
选项代替-q
。这是保持PNG图像质量的最佳选择。要从第一步转换下载的PNG图像,请输入:
cwebp -lossless logo.png -o logo.webp
以下命令显示,无损WebP图像大小(60K)大约是原始PNG图像(116K)的一半:
ls -lh logo.png logo.webp
-rw-r--r-- 1 sammy sammy 116K Jul 18 2017 logo.png
-rw-r--r-- 1 sammy sammy 60K Feb 18 16:42 logo.webp
/var/www/html/webp
目录中转换的WebP图像大约比JPEG和PNG图像小一半。实际上,压缩率可能因某些因素而异,包括原始图像的压缩率、文件格式、转换类型(有损或无损)、质量百分比和操作系统。当您转换更多图片时,您可能会看到与这些因素相关的转化率变化。
编写脚本将免除手动转换的工作,从而简化转换过程。我们现在将编写一个转换脚本来查找JPEG文件,并将它们转换为具有90%质量的WebP格式,同时还将PNG文件转换为无损WebP图像。
使用nano
或您喜欢的编辑器,在用户的主目录中创建脚本webp-convert.sh
:
nano ~/webp-convert.sh
脚本的第一行如下所示:
find $1 -type f -and \( -iname "*.jpg" -o -iname "*.jpeg" \)
该行包含以下部分:
find
:此命令将搜索指定目录中的文件。$1
:此位置参数指定从命令行获取的images目录的路径。最终,它使目录的位置较少依赖于脚本的位置。-type f
:此选项告诉find
仅查找常规文件。-iname
:此测试将文件名与指定的模式匹配。-iname
测试不区分大小写,告诉find
查找以.jpg
(*.jpg
)或.jpeg
(*.jpeg
)结尾的任何文件名。-o
:此指示find
命令列出与第一个-iname
测试(-iname "*.jpg"
)或第二个(-iname "*.jpeg"
)匹配的文件。()
:括号以及-and
操作符确保始终执行第一个测试(即-type f
)。脚本的第二行将使用-exec
参数将图像转换为WebP 。此参数的一般语法是-exec command {} \;
。该字符串{}
由命令迭代的每个文件替换;
告诉find
命令结束:
find $1 -type f -and \( -iname "*.jpg" -o -iname "*.jpeg" \) \
-exec bash -c 'commands' {} \;
在这种情况下,-exec
参数将需要多个命令来搜索和转换图像:
bash
:此命令将执行一个小脚本,如果文件不存在,将生成该文件的.webp
版本。由于该-c
选项,此脚本将作为字符串传递给bash。'commands'
:此占位符是将生成文件的.webp
版本的脚本。里面的脚本'commands'
将执行以下操作:
webp_path
变量。.webp
文件的版本是否存在。脚本如下所示:
...
webp_path=$(sed 's/\.[^.]*$/.webp/' <<< "$0");
if [ ! -f "$webp_path" ]; then
cwebp -quiet -q 90 "$0" -o "$webp_path";
fi;
脚本中的元素包括:
webp_path
:此变量使用sed
和从bash
命令生成的匹配的文件名生成,由参数$0
表示。一个在此字符串(<<<
)将把这个名字发送给sed
。if [ ! -f "$webp_path" ]
此测试使用逻辑not运算符(!
),为了确定名为"$webp_path
"的文件是否存在。cwebp
:如果文件不存在,此命令将创建该文件,使用-q
选项使不输出。转换JPEG图像的完整脚本现在将如下所示:
find $1 -type f -and \( -iname "*.jpg" -o -iname "*.jpeg" \) \
-exec bash -c '
webp_path=$(sed 's/\.[^.]*$/.webp/' <<< "$0");
if [ ! -f "$webp_path" ]; then
cwebp -quiet -q 90 "$0" -o "$webp_path";
fi;' {} \;
要将PNG图像转换为WebP,我们将采用相同的方法,但有两点不同:首先,find
命令中的-iname
模式将是"*.png"
。其次,转换命令将使用-lossless
选项而不是-q
选项。
完成的脚本如下所示:
#!/bin/bash
# converting JPEG images
find $1 -type f -and \( -iname "*.jpg" -o -iname "*.jpeg" \) \
-exec bash -c '
webp_path=$(sed 's/\.[^.]*$/.webp/' <<< "$0");
if [ ! -f "$webp_path" ]; then
cwebp -quiet -q 90 "$0" -o "$webp_path";
fi;' {} \;
# converting PNG images
find $1 -type f -and -iname "*.png" \
-exec bash -c '
webp_path=$(sed 's/\.[^.]*$/.webp/' <<< "$0");
if [ ! -f "$webp_path" ]; then
cwebp -quiet -lossless "$0" -o "$webp_path";
fi;' {} \;
保存文件并退出编辑器。
接下来,让我们使用/var/www/html/webp
目录中的文件运行webp-convert.sh
脚本。通过运行以下命令确保脚本文件是可执行的:
chmod a+x ~/webp-convert.sh
在images目录上运行脚本:
./webp-convert.sh /var/www/html/webp
什么都没发生!那是因为我们已经在第二步中转换了这些图像。然后,当我们添加新文件或删除.webp
版本时,webp-convert
脚本将转换图像。要查看其工作原理,请删除我们在第二步中创建的.webp
文件:
rm /var/www/html/webp/*.webp
删除所有.webp
图像后,再次运行脚本:
./webp-convert.sh /var/www/html/webp
ls命令将确认脚本已成功转换图像:
ls -lh /var/www/html/webp
Output
-rw-r--r-- 1 sammy sammy 7.4M Oct 28 23:36 image1.jpg
-rw-r--r-- 1 sammy sammy 3.9M Feb 18 16:46 image1.webp
-rw-r--r-- 1 sammy sammy 16M Dec 18 2016 image2.jpg
-rw-r--r-- 1 sammy sammy 7.0M Feb 18 16:59 image2.webp
-rw-r--r-- 1 sammy sammy 116K Jul 18 2017 logo.png
-rw-r--r-- 1 sammy sammy 60K Feb 18 16:42 logo.webp
此步骤中的脚本是在您的站点中使用WebP图像的基础,因为您需要WebP格式的所有图像的工作版本才能为访问者提供服务。下一步将介绍如何自动转换新图像。
在此步骤中,我们将创建一个新脚本来观察我们的images目录以进行更改并自动转换新创建的图像。
创建一个监视我们的images
目录的webp-convert.sh
脚本可以解决脚本编写时的某些问题。例如,此脚本无法识别我们是否重命名了图像。如果我们有一个名为foo.jpg
的图像,运行webp-convert.sh
,重命名bar.jpg
文件,然后再次运行webp-convert.sh
,我们将有重复的.webp
文件(foo.webp
和bar.webp
)。要解决此问题,并避免手动运行脚本,我们会将添加到另一个脚本。监视器监视指定的文件或目录以进行更改并运行命令以响应这些更改。
inotifywait
命令将在我们的脚本中设置观察者。此命令是inotify-tools
程序包的一部分,该程序包是一组命令行工具,为inotify
内核子系统提供简单的接口。要在Ubuntu上安装它,请输入:
sudo apt-get install inotify-tools
如果您使用的是CentOS,可在EPEL存储库中找到该inotify-tools
软件包。使用以下命令安装EPEL存储库和inotify-tools
包:
sudo yum install epel-release
sudo yum install inotify-tools
接下来,使用nano在用户的主目录中创建webp-watchers.sh
脚本:
nano ~/webp-watchers.sh
脚本中的第一行如下所示:
inotifywait -q -m -r --format '%e %w%f' -e close_write -e moved_from -e moved_to -e delete $1
该行包括以下元素:
inotifywait
:此命令监视对某个目录的更改。-q
:此选项将告诉inotifywait
不会产生大量输出。-m
:此选项将告知inotifywait
无限期运行,并在收到单个事件后不退出。-r
:此选项将递归地设置观察者,观察指定的目录及其所有子目录。--format
:此选项告诉inotifywait
您使用事件名称后跟文件路径来监视更改。我们要监视的是close_write
(创建文件,并完全写入到磁盘时触发),moved_from
与moved_to
(当文件被移动触发),和delete
(当一个文件被删除触发)。$1
:此位置参数保存已更改文件的路径。接下来,让我们添加一个grep
命令来确定我们的文件是JPEG还是PNG图像。-i
选项将告诉grep
忽略大小写,-E
将指定grep
应该使用扩展正则表达式,--line-buffered
告诉grep
将匹配的行传递给while
循环:
inotifywait -q -m -r --format '%e %w%f' -e close_write -e moved_from -e moved_to -e delete $1 | grep -i -E '\.(jpe?g|png)$' --line-buffered
接下来,我们将使用read
命令构建一个while
循环。read
将处理inotifywait
检测到的事件,将其分配给一个名为$operation
的变量,并将处理后的文件路径分配给名为$path
的变量:
...
| while read operation path; do
# commands
done;
让我们将这个循环与我们脚本的其余部分结合起来:
inotifywait -q -m -r --format '%e %w%f' -e close_write -e moved_from -e moved_to -e delete $1 \
| grep -i -E '\.(jpe?g|png)$' --line-buffered \
| while read operation path; do
# commands
done;
while
循环检查完事件后,循环内的命令将采取以下操作,具体取决于结果:
循环内有三个主要部分。名为webp_path
的变量将保存.webp
主题图像版本的路径:
...
webp_path="$(sed 's/\.[^.]*$/.webp/' <<< "$path")";
接下来,该脚本将测试发生了那些事件:
...
if [ $operation = "MOVED_FROM" ] || [ $operation = "DELETE" ]; then
# commands to be executed if the file is moved or deleted
elif [ $operation = "CLOSE_WRITE,CLOSE" ] || [ $operation = "MOVED_TO" ]; then
# commands to be executed if a new file is created
fi;
如果文件已被移动或删除,脚本将检查.webp
版本是否存在。如果是,脚本将使用rm
将其删除:
...
if [ -f "$webp_path" ]; then
$(rm -f "$webp_path");
fi;
对于新创建的文件,压缩将按如下方式进行:
-quality
选项的有损压缩。让我们将执行此工作的cwebp命令添加到脚本中:
...
if [ $(grep -i '\.png$' <<< "$path") ]; then
$(cwebp -quiet -lossless "$path" -o "$webp_path");
else
$(cwebp -quiet -q 90 "$path" -o "$webp_path");
fi;
完成后,webp-watchers.sh
文件将如下所示:
#!/bin/bash
echo "Setting up watches.";
# watch for any created, moved, or deleted image files
inotifywait -q -m -r --format '%e %w%f' -e close_write -e moved_from -e moved_to -e delete $1 \
| grep -i -E '\.(jpe?g|png)$' --line-buffered \
| while read operation path; do
webp_path="$(sed 's/\.[^.]*$/.webp/' <<< "$path")";
if [ $operation = "MOVED_FROM" ] || [ $operation = "DELETE" ]; then # if the file is moved or deleted
if [ -f "$webp_path" ]; then
$(rm -f "$webp_path");
fi;
elif [ $operation = "CLOSE_WRITE,CLOSE" ] || [ $operation = "MOVED_TO" ]; then # if new file is created
if [ $(grep -i '\.png$' <<< "$path") ]; then
$(cwebp -quiet -lossless "$path" -o "$webp_path");
else
$(cwebp -quiet -q 90 "$path" -o "$webp_path");
fi;
fi;
done;
保存并关闭文件。别忘了让它可执行:
chmod a+x ~/webp-watchers.sh
让我们使用&在后台/var/www/html/webp
目录上运行此脚本。我们还将标准输出和标准错误重定向到~/output.log
,以便将输出存储在一个随时可用的位置:
./webp-watchers.sh /var/www/html/webp > output.log 2>&1 &
此时,您已将/var/www/html/webp
中的JPEG和PNG文件转换为WebP格式,并设置使用webp-watchers.sh
脚本执行此操作。现在可以试着向您的网站用户提供WebP图像的选项了。
在此步骤中,我们将解释如何使用HTML元素提供WebP图像。此时,/var/www/html/webp
目录中应该有每个测试JPEG和PNG图像的.webp版本。我们现在可以使用HTML5元素(<picture>
)或mod_rewriteApache
模块为它们提供支持。我们将在此步骤中使用HTML元素。
<picture>
元素允许您直接在网页中包含图像并定义多个图像源。如果您的浏览器支持WebP格式,它将下载该文件的.webp
版本而不是原始版本,从而使网页的服务速度更快。值得一提的是,<picture>
元素在支持WebP格式的现代浏览器中得到了很好的支持。
<picture>
元件是与容器<source>
和<img>
指向特定文件的元素。如果我们使用<source>
指向.webp图像,浏览器将查看它是否可以处理它;否则,它将回退到元素src属性中指定的图像文件<img>
。
让我们使用我们转换为logo.webp
的/var/www/html/webp
目录中的logo.png
文件作为<source>
的示例。我们可以使用以下HTML代码在任何支持WebP格式的浏览器显示logo.webp
,以及在任何不支持WebP或<picture>
元素的浏览器显示logo.png。
创建位于/var/www/html/webp/picture.html
的HTML文件:
nano /var/www/html/webp/picture.html
将以下代码添加到网页,以使用该<picture>
元素在支持的浏览器显示logo.webp
:
<picture>
<source srcset="logo.webp" type="image/webp">
<img src="logo.png" alt="Site Logo">
</picture>
保存并关闭文件。
要测试一切正常,请导航至http://your_server_ip/webp/picture.html
。您应该看到测试PNG图像。
既然您已经知道如何直接从HTML代码提供.webp
图像,那么让我们看看如何使用Apache的mod_rewrite
模块自动化这个过程。
如果我们想要优化我们网站的速度,但是有大量页面或者编辑HTML代码的时间太少,那么Apache的mod_rewrite
模块可以帮助我们自动化为支持浏览器提供.webp
图像。
首先,使用以下命令在/var/www/html/webp
目录中创建一个.htaccess
文件:
nano /var/www/html/webp/.htaccess
ifModule
指令将测试是否mod_rewrite
可用; 如果是,可以通过使用RewriteEngine On
激活它。将这些指令添加到.htaccess
:
<ifModule mod_rewrite.c>
RewriteEngine On
# further directives
</IfModule>
Web服务器将进行多次测试以确定何时向用户提供.webp
图像。当浏览器发出请求时,它包含一个标题,用于向服务器指示浏览器能够处理的内容。对于WebP,浏览器将发送Accept
包含的标头image/webp
。我们将检查浏览器是否使用了标头RewriteCond
,该标准指定了应该匹配的标准以执行RewriteRule
:
...
RewriteCond %{HTTP_ACCEPT} image/webp
应该过滤掉所有内容,除了JPEG和PNG图像。再次使用RewriteCond
,添加一个正则表达式来匹配请求的URI:
...
RewriteCond %{REQUEST_URI} (?i)(.*)(\.jpe?g|\.png)$
该(?i)
修改将使得匹配不区分大小写。要检查文件的.webp
版本是否存在,请再次使用RewriteCond
,如下所示:
...
RewriteRule (?i)(.*)(\.jpe?g|\.png)$ %1\.webp [L,T=image/webp,R]
最后,如果满足所有先前条件,RewriteRule
则会将请求的JPEG或PNG文件重定向到其关联的WebP文件。请注意,这将使用-R
标志重定向,而不是重写URI。重写和重定向之间的区别在于服务器将在不告知浏览器的情况下提供重写的URI。例如,URI将显示文件扩展名.png
,但它实际上是一个.webp文件。添加RewriteRule到文件:
...
RewriteRule (?i)(.*)(\.jpe?g|\.png)$ %1\.webp [L,T=image/webp,R]
此时,.htaccess
文件中的mod_rewrite
部分已完成。但是,如果服务器和客户端之间存在中间缓存服务器,会发生什么?它可以为最终用户提供错误的版本。这就是为什么值得检查以查看是否mod_headers
已启用,以便发送Vary:Accept
标头。Vary
报头指示缓存服务器(如代理服务器),该文件的内容类型,这取决于请求该文档的浏览器的功能而变化。此外,响应将基于Accept
请求中的标头生成。具有不同Accept
标头的请求可能会得到不同的响应。此标头很重要,因为它可以防止缓存的WebP图像被提供给不支持的浏览器:
...
<IfModule mod_headers.c>
Header append Vary Accept env=REDIRECT_accept
</IfModule>
最后,在.htaccess
文件末尾,使用AddType
指令在image/webp
设置.webp
图像的MIME类型。这将使用正确的MIME类型提供图像:
...
AddType image/webp .webp
这是我们.htaccess
文件的最终版本:
<ifModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTP_ACCEPT} image/webp
RewriteCond %{REQUEST_URI} (?i)(.*)(\.jpe?g|\.png)$
RewriteCond %{DOCUMENT_ROOT}%1.webp -f
RewriteRule (?i)(.*)(\.jpe?g|\.png)$ %1\.webp [L,T=image/webp,R]
</IfModule>
<IfModule mod_headers.c>
Header append Vary Accept env=REDIRECT_accept
</IfModule>
AddType image/webp .webp
注意:您可以将
.htaccess
与另一个.htaccess
文件合并(如果存在)。例如,如果您使用的是WordPress,则应复制此.htaccess
文件并将其粘贴到现有文件的顶部。
让我们运行我们在这一步中所做的设置。如果您已按照前面步骤中的说明操作,/var/www/html/webp
则应存在logo.png和logo.webp图像。让我们使用一个简单的<img>标签在我们的网页中包含logo.png。创建一个新的HTML文件来测试设置:
nano /var/www/html/webp/img.html
在文件中输入以下HTML代码:
<img src="logo.png" alt="Site Logo">
保存并关闭文件。
当您通过Chrome访问http://your_server_ip/webp/img.html
时,您会注意到所提供的图像是.webp
版本。如果您使用Firefox,您将自动获得.png
图像。
在本教程中,我们介绍了使用WebP图像的基本技术。我们已经解释了如何使用cwebp转换文件,以及向用户提供这些图像的两个选项:HTML5的<picture>
元素和Apache的mod_rewrite。图像使用WebP格式会大大减少文件大小。这可以降低带宽使用率并加快页面加载速度,尤其是当您的网站使用大量图像时。更多Linux教程请前往腾讯云+社区学习更多知识。
参考文献:《How To Create and Serve WebP Images to Speed Up Your Website》
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。