在Python中使用pngquant压缩png图片的教程


Posted in Python onApril 09, 2015

说到png图片压缩,可能很多人知道TinyPNG这个网站。但PS插件要钱(虽然有破解的),Developer API要连到他服务器去,不提网络传输速度,Key也是有每月限制的。
    
    但是貌似tinyPNG是使用了来自于 pngquant 的技术,至少在 http://pngquant.org/ 中是如此声称的:TinyPNG and Kraken.io — on-line interfaces for pngquant。如果真是这样,我很想对TinyPNG说呵呵。后者是开源的,连首页中提供的GUI工具也都是开源的。并且TinyPNG在首页的原理说明里面,一次都没提到pngquant

    我取了tinyPNG的首页上的示例图用pngquant命令行跑了一下,压缩率和显示效果差不多。

    pngquant首页上提供的工具中,Pngyu(http://nukesaq88.github.io/Pngyu/)是跨平台并且开源的,个人觉得已经相当好用了,直接把文件夹往里面拽就能递归处理,支持各种形式的生成方式(改名、覆盖、存储到其他目录等),压缩结束给出压缩比,并且还支持预览。

    但我还是会希望能够通过脚本来处理,一方面可定制性更强,一方面更方便整合到整个自动化的流程链中。于是我又拿出了python试图写点什么,谁知道……

    pngquant的命令行方式略坑……help中的参数说明和实际效果不一致,已经发现的问题有

    1. --force 参数无效,只要输出文件存在,就会报错,无视这个本用来指定覆写的参数
    2. --skip-if-larger 参数不正常,有时候生成文件明明比较小,也会被skip掉……

    不过好在python大法好,这些问题虽然命令行本身不能处理,但python可以在上层处理掉,下面就是目前实际使用的递归处理某文件夹png的脚本:

'''
pngquant.py
use pngquant to reduces png file size
Ruoqian, Chen<piao.polar@gmail.com> 

----------
2015/4/3
1. del option --quality=50-90, special pic need skip can config in lod ini

  lod ini format:

[PixelFormat]
map_01.png=0

  0 means skip in file

----------
2015/4/2
1. desDir can be the same to srcDir, or another dir
2. lod ini config can be not exist

----------
2015/3/31
create
'''

import os
import os.path
import sys
import ConfigParser
import string

PngquantExe="pngquant"

thisFilePath = sys.path[0];

print "this py file in dir : " + thisFilePath

projectPath = thisFilePath + "/../CMWar_2dx/CMWar_2dx/";
srcResDir = "Resources/";
dstResDir = "Resources/";

lodIniPath = projectPath + srcResDir + "ini/pic.ini"
keepOrgPaths = [];
if os.path.exists(lodIniPath):
  config = ConfigParser.SafeConfigParser()
  config.read(lodIniPath)
  section = "PixelFormat";
  options = config.options(section)
  for option in options:
    value = string.atoi(config.get(section, option))
    if not value:
      keepOrgPaths.append(option);

print keepOrgPaths

srcResPath = projectPath + srcResDir;

pngCount = 0;
transCount = 0;

#pngquant --force --skip-if-larger --ext .png --quality 50-90 --speed 1

for parent,dirnames,filenames in os.walk(srcResPath):
  print "----- process Dir " + parent
  dstDir = parent.replace(srcResDir, dstResDir)
  if not os.path.exists(dstDir):
    os.makedirs(dstDir)
  for filename in filenames:
    if os.path.splitext(filename)[1] == '.png':
      pngCount += 1;
      srcFilePath = os.path.join(parent, filename);
      dstFilePath = os.path.join(dstDir, filename);
      tmpFilePath = dstFilePath + ".tmp";

      if filename in keepOrgPaths:
        print "----- keep ----- " + filename;
      else:
#        print "----- process ----- " + filename;
#        cmd = "\"" + PngquantExe + "\"" + " --force --speed=1 --quality=50-90 -v " + srcFilePath + " -o " + tmpFilePath;
        cmd = "\"" + PngquantExe + "\"" + " --force --speed=1 " + srcFilePath + " -o " + tmpFilePath;
#        print cmd;
        os.system(cmd)
        if os.path.exists(tmpFilePath):
          sizeNew = os.path.getsize(tmpFilePath);
          sizeOld = os.path.getsize(srcFilePath);
          if sizeNew < sizeOld:
            open(dstFilePath, "wb").write(open(tmpFilePath, "rb").read())
            transCount += 1;
          os.remove(tmpFilePath)
      if not os.path.exists(dstFilePath):
        open(dstFilePath, "wb").write(open(srcFilePath, "rb").read())

print "Done. Trans Pngs: %d/%d" %(transCount, pngCount)

Python 相关文章推荐
python使用SMTP发送qq或sina邮件
Oct 21 Python
对python中矩阵相加函数sum()的使用详解
Jan 28 Python
12个Python程序员面试必备问题与答案(小结)
Jun 24 Python
Flask使用Pyecharts在单个页面展示多个图表的方法
Aug 05 Python
Django后端发送小程序微信模板消息示例(服务通知)
Dec 17 Python
带你彻底搞懂python操作mysql数据库(cursor游标讲解)
Jan 06 Python
解决django FileFIELD的编码问题
Mar 30 Python
完美解决pycharm 不显示代码提示问题
Jun 02 Python
PyCharm中配置PySide2的图文教程
Jun 18 Python
Python pysnmp使用方法及代码实例
Aug 24 Python
Python+OpenCV图像处理—— 色彩空间转换
Oct 22 Python
Pytorch可视化的几种实现方法
Jun 10 Python
python optparse模块使用实例
Apr 09 #Python
Python中处理时间的几种方法小结
Apr 09 #Python
Python CSV模块使用实例
Apr 09 #Python
Python常用随机数与随机字符串方法实例
Apr 09 #Python
在Python中使用CasperJS获取JS渲染生成的HTML内容的教程
Apr 09 #Python
举例讲解Python程序与系统shell交互的方式
Apr 09 #Python
使用Python中的cookielib模拟登录网站
Apr 09 #Python
You might like
基于mysql的论坛(5)
2006/10/09 PHP
COM in PHP (winows only)
2006/10/09 PHP
使用php+Ajax实现唯一校验实现代码[简单应用]
2011/11/29 PHP
PHP curl 并发最佳实践代码分享
2012/09/05 PHP
使用新浪微博API的OAuth认证发布微博实例
2015/03/27 PHP
php远程请求CURL实例教程(爬虫、保存登录状态)
2020/12/10 PHP
js 遍历json返回的map内容示例代码
2013/10/29 Javascript
js动态修改input输入框的type属性(实现方法解析)
2013/11/13 Javascript
jquery制作漂亮的弹出层提示消息特效
2014/12/23 Javascript
Javascript基础教程之argument 详解
2015/01/18 Javascript
通过Tabs方法基于easyUI+bootstrap制作工作站
2016/03/28 Javascript
用JS动态设置CSS样式常见方法小结(推荐)
2016/11/10 Javascript
JS基于递归算法实现1,2,3,4,5,6,7,8,9倒序放入数组中的方法
2017/01/03 Javascript
JavaScript实现简易的天数计算器实例【附demo源码下载】
2017/01/18 Javascript
JS非空验证及邮箱验证的实例
2017/08/11 Javascript
基于Vue 2.0的模块化前端 UI 组件库小结
2017/12/21 Javascript
Layui多选只有最后一个值的解决方法
2019/09/02 Javascript
JavaScript如何实现监听键盘输入和鼠标监点击
2020/07/20 Javascript
javascript前端和后台进行数据交互方法示例
2020/08/07 Javascript
[02:08]2018年度CS GO枪械皮肤设计大赛优秀作者-完美盛典
2018/12/16 DOTA
python登陆asp网站页面的实现代码
2015/01/14 Python
PyQt5利用QPainter绘制各种图形的实例
2017/10/19 Python
python实现与redis交互操作详解
2020/04/21 Python
浅谈Django前端后端值传递问题
2020/07/15 Python
纯css3实现的鼠标悬停动画按钮
2014/12/23 HTML / CSS
小天鹅官方商城:LittleSwan
2017/06/16 全球购物
Nili Lotan官网:Nili Lotan同名品牌
2018/01/07 全球购物
法国足球商店:Footcenter
2019/07/06 全球购物
负责人任命书范本
2014/06/04 职场文书
2014最新开业庆典策划方案(5篇)
2014/09/15 职场文书
公司内部升职自荐信
2015/03/27 职场文书
婚礼父母致辞
2015/07/28 职场文书
机关单位2016年法制宣传日活动总结
2016/04/01 职场文书
mysql配置SSL证书登录的实现
2021/09/04 MySQL
oracle索引总结
2021/09/25 Oracle
Django基础CBV装饰器和中间件
2022/03/22 Python