matterbridge/vendor/github.com/Benau/tgsconverter/libtgsconverter/lib.go

161 lines
3.9 KiB
Go

package libtgsconverter
import "bytes"
import "errors"
import "compress/gzip"
import "image"
import "io/ioutil"
import "github.com/Benau/go_rlottie"
type ConverterOptions interface {
SetExtension(ext string)
SetFPS(fps uint)
SetScale(scale float32)
SetWebpQuality(webp_quality float32)
GetExtension() string
GetFPS() uint
GetScale() float32
GetWebpQuality() float32
}
type converter_options struct {
// apng, gif, png or webp
extension string
// Frame per second of output image (if you specify apng, gif or webp)
fps uint
// Scale of image result
scale float32
// Webp encoder quality (0 to 100)
webpQuality float32
}
func(opt *converter_options) SetExtension(ext string) {
opt.extension = ext
}
func(opt *converter_options) SetFPS(fps uint) {
opt.fps = fps
}
func(opt *converter_options) SetScale(scale float32) {
opt.scale = scale
}
func(opt *converter_options) SetWebpQuality(webp_quality float32) {
opt.webpQuality = webp_quality
}
func(opt *converter_options) GetExtension() string {
return opt.extension
}
func(opt *converter_options) GetFPS() uint {
return opt.fps
}
func(opt *converter_options) GetScale() float32 {
return opt.scale
}
func(opt *converter_options) GetWebpQuality() float32 {
return opt.webpQuality
}
func NewConverterOptions() ConverterOptions {
return &converter_options{"png", 30, 1.0, 75}
}
func imageFromBuffer(p []byte, w uint, h uint) *image.RGBA {
// rlottie use ARGB32_Premultiplied
for i := 0; i < len(p); i += 4 {
p[i + 0], p[i + 2] = p[i + 2], p[i + 0]
}
m := image.NewRGBA(image.Rect(0, 0, int(w), int(h)))
m.Pix = p
m.Stride = int(w) * 4
return m
}
var disabled_cache = false
func ImportFromData(data []byte, options ConverterOptions) ([]byte, error) {
if !disabled_cache {
disabled_cache = true
go_rlottie.LottieConfigureModelCacheSize(0)
}
z, err := gzip.NewReader(bytes.NewReader(data))
if err != nil {
return nil, errors.New("Failed to create gzip reader:" + err.Error())
}
uncompressed, err := ioutil.ReadAll(z)
if err != nil {
return nil, errors.New("Failed to read gzip archive")
}
z.Close()
animation := go_rlottie.LottieAnimationFromData(string(uncompressed[:]), "", "")
if animation == nil {
return nil, errors.New("Failed to import lottie animation data")
}
w, h := go_rlottie.LottieAnimationGetSize(animation)
w = uint(float32(w) * options.GetScale())
h = uint(float32(h) * options.GetScale())
frame_rate := go_rlottie.LottieAnimationGetFramerate(animation)
frame_count := go_rlottie.LottieAnimationGetTotalframe(animation)
duration := float32(frame_count) / float32(frame_rate)
var desired_framerate = float32(options.GetFPS())
// Most (Gif) player doesn't support ~60fps (found in most tgs)
if desired_framerate > 50. {
desired_framerate = 50.
}
step := 1.0 / desired_framerate
writer := newImageWriter(options.GetExtension(), w, h, options)
if writer == nil {
return nil, errors.New("Failed create imagewriter")
}
var i float32
for i = 0.; i < duration; i += step {
frame := go_rlottie.LottieAnimationGetFrameAtPos(animation, i / duration)
buf := make([]byte, w * h * 4)
go_rlottie.LottieAnimationRender(animation, frame, buf, w, h, w * 4)
m := imageFromBuffer(buf, w, h)
err := writer.AddFrame(m, uint(desired_framerate))
if err != nil {
return nil, errors.New("Failed to add frame:" + err.Error())
}
if !writer.SupportsAnimation() {
break
}
}
go_rlottie.LottieAnimationDestroy(animation)
return writer.Result(), nil
}
func ImportFromFile(path string, options ConverterOptions) ([]byte, error) {
tgs, err := ioutil.ReadFile(path)
if err != nil {
return nil, errors.New("Error when opening file:" + err.Error())
}
return ImportFromData(tgs, options)
}
func SupportsExtension(extension string) (bool) {
switch extension {
case "apng":
fallthrough
case "gif":
fallthrough
case "png":
fallthrough
case "webp":
return true
default:
return false
}
return false
}