From 45cf096d873ad0f24e3f42ce6e5f3083970d925f Mon Sep 17 00:00:00 2001 From: Colin Clark Date: Mon, 10 May 2021 12:03:22 +0100 Subject: [PATCH] Part fix #891: Application crashes while viewing CR3 thumbnails https://github.com/BestImageViewer/geeqie/issues/891 Use LibRaw to extract preview images from .cr3 files (or any raw files not recognized by exiv2). --- README.md | 3 + configure.ac | 28 ++++++- doxygen.conf | 1 + src/Makefile.am | 4 +- src/image-load.c | 38 ++++++++- src/image-load.h | 8 +- src/image_load_libraw.c | 149 +++++++++++++++++++++++++++++++++++ src/image_load_libraw.h | 29 +++++++ web/geeqie-install-debian.sh | 4 +- 9 files changed, 257 insertions(+), 7 deletions(-) create mode 100644 src/image_load_libraw.c create mode 100644 src/image_load_libraw.h diff --git a/README.md b/README.md index 7f06060e..4ef910ce 100644 --- a/README.md +++ b/README.md @@ -266,6 +266,9 @@ And either the ChangeLog file or [Geeqie ChangeLog](http://geeqie.org/cgi-bin/gi libopenjp2 For displaying JP2 images + libraw 0.20 + For displaying CR3 images + yelp-tools For creating the Help files diff --git a/configure.ac b/configure.ac index ba7dca77..799128bc 100644 --- a/configure.ac +++ b/configure.ac @@ -368,6 +368,31 @@ AM_CONDITIONAL(HAVE_TIFF, [test "x$HAVE_TIFF" = xyes]) AC_SUBST(TIFF_CFLAGS) AC_SUBST(TIFF_LIBS) +# libraw support +# ---------------------------------------------------------------------- + +AC_ARG_ENABLE([raw], + AC_HELP_STRING([--disable-raw], [disable LibRaw support]), + [libraw=$enableval], [libraw=auto]) + +if test "x${libraw}" != "xno"; then + PKG_CHECK_MODULES(RAW, [libraw >= 0.20], + [ + HAVE_RAW=yes + AC_DEFINE(HAVE_RAW, 1, [define to enable libraw support]) + ], + [ + HAVE_RAW=no + AC_MSG_WARN([$RAW_PKG_ERRORS]) + ]) +else + HAVE_RAW=disabled +fi + +AM_CONDITIONAL(HAVE_RAW, [test "x$HAVE_RAW" = xyes]) +AC_SUBST(RAW_CFLAGS) +AC_SUBST(RAW_LIBS) + # libffmpegthumbnailer support # ---------------------------------------------------------------------- @@ -784,7 +809,7 @@ Flags: Gtk: $GTK_CFLAGS Glib: $GLIB_CFLAGS Thread: $GTHREAD_LIBS - Others: $JPEG_LIBS $TIFF_LIBS $LCMS_LIBS $EXIV2_LIBS $CLUTTER_LIBS $CLUTTER_GTK_LIBS $LIBCHAMPLAIN_LIBS $LIBCHAMPLAIN_GTK_LIBS $LUA_LIBS + Others: $JPEG_LIBS $TIFF_LIBS $LCMS_LIBS $EXIV2_LIBS $CLUTTER_LIBS $CLUTTER_GTK_LIBS $LIBCHAMPLAIN_LIBS $LIBCHAMPLAIN_GTK_LIBS $LUA_LIBS $RAW_LIBS Localization: NLS support: $USE_NLS @@ -810,6 +835,7 @@ Support: WebP: $HAVE_WEBP DjVu: $HAVE_DJVU J2K: $HAVE_J2K + LibRaw: $HAVE_RAW Documentation: Doxygen: $DX_DOXYGEN diff --git a/doxygen.conf b/doxygen.conf index e4d2b2e4..d952f4bc 100644 --- a/doxygen.conf +++ b/doxygen.conf @@ -2111,6 +2111,7 @@ PREDEFINED = HAVE_CLUTTER=1 \ HAVE_LIRC=1 \ HAVE_LUA=1 \ HAVE_PDF=1 \ + HAVE_RAW=1 \ HAVE_TIFF=1 \ HAVE_WEBP=1 diff --git a/src/Makefile.am b/src/Makefile.am index 64e4d61b..bff64e13 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -205,6 +205,8 @@ geeqie_SOURCES = \ image_load_psd.h\ image_load_j2k.c\ image_load_j2k.h\ + image_load_libraw.c\ + image_load_libraw.h\ image_load_svgz.c\ image_load_svgz.h\ image_load_ffmpegthumbnailer.c\ @@ -299,7 +301,7 @@ geeqie_SOURCES = \ zonedetect.c \ zonedetect.h -geeqie_LDADD = $(GTK_LIBS) $(GLIB_LIBS) $(INTLLIBS) $(JPEG_LIBS) $(TIFF_LIBS) $(LCMS_LIBS) $(EXIV2_LIBS) $(LIBCHAMPLAIN_LIBS) $(LIBCHAMPLAIN_GTK_LIBS) $(LUA_LIBS) $(CLUTTER_LIBS) $(CLUTTER_GTK_LIBS) $(FFMPEGTHUMBNAILER_LIBS) $(PDF_LIBS) $(HEIF_LIBS) $(WEBP_LIBS) $(DJVU_LIBS) $(J2K_LIBS) +geeqie_LDADD = $(GTK_LIBS) $(GLIB_LIBS) $(INTLLIBS) $(JPEG_LIBS) $(TIFF_LIBS) $(LCMS_LIBS) $(EXIV2_LIBS) $(LIBCHAMPLAIN_LIBS) $(LIBCHAMPLAIN_GTK_LIBS) $(LUA_LIBS) $(CLUTTER_LIBS) $(CLUTTER_GTK_LIBS) $(FFMPEGTHUMBNAILER_LIBS) $(PDF_LIBS) $(HEIF_LIBS) $(WEBP_LIBS) $(DJVU_LIBS) $(J2K_LIBS) $(RAW_LIBS) EXTRA_DIST = \ $(extra_SLIK) diff --git a/src/image-load.c b/src/image-load.c index 4f722e43..0ddf32cc 100644 --- a/src/image-load.c +++ b/src/image-load.c @@ -34,6 +34,7 @@ #include "image_load_collection.h" #include "image_load_webp.h" #include "image_load_j2k.h" +#include "image_load_libraw.h" #include "image_load_svgz.h" #include "exif.h" @@ -109,6 +110,7 @@ static void image_loader_init(GTypeInstance *instance, gpointer g_class) il->idle_read_loop_count = IMAGE_LOADER_IDLE_READ_LOOP_COUNT_DEFAULT; il->read_buffer_size = IMAGE_LOADER_READ_BUFFER_SIZE_DEFAULT; il->mapped_file = NULL; + il->preview = IMAGE_LOADER_PREVIEW_NONE; il->requested_width = 0; il->requested_height = 0; @@ -682,6 +684,7 @@ static void image_loader_setup_loader(ImageLoader *il) DEBUG_1("Using custom jpeg loader"); image_loader_backend_set_jpeg(&il->backend); } +#ifndef HAVE_RAW else if (il->bytes_total >= 11 && (memcmp(il->mapped_file + 4, "ftypcrx", 7) == 0) && @@ -690,6 +693,7 @@ static void image_loader_setup_loader(ImageLoader *il) DEBUG_1("Using custom cr3 loader"); image_loader_backend_set_cr3(&il->backend); } +#endif else #endif #ifdef HAVE_TIFF @@ -954,13 +958,37 @@ static gboolean image_loader_setup_source(ImageLoader *il) ExifData *exif = exif_read_fd(il->fd); if (options->thumbnails.use_exif) + { il->mapped_file = exif_get_preview(exif, (guint *)&il->bytes_total, il->requested_width, il->requested_height); + + if (il->mapped_file) + { + il->preview = IMAGE_LOADER_PREVIEW_EXIF; + } + } else + { il->mapped_file = exif_get_preview(exif, (guint *)&il->bytes_total, 0, 0); /* get the largest available preview image or NULL for normal images*/ + if (il->mapped_file) + { + il->preview = IMAGE_LOADER_PREVIEW_EXIF; + } + } + + /* If exiv2 does not find a thumbnail, try libraw (which may be slower) */ + if (!il->mapped_file) + { + il->mapped_file = libraw_get_preview(il, (guint *)&il->bytes_total); + + if (il->mapped_file) + { + il->preview = IMAGE_LOADER_PREVIEW_LIBRAW; + } + } + if (il->mapped_file) { - il->preview = TRUE; DEBUG_1("Usable reduced size (preview) image loaded from file %s", il->fd->path); } exif_free_fd(il->fd, exif); @@ -994,7 +1022,7 @@ static gboolean image_loader_setup_source(ImageLoader *il) il->mapped_file = 0; return FALSE; } - il->preview = FALSE; + il->preview = IMAGE_LOADER_PREVIEW_NONE; } return TRUE; @@ -1006,10 +1034,14 @@ static void image_loader_stop_source(ImageLoader *il) if (il->mapped_file) { - if (il->preview) + if (il->preview == IMAGE_LOADER_PREVIEW_EXIF) { exif_free_preview(il->mapped_file); } + else if (il->preview == IMAGE_LOADER_PREVIEW_LIBRAW) + { + libraw_free_preview(il->mapped_file); + } else { munmap(il->mapped_file, il->bytes_total); diff --git a/src/image-load.h b/src/image-load.h index 176a7901..4c005833 100644 --- a/src/image-load.h +++ b/src/image-load.h @@ -58,6 +58,12 @@ struct _ImageLoaderBackend ImageLoaderBackendFuncGetPageTotal get_page_total; }; +typedef enum { + IMAGE_LOADER_PREVIEW_NONE = 0, + IMAGE_LOADER_PREVIEW_EXIF = 1, + IMAGE_LOADER_PREVIEW_LIBRAW = 2 +} ImageLoaderPreview; + //typedef struct _ImageLoader ImageLoader; typedef struct _ImageLoaderClass ImageLoaderClass; @@ -74,7 +80,7 @@ struct _ImageLoader gsize bytes_read; gsize bytes_total; - gboolean preview; + ImageLoaderPreview preview; gint requested_width; gint requested_height; diff --git a/src/image_load_libraw.c b/src/image_load_libraw.c new file mode 100644 index 00000000..bed4efc5 --- /dev/null +++ b/src/image_load_libraw.c @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2021 The Geeqie Team + * + * Authors: Colin Clark + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/** + * @file + * This uses libraw to extract a thumbnail from a raw image. The exiv2 library + * does not (yet) extract thumbnails from .cr3 images. + * LibRaw seems to be slower than exiv2, so let exiv2 have priority. + */ + +#include "main.h" + +#include "filefilter.h" +#include "image-load.h" +#include "image_load_libraw.h" + +#ifdef HAVE_RAW + +#include +#include + +typedef struct _UnmapData UnmapData; +struct _UnmapData +{ + guchar *ptr; + guchar *map_data; + size_t map_len; + libraw_data_t *lrdt; +}; + +static GList *libraw_unmap_list = 0; + +void libraw_free_preview(guchar *buf) +{ + GList *work = libraw_unmap_list; + + while (work) + { + UnmapData *ud = (UnmapData *)work->data; + if (ud->ptr == buf) + { + munmap(ud->map_data, ud->map_len); + libraw_close(ud->lrdt); + libraw_unmap_list = g_list_remove_link(libraw_unmap_list, work); + g_free(ud); + return; + } + work = work->next; + } + g_assert_not_reached(); +} + +guchar *libraw_get_preview(ImageLoader *il, guint *data_len) +{ + libraw_data_t *lrdt; + int ret; + UnmapData *ud; + struct stat st; + guchar *map_data; + size_t map_len; + int fd; + + if (!filter_file_class(il->fd->path, FORMAT_CLASS_RAWIMAGE)) return NULL; + + fd = open(il->fd->path, O_RDONLY); + if (fd == -1) + { + return NULL; + } + + if (fstat(fd, &st) == -1) + { + close(fd); + return NULL; + } + + map_len = st.st_size; + map_data = (guchar *) mmap(0, map_len, PROT_READ, MAP_PRIVATE, fd, 0); + close(fd); + + if (map_data == MAP_FAILED) + { + return NULL; + } + + lrdt = libraw_init(0); + if (!lrdt) + { + log_printf("Warning: Cannot create libraw handle\n"); + return NULL; + } + + ret = libraw_open_buffer(lrdt, (void *)map_data, map_len); + if (ret == LIBRAW_SUCCESS) + { + ret = libraw_unpack_thumb(lrdt); + if (ret == LIBRAW_SUCCESS) + { + il->mapped_file = (guchar *)lrdt->thumbnail.thumb; + *data_len = lrdt->thumbnail.tlength; + + ud = g_new(UnmapData, 1); + ud->ptr =(guchar *)lrdt->thumbnail.thumb; + ud->map_data = map_data; + ud->map_len = lrdt->thumbnail.tlength; + ud->lrdt = lrdt; + + libraw_unmap_list = g_list_prepend(libraw_unmap_list, ud); + + return (guchar *)lrdt->thumbnail.thumb; + } + } + + libraw_close(lrdt); + + return NULL; +} + +#else /* !define HAVE_RAW */ + +void libraw_free_preview(guchar *buf) +{ +} + +guchar *libraw_get_preview(ImageLoader *il, guint *data_len) +{ + return NULL; +} + +#endif + +/* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */ diff --git a/src/image_load_libraw.h b/src/image_load_libraw.h new file mode 100644 index 00000000..30e5578f --- /dev/null +++ b/src/image_load_libraw.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2021 The Geeqie Team + * + * Author: Colin Clark + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef IMAGE_LOAD_RAW_H +#define IMAGE_LOAD_RAW_H + +guchar *libraw_get_preview(ImageLoader *il, guint *data_len); +void libraw_free_preview(guchar *buf); + +#endif + +/* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */ diff --git a/web/geeqie-install-debian.sh b/web/geeqie-install-debian.sh index a606422e..9a16278e 100755 --- a/web/geeqie-install-debian.sh +++ b/web/geeqie-install-debian.sh @@ -1,5 +1,5 @@ #!/bin/bash -version="2019-12-30" +version="2021-05-10" description=$' Geeqie is an image viewer. This script will download, compile, and install Geeqie on Debian-based systems. @@ -69,6 +69,8 @@ optional_array=( "libdjvulibre-dev" "libopenjp2 (for JP2 images)" "libopenjp2-7-dev" +"libraw (for CR3 images)" +"libraw-dev" ) # Optional for GTK3 only -- 2.20.1