Hardcode Exif orientation in thumbnails
This commit is contained in:
parent
bf47782f0a
commit
98bdab443a
55
fiv-io.c
55
fiv-io.c
|
@ -2627,6 +2627,61 @@ fiv_io_save(cairo_surface_t *page, cairo_surface_t *frame, FivIoProfile target,
|
||||||
|
|
||||||
// --- Metadata ----------------------------------------------------------------
|
// --- 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
|
FivIoOrientation
|
||||||
fiv_io_exif_orientation(const guint8 *tiff, gsize len)
|
fiv_io_exif_orientation(const guint8 *tiff, gsize len)
|
||||||
{
|
{
|
||||||
|
|
8
fiv-io.h
8
fiv-io.h
|
@ -108,6 +108,14 @@ typedef enum _FivIoOrientation {
|
||||||
FivIoOrientation270 = 8
|
FivIoOrientation270 = 8
|
||||||
} FivIoOrientation;
|
} 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);
|
FivIoOrientation fiv_io_exif_orientation(const guint8 *exif, gsize len);
|
||||||
|
|
||||||
/// Save metadata attached by this module in Exiv2 format.
|
/// Save metadata attached by this module in Exiv2 format.
|
||||||
|
|
|
@ -95,26 +95,33 @@ fiv_thumbnail_get_root(void)
|
||||||
|
|
||||||
// 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 *
|
||||||
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);
|
cairo_format_t format = cairo_image_surface_get_format(thumbnail);
|
||||||
int width = cairo_image_surface_get_width(thumbnail);
|
int w = 0, width = cairo_image_surface_get_width(thumbnail);
|
||||||
int height = cairo_image_surface_get_height(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_x = 1;
|
||||||
double scale_y = 1;
|
double scale_y = 1;
|
||||||
if (width > FIV_THUMBNAIL_WIDE_COEFFICIENT * height) {
|
if (w > FIV_THUMBNAIL_WIDE_COEFFICIENT * h) {
|
||||||
scale_x = FIV_THUMBNAIL_WIDE_COEFFICIENT * row_height / width;
|
scale_x = FIV_THUMBNAIL_WIDE_COEFFICIENT * row_height / w;
|
||||||
scale_y = round(scale_x * height) / height;
|
scale_y = round(scale_x * h) / h;
|
||||||
} else {
|
} else {
|
||||||
scale_y = row_height / height;
|
scale_y = row_height / h;
|
||||||
scale_x = round(scale_y * width) / width;
|
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);
|
return cairo_surface_reference(thumbnail);
|
||||||
|
|
||||||
int projected_width = round(scale_x * width);
|
int projected_width = round(scale_x * w);
|
||||||
int projected_height = round(scale_y * height);
|
int projected_height = round(scale_y * h);
|
||||||
cairo_surface_t *scaled = cairo_image_surface_create(
|
cairo_surface_t *scaled = cairo_image_surface_create(
|
||||||
(format == CAIRO_FORMAT_RGB24 || format == CAIRO_FORMAT_RGB30)
|
(format == CAIRO_FORMAT_RGB24 || format == CAIRO_FORMAT_RGB30)
|
||||||
? CAIRO_FORMAT_RGB24
|
? 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_set_source_surface(cr, thumbnail, 0, 0);
|
||||||
cairo_pattern_t *pattern = cairo_get_source(cr);
|
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_extend(pattern, CAIRO_EXTEND_PAD);
|
||||||
|
cairo_pattern_set_matrix(pattern, &matrix);
|
||||||
|
|
||||||
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
|
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
|
||||||
cairo_paint(cr);
|
cairo_paint(cr);
|
||||||
cairo_destroy(cr);
|
cairo_destroy(cr);
|
||||||
mark_thumbnail_lq(scaled);
|
|
||||||
return 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--) {
|
for (int use = max_size; use >= FIV_THUMBNAIL_SIZE_MIN; use--) {
|
||||||
cairo_surface_t *scaled =
|
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,
|
gchar *path = g_strdup_printf("%s/wide-%s/%s.webp", thumbnails_dir,
|
||||||
fiv_thumbnail_sizes[use].thumbnail_spec_name, sum);
|
fiv_thumbnail_sizes[use].thumbnail_spec_name, sum);
|
||||||
save_thumbnail(scaled, path, thum);
|
save_thumbnail(scaled, path, thum);
|
||||||
|
|
73
fiv-view.c
73
fiv-view.c
|
@ -55,9 +55,9 @@ struct _FivView {
|
||||||
|
|
||||||
G_DEFINE_TYPE(FivView, fiv_view, GTK_TYPE_WIDGET)
|
G_DEFINE_TYPE(FivView, fiv_view, GTK_TYPE_WIDGET)
|
||||||
|
|
||||||
struct size {
|
typedef struct _Dimensions {
|
||||||
double width, height;
|
double width, height;
|
||||||
};
|
} Dimensions;
|
||||||
|
|
||||||
static FivIoOrientation view_left[9] = {
|
static FivIoOrientation view_left[9] = {
|
||||||
[FivIoOrientationUnknown] = FivIoOrientationUnknown,
|
[FivIoOrientationUnknown] = FivIoOrientationUnknown,
|
||||||
|
@ -201,11 +201,11 @@ fiv_view_set_property(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct size
|
static Dimensions
|
||||||
get_surface_dimensions(FivView *self)
|
get_surface_dimensions(FivView *self)
|
||||||
{
|
{
|
||||||
if (!self->image)
|
if (!self->image)
|
||||||
return (struct size) {};
|
return (Dimensions) {};
|
||||||
|
|
||||||
cairo_rectangle_t extents = {};
|
cairo_rectangle_t extents = {};
|
||||||
switch (cairo_surface_get_type(self->page)) {
|
switch (cairo_surface_get_type(self->page)) {
|
||||||
|
@ -222,65 +222,20 @@ get_surface_dimensions(FivView *self)
|
||||||
g_assert_not_reached();
|
g_assert_not_reached();
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (self->orientation) {
|
if (fiv_io_orientation_is_sideways(self->orientation))
|
||||||
case FivIoOrientation90:
|
return (Dimensions) {extents.height, extents.width};
|
||||||
case FivIoOrientationMirror90:
|
|
||||||
case FivIoOrientation270:
|
return (Dimensions) {extents.width, extents.height};
|
||||||
case FivIoOrientationMirror270:
|
|
||||||
return (struct size) {extents.height, extents.width};
|
|
||||||
default:
|
|
||||||
return (struct size) {extents.width, extents.height};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
get_display_dimensions(FivView *self, int *width, int *height)
|
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);
|
*width = ceil(surface_dimensions.width * self->scale);
|
||||||
*height = ceil(surface_dimensions.height * 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
|
static void
|
||||||
fiv_view_get_preferred_height(GtkWidget *widget, gint *minimum, gint *natural)
|
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)
|
if (!self->image || !self->scale_to_fit)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
struct size surface_dimensions = get_surface_dimensions(self);
|
Dimensions surface_dimensions = get_surface_dimensions(self);
|
||||||
self->scale = 1;
|
self->scale = 1;
|
||||||
|
|
||||||
if (ceil(surface_dimensions.width * self->scale) > allocation->width)
|
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)
|
if (h < allocation.height)
|
||||||
y = round((allocation.height - h) / 2.);
|
y = round((allocation.height - h) / 2.);
|
||||||
|
|
||||||
struct size surface_dimensions = get_surface_dimensions(self);
|
Dimensions surface_dimensions = get_surface_dimensions(self);
|
||||||
cairo_matrix_t matrix = get_orientation_matrix(
|
cairo_matrix_t matrix = fiv_io_orientation_matrix(
|
||||||
self->orientation, surface_dimensions.width, surface_dimensions.height);
|
self->orientation, surface_dimensions.width, surface_dimensions.height);
|
||||||
cairo_translate(cr, x, y);
|
cairo_translate(cr, x, y);
|
||||||
if (self->checkerboard) {
|
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.
|
// Any DPI will be wrong, unless we import that information from the image.
|
||||||
double scale = 1 / 96.;
|
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 w = surface_dimensions.width * scale;
|
||||||
double h = surface_dimensions.height * 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_t *cr = gtk_print_context_get_cairo_context(context);
|
||||||
cairo_scale(cr, scale, scale);
|
cairo_scale(cr, scale, scale);
|
||||||
cairo_set_source_surface(cr, self->frame, 0, 0);
|
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);
|
self->orientation, surface_dimensions.width, surface_dimensions.height);
|
||||||
cairo_pattern_set_matrix(cairo_get_source(cr), &matrix);
|
cairo_pattern_set_matrix(cairo_get_source(cr), &matrix);
|
||||||
cairo_paint(cr);
|
cairo_paint(cr);
|
||||||
|
|
Loading…
Reference in New Issue