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),