“Images” exercise from A Tour of Go

The "Images" exercise in A Tour of Go asks for an implementation of image.Image. I wrote two solutions, one easy and one harder (just for practice in dealing with interfaces).

SOLUTION 1: (HARD WAY)

package main

import (
"golang.org/x/tour/pic"
"image"
"image/color"
)

type Image struct{
// one array for x value, one array for y values, array of integer for pixel RGBA values
image_ [][][]uint8
x0, y0, x1, y1 int
}

func (i *Image) NewImage(x, y int) *Image {
image := make([][][]uint8, y)
for i := 0; i < x; i++ {
image[i] = make([][]uint8, x)
for j := 0; j < y; j++ {
image[i][j] = make([]uint8, 4)
}
}
return &Image{image, 0, 0, x, y}
}

func (p *Image) ColorModel() color.Model { return color.RGBAModel }

func (p *Image) At(x, y int) color.Color {
var c color.Color
rgba := color.RGBA{
p.image_[x][y][0],
p.image_[x][y][1],
p.image_[x][y][2],
p.image_[x][y][3],
}
c = rgba
return c
}

func (p *Image) Bounds() image.Rectangle {
rectangle := image.Rect(p.x0, p.y0, p.x1, p.y1)
return rectangle
}

func (p *Image) crazyColors() *Image {
for i := 0; i < len(p.image_) - 1; i++ {
for j := 0; j < len(p.image_[i]) - 1; j++ {
p.image_[i][j][0] = uint8(i + j / 2)
p.image_[i][j][1] = uint8(i + j * 2)
p.image_[i][j][2] = uint8(i + j * 2)
p.image_[i][j][3] = uint8(255)
}
}
return p
}

func main() {
var i *Image
i = i.NewImage(255, 255)
i.crazyColors()
pic.ShowImage(i)
}


SOLUTION 2: (EASY WAY)

package main

import (
"golang.org/x/tour/pic"
"image"
)

type Image struct{
image.RGBA
}

func (i Image) crazyColors() Image {
for p := 0; p < len(i.Pix); p += 4 {
i.Pix[p] = uint8(p + p*2)
i.Pix[p+1] = uint8(p + p*2)
i.Pix[p+2] = uint8(p + p*2)
i.Pix[p+3] = uint8(p + p*2)
}
return i
}

func main() {
rect := image.Rect(0,0,255,255)
m := Image{*image.NewRGBA(rect)}
m.crazyColors()
pic.ShowImage(&m)
}

• I'm not sure what your question is? would it be performance? or better solution? – Siobhan Oct 12 '16 at 16:35
• The second program looks broken. Where does Pix come from? – janos Oct 12 '16 at 16:45
• Also, it would be good to include a description of what you're actually trying to solve here. – janos Oct 12 '16 at 16:47

Storing a rectangle

The Image stores the parameters to create a rectangle. Those values are not used for anything else in the lifetime of the object, except to create the bounding rectangle when needed. You could instead just store the rectangle itself, so could simply return it when needed.

Pointless local variables

Many of the local variables are pointless, you could skip declaring and assigning to them and simply return values directly, for example:

func (p *Image) At(x, y int) color.Color {
return color.RGBA{
p.image_[x][y][0],
p.image_[x][y][1],
p.image_[x][y][2],
p.image_[x][y][3],
}
}


Naming

The _ suffix in Image.image_ is unusual. I suggest to simply drop the suffix.

The name i is most often used in simple counting loops, I suggest to avoid using it for other purposes. A good short name for an image instance could be img, for example.