Downscale embedded thumbnails within minions

Otherwise the UI would become unresponsive during loading.
This commit is contained in:
Přemysl Eric Janouch 2022-06-08 02:45:45 +02:00
parent a8f7532abd
commit 84f8c9436f
Signed by: p
GPG Key ID: A0420B94F92B9493
3 changed files with 76 additions and 67 deletions

View File

@ -130,69 +130,6 @@ render(GFile *target, GBytes *data, gboolean *color_managed, GError **error)
return surface; 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. // In principle similar to rescale_thumbnail() from fiv-browser.c.
static cairo_surface_t * static cairo_surface_t *
adjust_thumbnail(cairo_surface_t *thumbnail, double row_height) adjust_thumbnail(cairo_surface_t *thumbnail, double row_height)
@ -264,6 +201,76 @@ adjust_thumbnail(cairo_surface_t *thumbnail, double row_height)
return scaled; 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 static WebPData
encode_thumbnail(cairo_surface_t *surface) encode_thumbnail(cairo_surface_t *surface)
{ {

View File

@ -56,7 +56,9 @@ extern cairo_user_data_key_t fiv_thumbnail_key_lq;
gchar *fiv_thumbnail_get_root(void); gchar *fiv_thumbnail_get_root(void);
/// Attempts to extract any low-quality thumbnail from fast targets. /// 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. /// Generates wide thumbnails of up to the specified size, saves them in cache.
/// Returns the surface used for the maximum size, or an error. /// Returns the surface used for the maximum size, or an error.

6
fiv.c
View File

@ -1773,9 +1773,9 @@ output_thumbnail(const char *path_arg, gboolean extract, const char *size_arg)
if (!path_arg) if (!path_arg)
exit_fatal("no path given"); exit_fatal("no path given");
FivThumbnailSize size = 0; FivThumbnailSize size = FIV_THUMBNAIL_SIZE_COUNT;
if (size_arg) { if (size_arg) {
for (; size < FIV_THUMBNAIL_SIZE_COUNT; size++) { for (size = 0; size < FIV_THUMBNAIL_SIZE_COUNT; size++) {
if (!strcmp( if (!strcmp(
fiv_thumbnail_sizes[size].thumbnail_spec_name, size_arg)) fiv_thumbnail_sizes[size].thumbnail_spec_name, size_arg))
break; break;
@ -1787,7 +1787,7 @@ output_thumbnail(const char *path_arg, gboolean extract, const char *size_arg)
GError *error = NULL; GError *error = NULL;
GFile *file = g_file_new_for_commandline_arg(path_arg); GFile *file = g_file_new_for_commandline_arg(path_arg);
cairo_surface_t *surface = NULL; 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); fiv_io_serialize_to_stdout(surface, FIV_IO_SERIALIZE_LOW_QUALITY);
else if (size_arg && else if (size_arg &&
(g_clear_error(&error), (g_clear_error(&error),