Handle Exif rotation
Does not currently work for SVG and X11 cursors.
This commit is contained in:
parent
8c89759325
commit
bd7f2f8c98
|
@ -57,9 +57,9 @@ typedef enum _FastivIoOrientation {
|
||||||
FastivIoOrientationMirror0 = 2,
|
FastivIoOrientationMirror0 = 2,
|
||||||
FastivIoOrientation180 = 3,
|
FastivIoOrientation180 = 3,
|
||||||
FastivIoOrientationMirror180 = 4,
|
FastivIoOrientationMirror180 = 4,
|
||||||
FastivIoOrientationMirror90 = 5,
|
FastivIoOrientationMirror270 = 5,
|
||||||
FastivIoOrientation90 = 6,
|
FastivIoOrientation90 = 6,
|
||||||
FastivIoOrientationMirror270 = 7,
|
FastivIoOrientationMirror90 = 7,
|
||||||
FastivIoOrientation270 = 8
|
FastivIoOrientation270 = 8
|
||||||
} FastivIoOrientation;
|
} FastivIoOrientation;
|
||||||
|
|
||||||
|
|
114
fastiv-view.c
114
fastiv-view.c
|
@ -33,12 +33,49 @@ struct _FastivView {
|
||||||
GtkWidget parent_instance;
|
GtkWidget parent_instance;
|
||||||
cairo_surface_t *surface; ///< The loaded image (sequence)
|
cairo_surface_t *surface; ///< The loaded image (sequence)
|
||||||
cairo_surface_t *frame; ///< Current frame within, unreferenced
|
cairo_surface_t *frame; ///< Current frame within, unreferenced
|
||||||
|
FastivIoOrientation orientation; ///< Current orientation
|
||||||
bool scale_to_fit;
|
bool scale_to_fit;
|
||||||
double scale;
|
double scale;
|
||||||
};
|
};
|
||||||
|
|
||||||
G_DEFINE_TYPE(FastivView, fastiv_view, GTK_TYPE_WIDGET)
|
G_DEFINE_TYPE(FastivView, fastiv_view, GTK_TYPE_WIDGET)
|
||||||
|
|
||||||
|
static FastivIoOrientation view_left[9] = {
|
||||||
|
[FastivIoOrientationUnknown] = FastivIoOrientationUnknown,
|
||||||
|
[FastivIoOrientation0] = FastivIoOrientation270,
|
||||||
|
[FastivIoOrientationMirror0] = FastivIoOrientationMirror270,
|
||||||
|
[FastivIoOrientation180] = FastivIoOrientation90,
|
||||||
|
[FastivIoOrientationMirror180] = FastivIoOrientationMirror90,
|
||||||
|
[FastivIoOrientationMirror270] = FastivIoOrientationMirror180,
|
||||||
|
[FastivIoOrientation90] = FastivIoOrientation0,
|
||||||
|
[FastivIoOrientationMirror90] = FastivIoOrientationMirror0,
|
||||||
|
[FastivIoOrientation270] = FastivIoOrientation180
|
||||||
|
};
|
||||||
|
|
||||||
|
static FastivIoOrientation view_mirror[9] = {
|
||||||
|
[FastivIoOrientationUnknown] = FastivIoOrientationUnknown,
|
||||||
|
[FastivIoOrientation0] = FastivIoOrientationMirror0,
|
||||||
|
[FastivIoOrientationMirror0] = FastivIoOrientation0,
|
||||||
|
[FastivIoOrientation180] = FastivIoOrientationMirror180,
|
||||||
|
[FastivIoOrientationMirror180] = FastivIoOrientation180,
|
||||||
|
[FastivIoOrientationMirror270] = FastivIoOrientation270,
|
||||||
|
[FastivIoOrientation90] = FastivIoOrientationMirror270,
|
||||||
|
[FastivIoOrientationMirror90] = FastivIoOrientation90,
|
||||||
|
[FastivIoOrientation270] = FastivIoOrientationMirror270
|
||||||
|
};
|
||||||
|
|
||||||
|
static FastivIoOrientation view_right[9] = {
|
||||||
|
[FastivIoOrientationUnknown] = FastivIoOrientationUnknown,
|
||||||
|
[FastivIoOrientation0] = FastivIoOrientation90,
|
||||||
|
[FastivIoOrientationMirror0] = FastivIoOrientationMirror90,
|
||||||
|
[FastivIoOrientation180] = FastivIoOrientation270,
|
||||||
|
[FastivIoOrientationMirror180] = FastivIoOrientationMirror270,
|
||||||
|
[FastivIoOrientationMirror270] = FastivIoOrientationMirror0,
|
||||||
|
[FastivIoOrientation90] = FastivIoOrientation180,
|
||||||
|
[FastivIoOrientationMirror90] = FastivIoOrientationMirror180,
|
||||||
|
[FastivIoOrientation270] = FastivIoOrientation0
|
||||||
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
PROP_SCALE = 1,
|
PROP_SCALE = 1,
|
||||||
PROP_SCALE_TO_FIT,
|
PROP_SCALE_TO_FIT,
|
||||||
|
@ -83,13 +120,24 @@ get_surface_dimensions(FastivView *self, double *width, double *height)
|
||||||
cairo_rectangle_t extents = {};
|
cairo_rectangle_t extents = {};
|
||||||
switch (cairo_surface_get_type(self->surface)) {
|
switch (cairo_surface_get_type(self->surface)) {
|
||||||
case CAIRO_SURFACE_TYPE_IMAGE:
|
case CAIRO_SURFACE_TYPE_IMAGE:
|
||||||
|
switch (self->orientation) {
|
||||||
|
case FastivIoOrientation90:
|
||||||
|
case FastivIoOrientationMirror90:
|
||||||
|
case FastivIoOrientation270:
|
||||||
|
case FastivIoOrientationMirror270:
|
||||||
|
*width = cairo_image_surface_get_height(self->surface);
|
||||||
|
*height = cairo_image_surface_get_width(self->surface);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
*width = cairo_image_surface_get_width(self->surface);
|
*width = cairo_image_surface_get_width(self->surface);
|
||||||
*height = cairo_image_surface_get_height(self->surface);
|
*height = cairo_image_surface_get_height(self->surface);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
case CAIRO_SURFACE_TYPE_RECORDING:
|
case CAIRO_SURFACE_TYPE_RECORDING:
|
||||||
if (!cairo_recording_surface_get_extents(self->surface, &extents))
|
if (!cairo_recording_surface_get_extents(self->surface, &extents)) {
|
||||||
cairo_recording_surface_ink_extents(self->surface,
|
cairo_recording_surface_ink_extents(self->surface,
|
||||||
&extents.x, &extents.y, &extents.width, &extents.height);
|
&extents.x, &extents.y, &extents.width, &extents.height);
|
||||||
|
}
|
||||||
|
|
||||||
*width = extents.width;
|
*width = extents.width;
|
||||||
*height = extents.height;
|
*height = extents.height;
|
||||||
|
@ -227,7 +275,9 @@ fastiv_view_draw(GtkWidget *widget, cairo_t *cr)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
int w, h;
|
int w, h;
|
||||||
|
double sw, sh;
|
||||||
get_display_dimensions(self, &w, &h);
|
get_display_dimensions(self, &w, &h);
|
||||||
|
get_surface_dimensions(self, &sw, &sh);
|
||||||
|
|
||||||
double x = 0;
|
double x = 0;
|
||||||
double y = 0;
|
double y = 0;
|
||||||
|
@ -258,11 +308,47 @@ fastiv_view_draw(GtkWidget *widget, cairo_t *cr)
|
||||||
cairo_rectangle(cr, x, y, w, h);
|
cairo_rectangle(cr, x, y, w, h);
|
||||||
cairo_clip(cr);
|
cairo_clip(cr);
|
||||||
|
|
||||||
|
cairo_translate(cr, x, y);
|
||||||
cairo_scale(cr, self->scale, self->scale);
|
cairo_scale(cr, self->scale, self->scale);
|
||||||
cairo_set_source_surface(
|
cairo_set_source_surface(cr, self->frame, 0, 0);
|
||||||
cr, self->frame, x / self->scale, y / self->scale);
|
|
||||||
|
cairo_matrix_t matrix = {};
|
||||||
|
cairo_matrix_init_identity(&matrix);
|
||||||
|
switch (self->orientation) {
|
||||||
|
case FastivIoOrientation90:
|
||||||
|
cairo_matrix_rotate(&matrix, -M_PI_2);
|
||||||
|
cairo_matrix_translate(&matrix, -sw, 0);
|
||||||
|
break;
|
||||||
|
case FastivIoOrientation180:
|
||||||
|
cairo_matrix_scale(&matrix, -1, -1);
|
||||||
|
cairo_matrix_translate(&matrix, -sw, -sh);
|
||||||
|
break;
|
||||||
|
case FastivIoOrientation270:
|
||||||
|
cairo_matrix_rotate(&matrix, +M_PI_2);
|
||||||
|
cairo_matrix_translate(&matrix, 0, -sh);
|
||||||
|
break;
|
||||||
|
case FastivIoOrientationMirror0:
|
||||||
|
cairo_matrix_scale(&matrix, -1, +1);
|
||||||
|
cairo_matrix_translate(&matrix, -sw, 0);
|
||||||
|
break;
|
||||||
|
case FastivIoOrientationMirror90:
|
||||||
|
cairo_matrix_rotate(&matrix, +M_PI_2);
|
||||||
|
cairo_matrix_scale(&matrix, -1, +1);
|
||||||
|
cairo_matrix_translate(&matrix, -sw, -sh);
|
||||||
|
break;
|
||||||
|
case FastivIoOrientationMirror180:
|
||||||
|
cairo_matrix_scale(&matrix, +1, -1);
|
||||||
|
cairo_matrix_translate(&matrix, 0, -sh);
|
||||||
|
break;
|
||||||
|
case FastivIoOrientationMirror270:
|
||||||
|
cairo_matrix_rotate(&matrix, -M_PI_2);
|
||||||
|
cairo_matrix_scale(&matrix, -1, +1);
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
cairo_pattern_t *pattern = cairo_get_source(cr);
|
cairo_pattern_t *pattern = cairo_get_source(cr);
|
||||||
|
cairo_pattern_set_matrix(pattern, &matrix);
|
||||||
cairo_pattern_set_extend(pattern, CAIRO_EXTEND_PAD);
|
cairo_pattern_set_extend(pattern, CAIRO_EXTEND_PAD);
|
||||||
// TODO(p): Prescale it ourselves to an off-screen bitmap, gamma-correctly.
|
// TODO(p): Prescale it ourselves to an off-screen bitmap, gamma-correctly.
|
||||||
cairo_pattern_set_filter(pattern, CAIRO_FILTER_GOOD);
|
cairo_pattern_set_filter(pattern, CAIRO_FILTER_GOOD);
|
||||||
|
@ -352,14 +438,27 @@ fastiv_view_key_press_event(GtkWidget *widget, GdkEventKey *event)
|
||||||
return set_scale(self, self->scale / SCALE_STEP);
|
return set_scale(self, self->scale / SCALE_STEP);
|
||||||
case GDK_KEY_F:
|
case GDK_KEY_F:
|
||||||
return set_scale_to_fit(self, !self->scale_to_fit);
|
return set_scale_to_fit(self, !self->scale_to_fit);
|
||||||
case GDK_KEY_greater: {
|
|
||||||
|
case GDK_KEY_less:
|
||||||
|
self->orientation = view_left[self->orientation];
|
||||||
|
gtk_widget_queue_resize(widget);
|
||||||
|
return TRUE;
|
||||||
|
case GDK_KEY_equal:
|
||||||
|
self->orientation = view_mirror[self->orientation];
|
||||||
|
gtk_widget_queue_draw(widget);
|
||||||
|
return TRUE;
|
||||||
|
case GDK_KEY_greater:
|
||||||
|
self->orientation = view_right[self->orientation];
|
||||||
|
gtk_widget_queue_resize(widget);
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
case GDK_KEY_bracketright:
|
||||||
if (!(self->frame = cairo_surface_get_user_data(
|
if (!(self->frame = cairo_surface_get_user_data(
|
||||||
self->frame, &fastiv_io_key_frame_next)))
|
self->frame, &fastiv_io_key_frame_next)))
|
||||||
self->frame = self->surface;
|
self->frame = self->surface;
|
||||||
gtk_widget_queue_draw(widget);
|
gtk_widget_queue_draw(widget);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -416,5 +515,10 @@ fastiv_view_open(FastivView *self, const gchar *path, GError **error)
|
||||||
|
|
||||||
self->frame = self->surface = surface;
|
self->frame = self->surface = surface;
|
||||||
set_scale_to_fit(self, true);
|
set_scale_to_fit(self, true);
|
||||||
|
|
||||||
|
if ((self->orientation = (uintptr_t) cairo_surface_get_user_data(
|
||||||
|
self->surface, &fastiv_io_key_orientation)) ==
|
||||||
|
FastivIoOrientationUnknown)
|
||||||
|
self->orientation = FastivIoOrientation0;
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue