2016-07-13 23 views

Antwort

0

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:

1

Leanify (ich schrieb) unterstützt die Optimierung von Daten-URI-Bildern in CSS-Dateien. Es verwendet intern ZoppliPNG für PNG-Dateien.

Es hat ein paar Vorteile gegenüber Ihrem Python-Skript:

  1. Es auch anderes Bildformat unterstützen wie JPEG, ICO und SVG.

  2. Es benötigt keine temporären Dateien, alles wird im Speicher ausgeführt.

  3. Die Daten-URI-Suche hat eine bessere Kompatibilität. Für CSS-Dateien gibt es möglicherweise ' oder " zwischen url( und data:image, es unterstützt auch die Suche in HTML- und JS-Dateien, die möglicherweise url( überhaupt nicht haben.

https://github.com/JayXon/Leanify