Golang で ImageMagick を使わずに画像をいじる
はじめに
最近動的に画像を変換するみたいなことをやっていて ImageMagick を使えば簡単にできるんですが
Golang の場合 ImageMagick を使わなくても様々な画像の加工が可能なので ImageMagick を使わずにやった時のメモ
画像形式の変換
最初は画像形式の変換の説明
jpg を png にしたり webp にしたりなどです。
ちなみに Golang では webp の Encode は標準でサポートされていないので今回は https://github.com/chai2010/webp を使用します。
package main import ( "flag" "fmt" "github.com/chai2010/webp" "image" "image/gif" "image/jpeg" "image/png" "os" "strings" ) 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() slice := strings.Split(args[1], ".") switch slice[len(slice)-1] { // 出力画像の拡張子によってエンコードを変える case "jpeg", "jpg": jpeg.Encode(fso, img, &jpeg.Options{}) case "png": png.Encode(fso, img) case "gif": gif.Encode(fso, img, nil) case "webp": webp.Encode(fso, img, &webp.Options{Lossless: true}) default: } }
こんなコードを用意して下記のように実行すると変換されます。
$ go run main.go test.jpg hoge.png $ go run main.go test.jpg hoge.webp
元画像 | 変換後(gif) |
画像の切り抜き
続いて画像の一部を切り抜く方法を説明
package main import ( "fmt" "image" "image/jpeg" "os" ) type SubImager interface { SubImage(r image.Rectangle) image.Image } func main() { f, err := os.Open("test.jpg") 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("out.jpg") if err != nil { fmt.Println("create:", err) return } defer fso.Close() cimg := img.(SubImager).SubImage(image.Rect(50, 0, 150, 100)) jpeg.Encode(fso, cimg, &jpeg.Options{Quality: 100}) // Quality を指定しないと荒すぎる画像が出来上がるよ }
image.Rect で横は 50px ~ 150px 縦は 0px ~ 100px まで切り取るという指定をしています。
こうして出来上がったのが下記の画像
元画像 | 切り取り後 |
画像の合成
最後に画像の合成
2 つの画像を重ね合わせるなどして合成する方法を説明します。
package main import ( "fmt" "golang.org/x/image/draw" "image" "image/color" "image/jpeg" "os" ) type SubImager interface { SubImage(r image.Rectangle) image.Image } func main() { f, err := os.Open("test.jpg") 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("out.jpg") if err != nil { fmt.Println("create:", err) return } defer fso.Close() m := image.NewRGBA(image.Rect(0, 0, 200, 200)) // 200x200 の画像に test.jpg をのせる c := color.RGBA{0, 0, 255, 255} // RGBA で色を指定(B が 255 なので青) draw.Draw(m, m.Bounds(), &image.Uniform{c}, image.ZP, draw.Src) // 青い画像を描画 rct := image.Rectangle{image.Point{25, 25}, m.Bounds().Size()} // test.jpg をのせる位置を指定する(中央に配置する為に横:25 縦:25 の位置を指定) draw.Draw(m, rct, img, image.Point{0, 0}, draw.Src) // 合成する画像を描画 jpeg.Encode(fso, m, &jpeg.Options{Quality: 100}) }
こうして出来上がったのが下記の画像
元画像 | 合成後 |
上記では青い画像を作成して合成を行なったがもちろん既存の画像を使うことも可能で下記のように書く
// 上記の defer fso.Close() まで略 f2, _ := os.Open("hoge.jpg") // 元になる画像 img2, _, _ := image.Decode(f2) rgba := image.NewRGBA(image.Rectangle{image.Point{0, 0}, image.Point{200, 200}}) // RGB形式の画像を用意する draw.Draw(rgba, image.Rectangle{image.Point{0, 0}, img2.Bounds().Size()}, img2, image.Point{0, 0}, draw.Src) // 元になる画像を描画する rct := image.Rectangle{image.Point{25, 25}, img2.Bounds().Size()} // 元画像への描画位置を決める draw.Draw(rgba, rct, img, image.Point{0, 0}, draw.Src) // 乗せる画像を描画 jpeg.Encode(fso, rgba, &jpeg.Options{Quality: 100}) }
これで出来上がるのが下記の画像
元画像 | 合成する画像 | 合成後 |
終わりに
ちょっと長くなってしまったので今日はここまで
続きは次週とかに書くかもしれない