GIF image creation in Go tutorial


I would like to share with you a straightforward and elegant way of creating GIF images in Go programming language. Many developers are afraid of images creation or manipulation. However, as you will see, generation of GIF images using out-of-the-box Go libraries is just fun.

Basic GIF image

In order to create a GIF image we need packages such as image, image/color and image/gif. The following function creates a GIF image with a given width and height, the white background and a black pixel in the middle of the image. Note that for simplicity of the example I am not handling any error related to GIF encoding.

import (
  "image"
  "image/color"
  "image/gif"
)

// CreateBasicGif creates a GIF image with the given width and height.
// It uses white background and a black pixel in the middle of the image.
func CreateBasicGif(out io.Writer, width, height int) {

  palette := []color.Color{color.White, color.Black}
  rect := image.Rect(0, 0, width, height)
  img := image.NewPaletted(rect, palette)

  img.SetColorIndex(width/2, height/2, 1)

  anim := gif.GIF{Delay: []int{0}, Image: []*image.Paletted{img}}

  gif.EncodeAll(out, &anim)
}

Saving generated image

So a GIF image creation was pretty easy. A few lines of code and we have a GIF image ready. Now we need to save it. And the fascinating thing is that you can call that function with multiple io.Writer to achieve different saving methods, e.g. save the image directly to a file, to the output stream or a web request response.

Saving an image to a file

This example presents a method of saving an image directly to a file.

import "os"

func main() {
  f, err := os.Create("my-image.gif")
  if err != nil {
    panic(err)
  }
  defer f.Close()

  CreateBasicGif(f, 50, 50)
}

Saving an image to the output stream

This example sends an image to the output stream. You can save a generated image by streaming output of your program to a file e.g. app > image.gif.

import "os"

func main() {
  CreateBasicGif(os.Stdout, 50, 50)
}

More interesting GIF image

Image with a random pattern

In this example, I create several images with grey color shades palette and randomly set pixels. This example is pretty trivial and its primary purpose is to give you an idea of an image creation. I would encourage you to experiment with different algorithms resulting in exciting designs.

Note that I am using math/rand.Seed function to initialize random number generator with the current time in the main function.

package main

import (
  "image"
  "image/color"
  "image/gif"
  "io"
  "math/rand"
  "os"
  "time"
)

func main() {
  rand.Seed(time.Now().UnixNano())
  CreateGif(os.Stdout, 300, 100, 2, 500000)
}

// CreateGif creates a GIF image with the given width and height, number of colors and
// number of randomly set pixels. The image is written to the given out writer.
func CreateGif(out io.Writer, width, height, colors, dots int) {
  var palette = []color.Color{}

  for i, delta := 0, 255/(colors-1); i < 256; i++ {
    palette = append(palette, color.Gray{uint8(delta * i)})
  }

  rect := image.Rect(0, 0, width, height)
  img := image.NewPaletted(rect, palette)

  for i := 0; i < dots; i++ {
    x := rand.Intn(width)
    y := rand.Intn(height)
    c := rand.Intn(colors)

    img.SetColorIndex(x, y, uint8(c))
  }

  anim := gif.GIF{Delay: []int{0}, Image: []*image.Paletted{img}}

  gif.EncodeAll(out, &anim)
}
images/scale-100x100c2.gif
100 x 100 pixel images with 2 (black and white) and 50 gray shades respectively - zoomed in 3 times

Fractal images based on Mandelbrot set

In this example I create several images presenting Mandelbrot fractals. For that purpose I use go-mandelbrot package. I generate and save a GIF image using the above-mentioned approach.

Note that in this example lowest and highest color index use black color. I would encourage you to experiment with different colors to achieve very interesting results.

package main

import (
  "image"
  "image/color"
  "image/gif"
  "io"
  "os"

  mandelbrot "github.com/t-pwk/go-mandelbrot"
)

const (
  width  = 600
  height = 600
)

func main() {

  m := mandelbrot.Mandelbrot(-2+1.25i, 0.5-1.25i, height, width, 255)
  createImage(os.Stdout, height, width, m, 255)
}

func createImage(w io.Writer, heigh, width int, values [][]uint) {
  palette := make([]color.Color, 256)

  for i := 0; i < 256; i++ {
    palette[i] = color.Gray{255 - uint8(i)}
  }

  rect := image.Rect(0, 0, width, height)
  img := image.NewPaletted(rect, palette)

  for y := 0; y < int(height); y++ {
    for x := 0; x < int(width); x++ {
      img.SetColorIndex(x, y, uint8(values[y][x]))
    }
  }

  anim := gif.GIF{Delay: []int{0}, Image: []*image.Paletted{img}}
  gif.EncodeAll(w, &anim)
}

**Mandelbrot set**, points between **-2+1.25i** and **0.5-1.25i** with **255** iterations
Mandelbrot set, points between -2+1.25i and 0.5-1.25i with 255 iterations
**Mandelbrot - elephant valley**, points between **0.25+0.05i** and **0.35-0.05i** with **255** iterations
Mandelbrot - elephant valley, points between 0.25+0.05i and 0.35-0.05i with 255 iterations

Conclusion

As you can see from the above examples, GIF image creation is not that scary after all. When you look at the Mandelbrot fractal example, you can see that with a minimal amount of code you can generate really breathtaking images.

I would encourage you to visit Go documentation and review different methods related to GIF as well as other image formats.

Happy Coding!


Tags:

#Mandelbrot #algorithm #color #fractal #gif #go #image #random


You may also be interested in:



comments powered by Disqus