画像形式WebPと他形式との変換に用いるコマンド

Last modified: 2020-10-21

WebP形式とlibwebpについて

形式の概要

WebPは比較的新しく作られた圧縮済み画像形式(仕様公表されたのが2010年)で

  • 不可逆圧縮モードでJPEGよりも
  • 可逆(ロスレス)圧縮モードでPNGよりも

それぞれ高い圧縮率が出るとされる(公式によると同一画像の同等品質の圧縮後サイズで “前者が25-34%,後者が26%” の差)。ただ、JPEG画像に対してはMozillaが公開しているmozjpegと呼ばれるソフトウェアのjpegtranコマンドを用いることで既存の画像に対して無劣化である程度ファイルサイズを削減することが可能となっており、圧縮率のメリットは小さくなっている。

WebPでは可逆/不可逆のいずれの圧縮モードでもアルファチャンネルに対応している。

可逆圧縮やアルファチャンネルの機能は2011年から2012年にかけて追加され、 “不可逆圧縮 + アルファチャンネル” が利用できる画像形式は他にはあまりない。

サポートするソフトウェア

Webブラウザ

  • Chrome/Chromium系Webブラウザ
  • Opera
  • Mozilla Firefox (バージョン65以上)
  • Microsoft Edge (October 2018 Update以上の適用されたWindows 10が必要)

WebPをサポートするFirefox 65が2019年1月に公開され、2018年-2019年にかけてWebブラウザのサポート状況は大きく改善した。

画像処理ソフトウェア

  • GIMP (バージョン2.10以上)

GIMPについては、以前に外部の開発者により作られたプラグインに基づいたコードが公式に入り、標準で読み書きできるようになった。

libwebp

プログラム内でWebP形式の画像を扱うには “libwebp” と呼ばれる公式提供のC言語ライブラリを用いると便利。 同ライブラリには、他形式の画像との間で変換が行えるツール(コマンド)群が付属しており、GNU/Linuxでもディストリのパッケージとして収録されている。Debian/Ubuntuでは

  • webp: 形式変換のコマンド群
  • libwebp[数字]: libwebpのライブラリ(libwebpを用いたプログラムから用いられる)
  • libwebp-dev: libwebpを用いたプログラムをビルドするために必要な開発用ファイル群

としてパッケージが用意されている。

可逆(ロスレス)圧縮はバージョン0.2.0以上でのみ対応しているが、2015年頃から後に公開されたバージョンのディストリであれば問題なく使える。

libwebp付属のツール

他形式からWebP形式への変換コマンド

他の画像形式からWebP形式へ変換するためのコマンドはcwebpとなる。対応する入力形式は

  • JPEG
  • PNG
  • TIFF

となっている。

出力ファイルは-oオプションで指定する。指定をしないと、内部で処理は行われるがその出力結果は破棄されるので注意。

不可逆圧縮

不可逆の圧縮を行う場合は-q [0から100の値]オプションを付ける。品質値は小数でも指定可。

$ cwebp -q [品質値(0-100)] /path/to/input.jpg -o /path/to/output.webp
可逆(ロスレス)圧縮

可逆(ロスレス/無劣化)の圧縮を行う場合は-losslessオプションを付ける。PNG画像から無劣化なままで変換する場合は下のようにする。

$ cwebp -lossless /path/to/input.png -o /path/to/output.webp

WebPから他形式への変換コマンド

WebP形式から他の画像形式へ変換するためのコマンドはdwebpとなる。

出力形式は既定のPNG形式の他、PAM,PPM,PGM,YUVに対応している(-pamなど、形式を指定するオプションを付ける)。

このコマンドも、出力ファイルは-oオプションで指定する。指定をしないと出力は行われない。

下はPNG形式に変換して出力する例。

$ dwebp /path/to/input.webp -o /path/to/output.png

PNG画像をロスレスWebP画像に一括変換する

下はPNG画像をWebP形式にまとめてロスレスで変換してPNG画像のディレクトリに書き出し、元画像の最終更新日時をWebPファイルに適用するPythonスクリプトの例。

[任意]ファイル名:png2losslesswebp.py ライセンス:zlib
#! /usr/bin/python

"""
png2losslesswebp.py - convert PNG to lossless WebP.

(C) 2019-2020 kakurasan
Licensed under zlib
"""

from __future__ import print_function

import multiprocessing as mp
import os
try:
    import queue
except ImportError:
    import Queue as queue
import subprocess
import sys


# pylint: disable=too-few-public-methods
class Config:
    """Configuration data."""

    cwebp = "/usr/bin/cwebp"  # path to cwebp
    options = ["-lossless", "-quiet"]


def run_cwebp(fname, root):
    """Run cwebp and copy last modified date/time from original PNG file."""
    f_lower = fname.lower()
    if f_lower.endswith(".png"):
        infile = os.path.join(root, fname)
        outfile = os.path.join(
            root, "{}.webp".format(fname[:fname.rfind(".")]))
        print("Converting '{}'".format(infile))
        try:
            subprocess.check_call(
                [Config.cwebp] + Config.options + [infile, "-o", outfile],
            )
        except subprocess.CalledProcessError:
            print("Failed to convert '{}'".format(infile))
            return
        st_before = os.stat(infile)
        os.utime(outfile, (st_before.st_atime, st_before.st_mtime))


def worker(que):
    """Get filename and root from the queue and call run_cwebp()."""
    while True:
        try:
            fname, root = que.get(True, 1)
            run_cwebp(fname, root)
            que.task_done()
        except queue.Empty:
            break


def main():
    """Put paths into a JoinableQueue and start processes."""
    if len(sys.argv) < 2:
        sys.exit("USAGE: {} [DIR...]".format(__file__))
    que = mp.JoinableQueue()
    for topdir in sys.argv[1:]:
        for root, _, files in os.walk(topdir):
            for fname in files:
                que.put((fname, root))
    for _ in range(mp.cpu_count()):
        proc = mp.Process(target=worker, args=(que,))
        proc.start()
    que.join()


if __name__ == "__main__":
    main()

下はその実行方法。動作にはlibwebp付属ツールが必要(cwebpコマンドを使用する)。引数に指定するディレクトリは複数指定できる。

(指定ディレクトリ内のPNG画像をWebP形式に一括変換)
$ /path/to/png2losslesswebp.py /path/to/png/dir

PNG形式から変換したWebPファイルはoptipngで最大限最適化をしたPNGファイルよりも更にファイルサイズが小さくなる場合が多いが、逆に大きくなるファイルもあるので注意が必要。