2013年12月30日月曜日

Golang Cafe #10を開催しました。

Golang Cafe #10を開催しました。

今回は、imageパッケージを使ってみる会ということで画像処理のコードを書いていました。
サンプルコードはGithubにpushしてありますので、ご興味があればごらんください。

今回提示したサンプルは

  1. png画像をjpegに変換する(単純に読みだして、そのまま書き出す)
  2. png画像に「#」を書き加えてpng画像を出力する。(#golangとしたかったけど時間が足りなかった)
基本的に画像を読み込む場合は、os.Open("ファイル名")でファイルを開きます。書き出す時は、os.Create("ファイル名")でファイルを作成した後、os.Fileのポインタを介して画像データを書き出します。

Goのimageパッケージは、画像のピクセル情報をimage.Imageインターフェイスを実装した構造体が管理しており、画像の形式(gif/jpeg/png)にかかわらず、Imageインターフェイスを介して画像が生成されるようになっています。ImageインターフェイスはRectangleの取得、color.Modelの取得、ピクセルの色を取得しかありません。
したがって、直接編集することができないようになっています。

画像を編集しようと思うとどうするか。というと、元画像を読み取り、いちいち画像データをコピーする必要があります。今回はRGBAにコピーしています。RGBAは一般的なRGBA(Aは透明度?)に対応した型です。
(以下はwritesample.goの抜粋です)
rect := img.Bounds()
rgba := image.NewRGBA(rect)
size := rect.Size()

// 元画像のコピー
for x := 0; x < size.X; x++ {
 for y := 0; y < size.Y; y++ {
  rgba.Set(x, y, img.At(x, y))
 }
}

// #golangとか書きたいけど、今は時間がない。
for i := 0; i < 10; i++ {
 rgba.Set(60, (10 + i), image.Black.At(0, 0))
 rgba.Set(65, (10 + i), image.Black.At(0, 0))
 rgba.Set((58 + i), 13, image.Black.At(0, 0))
 rgba.Set((58 + i), 16, image.Black.At(0, 0))
}

outRect := image.Rect(0, 0, rect.Max.X, rect.Max.Y)
outImage := rgba.SubImage(outRect)

RGBAだけでなく、Gray16や、RGBA64にはSet()が用意されており、ピクセルデータを上書きする事ができます。今回は黒で上書きしたので、定数で定義されている、image.Blackを利用しました。用意されているのは、黒と白だけのようなので、他の色は作るしかないです。
Goには、JavaとかC#などのように、「線を引く」「円を描く」「画像を描画する」というAPIが用意されていないので、自分でピクセルの上書き処理を書かないといけません。
(あってもいいと思うけど何でないの?)

しかも、画像として書き出すためには、image.Imageを作らないといけないので、出力用のRectangleを用意して、SubImage()で取り出すという事をしなければいけないという、ちょっと面倒な感じになっています。(ただ、データ構造として、interfaceになっていて、画像形式に依存したコードがそれぞれの処理で分離されているのは良い設計だと思う)

ということで、便利なライブラリがないかと探してみると、draw2dというライブラリが存在しています。後半はこれを使ったコードを書いて、動かすという流れになりました。
サンプルコードはwritesamplewithdraw2d.goを見て下さい。

draw2dを使う場合は、"code.google.com/p/draw2d/draw2d"をimportします。
ライブラリ自体を取得する場合は、go getコマンドで取得して下さい。

使い方は、image.NewRGBA()までは同じですが、その後、戻り値のimage.Imageをdraw2d.NewGraphicContext()の引数にして、GraphicContextを取得します。
GraphicContextには、DrawImage()も、LineTo()もありますから、それぞれのAPIを呼び出せば、画像が描けたり、線が引けたりします。
(それでも、少し不便な感じがしなくはないですが…)

文字も描画できますが、事前にTrueTypeFontを読み取らないといけません。
初期値が"../resource/font/"になっていて、しかも、freetype-goというライブラリに依存しているため、そちらのソースコードを編集するか、draw2d.SetFontFolder("font/")という感じで、事前にフォントのディレクトリを指定しておく必要があります。
しかも、それだけではまだダメで、任意のフォント(例えば、システムフォントなど)を読み出そうと思ったら、内部でチェックがかかっていて、ファイル名を勝手に生成するようになっているので、”MS ゴシック"とか、"ヒラギノ角ゴ"というようなフォントを指定してもそのまま使えないという残念な結果になりました。
(元々この辺は使えないのだろうか?)

ということで、imageパッケージ周りはまだまだライブラリを作る余地があり、標準に用意されても良さそうな感じはしました。来年の1.3以降のリリースに期待ですね。

さて、次回は、archiveパッケージを使ってみる会になる予定です。