初歩のシェルスクリプトで遊ぶ[JPEG XLでのjpegロスレス圧縮を試す]
今回はシェルスクリプトではなく、コマンドの試用です。
JPEG XL ではjpegファイルを中身そのままでサイズ圧縮できるらしい
が、手軽に試せるツールが見当たらん。
*.jxl — Krita Manual 5.2.0 ドキュメント
有名どころが JPEG XL に対応した、という話はときどき聞きますが、ものを見てみると通常のロッシー圧縮かロスレス圧縮かの対応です。
私が試したかったのはjpegをそのまま中身のデータを保ってファイルサイズを圧縮できて、しかも再び元のjpegファイルに戻せる、という圧縮です。これはwebpとavifではできない処理です。
JPEG XL - ArchWiki
GitHub - libjxl/libjxl: JPEG XL image format reference implementation
Debian -- Details of package libjxl-tools in bookworm
GitHub - uyjulian/ifjxl: JPEG XL plugin for Susie Image Viewer
てっきりソースからどうこうせにゃならんかと思ってましたが、私が使ってるDebianでも、バージョンは少々古いけれど普通に apt で入りました。
コマンドも、オプションを指定しなければならないだろうと決めつけてかかってましたが、オプションなしでjpegファイルを突っ込むと、元に戻せるjpegロスレス圧縮になるみたいです。
$ cjxl input.jpg output.jxl
説明書は詳しく、詳しく
For more settings run cjxl --help or for a full list of options run cjxl -v -v --help.
https://github.com/libjxl/libjxl
$ cjxl -v -v --help $ cjxl --verbose --verbose --help
説明だいたいこれだけで終わるんですが、--verbose を二回指定してヘルプを出すと、詳しい説明書が読めます。
使ってみた感じ(一般的な8bit420のみ、メタデータも調べていない前提で)
むしろjpegファイルを普通に画質劣化させて.jxlに変換するほうがややこしい
$ cjxl input.jpg output.jxl -j 0 -d 1 -e 7
「-j」「-d」の指定が両方とも必須です。「-e」はなくてもよい。
まとめて画像ファイルを変換するスクリプトを書くときは、入力がjpegでもpngでもロッシー圧縮させるようなオプション指定をするなり、検討は要ります。
参考スクリプト
私が使ってるスクリプトです。
画像ファイルをまとめて変換するスクリプトに組み込んで使ってるもので、このシェルスクリプトを xargs から実行してます。変換元の画像ファイルを削除するので注意してください。試用するときはrmコマンドの部分を削除してから実行するのがお勧めです。
複数の画像ファイルを同時に変換したいときは、xargsのオプションで -P を指定します。
異常時の終了コードを255にしているのは、xargsが255を受け取ると即座に終了してくれるからです。
拡張子は .jpg をそのまま残し、.jxl を追加しています。二重拡張子です。これは私が個人的にやっていることで、一般的なルールではありません。.tar.gz みたいなものではないのでご注意。
#!/bin/sh #set -x # ======================================================================================== # ■ jpegをjxlへ無劣化変換 # # ・入力ファイルはjpegのみ扱う # ・拡張子が.jpeg.jpg.jpeのとき処理し、でなければ何もせずに正常終了する # jpeg以外のファイルが混じっていても処理できるように # ・出力ファイル名は元ファイル名に [.jxl] を加える # # # # # ======================================================================================== if test -f "${1:?}" then inputImage="${1}" else exit 255 fi # jpeg jpg jpe のみ処理対象とする # これ以外のファイルには手を付けない case "${inputImage}" in ( *.[jJ][pP][eE][gG] | *.[jJ][pP][gG] | *.[jJ][pP][eE] ) true ;; ( * ) exit 0 ;; esac # 出力ファイル先を確保 outputTemp="`mktemp`" # jpeg-xlへ変換 if cjxl "${inputImage}" "${outputTemp}" \ --lossless_jpeg=1 --distance=0 -e 9 \ --jpeg_store_metadata=1 --verbose ; then true else exit 255 fi # 変換元jpegファイルを削除する if rm -v -- "${inputImage}" then true else exit 255 fi # jxlファイルを変換元jpegファイルが置かれていたディレクトリへ移動する if mv -v -n -- "${outputTemp}" "${inputImage}.jxl" then exit 0 else exit 255 fi
#!/bin/sh #set -x # ======================================================================================== # ■ jpegをjxlへ無劣化変換、したものをjpegへ戻す # # ・入力ファイルはjpegを無劣化変換してjxlにしたもののみ扱う # ・拡張子が.jxlのときjxlinfoで検査、対象ファイルは処理、対象外は何もせずに正常終了する # # ・ファイル名の二重拡張子も考慮して出力拡張子を名付ける # [.jpg.jxl]->[.jpg] # [.jxl] ->[.jpg] # # # # # ======================================================================================== if test -f "${1:?}" then inputImage="${1}" else exit 255 fi # jxl のみ処理対象とする # これ以外のファイルには手を付けない case "${inputImage}" in ( *.jxl ) true ;; ( * ) exit 0 ;; esac if jxlinfo "${inputImage}" | grep -e '^JPEG bitstream reconstruction data available$' then echo "${inputImage}" 1>&2 else exit 0 fi # 出力ファイル先を確保 djxlの出力先拡張子は.jpgでなければならない outputTemp="`mktemp --suffix='.jpg'`" # jpeg-xlへ変換 if djxl "${inputImage}" "${outputTemp}" ; then true else exit 255 fi # 変換元jxlファイルを削除する if rm -v -- "${inputImage}" then true else exit 255 fi # .jxl を削る inputImage="${inputImage%.jxl}" # .jpg があれば残し、なければ付加する case "${inputImage}" in ( *.[jJ][pP][eE][gG] | *.[jJ][pP][gG] | *.[jJ][pP][eE] ) true ;; ( * ) inputImage="${inputImage}.jpg" ;; esac # jpgファイルを変換元jxlファイルが置かれていたディレクトリへ移動する if mv -v -n -- "${outputTemp}" "${inputImage}" then exit 0 else exit 255 fi