問題文は以下の通り。
Go 言語で、PNG 画像を入力として受け取り、その画像が何色使っているかを返す関数
func CountColor(png io.Reader) int
を実装してください。PNG 画像は io.Reader 型で与えられます。
なお、入力の画像は R G B の各色の値が 0 から 255 までの 256 段階のいずれかであり、不透明(アルファチャンネルの値が常に 255)であることが保証されています。
答えとして送ったもの(ただし変数名は多少整理した)。素直にスキャンしているだけです。
package main
import (
"fmt"
"io"
"strings"
"image"
"image/png"
)
func CountColor(r io.Reader) int {
colormap := map[uint32]int{}
image, _ := png.Decode(r)
bounds := image.Bounds()
w, h := bounds.Max.X, bounds.Max.Y
var colorNum uint32 = 0
for i := 0; i < w; i++ {
for j := 0; j < h; j++ {
colorNum = colorCheck(image.At(i, j))
colormap[colorNum] = colormap[colorNum] + 1
}
}
return len(colormap)
}
func colorCheck(color image.Color) uint32 {
r, g, b, _ := color.RGBA()
var num uint32
num = uint32(uint8(r))
num = num << 8
num = num + uint32(uint8(g))
num = num << 8
num = num + uint32(uint8(b))
return num
}
/* これらの関数は提出時に自動挿入されます。 */
func main() {
png := GetPngBinary()
cnt := CountColor(png)
fmt.Println(cnt)
}
func GetPngBinary() io.Reader {
// img_strの中身は提出するたびに変化します。
// 省略
}
以下は、後から考えたgoroutine使用版。
package main
import (
"fmt"
"io"
"strings"
"image"
"image/png"
)
func CountColor(r io.Reader) int {
colormap := map[uint32]int{}
img, _ := png.Decode(r)
bounds := img.Bounds()
w, h := bounds.Max.X, bounds.Max.Y
result := make(chan uint32)
go colorCheck(img, w, h, result)
for i := 0; i < w*h; i++ {
colormap[<-result]++
}
return len(colormap)
}
func colorCheck(img image.Image, w, h int, result chan uint32) {
var num uint32
for x := 0; x < w; x++ {
for y := 0; y < h; y++ {
r, g, b, _ := img.At(x, y).RGBA()
num = uint32(uint8(r))
num = num << 8
num = num + uint32(uint8(g))
num = num << 8
num = num + uint32(uint8(b))
result <- num
}
}
}
/* これらの関数は提出時に自動挿入されます。 */
func main() {
png := GetPngBinary()
cnt := CountColor(png)
fmt.Println(cnt)
}
func GetPngBinary() io.Reader {
// img_strの中身は提出するたびに変化します。
// 省略
}
goっぽさという点ではgoroutine版のが良いのだろうけど、いきなりこれを書くのは今の私には無理でした。改めて見ると、後者ではImageをスキャンしている部分(colorCheck)と、色数を数える部分(CountColor)が分離出来ているので、すっきりしているかも。