rmoff's random ramblings
about talks

Learning Golang (some rough notes) - S01E08 - Images

Published Jul 2, 2020 by in Go, Golang, Images at https://rmoff.net/2020/07/02/learning-golang-some-rough-notes-s01e08-images/

👉 A Tour of Go : Exercise: Images

This is based on the Picture generator from the Slices exercise.

func Pic(dx, dy int) [][]uint8 {
	p := make([][]uint8,dy)
	
	for i := range p {
		p[i] = make([]uint8,dx)
	}

	 for y := range p {
        for x := range p[y] {
            p[y][x]=(uint8(x)*uint8(y))
        }
    }

	return p
}
slice02

this time it will return an implementation of image.Image instead of a slice of data.

So we need to implement the interfaces defined:

  • ColorModel

  • Bounds

  • At

Let’s start off with one of these to see if we’re on the right lines…

package main

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

type Image struct{}

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

func main() {
	m := Image{}
	pic.ShowImage(m)
}

This compiles (🙌) and fails (as we’d expect) with something that may or may not be validating that we’ve not screwed things up yet:

./prog.go:17:15: cannot use m (type Image) as type image.Image in argument to pic.ShowImage:
	Image does not implement image.Image (missing At method)

Let’s add in the other fixed value, Bounds:

package main

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

type Image struct{}

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

func (i Image) Bounds() image.Rectangle {
	return image.Rect(0, 0, 256, 256)
}

func main() {
	m := Image{}
	pic.ShowImage(m)
}

Now the final part - At. Building it up bit by bit, we know what the function definition should look like, based on the above pattern and the interface definition:

func (i Image) At(x,y int) color.Color {

The value returned by this function is the colour (yes, I said colo_u_r! 🇬🇧) at the given coordinates. In the picture we created earlier this was using the expression x*y to describe the strength of the bluescale to plot. The Color type for the RGBAModel we’re using is + RGBA, which returns RGB plus alpha, so let’s try this here:

package main

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

type Image struct{}

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

func (i Image) Bounds() image.Rectangle {
	return image.Rect(0, 0, 256, 256)
}

func (i Image) At(x,y int) color.Color {
    var r,g,b,a uint8 = 25 ,0,0,0
    b=uint8(x)*uint8(y)
	return color.RGBA{r,g,b,a}
}

func main() {
	m := Image{}
	pic.ShowImage(m)
}

This not only compiles (🙌) but successfully runs (😅)…but doesn’t display anything 😢 … or does it? 🤔

In the Go execution window the Program exited is lower down the page:

image01

and if you right-click over the blank space you can see there’s an image there, and inspecting this with developer tools shows it’s a 256x256 transparent image. That alpha thingy… setting it to zero means the image is transparent!

Let’s try again and set the alpha level this time:

package main

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

type Image struct{}

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

func (i Image) Bounds() image.Rectangle {
	return image.Rect(0, 0, 256, 256)
}

func (i Image) At(x,y int) color.Color {
    var r,g,b,a uint8 = 0 ,0,0,0
    b=uint8(x)*uint8(y)
	a=b
	return color.RGBA{r,g,b,a}
}

func main() {
	m := Image{}
	pic.ShowImage(m)
}

🎉 TADA! 🎉

image02

You can muck about with the other colour values too:

func (i Image) At(x,y int) color.Color {
    var r,g,b,a uint8 = 0 ,0,0,0
	b=uint8(float64(y)*0.2) * uint8(x)
	r=uint8(float64(y)*0.5)
	a=b
	
	return color.RGBA{r,g,b,a}
}
image03
func (i Image) At(x,y int) color.Color {
    var r,g,b,a uint8 = 0 ,0,0,0
	b=uint8(float64(y)*4.25) * uint8(x*2) 
	r=uint8(float64(y)*16)
	a=b
	
	return color.RGBA{r,g,b,a}
}
image04

📺 More Episodes… ðŸ”—

  • Kafka and Go

    • S02E00 - Kafka and Go

    • S02E01 - My First Kafka Go Producer

    • S02E02 - Adding error handling to the Producer

    • S02E03 - Kafka Go Consumer (Channel-based)

    • S02E04 - Kafka Go Consumer (Function-based)

    • S02E05 - Kafka Go AdminClient

    • S02E06 - Putting the Producer in a function and handling errors in a Go routine

    • S02E07 - Splitting Go code into separate source files and building a binary executable

    • S02E08 - Checking Kafka advertised.listeners with Go

    • S02E09 - Processing chunked responses before EOF is reached

  • Learning Go

    • S01E00 - Background

    • S01E01 - Pointers

    • S01E02 - Slices

    • S01E03 - Maps

    • S01E04 - Function Closures

    • S01E05 - Interfaces

    • S01E06 - Errors

    • S01E07 - Readers

    • S01E08 - Images

    • S01E09 - Concurrency (Channels, Goroutines)

    • S01E10 - Concurrency (Web Crawler)


Robin Moffatt

Robin Moffatt works on the DevRel team at Confluent. He likes writing about himself in the third person, eating good breakfasts, and drinking good beer.

Story logo

© 2025