大量の画像ファイルをWebPに変換する

## 前提
大前提として大量のjpg/png/bmp/gifの入り混じった画像ファイルがあるのはそうなのだが、以下のソフトを利用する。
- Bash -- 確認してないけどBash固有の拡張を使ってないと思うからshで十分かも
- GNU Parallel(https://www.gnu.org/software/parallel/) -- 並列実行
- find/rm/mv等いわゆるcoreutils -- 多分GNU拡張使ってるからBSD系だと動かない
- libwebp(https://chromium.googlesource.com/webm/libwebp) -- examplesに入っているものを使う
- GraphicsMagick(http://www.GraphicsMagick.org) -- libwebpで直接扱えないものの一次変換
- zopfli(https://github.com/google/zopfli) -- pngの最適化

## 実装
シェルスクリプトで書く。

とりあえずお決まり
```bash
#!/bin/bash
set -e
```
libwebpに含まれるgif2webpを用いて、gifをWebPに変換する。
この時、元ファイルと変換後のファイルの小さいほうを残す。
```bash
function conv_gif(){
        for arg; do
                FN=`basename "${arg}"`
                FDIR=`dirname "${arg}"`
                OUT=${FN%.*}.webp
                pushd "${FDIR}" >/dev/null 2>&1
                if [ ! -f "${OUT}" ]; then
                        gif2webp -mixed -m 6 -v -o "${OUT}" "${FN}"
                fi
                if [ -f "${OUT}" -a -s "${OUT}" ]; then
                        P_SIZE=`stat -c %s -- "${FN}"`
                        A_SIZE=`stat -c %s -- "${OUT}"`
                        if [ ${P_SIZE} -gt ${A_SIZE} ]; then
                                rm -- "${FN}"
                        else
                                rm -- "${OUT}"
                        fi
                fi
                popd >/dev/null 2>&1
        done
}
export -f conv_gif
find -O3 -type f -iname \*.gif -print0 | parallel -0 --eta -r --nice 10 -q conv_gif
```
bmpやtiffをとりあえずpngにする。ここで使うのはgm(GraphicsMagick)
```bash
function conv_png(){
        for arg; do
                FN=`basename "${arg}"`
                FDIR=`dirname "${arg}"`
                OUT=${FN%.*}.png
                pushd "${FDIR}" >/dev/null 2>&1
                if [ -f "${OUT}" ]; then
                        rm -- "${FN}"
                else
                        gm convert "${FN}" "${OUT}"
                        if [ -f "${OUT}" -a -s "${OUT}" ]; then
                                rm -- "${FN}"
                        fi
                fi
                popd >/dev/null 2>&1
        done
}
export -f conv_png
find -O3 -type f \( -iname \*.bmp -or -iname \*.tif -or -iname \*.tiff \) -print0 | parallel -0 --eta --nice 10 -r -q conv_png
find -empty -delete
```
jpgやpngをWebPにする。
ここでもやはり、元ファイルと変換後のファイルの小さいほうを残す。
また、一部のjpgがcwebpだと読み取りに失敗するので、失敗した場合は一旦pngに変換してリトライする。
```bash
function conv_webp(){
        for arg; do
                FN=`basename "${arg}"`
                FDIR=`dirname "${arg}"`
                OUT=${FN%.*}.webp
                pushd "${FDIR}" >/dev/null 2>&1
                if [ ! -f "${OUT}" ]; then
                        cwebp -m 6 -af -sharp_yuv -quiet -alpha_filter best -o "${OUT}" -- "${FN}"
                fi
                if [ ! -f "${OUT}" ]; then
                        gm convert "${FN}" "${FN%.*}.new.png"
                        P_SIZE=`stat -c %s -- "${FN}"`
                        A_SIZE=`stat -c %s -- "${FN%.*}.new.png"`
                        if [ ${P_SIZE} -gt ${A_SIZE} ]; then
                                rm -- "${FN}"
                                mv "${FN%.*}.new.png" "${FN%.*}.png"
                        else
                                cwebp -m 6 -af -sharp_yuv -quiet -alpha_filter best -o "${OUT}" -- "${FN%.*}.new.png"
                                rm -- "${FN%.*}.new.png"
                        fi
                fi
                if [ -f "${OUT}" -a -s "${OUT}" ]; then
                        P_SIZE=`stat -c %s -- "${FN}"`
                        A_SIZE=`stat -c %s -- "${OUT}"`
                        if [ ${P_SIZE} -gt ${A_SIZE} ]; then
                                rm -- "${FN}"
                        else
                                rm -- "${OUT}"
                        fi
                fi
                popd >/dev/null 2>&1
        done
}
export -f conv_webp
find -O3 -type f \( -iname \*.jpg -or -iname \*.jpeg -or -iname \*.png \) -print0 | parallel -0 --eta --nice 10 -r -q conv_webp
find -empty -delete
```
pngを最適化する。
当然、元ファイルと変換後のファイルの小さいほうを残す。
```bash
function opt_png(){
        for arg; do
                FN=`basename "${arg}"`
                FDIR=`dirname "${arg}"`
                OUT=${FN%.*}.opt.png
                pushd "${FDIR}" >/dev/null 2>&1
                if [ ! -f "${OUT}" ]; then
                        zopflipng -m --filters=01234me --lossy_transparent --lossy_8bit "${FN}" "${OUT}"
                fi
                if [ -f "${OUT}" -a -s "${OUT}" ]; then
                        P_SIZE=`stat -c %s -- "${FN}"`
                        A_SIZE=`stat -c %s -- "${OUT}"`
                        if [ ${P_SIZE} -gt ${A_SIZE} ]; then
                                rm -- "${FN}"
                                mv "${OUT}" "${FN}"
                        else
                                rm -- "${OUT}"
                        fi
                fi
                popd >/dev/null 2>&1
        done
}
export -f opt_png
find -O3 -type f -iname \*.png -print0 | parallel --nice 10 -0 --eta -r -q opt_png
find -empty -delete
```