如何在循环中旋转图像以创建GIF动画?

huangapple go评论76阅读模式
英文:

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

问题

我想要在循环中重复旋转一张图片,以创建一个GIF,使用Go的各种图像处理工具,但我似乎无法弄清楚我做错了什么。在这里,Gwenview报告生成的GIF不是动画的,只包含一帧。


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) // 注意:忽略编码错误
}
英文:

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 (
	&quot;image&quot;
	&quot;image/color/palette&quot;
	&quot;image/color&quot;
	&quot;image/gif&quot;
	&quot;image/draw&quot;
	&quot;io&quot;
	&quot;os&quot;
	&quot;github.com/disintegration/imaging&quot;
)



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

func rotate(out io.Writer) {


	f, _ := os.Open(&quot;myimage.png&quot;)
	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 &lt; 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, &amp;anim) // NOTE: ignoring encoding errors
}

答案1

得分: 2

问题确实是你忽略了错误消息。永远不要这样做,要准确处理错误!在你的特定情况下,你的示例不起作用,因为你将新创建的图像边界设置为原始图像,但是因为在每个帧迭代中你都在旋转图像,它们的尺寸超出了原始边界。如果你没有忽略编码错误,你就可以捕获到出错的地方。

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

错误信息:

$ gif: image block is out of bounds  
英文:

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, &amp;anim)
if err != nil {
	fmt.Printf(&quot;%v&quot;, err)
}

The error:

$ gif: image block is out of bounds  

答案2

得分: 0

这是我用来制作gif的一个示例。也许它可以帮助你找到解决方案。

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
	// 设置动画循环
	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; 完整示例请参见 gist

致敬 nitoyon

英文:

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

package main
import (
&quot;fmt&quot;
&quot;image&quot;
&quot;image/color&quot;
&quot;image/gif&quot;
&quot;math&quot;
&quot;os&quot;
)
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 &gt; 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{&amp;Circle{}, &amp;Circle{}, &amp;Circle{}}
steps := 20
// Set up for the animtion loop 
for step := 0; step &lt; 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 &lt; w; x++ {
for y := 0; y &lt; 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(&quot;rgb.gif&quot;, os.O_WRONLY|os.O_CREATE, 0600)
if err != nil {
fmt.Println(err)
return
}
defer f.Close()
gif.EncodeAll(f, &amp;gif.GIF{
Image: images,
Delay: delays,
})
}

TLDR; See gist for completed example

Kuduos to nitoyon

huangapple
  • 本文由 发表于 2022年6月5日 12:17:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/72504751.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定