[Newbie] Create PNG from 2D Array and Write Over HTTP

552 views
Skip to first unread message

maaa...@gmail.com

unread,
Feb 27, 2017, 10:23:52 AM2/27/17
to golang-nuts
Hi, I'm just starting to learn Go. I have a small pattern in a 5x5 array of bools. I turn this into an image by looping through all of the values in the array and using Image.Set if the value is true.

matrix := [5][5]bool{}
// fill in matrix here
m
:= image.NewRGBA(image.Rect(0, 0, 5, 5))
fg
:= color.RGBA{255, 0, 255, 255}
bg
:= color.RGBA{255, 255, 255, 255}
draw
.Draw(m, m.Bounds(), &image.Uniform{bg}, image.ZP, draw.Src)
for x, row := range matrix {
   
for y, cell := range row {
       
if cell {
            m
.Set(x, y, fg)
       
}
   
}
}

Then I encode the image to a png and write it to the http.ResponseWriter

buffer := new(bytes.Buffer)
png
.Encode(buffer, *img)
w
.Write(buffer.Bytes())

It wasn't too slow, but I feel like I am doing something very wrong and that it could be faster. I wrote a benchmark method in a test file with ReportAllocs that calls the method in a loop and it reported that each call was allocating memory 47 times so I'm sure that there's a better way to do this.

I found the "github.com/oxtoacart/bpool" library which I can use to pool the buffers I encode the png into, but after running with GODEBUG=allocfreetrace=1 it shows that most of the allocations come from creating the image, drawing the background and plotting all of the pixels.

Sorry if this post is a bit confusing or all over the place, tl;dr: How can I quickly plot a 2D array of pixels onto a PNG that I can write to a http.ResponseWriter?

Thanks :)

howar...@gmail.com

unread,
Feb 27, 2017, 12:19:33 PM2/27/17
to golang-nuts, maaa...@gmail.com
You could define the colors higher in the package - right now you are allocating them every time, but they are not changing. You could also also retain the image and simply wipe and rewrite it every time as long as it is not happening in a goroutine in multiple places - if so, you could retain one image per goroutine. When you do png.Encode, the image is only read, not modified, and it is fine to hold on to it, change the pixels, and Encode it again.

It is possible to access the bytes directly but I can't see any advantage to doing that in a 5x5 example. 

Howard

Guillermo Estrada

unread,
Feb 27, 2017, 2:07:18 PM2/27/17
to golang-nuts, maaa...@gmail.com
Hi, first I would avoid using 2D arrays for storing pixels and such, that's not even a Go thing, (although Go internal library uses a 1D array for storing pixels of images), even in C or C++ a 1D array is recomended, it is faster to say the least and more efficient.

img[x][y] becomes img[y*width+x]

And you iterate exactly the same. As for Go, 2D Arrays have to be initialized properly (each array inside the main one) and 1D arrays don't have that problem.
Also png.Encode takes a Writer and an image, so you can actually do that at once (without the buffer) as w (http.ResponseWriter) is a Writer already.

png.Encode(w, image)
Reply all
Reply to author
Forward
0 new messages