压缩博客的图片和视频

最近琢磨着更新一下《爱丁堡的博物馆,但因为要先把图片拖到OneDrive文件夹里,再点右键在线查看→···→嵌入大(1024px)→复制URL→输入![alt text]()→粘贴,所以歇了。仔细一想,这样插图确实太复杂了,干脆还是把图片全存本地,用remotely-save同步到VPS里好了——但这样就需要自己压缩图片和视频,也就有了这篇博客。

图片

压缩图片最立竿见影的方法是降分辨率。我不清楚2023年博客最适合的分辨率是多少,但我之前插的图大部分是1024px,够用。

ImageMagick可以原地修改图片(magick mogrify,但因为我要保留原图看压缩有没有劣化太多,所以我喜欢用创建新图片的convert(仍然是ImageMagick的一部分,但切记不要在前面加上magick。让图片最长边不超过1024px的命令是:

convert 要修改的图片 -resize 1024x1024\> 新的图片 # 注意大于号

2024-02-06更新

其实在2023-12-14,也就是写完《音乐整理博士》的前几天,我不再用ImageMagick压缩图片了。

现在我直接把原图通过git-annex记录进Git仓库,再pushS3桶中。在Netlify构建时,先恢复缓存,再从S3桶中下载新增的图片。然后使用Zola的模板函数压缩图片、把指向原图的<img>替换成带有srcset、height、width、decoding、loading属性的<img>(视频仍然用FFmpeg提前压缩好。最后再把缓存保存到Netlify的缓存目录里。

光说有点抽象,最好还是把设置仓库的命令、压缩图片的模板、构建脚本都贴上来。但是我已不想在博客上花时间了,所以我不会解释到那种程度。只是有读者在我停更之后才发现这篇博客,我才决定至少要说明一下现在的解决方案。

这样的好处是保留了原图,之后想要改变压缩策略时不会被二次压缩。因为使用了srcset配合多种分辨率的同一张图,使用小屏幕浏览时不会加载没必要的细节。而且所有图片都由Netlify分发,速度大概会比自己的VPS快。还有,把图片一同登记到Git中,可以避免更新了Markdown,但忘了把配套图片传到VPS的粗心之举(真的发生过

快过年了,祝大家万事如意。

JPEG

缩小图片之后我们还可以更进一步减小JPEG图片的大小——当然,以技术指标上的降质来换。参数降低不代表观感降低,所以可以大胆地压。最长边只有1024pxJPEG,压到100KB左右观感毫无问题:

jpegoptim 新的图片(会被覆盖) --quiet --size=100K

JPEG一般是自己的相片,在分享前得把敏感元信息脱掉这件事已经是共识了。网上的教程喜欢用ExifToolImageMagick一口气去掉所有元信息,但其实有些元信息是应该保留的:

  1. EXIF Orientation信息:当你旋转一张照片时,编辑器大概率只是在这里记录下旋转了多少度,并没有真的把整张图片转过去。所以要么保留它,要么在去除它之前真的把图片转过去(convert -auto-orient
  2. ICC Profile:这里记录了图片的色彩空间等信息,具体我也不懂,但去除后图片会变色。我的做法是保留它们,因为最敏感的GPS信息是以EXIF格式存储的。

另外,拍摄时间之类的元信息也没必要清除——如果一张照片连拍摄时间都要隐藏才能发,那我建议直接别发。俗话说的好:上网不涉密,涉密不上网。

PNG

PNG格式的图片一般不会暴露敏感信息:一来谁的相机照出来是PNG啊,二来PNG17年才加入EXIF支持。所以不用担心什么元信息。

至于压缩软件PNG我选pngquant。记得19年我选了一圈,但现在忘了当时为什么选pngquant了。

视频

可恶,我为什么要在博客里插视频呀,这不是给自己找麻烦么!我插了几段H.265编码,比特率莫名其妙地高的视频——太占地了,压缩!

最开始我用降低比特率的方法压缩,但是发现有些读者没法看H.265的视频。然后我开始考虑把H.265的视频转成VP9/AV1给看不了H.265的朋友当退路,所以对比了下libvpx-vp9、libsvtav1的编码速度和效果(libvpx-vp9的速度极慢,效果也不如libsvtav1——但它们的速度和效果都不如libx265。考虑到这三种编码的覆盖率各有千秋,最后我还是把目光投向了所有浏览器都支持的H.264——毕竟博客上的视频是让读者看的,不是给自己收藏的,所以折腾那些读者没法看的编码、参数没有用。

可是,视频原本是H.265,如果其他条件相同,转成H.264一定会更大。那只好使用绝活了——降分辨率:

ffmpeg -i input.mp4 -vf scale=iw/2:ih/2 output.mp4

另外,在安卓上用remotely-save插件同步视频会造成Obsidian闪退,解决方法是禁止同步大文件。

脚本

基本就是给前面提到的命令加个for循环。其中EXTENDED_GLOB是为了开启GLOB的取反和或操作,NULL_GLOB则是在匹配不到任何字符串时取消执行整条命令而不报错。

还有,最开始我对每个循环都遍历一次所有文件——毕竟从复杂度上来说这和只遍历一次一样,不过我有331个文件和26个文件夹,遍历一次已经够慢了,所以还是改掉了。

#!/bin/zsh

set -euxo pipefail

SRC_FOLDER=$1

setopt EXTENDED_GLOB NULL_GLOB # Don't exec if no match
files=($SRC_FOLDER/**/(*.{jpg,png,mp4}~*-(optim.jpg|fs8.png|scaled.mp4)))

cleanup () {
        sed -i "s|${1:t}|${2:t}|g" $SRC_FOLDER/**/*.md
        rm $1
}

for f (${(M)files:#*.jpg}) {
        local newf=${f%%.jpg}-optim.jpg
        convert $f -auto-orient -resize 1024x1024\> JPG:- \
                | jpegoptim - --quiet --strip-exif --size=100K > $newf
        cleanup $f $newf
}

for f (${(M)files:#*.png}) {
        local newf=${f%%.png}-scaled.png
        convert $f -resize 1024x1024\> PNG:- | pngquant - > $newf
        cleanup $f $newf
}

for f (${(M)files:#*.mp4}) {
        local newf=${f%%.mp4}-crf31.webm
        ffmpeg -i $f -vf scale=iw/2:ih/2 $newf
        cleanup $f $newf
}

复制以下链接,并粘贴到你的Mastodon、MisskeyGoToSocial等应用的搜索栏中,即可搜到对应本文的嘟文。对嘟文进行的点赞、转发、评论,都会出现在本文底部。快去试试吧!

链接:https://emptystack.top/note/compress-image-video


两条评论:

注:点击昵称可以查看对评论的回复。

  1. 河蚌 :abloblurk:

    @actor
    图片现在我在用i0.wp.com/ 来处理,虽然本质是cdn加速,但是也可以作为图床用了,也可以通过在链接尾部在参数来定制分辨率滤镜一系列。(除了不能删除外一切都好)

  2. Coelacanthus :archlinux: 🏳️‍⚧️

    @actor ICC 规范图像的色彩如何映射到屏幕/打印机的色彩(严格来讲还需要一个屏幕/打印机的 ICC profile 才能完成,前者 ICC 将图像的色彩映射到 PCS,后者将 PCS 映射到屏幕/打印机的色彩),如果移除它图像渲染软件就不知道如何正确映射色彩了,自然会偏色。