aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPřemysl Eric Janouch <p@janouch.name>2022-06-08 02:45:45 +0200
committerPřemysl Eric Janouch <p@janouch.name>2022-06-08 02:51:55 +0200
commit84f8c9436ffb84ca5d443b906f1ffb7be42a50e2 (patch)
tree5b9a614080f5b74806e7d37e7292982f9f401406
parenta8f7532abdd9eade6ccc7587968e63eea3b5d159 (diff)
downloadfiv-84f8c9436ffb84ca5d443b906f1ffb7be42a50e2.tar.gz
fiv-84f8c9436ffb84ca5d443b906f1ffb7be42a50e2.tar.xz
fiv-84f8c9436ffb84ca5d443b906f1ffb7be42a50e2.zip
Downscale embedded thumbnails within minions
Otherwise the UI would become unresponsive during loading.
-rw-r--r--fiv-thumbnail.c133
-rw-r--r--fiv-thumbnail.h4
-rw-r--r--fiv.c6
3 files changed, 76 insertions, 67 deletions
diff --git a/fiv-thumbnail.c b/fiv-thumbnail.c
index aee3d49..1a9213a 100644
--- a/fiv-thumbnail.c
+++ b/fiv-thumbnail.c
@@ -130,69 +130,6 @@ render(GFile *target, GBytes *data, gboolean *color_managed, GError **error)
return surface;
}
-cairo_surface_t *
-fiv_thumbnail_extract(GFile *target, GError **error)
-{
- const char *path = g_file_peek_path(target);
- if (!path) {
- set_error(error, "thumbnails will only be extracted from local files");
- return NULL;
- }
-
- GMappedFile *mf = g_mapped_file_new(path, FALSE, error);
- if (!mf)
- return NULL;
-
- cairo_surface_t *surface = NULL;
-#ifndef HAVE_LIBRAW
- // TODO(p): Implement our own thumbnail extractors.
- set_error(error, "unsupported file");
-#else // HAVE_LIBRAW
- libraw_data_t *iprc = libraw_init(
- LIBRAW_OPIONS_NO_MEMERR_CALLBACK | LIBRAW_OPIONS_NO_DATAERR_CALLBACK);
- if (!iprc) {
- set_error(error, "failed to obtain a LibRaw handle");
- goto fail;
- }
-
- int err = 0;
- if ((err = libraw_open_buffer(iprc, (void *) g_mapped_file_get_contents(mf),
- g_mapped_file_get_length(mf))) ||
- (err = libraw_unpack_thumb(iprc))) {
- set_error(error, libraw_strerror(err));
- goto fail_libraw;
- }
-
- libraw_processed_image_t *image = libraw_dcraw_make_mem_thumb(iprc, &err);
- if (!image) {
- set_error(error, libraw_strerror(err));
- goto fail_libraw;
- }
-
- gboolean dummy = FALSE;
- switch (image->type) {
- case LIBRAW_IMAGE_JPEG:
- surface = render(
- target, g_bytes_new(image->data, image->data_size), &dummy, error);
- break;
- case LIBRAW_IMAGE_BITMAP:
- // TODO(p): Implement this one as well.
- default:
- set_error(error, "unsupported embedded thumbnail");
- }
-
- libraw_dcraw_clear_mem(image);
-fail_libraw:
- libraw_close(iprc);
-#endif // HAVE_LIBRAW
-
-fail:
- g_mapped_file_unref(mf);
- return surface;
-}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
// In principle similar to rescale_thumbnail() from fiv-browser.c.
static cairo_surface_t *
adjust_thumbnail(cairo_surface_t *thumbnail, double row_height)
@@ -264,6 +201,76 @@ adjust_thumbnail(cairo_surface_t *thumbnail, double row_height)
return scaled;
}
+cairo_surface_t *
+fiv_thumbnail_extract(GFile *target, FivThumbnailSize max_size, GError **error)
+{
+ const char *path = g_file_peek_path(target);
+ if (!path) {
+ set_error(error, "thumbnails will only be extracted from local files");
+ return NULL;
+ }
+
+ GMappedFile *mf = g_mapped_file_new(path, FALSE, error);
+ if (!mf)
+ return NULL;
+
+ cairo_surface_t *surface = NULL;
+#ifndef HAVE_LIBRAW
+ // TODO(p): Implement our own thumbnail extractors.
+ set_error(error, "unsupported file");
+#else // HAVE_LIBRAW
+ libraw_data_t *iprc = libraw_init(
+ LIBRAW_OPIONS_NO_MEMERR_CALLBACK | LIBRAW_OPIONS_NO_DATAERR_CALLBACK);
+ if (!iprc) {
+ set_error(error, "failed to obtain a LibRaw handle");
+ goto fail;
+ }
+
+ int err = 0;
+ if ((err = libraw_open_buffer(iprc, (void *) g_mapped_file_get_contents(mf),
+ g_mapped_file_get_length(mf))) ||
+ (err = libraw_unpack_thumb(iprc))) {
+ set_error(error, libraw_strerror(err));
+ goto fail_libraw;
+ }
+
+ libraw_processed_image_t *image = libraw_dcraw_make_mem_thumb(iprc, &err);
+ if (!image) {
+ set_error(error, libraw_strerror(err));
+ goto fail_libraw;
+ }
+
+ gboolean dummy = FALSE;
+ switch (image->type) {
+ case LIBRAW_IMAGE_JPEG:
+ surface = render(
+ target, g_bytes_new(image->data, image->data_size), &dummy, error);
+ break;
+ case LIBRAW_IMAGE_BITMAP:
+ // TODO(p): Implement this one as well.
+ default:
+ set_error(error, "unsupported embedded thumbnail");
+ }
+
+ libraw_dcraw_clear_mem(image);
+fail_libraw:
+ libraw_close(iprc);
+#endif // HAVE_LIBRAW
+
+fail:
+ g_mapped_file_unref(mf);
+ if (!surface || max_size < FIV_THUMBNAIL_SIZE_MIN ||
+ max_size > FIV_THUMBNAIL_SIZE_MAX)
+ return surface;
+
+ cairo_surface_t *result =
+ adjust_thumbnail(surface, fiv_thumbnail_sizes[max_size].size);
+ cairo_surface_destroy(surface);
+ return result;
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
static WebPData
encode_thumbnail(cairo_surface_t *surface)
{
diff --git a/fiv-thumbnail.h b/fiv-thumbnail.h
index 301a641..1a22c75 100644
--- a/fiv-thumbnail.h
+++ b/fiv-thumbnail.h
@@ -56,7 +56,9 @@ extern cairo_user_data_key_t fiv_thumbnail_key_lq;
gchar *fiv_thumbnail_get_root(void);
/// Attempts to extract any low-quality thumbnail from fast targets.
-cairo_surface_t *fiv_thumbnail_extract(GFile *target, GError **error);
+/// If `max_size` is a valid value, the image will be downscaled as appropriate.
+cairo_surface_t *fiv_thumbnail_extract(
+ GFile *target, FivThumbnailSize max_size, GError **error);
/// Generates wide thumbnails of up to the specified size, saves them in cache.
/// Returns the surface used for the maximum size, or an error.
diff --git a/fiv.c b/fiv.c
index 9ec976c..f3ac933 100644
--- a/fiv.c
+++ b/fiv.c
@@ -1773,9 +1773,9 @@ output_thumbnail(const char *path_arg, gboolean extract, const char *size_arg)
if (!path_arg)
exit_fatal("no path given");
- FivThumbnailSize size = 0;
+ FivThumbnailSize size = FIV_THUMBNAIL_SIZE_COUNT;
if (size_arg) {
- for (; size < FIV_THUMBNAIL_SIZE_COUNT; size++) {
+ for (size = 0; size < FIV_THUMBNAIL_SIZE_COUNT; size++) {
if (!strcmp(
fiv_thumbnail_sizes[size].thumbnail_spec_name, size_arg))
break;
@@ -1787,7 +1787,7 @@ output_thumbnail(const char *path_arg, gboolean extract, const char *size_arg)
GError *error = NULL;
GFile *file = g_file_new_for_commandline_arg(path_arg);
cairo_surface_t *surface = NULL;
- if (extract && (surface = fiv_thumbnail_extract(file, &error)))
+ if (extract && (surface = fiv_thumbnail_extract(file, size, &error)))
fiv_io_serialize_to_stdout(surface, FIV_IO_SERIALIZE_LOW_QUALITY);
else if (size_arg &&
(g_clear_error(&error),