07 Jan 2016
Generate an animated GIF with Golang
This article shows how to generate an animated GIF with Golang in 3 ways.
- Generate from static images
- Generate from video
- Generate programatically
Generate from static images
Let's make an animated GIF from static images.
Supose that we have following static GIF images:
We got:
This animated GIF is generated by following code:
package main
import "image"
import "image/gif"
import "os"
func main() {
files := []string{"g1.gif", "g2.gif","g3.gif", "g2.gif"}
// load static image and construct outGif
outGif := &gif.GIF{}
for _, name := range files {
f, _ := os.Open(name)
inGif, _ := gif.Decode(f)
f.Close()
outGif.Image = append(outGif.Image, inGif.(*image.Paletted))
outGif.Delay = append(outGif.Delay, 0)
}
// save to out.gif
f, _ := os.OpenFile("out.gif", os.O_WRONLY|os.O_CREATE, 0600)
defer f.Close()
gif.EncodeAll(f, outGif)
}
Note:
- Read each frame GIF image with
gif.Decode
. If we read JPEG images, we have to convert them programatically (goanigiffy does this by callinggif.Encode
andgif.Decode
). - Call
gif.EncodeAll
to save animated GIF.
Convert video to Animated GIF
Use MPlayer to extract frames, and create animated GIF with goanigiffy (see GoAniGiffy for details).
Programatically
Let's generate animated GIF programatically.
Generate []*image.Paletted
programatically and pass it to gif.EncodeAll
.
var images []*image.Paletted
var delays []int
// create 20 images and draw circles
for step := 0; step < 20; step++ {
img := image.NewPaletted(image.Rect(0, 0, w, h), palette)
images = append(images, img)
delays = append(delays, 0)
// drawing code (too long)
}
// save to rgb.gif
f, _ := os.OpenFile("rgb.gif", os.O_WRONLY|os.O_CREATE, 0600)
defer f.Close()
gif.EncodeAll(f, &gif.GIF{
Image: images,
Delay: delays,
})
The entire code is as follows:
package main
import (
"image"
"image/color"
"image/gif"
"math"
"os"
)
type Circle struct {
X, Y, R float64
}
func (c *Circle) Brightness(x, y float64) uint8 {
var dx, dy float64 = c.X - x, c.Y - y
d := math.Sqrt(dx*dx+dy*dy) / c.R
if d > 1 {
return 0
} else {
return 255
}
}
func main() {
var w, h int = 240, 240
var hw, hh float64 = float64(w / 2), float64(h / 2)
circles := []*Circle{&Circle{}, &Circle{}, &Circle{}}
var palette = []color.Color{
color.RGBA{0x00, 0x00, 0x00, 0xff},
color.RGBA{0x00, 0x00, 0xff, 0xff},
color.RGBA{0x00, 0xff, 0x00, 0xff},
color.RGBA{0x00, 0xff, 0xff, 0xff},
color.RGBA{0xff, 0x00, 0x00, 0xff},
color.RGBA{0xff, 0x00, 0xff, 0xff},
color.RGBA{0xff, 0xff, 0x00, 0xff},
color.RGBA{0xff, 0xff, 0xff, 0xff},
}
var images []*image.Paletted
var delays []int
steps := 20
for step := 0; step < steps; step++ {
img := image.NewPaletted(image.Rect(0, 0, w, h), palette)
images = append(images, img)
delays = append(delays, 0)
θ := 2.0 * math.Pi / float64(steps) * float64(step)
for i, circle := range circles {
θ0 := 2 * math.Pi / 3 * float64(i)
circle.X = hw - 40*math.Sin(θ0) - 20*math.Sin(θ0+θ)
circle.Y = hh - 40*math.Cos(θ0) - 20*math.Cos(θ0+θ)
circle.R = 50
}
for x := 0; x < w; x++ {
for y := 0; y < h; y++ {
img.Set(x, y, color.RGBA{
circles[0].Brightness(float64(x), float64(y)),
circles[1].Brightness(float64(x), float64(y)),
circles[2].Brightness(float64(x), float64(y)),
255,
})
}
}
}
f, _ := os.OpenFile("rgb.gif", os.O_WRONLY|os.O_CREATE, 0600)
defer f.Close()
gif.EncodeAll(f, &gif.GIF{
Image: images,
Delay: delays,
})
}
Thank you for reading.