I'm going through the Golang tutorial and I'm a little bit confused as to what it is doing with some of the values in the slices exercise. https://tour.golang.org/moretypes/18
Here is the code that I am confused with:
A value of 0 is a perfectly blue pixel and a value of 255 is a perfectly white pixel. So what is happening here when the value displayed is some form of x*y
(I did /20
to make the image a little bit bigger and easier to see).
If you follow the image horizontally, you will see that at some point in the process, the ever increasing x and y values seem to revert to blue (0 value) If I type a static value like 256
in the return I get a compile error. So it obviously does not allow the numbers to go off the scale
and revert to 0 or anything. So how does it get the blue curves in the picture?
imported source here: https://github.com/golang/tour/blob/master/pic/pic.go#L15
package main
import "golang.org/x/tour/pic"
func Pic(dx, dy int) [][]uint8 {
//First, the array has to be made so we can put some values in it later
//This only makes the second dimension of the array ([[uint8 dy]])?
image := make([][]uint8, dy)
//The inputs into the function are Int's, so it is ok to have a non uint8
//loop initializer
for x := 0; x < dy; x++ {
//once we are in the loop we have to make the first dimension of the array
//based on the dx values
image[x] = make([]uint8, dx)
for y := 0; y < dx; y++ {
//This is a function +to assign the pixel values to the array
image[x][y] = uint8((x * y) /20)
}
}
return image
}
func main() {
pic.Show(Pic)
}
Imagine i
is of type int
, uint8(i)
returns Least Significant Byte (LSB) of i
:
When x
is in range [0, 255]
, meaning: 0 <= x <= 255
and y
is in range [0, 255],
then x*y
is in range [0, 255*255] = [0, 65025]
so x*y/20
is in range [0, 255*255/20] = [0, 65025/20] = [0, 3251]
and value of uint8(x*y/20)
is equal to (x*y/20)%256
meaning exactly LSB byte:uint8(3251) = uint8(0XCB3) = 0XB3 = 179
3251 = 12*256 + 179
So every time the x*y/20
is bigger than 255 it counts from 0 again: (x*y/20) % 256
this is why your image is repeated circles.
Try this working sample code:
package main
import "fmt"
func main() {
for y := 0; y <= 255; y++ {
for x := 0; x <= 255; x++ {
v := x * y / 20
if int(uint8(v)) != v%256 {
fmt.Println(v, v%256)
}
}
}
fmt.Println("Done.")
}
output:
Done.
Let's simplify you example, see this working sample code:
package main
import (
"bytes"
"image"
"image/png"
"os"
)
func main() {
const dx = 256
const dy = 256
m := image.NewNRGBA(image.Rect(0, 0, dx, dy))
for y := 0; y < dy; y++ {
for x := 0; x < dx; x++ {
v := uint8(x * y / 20)
i := y*m.Stride + x*4
m.Pix[i] = v //R
m.Pix[i+1] = v //G
m.Pix[i+2] = 255 //B
m.Pix[i+3] = 255 //A
}
}
var buf bytes.Buffer
err := png.Encode(&buf, m)
if err != nil {
panic(err)
}
os.Stdout.Write(buf.Bytes())
}
And redirect the output to a file like main > b.png
or, go run main.go > b.png
see output file b.png
:
uint8(anotherIntValue)
conversion will take the last byte of anotherIntValue
. That is why your code can produce many blue (0). For example, following code would print 'val = 0'.
dx, dy := 128, 2
fmt.Println("val =", uint8(dx*dy))
Constant conversion will be checked by compiler for out of range errors.