Quick and dirty wrapper for the Google image compression utilities zopflipng (PNG) and guetzli (JPG).
#!/usr/bin/env python
"""goptim: PNG/JPG image optimizer based on Google Open-Source projects
Requires:
zopflipng (https://github.com/google/zopfli, `make zoplipng`)
guetzli (https://github.com/google/guetzli/, `make`)
"""
import sys
import getopt
import os.path
import subprocess
import shutil
import uuid
import time
from datetime import datetime
files = []
processes = []
def main():
'''Runs the main command logic'''
# Parse options and arguments
try:
opts, args = getopt.getopt(sys.argv[1:], 'h', ['help'])
except getopt.GetoptError as err:
# Print help information and exit
print str(err)
usage()
sys.exit(2)
for opt in opts:
if opt in ('-h', '--help'):
usage()
sys.exit()
else:
assert False, "unhandled option"
for item in args:
if os.path.isdir(item):
for filename in os.listdir(item):
check_file(item + '/' + filename)
else:
check_file(item)
if files:
count = 1
doneCount = 1
total = len(files)
out = open('/tmp/optim.log', 'a')
out.write(datetime.now().strftime("%A, %d. %B %Y %I:%M%p\n"))
out.flush()
print 'Processing ' + str(total) + ' files...'
for item in files:
tempfilename = '.' + str(uuid.uuid4())
if item['type'] is 'jpg':
print 'Threading Optimization ' + str(count) + '/' + str(total) + ' (JPG)'
processes.append({'process': subprocess.Popen([
'guetzli',
'--verbose',
item['file'],
tempfilename
],
stdout=out,
stderr=out
), 'tempfilename': tempfilename, 'filename': item['file']})
elif item['type'] is 'png':
print 'Threading Optimization ' + str(count) + '/' + str(total) + ' (PNG)'
processes.append({'process': subprocess.Popen([
'zopflipng',
'-m',
item['file'],
tempfilename
],
stdout=out,
stderr=out
), 'tempfilename': tempfilename, 'filename': item['file']})
count += 1
while processes:
for proc in processes:
retcode = proc['process'].poll()
if retcode is not None:
shutil.copy(proc['tempfilename'], proc['filename'])
os.remove(proc['tempfilename'])
processes.remove(proc)
print 'Thread ' + str(doneCount) + '/' + str(total) + ' Ended'
if doneCount == total:
print 'Processing Complete!'
doneCount += 1
break
else:
time.sleep(.1)
continue
def check_file(item):
'''Checks if a file is a JPG or PNG, and sorts them'''
if os.path.isfile(item):
if item.endswith(('.jpg', '.jpeg', '.JPG', '.JPEG')):
files.append({'file': item, 'type': 'jpg'})
elif item.endswith(('.png', '.PNG')):
files.append({'file': item, 'type': 'png'})
def usage():
'''Prints usage statement'''
print 'goptim [-h] <PNG/JPG or Directory>[, <PNG/JPG or Directory>][, ...]'
if __name__ == "__main__":
main()