From ddd43370bc257adaa43b22f1eb3b293910228bf4 Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Wed, 24 Dec 2014 00:08:22 +0900 Subject: [PATCH] Add RecordScreenAsGIF (#23) --- ebitenutil/gif.go | 71 +++++++++++++++++++++++++++++++++++ example/alphablending/main.go | 7 +++- 2 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 ebitenutil/gif.go diff --git a/ebitenutil/gif.go b/ebitenutil/gif.go new file mode 100644 index 000000000..cd4643151 --- /dev/null +++ b/ebitenutil/gif.go @@ -0,0 +1,71 @@ +/* +Copyright 2014 Hajime Hoshi + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package ebitenutil + +import ( + "github.com/hajimehoshi/ebiten" + "image" + "image/color/palette" + "image/draw" + "image/gif" + "io" +) + +type recorder struct { + inner func(screen *ebiten.Image) error + writer io.Writer + gif *gif.GIF + currentFrame int +} + +func (r *recorder) update(screen *ebiten.Image) error { + if err := r.inner(screen); err != nil { + return err + } + if r.currentFrame == len(r.gif.Image) { + return nil + } + img := image.NewPaletted(screen.Bounds(), palette.Plan9) + draw.Draw(img, img.Bounds(), screen, screen.Bounds().Min, draw.Over) + r.gif.Image[r.currentFrame] = img + // The actual FPS is 60, but GIF can't have such FPS. Set 50 FPS instead. + r.gif.Delay[r.currentFrame] = 2 + + r.currentFrame++ + if r.currentFrame == len(r.gif.Image) { + if err := gif.EncodeAll(r.writer, r.gif); err != nil { + return err + } + } + return nil +} + +// RecordScreenAsGIF returns updating function with recording the screen as an animation GIF image. +// +// This encodes each screen at each frame and may slows the application. +func RecordScreenAsGIF(update func(*ebiten.Image) error, out io.Writer, frameNum int) func(*ebiten.Image) error { + r := &recorder{ + inner: update, + writer: out, + gif: &gif.GIF{ + Image: make([]*image.Paletted, frameNum), + Delay: make([]int, frameNum), + LoopCount: -1, + }, + } + return r.update +} diff --git a/example/alphablending/main.go b/example/alphablending/main.go index c1453b6a6..d9eb0f510 100644 --- a/example/alphablending/main.go +++ b/example/alphablending/main.go @@ -36,7 +36,7 @@ var ( saved bool ) -func Update(screen *ebiten.Image) error { +func update(screen *ebiten.Image) error { count++ count %= 600 diff := float64(count) * 0.2 @@ -87,7 +87,10 @@ func main() { if err != nil { log.Fatal(err) } - if err := ebiten.Run(Update, screenWidth, screenHeight, 2, "Alpha Blending (Ebiten Demo)"); err != nil { + update := update + // f, _ := os.Create("out.gif") + // update = ebitenutil.RecordScreenAsGIF(update, f, 100) + if err := ebiten.Run(update, screenWidth, screenHeight, 2, "Alpha Blending (Ebiten Demo)"); err != nil { log.Fatal(err) } }