一站式解决图片问题:我的 Obsidian+Hugo自动化发布流
文章介绍了从 Obsidian 到 Hugo 的静态博客工作流优化方法,重点解决图片压缩与上传问题。通过脚本实现 Markdown 链接转换、图像降采样与压缩,并自动上传至 Cloudflare R2 存储桶。采用 SSIM 和 LPIPS 指标优化压缩参数,提升图片质量与加载效率。最终实现高效的写作与发布流程,并分享相关代码。 2025-8-6 03:31:20 Author: sspai.com(查看原文) 阅读量:12 收藏

Markdown × 静态博客:图片智能压缩与高效写作发布流

Matrix 首页推荐 

Matrix 是少数派的写作社区,我们主张分享真实的产品体验,有实用价值的经验与思考。我们会不定期挑选 Matrix 最优质的文章,展示来自用户的最真实的体验和观点。 
文章代表作者个人观点,少数派仅对标题和排版略作修改。


Obsidian to Hugo 工作流

Hugo 允许我们使用 Markdown 格式进行写作,并自动转换为静态网站,Markdown 编辑器可以自由地选择。我使用的是 Obsidian 编辑器,将.md文件同步至 HomeServer 后,在 Linux 环境中构建并预览网站,最终 Push 至 Github 并由 Cloudflare 解析。这样的工作流并无可说道之处,但是其中的附件(图片、视频)的处理是比较麻烦的,常规的处理办法有:

  • 使用 Markdown 风格链接附件,并随项目上传至 Github 仓库;
  • 写作时使用图床(图床服务、OSS 等)托管图片并在.md文件中以 Markdown 风格插入链接。

不管哪种方法,在写作时都是不够流畅的,在前期、后期还可能要处理图像的压缩问题,当然我们可以引入第三方的工具比如WebP Cloud Services,但有悖于我用 Cloudflare 一把梭哈的理念1,且无法解决 CF 的 R2 免费存储空间(10GB)可能不足的问题。

为了让Obsidian - Hugo的写作、发布流更加顺畅,我之前使用脚本在本地(HomeServer)转换 Obsidian 的 WiKi 链接(双方括号)并压缩图像自动上传至 CloudFlare R2。有 24 小时在线的 HomeServer 辅助,这套流程允许我在全平台同步写作、插入附件,足够流畅。但使用过程中发现,固定的压缩设置使得一些照片质量有明显的下降,而对于一些画面简单的图片,体积似乎还有压缩的空间。

因此,Obsidian - Hugo自动化发布的核心在于解决多媒体附件(主要是图片)问题,即自动转换附件链接、自动优化图片体积与质量、自动上传 OSS。

图像优化既是一门艺术,也是一门科学:说它是一门艺术,是因为单个图像的压缩并不存在明确的最佳方案,说它是一门科学,则是因为有许多发展成熟的方法和算法都能够显著缩减图像的大小。找到图像的最佳设置需要在许多方面进行认真分析:格式能力、编码数据的内容、质量、像素尺寸等。

—— Google Web Fundamentals

图像尺寸的确定

首先要确定目标尺寸宽高,高清原图超大的尺寸对于 Web 浏览来说是无意义的2,浏览器会根据 css 样式和设备屏幕自动缩放图像,与其让浏览器对图像降采样,不如在服务端完成,如此可以有效减小存储体积并提高网站加载速度。

应对多设备的最佳画质图片问题,可以通过优化单张图片,或者准备数张不同尺寸的图片并根据设备自动选择。为了在有限容量的 R2 存储桶中尽可能多地存储文件,我们还是采用优化单张图片的路线。因此首先要确定图片的宽高尺寸应该设置为多大。

图像元素

根据 hugo-book 的样式源码:

// /themes/hugo-book/assets/_defaults.scss
$font-size-base: 16px !default;
$font-size-16: 1rem !default;
$body-min-width: 20rem !default;
$container-max-width: 80rem !default;
$menu-width: 16rem !default;
$toc-width: 16rem !default;

1rem对应16px,因此有效画布的最大尺寸为80*16px=1280px,其中菜单menu和标签toc的组件宽度固定为16rem,对于横向分辨率大于1280px的浏览器,两边自动留空。在网站的正文区域,最大横向显示尺寸为(80-16-16)*16px=768px,由此我们初步确定正文插图的最大的横向尺寸为768px,其它容器中的图像尺寸也可以在 css 样式中查到,或者直接通过浏览器开发者模式(ctrl+shift+c)并用样式拾取器查看。

对于移动端,我们在浏览器开发者模式中模拟移动设备(Device Toolbar),可以看到一些预设的设备尺寸,比如Samsung Galxy S20 Ultra的尺寸为412*915px。然而,如果我们将图像降采样为412px像素,会感到模糊不清,412px也远低于真实的屏幕分辨率。这和浏览器渲染网页使用的是「CSS 像素(viewport)」而非物理像素有关,例如 Galaxy S20 Ultra 的 CSS 像素为412px*915px,物理像素为1080px*2400px(FHD+模式),比值 Device Pixel Ratio (DPR)为 2.62。

设备 DPR

在像素密度较高的设备(如 Retina 显示器)上,DPR 大于 1(例如 2、3 甚至更高)。 这意味着单个 CSS 像素将由多个物理像素表示,从而产生更清晰的图像和文本。从本质上讲,DPR 允许 Web 开发人员使内容适应不同的屏幕分辨率,确保图像和文本在各种设备上显示清晰且大小合适。例如在 hugo-book 主题中,通过布局断点$mobile-breakpoint来进行移动端适配,$mobile-breakpoint的默认值为56rem896px

$mobile-breakpoint: $menu-width + $body-min-width * 1.2 + $toc-width !default;
@media screen and (max-width: $mobile-breakpoint) {
  .book-menu {
    visibility: hidden;
    margin-inline-start: -$menu-width;
    z-index: 1;
  }
...

但是,我们仍应准备等于或略高于CSS 像素 * DPR的图像,这样才能在高清屏(高 DPR)下显示清晰。在移动端,我们也可以简单地直接取物理像素为参考值(即不考虑边距)。

目前,移动端的高分屏已达1440px,我们就取这个作为移动端的尺寸上限。在桌面端,由于高分屏的普及,DPR 也随移动端一样水涨船高,比如 4k 屏和 iMac Retina 屏幕,这类屏幕的 DPR 一般可达 2。因此,综合现有硬件和 hugo-book 模板的设置,我们应该准备的插图横向尺寸不应小于1440px768*2=1536px。我们将博客中不同种类的图的最大尺寸计算出来,以最终的综合尺寸为目标像素值。

图像类型CSS 像素/px移动端最大尺寸/pxDPR(desktop)综合尺寸/px
banner76814402.01536
插图61414402.01440
双栏插图3327202.0720
卡片插图1203602.0360

正确地截图

相机/手机拍摄的图像分辨远远超过参考像素值,我们对其进行降采样处理。但如果网站中有大量的屏幕截图,其原始尺寸可能就比参考像素低了,当然我们可以对其进行超采样,但这件事放在前期做效果会更好。

在浏览器中,直接通过ctrl+鼠标滚轮对窗口放大(chrome 最大可以至 500%),再对目标进行截图就可以得到分辨率更高的图了。桌面环境(win11),可以通过系统 - 屏幕 - 缩放和布局 增加缩放比例,让小元素放大显示。

以截本站侧边栏状态图为例,该组件的 CSS 像素宽度为224px,2k/25 寸屏的缩放率一般为 150%,若直接屏幕截图得到的图片宽度为336px,放在正文中(768px 宽度)显然是不够的,我们直接将浏览器放大 500%,就可以截到宽度近1700px的图,对比如下。

重采样、格式、质量

python 的Pillow库可以快速实现图像缩放、压缩和保存。其重采样默认算法为BICUBIC,我们对时间不敏感,因此直接显式指定质量最高的LANCZOS插值3

img = img.resize((w, h), resample=Image.Resampling.LANCZOS)

在保存时,可以进一步选择格式、压缩率和质量。

img.save(output_path, format="WEBP", method=6, quality=quality)

显式指定速度最慢但压缩率最高的method=6,尽可能地降低文件大小。

显式指定格式format="WEBP"。WebP 支持有损压缩与无损压缩,且支持动图和 Alpha 透明通道。平均而言,WebP 的文件大小比同类 JPEG 图像减少了 30%。时至今日,Webp格式已经得到绝大多数浏览器支持(仅 IE 不支持)4。博客网站完全可以统一使用 Webp 格式图像。

quality极大地影响文件体积和质量,一般来说取值60-80就能平衡好质量 - 体积这对矛盾。大多文章也就介绍到这了,以一个较为普适但固定的参数来应对所有场景。但我在实践中发现,固定的quality取值经常造成图像压缩过度或不足,而用肉眼去评估图像质量显然是低效的。

图像压缩与质量评价

评价指标

为了在保证质量的同时,根据每张图片的具体情况最大化地压缩图像体积,要引入评价标准,主观地来说,可以通过以下几点,但无法量化差异:

  • 是否模糊、失真(如文字边缘锯齿、细节丢失);
  • 色彩是否偏差、对比度是否异常;
  • 压缩伪影(如马赛克、块效应、色带);

尝试使用 NeRF 常用的评价指标来协助量化差异。

指标全称原理含义优点缺点
PSNRPeak Signal-to-Noise Ratio 峰值信噪比基于 MSE(均方误差)计算信号强度与噪声强度的比值误差越小,PSNR 越高,代表压缩图像越接近原图简单快速,历史最悠久无法反映结构、感知差异;对视觉不敏感
SSIMStructural Similarity Index 结构相似性模拟人眼对亮度、对比度、结构的感知更符合人眼感知的结构对比考虑结构相似性,视觉友好对多尺度、大范围失真不敏感
MS-SSIMMulti-Scale SSIM 多尺度结构相似性多分辨率下计算 SSIM,增强全局感知比 SSIM 更稳定地反映感知质量比 SSIM 更接近人类主观评分计算复杂度比 SSIM 稍高
LPIPSLearned Perceptual Image Patch Similarity 感知图像差异基于深度学习,使用特征空间距离计算感知相似度越小越接近,越大越不相似最贴近人眼感知,处理模糊、结构变形效果好依赖模型,速度慢

实际操作,同时使用 MS-SSIM 和 LPIPS 来评价图像质量,分别设置阈值为0.980.02,通过搜索quality的值来获取最佳设置。我测试了博客中的 20 张图片,前 6 张为手机拍摄的照片,后 14 张则包含了电子书插图、屏幕截图、线稿图、PPT 合成图等。以quality=80作为参考值,由结果可以看到,自适应的quality选择范围很大,10-86 都有;20 张图的平均结果,自适应方法节省空间 84.81%,固定质量(80)则为 81.69%。虽然总的来看空间节省差距不大,但可以初步看出,「照片」所需的quality要比截图、线稿要大一些,且分辨率越大的图,quality也会偏大;而画面干净的图quality可以很小,比如7.png9.png10.png19.jpg

文件名原始自适应Q=80质量 QMS-ALPIPS-AMS-Q80LPIPS-Q80
1.jpg425.7KB150.5KB185.7KB710.99240.01910.99440.0104
2.jpg2175.4KB163.7KB235.5KB630.98980.01990.99260.0120
3.jpg559.1KB206.1KB159.9KB850.99130.01910.98850.0325
4.jpg537.9KB177.9KB146.7KB840.99070.01930.98890.0248
5.jpg660.3KB336.2KB291.1KB830.99120.01770.98840.0276
6.png1183.5KB67.5KB50.9KB860.99150.01970.98820.0309
7.png288.1KB61.5KB146.5KB120.98590.01860.99620.0041
8.jpg232.1KB37.9KB55.2KB560.98920.02000.99450.0074
9.png101.8KB12.0KB26.0KB130.98880.01850.99760.0030
10.png200.6KB16.7KB41.8KB120.98930.01890.99870.0020
11.png159.8KB14.8KB26.1KB330.98810.01970.99580.0053
12.png402.3KB163.4KB147.2KB830.98030.00720.97920.0097
13.png128.2KB8.9KB16.4KB250.98520.01790.99010.0072
14.png925.1KB83.1KB155.3KB310.98440.01970.99260.0086
15.png642.8KB61.8KB114.4KB400.98540.01980.99240.0085
16.png749.8KB37.4KB38.9KB790.99550.01880.99570.0166
17.png880.0KB25.1KB38.9KB520.99050.01930.99400.0076
18.png523.0KB35.1KB41.9KB760.99160.01820.99330.0145
19.jpg444.8KB53.8KB126.7KB100.99110.01570.99950.0009
20.jpg331.1KB41.4KB69.6KB160.99330.01890.99830.0037
总和11551.3KB1754.8KB2114.6KB     

与在线工具的对比

有很多在线图像压缩工具或 CDN 提供了图像优化服务,来试试我们的压缩效果与之相比如何5WebP Cloud ServicesTinyPNG的压缩率选择有较大的差别,WebP Cloud Services 的质量较好,TinyPNG 的压缩率较大。我们无法精细地调试这些在线工具的压缩参数,本地的灵活性则较高,通过参数的调试可以达到同样的效果。最终,根据我们设定的 MS-SSIM 和 LPIPS 阈值,使用quality=85获得了 42.5KB 大小的最终文件,而原文件大小 599.0KB。

 quality=93WebP Cloudquality=75TinyPNGquality=85
SIZE /KB75.875.728.428.642.5
PSNR /dB42.8241.8337.8935.2740.10
SSIM0.98460.97820.95980.95950.9716
MS-SSIM0.99690.99540.99030.98900.9937
VIF0.88060.85130.77200.76610.8279
LPIPS0.00550.00740.02630.02600.0198

链接转换与文件上传

把图片的压缩问题解决后,剩下的就很简单了:

  • 使用正则表达式匹配 markdown 文件中的链接(WiKI 和 Markdown 风格);
  • 分类,判断类型:静态/动态图片、视频、本地/外链/站内链接;
  • 根据分类进行降采样、压缩,移除元数据;
  • 生成唯一文件名,保存至本地,将 markdown 文件中的链接替换为标准图像引用格式;
  • 将压缩参数、文件名映射保存至数据库。

以下是几种正则匹配的样式和转换后的样式:

![](image_filename | url)
[](image_filename | url)
![[image_filename | url]]
[[image_filename | url]]
>>>>>Transfer to>>>>>
![](https://img.osnsyc.top/XXXXXX.webp)
banner: [[image_filename | url]]
>>>>>Transfer to>>>>>
banner: https://img.osnsyc.top/XXXXXX.webp
{{< dbcard
    ...
    cover=[[Pasted image 2025.png]]
    ...
>}}
>>>>>Transfer to>>>>>
{{< dbcard
    ...
    cover="https://img.osnsyc.top/XXXXXX.webp"
    ...
>}}
![](video_filename | url)
[](video_filename | url)
![[video_filename | url]]
[[video_filename | url]]
>>>>>Transfer to>>>>>
{{< video src="https://img.osnsyc.top/XXXXXX.mp4" >}}

链接替换完成后生成一个新的 markdown 文件,可以由 hugo 正确地编译。生成的附件也可以用脚本一键上传至 Cloudfalre R2 存储桶。最终,一个完整的 Obsidian 至 Hugo 的工作流只需要两行命令即可完成。相关代码可以移步GitHub - osnsyc/obsidian-to-hugo-toolbox查看。

# 格式化 Markdown 文件
python md_publisher.py -f test_post.md
# 上传至 R2
python r2_uploader.py -f <path_to_file_or_folder>
左: Obsidian,右:静态博客

我在去年建立博客之初Hugo 博客快速搭建小记写道:

我写了 9 篇博文,平均篇幅 4570 字,附件不算少,R2 空间用了 160MB,算下来,免费空间够写 562 篇长文了。

现在看来,博客共有文章 24 篇,各类图像都有6,优化后的附件总大小为 113.9MB,所以现在算下来,CloudFlare R2 免费空间够写 2107 篇长文了。

 数量体积/MB平均体积
静态图片25823.10.09MB
动态图片2987.93.03MB
视频13.93.9MB
总和288113.90.40MB

相关阅读

> 关注 少数派小红书,感受精彩数字生活 🍃

> 实用、好用的 正版软件,少数派为你呈现 🚀


文章来源: https://sspai.com/post/101376
如有侵权请联系:admin#unsafe.sh