WebPのサンプルの用意

 自作のExifライブラリをWebPに対応させた。テストのためにWebPファイルが必要になったが、メジャーな形式でもないのでWeb上にそうそう転がっていなかった。なので取得方法をちょっと調べた。ここでは二つ。コマンドラインツールとPythonライブラリを使う方法。
 ちなみにぼくの仕事の範囲ではWebPなんぞまだ見ぬが、お世話になっている人に聞いてみたら、ごく最近に表示スピードを求めているサイトで使われていたとのことだった。

 まず一つ。cwebpというGoogleのツールを使う。ビルド済みのバイナリがあるのでそれを落として使うのが手っ取り早い。Windowsのバイナリでやってみたところ、引数で与えたオプションが出力に反映されていなかった。Sub System for LinuxのUbuntuでやったらOKだった。
https://developers.google.com/speed/webp/docs/cwebp

cwebp -metadata all input.jpg -o output.webp


 PythonユーザならPillowが対応してくれているのでこっちを使うのも手。ただしPillow5.0.0が、pypy3環境では一部ファイルを読み込めなかった。Python2.7, 3.4-3.6では問題なく読み込めるファイルだ。pypy3で使うにはバグがあるようだ。
http://pillow.readthedocs.io/en/latest/handbook/image-file-formats.html#webp

from PIL import Image

image = Image.new("RGBA", (3, 3))
image.save("output.webp")
comment: 0

WebPの構造

 Googleが近年作った画像形式のWebPをいじる必要があったので、いじりながら理解したその仕様をメモ。
https://developers.google.com/speed/webp/docs/riff_container#top_of_page



ファイルのヘッダ 12bytes
====================

'R' 'I' 'F' 'F' [file size(32bit, Little Endian)] 'W' 'E' 'B' 'P'
 file sizeは自身を含まず、9バイト目以降の長さ


Chunk - ファイルの構造
===================

ファイルヘッダに続くChunkそれぞれによってWebPは構成される。Chunkは画像データのストリームやExifなどのメタデータなどが入る。Chunkの構造は下記。

[FourCC(4bytes)] [chunk size(32bit, Little Endian)] [chunk data]

FourCC
 Chunkがなんのデータかを示す4文字のコード
 https://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/RIFF.html

chunk size
 この直後に続くchunkのサイズ。FourCC、自身、このあとに続くchunkに追加されることがあるpaddingは長さに含まない

chunk data
 データ本体。長さが奇数の場合、0でpaddingされる。前述のとおりこのpaddingの0は、chunk dataの長さに含まない。



Extended File Format
=================

 Exifを入れたりするような場合は、これをChunkの一つとして入れ、内部でデータの存在フラグを立てる。
'V' 'P' '8' 'X' [VP8X size(32bit, Little Endian)] [flags(1byte)]
'\x00' '\x00' '\x00' [Canvas Width - 1(24bit, Little Endian)]
[Canvas Height - 1(24bit, Little Endian)]

 VP8X sizeは長さが10バイトで固定なので、値として’\x0A’ '\x00' '\x00' '\x00'となるのが必然。
 flagsはbitでオプションデータの存在をフラグとして保持している。先頭2bitを0埋めし、その後ICCP、透過情報、Exif、XMP、Animation、0埋めと続く。



chunkを結合する
=============
 chunkがそろったらそれらを結合して、RIFFヘッダをつけてWebPは完成となる。結合に際しての留意事項。

・前述の通り、すべてのチャンクを結合するとき、長さを見てdata部分をpaddingしなきゃいけない場合がある
・VP8Xヘッダが入っているファイルで、チャンクにVP8Lが入っている場合。Alphaチャンクの有無とVP8Lチャンクのデータ部分からビットで設定されたAlphaフラグを読み取り、AlphaチャンネルがあるかをチェックしてVP8Xのフラグ群に設定しなければならない。そうしないとファイルが不正になり読み取れなくなる。ドキュメントにVP8X内のAlphaフラグを、VP8Lのチャンクを読んでまで設定しろと書いてあるのを見つけられなくて手間取った。chunkにAlphaチャンクがあるか、VP8LのAlphaフラグを読み取り、どっちかがtrueならVP8X内のAlphaフラグを立てろ。
 VP8LのAlphaフラグはVP8LのドキュメントでThe alpha_is_used bitという名前で説明されている。データ部分の開始1バイトがシグネチャ、続いて14bitで幅、14bitで高さに続いて、1bitでThe alpha_is_used bitになっている。つまり37bit目を透過情報があるかのフラグとして読むということ。

・VP8Xヘッダを作るには画像サイズが必要。場合によってはそれを得るためにまたビット演算が必要

 ところどころ出てくるビット演算。そこらがちょっと厄介どころだった。
comment: 0