aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPřemysl Eric Janouch <p@janouch.name>2021-12-28 23:10:45 +0100
committerPřemysl Eric Janouch <p@janouch.name>2021-12-28 23:29:58 +0100
commit98bdab443adfbf4d6ecc485874806016771ddbf6 (patch)
tree993a4b3a0db308b83fe26eefe4b648ed8d7d56af
parentbf47782f0a4720da8b6aeb39cfc128b6b26ded6e (diff)
downloadfiv-98bdab443adfbf4d6ecc485874806016771ddbf6.tar.gz
fiv-98bdab443adfbf4d6ecc485874806016771ddbf6.tar.xz
fiv-98bdab443adfbf4d6ecc485874806016771ddbf6.zip
Hardcode Exif orientation in thumbnails
-rw-r--r--fiv-io.c55
-rw-r--r--fiv-io.h8
-rw-r--r--fiv-thumbnail.c36
-rw-r--r--fiv-view.c73
4 files changed, 99 insertions, 73 deletions
diff --git a/fiv-io.c b/fiv-io.c
index 759cb4e..ee597bb 100644
--- a/fiv-io.c
+++ b/fiv-io.c
@@ -2627,6 +2627,61 @@ fiv_io_save(cairo_surface_t *page, cairo_surface_t *frame, FivIoProfile target,
// --- Metadata ----------------------------------------------------------------
+gboolean
+fiv_io_orientation_is_sideways(FivIoOrientation orientation)
+{
+ switch (orientation) {
+ case FivIoOrientation90:
+ case FivIoOrientationMirror90:
+ case FivIoOrientation270:
+ case FivIoOrientationMirror270:
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+cairo_matrix_t
+fiv_io_orientation_matrix(
+ FivIoOrientation orientation, double width, double height)
+{
+ cairo_matrix_t matrix = {};
+ cairo_matrix_init_identity(&matrix);
+ switch (orientation) {
+ case FivIoOrientation90:
+ cairo_matrix_rotate(&matrix, -M_PI_2);
+ cairo_matrix_translate(&matrix, -width, 0);
+ break;
+ case FivIoOrientation180:
+ cairo_matrix_scale(&matrix, -1, -1);
+ cairo_matrix_translate(&matrix, -width, -height);
+ break;
+ case FivIoOrientation270:
+ cairo_matrix_rotate(&matrix, +M_PI_2);
+ cairo_matrix_translate(&matrix, 0, -height);
+ break;
+ case FivIoOrientationMirror0:
+ cairo_matrix_scale(&matrix, -1, +1);
+ cairo_matrix_translate(&matrix, -width, 0);
+ break;
+ case FivIoOrientationMirror90:
+ cairo_matrix_rotate(&matrix, +M_PI_2);
+ cairo_matrix_scale(&matrix, -1, +1);
+ cairo_matrix_translate(&matrix, -width, -height);
+ break;
+ case FivIoOrientationMirror180:
+ cairo_matrix_scale(&matrix, +1, -1);
+ cairo_matrix_translate(&matrix, 0, -height);
+ break;
+ case FivIoOrientationMirror270:
+ cairo_matrix_rotate(&matrix, -M_PI_2);
+ cairo_matrix_scale(&matrix, -1, +1);
+ default:
+ break;
+ }
+ return matrix;
+}
+
FivIoOrientation
fiv_io_exif_orientation(const guint8 *tiff, gsize len)
{
diff --git a/fiv-io.h b/fiv-io.h
index 54e2727..35eff32 100644
--- a/fiv-io.h
+++ b/fiv-io.h
@@ -108,6 +108,14 @@ typedef enum _FivIoOrientation {
FivIoOrientation270 = 8
} FivIoOrientation;
+/// Returns whether dimensions need to be swapped for rendering.
+gboolean fiv_io_orientation_is_sideways(FivIoOrientation orientation);
+
+/// Returns a rendering matrix for a surface. Dimensions need to be pre-swapped.
+cairo_matrix_t fiv_io_orientation_matrix(
+ FivIoOrientation orientation, double width, double height);
+
+/// Extracts the orientation field from Exif, if there's any.
FivIoOrientation fiv_io_exif_orientation(const guint8 *exif, gsize len);
/// Save metadata attached by this module in Exiv2 format.
diff --git a/fiv-thumbnail.c b/fiv-thumbnail.c
index 1384213..24063f3 100644
--- a/fiv-thumbnail.c
+++ b/fiv-thumbnail.c
@@ -95,26 +95,33 @@ fiv_thumbnail_get_root(void)
// In principle similar to rescale_thumbnail() from fiv-browser.c.
static cairo_surface_t *
-rescale_thumbnail(cairo_surface_t *thumbnail, double row_height)
+adjust_thumbnail(cairo_surface_t *thumbnail, double row_height)
{
cairo_format_t format = cairo_image_surface_get_format(thumbnail);
- int width = cairo_image_surface_get_width(thumbnail);
- int height = cairo_image_surface_get_height(thumbnail);
+ int w = 0, width = cairo_image_surface_get_width(thumbnail);
+ int h = 0, height = cairo_image_surface_get_height(thumbnail);
+
+ // Hardcode orientation.
+ FivIoOrientation orientation = (uintptr_t) cairo_surface_get_user_data(
+ thumbnail, &fiv_io_key_orientation);
+ cairo_matrix_t matrix = fiv_io_orientation_is_sideways(orientation)
+ ? fiv_io_orientation_matrix(orientation, (w = height), (h = width))
+ : fiv_io_orientation_matrix(orientation, (w = width), (h = height));
double scale_x = 1;
double scale_y = 1;
- if (width > FIV_THUMBNAIL_WIDE_COEFFICIENT * height) {
- scale_x = FIV_THUMBNAIL_WIDE_COEFFICIENT * row_height / width;
- scale_y = round(scale_x * height) / height;
+ if (w > FIV_THUMBNAIL_WIDE_COEFFICIENT * h) {
+ scale_x = FIV_THUMBNAIL_WIDE_COEFFICIENT * row_height / w;
+ scale_y = round(scale_x * h) / h;
} else {
- scale_y = row_height / height;
- scale_x = round(scale_y * width) / width;
+ scale_y = row_height / h;
+ scale_x = round(scale_y * w) / w;
}
- if (scale_x == 1 && scale_y == 1)
+ if (orientation <= FivIoOrientation0 && scale_x == 1 && scale_y == 1)
return cairo_surface_reference(thumbnail);
- int projected_width = round(scale_x * width);
- int projected_height = round(scale_y * height);
+ int projected_width = round(scale_x * w);
+ int projected_height = round(scale_y * h);
cairo_surface_t *scaled = cairo_image_surface_create(
(format == CAIRO_FORMAT_RGB24 || format == CAIRO_FORMAT_RGB30)
? CAIRO_FORMAT_RGB24
@@ -126,13 +133,14 @@ rescale_thumbnail(cairo_surface_t *thumbnail, double row_height)
cairo_set_source_surface(cr, thumbnail, 0, 0);
cairo_pattern_t *pattern = cairo_get_source(cr);
- cairo_pattern_set_filter(pattern, CAIRO_FILTER_BEST);
+ // CAIRO_FILTER_BEST, for some reason, works bad with CAIRO_FORMAT_RGB30.
+ cairo_pattern_set_filter(pattern, CAIRO_FILTER_GOOD);
cairo_pattern_set_extend(pattern, CAIRO_EXTEND_PAD);
+ cairo_pattern_set_matrix(pattern, &matrix);
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
cairo_paint(cr);
cairo_destroy(cr);
- mark_thumbnail_lq(scaled);
return scaled;
}
@@ -260,7 +268,7 @@ fiv_thumbnail_produce(GFile *target, FivThumbnailSize max_size, GError **error)
for (int use = max_size; use >= FIV_THUMBNAIL_SIZE_MIN; use--) {
cairo_surface_t *scaled =
- rescale_thumbnail(surface, fiv_thumbnail_sizes[use].size);
+ adjust_thumbnail(surface, fiv_thumbnail_sizes[use].size);
gchar *path = g_strdup_printf("%s/wide-%s/%s.webp", thumbnails_dir,
fiv_thumbnail_sizes[use].thumbnail_spec_name, sum);
save_thumbnail(scaled, path, thum);
diff --git a/fiv-view.c b/fiv-view.c
index 467dd0f..5162f32 100644
--- a/fiv-view.c
+++ b/fiv-view.c
@@ -55,9 +55,9 @@ struct _FivView {
G_DEFINE_TYPE(FivView, fiv_view, GTK_TYPE_WIDGET)
-struct size {
+typedef struct _Dimensions {
double width, height;
-};
+} Dimensions;
static FivIoOrientation view_left[9] = {
[FivIoOrientationUnknown] = FivIoOrientationUnknown,
@@ -201,11 +201,11 @@ fiv_view_set_property(
}
}
-static struct size
+static Dimensions
get_surface_dimensions(FivView *self)
{
if (!self->image)
- return (struct size) {};
+ return (Dimensions) {};
cairo_rectangle_t extents = {};
switch (cairo_surface_get_type(self->page)) {
@@ -222,65 +222,20 @@ get_surface_dimensions(FivView *self)
g_assert_not_reached();
}
- switch (self->orientation) {
- case FivIoOrientation90:
- case FivIoOrientationMirror90:
- case FivIoOrientation270:
- case FivIoOrientationMirror270:
- return (struct size) {extents.height, extents.width};
- default:
- return (struct size) {extents.width, extents.height};
- }
+ if (fiv_io_orientation_is_sideways(self->orientation))
+ return (Dimensions) {extents.height, extents.width};
+
+ return (Dimensions) {extents.width, extents.height};
}
static void
get_display_dimensions(FivView *self, int *width, int *height)
{
- struct size surface_dimensions = get_surface_dimensions(self);
+ Dimensions surface_dimensions = get_surface_dimensions(self);
*width = ceil(surface_dimensions.width * self->scale);
*height = ceil(surface_dimensions.height * self->scale);
}
-static cairo_matrix_t
-get_orientation_matrix(FivIoOrientation o, double width, double height)
-{
- cairo_matrix_t matrix = {};
- cairo_matrix_init_identity(&matrix);
- switch (o) {
- case FivIoOrientation90:
- cairo_matrix_rotate(&matrix, -M_PI_2);
- cairo_matrix_translate(&matrix, -width, 0);
- break;
- case FivIoOrientation180:
- cairo_matrix_scale(&matrix, -1, -1);
- cairo_matrix_translate(&matrix, -width, -height);
- break;
- case FivIoOrientation270:
- cairo_matrix_rotate(&matrix, +M_PI_2);
- cairo_matrix_translate(&matrix, 0, -height);
- break;
- case FivIoOrientationMirror0:
- cairo_matrix_scale(&matrix, -1, +1);
- cairo_matrix_translate(&matrix, -width, 0);
- break;
- case FivIoOrientationMirror90:
- cairo_matrix_rotate(&matrix, +M_PI_2);
- cairo_matrix_scale(&matrix, -1, +1);
- cairo_matrix_translate(&matrix, -width, -height);
- break;
- case FivIoOrientationMirror180:
- cairo_matrix_scale(&matrix, +1, -1);
- cairo_matrix_translate(&matrix, 0, -height);
- break;
- case FivIoOrientationMirror270:
- cairo_matrix_rotate(&matrix, -M_PI_2);
- cairo_matrix_scale(&matrix, -1, +1);
- default:
- break;
- }
- return matrix;
-}
-
static void
fiv_view_get_preferred_height(GtkWidget *widget, gint *minimum, gint *natural)
{
@@ -318,7 +273,7 @@ fiv_view_size_allocate(GtkWidget *widget, GtkAllocation *allocation)
if (!self->image || !self->scale_to_fit)
return;
- struct size surface_dimensions = get_surface_dimensions(self);
+ Dimensions surface_dimensions = get_surface_dimensions(self);
self->scale = 1;
if (ceil(surface_dimensions.width * self->scale) > allocation->width)
@@ -443,8 +398,8 @@ fiv_view_draw(GtkWidget *widget, cairo_t *cr)
if (h < allocation.height)
y = round((allocation.height - h) / 2.);
- struct size surface_dimensions = get_surface_dimensions(self);
- cairo_matrix_t matrix = get_orientation_matrix(
+ Dimensions surface_dimensions = get_surface_dimensions(self);
+ cairo_matrix_t matrix = fiv_io_orientation_matrix(
self->orientation, surface_dimensions.width, surface_dimensions.height);
cairo_translate(cr, x, y);
if (self->checkerboard) {
@@ -731,7 +686,7 @@ on_draw_page(G_GNUC_UNUSED GtkPrintOperation *operation,
{
// Any DPI will be wrong, unless we import that information from the image.
double scale = 1 / 96.;
- struct size surface_dimensions = get_surface_dimensions(self);
+ Dimensions surface_dimensions = get_surface_dimensions(self);
double w = surface_dimensions.width * scale;
double h = surface_dimensions.height * scale;
@@ -743,7 +698,7 @@ on_draw_page(G_GNUC_UNUSED GtkPrintOperation *operation,
cairo_t *cr = gtk_print_context_get_cairo_context(context);
cairo_scale(cr, scale, scale);
cairo_set_source_surface(cr, self->frame, 0, 0);
- cairo_matrix_t matrix = get_orientation_matrix(
+ cairo_matrix_t matrix = fiv_io_orientation_matrix(
self->orientation, surface_dimensions.width, surface_dimensions.height);
cairo_pattern_set_matrix(cairo_get_source(cr), &matrix);
cairo_paint(cr);