畫像を Internet に上げる前に壓縮する習慣を持ってゐる。macOS では ImageOptim を使ってゐるが、Windows では無い。
JPEG 畫像は mozjpeg で、PNG 畫像は zopfli で可逆壓縮できればよい。以下の通りにやってゐる。
mozjpeg は scoop で入れる。今なら winget でよい。これで WSL2 からも jpegtran.exe
が呼べる。
scoop install mozjpeg
zopfli は WSL2 で build してある。
git clone https://github.com/google/zopfli.git
cd zopfli
make
これ等を Python から呼ぶ。
#!/usr/bin/env python3 """ Optimize JPEG images by mozjpeg & PNG images by zopflipng. Usage : ag -0 -g '\.((jp(e?)g)|png)$' | xargs -0 -t -n2 -P$(nproc) /mnt/c/<PATH TO>/imageoptim.py """ import os import subprocess from shlex import quote import sys import uuid class Image: @classmethod def from_input_file_name(cls, input_file_name: str) -> "Image": if input_file_name.endswith(".jpg") or input_file_name.endswith(".jpeg"): return JpegImage(input_file_name) elif input_file_name.endswith(".png"): return PngImage(input_file_name) raise f"Can not detect fle type: {input_file_name}" input_file_name: str output_file_name: str def compress(self) -> None: raise NotImplementedError() class JpegImage(Image): def __init__(self, input_file_name: str): self.input_file_name = input_file_name self.output_file_name = f"{uuid.uuid4()}.jpg" def compress(self) -> None: try: command = f"jpegtran.exe -copy none -optimize -outfile {quote(self.output_file_name)} {quote(self.input_file_name)}" print(command) subprocess.check_call(command, shell=True) print(f"{self.input_file_name} {os.stat(self.input_file_name).st_size} -> {os.stat(self.output_file_name).st_size}") os.replace(self.output_file_name, self.input_file_name) except subprocess.CalledProcessError as err: print(err) if os.path.isfile(self.output_file_name): os.remove(self.output_file_name) class PngImage(Image): def __init__(self, input_file_name: str): self.input_file_name = input_file_name self.output_file_name = f"{uuid.uuid4()}.png" def compress(self) -> None: try: command = f"/mnt/c/<PATH TO>/zopflipng -m --lossy_transparent {quote(self.input_file_name)} {quote(self.output_file_name)}" print(command) subprocess.check_call(command, shell=True) print(f"{self.input_file_name} {os.stat(self.input_file_name).st_size} -> {os.stat(self.output_file_name).st_size}") os.replace(self.output_file_name, self.input_file_name) except subprocess.CalledProcessError as err: print(err) if os.path.isfile(self.output_file_name): os.remove(self.output_file_name) for input_file_name in sys.argv[1:]: Image.from_input_file_name(input_file_name).compress()
昔書いたので Python だ。今なら Clojure で書く。書き直すか…。
追記 2021-09-19 書き直した。 c4se.hatenablog.com
書く程の事ではなかったが書いた。