Goで画像生成・編集

   · ☕ 3 min read
🏷️
  • #go
  • 画像作成

    とある授業で画像変換機能実装の課題が出ました。
    何から手をつければ良いかよくわからなかったが、とりあえず image パッケージなるものが golang.org を眺めていたところ見つかったので、
    手始めに何か触ってみようと思った。

    個人的には、いきなり 画像変換 Go とかでググるより 一次情報にアクセスした方がモテるという話を聞いたので、
    小一時間に渡り公式ドキュメントというなの樹海(僕にとって)をさまようことになる…

    だらだらとパッケージのドキュメントをみていると、 image/png というパッケージの中に、Encode なる関数が見つかった。
    なんかこいつを使えば、簡単な画像とか生成できるんじゃね? と思った。
    Encode関数はこんな感じだ。

    type.Encode

    func Encode(w io.Writer, m image.Image) error
    

    第一引数に io.Writer がきているので、どこかしらに画像を書き込める匂いがプンプンしている。
    これだ! と思った はいいものの、第二引数の image.Image というものがわからん。

    リンクを飛んでみると、どうやら 画像情報を保持しているインターフェースのようだ。

    type Image interface {
            ColorModel() color.Model
            Bounds()     Rectangle
            At(x, y int) color.Color
    }
    

    よくわからん。
    だが golang.org のサイトはありがたいことに、多くの関数に対して 使用例exampleを用意してくれている。
    func Encode の使用例は以下。

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    
    // Create a colored image of the given width and height.
    	img := image.NewNRGBA(image.Rect(0, 0, width, height))
    
    	for y := 0; y < height; y++ {
    		for x := 0; x < width; x++ {
    			img.Set(x, y, color.NRGBA{
    				R: uint8((x + y) & 255),
    				G: uint8((x + y) << 1 & 255),
    				B: uint8((x + y) << 2 & 255),
    				A: 255,
    			})
    		}
    	}
    	
    	f, err := os.Create("image.png")
        	if err != nil {
        		log.Fatal(err)
        	}
        
        	if err := png.Encode(f, img); err != nil {
        		f.Close()
        		log.Fatal(err)
        	}
    

    この例をみると、 png.Encode(f, img) のところで io.Writer と img を渡している。
    この img が上記であげた image.Image インターフェースに当たるわけだが、
    こいつは

    1
    
    img := image.NewNRGBA(image.Rect(0, 0, width, height))
    

    というように NewNRGBAという機能で生成されている。
    (New… という名前が完全に生成っぽい)

    この関数は 返り値に RGBA 型を当てている。
    RGBA型ってなんだ?って思ってリンクを辿ってみたところ、下記のようなメンバ(表現として合っていたかな?)を保持しているようだ。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    type RGBA struct {
            // Pix holds the image's pixels, in R, G, B, A order. The pixel at
            // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*4].
            Pix []uint8
            // Stride is the Pix stride (in bytes) between vertically adjacent pixels.
            Stride int
            // Rect is the image's bounds.
            Rect Rectangle
    }
    

    よくわからんが、 png.Encode 関数の引数として渡せれる img は、Imageインターフェースを満たしている必要があり、
    image.NewNRGBA関数で作成される RGBA型 はこのImageインターフェースを満たしている、ということのようだ。

    png を作成

    これ前の内容をずらずらとコードにまとめる。
    以下のコードを実行すると、真っ黒なpngが生成される。

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    
    package main
    
    import (
    	"image"
    	"image/color"
    	"image/png"
    	"log"
    	"os"
    )
    
    func main() {
    
    	min := image.Point{X: 10, Y: 10}
    	max := image.Point{X: 110, Y: 110}
    	r := image.Rectangle{Min: min, Max: max}
    
    	// NRGBA を作成
    	n := image.NewNRGBA(r)
    
    	// 描画
    	for h := r.Min.Y; h < r.Max.Y; h++ {
    		for v := r.Min.X; v < r.Max.X; v++ {
    			n.Set(v, h, color.RGBA{
    				R: uint8(0),
    				G: uint8(0),
    				B: uint8(0),
    				A: uint8(255),
    			})
    		}
    	}
    
    	// io.Writer 作成
    	f, err := os.Create("img.png")
    	if err != nil {
    		log.Fatal(err)
    	}
    
    	defer f.Close()
    
    	// エンコード
    	if err := png.Encode(f, n); err != nil {
    		log.Fatal(err)
    	}
    
    }
    
    
    Share on

    whasse
    WRITTEN BY
    whasse
    Web Developer