Hexo - 使用WebP格式的图片加速Hexo网页访问速度
目录
需求来源
我在写博客的时候经常需要引用很多种格式的图片,比如 jpg
、jpeg
、png
、gif
,这时候就出现一个问题,各种图片不仅格式不统一,而且很多图片非常大(因为有些图片是自己拍的,传输的时候是原图),但是放在博客上的图片这么大是没有意义的。网络在上传和分发图片的时候并不会按照原图来呈现,而且这样的清晰度对于网页浏览同样也资源过剩,反而造成了流量的浪费和用户的等待时间过长(除了一些摄影网站之类的可能需要原图)。
因此我必须解决图片格式不统一和图片过大的问题,这时候我就想能不能先在本地将图片压缩(最好是无损的),然后上传的时候直接上传压缩过后的图片就可以了,这样就能解决图片过大的问题。然后接下来的问题就是解决选择压缩到什么格式,经过一番探索,我选择压缩成 WebP格式:
WebP 是一种新型图片格式,可为网络上的图片提供品质卓越的无损和有损压缩。使用 WebP,网站站长和网络开发者可以创建体积更小但细节更丰富的图片,从而提高网络访问速度。
WebP 无损图片比 PNG 图片小 26%。WebP 有损图片比采用等效 SSIM 质量指标的同等 JPEG 图片 缩小 25-34%。
无损 WebP 支持透明度(也称为 Alpha 通道),只需 增加 22% 的字节。对于可以接受有损 RGB 压缩的情况,有损 WebP 也支持透明度,生成的文件大小通常比 PNG 小 3 倍。
动画 WebP 图片支持有损、无损和透明,与 GIF 和 APNG 相比,可以缩减文件大小。
选择WebP格式的原因除了支持很多格式图片的转换外,还因为它支持很多浏览器(IE浏览器用户就不管了,没有办法适配所有用户):
Google Chrome、Safari、Firefox、Edge、Opera 浏览器以及 许多其他工具和软件库都原生支持 WebP。开发者还添加了对各种图片编辑工具的支持。
WebP 包括轻量级编码和解码库
libwebp
,以及用于将图片转换为 WebP 格式和从 WebP 格式转换为其他格式的命令行工具cwebp
和dwebp
,以及用于查看、混合和为 WebP 图片添加动画效果的工具。完整的源代码可在 下载页面上找到。
因此最终我打算将Hexo博客上的图片都转换为WebP格式。接下来将需求拆解:
- 在本地安装WebP转换所需要的库
libwebp
- 编写
PowerShell
脚本(我所使用的系统是 Windows 10)自动将其他格式的图片转换成.webp
格式的图片 - 编写新的
PowerShell
脚本修改.md
的 Markdown 文件中引用图片的地方,将各种格式的图片后缀改成.webp
(因为我使用 Typora 来直接拖拽引入原图,所以需要在写完保存.md
文件后再批量修改.md
文件中引用图片的地方) - 将前面两个脚本整合到本地预览和远程部署的脚本当中
需求实现
安装WebP库
安装WebP转换相应的库,我采用 Scoop 进行安装:
1scoop install main/libwebp
安装完成之后通过下面的命令来验证是否安装成功:
1cwebp -version
编写自动化脚本
在Hexo博客目录下创建四个脚本分别用于执行不同的任务:
local.ps1
用于在本地预览最终的修改效果deploy.ps1
用于部署到远程托管仓库convert-to-webp.ps1
用于将本地的其他图片格式转换为.webp
图片格式update-markdown-images.ps1
用于更新.md
文件中引用图片的地方
下面脚本的内容可以根据个人存放位置和需求的不同进行更改。
local.ps1
:
1cd E:\ChenHuaneng\Article\Academic\academic-homepage
2bundle exec jekyll build
3robocopy "_site" "E:\ChenHuaneng\Article\Blogs\source\academic" /E /NFL /NDL /NP /XO
4cd E:\ChenHuaneng\Article\Blogs
5Write-Host "运行WebP转换..."
6& .\convert-to-webp.ps1
7Write-Host "更新Markdown图片引用..."
8& .\update-markdown-images.ps1
9npx hexo clean
10npx hexo g
11npx hexo s -p 8080
deploy.ps1
:
1# 修改学术主页
2Write-Host "修改学术主页..."
3cd E:\ChenHuaneng\Article\Academic\academic-homepage
4bundle exec jekyll build
5robocopy "_site" "E:\ChenHuaneng\Article\Blogs\source\academic" /E /NFL /NDL /NP /XO
6cd E:\ChenHuaneng\Article\Blogs
7# 查看当前修改的文件
8$gitStatus = git status --porcelain
9$gitAhead = git status -b --porcelain | Select-String "ahead"
10
11# 判断是否有修改或者未推送的提交
12if ($gitStatus -or $gitAhead) {
13 Write-Host "检测到修改或未推送的提交,开始处理..."
14
15 if ($gitStatus) {
16 # 添加所有修改的文件
17 git add .
18
19 # 提交修改,自动生成提交信息
20 $currentTime = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
21 $commitMessage = "Auto commit at $currentTime"
22 git commit -m $commitMessage
23 } else {
24 Write-Host "没有检测到新的修改,但有未推送的提交。"
25 }
26
27 # 推送到远程仓库
28 git push -u origin main
29} else {
30 Write-Host "没有检测到修改或未推送的提交,跳过 Git 操作。"
31}
32
33Write-Host "开始图片WebP转换..."
34Set-Location "E:\ChenHuaneng\Article\Blogs"
35& .\convert-to-webp.ps1
36Write-Host "WebP转换完成!"
37
38Write-Host "更新Markdown中的图片引用..."
39& .\update-markdown-images.ps1
40Write-Host "图片引用更新完成!"
41
42# 重新生成静态网页
43npx hexo clean
44npx hexo g
45
46# 部署更新后的网页文件
47hexo deploy
convert-to-webp.ps1
:
1param(
2 [string]$basePath = "E:\ChenHuaneng\Article\Blogs\source"
3)
4
5# 支持的图片扩展名
6$imageExtensions = @('.png','.jpg','.jpeg','.gif','.avif')
7
8# 需要处理的目录
9$directories = @('imgs', '_posts', 'academic')
10
11# 获取cwebp完整路径 (避免环境变量问题)
12$cwebpPath = (Get-Command cwebp).Source
13
14foreach ($dir in $directories) {
15 $fullPath = Join-Path $basePath $dir
16 if (Test-Path $fullPath) {
17 Write-Host "Processing directory: $fullPath"
18 # 递归处理子目录中的图片
19 $files = Get-ChildItem -Path $fullPath -Recurse -File | Where-Object { $imageExtensions -contains $_.Extension.ToLower() }
20
21 foreach ($file in $files) {
22 $webpPath = [System.IO.Path]::ChangeExtension($file.FullName, 'webp')
23
24 # 仅当WebP文件不存在或比原图新时转换
25 if (-not (Test-Path $webpPath) -or $file.LastWriteTime -gt (Get-Item $webpPath).LastWriteTime) {
26 try {
27 # 修复参数传递问题
28 $qualityArg = "-q", "75"
29
30 # 处理GIF的特殊情况
31 if ($file.Extension -eq '.gif') {
32 # GIF使用gif2webp工具处理
33 $gif2webpPath = (Get-Command gif2webp).Source
34 & $gif2webpPath "-q" "75" "-mixed" "$($file.FullName)" "-o" "$webpPath"
35 }
36 else {
37 # 其他图片使用cwebp
38 & $cwebpPath "-q" "75" "$($file.FullName)" "-o" "$webpPath"
39 }
40
41 if ($LASTEXITCODE -eq 0) {
42 Write-Host "✅ Converted: $($file.Name) → $([System.IO.Path]::GetFileName($webpPath))"
43 } else {
44 Write-Host "⚠️ Failed to convert: $($file.FullName) (Exit code: $LASTEXITCODE)"
45 }
46 } catch {
47 Write-Host "🛑 Error processing $($file.FullName): $_"
48 }
49 } else {
50 Write-Host "⏩ Skipped (up-to-date): $($file.Name)"
51 }
52 }
53 }
54}
55
56Write-Host "🎉 WebP conversion complete!"
update-markdown-images.ps1
:
1# 参数定义:基础目录路径(可运行时指定)
2param([string]$basePath = "E:\ChenHuaneng\Article\Blogs\source")
3
4# 定义目标子目录和支持的图片扩展名
5$directories = @('_posts', 'image', 'about')
6$imageExtensions = @('.png','.jpg','.jpeg','.gif','.avif')
7
8# 获取待处理的 Markdown 文件(3天内修改)
9$markdownFiles = Get-ChildItem -Path $basePath -Recurse -Include "*.md" |
10 Where-Object {
11 $_.DirectoryName -match "($($directories -join '|'))" -and
12 $_.LastWriteTime -gt (Get-Date).AddDays(-3)
13 }
14
15# 遍历每个文件进行替换
16foreach ($file in $markdownFiles) {
17 $content = Get-Content -Path $file.FullName -Raw
18
19 # 正则表达式:匹配 Markdown 图片语法
20 $typoraPattern = '\!\[(.*?)\]\((.*?)(' +
21 ($imageExtensions + $imageExtensions.ToUpper() | Join-String -Separator "|") +
22 ')\)'
23
24 # 执行替换(保留描述和路径,仅修改扩展名为 .webp)
25 $newContent = $content -replace $typoraPattern, ''
26
27 # 保存修改后的文件
28 if ($newContent -ne $content) {
29 Set-Content -Path $file.FullName -Value $newContent -NoNewline
30 Write-Host "✅ Updated $($file.Name)"
31 } else {
32 Write-Host "⏩ No images to update in $($file.Name)"
33 }
34}
35Write-Host "🎉 All Markdown files updated to reference WebP images"