aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/imv.1.txt9
-rw-r--r--src/canvas.c22
-rw-r--r--src/canvas.h8
-rw-r--r--src/imv.c49
-rw-r--r--src/viewport.c36
-rw-r--r--src/viewport.h18
6 files changed, 133 insertions, 9 deletions
diff --git a/doc/imv.1.txt b/doc/imv.1.txt
index 0738882..14dd727 100644
--- a/doc/imv.1.txt
+++ b/doc/imv.1.txt
@@ -99,6 +99,15 @@ Commands can be entered by pressing *:*. imv supports the following commands:
'actual' resets the zoom to 100%, showing the image at its actual size.
Aliased to 'z'.
+*rotate* <amount>::
+ Rotate image clockwise by the given amount in degrees.
+
+*rotate_to* <angle>::
+ Rotate image clockwise to the given angle in degrees.
+
+*flip* <'horizontal'|'vertical'>::
+ Flip image horizontally/vertically (across vertical/horizontal axis).
+
*open* [-r] <paths ...>::
Add the given paths to the list of open images. If the '-r' option is
specified, do so recursively. Shell expansions may be used.
diff --git a/src/canvas.c b/src/canvas.c
index c185c06..a1044d5 100644
--- a/src/canvas.c
+++ b/src/canvas.c
@@ -8,9 +8,9 @@
#include <cairo/cairo.h>
#include <pango/pangocairo.h>
#include <stdarg.h>
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
-#include <stdbool.h>
#ifdef IMV_BACKEND_LIBRSVG
#include <librsvg/rsvg.h>
@@ -204,7 +204,9 @@ static int convert_pixelformat(enum imv_pixelformat fmt)
static void draw_bitmap(struct imv_canvas *canvas,
struct imv_bitmap *bitmap,
int bx, int by, double scale,
- enum upscaling_method upscaling_method, bool cache_invalidated)
+ double rotation, bool mirrored,
+ enum upscaling_method upscaling_method,
+ bool cache_invalidated)
{
GLint viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport);
@@ -249,6 +251,15 @@ static void draw_bitmap(struct imv_canvas *canvas,
const int top = by;
const int right = left + bitmap->width * scale;
const int bottom = top + bitmap->height * scale;
+ const int center_x = left + bitmap->width * scale / 2;
+ const int center_y = top + bitmap->height * scale / 2;
+
+ glTranslated(center_x, center_y, 0);
+ if (mirrored) {
+ glScaled(-1, 1, 1);
+ }
+ glRotated(-rotation, 0, 0, 1);
+ glTranslated(-center_x, -center_y, 0);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
@@ -273,11 +284,14 @@ RsvgHandle *imv_image_get_svg(const struct imv_image *image);
void imv_canvas_draw_image(struct imv_canvas *canvas, struct imv_image *image,
int x, int y, double scale,
- enum upscaling_method upscaling_method, bool cache_invalidated)
+ double rotation, bool mirrored,
+ enum upscaling_method upscaling_method,
+ bool cache_invalidated)
{
struct imv_bitmap *bitmap = imv_image_get_bitmap(image);
if (bitmap) {
- draw_bitmap(canvas, bitmap, x, y, scale, upscaling_method, cache_invalidated);
+ draw_bitmap(canvas, bitmap, x, y, scale, rotation, mirrored,
+ upscaling_method, cache_invalidated);
return;
}
diff --git a/src/canvas.h b/src/canvas.h
index fc043e5..255c10c 100644
--- a/src/canvas.h
+++ b/src/canvas.h
@@ -1,8 +1,8 @@
-#include <stdbool.h>
-
#ifndef IMV_CANVAS_H
#define IMV_CANVAS_H
+#include <stdbool.h>
+
struct imv_canvas;
struct imv_image;
@@ -48,6 +48,8 @@ void imv_canvas_draw(struct imv_canvas *canvas);
/* Blit the given image to the current OpenGL framebuffer */
void imv_canvas_draw_image(struct imv_canvas *canvas, struct imv_image *image,
int x, int y, double scale,
- enum upscaling_method upscaling_method, bool cache_invalidated);
+ double rotation, bool mirrored,
+ enum upscaling_method upscaling_method,
+ bool cache_invalidated);
#endif
diff --git a/src/imv.c b/src/imv.c
index 5522223..313b253 100644
--- a/src/imv.c
+++ b/src/imv.c
@@ -179,6 +179,9 @@ static void command_next(struct list *args, const char *argstr, void *data);
static void command_prev(struct list *args, const char *argstr, void *data);
static void command_goto(struct list *args, const char *argstr, void *data);
static void command_zoom(struct list *args, const char *argstr, void *data);
+static void command_rotate(struct list *args, const char *argstr, void *data);
+static void command_rotate_to(struct list *args, const char *argstr, void *data);
+static void command_flip(struct list *args, const char *argstr, void *data);
static void command_open(struct list *args, const char *argstr, void *data);
static void command_close(struct list *args, const char *argstr, void *data);
static void command_fullscreen(struct list *args, const char *argstr, void *data);
@@ -497,6 +500,9 @@ struct imv *imv_create(void)
imv_command_register(imv->commands, "prev", &command_prev);
imv_command_register(imv->commands, "goto", &command_goto);
imv_command_register(imv->commands, "zoom", &command_zoom);
+ imv_command_register(imv->commands, "rotate", &command_rotate);
+ imv_command_register(imv->commands, "rotate_to", &command_rotate_to);
+ imv_command_register(imv->commands, "flip", &command_flip);
imv_command_register(imv->commands, "open", &command_open);
imv_command_register(imv->commands, "close", &command_close);
imv_command_register(imv->commands, "fullscreen", &command_fullscreen);
@@ -1183,10 +1189,15 @@ static void render_window(struct imv *imv)
/* draw our actual image */
if (imv->current_image) {
int x, y;
- double scale;
+ double scale, rotation;
+ bool mirrored;
imv_viewport_get_offset(imv->view, &x, &y);
imv_viewport_get_scale(imv->view, &scale);
- imv_canvas_draw_image(imv->canvas, imv->current_image, x, y, scale, imv->upscaling_method, imv->cache_invalidated);
+ imv_viewport_get_rotation(imv->view, &rotation);
+ imv_viewport_get_mirrored(imv->view, &mirrored);
+ imv_canvas_draw_image(imv->canvas, imv->current_image,
+ x, y, scale, rotation, mirrored,
+ imv->upscaling_method, imv->cache_invalidated);
}
imv_canvas_clear(imv->canvas);
@@ -1497,6 +1508,39 @@ static void command_zoom(struct list *args, const char *argstr, void *data)
}
}
+static void command_rotate(struct list *args, const char *argstr, void *data)
+{
+ (void)argstr;
+ struct imv *imv = data;
+ if (args->len == 2) {
+ double degrees = strtod(args->items[1], NULL);
+ imv_viewport_rotate(imv->view, degrees);
+ }
+}
+
+static void command_rotate_to(struct list *args, const char *argstr, void *data)
+{
+ (void)argstr;
+ struct imv *imv = data;
+ if (args->len == 2) {
+ double degrees = strtod(args->items[1], NULL);
+ imv_viewport_rotate_to(imv->view, degrees);
+ }
+}
+
+static void command_flip(struct list *args, const char *argstr, void *data)
+{
+ (void)argstr;
+ struct imv *imv = data;
+ if (args->len == 2) {
+ if (!strcmp(args->items[1], "vertical")) {
+ imv_viewport_flip_v(imv->view);
+ } else if (!strcmp(args->items[1], "horizontal")) {
+ imv_viewport_flip_h(imv->view);
+ }
+ }
+}
+
static void command_open(struct list *args, const char *argstr, void *data)
{
(void)argstr;
@@ -1584,6 +1628,7 @@ static void command_reset(struct list *args, const char *argstr, void *data)
(void)args;
(void)argstr;
struct imv *imv = data;
+ imv_viewport_rotate_to(imv->view, 0);
imv->need_rescale = true;
imv->need_redraw = true;
}
diff --git a/src/viewport.c b/src/viewport.c
index c894f26..7cfb7db 100644
--- a/src/viewport.c
+++ b/src/viewport.c
@@ -1,9 +1,12 @@
#include "viewport.h"
+#include <stdbool.h>
#include <stdlib.h>
struct imv_viewport {
double scale;
+ double rotation;
+ bool mirrored;
struct {
int width, height;
} window; /* window dimensions */
@@ -32,6 +35,8 @@ struct imv_viewport *imv_viewport_create(int window_width, int window_height,
view->buffer.width = buffer_width;
view->buffer.height = buffer_height;
view->scale = 1;
+ view->rotation = 0;
+ view->mirrored = false;
view->x = view->y = view->redraw = 0;
view->pan_factor_x = view->pan_factor_y = 0.5;
view->playing = 1;
@@ -84,6 +89,20 @@ void imv_viewport_get_scale(struct imv_viewport *view, double *scale)
}
}
+void imv_viewport_get_rotation(struct imv_viewport *view, double *rotation)
+{
+ if(rotation) {
+ *rotation = view->rotation;
+ }
+}
+
+void imv_viewport_get_mirrored(struct imv_viewport *view, bool *mirrored)
+{
+ if(mirrored) {
+ *mirrored = view->mirrored;
+ }
+}
+
void imv_viewport_set_default_pan_factor(struct imv_viewport *view, double pan_factor_x, double pan_factor_y)
{
view->pan_factor_x = pan_factor_x;
@@ -177,6 +196,23 @@ void imv_viewport_zoom(struct imv_viewport *view, const struct imv_image *image,
view->locked = 1;
}
+void imv_viewport_rotate(struct imv_viewport *view, double degrees) {
+ view->rotation += degrees;
+}
+
+void imv_viewport_rotate_to(struct imv_viewport *view, double degrees) {
+ view->rotation = degrees;
+}
+
+void imv_viewport_flip_h(struct imv_viewport *view) {
+ view->mirrored = !view->mirrored;
+}
+
+void imv_viewport_flip_v(struct imv_viewport *view) {
+ view->mirrored = !view->mirrored;
+ view->rotation = -(180.0 - view->rotation);
+}
+
void imv_viewport_center(struct imv_viewport *view, const struct imv_image *image)
{
const int image_width = imv_image_width(image);
diff --git a/src/viewport.h b/src/viewport.h
index 5e5bc24..417bf93 100644
--- a/src/viewport.h
+++ b/src/viewport.h
@@ -42,6 +42,12 @@ void imv_viewport_get_offset(struct imv_viewport *view, int *x, int *y);
/* Fetch viewport scale */
void imv_viewport_get_scale(struct imv_viewport *view, double *scale);
+/* Fetch viewport rotation */
+void imv_viewport_get_rotation(struct imv_viewport *view, double *rotation);
+
+/* Fetch viewport mirror status */
+void imv_viewport_get_mirrored(struct imv_viewport *view, bool *mirrored);
+
/* Set the default pan_factor factor for the x and y position */
void imv_viewport_set_default_pan_factor(struct imv_viewport *view, double pan_factor_x, double pan_factor_y);
@@ -55,6 +61,18 @@ void imv_viewport_move(struct imv_viewport *view, int x, int y,
void imv_viewport_zoom(struct imv_viewport *view, const struct imv_image *image,
enum imv_zoom_source, int mouse_x, int mouse_y, int amount);
+/* Rotate the view by the given number of degrees */
+void imv_viewport_rotate(struct imv_viewport *view, double degrees);
+
+/* Rotate the view to the given number of degrees */
+void imv_viewport_rotate_to(struct imv_viewport *view, double degrees);
+
+/* Flip horizontally (across vertical axis) */
+void imv_viewport_flip_h(struct imv_viewport *view);
+
+/* Flip vertically (across horizontal axis) */
+void imv_viewport_flip_v(struct imv_viewport *view);
+
/* Recenter the view to be in the middle of the image */
void imv_viewport_center(struct imv_viewport *view,
const struct imv_image *image);