引言

最近在做 H5 小游戏的开发,与 App 不同,由于 H5 所有的资源都是通过 CDN 获取的,考虑到网络资源加载速度的问题,优化资源显得格外重要。因此,图片资源的压缩也是必不可少的。

起源

起初,我们在 windows 下是通过一个叫做 PNGoo 的 GUI 工具来实现图片资源批量压缩的。但考虑压缩资源还需要启动一个应用,将图片资源拖进去再开始压缩,显然不够智能,希望通过 python 脚本自动完成。

后来,找到了这个工具的 Github 源码 pngoo ,才发现这个工具是基于 pngquant 这个开源库实现的,类似的基于此压缩算法库工具还有 Pngyu (Github 源码:Pngyu)和网页版压缩工具的 TinyPng 。

重点是这个开源的压缩库压缩比达到 60%-80% ,也是相当可观了。

源码资源

  • Pngyu Win 和 Mac 下皆可使用的 GUI 工具

  • pngoo 使用 Visual Studio 2015 即可打开且编译运行

  • pngquant 基于 C 语言编写的开源 png 图片压缩库

python 实现

直接下载 win 和 mac 平台的命令行工具包:

  • Binary for Windows (v2.12.0)

  • Binary for macOS (v2.12.0)

具体实现步骤如下:

  • 遍历指定目录下所有的 .png 后缀的文件;

  • 根据是否覆盖源文件进行压缩处理。

核心的方法有:

  • getImages

    这个方法用来获取需要进行压缩的图片

    # 获取文件列表
    def getImages():print u"========= 开始遍历图片"global file_listfiles = os.listdir(PngSrcRoot)for file in files:# 过滤出 png 图片if os.path.isdir(file):print u"过滤掉文件目录:"+fileelse:endStr = os.path.splitext(file)[1]if endStr == file_end:if isBack(file):print u"过滤掉黑名单中的文件:"+fileelse:file_list.append(file)# print u"文件 " + file + u" 添加到压缩列表"

    假如需要获取子目录下的图片资源,可以改写成递归调用的方式,改成如下即可很简单:

    def getImages(path, recursion):global file_listfiles = os.listdir(path)for file in files:# 过滤出 png 图片if os.path.isdir(file):getImages(path+'/'+file, recursion)else:endStr = os.path.splitext(file)[1]if endStr == file_end:if isBack(file):print u"过滤掉黑名单中的文件:"+fileelse:file_list.append(path+'/'+file)

    使用递归遍历的方式需要保存完整的文件路径(绝对路径或相对路径),非递归可直接保存文件名即可。

  • compress

    这是压缩文件的方法,当然要根据是否覆盖源文件做区分处理:

    # 压缩一个图片
    def compress(fileName):srcPath = PngSrcRoot + '/' + fileNameoutPath = SaveRoot + '/' + fileNameif SaveToOriginalDir:   # 使用 .png 后缀,且通过 -f 覆盖源文件cmd = PngquantExe + " -f --ext "+ file_end + " " + srcPath + " --quality " + compress_qualityos.system(cmd)returnelse:                   # 默认压缩到当前目录下,并加上 '-fs8.png' 后缀cmd = PngquantExe + " --ext "+ file_temp_end + " " + srcPath + " --quality " + compress_qualityos.system(cmd)# 复制到文件夹fileOriginalName = os.path.splitext(fileName)[0]compressed_srcpath = PngSrcRoot + '/'+fileOriginalName + file_temp_endif os.path.exists(compressed_srcpath):if os.path.exists(outPath):os.remove(outPath)shutil.move(compressed_srcpath, outPath)          #移动文件

    覆盖源文件的直接使用命令参数 -f--force 即可,保存到另外目录下的使用 -fs8.png 做后缀,移动到目标地址时再改名即可。当然也可以直接使用 -o 参数,达到一样的效果,省去了移动文件的操作。

完整的脚本如下:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
​
import os
import os.path
import shutil
import sys
​
# 压缩结果是否覆盖源文件
SaveToOriginalDir=True
​
SelfPath = sys.path[0]
# 压缩工具
PngquantExe=SelfPath+".\pngquant\pngquant"  # 参考 https://pngquant.org/ 工具来实现的
​
​
# 工程根目录
PathWorkspaceRoot = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
print u"当前工作目录: "+PathWorkspaceRoot
# 压缩资源目录
PngSrcRoot=PathWorkspaceRoot+"../../resource/@ui"
# 压缩后存放的目录
SaveRoot=PathWorkspaceRoot+"../../resource/@ui_pressed"
# 压缩过的图片列表
CompressFilesRecord=PngSrcRoot+'/compress_record.txt'
​
# 黑名单(不需要压缩的图片)
Backlits=['NetworkTips_atlas0.png','Common_atlas0.png','BldgUpgrade_atlas0.png']
​
# 文件后缀名
file_end='.png'
file_temp_end='-fs8.png'
​
# 压缩品质范围
compress_quality='75-80'
​
# 文件列表
file_list=[]
​
# 清理旧文件
def initDir():global SaveRootif(SaveToOriginalDir):if os.path.exists(CompressFilesRecord):print u"图片已经压缩过了!"returnSaveRoot = PngSrcRootelse:if os.path.exists(SaveRoot):print u"压缩文件存放目录清空"shutil.rmtree(SaveRoot)print u"创建压缩文件存放目录:"+SaveRootos.makedirs(SaveRoot)
​
# 获取文件列表
def getImages():print u"========= 开始遍历图片"global file_listfiles = os.listdir(PngSrcRoot)for file in files:# 过滤出 png 图片if os.path.isdir(file):print u"过滤掉文件目录:"+fileelse:endStr = os.path.splitext(file)[1]if endStr == file_end:if isBack(file):print u"过滤掉黑名单中的文件:"+fileelse:file_list.append(file)# print u"文件 " + file + u" 添加到压缩列表"
​
# 开始图片压缩任务
def startCompress():print u"========= 开始压缩图片"record_file = open(CompressFilesRecord,'w')if not os.path.exists(CompressFilesRecord):print u"创建压缩文件日志文件"for file in file_list:print u"压缩图片:"+filecompress(file)record_file.write(file+'\n')record_file.close()
​
def main():initDir()getImages()startCompress()print u"========= 图片压缩完成"# 判断是否在黑名单中
def isBack(filePath):for i in Backlits:if(filePath.find(i) != -1):return Truereturn False
​
# 压缩一个图片
def compress(fileName):srcPath = PngSrcRoot + '/' + fileNameoutPath = SaveRoot + '/' + fileNameif SaveToOriginalDir:   # 使用 .png 后缀,且通过 -f 覆盖源文件cmd = PngquantExe + " -f --ext "+ file_end + " " + srcPath + " --quality " + compress_qualityos.system(cmd)returnelse:                   # 默认压缩到当前目录下,并加上 '-fs8.png' 后缀cmd = PngquantExe + " --ext "+ file_temp_end + " " + srcPath + " --quality " + compress_qualityos.system(cmd)# 复制到文件夹fileOriginalName = os.path.splitext(fileName)[0]compressed_srcpath = PngSrcRoot + '/'+fileOriginalName + file_temp_endif os.path.exists(compressed_srcpath):if os.path.exists(outPath):os.remove(outPath)shutil.move(compressed_srcpath, outPath)          #移动文件
​
if __name__ == '__main__':main()sys.exit(0)

执行方式可以在脚本目录下执行:

$ python 脚本名称.py

假如使用 Visual Studio Code 的话,可以直接添加一个任务:

  • task.json 中的 "tasks" 添加一个任务:

    {"label": "压缩 UI 图片", // 压缩 ui 图片"type": "shell","presentation": {"echo": true,"reveal": "always","focus": true,"panel": "shared"},"command": "python","args": ["${workspaceRoot}/subproj/png图片压缩工具/ImgCompress.py" // 上面压缩脚本的相对路径],"group": "build","problemMatcher": []
    }
  • 执行时在 VS Code 使用快捷键 Ctrl+Shift+P 换出任务列表,选择 压缩 UI 图片 即可开始执行上面的压缩脚本。

pngquant 相关参数:

  • --quality min-max

    min 和 max 是从 0-100 的数值,用于设置压缩后图片的品质,品质越高压缩率越低;如果转换后的图片比最低品质还低,就不保存,并返回错误码99

  • --ext new.png

    设置输出图片的后缀名,默认使用 -fs8.png 做后缀(防止与源文件重名),假如设置 -ext=.png 则需要带上 --force 参数,否则会提示输出文件与输入文件重名无法覆盖;

  • -o out.png--output out.png

    压缩后图片的输出路径设置参数,不设置则默认输出当源文件相同路径下;

  • --skip-if-larger

    假如压缩后的图片文件比源文件还大,则放弃压缩结果;

  • --speed N

    转换速度与品质的比例。1(最佳品质),10(速度最快),默认是3;

  • --nofs

    禁用 Floyd–Steinberg dithering (即基于错误扩散的抖动算法)效果。

    而另外一个参数 --floyd=0.5 则用于控制抖动的等级,取值范围 0-1 ,0表示无抖动(等价于--nofs),1表示满级,这里 = 符号是必须的;

  • --posterize bits

    按位数减少调色板的精度。当图像在低深度屏幕上显示时使用(例如,16位显示或压缩的纹理在ARBB44格式);

  • --strip

    不要复制可选的 PNG 块。在MAC(使用Cocoa reader)时,元数据总是被删除。

参考

  • pngquant 官方文档

  • pngquant/README

  • Python 编写自动化工具

  • Shader特效——"Floyd Steinberg 抖动” 的实现 【OpenCV】【GLSL】

  • pngquant——一个好用的png压缩工具

python Png图片压缩工具相关推荐

  1. 开发一款图片压缩工具:使用 pngquant 实现图片压缩

    活动地址:CSDN21天学习挑战赛 开发一款图片压缩工具(二):使用 pngquant 实现图片压缩 上一篇我尝试使用了 pillow 库对 png 图片进行了压缩,效果不好.这次我换用 pngqua ...

  2. python爬图片_网络爬虫经验:反爬和反反爬

    我想很多人入门python是图片爬虫,就是HTTP请求,保存一下图片,用python实现非常快.网上很多爬虫的教程就讲到这里,实际上很单一,看了跟没看没什么区别,都是找一下网页的规律,然后Beauti ...

  3. Python调整图片大小并保存调整后的图像

    Python调整图片大小并保存调整后的图像 目录 Python调整图片大小并保存调整后的图像 #原始图像

  4. Python裁剪图片(Crop an Image)

    Python裁剪图片(Crop an Image) 目录 Python裁剪图片(Crop an Image) #原始图像 #图像剪裁 #处理后的图像

  5. python 多种图片数据格式互转

    python 多种图片数据格式 numpy.bytes.base64 互转 import cv2 import numpy as np import base64 from PIL import Im ...

  6. python pillow 图片处理

    python pillow 图片处理 视频 https://www.bilibili.com/video/BV1jK4y187yB?p=42 内容 #!/usr/bin/env pyth

  7. python 改变图片尺寸

    python 改变图片尺寸 #!/usr/bin/env python # -*- encoding: utf-8 -*- """ #!/usr/bin/env pyth ...

  8. 测试Python下载图片的三种方法

    简 介: 通过Python软件包对网络URL图片链接进行下载,可以加快后期处理.本文测试了urllib, request两个软件包对图片进行下载效果.如果图片原网页有了防止下载机制,是无法下载图片. ...

  9. C#制作图片压缩工具

    最近做的项目当中,需要将视频采集卡采集过来的图片进行压缩处理,原有一张JPG默认320*240大小为300KB,经过压缩之后为6KB,压缩50倍! 先放上截图吧: 可以添加单个文件,支持多选,也可以添 ...

最新文章

  1. Linux安装python3.6
  2. ios开发学习笔记--Core Motion
  3. log_archive_dest_1设置报错
  4. python 面向对象_多态、内置方法、反射
  5. Linux的磁盘系统和文件系统显示的文件大小为什么不一样(du指令和ls指令的区别)...
  6. isjavaidentifierpart和isjavaidentifierstart有区别么?
  7. Eclipse主题设置
  8. MTK6762 安卓 4g 核心板不同配置区别对比
  9. mac如何显示隐藏文件
  10. VirtuoZo:航摄影像的处理及拼接
  11. BootStrap4中使用图标
  12. 查找网站真实IP的方法大全
  13. mapUnderscoreToCamelCase作用- 开启驼峰
  14. iPhont X适配
  15. ZGC收集器(学习笔记)
  16. 成功解决sklearn.exceptions.NotFittedError: This StandardScaler instance is not fitted yet. Call ‘fit‘ wi
  17. linux系统深入学习
  18. qzezoj 1590 买玩具
  19. 写给未来的自己-面试的那些准备
  20. Vive controller vibration

热门文章

  1. HDDREG结合MHDD快速修复硬盘坏道(转载)
  2. 6.1使用设备树给DM9000网卡_触摸屏指定中断
  3. 对于“2017面向对象程序设计(Java)第五周工作总结”存在问题的反馈及本周教学计划...
  4. HTML还可以放音乐,放视频(真的吗?)
  5. Android SDK 环境配置与离线安装问题(校园网)
  6. 求大神赐教Maven中子模块之间无法建立依赖关系问题
  7. 智云通CRM:客户说“我随便看看”,如何回应才能促进成交?
  8. 美刊评选出25年十大牛股 微软思科甲骨文入选
  9. 谈谈coding面试的种类与基本应对策---一亩三分地帖子
  10. Google PR 劫持方法