画像をアルゴリズムを選んで簡単にすぐにリサイズするGo言語コードの紹介と解説

GUIプログラミングやゲームでなくとも、画像をリサイズしたい時がありますよね。当ブログでは、1つの元となる画像からレスポンシブ対応するためにリサイズして複数サイズの画像を生成しています。

Go言語では、画像を簡単にリサイズしてアルゴリズムも指定できる素晴らしいライブラリがあるので、今回はそれをご紹介していきます。

コンテンツの転載は固くお断りいたします。

コードの紹介

今回は横幅1280px、縦幅765pxの『test.jpg』という画像ファイルを用意し、それを読み込んで横幅を300pxに縮小し、『test1.jpg』という名前でファイルに保存しています。


package main

import (
	"image/jpeg"
	"log"
	"os"

	"github.com/nfnt/resize"
)

func main() {
	file, err := os.Open("test.jpg")
	if err != nil {
		log.Fatal(err)
	}

	img, err := jpeg.Decode(file)
	if err != nil {
		log.Fatal(err)
	}
	file.Close()

	m := resize.Resize(300, 0, img, resize.Lanczos3)

	out, err := os.Create("test1.jpg")
	if err != nil {
		log.Fatal(err)
	}
	defer out.Close()

	err = jpeg.Encode(out, m, nil)
	if err != nil {
		log.Fatal(err)
	}
}

コードの解説

では、コードを解説していきます。

必要なパッケージ


import (
	"image/jpeg"
	"log"
	"os"

	"github.com/nfnt/resize"
)

『image/jpeg』は jpeg画像を扱うためのパッケージです。『log』はログを出力するために、『os』は OSの様々な機能を使うためのパッケージであり、今回はファイルを開いたり、新規作成するために使用します。

『github.com/nfnt/resize』は画像をリサイズするためのライブラリで、以下のコマンドでダウンロードとインストールをしておいてください。


go get github.com/nfnt/resize

画像ファイルを開く


file, err := os.Open("test.jpg")
if err != nil {
	log.Fatal(err)
}

『os』パッケージの『Open』関数の第一引数にファイル名である『test.jpge』を指定して開きます。戻り値の『file』はファイルデスクリプタで、ファイルからデータを読み込んだり書き込むのに必要となります。

jpeg画像をデコードする


img, err := jpeg.Decode(file)
if err != nil {
	log.Fatal(err)
}
file.Close()

『jpeg』パッケージの『Decode』関数に、先ほどの『file』を渡してデコードして画像データを取り込みます。jpeg画像は圧縮されているので、元の画像データに戻す必要があり、この戻す操作をデコードと言います。

最後は『Close』関数を読んで閉じておいてください。

画像をサイズとアルゴリズムを指定してリサイズする


m := resize.Resize(300, 0, img, resize.Lanczos3)

『resize』パッケージの『Resize』関数を使って画像のリサイズを行います。

第一引数にリサイズ後の横幅を指定します。第二引数にはリサイズ後の縦幅を指定するのですが、ゼロを指定すると横幅に合わせて縦横の比率を保ったままリサイズされます。

第三引数にはデコードした画像データを渡し、最後にアルゴリズムを指定します。今回は『Lanczos3』を指定しました。

書き出し用のファイルを作成する


out, err := os.Create("test1.jpg")
if err != nil {
	log.Fatal(err)
}
defer out.Close()

『os』パッケージの『Create』関数に新規作成したいファイル名を指定して、リサイズした画像データを保存するためのファイルを用意します。

用が済んだら自動的に閉じるように『defer out.Close()』を書いておきます。

画像データをjpeg画像として保存する


err = jpeg.Encode(out, m, nil)
if err != nil {
	log.Fatal(err)
}

『jpeg』パッケージの『Encode』関数を使って、画像データをjpegにエンコードします。

第一引数に保存する先のファイル、第二引数に画像データ、第三引数にはクオリティーを指定します。クオリティーは0〜100まであり、より圧縮したい場合は70〜80くらいを指定すると良いかもしれません。

クオリティーの指定には次のような構造体を使用します。


type Options struct {
    Quality int
}

アルゴリズム別に出力画像容量などを比較

アルゴリズム別に出力された画像の容量などをざっくり比較していきます。まずは元画像を、そして出力画像容量が小さかった順にご紹介していきます。

元画像

元画像は先ほどのコードでも使用した横幅1280px、縦幅765pxのものです。以下のリサイズ後の画像は横幅を800pxにして縮小しています。

Bilinear(バイリニア補間)

25,580byte

MitcheNetravali

26,160byte

NearestNeighhor

27,093byte

Bicubric(バイキュビック補間)

27,293byte

Lancros2

27,318byte

Lancros3

27,591byte

分析

文字や線画、写真等で最適なアルゴリズムは異なりそうですが、Bilinear が一番サイズが小さくなりました。Lancros3 が一番大きいですね。

横幅を300pxにしての縮小も試してみると『NearestNeighhor』で出力された画像が『Lancros2』の次に容量の大きなものとなり、縮小サイズによっては多少の変動があるかもしれません。

ぱっと見では、どの画像も同じような感じですね(笑)

終わりに

今回使用したライブラリ『nfnt/resize』は画像のリサイズとしても使えますし、クオリティーの数値を変えたりすれば更なる圧縮も可能なものです。

フォルダの中にある画像を全て、サーバーにアップロードした画像を全て、リサイズしたり圧縮する際に活用してみてはいかがでしょうか。