Hardcode Exif orientation in thumbnails
This commit is contained in:
		
							
								
								
									
										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 ----------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										8
									
								
								fiv-io.h
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								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.
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										73
									
								
								fiv-view.c
									
									
									
									
									
								
							
							
						
						
									
										73
									
								
								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);
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user