Python-basierte Lösung:
#!/usr/bin/env python
''' Tool to optimize PNG images embedded as data URLs in CSS files or similar
using ZopfliPNG.
'''
import base64
import re
import subprocess
import sys
import tempfile
__author__ = "phk @ stackoverflow (https://stackoverflow.com/users/2261442)"
__version__ = "1.0.1"
# parameters for ZopfliPNG controlling the optimization method
OPTIMIZATION_PARAMS = [
"-m",
"--lossy_transparent",
"--iterations=1000"
]
if len(sys.argv) < 2:
print("Usage: {} ZOPFLIPNG_EXECUTABLE TARGET_FILES...".format(sys.argv[0]))
sys.exit(1)
zopflipng = sys.argv[1]
targets = sys.argv[2:]
# regex to match all the data urls with PNGs inside CSS or therelike
# but only return the base64 encoded PNG data
inline_png_re = re.compile(
r"(?<=url\(data:image/png;base64,)[A-Za-z0-9+/]+=*(?=\))")
# create temporary input/output files for ZopfliPNG, it only deals with files
with tempfile.NamedTemporaryFile('w+b') as tmpf_in, \
tempfile.NamedTemporaryFile('r+b') as tmpf_out:
def replace_inline_png(match):
''' Replace all the PNGs inside data URLs with optimized versions. '''
orig_data = match.group(0)
try:
data = base64.b64decode(orig_data)
except TypeError:
print("Invalid base64 string. Skipping this data URL.")
return orig_data
# prepare input file for ZopfliPNG
tmpf_in.seek(0) # because the temporary input file gets re-used
tmpf_in.truncate()
tmpf_in.write(data)
tmpf_in.flush() # because the file is kept open
tmpf_out.seek(0)
tmpf_out.truncate()
return_code = subprocess.call([
zopflipng,
"-y", # silent overwriting of output file necessary
] + OPTIMIZATION_PARAMS + [
tmpf_in.name,
tmpf_out.name
])
if return_code:
print("ZopfliPNG reported an error. Skipping this PNG.")
return orig_data
# read zopflipng results from output file
data = tmpf_out.read()
return base64.b64encode(data)
def optimize_file(target):
''' Optimize the PNGs embedded as data URLs in target file. '''
try:
with open(target) as f_in:
contents = f_in.read()
except IOError:
print("Can't open {} for reading!".format(target))
return
# replace the inline PNGs with optimized versions
contents = inline_png_re.sub(replace_inline_png, contents)
try:
# write the changed file contents
with open(target, 'w') as f_out:
f_out.write(contents)
except IOError:
print("Can't open {} for writing!".format(target))
return
for target in targets:
optimize_file(target)
Works unter der Annahme, dass die Ein- und Ausgabedateien anders sein sollte (aus meinen Tests die gleiche ZopfliPNG wäre es auch waren Ein- und Ausgabe arbeiten, wie Sie von dieser erwarten Programm, aber nur um sicher zu sein, schienen die Parameter anscheinend auch dazu zu zwingen, eine andere Ausgabedatei zu verwenden). Hat ein wenig Mikro-Optimierung, während es die temporären Dateien wiederverwendet, die es erstellt.
Um es dann auf einen Ordner mit CSS/LESS/...-Dateien z. in einer UNIX-Shell könnten Sie tun: