goで画像のリサイズ処理を行う

# はじめに

こんにちは、icemint0828です。
今回は自作パッケージの紹介も兼ねて、goでの画像のリサイズ処理の方法を紹介します。


## 動作環境
go 1.18.3

## 使用パッケージ

* icemint0828/imgedit
画像のリサイズ処理に使用しています。
画像ファイルの拡張子の変換にも使用しています。

https://github.com/icemint0828/imgedit

## インストール

```shell
$  go get github.com/icemint0828/imgedit@v1.5.0
```

# 画像のリサイズ処理(サイズ指定)

```main.go
package main

import (
	"github.com/icemint0828/imgedit"
)

func main() {
	// サイズの指定(px)
	width, height := 500, 500

	// FileConverter
	fc, _, err := imgedit.NewFileConverter("srcImage.png")
	if err != nil {
		panic(err)
	}
	// リサイズ
	fc.Resize(width, height)
	
	// 保存(jpeg, gif形式での保存も可能)
	err = fc.SaveAs("dstImage.png", imgedit.Png)
	if err != nil {
		panic(err)
	}
}

```

比率は保持されないため、指定した`width`と`height`の画像が出力されます。

`fc.SaveAs`の第二引数では以下の形式で保存するファイルの形式を選択出来ます。
* `imgedit.Png`
* `imgedit.Jpeg`
* `imgedit.Gif`


# 画像のリサイズ処理(比率指定)

```main.go
package main

import (
	"github.com/icemint0828/imgedit"
)

func main() {
	// 比率の指定
	ratio := 0.5

	// FileConverter
	fc, _, err := imgedit.NewFileConverter("srcImage.png")
	if err != nil {
		panic(err)
	}
	// リサイズ
	fc.ResizeRatio(ratio)
	
	// 保存(jpeg, gif形式での保存も可能)
	err = fc.SaveAs("dstImage.png", imgedit.Png)
	if err != nil {
		panic(err)
	}
}

```

`ratio`は1以上も指定出来ますが、処理に時間がかかるかもしれません。


# 画像のリサイズ処理(image取得)
```main.go
package main

import (
	"image"

	"github.com/icemint0828/imgedit"
)

func main() {
	// 比率の指定
	ratio := 0.5

	// srcImgを何らかの方法で取得
	var srcImg image.Image

	// FileConverter
	c := imgedit.NewConverter(srcImg)

	// リサイズ
	c.ResizeRatio(ratio)
	dstImg := c.Convert()

	// dstImgを使用
}

```

ファイルを介さずにimageを処理したい場合は、上記のように`imgedit.NewConverter`で直接画像の加工が出来ます。

# パッケージ内の処理の説明

[imgedit](https://github.com/icemint0828/imgedit)パッケージ内の`converter.go`でリサイズ処理を実施しています。

```converter.go
// Resize resize the image
func (c *converter) Resize(resizeX, resizeY int) {
	dst := image.NewRGBA(image.Rect(0, 0, resizeX, resizeY))
	dstSize := dst.Bounds().Size()
	xRate, yRate := float64(c.Bounds().Dx())/float64(dstSize.X), float64(c.Bounds().Dy())/float64(dstSize.Y)
	for x := 0; x < dstSize.X; x++ {
		for y := 0; y < dstSize.Y; y++ {
			srcX, srcY := int(math.Round(float64(x)*xRate)), int(math.Round(float64(y)*yRate))
			dst.Set(x, y, c.Image.At(srcX, srcY))
		}
	}
	c.Image = dst
}
```

引数からサイズを取得し、`*image.RGBA`に対して、各ピクセルの色情報の書き込みしています。  
書き込みをする前に元画像と書き込み先の画像のサイズの比率を取得しています。
元画像が(400px, 400px)、リサイズ後の画像のサイズが(800px, 200px)の場合、比率は(0.5, 2.0)となります。
例えば、(400px, 50px)の地点のピクセルの色情報の書き込みをする際には、元画像の(200px, 100px)の地点のピクセルの色情報を参照しています。
ぴったりとした比率にならない場合は、math.Roundで丸めていますので、少し歪なリサイズ処理が行われるかもしれません。

```converter.go
// ResizeRatio resize the image with ratio
func (c *converter) ResizeRatio(ratio float64) {
	dst := image.NewRGBA(image.Rect(0, 0, int(math.Round(float64(c.Bounds().Dx())*ratio)), int(math.Round(float64(c.Bounds().Dy())*ratio))))
	dstSize := dst.Bounds().Size()
	xRate, yRate := 1/ratio, 1/ratio
	for x := 0; x < dstSize.X; x++ {
		for y := 0; y < dstSize.Y; y++ {
			srcX, srcY := int(math.Round(float64(x)*xRate)), int(math.Round(float64(y)*yRate))
			dst.Set(x, y, c.Image.At(srcX, srcY))
		}
	}
	c.Image = dst
}
```

ratioを元にサイズを取得し、`*image.RGBA`に対して、各ピクセルの色情報の書き込みしています。 
また、書き込みする際のピクセルの色情報の参照もratioから比率を取得して使用しています。

# おわりに
簡単な内容とはなりますが、画像のリサイズ処理を紹介させて頂きました。
最後まで読んで頂き、ありがとうございました。

#### 次の記事
[goで画像のトリム処理を行う](https://qiita.com/icemint0828/items/884dce09413bb8d2570d)