aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPřemysl Eric Janouch <p@janouch.name>2023-06-04 21:12:19 +0200
committerPřemysl Eric Janouch <p@janouch.name>2023-06-08 18:59:20 +0200
commita5b5e32c3bebe1801a41bc2ceb74a14dde22157d (patch)
tree0faed8f1e6c520481543e9e110e760feda280b71
parent1e8fe1411b536d4c95c725209b0d817f25ba33f6 (diff)
downloadfiv-a5b5e32c3bebe1801a41bc2ceb74a14dde22157d.tar.gz
fiv-a5b5e32c3bebe1801a41bc2ceb74a14dde22157d.tar.xz
fiv-a5b5e32c3bebe1801a41bc2ceb74a14dde22157d.zip
Refactor fiv_thumbnail_extract()
-rw-r--r--fiv-thumbnail.c184
1 files changed, 108 insertions, 76 deletions
diff --git a/fiv-thumbnail.c b/fiv-thumbnail.c
index 0f6d264..51e53b2 100644
--- a/fiv-thumbnail.c
+++ b/fiv-thumbnail.c
@@ -240,71 +240,68 @@ orient_thumbnail(cairo_surface_t *surface, FivIoOrientation orientation)
return oriented;
}
-cairo_surface_t *
-fiv_thumbnail_extract(GFile *target, FivThumbnailSize max_size, GError **error)
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+#ifdef HAVE_LIBRAW
+
+static cairo_surface_t *
+extract_libraw_bitmap(
+ libraw_data_t *iprc, libraw_processed_image_t *image, GError **error)
{
- const char *path = g_file_peek_path(target);
- if (!path) {
- set_error(error, "thumbnails will only be extracted from local files");
+ // Anything else is extremely rare.
+ if (image->colors != 3 || image->bits != 8) {
+ set_error(error, "unsupported bitmap thumbnail");
return NULL;
}
- GMappedFile *mf = g_mapped_file_new(path, FALSE, error);
- if (!mf)
- return NULL;
-
- // Bitmap thumbnails generally need rotating, e.g.:
- // - Hasselblad/H4D-50/2-9-2017_street_0012.fff
- // - OnePlus/One/IMG_20150729_201116.dng (and more DNGs in general)
- // Though it's apparent LibRaw doesn't adjust the thumbnails to match
- // the main image's "flip" field (it just happens to match up often), e.g.:
- // - Phase One/H 25/H25_Outdoor_.IIQ (correct Orientation in IFD0)
- // - Phase One/H 25/H25_IT8.7-2_Card.TIF (correctly missing in IFD0)
- //
- // JPEG thumbnails generally have the right rotation in their Exif, e.g.:
- // - Canon/EOS-1Ds Mark II/RAW_CANON_1DSM2.CR2
- // - Leica/C (Typ 112)/Leica_-_C_(Typ_112)-_3:2.RWL
- // - Nikon/1 S2/RAW_NIKON_1S2.NEF
- // - Panasonic/DMC-FZ18/RAW_PANASONIC_LUMIX_FZ18.RAW
- // - Panasonic/DMC-FZ70/P1000836.RW2
- // - Samsung/NX200/2013-05-08-194524__sam6589.srw
- // - Sony/DSC-HX95/DSC00018.ARW
- //
- // Some files are problematic and we won't bother with special-casing:
- // - Leaf/Aptus 22/L_003172.mos (JPEG)'s thumbnail wrongly contains
- // Exif Orientation 6, and sizes.flip also contains 6.
- // - Nokia/Lumia 1020/RAW_NOKIA_LUMIA_1020.DNG (bitmap) has wrong color.
- // - Ricoh/GXR/R0017428.DNG (JPEG) seems to be plainly invalid.
- FivIoOrientation orientation = FivIoOrientationUnknown;
- cairo_surface_t *surface = NULL;
-#ifndef HAVE_LIBRAW
- // TODO(p): Implement our own thumbnail extractors.
- set_error(error, "unsupported file");
-#else // HAVE_LIBRAW
- // In this case, g_mapped_file_get_contents() returns NULL, causing issues.
- if (!g_mapped_file_get_length(mf)) {
- set_error(error, "empty file");
- goto fail;
+ cairo_surface_t *surface = cairo_image_surface_create(
+ CAIRO_FORMAT_RGB24, image->width, image->height);
+ guint32 *out = (guint32 *) cairo_image_surface_get_data(surface);
+ const unsigned char *in = image->data;
+ for (guint64 i = 0; i < image->width * image->height; in += 3)
+ out[i++] = in[0] << 16 | in[1] << 8 | in[2];
+ cairo_surface_mark_dirty(surface);
+
+ // LibRaw actually turns an 8 to 5, so follow the documentation.
+ FivIoOrientation orient = FivIoOrientationUnknown;
+ switch (iprc->sizes.flip) {
+ break; case 3:
+ orient = FivIoOrientation180;
+ break; case 5:
+ orient = FivIoOrientation270;
+ break; case 6:
+ orient = FivIoOrientation90;
+ break; default:
+ return surface;
}
+ cairo_surface_set_user_data(
+ surface, &fiv_io_key_orientation, (void *) (intptr_t) orient, NULL);
+ return surface;
+}
+
+static cairo_surface_t *
+extract_libraw(GFile *target, GMappedFile *mf, GError **error)
+{
+ cairo_surface_t *surface = NULL;
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;
+ return NULL;
}
int err = 0;
if ((err = libraw_open_buffer(iprc, (void *) g_mapped_file_get_contents(mf),
g_mapped_file_get_length(mf)))) {
set_error(error, libraw_strerror(err));
- goto fail_libraw;
+ goto fail;
}
#if LIBRAW_VERSION >= LIBRAW_MAKE_VERSION(0, 21, 0)
if (!iprc->thumbs_list.thumbcount) {
set_error(error, "no thumbnails found");
- goto fail_libraw;
+ goto fail;
}
// The old libraw_unpack_thumb() goes for the largest thumbnail,
@@ -323,66 +320,101 @@ fiv_thumbnail_extract(GFile *target, FivThumbnailSize max_size, GError **error)
}
if ((err = libraw_unpack_thumb_ex(iprc, best_index))) {
set_error(error, libraw_strerror(err));
- goto fail_libraw;
+ goto fail;
}
-#else
+#else // LIBRAW_VERSION < LIBRAW_MAKE_VERSION(0, 21, 0)
if ((err = libraw_unpack_thumb(iprc))) {
set_error(error, libraw_strerror(err));
- goto fail_libraw;
+ goto fail;
}
-#endif
+#endif // LIBRAW_VERSION < LIBRAW_MAKE_VERSION(0, 21, 0)
libraw_processed_image_t *image = libraw_dcraw_make_mem_thumb(iprc, &err);
if (!image) {
set_error(error, libraw_strerror(err));
- goto fail_libraw;
+ goto fail;
}
- gboolean dummy = FALSE;
+ // Bitmap thumbnails generally need rotating, e.g.:
+ // - Hasselblad/H4D-50/2-9-2017_street_0012.fff
+ // - OnePlus/One/IMG_20150729_201116.dng (and more DNGs in general)
+ // Though it's apparent LibRaw doesn't adjust the thumbnails to match
+ // the main image's "flip" field (it just happens to match up often), e.g.:
+ // - Phase One/H 25/H25_Outdoor_.IIQ (correct Orientation in IFD0)
+ // - Phase One/H 25/H25_IT8.7-2_Card.TIF (correctly missing in IFD0)
+ //
+ // JPEG thumbnails generally have the right rotation in their Exif, e.g.:
+ // - Canon/EOS-1Ds Mark II/RAW_CANON_1DSM2.CR2
+ // - Leica/C (Typ 112)/Leica_-_C_(Typ_112)-_3:2.RWL
+ // - Nikon/1 S2/RAW_NIKON_1S2.NEF
+ // - Panasonic/DMC-FZ18/RAW_PANASONIC_LUMIX_FZ18.RAW
+ // - Panasonic/DMC-FZ70/P1000836.RW2
+ // - Samsung/NX200/2013-05-08-194524__sam6589.srw
+ // - Sony/DSC-HX95/DSC00018.ARW
+ //
+ // Some files are problematic and we won't bother with special-casing:
+ // - Leaf/Aptus 22/L_003172.mos (JPEG)'s thumbnail wrongly contains
+ // Exif Orientation 6, and sizes.flip also contains 6.
+ // - Nokia/Lumia 1020/RAW_NOKIA_LUMIA_1020.DNG (bitmap) has wrong color.
+ // - Ricoh/GXR/R0017428.DNG (JPEG) seems to be plainly invalid.
switch (image->type) {
+ gboolean dummy;
case LIBRAW_IMAGE_JPEG:
surface = render(
target, g_bytes_new(image->data, image->data_size), &dummy, error);
- orientation = (int) (intptr_t) cairo_surface_get_user_data(
- surface, &fiv_io_key_orientation);
break;
case LIBRAW_IMAGE_BITMAP:
- // Anything else is extremely rare.
- if (image->colors != 3 || image->bits != 8) {
- set_error(error, "unsupported bitmap thumbnail");
- break;
- }
-
- surface = cairo_image_surface_create(
- CAIRO_FORMAT_RGB24, image->width, image->height);
- guint32 *out = (guint32 *) cairo_image_surface_get_data(surface);
- const unsigned char *in = image->data;
- for (guint64 i = 0; i < image->width * image->height; in += 3)
- out[i++] = in[0] << 16 | in[1] << 8 | in[2];
- cairo_surface_mark_dirty(surface);
-
- // LibRaw actually turns an 8 to 5, so follow the documentation.
- switch (iprc->sizes.flip) {
- break; case 3: orientation = FivIoOrientation180;
- break; case 5: orientation = FivIoOrientation270;
- break; case 6: orientation = FivIoOrientation90;
- }
+ surface = extract_libraw_bitmap(iprc, image, error);
break;
default:
set_error(error, "unsupported embedded thumbnail");
}
libraw_dcraw_clear_mem(image);
-fail_libraw:
+fail:
libraw_close(iprc);
+ return surface;
+}
+
#endif // HAVE_LIBRAW
-fail:
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+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;
+
+ // In this case, g_mapped_file_get_contents() returns NULL, causing issues.
+ if (!g_mapped_file_get_length(mf)) {
+ set_error(error, "empty file");
+ return NULL;
+ }
+
+ cairo_surface_t *surface = NULL;
+#ifdef HAVE_LIBRAW
+ surface = extract_libraw(target, mf, error);
+#else // ! HAVE_LIBRAW
+ // TODO(p): Implement our own thumbnail extractors.
+ set_error(error, "unsupported file");
+#endif // ! HAVE_LIBRAW
g_mapped_file_unref(mf);
- // This hardcodes Exif orientation before adjust_thumbnail() might do so,
+ // Hardcode Exif orientation before adjust_thumbnail() might do so,
// before the early return below.
- surface = orient_thumbnail(surface, orientation);
+ if (surface) {
+ int orientation = (intptr_t) cairo_surface_get_user_data(
+ surface, &fiv_io_key_orientation);
+ surface = orient_thumbnail(surface, orientation);
+ }
if (!surface || max_size < FIV_THUMBNAIL_SIZE_MIN ||
max_size > FIV_THUMBNAIL_SIZE_MAX)
return surface;