ES-DE/external/rlottie/example/lottie2gif.cpp

179 lines
4.8 KiB
C++

#include "gif.h"
#include <rlottie.h>
#include<iostream>
#include<string>
#include<vector>
#include<array>
#ifndef _WIN32
#include<libgen.h>
#else
#include <windows.h>
#include <stdlib.h>
#endif
class GifBuilder {
public:
explicit GifBuilder(const std::string &fileName , const uint32_t width,
const uint32_t height, const int bgColor=0xffffffff, const uint32_t delay = 2)
{
GifBegin(&handle, fileName.c_str(), width, height, delay);
bgColorR = (uint8_t) ((bgColor & 0xff0000) >> 16);
bgColorG = (uint8_t) ((bgColor & 0x00ff00) >> 8);
bgColorB = (uint8_t) ((bgColor & 0x0000ff));
}
~GifBuilder()
{
GifEnd(&handle);
}
void addFrame(rlottie::Surface &s, uint32_t delay = 2)
{
argbTorgba(s);
GifWriteFrame(&handle,
reinterpret_cast<uint8_t *>(s.buffer()),
s.width(),
s.height(),
delay);
}
void argbTorgba(rlottie::Surface &s)
{
uint8_t *buffer = reinterpret_cast<uint8_t *>(s.buffer());
uint32_t totalBytes = s.height() * s.bytesPerLine();
for (uint32_t i = 0; i < totalBytes; i += 4) {
unsigned char a = buffer[i+3];
// compute only if alpha is non zero
if (a) {
unsigned char r = buffer[i+2];
unsigned char g = buffer[i+1];
unsigned char b = buffer[i];
if (a != 255) { //un premultiply
unsigned char r2 = (unsigned char) ((float) bgColorR * ((float) (255 - a) / 255));
unsigned char g2 = (unsigned char) ((float) bgColorG * ((float) (255 - a) / 255));
unsigned char b2 = (unsigned char) ((float) bgColorB * ((float) (255 - a) / 255));
buffer[i] = r + r2;
buffer[i+1] = g + g2;
buffer[i+2] = b + b2;
} else {
// only swizzle r and b
buffer[i] = r;
buffer[i+2] = b;
}
} else {
buffer[i+2] = bgColorB;
buffer[i+1] = bgColorG;
buffer[i] = bgColorR;
}
}
}
private:
GifWriter handle;
uint8_t bgColorR, bgColorG, bgColorB;
};
class App {
public:
int render(uint32_t w, uint32_t h)
{
auto player = rlottie::Animation::loadFromFile(fileName);
if (!player) return help();
auto buffer = std::unique_ptr<uint32_t[]>(new uint32_t[w * h]);
size_t frameCount = player->totalFrame();
GifBuilder builder(gifName.data(), w, h, bgColor);
for (size_t i = 0; i < frameCount ; i++) {
rlottie::Surface surface(buffer.get(), w, h, w * 4);
player->renderSync(i, surface);
builder.addFrame(surface);
}
return result();
}
int setup(int argc, char **argv, size_t *width, size_t *height)
{
char *path{nullptr};
*width = *height = 200; //default gif size
if (argc > 1) path = argv[1];
if (argc > 2) {
char tmp[20];
char *x = strstr(argv[2], "x");
if (x) {
snprintf(tmp, x - argv[2] + 1, "%s", argv[2]);
*width = atoi(tmp);
snprintf(tmp, sizeof(tmp), "%s", x + 1);
*height = atoi(tmp);
}
}
if (argc > 3) bgColor = strtol(argv[3], NULL, 16);
if (!path) return help();
std::array<char, 5000> memory;
#ifdef _WIN32
path = _fullpath(memory.data(), path, memory.size());
#else
path = realpath(path, memory.data());
#endif
if (!path) return help();
fileName = std::string(path);
if (!jsonFile()) return help();
gifName = basename(fileName);
gifName.append(".gif");
return 0;
}
private:
std::string basename(const std::string &str)
{
return str.substr(str.find_last_of("/\\") + 1);
}
bool jsonFile() {
std::string extn = ".json";
if ( fileName.size() <= extn.size() ||
fileName.substr(fileName.size()- extn.size()) != extn )
return false;
return true;
}
int result() {
std::cout<<"Generated GIF file : "<<gifName<<std::endl;
return 0;
}
int help() {
std::cout<<"Usage: \n lottie2gif [lottieFileName] [Resolution] [bgColor]\n\nExamples: \n $ lottie2gif input.json\n $ lottie2gif input.json 200x200\n $ lottie2gif input.json 200x200 ff00ff\n\n";
return 1;
}
private:
int bgColor = 0xffffffff;
std::string fileName;
std::string gifName;
};
int
main(int argc, char **argv)
{
App app;
size_t w, h;
if (app.setup(argc, argv, &w, &h)) return 1;
app.render(w, h);
return 0;
}