I am currently building an avatar generator with rjourde in Go.

In the process of doing it I am learning about how to create images on the fly and display them in an html page.

Here is what I found today:

Objective

I want to have a simple web server, with two entry points: /blue and /red .

This two entry points will display a blue or red image that will be created on the fly.



var root = flag.String("root", ".", "file system path")



func main() {

http.HandleFunc("/blue/", blueHandler)

http.HandleFunc("/red/", redHandler)

http.Handle("/", http.FileServer(http.Dir(*root)))

log.Println("Listening on 8080")

err := http.ListenAndServe(":8080", nil)

if err != nil {

log.Fatal("ListenAndServe:", err)

}

}

Building an image:

For this specific example there is no much complexity in the image I want to create. So a simple RGBA image will do the work. We do this with three golang packages: image, image/color, image/draw.



m := image.NewRGBA(image.Rect(0, 0, 240, 240))

blue := color.RGBA{0, 0, 255, 255}

draw.Draw(m, m.Bounds(), &image.Uniform{blue}, image.ZP, draw.Src)

Write image to http.ResponseWriter:

Now that we have a proper image, we need to send an HTTP response with it. I found two ways to do this:



Option 1: Send an HTTP response of type image/jpeg:

image/jpeg

WriteImage

// writeImage encodes an image 'img' in jpeg format and writes it into ResponseWriter.

func writeImage(w http.ResponseWriter, img *image.Image) {



buffer := new(bytes.Buffer)

if err := jpeg.Encode(buffer, *img, nil); err != nil {

log.Println("unable to encode image.")

}



w.Header().Set("Content-Type", "image/jpeg")

w.Header().Set("Content-Length", strconv.Itoa(len(buffer.Bytes())))

if _, err := w.Write(buffer.Bytes()); err != nil {

log.Println("unable to write image.")

}

}

Get an Image

Encode it with a specific format.

Write the array of bytes to the http.ResponseWriter using the Write function.

Option 2: Use a http/template to send the image:

The first option is to write an HTTP response of typeor any format you want. This is whatdoes:This is quite straight forward:

First we define a template that reads a raw image encoded in base 64:



var ImageTemplate string = `<!DOCTYPE html>

<html lang="en"><head></head>

<body><img src="data:image/jpg;base64,{{.Image}}"></body>`

// writeImageWithTemplate encodes an image 'img' in jpeg format and writes it into ResponseWriter using a template.

func writeImageWithTemplate(w http.ResponseWriter, img *image.Image) {



buffer := new(bytes.Buffer)

if err := jpeg.Encode(buffer, *img, nil); err != nil {

log.Println("unable to encode image.")

}



str := base64.StdEncoding.EncodeToString(buffer.Bytes())

if tmpl, err := template.New("image").Parse(ImageTemplate); err != nil {

log.Println("unable to parse image template.")

} else {

data := map[string]interface{}{"Image": str}

if err = tmpl.Execute(w, data); err != nil {

log.Println("unable to execute template.")

}

}

}

str := base64.StdEncoding.EncodeToString(buffer.Bytes())

<!DOCTYPE html>

<html lang="en"><head><title></title></head>

<body>

<img src="data:image/jpg;base64,/9j/2wCEAAgGBgc....KKAP/2Q==">

</body>

All together:

Then we create a function that use this template:Notice that we are using the package encoding/base64 in order to transform the image in a raw image.This is important, if you don't do this and only pass an array of bytes the browser will not be able to generate the image as it expects an image encoded in base64.If you look at the generated HTML source code you would see something like this:

Here is the full example also available in this gist







Some links that helped me find this:



Santiaago