2016-07-13 4 views
1

一部のPNGであるインラインイメージ(base64エンコードデータURI [AKAデータURL])を持つCSSファイルとLESSファイルがあります。私はこれらのPNGをZopfliPNGsを使って自動的にエンコードしたいと思っています。ZopfliPNGを使用したCSSファイル(データURI)内のPNGの自動最適化

悲しいことに、ZopfliPNGはファイルのみを扱うことができます。 stdin/stdout( "Support piping input"のようなバグトラッカーエントリはまだ開いています)では、やや複雑になります。

答えて

0

Pythonベースのソリューション:入力ファイルと出力ファイルは異なるべきであるという前提の下で

#!/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) 

作品(私のテストからZopfliPNGはまた、あなたがこのことから期待されるように、入力と出力が同じであった、それをうまくいきますしかし、パラメータは明らかに異なる出力ファイルを使用するように見えました)。それは作成する一時ファイルを再利用するのに対し、マイクロ最適化は少しあります。

CSS/LESS/...ファイルを含むフォルダで使用する場合は、 UNIXであなたができるシェル:

find /css-folder/ -type f -name '*.*ss' -exec \ 
    /path/to/this_script_here.py /path/to/zopfli/zopflipng {} + 
1

Leanify(私が書いた)CSSファイルのデータURI画像の最適化をサポートしています。 ZopfliPNGを内部的にPNGファイルに使用しています。

それはあなたのPythonスクリプトの上にいくつかの利点があります。

  1. それはまた、JPEG、ICOやSVGなどの他の画像フォーマットをサポートしています。

  2. 一時ファイルは必要ありません。すべてがメモリ内で行われます。

  3. データURIの検索には、互換性があります。 CSSファイルの場合、url(data:imageの間に'または"があり、url(を含まないHTMLファイルとJSファイルの検索もサポートされています。

https://github.com/JayXon/Leanify

関連する問題