diff options
| -rw-r--r-- | fiv-io.c | 55 | ||||
| -rw-r--r-- | fiv-io.h | 8 | ||||
| -rw-r--r-- | fiv-thumbnail.c | 36 | ||||
| -rw-r--r-- | fiv-view.c | 73 | 
4 files changed, 99 insertions, 73 deletions
@@ -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)  { @@ -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); @@ -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);  | 
