ユニファ開発者ブログ

ユニファ株式会社プロダクトデベロップメント本部メンバーによるブログです。

Go言語 disintegration/imaging で JPEG 画像処理をしてみる

こんにちは、 rightgo09 です。

Go 言語の disintegration/imaging を使った JPEG の画像処理をしてみます。

Exif の Orientation

JPEG 画像の Exif 情報には、 Orientation (方向)という項目が存在することがあり、この Orientation を適用しないと期待通りの方向に見えません。

Orientation については、こちらの Qiita の記事がわかりやすかったです。ありがとうございます。 qiita.com

iPod touchで縦向きに撮った写真が、 Orientation: 6 (反時計回りに90度回転) となっていたので、この縦長の写真を使って確認してみます。

Orientation がビューワに認識されている場合

f:id:rightgo09:20181219212717p:plain
mac のプレビュー.app で見たとき

Orientation がビューワに認識されていない場合

f:id:rightgo09:20181219212652p:plain
IDE の RubyMine で見たとき

disintegration/imaging を使ってみる

github.com

画像の幅と高さ

Orientation が 6 (反時計回りに90度回転) の画像の幅と高さを確認してみます。

package main

import (
    "fmt"

    "github.com/disintegration/imaging"
)


func main () {
    path := "./photo.jpg"

    srcImage, err := imaging.Open(path)
    if err != nil {
        panic(err)
    }

    point := srcImage.Bounds().Size()
    fmt.Printf("width: %d, height: %d\n", point.X, point.Y)
}
$ go run main.go
width: 3264, height: 2448

幅の方が長い、横長の画像として認識されています。

しかし、 v1.5.0 からは、 Open() に AutoOrientation フラグを指定できるようになったので、これを利用してみます。

    srcImage, err := imaging.Open(path, imaging.AutoOrientation(true))
    if err != nil {
        panic(err)
    }

    point := srcImage.Bounds().Size()
    fmt.Printf("width: %d, height: %d\n", point.X, point.Y)
$ go run main.go
width: 2448, height: 3264

高さの方が長い、縦長の画像として認識されました。

回転処理とリサイズ処理

幅 800px のサムネイルを作成してみます。

    srcImage, err := imaging.Open(path)
    if err != nil {
        panic(err)
    }

    f, err := os.Create("./thumbnail.jpg")
    if err != nil {
        panic(err)
    }

    // 幅を800pxにする
    thumbnailImage := imaging.Resize(srcImage, 800, 0, imaging.Lanczos)

    if err := imaging.Save(thumbnailImage, f.Name()); err != nil {
        panic(err)
    }
    f.Close()

f:id:rightgo09:20181220092608p:plain
サムネイルを作成

Orientation を無視して、画像が作成されてしまいました。 この作成された画像は Orientation が削除されているため、mac のプレビュー.app でも期待した方向になっていません。

ということで、サムネイル作成などのリサイズ処理をする前には、やはり Orientation を気にする必要がありました。 Orientation が 6 のときは、270度反時計回りに回転させます。

    if orientation == 6 {
        srcImage = imaging.Rotate270(srcImage)
    }

しかしこちらの場合も、Open() に AutoOrientation フラグをつけておくと、この回転処理自体が不要になりました。

    srcImage, err := imaging.Open(path, imaging.AutoOrientation(true))
    if err != nil {
        panic(err)
    }

    f, err := os.Create("./thumbnail.jpg")
    if err != nil {
        panic(err)
    }

    // 幅を800pxにする
    thumbnailImage := imaging.Resize(srcImage, 800, 0, imaging.Lanczos)

    if err := imaging.Save(thumbnailImage, f.Name()); err != nil {
        panic(err)
    }
    f.Close()

f:id:rightgo09:20181220093503p:plain
AutoOrientation つきでリサイズ処理

以上です。