Skip to content

Instantly share code, notes, and snippets.

@vtorri
Last active March 22, 2026 12:57
Show Gist options
  • Select an option

  • Save vtorri/af7db9193a5c90c43fabfc7b9a8e7ac3 to your computer and use it in GitHub Desktop.

Select an option

Save vtorri/af7db9193a5c90c43fabfc7b9a8e7ac3 to your computer and use it in GitHub Desktop.
example of usage of ThorVG for lottie files with the EFL
/* gcc -g -Wall -Wextra -o efl_lot efl_lot.c `pkgconf --cflags --libs eina ecore evas ecore-evas thorvg-1` */
#include <stdio.h>
//#include <windows.h>
#include <Eina.h>
#include <Ecore.h>
#include <Evas.h>
#include <Ecore_Evas.h>
#include <thorvg_capi.h>
typedef struct
{
Evas_Object *o;
Tvg_Canvas canvas;
Tvg_Animation animation;
unsigned int *pixels;
float total;
float duration;
int current;
} Data;
static Ecore_Timer *timer;
static Eina_Bool
_anim_cb(void *data)
{
Data *d = data;
int w;
int h;
d->current++;
if (d->current > d->total)
d->current = 0;
tvg_animation_set_frame(d->animation, d->current);
tvg_canvas_update(d->canvas);
tvg_canvas_draw(d->canvas, true); // true or false ??
tvg_canvas_sync(d->canvas);
evas_object_image_data_set(d->o, d->pixels);
evas_object_geometry_get(d->o, NULL, NULL, &w, &h);
evas_object_image_data_update_add(d->o, 0, 0, w, h);
return ECORE_CALLBACK_RENEW;
}
static void _quit(Ecore_Evas *ee)
{
ecore_main_loop_quit();
(void)ee;
}
int main(int argc, char *argv[])
{
Ecore_Evas *ee;
Evas *evas;
Evas_Object *o;
int w,h;
Evas_Load_Error err;
Tvg_Result res;
Tvg_Canvas canvas;
unsigned int *pixels;
if (argc < 2)
{
printf("Usage: %s file.json\n", argv[0]);
fflush(stdout);
return 1;
}
///// ThorVG
// init: number of threads: 4
res = tvg_engine_init(4);
if (res != TVG_RESULT_SUCCESS)
{
printf("no thorvg\n");
return 0;
}
// canvas - software
canvas = tvg_swcanvas_create(TVG_ENGINE_OPTION_DEFAULT);
// animation for Lottie file
Tvg_Animation animation = tvg_animation_new();
if (!animation)
{
printf("can not create animation\n");
return 0;
}
// load Lottie file
Tvg_Paint pict = tvg_animation_get_picture(animation);
res = tvg_picture_load(pict, argv[1]);
if (res != TVG_RESULT_SUCCESS)
{
tvg_animation_del(animation);
printf("no lottie file\n");
return 0;
}
// get Lottie file size
float width, height;
tvg_picture_get_size(pict, &width, &height);
// set half size
w = width / 2;
h = height / 2;
tvg_picture_set_size(pict, w, h);
//tvg_paint_scale(pict, 0.75f);
// add picture to the canvas
tvg_canvas_add(canvas, pict);
//////// EFL
ecore_evas_init();
ee = ecore_evas_new(NULL, 0, 0, 1, 1, NULL);
if (!ee)
{
printf("no ee\n");
return 0;
}
evas = ecore_evas_get(ee);
ecore_evas_title_set(ee, "thorVG Lottie");
ecore_evas_callback_delete_request_set(ee, _quit);
o = evas_object_rectangle_add(evas);
evas_object_move(o, 0, 0);
evas_object_resize(o, w, h);
evas_object_color_set(o, 255, 0, 0, 255);
evas_object_show(o);
o = evas_object_image_filled_add(evas);
evas_object_image_alpha_set(o, EINA_TRUE);
evas_object_image_size_set(o, w, h);
pixels = evas_object_image_data_get(o, EINA_TRUE);
//evas_object_image_pixels_dirty_set(o, EINA_TRUE);
evas_object_move(o, 0, 0);
evas_object_resize(o, w, h);
evas_object_show(o);
// set pixels to write to in tvg canvas
tvg_swcanvas_set_target(canvas, (uint32_t*)pixels, w, w, h, TVG_COLORSPACE_ARGB8888S);
float duration, total;
tvg_animation_get_duration(animation, &duration);
tvg_animation_get_total_frame(animation, &total);
Data data;
data.total = total;
data.duration = duration;
data.canvas = canvas;
data.current = 0;
data.pixels = pixels;
data.animation = animation;
data.o = o;
timer = ecore_timer_add(duration / total, _anim_cb, &data);
evas_object_image_data_set(o, pixels);
evas_object_image_data_update_add(o, 0, 0, w, h);
ecore_evas_resize(ee, w, h);
ecore_evas_show(ee);
ecore_main_loop_begin();
tvg_animation_del(animation);
tvg_canvas_destroy(canvas);
tvg_engine_term();
ecore_evas_shutdown();
return 0;
}
@hermet
Copy link
Copy Markdown

hermet commented Mar 22, 2026

int main(int argc, char *argv[])
{
...
data.begin_time = ecore_time_get(); //capture the begin time
...
}

_anim_cb()
{
...
float current_time = (float) ecore_time_get();
d->progress = (current_time - data.begin_time) / data.duration ; //get the animation progress
if (progresss > 1) progress -= 1.0f; //repeat
tvg_animation_set_frame(d->animation, d->progress ;
...
}

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