├── README.md ├── .gitignore └── tinypng.py /README.md: -------------------------------------------------------------------------------- 1 | # GGTinypng 2 | 批量压缩png和jpg图片python脚本 3 | 减少图片50%以上的大小,肉眼看不出差别。减量不减质。 4 | 图片数量少的话可以在tinypng.com上试一下。看下效果。 5 | 6 | 已经支持子文件夹里面的图片,会按原始的相对路径存放到输出文件夹内 7 | 8 | 7.30 新加功能:一条命令压缩整个项目内的图片。 9 | 10 | 显著降低app的大小 11 | 12 | ## 使用方法 13 | 可以使用alias来简化命令 14 | python3 tinypng.py -i -o 15 | 16 | -o 参数可以为空,因为要遍历picDocPath子文件夹 所以默认outputDocPath改为picDocPath父目录 17 | 内的outputTinypng文件夹,与picDocPath同级。 18 | 19 | 7.30 新参数:python3 tinypng.py -r <项目路径或者项目内某个图片文件夹的路径> 20 | 21 | -r 参数会压缩文件夹内的图片并替换原图片 22 | 23 | 去 https://tinypng.com/developers 免费申请自己的key 每key每月免费压缩500个图 24 | 25 | 默认并发数为10 可以自己调整 26 | 27 | ##to do 28 | 29 | 如果有时间的话可能会做成处理mac程序或者xcode插件。不过短时间内不会,因为我自己用的话 30 | 脚本就足够了。 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | 5 | # C extensions 6 | *.so 7 | 8 | # Distribution / packaging 9 | .Python 10 | env/ 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | *.egg-info/ 23 | .installed.cfg 24 | *.egg 25 | 26 | # PyInstaller 27 | # Usually these files are written by a python script from a template 28 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 29 | *.manifest 30 | *.spec 31 | 32 | # Installer logs 33 | pip-log.txt 34 | pip-delete-this-directory.txt 35 | 36 | # Unit test / coverage reports 37 | htmlcov/ 38 | .tox/ 39 | .coverage 40 | .coverage.* 41 | .cache 42 | nosetests.xml 43 | coverage.xml 44 | *,cover 45 | 46 | # Translations 47 | *.mo 48 | *.pot 49 | 50 | # Django stuff: 51 | *.log 52 | 53 | # Sphinx documentation 54 | docs/_build/ 55 | 56 | # PyBuilder 57 | target/ 58 | -------------------------------------------------------------------------------- /tinypng.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # coding=utf-8 3 | 4 | # from os.path import dirname 5 | import os,sys, getopt 6 | from urllib.request import Request, urlopen 7 | from base64 import b64encode 8 | from multiprocessing import Pool 9 | 10 | poolLimite = 10 11 | key = "PX-pm9lAY3siS8cHIWz44zWFZHj6TtYX" 12 | # input = "large-input.png" 13 | # output = "tiny-output.png" 14 | opts, args = getopt.getopt(sys.argv[1:], "hi:o:r:") 15 | input_doc_path="" 16 | output_doc_path = '' 17 | filePaths=[] 18 | 19 | for op, value in opts: 20 | if op == "-i": 21 | input_doc_path = value 22 | elif op == "-o": 23 | output_doc_path = value 24 | elif op == "-r": 25 | input_doc_path = value 26 | output_doc_path = value 27 | elif op == "-h": 28 | print(''' 29 | 使用方法 python3 tinypng.py -i picDocPath -o outputDocPath 30 | -o 参数可以为空,默认存在picDocPath/tinypng 内 31 | 去 https://tinypng.com/developers 申请自己的key 每key每月免费压缩500个图 32 | 默认并发数为10 可以自己调整''') 33 | 34 | 35 | def absFilePath(fileName): 36 | return os.path.join(input_doc_path,fileName) 37 | def getTinyPng(filePath): 38 | print('开始'+filePath) 39 | request = Request("https://api.tinify.com/shrink", open(filePath, "rb").read()) 40 | 41 | cafile = None 42 | # Uncomment below if you have trouble validating our SSL certificate. 43 | # Download cacert.pem from: http://curl.haxx.se/ca/cacert.pem 44 | # cafile = dirname(__file__) + "/cacert.pem" 45 | 46 | auth = b64encode(bytes("api:" + key, "ascii")).decode("ascii") 47 | request.add_header("Authorization", "Basic %s" % auth) 48 | 49 | response = urlopen(request, cafile = cafile) 50 | if response.status == 201: 51 | # Compression was successful, retrieve output from Location header. 52 | result = urlopen(response.getheader("Location"), cafile = cafile).read() 53 | 54 | output = os.path.join(output_doc_path, os.path.relpath(filePath,input_doc_path)) 55 | open(output, "wb").write(result) 56 | print('完成'+output) 57 | else: 58 | print('失败'+filePath) 59 | # Something went wrong! You can parse the JSON body for details. 60 | print("Compression failed") 61 | 62 | def main(): 63 | global output_doc_path 64 | if output_doc_path == '': 65 | output_doc_path = os.path.join(os.path.split(input_doc_path)[0], 'outputTinypng') 66 | if not os.path.exists(output_doc_path): 67 | os.mkdir(output_doc_path) 68 | 69 | for parent,dirnames,filenames in os.walk(input_doc_path): #三个参数:分别返回1.父目录 2.所有文件夹名字(不含路径) 3.所有文件名字 70 | for dirname in dirnames: #输出文件夹信息 71 | # print("parent is:" + parent) 72 | # print("dirname is" + dirname) 73 | outDir = os.path.join(output_doc_path,os.path.relpath(os.path.join(parent,dirname),input_doc_path)) 74 | if not os.path.exists(outDir): 75 | os.mkdir(outDir) 76 | 77 | for filename in filenames: #输出文件信息 78 | # print("parent is:" + parent) 79 | # print("filename is:" + filename) 80 | filePaths.append(os.path.join(parent,filename)) 81 | 82 | pngFilePaths = filter(lambda x:os.path.splitext(x)[1]=='.png' or os.path.splitext(x)[1]=='.jpg',filePaths) 83 | print('Parent process %s.' % os.getpid()) 84 | p = Pool(poolLimite) 85 | for fileName in pngFilePaths: 86 | p.apply_async(getTinyPng, args=(fileName,)) 87 | print('Waiting for all subprocesses done...') 88 | p.close() 89 | p.join() 90 | print('All subprocesses done.') 91 | 92 | if __name__=='__main__': 93 | if os.path.isdir(input_doc_path): 94 | main() 95 | --------------------------------------------------------------------------------