diff --git a/ffmpeg/convert.go b/ffmpeg/convert.go index 4152f79..abf4733 100644 --- a/ffmpeg/convert.go +++ b/ffmpeg/convert.go @@ -68,7 +68,7 @@ func ConvertPath(ctx context.Context, inputFile string, outputExtension string, cmd.Stderr = logWriter err := cmd.Run() if err != nil { - return "", fmt.Errorf("ffmpeg error: %+v", err) + return "", fmt.Errorf("ffmpeg error: %w", err) } if removeInput { diff --git a/lottie/convert.go b/lottie/convert.go new file mode 100644 index 0000000..933ac87 --- /dev/null +++ b/lottie/convert.go @@ -0,0 +1,103 @@ +// Copyright (c) 2024 Sumner Evans +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package lottie + +import ( + "bytes" + "context" + "fmt" + "io" + "os" + "os/exec" + "path/filepath" + "strings" + + "github.com/rs/zerolog" + "go.mau.fi/util/exzerolog" +) + +var lottieconverterPath string + +func init() { + lottieconverterPath, _ = exec.LookPath("lottieconverter") +} + +// Supported returns whether lottieconverter is available on the system. +// +// lottieconverter is considered to be available if a binary called +// lottieconverter is found in $PATH, or if [SetPath] has been called +// explicitly with a non-empty path. +func Supported() bool { + return lottieconverterPath != "" +} + +// SetPath overrides the path to the lottieconverter binary. +func SetPath(path string) { + lottieconverterPath = path +} + +// ConvertPath converts a lottie file on disk using lottieconverter. The +// filename will be the same as the input file, but with the extension changed +// to the format specified. +// +// Args: +// - inputFile: the full path to the file. +// - format: the format to convert to. Either "gif" or "png". +// - width: the width of the output file. +// - height: the height of the output file. +// - extraArgs: additional arguments to pass to lottieconverter. +// +// Returns: the path to the converted file. +func ConvertPath(ctx context.Context, inputFile, format string, width, height int, removeInput bool, extraArgs ...string) (outputFile string, err error) { + outputFile = strings.TrimSuffix(strings.TrimSuffix(inputFile, filepath.Ext(inputFile)), "*") + "." + format + err = convert(ctx, inputFile, nil, outputFile, nil, format, width, height, extraArgs...) + if err != nil { + return "", err + } + + if removeInput { + _ = os.Remove(inputFile) + } + return outputFile, nil +} + +// ConvertBytes converts lottie data to an [image.Image] using lottieconverter. +// +// Args: +// - data: the lottie data. +// - format: the format to convert to. Either "gif" or "png". +// - width: the width of the output file. +// - height: the height of the output file. +// - extraArgs: additional arguments to pass to lottieconverter. +// +// Returns: the path to the converted file. +func ConvertBytes(ctx context.Context, data []byte, format string, width, height int, extraArgs ...string) (img []byte, err error) { + var output bytes.Buffer + err = convert(ctx, "-", bytes.NewReader(data), "-", &output, format, width, height, extraArgs...) + return output.Bytes(), err +} + +func convert(ctx context.Context, inputFile string, inputReader io.Reader, outputFile string, outputWriter io.Writer, format string, width, height int, extraArgs ...string) error { + args := []string{inputFile, outputFile, format, fmt.Sprintf("%dx%d", width, height)} + args = append(args, extraArgs...) + + cmd := exec.CommandContext(ctx, lottieconverterPath, args...) + ctxLog := zerolog.Ctx(ctx).With().Str("command", "lottieconverter").Logger() + logWriter := exzerolog.NewLogWriter(ctxLog).WithLevel(zerolog.WarnLevel) + cmd.Stdin = inputReader + if outputWriter != nil { + cmd.Stdout = outputWriter + } else { + cmd.Stdout = logWriter + } + cmd.Stderr = logWriter + + if err := cmd.Run(); err != nil { + return fmt.Errorf("lottieconverter error: %w", err) + } + return nil +}