convert png boards to gif
This commit is contained in:
parent
22f03b8f48
commit
588398a4df
7 changed files with 98 additions and 0 deletions
1
go.mod
generated
1
go.mod
generated
|
|
@ -9,6 +9,7 @@ require (
|
|||
github.com/dop251/goja v0.0.0-20230122112309-96b1610dd4f7
|
||||
github.com/dsoprea/go-exif/v3 v3.0.0-20221012082141-d21ac8e2de85
|
||||
github.com/dsoprea/go-png-image-structure/v2 v2.0.0-20210512210324-29b889a6093d
|
||||
github.com/ericpauley/go-quantize v0.0.0-20200331213906-ae555eb2afa4
|
||||
github.com/fsnotify/fsnotify v1.6.0
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0
|
||||
github.com/jung-kurt/gofpdf v1.16.2
|
||||
|
|
|
|||
2
go.sum
generated
2
go.sum
generated
|
|
@ -60,6 +60,8 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF
|
|||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/ericpauley/go-quantize v0.0.0-20200331213906-ae555eb2afa4 h1:BBade+JlV/f7JstZ4pitd4tHhpN+w+6I+LyOS7B4fyU=
|
||||
github.com/ericpauley/go-quantize v0.0.0-20200331213906-ae555eb2afa4/go.mod h1:H7chHJglrhPPzetLdzBleF8d22WYOv7UM/lEKYiwlKM=
|
||||
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
|
||||
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
|
||||
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
|
||||
|
|
|
|||
BIN
lib/xgif/test_input1.png
Normal file
BIN
lib/xgif/test_input1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 271 KiB |
BIN
lib/xgif/test_input2.png
Normal file
BIN
lib/xgif/test_input2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 340 KiB |
BIN
lib/xgif/test_output.gif
Normal file
BIN
lib/xgif/test_output.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 206 KiB |
56
lib/xgif/xgif.go
Normal file
56
lib/xgif/xgif.go
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
package xgif
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"image"
|
||||
"image/gif"
|
||||
"image/png"
|
||||
|
||||
"github.com/ericpauley/go-quantize/quantize"
|
||||
)
|
||||
|
||||
const INFINITE_LOOP = 0
|
||||
|
||||
func AnimatePNGs(pngs [][]byte, gifWidth, gifHeight int, animIntervalMs int) ([]byte, error) {
|
||||
interval := animIntervalMs / 10 // gif animation interval is in 100ths of a second
|
||||
anim := &gif.GIF{
|
||||
LoopCount: INFINITE_LOOP,
|
||||
Config: image.Config{
|
||||
Width: gifWidth,
|
||||
Height: gifHeight,
|
||||
},
|
||||
}
|
||||
|
||||
for _, pngBytes := range pngs {
|
||||
pngImage, err := png.Decode(bytes.NewBuffer(pngBytes))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
buf := bytes.NewBuffer(nil)
|
||||
err = gif.Encode(buf, pngImage, &gif.Options{
|
||||
NumColors: 256, // GIFs can have up to 256 colors
|
||||
Quantizer: quantize.MedianCutQuantizer{},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
gifImg, err := gif.Decode(buf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
palettedImg, ok := gifImg.(*image.Paletted)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("decoded git image could not be cast as *image.Paletted")
|
||||
}
|
||||
anim.Image = append(anim.Image, palettedImg)
|
||||
anim.Delay = append(anim.Delay, interval)
|
||||
}
|
||||
|
||||
buf := bytes.NewBuffer(nil)
|
||||
err := gif.EncodeAll(buf, anim)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
39
lib/xgif/xgif_test.go
Normal file
39
lib/xgif/xgif_test.go
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
package xgif
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
_ "embed"
|
||||
"image/png"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"oss.terrastruct.com/util-go/go2"
|
||||
)
|
||||
|
||||
//go:embed test_input1.png
|
||||
var test_input1 []byte
|
||||
|
||||
//go:embed test_input2.png
|
||||
var test_input2 []byte
|
||||
|
||||
//go:embed test_output.gif
|
||||
var test_output []byte
|
||||
|
||||
func TestPngToGif(t *testing.T) {
|
||||
board1, err := png.Decode(bytes.NewBuffer(test_input1))
|
||||
assert.NoError(t, err)
|
||||
gifWidth := board1.Bounds().Dx()
|
||||
gifHeight := board1.Bounds().Dy()
|
||||
|
||||
board2, err := png.Decode(bytes.NewBuffer(test_input2))
|
||||
assert.NoError(t, err)
|
||||
gifWidth = go2.Max(board2.Bounds().Dx(), gifWidth)
|
||||
gifHeight = go2.Max(board2.Bounds().Dy(), gifHeight)
|
||||
|
||||
boards := [][]byte{test_input1, test_input2}
|
||||
interval := 1_000
|
||||
gifBytes, err := AnimatePNGs(boards, gifWidth, gifHeight, interval)
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Equal(t, test_output, gifBytes)
|
||||
}
|
||||
Loading…
Reference in a new issue