Skip to content

Instantly share code, notes, and snippets.

@SneakyWhoami
Last active November 12, 2021 10:54
Show Gist options
  • Save SneakyWhoami/79c553f66502e2369d3673095585a3f5 to your computer and use it in GitHub Desktop.
Save SneakyWhoami/79c553f66502e2369d3673095585a3f5 to your computer and use it in GitHub Desktop.
lottie thumbnailer
cmake_minimum_required(VERSION 3.0)
project(lottiethumb)
list(APPEND CMAKE_PREFIX_PATH "/usr/share/quazip")
set(CMAKE_CXX_STANDARD 14)
find_package(rlottie REQUIRED)
find_package(Qt5 COMPONENTS Gui REQUIRED)
find_package(QuaZip5 REQUIRED)
include_directories(${QUAZIP_INCLUDE_DIRS})
add_executable(lottiethumb main.cpp)
target_link_libraries(lottiethumb rlottie Qt5::Gui ${QUAZIP_LIBRARIES})
#include <iostream>
#include <rlottie.h>
#include <QImage>
#include <quagzipfile.h>
#include <QDebug>
#include <cmath>
int main(int argc, char **argv)
{
// help text stuff start
// if you delete this test, you can hardcode default in/out filenames
if (argc < 3) {
std::cout << "Usage: " << argv[0] << "<infilename.json> <outfilename.webp> [width] [height] [percentage]\n"
<< "Create a thumbnail for infilename.json at outfilename.webp, of size [width] pixels by [height] pixels.\n"
<< "Optionally, create the thumbnail on the frame at the [percentage] playback progress mark.\n"
<< "Output file format is determined by output filename and installed QImageCodecs.\n";
exit(2);
}
// help text stuff end, defaults start
QString inName = argc > 1 ? argv[1] : "/tmp/AnimatedSticker.tgs";
QString outName = argc > 2 ? argv[2] : "/tmp/stick.webp";
int width = argc > 3 ? atoi(argv[3]) : 512;
width = width > 0 ? width : 512;
int height = argc > 4 ? atoi(argv[4]) : 512;
height = height > 0 ? height : 512;
double selected = argc > 5 ? atoi(argv[5]) : 80;
selected = fmod(selected, 100);
selected = selected > 0 ? selected : 80;
selected = 100 / selected;
// defaults end, business logic start
QuaGzipFile lottiefile(inName);
lottiefile.open(QIODevice::ReadOnly);
// This format is the default used by rlottie anyway
QImage pic(width, height, QImage::Format_ARGB32_Premultiplied);
// rlottie can render to a surface if it looks liek this
auto buffer = std::make_unique<uint32_t[]>(width * height);
// so we load the animation (the input file)
auto animation = rlottie::Animation::loadFromData(lottiefile.readAll().toStdString(), inName.toStdString());
// then we load up our frame from the animation into buffer...
rlottie::Surface surface(buffer.get(), width, height, width * 4);
animation->renderSync((animation->totalFrame() / selected), surface);
// give it a gentle massage to get it into QImage
for (int i = 0; i < width * height; i++) {
if (buffer.get()[i]) {
pic.setPixelColor(i % width, i / height, QColor(buffer.get()[i]));
} else {
// an int value of straight-up "0" is our transparent (background) colour
pic.setPixelColor(i % width, i / height, QColor(0, 0, 0, 0));
}
}
// Qt will magically spit out whatever image format is implied by the file extension
if (pic.save(outName)) {
return 0;
} else {
return 1;
}
}
@SneakyWhoami
Copy link
Author

SneakyWhoami commented Nov 6, 2021

Probably you shouldn't use this. I mostly wrote it by accident. You're probably much better off with lottie_convert.py from https://pypi.org/project/lottie/

Here's why:

  • supports all the functionality that my program does
  • also can do animated conversions (eg to animated gif)

and if you really want some variety, I am very impressed by

Having said that, if you find this useful, COOL! And if you have fixes (like error handling for when someone passes wrong command line arguments, or better arg parsing altogether, or... idk, sky's the limit, right?) then sure, fork or comment and maybe someone will find it useful.

@SneakyWhoami
Copy link
Author

SneakyWhoami commented Nov 6, 2021

oh yeah, while i have the tab open, consider this public domain. at your option you can license and sublicense under wtfpl, expat, cc0, whatever you want. there aint much in it, so it's provided only in the hope that it is useful

@SneakyWhoami
Copy link
Author

Very crashable :) I don't check for sanity on any of the files going in (right now) so you can pass in a malformed file and get a segfault. Just heads-up in case I don't come back and fix it up

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment