前言
相机、手机等设备拍摄的照片通常输出为JPEG格式,而直出的JPEG图片不仅压缩率低,而且还为了保存图片上的无用噪点而浪费了大量的存储空间。笔者经常需要将这些JPEG图片转码为WebP格式,以节省存储空间。
笔者以前通常使用bash、zsh或fish的for循环,调用各编解码器的命令行工具来实现批量转码,但是WebP等图片往往无法多线程编码,在转码时只有一个核实际参与计算,导致电脑性能不能得到充分利用。
parallel
的使用
笔者最近开始使用parallel这个工具进行并行的多张图片批量转码,它可以将多个命令行工具的输出进行并行处理,从而充分利用电脑的性能。
首先需要安装parallel
,在Arch Linux下可以使用pacman
安装:
sudo pacman -S parallel
parallel
的基本使用方法非常简单,既可以使用:::
或<
来传递并行处理的参数,也可以使用管道符|
来传递并行处理的参数,例如:
parallel echo ::: 1 2 3 4 5
parallel echo < <(seq 1 5)
seq 1 5 | parallel echo
这三条命令的输出均为:
1
2
3
4
5
parallel
还可以接受一些选项来调整并行处理的参数,例如:
-j
:指定并行处理的最大任务数,例如-j 4
表示最多同时处理4个任务;默认值为CPU核心数。-k
:保持输出的顺序,即使任务完成的顺序不同。--bar
:显示进度条。
将parallel
用于并行图片转码
在有多张图片的情况下,使用parallel
可以弥补图片编码器本身不支持多线程编码的问题,从而充分利用电脑的性能。
可以使用以下命令将当前目录下的所有JPEG图片转码为WebP格式,保留所有元数据信息,并显示进度条:
parallel --bar "cwebp -metadata all {} -o {.}.webp" ::: *.jpg
这里的{}
表示parallel
接受的参数,{.}
表示parallel
接受的参数的文件名部分,:::
表示parallel
接受的参数来自于命令行,*.jpg
表示当前目录下的所有JPEG图片。
对于较大的WebP图片,则需要对cwebp
命令的-segments
选项调整为1
,还可以将-partition_limit
选项调整为100
,从而提高编码速度:
parallel --bar "cwebp -metadata all -segments 1 -partition_limit 100 {} -o {.}.webp" ::: *.jpg
如果需要同时删除原图,可以使用以下命令:
parallel --bar "cwebp -metadata all -segments 1 -partition_limit 100 {} -o {.}.webp && rm {}" ::: *.jpg
类似地,如果需要调用ffmpeg
或者convert
其他命令行工具来批量转码图片,也可以使用parallel
来实现:
parallel --bar "ffmpeg -hwaccel auto -i {} -c:v libsvtav1 {.}.avif" ::: *.jpg
parallel --bar "convert {} {.}.avif" ::: *.jpg
对于音频转码,可以考虑类似的方法,但是对于视频转码则没有必要,因为视频编码器一般有良好的多线程支持。