终于为自己的小网站做了一款小工具(用Python开发),smally,无损批量压缩JPG和PNG图片,以及其它一些方便网站图片管理的功能。开发这个工具的需求,就是围绕网站图片的管理,网站的一个核心诉求就是访问速度,而对图片的核心需求就是体积要尽可能的小,尽量都使用JPG图片。
没碰有损压缩,因为这会直接导致图片的视觉效果变差,而每个人对视觉效果变差的接受程度不一样。软件运行可能会生成新的图片(保留图片文件名不变),如果是做有损压缩,就必须要将原图进行备份保存,还要让使用者方便地对比压缩前后的效果,如果效果不好就要恢复原图。这些操作都极大地增加了软件的复杂度,也增加了使用者的复杂度(有好些WordPress的图片压缩插件就是这么干的)。而我只想做一款够简单的管理网站图片的工具。有损压缩,请使用别的工具,最后再用smally做一轮无损压缩即可!
原理和算法
smally使用著名的jpegtran工具来进行JPG图片的无损压缩,除了这个工具,还使用了一个小算法:smally对每一张JPG图片,生成两份临时图片,分别是baseline格式和progressive格式,然后比较原图,baseline图和progressive图的体积大小,在这三者中选择体积最小的那一张;如果原图的大小与progressive格式一样,选择progressive格式的图片(几乎不存在这种情况,但程序逻辑已覆盖)!这部分的细节,请参考:网页图片优化指南。
对于PNG图片,使用optipng进行无损压缩,命令行可以自定义压缩级别。
smally的安装和配置
你需要确保Linux系统的PATH路径中能够找到 jpegtran,identify 和 optipng 这三个工具!
如何编译安装jpegtran工具,请参考:在Linux系统中编译安装libjpeg
identify工具来自著名的Imagemagick,安装命令:sudo apt install imagemagick。如想编译安装,请参考:编译安装Imagemagick
你还需要Python3,smally只能在Python3下运行。如果需要Python3的安装帮助,请参考:在Linux系统中编译安装Python3。
安装optipng:sudo apt install optipng
编译安装的好处是,可以更方便的选择这些工具的版本!
最后,获取smally的源码:
$ git clone https://github.com/xinlin-z/smally
smally使用说明
smally工具的各项参数说明:
$ python3 smally.py -h
-h,可查看很多usage examples;
--show,--size,--jpegtran,--optipng 这4个功能选项是三选一;
--jpg,--png,--gif,--webp 这4个图片类型参数可以多选,但至少要选一个;对于 --show 命令,可以不选择图片类型,此时将显示路径中的其它文件信息(V0.21新增)
-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和PNG图片
--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/0/123
打印信息说明:
-- 表示无变化,-xxx 表示压缩了xxx字节,-百分号表示压缩比,[b] 表示最后选择了baseline格式,[p] 表示最后选择了progressive格式。
c/n/e/t:表示一共扫描了t个文件(所有的文件),其中有e个文件错误(文件名以 - 开头,或者文件有图片后缀但却不是图片内容),其中符合条件并执行动作的有n张图片,只有c张图片被真正执行(不如压缩)。--show和--size命令,c=n。
只显示有压缩的信息(如果图片特别多的话):
$ python3 smally.py -p path/to/pic -r -k --jpegtran --jpg | \
grep -E "\s-[0-9]{1,}\s"
批量压缩PNG图片的操作是一样的,唯一的区别是,需要自己指定一个压缩级别,没有默认值(建议选择o2,这是optipng的默认值):
$ python3 smally.py -p path -r -k --optipng o2 --png
我已自己的网站服务器上部署这个脚本,每天凌晨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]: display stat: 17/17/0/27
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
[smally]: display stat: 7/7/0/27
网页图片优化的一条准则是,一般图片尽量都使用JPG格式,因为JPG是“性价比”最高的图片方案。smally的show功能,可以帮你找出所有非JPG图片,方便你的优化。比如找出所有webp图片,你需要用JPG格式去替换webp,因为webp至今的兼容性还不是很好。
查看体积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,请各位根据自己的情况修改参数。
显示其它文件信息(图片文件夹里面怎么有别的文件?):
$ python3 ~/repos/smally/smally.py -p . --show
/home/pi/test/pics/pkg.link __Not_Reg_File
/home/pi/test/pics/iamnotapic __Not_Pic_File_Extension
显示错误的图片文件:
$ python3 smally.py -p path --show --jpg --gif --png | grep __Wrong_File
(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
[smally]: total size: 28099, 27.44K, 0.027M, 0.0G, 15/15/0/20
版本
2020年10月30日,V0.22:
增加--optipng选项,批量压缩PNG图片;
重构优化部分代码;
2020年7月5日,V0.21:
用logging代替print;
图片统计信息增强,l/m/n修改为c/n/e/t,并在所有命令中都有;
--show 命令可以不带图片类型,此时显示其它文件;
完善 -h 信息;
bugfix;
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 --