From 8b3ae5027e9490bd7edfeea3d3cd2fbc5ec4beaf Mon Sep 17 00:00:00 2001 From: Bert Date: Thu, 18 Aug 2011 16:05:32 +0200 Subject: Added support for gif animation --- commands.c | 3 +- config.h | 7 +++++ image.c | 104 ++++++++++++++++++++++++++++++++++++++++++++----------------- image.h | 13 ++++++-- main.c | 20 ++++++++++-- util.c | 13 ++++++++ util.h | 2 ++ 7 files changed, 126 insertions(+), 36 deletions(-) diff --git a/commands.c b/commands.c index 50a3c2b..b0f7b08 100644 --- a/commands.c +++ b/commands.c @@ -41,6 +41,7 @@ extern int filecnt, fileidx; extern int timo_cursor; extern int timo_redraw; +extern int timo_delay; int it_quit(arg_t a) { cleanup(); @@ -148,7 +149,7 @@ int it_last(arg_t a) { } int i_navigate_frame(arg_t a) { - return img_change_frame(&img, (int) a); + return img_frame_navigate(&img, (int) a); } int it_move(arg_t a) { diff --git a/config.h b/config.h index a55ea18..07371c9 100644 --- a/config.h +++ b/config.h @@ -29,6 +29,13 @@ static const float zoom_levels[] = { 100.0, 150.0, 200.0, 400.0, 800.0 }; +/* default settings for gif images: */ +enum { + GIF_DELAY = 100, /* delay time (in ms) */ + GIF_AUTOPLAY = 1, /* autoplay when loaded [0/1] */ + GIF_LOOP = 0 /* endless loop [0/1] */ +}; + #endif #ifdef _THUMBS_CONFIG diff --git a/image.c b/image.c index 7c610a6..178ace3 100644 --- a/image.c +++ b/image.c @@ -32,6 +32,8 @@ #include "util.h" #include "config.h" +enum { MIN_GIF_DELAY = 50 }; + int zl_cnt; float zoom_min; float zoom_max; @@ -44,6 +46,7 @@ void img_init(img_t *img, win_t *win) { if (img) { img->im = NULL; img->multi.cap = img->multi.cnt = 0; + img->multi.animate = 0; img->zoom = options->zoom; img->zoom = MAX(img->zoom, zoom_min); img->zoom = MIN(img->zoom, zoom_max); @@ -72,11 +75,12 @@ int img_load_gif(img_t *img, const fileinfo_t *file) { int intoffset[] = { 0, 4, 2, 1 }; int intjump[] = { 8, 8, 4, 2 }; int err = 0, transp = -1; + unsigned int delay = 0; if (img->multi.cap == 0) { img->multi.cap = 8; - img->multi.frames = (Imlib_Image**) - s_malloc(sizeof(Imlib_Image*) * img->multi.cap); + img->multi.frames = (img_frame_t*) + s_malloc(sizeof(img_frame_t) * img->multi.cap); } img->multi.cnt = 0; img->multi.sel = 0; @@ -107,6 +111,10 @@ int img_load_gif(img_t *img, const fileinfo_t *file) { transp = (int) ext[4]; else transp = -1; + + delay = 10 * ((unsigned int) ext[3] << 8 | (unsigned int) ext[2]); + if (delay) + delay = MAX(delay, MIN_GIF_DELAY); } ext = NULL; DGifGetExtensionNext(gif, &ext); @@ -186,11 +194,13 @@ int img_load_gif(img_t *img, const fileinfo_t *file) { if (img->multi.cnt == img->multi.cap) { img->multi.cap *= 2; - img->multi.frames = (Imlib_Image**) + img->multi.frames = (img_frame_t*) s_realloc(img->multi.frames, - img->multi.cap * sizeof(Imlib_Image*)); + img->multi.cap * sizeof(img_frame_t)); } - img->multi.frames[img->multi.cnt++] = im; + img->multi.frames[img->multi.cnt].im = im; + img->multi.frames[img->multi.cnt].delay = delay ? delay : GIF_DELAY; + img->multi.cnt++; } } while (rec != TERMINATE_RECORD_TYPE); @@ -199,13 +209,15 @@ int img_load_gif(img_t *img, const fileinfo_t *file) { if (!err && img->multi.cnt > 1) { imlib_context_set_image(img->im); imlib_free_image(); - img->im = img->multi.frames[0]; + img->im = img->multi.frames[0].im; + img->multi.animate = GIF_AUTOPLAY; } else { for (i = 0; i < img->multi.cnt; i++) { - imlib_context_set_image(img->multi.frames[i]); + imlib_context_set_image(img->multi.frames[i].im); imlib_free_image(); } img->multi.cnt = 0; + img->multi.animate = 0; } imlib_context_set_image(img->im); @@ -256,7 +268,7 @@ void img_close(img_t *img, int decache) { if (img->multi.cnt) { for (i = 0; i < img->multi.cnt; i++) { - imlib_context_set_image(img->multi.frames[i]); + imlib_context_set_image(img->multi.frames[i].im); imlib_free_image(); } img->multi.cnt = 0; @@ -378,27 +390,6 @@ void img_render(img_t *img, win_t *win) { win_draw(win); } -int img_change_frame(img_t *img, int d) { - if (!img || !img->multi.cnt || !d) - return 0; - - d += img->multi.sel; - if (d < 0) - d = 0; - else if (d >= img->multi.cnt) - d = img->multi.cnt - 1; - - img->multi.sel = d; - img->im = img->multi.frames[d]; - - imlib_context_set_image(img->im); - img->w = imlib_image_get_width(); - img->h = imlib_image_get_height(); - img->checkpan = 1; - - return 1; -} - int img_fit_win(img_t *img, win_t *win) { if (!img || !img->im || !win) return 0; @@ -569,3 +560,58 @@ void img_toggle_antialias(img_t *img) { imlib_context_set_anti_alias(img->aa); } } + +int img_frame_goto(img_t *img, int n) { + if (!img || n < 0 || n >= img->multi.cnt) + return 0; + + if (n == img->multi.sel) + return 0; + + img->multi.sel = n; + img->im = img->multi.frames[n].im; + + imlib_context_set_image(img->im); + img->w = imlib_image_get_width(); + img->h = imlib_image_get_height(); + img->checkpan = 1; + + return 1; +} + +int img_frame_navigate(img_t *img, int d) { + if (!img || !img->multi.cnt || !d) + return 0; + + d += img->multi.sel; + if (d < 0) + d = 0; + else if (d >= img->multi.cnt) + d = img->multi.cnt - 1; + + return img_frame_goto(img, d); +} + +int img_frame_animate(img_t *img, int restart) { + if (!img || !img->multi.cnt) + return 0; + + if (!img->multi.animate && !restart) + return 0; + + if (restart) { + img_frame_goto(img, 0); + img->multi.animate = 1; + } else if (img->multi.sel + 1 >= img->multi.cnt) { + if (!GIF_LOOP) { + img->multi.animate = 0; + return 0; + } else { + img_frame_goto(img, 0); + } + } else { + img_frame_goto(img, img->multi.sel + 1); + } + + return img->multi.frames[img->multi.sel].delay; +} diff --git a/image.h b/image.h index 408992e..cf50718 100644 --- a/image.h +++ b/image.h @@ -25,10 +25,16 @@ #include "window.h" typedef struct { + Imlib_Image *im; + unsigned int delay; +} img_frame_t; + +typedef struct { + img_frame_t *frames; int cap; int cnt; int sel; - Imlib_Image **frames; + unsigned char animate; } multi_img_t; typedef struct { @@ -56,8 +62,6 @@ void img_close(img_t*, int); void img_render(img_t*, win_t*); -int img_change_frame(img_t*, int); - int img_fit_win(img_t*, win_t*); int img_center(img_t*, win_t*); @@ -74,4 +78,7 @@ void img_rotate_right(img_t*, win_t*); void img_toggle_antialias(img_t*); +int img_frame_navigate(img_t*, int); +int img_frame_animate(img_t*, int); + #endif /* IMAGE_H */ diff --git a/main.c b/main.c index 27788db..3e2f353 100644 --- a/main.c +++ b/main.c @@ -54,6 +54,7 @@ char win_title[TITLE_LEN]; int timo_cursor; int timo_redraw; +int timo_adelay; /* multi-frame animation delay time */ void cleanup() { static int in = 0; @@ -140,6 +141,9 @@ void load_image(int new) { filesize = fstats.st_size; else filesize = 0; + + if (img.multi.cnt && img.multi.animate) + timo_adelay = img.multi.frames[img.multi.sel].delay; } void update_title() { @@ -296,10 +300,12 @@ void run() { } else { timo_redraw = TO_THUMBS_LOAD; } - } else if (timo_cursor || timo_redraw) { + } + + if (timo_cursor || timo_redraw || timo_adelay) { /* check active timeouts */ gettimeofday(&t0, 0); - timeout = MIN(timo_cursor + 1, timo_redraw + 1); + timeout = min_int_nz(3, timo_cursor, timo_redraw, timo_adelay); MSEC_TO_TIMEVAL(timeout, &tt); xfd = ConnectionNumber(win.env.dpy); FD_ZERO(&fds); @@ -321,7 +327,15 @@ void run() { if (!timo_redraw) redraw(); } - if ((timo_cursor || timo_redraw) && !XPending(win.env.dpy)) + if (timo_adelay) { + timo_adelay = MAX(0, timo_adelay - timeout); + if (!timo_adelay) { + if ((timo_adelay = img_frame_animate(&img, 0))) + redraw(); + } + } + if ((timo_cursor || timo_redraw || timo_adelay) && + !XPending(win.env.dpy)) continue; } diff --git a/util.c b/util.c index 0c4574e..5bed511 100644 --- a/util.c +++ b/util.c @@ -87,6 +87,19 @@ void die(const char* fmt, ...) { exit(1); } +int min_int_nz(int n, ...) { + va_list args; + int i, a, m = 0; + + va_start(args, n); + for (i = 0; i < n; i++) { + if ((a = va_arg(args, int)) && (!m || a < m)) + m = a; + } + va_end(args); + return m; +} + void size_readable(float *size, const char **unit) { const char *units[] = { "", "K", "M", "G" }; int i; diff --git a/util.h b/util.h index e0d28c0..a891054 100644 --- a/util.h +++ b/util.h @@ -60,6 +60,8 @@ char* s_strdup(char*); void warn(const char*, ...); void die(const char*, ...); +int min_int_nz(int, ...); + void size_readable(float*, const char**); char* absolute_path(const char*); -- cgit v1.2.3-54-g00ecf