Squoosh CLIでJPEG/PNGをWebPに一括変換
Googleが提供する画像最適化ツールSquooshは、JPEG/PNG/GIFなどの従来形式の画像をWebPやAVIFなどの次世代画像形式に変換してくれるツールです。
本記事では、一括変換が可能なSquooshのCLI版を使ってJPEG/PNGをWebPに一括変換する方法についてまとめました。
エラーによりはまった点もあったので、エラー内容と解消した方法も紹介していきます。
参考
以下を参考にしました。(※サポート終了に伴い削除されています)
squoosh/cli at dev · GoogleChromeLabs/squoosh - GitHub
https://github.com/GoogleChromeLabs/squoosh/blob/dev/libsquoosh/src/codecs.ts
環境
- macOS Monterey 12.3
Squoosh CLIの準備
本記事では、npmでSquoosh CLIをインストールして使う方法を紹介します。
GoogleChromeLabsのGitHubにはnpxを用いてインストールせずに利用する方法も書かれていました。
インストールします。
$ npm i -g @squoosh/cli
JPEG/PNGをWebPに変換
うまくいった条件&コマンド
結論から先に。
以下の条件とコマンドで、カレントディレクトリ配下のJPEGファイルをWebPファイルに一括変換することができました。
- Node.js v17.6.0
- @squoosh/cli@0.7.2
$ squoosh-cli --webp '{}' *.jpg
PNGファイルも同様に変換できます。
$ squoosh-cli --webp '{}' *.png
画像の品質はqualityで指定します。デフォルトでは75%に設定されています。
(品質はPNGやJPGの圧縮率に近いものですが、完全に同じものではありません。値が大きいほど視覚的品質が高くなり、小さいほど品質が低くなります。)
$ squoosh-cli --webp '{quality: 100}' *.jpg # 品質100%
オプションの設定の種類とデフォルト値はcodecs.tsのdefaultEncoderOptions
プロパティで確認できます。
--webp
のデフォルト設定は以下のようになっていました。
defaultEncoderOptions: {
quality: 75,
target_size: 0,
target_PSNR: 0,
method: 4,
sns_strength: 50,
filter_strength: 60,
filter_sharpness: 0,
filter_type: 1,
partitions: 0,
segments: 4,
pass: 1,
show_compressed: 0,
preprocessing: 0,
autofilter: 0,
partition_limit: 0,
alpha_compression: 1,
alpha_filtering: 1,
alpha_quality: 100,
lossless: 0,
exact: 0,
image_hint: 0,
emulate_jpeg_size: 0,
thread_level: 0,
low_memory: 0,
near_lossless: 100,
use_delta_palette: 0,
use_sharp_yuv: 0,
}
TypeError: Failed to parse URL from /Users/*/.nodebrew/node/v18.4.0/lib/node_modules/@squoosh/cli/node_modules/@squoosh/lib/build/imagequant_node-a4aafbae.wasm
はまったエラー1: エラーが起こった条件
- Node.js v18.4.0
- @squoosh/cli@0.7.2
以下を実行
$ squoosh-cli --webp '{}' *.jpg
TypeError: Failed to parse URL from /Users/*/.nodebrew/node/v18.4.0/lib/node_modules/@squoosh/cli/node_modules/@squoosh/lib/build/imagequant_node-a4aafbae.wasm
at new Request (node:internal/deps/undici/undici:4832:19)
at Agent.fetch2 (node:internal/deps/undici/undici:5524:29)
... 4 lines matching cause stack trace ...
at /Users/*/.nodebrew/node/v18.4.0/lib/node_modules/@squoosh/cli/node_modules/@squoosh/lib/build/index.js:28:35216
at instantiateEmscriptenWasm (/Users/*/.nodebrew/node/v18.4.0/lib/node_modules/@squoosh/cli/node_modules/@squoosh/lib/build/index.js:1:466)
at Object.<anonymous> (/Users/*/.nodebrew/node/v18.4.0/lib/node_modules/@squoosh/cli/node_modules/@squoosh/lib/build/index.js:30:323)
at Module._compile (node:internal/modules/cjs/loader:1112:14) {
[cause]: TypeError [ERR_INVALID_URL]: Invalid URL
at new NodeError (node:internal/errors:388:5)
at URL.onParseError (node:internal/url:564:9)
at new URL (node:internal/url:644:5)
at new Request (node:internal/deps/undici/undici:4830:25)
at Agent.fetch2 (node:internal/deps/undici/undici:5524:29)
at Object.fetch (node:internal/deps/undici/undici:6351:20)
at fetch (node:internal/bootstrap/pre_execution:197:25)
at instantiateAsync (/Users/*/.nodebrew/node/v18.4.0/lib/node_modules/@squoosh/cli/node_modules/@squoosh/lib/build/index.js:28:11469)
at createWasm (/Users/*/.nodebrew/node/v18.4.0/lib/node_modules/@squoosh/cli/node_modules/@squoosh/lib/build/index.js:28:12079)
at /Users/*/.nodebrew/node/v18.4.0/lib/node_modules/@squoosh/cli/node_modules/@squoosh/lib/build/index.js:28:35216 {
input: '/Users/*/.nodebrew/node/v18.4.0/lib/node_modules/@squoosh/cli/node_modules/@squoosh/lib/build/imagequant_node-a4aafbae.wasm',
code: 'ERR_INVALID_URL'
}
}
※ユーザー名は*
で置き換えています
GitHubのissues[LibSquoosh] URL invalid #1033にて同様の事例を見つけ、以下の回答がありました。
The only thing that has changed for me was node 18 being upgraded to a newer version, so perhaps that's the root cause.
For anyone running into the same problem: Temporarily downgrading to node >=v16 when using @squoosh/lib@0.4.0 is a successful workaround.
Node.jsのバージョンとsquoosh-cliのバージョンの組み合わせによってこのエラーが出る場合があるようです。私はNode.jsのバージョンを17.6.0
にダウングレードすることによってこのエラーが出なくなりました。
SyntaxError: JSON5: invalid character 'c' at 1:1
はまったエラー2: エラーが起こった条件
- Node.js v17.6.0
- @squoosh/cli@0.7.2
以下を実行
$ squoosh-cli --webp *.jpg
/Users/*/.nodebrew/node/v17.6.0/lib/node_modules/@squoosh/cli/node_modules/json5/lib/parse.js:1083
const err = new SyntaxError(message)
^
SyntaxError: JSON5: invalid character 'c' at 1:1
at syntaxError (/Users/*/.nodebrew/node/v17.6.0/lib/node_modules/@squoosh/cli/node_modules/json5/lib/parse.js:1083:17)
at invalidChar (/Users/*/.nodebrew/node/v17.6.0/lib/node_modules/@squoosh/cli/node_modules/json5/lib/parse.js:1028:12)
at Object.value (/Users/*/.nodebrew/node/v17.6.0/lib/node_modules/@squoosh/cli/node_modules/json5/lib/parse.js:287:15)
at lex (/Users/*/.nodebrew/node/v17.6.0/lib/node_modules/@squoosh/cli/node_modules/json5/lib/parse.js:78:42)
at Object.parse (/Users/*/.nodebrew/node/v17.6.0/lib/node_modules/@squoosh/cli/node_modules/json5/lib/parse.js:25:17)
at Command.processFiles (file:///Users/*/.nodebrew/node/v17.6.0/lib/node_modules/@squoosh/cli/src/index.js:172:60) {
lineNumber: 1,
columnNumber: 1
}
※ユーザー名は*
で置き換えています
このエラーについてもGitHubのissuesに情報がありました。
--webp takes a JSON parameter to configure the encoder, that’s why it’s trying to decode the first file name using JSON5. If you use --webp '{}', it should work.
RuntimeError: abort(SyntaxError: JSON5: invalid character 'w' at 1:1) #956
$ squoosh-cli --webp '{}' *.jpg
とすることで解決しました。
(余談)JPEGをWebPに変換したらファイルサイズが大きくなった!?
圧縮率80%で書き出したJPEGを、Squooshでquality:100%でWebPに変換したところ、ファイルサイズ(重さ)が元画像より大きくなってしましました。
WebPは複数の圧縮アルゴリズムを組み合わせて、設定された品質(quality)になるように画像を変換します。JPEGからWebPに変換するアルゴリズムでは、qualityの値は元の画像に対して相対的に100%の品質というわけではなく、絶対的な評価値になります。(他のアルゴリズムでは相対的な値であることもあるそうです)
そのため、圧縮率80%のJPEGをquality:100%でWebPに変換した場合、元のJPGEGより多くの情報を保持するために必要なビット数が増加し、ファイルサイズが大きくなってしまうことがあります。
Discussion