From 5994df7f048492b234c2827cf9a7e313b356c6b8 Mon Sep 17 00:00:00 2001 From: Dave Davenport Date: Sun, 18 Oct 2020 21:37:05 +0200 Subject: [PATCH] [IconLoader] add optional gif loader. --- Makefile.am | 1 + configure.ac | 31 ++++++++++++++++ meson.build | 4 ++ source/dialogs/filebrowser.c | 11 +++++- source/rofi-icon-fetcher.c | 71 +++++++++++++++++++++++++++++++++++- 5 files changed, 115 insertions(+), 3 deletions(-) diff --git a/Makefile.am b/Makefile.am index 6d1fa925..d979dba8 100644 --- a/Makefile.am +++ b/Makefile.am @@ -168,6 +168,7 @@ rofi_LDADD=\ $(cairo_LIBS)\ $(librsvg_LIBS)\ $(libjpeg_LIBS)\ + $(libgif_LIBS)\ $(LIBS) ## diff --git a/configure.ac b/configure.ac index f05ee356..bb9ac057 100644 --- a/configure.ac +++ b/configure.ac @@ -165,7 +165,38 @@ dnl Gets the resource compile tool path. dnl --------------------------------------------------------------------- AM_PATH_GLIB_2_0 +dnl Test for libgif or libungif +AC_ARG_WITH([libgif], + AS_HELP_STRING([--with-libgif=PREFIX], + [Prefix where libgif is installed, or 'no' to disable]), + [libgif_prefix="$withval"], [libgif_prefix="${prefix}"]) + if test x$with_libgif != xno && test -z "$libgif_LIBS"; then + GIF_CFLAGS="-I${libgif_prefix}/include" + GIF_LIBS="-L${libgif_prefix}/lib" + save_cflags=$CFLAGS; CFLAGS=$GIF_CFLAGS + save_libs=$LIBS; LIBS=$GIF_LIBS + AC_CHECK_LIB(gif, DGifOpenFileName, + [AC_CHECK_HEADER(gif_lib.h, + GIF='gif'; libgif_LIBS='-lgif'; gif_ok=yes, + AC_MSG_WARN(*** GIF loader will not be built (giflibrary not found) ***))], + AC_MSG_WARN(*** GIF loader will not be built (giflibrary not found) ***)) + + AC_CHECK_LIB(ungif, DGifOpenFileName, + [AC_CHECK_HEADER(gif_lib.h, + GIF='ungif'; libgif_LIBS='-lungif'; gif_ok=yes, + AC_MSG_WARN(*** GIF loader will not be built (ungiflibrary not found) ***))], + AC_MSG_WARN(*** GIF loader will not be built (ungiflibrary not found) ***)) + CFLAGS+=$save_cflags + LIBS+=$save_libs + fi + +if test x$GIF != x; then + AC_SUBST(libgif_LIBS) + AC_DEFINE(HAVE_LIBGIF, 1, Define if gif support is available) +else + gif_ok="no (See http://sourceforge.net/projects/libgif)" +fi dnl --------------------------------------------------------------------- dnl Add extra compiler flags dnl --------------------------------------------------------------------- diff --git a/meson.build b/meson.build index d220b030..09335107 100644 --- a/meson.build +++ b/meson.build @@ -69,6 +69,9 @@ deps += [ dependency('libstartup-notification-1.0'), ] +libgif = c_compiler.find_library('libgif', required: false) +deps += [ libgif ] + check = dependency('check', version: '>= 0.11.0', required: get_option('check')) header_conf = configuration_data() @@ -88,6 +91,7 @@ header_conf.set('GLIB_VERSION_MIN_REQUIRED', '(G_ENCODE_VERSION(@0@,@1@))'.forma header_conf.set('GLIB_VERSION_MAX_ALLOWED', '(G_ENCODE_VERSION(@0@,@1@))'.format(glib_min_major, glib_min_minor)) header_conf.set('ENABLE_DRUN', get_option('drun')) +header_conf.set('HAVE_LIBGIF', libgif.found()) header_conf.set('WINDOW_MODE', get_option('window')) header_conf.set_quoted('MANPAGE_PATH', join_paths(get_option('prefix'), get_option('mandir'))) diff --git a/source/dialogs/filebrowser.c b/source/dialogs/filebrowser.c index 201d1ac7..426e3127 100644 --- a/source/dialogs/filebrowser.c +++ b/source/dialogs/filebrowser.c @@ -35,6 +35,9 @@ #include #include + +#include + #include "mode.h" #include "helper.h" #include "mode-private.h" @@ -341,7 +344,11 @@ static int file_browser_token_match ( const Mode *sw, rofi_int_matcher **tokens, } -const char * const image_exts[] = {".png",".PNG",".jpg",".JPG",".jpeg",".JPEG",".svg",".SVG"}; +const char * const image_exts[] = {".png",".PNG",".jpg",".JPG",".jpeg",".JPEG",".svg",".SVG" +#ifdef HAVE_LIBGIF + ,".gif",".GIF" +#endif +}; static gboolean file_browser_is_image ( const char * const path ) { if ( path == NULL ) { @@ -351,7 +358,7 @@ static gboolean file_browser_is_image ( const char * const path ) if ( suf == NULL ) { return FALSE; } - for ( uint32_t i = 0; i < (sizeof (image_exts)/sizeof(char*)); i++ ) { + for ( uint32_t i = 0; i < G_N_ELEMENTS(image_exts); i++ ) { if ( g_strcmp0(suf,image_exts[i]) == 0 ) { return TRUE; } diff --git a/source/rofi-icon-fetcher.c b/source/rofi-icon-fetcher.c index e718d19d..f0216473 100644 --- a/source/rofi-icon-fetcher.c +++ b/source/rofi-icon-fetcher.c @@ -28,6 +28,7 @@ /** The log domain of this Helper. */ #define G_LOG_DOMAIN "Helpers.IconFetcher" + #include "rofi-icon-fetcher.h" #include "rofi-types.h" #include "helper.h" @@ -44,6 +45,7 @@ #include +#include typedef struct { // Context for icon-themes. @@ -187,7 +189,7 @@ static void jpegErrorExit (j_common_ptr cinfo) /* Create the message */ ( *(cinfo->err->format_message) ) (cinfo, jpegLastErrorMsg); - g_warning ( jpegLastErrorMsg ); + g_warning ( jpegLastErrorMsg, NULL ); /* Jump to the setjmp point */ longjmp(myerr->setjmp_buffer, 1); @@ -224,6 +226,68 @@ static cairo_surface_t* cairo_image_surface_create_from_jpeg ( const char* file return surface; } +#ifdef HAVE_LIBGIF +#include + +static cairo_surface_t* cairo_image_surface_create_from_gif(const char* file ) +{ + cairo_surface_t* img = NULL; + + int err; + GifFileType* gif = DGifOpenFileName(file, &err); + if (!gif) { + g_warning( "[%i] %s", err, GifErrorString(err)); + return NULL; + } + + // decode with high-level API + if (DGifSlurp(gif) != GIF_OK) { + g_warning("Decoder error: %s", GifErrorString(gif->Error)); + goto done; + } + if (!gif->SavedImages) { + g_warning("No saved images"); + goto done; + } + + // create canvas + img = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, gif->SWidth, gif->SHeight); + if (cairo_surface_status(img) != CAIRO_STATUS_SUCCESS) { + g_warning("Unable to create surface: %s", + cairo_status_to_string(cairo_surface_status(img))); + cairo_surface_destroy(img); + img = NULL; + goto done; + } + + // we don't support animation, show the first frame only + const GifImageDesc* frame = &gif->SavedImages->ImageDesc; + const GifColorType* colors = gif->SColorMap ? gif->SColorMap->Colors : + frame->ColorMap->Colors; + uint32_t* base = (uint32_t*)(cairo_image_surface_get_data(img) + + frame->Top * cairo_image_surface_get_stride(img)); + for (int y = 0; y < frame->Height; ++y) { + uint32_t* pixel = base + y * gif->SWidth + frame->Left; + const uint8_t* raster = &gif->SavedImages->RasterBits[y * gif->SWidth]; + for (int x = 0; x < frame->Width; ++x) { + const uint8_t color = raster[x]; + if (color != gif->SBackGroundColor) { + const GifColorType* rgb = &colors[color]; + *pixel = 0xff000000 | + rgb->Red << 16 | rgb->Green << 8 | rgb->Blue; + } + ++pixel; + } + } + + cairo_surface_mark_dirty(img); + +done: + DGifCloseFile(gif, NULL); + return img; +} +#endif + static void rofi_icon_fetcher_worker ( thread_state *sdata, G_GNUC_UNUSED gpointer user_data ) { g_debug ( "starting up icon fetching thread." ); @@ -255,6 +319,11 @@ static void rofi_icon_fetcher_worker ( thread_state *sdata, G_GNUC_UNUSED gpoint if ( g_str_has_suffix ( icon_path, ".png" ) || g_str_has_suffix ( icon_path, ".PNG" ) ) { icon_surf = cairo_image_surface_create_from_png ( icon_path ); } +#ifdef HAVE_LIBGIF + else if ( g_str_has_suffix ( icon_path, ".gif" ) || g_str_has_suffix ( icon_path, ".GIF" ) ) { + icon_surf = cairo_image_surface_create_from_gif ( icon_path ); + } +#endif else if ( g_str_has_suffix ( icon_path, ".jpeg" ) || g_str_has_suffix ( icon_path, ".jpg" ) || g_str_has_suffix ( icon_path, ".JPEG" ) || g_str_has_suffix ( icon_path, ".JPG" ) ) {