smally:批量无损压缩JPG图片

2019年8月19日 / 287次阅读 / Last Modified 2019年11月13日
开源项目

终于为自己的小网站做了一款小工具(用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的help信息

$ python3 smally.py -h
usage: smally.py [-h] -a ABSPATH [--jpg] [--png] [--gif] [--webp]
                 (--show | --size | --jpegtran) [-v]

optional arguments:
  -h, --help            show this help message and exit
  -a ABSPATH, --abspath ABSPATH
                        absolute path for the picture folder
  --jpg                 for both .jpg and .jpeg suffix
  --png
  --gif
  --webp
  --show                show pathname and size in bytes
  --size                calculate total size
  --jpegtran            lossless compress JPGs with jpegtran tool
  -v, --version         show program's version number and exit

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

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

-a 表示待处理图片所在的顶层路径,必须是绝对路径,支持~扩展。

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

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

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

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

$ python3 smally.py -a ~/pynote.net/pics/ --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

-- 表示无变化,-xxx 表示压缩了xxx字节,-百分号表示压缩比,[b] 表示最后选择了baseline格式,[p] 表示最后选择了progressive格式。然后打印出一共压缩了多少空间出来。n/m 表示压缩了n张图片,一共有m张图片。

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

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

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

(1)查看图片信息

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

$ python3 smally.py -a ~/test/pics/ --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 -a ~/test/pics/ --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 -a ~/test/pics/ --show --jpg | wc -l

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

$ python3 smally.py -a ~/test/uploads/2019/ --show --jpg | sort -k3nr | head

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

$ python3 smally.py -a ~/test/uploads/ --show --jpg | grep -E "\s[0-9]{4}.*K$"

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

$ python3 smally.py -a ~/test/uploads/ --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 -a ~/maixj.net/pics/ --size --jpg --png --gif
[smally]: total size: 241903070, 236233.47K, 230.697M, 0.2253G

版本

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:

$ python3 smally.py -v
[smally]: compress JPGs losslessly in batch mode and more... V0.09 by
www.pynote.net

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

-- EOF --

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

留言区

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

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

  • 麦新杰

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

    • 麦新杰

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

  • 麦新杰

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


前一篇:
后一篇:

More

麦新杰的Python笔记

Ctrl+D 收藏本页


©Copyright 麦新杰 Since 2019 Python笔记

go to top