Home > OS >  How can I rotate an image in a loop in order to create a GIF in golang?
How can I rotate an image in a loop in order to create a GIF in golang?

Time:06-05

I want to repeatedly rotate an image in a loop, in order to create a GIF, using Go's various image processing tools, but I can't seem to figure out what I'm doing wrong. Here, Gwenview reports that the GIF produced is not animated, and contains only one frame.


package main

import (
    "image"
    "image/color/palette"
    "image/color"
    "image/gif"
    "image/draw"
    "io"
    "os"
    "github.com/disintegration/imaging"
)



func main() {
    rotate(os.Stdout)
}

func rotate(out io.Writer) {


    f, _ := os.Open("myimage.png")
    defer f.Close()
    base, _, _ := image.Decode(f)
    const (
        rot     = 45    // degrees
        nframes = 5    // number of animation frames
        delay   = 20     // delay between frames in 10ms units
    )
    bounds  := base.Bounds()


    anim := gif.GIF{LoopCount: nframes}

    for i := 0; i < nframes; i   {
        img := imaging.Rotate(base, float64(360 - (rot * i)), color.Transparent)
        bounds = img.Bounds()
        palettedImg := image.NewPaletted(bounds, palette.Plan9)
        draw.Draw(palettedImg, bounds, img, bounds.Min, draw.Src)

        anim.Delay = append(anim.Delay, delay)
        anim.Image = append(anim.Image, palettedImg)
    }
    gif.EncodeAll(out, &anim) // NOTE: ignoring encoding errors
}

CodePudding user response:

The problem is indeed that you are ignoring the error messages. Never do that, always handle the errors accurately! In your specific case your example is not working because you are setting the newly created image bounds to the original image, but because on each frame iteration you are rotating the image, their dimensions are going outside of the original bounds. If you didn't ignored the encoding errors, you could captured what's going wrong.

err := gif.EncodeAll(out, &anim)
if err != nil {
    fmt.Printf("%v", err)
}

The error:

$ gif: image block is out of bounds  

CodePudding user response:

This is an example I used to make a gif. Perhaps it could help lead you to your solution.

package main

import (
    "fmt"
    "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 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

    var hw, hh float64 = float64(w / 2), float64(h / 2)
    circles := []*Circle{&Circle{}, &Circle{}, &Circle{}}
    steps := 20
    // Set up for the animtion loop 
    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, err := os.OpenFile("rgb.gif", os.O_WRONLY|os.O_CREATE, 0600)
    if err != nil {
        fmt.Println(err)
        return
    }
    defer f.Close()
    gif.EncodeAll(f, &gif.GIF{
        Image: images,
        Delay: delays,
    })
}

TLDR; See gist for completed example

Kuduos to nitoyon

  • Related