summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/sizeofint/webpanimation/webpanimation.go
blob: b8a2adeb05da0f12d83d622567f5b8b0d822e400 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
package webpanimation

import (
	"errors"
	"fmt"
	"image"
	"image/draw"
	"io"
)

type WebpAnimation struct {
	WebPAnimEncoderOptions *WebPAnimEncoderOptions
	Width                  int
	Height                 int
	loopCount              int
	AnimationEncoder       *WebPAnimEncoder
	WebPData               *WebPData
	WebPMux                *WebPMux
	WebPPictures           []*WebPPicture
}

// NewWebpAnimation Initialize animation
func NewWebpAnimation(width, height, loopCount int) *WebpAnimation {
	webpAnimation := &WebpAnimation{loopCount: loopCount, Width: width, Height: height}
	webpAnimation.WebPAnimEncoderOptions = &WebPAnimEncoderOptions{}

	WebPAnimEncoderOptionsInitInternal(webpAnimation.WebPAnimEncoderOptions)

	webpAnimation.AnimationEncoder = WebPAnimEncoderNewInternal(width, height, webpAnimation.WebPAnimEncoderOptions)
	return webpAnimation
}

// ReleaseMemory release memory
func (wpa *WebpAnimation) ReleaseMemory() {
	WebPDataClear(wpa.WebPData)
	WebPMuxDelete(wpa.WebPMux)
	for _, webpPicture := range wpa.WebPPictures {
		WebPPictureFree(webpPicture)
	}
	WebPAnimEncoderDelete(wpa.AnimationEncoder)
}

// AddFrame add frame to animation
func (wpa *WebpAnimation) AddFrame(img image.Image, timestamp int, webpcfg WebPConfig) error {
	var webPPicture *WebPPicture = nil
	var m *image.RGBA
	if img != nil {
		if v, ok := img.(*image.RGBA); ok {
			m = v
		} else {
			b := img.Bounds()
			m = image.NewRGBA(image.Rect(0, 0, b.Dx(), b.Dy()))
			draw.Draw(m, m.Bounds(), img, b.Min, draw.Src)
		}

		webPPicture = &WebPPicture{}
		wpa.WebPPictures = append(wpa.WebPPictures, webPPicture)
		webPPicture.SetUseArgb(1)
		webPPicture.SetHeight(wpa.Height)
		webPPicture.SetWidth(wpa.Width)
		err := WebPPictureImportRGBA(m.Pix, m.Stride, webPPicture)
		if err != nil {
			return err
		}
	}

	res := WebPAnimEncoderAdd(wpa.AnimationEncoder, webPPicture, timestamp, webpcfg)
	if res == 0 {
		return errors.New("Failed to add frame in animation ecoder")
	}
	return nil
}

// Encode encode animation
func (wpa *WebpAnimation) Encode(w io.Writer) error {
	wpa.WebPData = &WebPData{}

	WebPDataInit(wpa.WebPData)

	WebPAnimEncoderAssemble(wpa.AnimationEncoder, wpa.WebPData)

	if wpa.loopCount > 0 {
		wpa.WebPMux = WebPMuxCreateInternal(wpa.WebPData, 1)
		if wpa.WebPMux == nil {
			return errors.New("ERROR: Could not re-mux to add loop count/metadata.")
		}
		WebPDataClear(wpa.WebPData)

		webPMuxAnimNewParams := WebPMuxAnimParams{}
		muxErr := WebPMuxGetAnimationParams(wpa.WebPMux, &webPMuxAnimNewParams)
		if muxErr != WebpMuxOk {
			return errors.New("Could not fetch loop count")
		}
		webPMuxAnimNewParams.SetLoopCount(wpa.loopCount)

		muxErr = WebPMuxSetAnimationParams(wpa.WebPMux, &webPMuxAnimNewParams)
		if muxErr != WebpMuxOk {
			return errors.New(fmt.Sprint("Could not update loop count, code:", muxErr))
		}

		muxErr = WebPMuxAssemble(wpa.WebPMux, wpa.WebPData)
		if muxErr != WebpMuxOk {
			return errors.New("Could not assemble when re-muxing to add")
		}

	}
	_, err := w.Write(wpa.WebPData.GetBytes())
	return err
}