smally:批量无损压缩JPG图片

2019年8月19日 / 1,072次阅读 / Last Modified 2020年6月23日
开源项目

终于为自己的小网站做了一款小工具(用Python开发),smally,无损批量压缩JPG图片,以及其它一些方便网站图片管理的功能。开发这个工具的需求,就是围绕网站图片的管理,网站的一个核心诉求就是访问速度,而对图片的核心需求就是体积要尽可能的小,尽量都使用JPG图片。

smally项目地址:https://github.com/xinlin-z/smally

没碰有损压缩,因为这会直接导致图片的视觉效果变差,而每个人对视觉效果变差的接受程度不一样。软件运行可能会生成新的图片(保留图片文件名不变),如果是做有损压缩,就必须要将原图进行备份保存,还要让使用者方便地对比压缩前后的效果,如果效果不好就要恢复原图。这些操作都极大地增加了软件的复杂度,也增加了使用者的复杂度(有好些WordPress的图片压缩插件就是这么干的)。而我只想做一款够简单的管理网站图片的工具。有损压缩,请使用别的工具,最后再用smally做一轮无损压缩即可!

原理和算法

smally使用著名的jpegtran工具来进行JPG图片的无损压缩,除了这个工具,还使用了一个小算法:smally对每一张JPG图片,生成两份临时图片,分别是baseline格式和progressive格式,然后比较原图,baseline图和progressive图的体积大小,在这三者中选择体积最小的那一张;如果原图的大小与progressive格式一样,选择progressive格式的图片(几乎不存在这种情况,但程序逻辑已覆盖)!这部分的细节,请参考:网页图片优化指南

smally的安装和配置

你需要确保Linux系统的PATH路径中能够找到 jpegtran 和 identify 这两个工具!smally重度依赖这两个程序。

如何编译安装jpegtran工具,请参考:在Linux系统中编译安装libjpeg

identify工具来自著名的Imagemagick,请参考:编译安装Imagemagick

你还需要Python3,smally目前只能在Python3下运行。如果需要Python3的安装帮助,请参考:在Linux系统中编译安装Python3

最后,获取smally的源码:

$ git clone https://github.com/xinlin-z/smally

smally使用说明

smally工具的各项参数说明:

$ python3 smally.py -h

-h,可查看很多usage examples;

--show,--size,--jpegtran 这3个功能选项是三选一;

--jpg,--png,--gif,--webp 这4个图片类型参数可以多选,但至少要选一个;

-p,表示待处理图片所在的路径,支持输入1个或多个路径参数;(V0.20将-a升级为-p,并开始支持相对路径)

-i,时间间隔(可选),表示处理每张图片间的间隔时间,如果直接在繁忙的服务器上操作,图片数量又很多,这个参数可以平滑smally工具对CPU的占用;(V0.17新增)

-r,递归进入子目录,默认smally会skip子目录;(V0.19新增)

-k,对于压缩后的文件,保持其于原文件的mtime一致;(V0.19新增,如果你有每日压缩的routine,并配合 -t 参数,这个 -k 参数就很有用,-k 参数只在 --jpegtran时有效)

-t,设置一个时间窗口(从运行smally的时刻往后的秒数),smally只会处理在此时间窗口中的文件;(V0.19新增)

smally从 -p 参数指定的路径开始,配合 -r 递归遍历寻找此路径下所有的图片(含子路径中的图片),做相应的处理,保持其它非图片文件不动。

(0)无损批量压缩JPG图片

--jpegtran 参数用来执行无损JPG的批量压缩。

无损批量压缩过程涉及到临时文件的创建和删除,如果担心原图损坏,建议先做一个备份。smally通过调用jpegtran工具生成临时文件,对比尺寸,然后删除较大的两份文件,修改选中文件名为原来的名字(除非原图最小)。这个过程如果出现任何异常,程序都会终止,恢复图片文件并删除临时文件。

$ python3 smally.py -p path/to/pics -r -k --jpegtran --jpg
/pics/vim_cheat_sheet.jpg -- [p]
/pics/firefox_ca_info.jpg -- [p]
/pics/reset_firefox.jpg -- [p]
/pics/reset_firefox-400x271.jpg -2246 -9.16% [p]
/pics/bad_ad.jpg -240 -6.33% [b]
/pics/dns_jumper-200x92.jpg -704 -9.92% [p]
/pics/jpg_youhua-400x326.jpg -2987 -11.17% [p]
/pics/reset_firefox-200x136.jpg -588 -7.25% [p]
/pics/tplink_dns-200x141.jpg -597 -11.32% [b]
/pics/vim_cheat_sheet-400x278.jpg -3228 -7.55% [p]
/pics/dns_test-193x150.jpg -797 -8.27% [p]
/pics/firefox_privacy-200x49.jpg -400 -12.28% [b]
/pics/vim_cheat_sheet-200x139.jpg -906 -7.23% [p]
/pics/bitmap.jpg -- [p]
/pics/dns_test.jpg -- [p]
/pics/jpg_youhua.jpg -- [p]
/pics/firefox_privacy.jpg -- [p]
/pics/dns_jumper.jpg -- [p]
/pics/jpg_youhua-184x150.jpg -638 -8.51% [b]
/pics/dns_test-400x310.jpg -2961 -7.81% [p]
/pics/firefox_ca_info-400x448.jpg -4038 -8.19% [p]
/pics/bitmap-200x83.jpg -680 -9.55% [p]
/pics/tplink_dns.jpg -- [p]
/pics/tplink_dns-768x542.jpg -5194 -13.35% [p]
/pics/firefox_ca_info-134x150.jpg -479 -6.57% [b]
/pics/firefox_privacy-400x98.jpg -857 -9.63% [p]
/pics/tplink_dns-400x282.jpg -1420 -9.49% [p]
/pics/dns_jumper-400x184.jpg -2355 -10.96% [p]
[smally]: total saved: 31315, 30.58K, 0.03M, 0.0G, 19/28/123

打印信息说明:

-- 表示无变化,-xxx 表示压缩了xxx字节,-百分号表示压缩比,[b] 表示最后选择了baseline格式,[p] 表示最后选择了progressive格式。然后打印出一共压缩了多少空间出来。l/n/m 表示一共扫描了m个文件,其中符合条件的有n张图片,只有l张图片被压缩。

只显示有压缩的信息(如果图片特别多的话):

$ python3 smally.py -p path/to/pic -r -k --jpegtran --jpg | \
        grep -E "\s-[0-9]{1,}\s"

我已自己的网站服务器上部署这个脚本,每天凌晨4点30分自动执行,然后将结果email到我的信箱......:)

(1)查看图片信息

--show 参数用来查看图片信息:

$ python3 smally.py -p path/to/pics -r --show --jpg
/home/pic/uploads/2019/01/ieee754-2008-400x224.jpg 400x224 18.37K
/home/pic/uploads/2019/01/stepstone-768x512.jpg 768x512 94.33K
/home/pic/uploads/2019/01/ieee754-2008-200x112.jpg 200x112 6.29K
/home/pic/uploads/2019/01/stepstone.jpg 1000x667 119.69K
/home/pic/uploads/2019/01/heshu.jpg 500x314 40.68K
/home/pic/uploads/2019/01/ieee754-2008.jpg 593x332 34.62K
/home/pic/uploads/2019/01/git.jpg 200x150 6.4K
/home/pic/uploads/2019/01/stepstone-200x133.jpg 200x133 11.09K
/home/pic/uploads/2019/01/zhangdie.jpg 490x854 67.49K
/home/pic/uploads/2019/01/heshu-200x126.jpg 200x126 10.73K
/home/pic/uploads/2019/01/zhangdie-400x697.jpg 400x697 43.32K
/home/pic/uploads/2019/01/juanji-400x257.jpg 400x257 15.08K
/home/pic/uploads/2019/01/zhangdie-86x150.jpg 86x150 3.97K
/home/pic/uploads/2019/01/heshu-400x251.jpg 400x251 29.86K
/home/pic/uploads/2019/01/stepstone-400x267.jpg 400x267 34.39K
/home/pic/uploads/2019/01/juanji.jpg 662x426 27.96K
/home/pic/uploads/2019/01/juanji-200x129.jpg 200x129 6.26K

smally会显示出图片的路径,宽x高(pixel),和体积大小(单位K)。还可以同时查看多种类型的图片:

$ python3 smally.py -p path/to/pics -r --show --jpg --png --gif
/home/xinlin/test/pics/chanpinzhongxin.gif 1621x270 189.97K
/home/xinlin/test/pics/hsaoma.gif 400x225 1447.65K
/home/xinlin/test/pics/te.jpg 778x445 157.42K
/home/xinlin/test/pics/5.jpg 750x599 91.46K
/home/xinlin/test/pics/tu10.png 600x322 312.82K
/home/xinlin/test/pics/tu6.png 600x450 494.57K
/home/xinlin/test/pics/9.jpg 750x733 211.47K

网页图片优化的一条准则是,一般图片尽量都使用JPG格式,因为JPG是“性价比”最高的图片方案。smally的show功能,可以帮你找出所有非JPG图片,方便你的优化。比如找出所有webp图片,你需要用JPG格式去替换webp,因为webp至今的兼容性还不是很好。

如果配合Linux的其它命令行工具,还可以实现更多查询显示功能。比如统计某种类型图片的数量

$ python3 smally.py -p path/to/pics -r --show --jpg | wc -l

查看体积Top10的JPG图片(重点优化对象):

$ python3 smally.py -p path/to/pics -r --show --jpg | sort -k3nr | head

查看体积在1000K以上的JPG图片(重点优化对象):

$ python3 smally.py -p path/to/pics -r --show --jpg | grep -E "\s[0-9]{4}.*K$"

查看宽大于768pixel的JPG图片(重点优化对象):

$ python3 smally.py -p path/to/pics -r --show --jpg | grep -E \
            "\s(769|[7-9][7-9][0-9]|[8|9][0-9]{2}|[0-9]{4,})x.*\s"

以上配合Linux的sort和grep命令的使用case,请各位根据自己的情况修改参数。

(2)计算文件夹中所有图片的总体积

--size 参数用来计算指定文件夹中指定类型图片的总体积,不支持计算单张图片的大小(使用ls -l命令就可以)。

$ python3 smally.py -p maixj.net/pics/ -r --size --jpg --png --gif
[smally]: total size: 241903070, 236233.47K, 230.697M, 0.2253G

版本

2020年3月7日,V0.20:

  • 将 -a 参数升级为 -p,可以输入相对路径;

2020年2月7日,V0.19:

  • 增加 -r 参数;
  • 增加 -k 参数;
  • 增加 -t 参数;
  • 增强 -a 参数,使其可以接受多于一个的路径参数;

2020年1月29日,V0.18:

  • 重构代码,核心代码采用OOP方式,以便后期增加GUI等新功能;
  • jpegtran时,n/m修改为l/n/m;

2019年12月31号,V0.17:

  • 增加-i可选参数
  • 增加异常时对临时文件的清理
  • 修复bug并优化代码

2019年9月17号,V0.16:

  • 在压缩时,增加压缩比率的显示
  • 轻微优化代码结构

2019年8月30日,V0.15:

  • 在--jpegtran命令中,增加n/m的显示;
  • 优化调整部分代码;

2019年8月24日,V0.12:

  • 在--show命令中增加 width x height的信息;
  • 优化算法逻辑;
  • 更新readme.md;
  • 代码优化和bugfix;

2019年8月19日,V0.09:

  • 第1个版本

希望您能喜欢smally!有任何想法,欢迎在项目的Github页面提Issue或PR,或者在本页留言。

-- EOF --

本文链接:https://www.pynote.net/archives/882

留言区

《smally:批量无损压缩JPG图片》有4条留言

电子邮件地址不会被公开。 必填项已用*标注

  • 麦新杰

    jpegtran的版本已经到9d了,无损压缩比列更厉害一点点... [回复]

  • 麦新杰

    Identify这个工具是必须的,smally用这个工具来判断jpg图片是baseline,还是progressive。 [回复]

    • 麦新杰

      还用这个工具来判断图片文件数据是否正常。 [回复]

  • 麦新杰

    也许你自己上传到WordPress的图片已经压缩好了,但是WordPress会自动生成几个不同尺寸的图片,这些自动生成的图片,还有不少压缩空间。 [回复]


前一篇:
后一篇:

More


©Copyright 麦新杰 Since 2019 Python笔记

go to top