go-libwebpとgo-libjpegをつくった
libwebpとlibjpegのGo bindingであるgo-libwebpとgo-libjpegをつくった。
それぞれWebPとJPEGファイルのデコード/エンコードに対応している。どちらもimage.Image
を扱うことが出来てimage/jpeg
やimage/png
と同じ感覚で使えるインターフェースにしている。たとえばgo-libjpeg
のサンプルコードは次のような感じ。
package main import ( "bufio" "image/png" "log" "os" "github.com/pixiv/go-libjpeg/jpeg" ) func main() { // Decoding JPEG into image.Image io, _ := os.Open("in.jpg") img, err := jpeg.Decode(io, &jpeg.DecoderOptions{}) if err != nil { log.Printf("Decode returns error: %v\n", err) return } f, _ := os.Create("out.png") b := bufio.NewWriter(f) png.Encode(b, img) b.Flush() f.Close() }
画像をimage.Image
で扱えるのでimage/png
や他のライブラリとのやりとりも簡単。既にimage/jpeg
を使ってる場合も少しの書き換えで使える。便利。
性能面では、go-libjpeg
はimage/jpeg
に比べて1.9倍くらい速い。簡単なベンチマークでは次のような感じだった。
BenchmarkDecode 1000 26345730 ns/op # go-libjpegを使ってYCbCrにデコード BenchmarkDecodeIntoRGB 500 30886383 ns/op # go-libjpegを使ってRGBにデコード BenchmarkDecodeWithNativeJPEG 300 49815928 ns/op # image/jpegを使ってYCbCrにデコード
libjpeg-turboを使うともっと速くて、OS X上でhomebrewのlibjpeg-turbo 1.3.1を使うと次のようになった。image/jpeg
に比べて5倍くらい速い。
BenchmarkDecode 2000 9557646 ns/op BenchmarkDecodeIntoRGB 1000 12676414 ns/op BenchmarkDecodeWithNativeJPEG 300 45836153 ns/op
オプションによってはさらに速いはずだ。どちらのライブラリもいくつかのオプションは渡せるようになっていて、go-libjpeg
は縮小デコード (imagemagickのヒントオプションとか言われてるやつ)に、go-libwebp
は縮小とクロッピングに対応している。
ただし、あまりデバッグされていないし、最低限のテストしかないし、バージョンも切ってないけど、これからプロダクションで使う予定があるのでそれなりにバグはとれていくと思う。たぶん。プロダクションで動いた暁にはpixivのエンジニアブログに書こうと思います。JPEGのサブサンプリングやWebPのYCbCrまわりで結構はまったけど、それは別の機会にQiitaにでもまとめよう。