大量でもコマンド一発!JPEGをキレイなままサイズダウンするスクリプトを公開【mozjpeg】

ダウンロードした写真画像や撮影した画像、数が増えるとハードディスクがいくらあっても足りませんよね。写真画像の大半はJPEGファイルですので、JPEGのファイルサイズが小さくできればストレージ容量の大幅な節約になるでしょう。また、Webページに使う写真もサイズを小さくしたほうが、SEO的にいいですよね。

そこで使えるのがmozjpegです。品質をそれほど落とさず、ファイルサイズを大幅に小さくすることができます。

では、mozjpegで実際にサイズダウンした画像と、Linuxにmozjpegを導入してJPEGファイルを大きくサイズダウンする方法を紹介しましょう。mozjpegを使って大量の画像データを一度にサイズダウンできるBashスクリプトも公開します。

mozjpegによるサイズダウンの例

ぱくたそからダウンロードした以下の画像をmozjpegで小さくしてみます(元画像のダウンロードページ)。

mozjpegにかける前のファイルサイズは、約273キロバイトです。以下は縦横サイズを縮小して貼ってあります。元画像はこちらをご覧ください。

これを、mozjpegで非可逆圧縮(品質を下げて圧縮)すると、約109キロバイトになりました。約60%もファイルサイズを削減できています。以下はページにあわせて縦横サイズを縮小したものですので、圧縮後の品質はこちらから確認してください。

よっぽど拡大しない限り差は分からないレベルですよね。この程度の変化でファイルサイズが半分以下になるなら、ほとんどの画像をmozjpegで小さくしても構わないって人、多いんじゃないでしょうか。機種にもよりますが、スマホやデジカメで撮影したJPEGなら、このページで紹介する方法で圧縮するだけで70%〜80%程度サイズダウンが期待できます。では、以下にLinuxへのmozjpegのインストール方法を紹介します。

mozjpegのインストール

まずは、mozjpegのビルドに必要なパッケージをインストールします。

Ubuntu/Debian系の場合

sudo apt -y install autoconf automake libtool nasm make pkg-config

Red Hat系の場合

sudo yum -y install automake libtool nasm pkgconfig

続いて以下の通り実行し、mozjpegの最新版ソースコードをダウンロード、展開、ビルド、インストールを行います。

mkdir /tmp/mozjpeg-install
cd /tmp/mozjpeg-install
curl -LO `curl -s 'https://api.github.com/repos/mozilla/mozjpeg/releases/latest' | grep browser_download_url | cut -d '"' -f 4`
tar xzvf mozjpeg-*-release-source.tar.gz
cd mozjpeg/
autoreconf -fiv
./configure
make
sudo make install
cd
sudo rm -rf /tmp/mozjpeg-install

これで、mozjpegが/opt/mozjpegにインストールされます。

mozjpegの使い方

mozjpegのコマンドは、「/opt/mozjpeg/bin」以下にインストールされます。ややこしいのですが、mozjpegはlibjpeg-turboを元に開発されており、「cjpeg」「jpegtran」といったコマンドのファイル名がlibjpeg-turboとかぶっています。そこで、mozjpegを使っているのかlibjpeg-turboを使っているのか分からなくなってしまうのを防ぐため、以下のコマンドを実行してコマンドの頭に「moz」をつけたシンボリックリンクを/usr/local/binに作っておくと便利です。こうしておけば、たとえば「/opt/mozjpeg/bin/cjpeg」が「mozcjpeg」で、「/opt/mozjpeg/bin/jpegtran」は「mozjpegtran」で実行できるようになります。

for f in /opt/mozjpeg/bin/*
do
  sudo ln -s $f /usr/local/bin/moz`basename $f`
done

以下は、この「moz」つきのコマンド名で解説を進めます。画像ファイルサイズの削減に使うのは、「mozcjpeg」と「mozjpegtran」です。

「mozcjpeg」は、画像ファイルをJPEGファイルに圧縮変換するコマンドです。JPEG以外のイメージをJPEGファイルに変換することもできますし、JPEGファイルを再変換することもできます。mozjpegで圧縮されていないJPEGファイル、例えばスマホやデジカメで写した写真の多くは、ファイルサイズを大きく減らすことができるでしょう。以下のように実行します。

mozcjpeg -quality 数値 入力画像ファイル > 出力画像ファイル

「-quality」には、画像のクオリティを0~100の数値で指定します。0が最も低品質、100が最も高品質です。指定しなかった場合のデフォルト値は75です。まずは75で処理して、必要に応じて調整することが推奨されています。

input.jpgを品質75で圧縮し、output.jpgに出力する場合は以下のように実行します。

mozcjpeg -quality 75 input.jpg > output.jpg

「mozjpegtran」には、クオリティを落とさずにデータ構造を最適化する機能や、撮影日時や撮影機器、撮影場所などのメタデータ(EXIF)を削除する機能などがあります。クオリティを保ったまま最適化し、メタデータも削除するには以下のように実行します。

mozjpegtran -copy none input.jpg > output.jpg

「-copy none」がメタデータをコピーしないための指定です。ほとんどの場合、メタデータを削除しても画像の見た目には影響ありません。しかし、スマホを縦持ちして撮った縦長の写真などは、横倒しになってしまうといった問題が発生することもあるので注意が必要です(後で紹介するスクリプトで解決します)。

Webなどでの公開用でなければ、撮影日時や撮影場所などのメタデータを残したい人も多いでしょう。そうした情報を残すには、以下のように「-copy all」を指定して実行します。

mozjpegtran -copy all input.jpg > output.jpg

クオリティを目視では気づかない程度に落とした上で、さらにメタデータも削除して画像ファイルサイズを可能な限り小さくするには、「mozcjpeg」と「mozjpegtran -copy none」の両方を実行してください。以下は、input.jpgを両方のコマンドで圧縮とメタデータの削除を行い、output.jpgに出力する例です。

mozcjpeg input.jpg | mozjpegtran -copy none > output.jpg

mozjpegをカンタンに使うためのスクリプト

ここまで見てきた通り、mozjpegでJPEGを圧縮するには、以下の点を考えて実行する必要があります。

  • 出力された画像を見て-qualityの数値を調整する
  • 画像によってメタデータ(EXIF)を削除するか保持するか決める
  • メタデータを削除したことで画像の回転がおかしくなっていれば修正する

非可逆圧縮とメタデータの削除の両方を行う場合、mozcjpegの後にmozjpegtranを実行するのは面倒ですよね。また、画像の回転修正も自動でやって欲しいところです。そこで、ラッパースクリプト「mozjpeg-wrap」を作成しました。このスクリプトを使えば、メタデータを削除する場合のみmozjpegtranを自動実行してくれます。また、メタデータに基づいて画像の回転や反転を無劣化で実行します。画像の方向情報を取得するため、「exiftool」を利用するので、スクリプト実行前に以下のコマンドでインストールしておいてください。

Ubuntu/Debian系の場合

sudo apt install libimage-exiftool-perl

Red Hat系の場合(RHELやCentOSの場合EPELレポジトリから導入する)

sudo yum install perl-Image-ExifTool

スクリプトはGitHubのレポジトリにアップロードしてあります。以下のコマンドで、~/bin/ディレクトリにダウンロードし、実行権限を追加するとコマンドとして利用可能です。

test ! -e ~/bin && mkdir ~/bin && PATH="$HOME/bin:$PATH"
curl -L https://raw.githubusercontent.com/lintaro-jp/mozjpeg-wrap/master/mozjpeg-wrap --output ~/bin/mozjpeg-wrap
chmod +x ~/bin/mozjpeg-wrap

使い方は以下の通りです。

mozjpeg-wrap [-l] [-q VALUE] [-c OPTION] 画像ファイル
引数解説:
  -l          ロスレス圧縮のみ行う(JPEGの場合のみ有効、デフォルトは非可逆圧縮)
  -q 数値     mozcjpegの-qualityに渡す数値
  -c 文字列   jpegtranの-copyに渡す文字列(none、comments、allのいずれか)
              デフォルトはallで、cjpegで最適化した場合はjpegtranを実行しません。

たとえば、input.jpgを開き、mozcjpegでクオリティ70を指定してサイズダウンを行い、mozjpegtranで必要に応じた自動回転とメタデータの削除を行ってoutput.jpgに出力するには、以下のように実行します。

mozjpeg-wrap -q 70 -c none input.jpg > output.jpg

以下はinput.jpgを開き、品質を下げる圧縮は行わず、mozjpegtranで最適化、自動回転、メタデータ削除だけを行う例です。

mozjpeg-wrap -l -c none input.jpg > output.jpg

大量のJPEGファイルを一度にサイズダウンするスクリプト

ファイルが1つならば「mozjpeg-wrap」だけで十分ですが、大量のJPEGファイルをまとめてサイズダウンする場合、一つ一つコマンドを実行するなんてやってられないですよね。そこで、特定のディレクトリ以下にある画像を探しだし、サイズダウンして別ディレクトリに書き出すスクリプト「mozjpeg-batch」も作成しました。実行には「mozjpeg-wrap」も必要なので、こちらも使うなら両方インストールしてください。

test ! -e ~/bin && mkdir ~/bin && PATH="$HOME/bin:$PATH"
curl -L https://raw.githubusercontent.com/lintaro-jp/mozjpeg-wrap/master/mozjpeg-wrap --output ~/bin/mozjpeg-wrap
curl -L https://raw.githubusercontent.com/lintaro-jp/mozjpeg-wrap/master/mozjpeg-batch --output ~/bin/mozjpeg-batch
chmod +x ~/bin/mozjpeg-wrap
chmod +x ~/bin/mozjpeg-batch

「mozjpeg-batch」の使い方は以下の通りです。

mozjpeg-batch [-l] [-q VALUE] [-c OPTION] 元ディレクトリ 保存先ディレクトリ
引数解説:
  -l          ロスレス圧縮のみ行う(JPEGの場合のみ有効、デフォルトは非可逆圧縮)
  -q 数値     mozcjpegの-qualityに渡す数値
  -c 文字列   jpegtranの-copyに渡す文字列(none、comments、allのいずれか)
              デフォルトはallで、cjpegで最適化した場合はjpegtranを実行しません。
  -s          ファイルが存在する場合は処理をスキップ
  -o          ファイルが存在する場合はバックアップをとらずに上書き
              -s と -o の両方が指定された場合は -s が優先されます。

このスクリプトは、ディレクトリ構造も保存先ディレクトリにコピーします。たとえば、以下のようなディレクトリがあるとします。

~/
└ ピクチャ/
  └ 2017/
     ├ 07/
     │ └ DSC_0001.jpg
     ├ 08/
     │ └ DSC_0002.jpg
     ├ 09/
     │ └ DSC_0003.jpg
     ├ memo.txt
     └ akeome.png

ここで、以下のコマンドを実行します。非可逆圧縮し、メタデータを削除する例です。

mozjpeg-batch -c none ピクチャ ピクチャ圧縮済み

すると画像が順次処理され、以下のように「ピクチャ圧縮済み」というフォルダに保存されます。

~/
└ ピクチャ圧縮済み/
  └ 2017/
     ├ 07/
     │ └ DSC_0001.jpg
     ├ 08/
     │ └ DSC_0002.jpg
     ├ 09/
     │ └ DSC_0003.jpg
     └ akeome.jpg

画像以外のファイルはコピーされません。また、JPEG以外の画像ファイルはJPEGに圧縮変換して保存されます。元ディレクトリには何も変更を加えないので、元の画像ファイルが不要ならば手動で削除してください。

このスクリプトを使うことで、何万もの画像があるフォルダでもコマンド一つでサイズダウンが可能です。ただし、元ファイルを上書きしないため、圧縮後の画像分のストレージ容量は必要です。空き容量を確認してから実行するようにしてください。

まとめ

mozjpegについてカンタンに紹介するつもりが、調べなおしているうちにコマンドを何度も実行する面倒くささが気になって、ラッパースクリプトを作ってしまいました。活用してもらえたら嬉しいです。