まっしろけっけ

めもてきなやーつ

Golang で ImageMagick を使わずに画像をいじる②

はじめに

shiro-16.hatenablog.com

前回は上記の記事で変換/切り抜き/合成あたりをやりました。
今回は画像のリサイズを行いたいと思います。

画像のリサイズ

まずは画像の縦横のサイズを半分にしてみます。

package main

import (
	"flag"
	"fmt"
	"image"
	"image/jpeg"
	"os"
	"golang.org/x/image/draw"
)

func main() {
	flag.Parse()
	args := flag.Args()

	f, err := os.Open(args[0])
	if err != nil {
		fmt.Println("open:", err)
		return
	}
	defer f.Close()

	img, _, err := image.Decode(f)
	if err != nil {
		fmt.Println("decode:", err)
		return
	}

	fso, err := os.Create(args[1])
	if err != nil {
		fmt.Println("create:", err)
		return
	}
	defer fso.Close()

	rct := img.Bounds()
	
	dst := image.NewRGBA(image.Rect(0, 0, rct.Dx() / 2, rct.Dy() / 2)) // ここで 1/2 のサイズ指定をしている
	draw.CatmullRom.Scale(dst, dst.Bounds(), img, rct, draw.Over, nil)

	jpeg.Encode(fso, dst, &jpeg.Options{Quality: 100})
}

元の画像が 150x150 なので 1/2 することで 75x75 の画像が出来上がります。
それが下記の画像

元画像 切り取り後
f:id:shiro-16:20200529113555j:plain f:id:shiro-16:20200605113615j:plain

今回は width と height 両方を 1/2 しましたが image.Rect(0, 0, rct.Dx() / 2, rct.Dy() / 2) の部分を image.Rect(0, 0, 100, 50) などに変更すると下記のような画像が出来上がります

元画像 切り取り後
f:id:shiro-16:20200529113555j:plain f:id:shiro-16:20200605114055j:plain

アスペクト比を無視して縮小が行われるので潰れた画像が出来上がってしまう。

そこでアスペクト比を維持したまま長辺のサイズを指定するというのを実現するのが下記のコード

// 上記の defer fso.Close() まで略
	arg, _ := strconv.ParseFloat(args[2], 64)

	rct := img.Bounds()

	var w, h int
	if rct.Dx() > rct.Dy() { // 横長画像
		m := arg / float64(rct.Dx())
		w = int(arg)
		h = int(float64(rct.Dy()) * m)
	} else { // 縦長画像
		m := arg / float64(rct.Dy())
		w = int(float64(rct.Dx()) * m)
		h = int(arg)
	}

	dst := image.NewRGBA(image.Rect(0, 0, w, h))
	draw.CatmullRom.Scale(dst, dst.Bounds(), img, rct, draw.Over, nil)

	jpeg.Encode(fso, dst, &jpeg.Options{Quality: 100})
}

わかりやすいように横長の画像を使用

150 × 84 を使用して下記のように長辺(今回は横)を 100 で指定する

$ go run main.go test.jpg out.jpg 100

すると下記のような 100 × 56 が出来上がる

元画像 切り取り後
f:id:shiro-16:20200605114910j:plain f:id:shiro-16:20200605115217j:plain

終わりに

前回の記事の内容と組み合わせると golang だけで様々な画像加工ができるのではないでしょうか?
計算とかめんどくさいという人は https://github.com/nfnt/resize を使うのも良いかもしれません。