【142】24周 通吃常用格式,用 LaunchBar 快速无损压缩图片 | 工作日志

Minja
02月07日

通吃常用格式,用 LaunchBar 快速无损压缩图片 | 工作日志

| 本文为付费栏目文章,您已订阅,可阅读全文 |
注:我们常说的「无损」,英文为「advanced lossy」,其实是「高级有损」压缩,只是画质的损失较少。
上周 @Hum 撰写了长文 Best Of:iOS 上的日历应用 ,我负责处理配图。由于文中有大量 iPhone X 的截图和录屏,体积非常大,我就用上了一个批量压缩图片的自动化动作,最终效果也比较满意,我们在信号不佳的南昆山山区成功发布了文章,并且文章加载起来也很快。
这个立下功劳的自动化动作是我自制的,这篇文章就带你了解它的优点、制作和和使用方式,其中语法的介绍部分如果你不感兴趣可以不读,不影响使用这个动作。现在请下载这个动作的 LaunchBar 版本 ,一边使用一边阅读本文。

为什么要自制图片压缩动作

自从开始写作后,我要处理的图片就多了起来,对于图片压缩的需求就也与日俱增,用过的工具更是不胜枚举,去年下半年有一段时间稳定在了 TinyPNG + GIF Compressor 的组合。
但是每次拖动上传图片很不方便,而且它们完全依赖网络,给我的工作带来了一些限制。最后我研究了几十个压缩服务和工具,把最好用的几个命令行工具(它们自定义程度很高)组合起来,做出了一个极致轻量、快速的本地自动化动作。它有着这些优点:
  • 本地运行,无需网络
  • 支持 jpg、png 和 gif
  • 压缩速度非常快
  • 体积减少明显,画质损伤小
  • 可批量压缩
  • 完全免费

快速批量压缩图片
选择文件,用快捷键发送到 LaunchBar,键入几个首字母就打开所需动作,随即压缩好了图片。不光能批量压缩,同时导入 jpg、png 和 gif 也能一次性处理完。

原料准备

事实上,这个动作是把几个命令行工具组合起来,针对不同格式的图片调用不同的工具。
在制作这个动作前我们需要先安装三个命令行工具:pngsquantjpegoptim 、和 gifsicle 。从它们的名字你也能猜出个大概,各自是负责处理 jpg、png 和 gif 格式的图片。
对于这三个工具我不做过多介绍,老手也可能有别的选择。你只需知道它们速度快、画质不输 TinyPNG 和 GIF Compressor,最重要的是,作为命令行程序,我可以很轻松地把它们融入 LaunchBar。
先打开 Terminal,用三条 brew 命令各自安装几个工具:
brew install pngquant
brew install jpegoptim
brew install gifsicle
安装 pngsquant 和 jpegoptim 时可能会「附赠」你一堆陌生的命令行工具,把 Terminal 搞得五颜六色,不用担心,它们是必要的依赖,我保证你的电脑没有被全家桶入侵 。
三个工具的语法各有不同,但我们最后要一视同仁地实现这个效果:
把压缩好的图片放到当前目录。
所以,每个工具的具体调教方式也有细微不同,这里只以 pngquant 为例讲讲思路。一般呢,如果你在 Terminal 里差遣 pngquant,可以输入这条命令:
pngquant 带压缩图片 --quality 70-95 -o haha.png
它的意思是压缩后保证最合适的画质,一般一张图压完后体积就直线下降,效果非常明显。

如果你比较细心,会注意的这个压缩率已经可以和大名鼎鼎的 TinyPNG 相比了。其实,现在的图片压缩算法已经很高效,我这台性能羸弱的 MacBook 也能迅速处理图片。使用在线压缩工具时真正拖累处理速度的,实际上是图片的上传与下载,所以我最终还是选择了本地工具。
接下来,看看 LaunchBar 是怎么调遣 pngquant 的。

制作动作

LaunchBar 可以直接运行脚本,换言之,不用打开 Terminal,就可以直接招呼上面那哥仨儿。但是 macOS 欺负外地人,非系统自带命令无法随意召唤(大概是我还没找对方式);请教 LaunchBar 教程作者 @契丹神童 讨论后,我决定借助更简单清晰的 Python 脚本来调用图片压缩命令。
我们来加一个自定义的动作。呼出 LaunchBar,按下快捷键 ⌥Option-⌘Command-E 打开动作编辑界面,点击左下角新建一个动作。移步右侧中间的「Scripts」,把所需脚本语言设为「Python(它可以让你尽可能避开那些诡异的语法问题)。1

点击「Edit」开始写脚本。想必你现在已经看累了,来点提神的东西吧 :

没事,这里绝大部分代码都不用理睬,蓝色部分是一些注释,黄色部分用于导入各种功能的模块,绿色的负责声明环境变量,最下面那一点点东西才是你要关心的。
首先看大红色的 for 这一行,它妙不可言,能把批量选中的图片依次交给接下来的命令去处理,每一张图片都能挨个洗净等着下锅。这就让 pngquant 命令变得非常易用,你不用每次手动输入文件名(这简直太恐怖了),直接把一张或一堆图片发送到 LaunchBar 就等同于指定了需要压缩的对象。
接下来,为了让 Python 能读懂命令,需要把它写成列表的格式(粉色部分):
my_command = ["pngquant", arg, "--quality", "70-95", "--force"]
但光有一条命令还不够,得指定一个干活的苦力,也就是把环境变量加上再执行:
sp.check_output(my_command, env=my_env)
现在就能压缩 png 格式图片了。
若非我们志在一次性搞定三种图片格式,此时就该停下脚步。精益求精,我们加两行判断语句(天蓝色部分),如果图片拓展名为 .png.PNG.Png 等变形写法,就对用 pngsquant 来处理:

如果是 gif 或 jpg 呢?就用其他两个工具。
完整的代码在下面。调用 jpegoptim 和 gifsicle 时会有一些差别,特别说明,jpegoptim 会毫不客气地覆盖原图,所以我导入了一个 shutil 模块,用来原地拷贝一份图片,不去动用原图。
#!/usr/bin/env python
#
# LaunchBar Action Script
#
import sys
import subprocess as sp
import os
import json
import shutil

my_env = os.environ.copy()
my_env["PATH"] = "/usr/local/bin:" + my_env["PATH"]
# Note: The first argument is the script's path

for arg in sys.argv[1:]:
fileType = (os.path.splitext(arg)[-1]).lower()
fileFolder = os.path.dirname(arg)
fileName = os.path.basename(arg)
newFile = fileFolder + "/new-" + fileName
if fileType == ".png":
my_command = ["pngquant", arg, "--quality", "70-95", "--force"]
sp.check_output(my_command, env=my_env)
elif fileType == ".jpg" or fileType == ".jpeg":
shutil.copy(arg,newFile)
my_command = ["jpegoptim", "-m70", "--max90", newFile]
sp.check_output(my_command, env=my_env)
elif fileType == ".gif":
my_command = ["gifsicle", "-i", arg, "--optimize=3", "-o", newFile]
sp.check_output(my_command, env=my_env)
保存好这个 LaunchBar 动作,抓来一撮儿格式各异的图片测试一下:

喔!

小结

对于图片压缩的折腾,到此算是暂告段落。去年八月起我就开始写这方面的文章,从单纯的工具推荐到现在打造适合自己的自动化动作,在使用中不断升级工具和工作方式。
曾几何时,图片压缩还令我头疼,轮番向 TinyPNG、GIF Compressor 求救也不是最终解决之道。现在有了这个自动化动作,我终于可以快速、批量、无视图片格式地完成压缩。
动作下载请赴我的 GitHub 。比较可惜的是,目前这个动作只有 LaunchBar 版本,因为 LaunchBar 对变量的输入、输出控制得非常好,我不用花时间去解决导入、导出图片的问题。Aumator 和 Keyboard Maestro 暂时没有这个压缩动作的对应版本,它们批量处理文件时容易宕机2 。至于 Alfred,由于我不知道如何一次性向它传递多个变量(多张图片),但我这份代码用以处理单张图片是可以的,如果有 Alfred 用户知道如何批量处理图片,请在评论区里告诉我。
  1. 直接用 shell 脚本,遇到名字带空格的文件就会出错。最常见的问题就是没法处理截屏图片。
  2. 传说中的「无限齿轮」,即菜单栏上出现一直在旋转的齿轮,只能重启或登出来解决。

上一期
为文件设置多种快速打开方式 | 实用技巧
下一期
iPhone X 截图掐头去尾 | Workflow 定制
 
精选评论(3) 我的评论
  • 契丹神童
    @Oscar 如果是绝对路径的话,每一次的软件更新都需要重新修改代码中的路径。另外,如果一个软件内部还调用其它软件功能的话,填绝对路径依然会出错。Python 可以直接跳过环境变量的问题,相对来说一劳永逸。
    02月08日 1
  • jinzhuo
    之前一直用 @ghui 的 Dropzone 的插件,来压缩图片,用的是 Tinypng 的服务,无网情况下就没法用了,而且依赖 requests 模块需要一定的动手能力...
    https://ghui.me/post/2016/08/tinify/
    02月08日
  • OscarGong
    homebrew 安装的第一个软件名应为「pngquant」。

    另外非系统自带软件在 Shell 脚本无法运行的情况,指定 pngquant 的绝对路径就 OK:( homebrew 安装的为)/usr/local/Cellar/pngquant/2.11.7/bin/pngquant
    02月08日
    • 少数派编辑部
      谢谢指出,软件名已改正。

      绝对路径也是一个好办法,不过我这个动作
      用到三个软件,为代码整洁就指定三方bin
      了。

      —— by Minja
      02月08日