A image-viewer/include/coords.h => image-viewer/include/coords.h +16 -0
@@ 0,0 1,16 @@
+#include <stdint.h>
+#include "image.h"
+#include "display_utils.h"
+
+typedef struct {
+ int32_t x;
+ int32_t y;
+} coords_t;
+
+coords_t coords_create(int32_t x, int32_t y);
+coords_t coords_get_image_screen_beg_coord(
+ image_t *image, image_zoom_t zoom);
+coords_t coords_get_image_screen_end_coords(image_t *image, image_zoom_t zoom);
+
+coords_t image_get_screen_coords(image_t *image, image_zoom_t zoom, coords_t image_coords);
+coords_t image_get_image_coords(image_t *image, image_zoom_t zoom, coords_t screen_coords);
M image-viewer/include/cursor.h => image-viewer/include/cursor.h +2 -2
@@ 25,7 25,7 @@ cursor_t cursor_create();
void cursor_center(cursor_t *cursor, image_region_t region);
bool cursor_move(cursor_t *cursor, image_region_t region, direction_t direction, int16_t amount);
-void cursor_show(cursor_t *cursor, display_t *display);
-void cursor_hide(cursor_t *cursor, display_t *display);
+void cursor_show(cursor_t *cursor, image_t *image, image_zoom_t zoom, display_t *display);
+void cursor_hide(cursor_t *cursor, image_t *image, image_zoom_t zoom, display_t *display);
#endif // __CURSOR_H__
M image-viewer/include/image.h => image-viewer/include/image.h +11 -3
@@ 42,6 42,12 @@ typedef struct {
typedef struct {
uint16_t x;
uint16_t y;
+ double scale;
+} image_zoom_t;
+
+typedef struct {
+ uint16_t x;
+ uint16_t y;
uint16_t width;
uint16_t height;
@@ 59,8 65,10 @@ image_region_t image_region_create(uint16_t x, uint16_t y, uint16_t width, uint1
bool image_region_move_within(image_region_t *to_move, direction_t direction,
int amount, image_region_t *border);
-double image_write_to_display(image_t *image, display_t *display,
- image_region_t region,
- image_region_t display_region);
+image_zoom_t image_write_to_display(image_t *image, display_t *display,
+ image_zoom_t scale);
+
+image_zoom_t image_get_initial_zoom(image_t *image);
+image_region_t image_get_zoom_region(image_t *image, image_zoom_t zoom);
#endif // __IMAGE_H__
M image-viewer/include/image_viewer.h => image-viewer/include/image_viewer.h +1 -3
@@ 10,7 10,7 @@
typedef struct {
image_t image;
cursor_t cursor;
- image_region_t region;
+ image_zoom_t scale;
image_region_t image_region;
image_region_t display_region;
image_error_t error;
@@ 18,8 18,6 @@ typedef struct {
display_t *display;
bool running;
- double scale_factor;
-
logger_t *logger;
} image_viewer_t;
A image-viewer/src/coords.c => image-viewer/src/coords.c +80 -0
@@ 0,0 1,80 @@
+#include "coords.h"
+
+coords_t coords_create(int32_t x, int32_t y) {
+ coords_t coords = {
+ .x = x,
+ .y = y
+ };
+
+ return coords;
+}
+
+coords_t coords_get_image_screen_beg_coord(image_t *image, image_zoom_t zoom) {
+ uint16_t scaled_w = (uint16_t)(zoom.scale * image->width),
+ scaled_h = (uint16_t)(zoom.scale * image->height);
+
+ int32_t beg_x = ((double)DISPLAY_WIDTH - (double)(scaled_w)) / 2;
+ int32_t beg_y = ((double)DISPLAY_HEIGHT - (double)(scaled_h)) / 2;
+
+ if (beg_x < 0) {
+ beg_x = 0;
+ }
+
+ if (beg_y < 0) {
+ beg_y = 0;
+ }
+
+ return coords_create(beg_x, beg_y);
+}
+
+coords_t coords_get_image_screen_end_coords(image_t *image, image_zoom_t zoom) {
+ uint16_t scaled_w = (uint16_t)(zoom.scale * image->width),
+ scaled_h = (uint16_t)(zoom.scale * image->height);
+
+ int32_t end_x = ((double)DISPLAY_WIDTH + (double)(scaled_w)) / 2;
+ int32_t end_y = ((double)DISPLAY_HEIGHT + (double)(scaled_h)) / 2;
+
+ if (end_x > DISPLAY_WIDTH - 1) {
+ end_x = DISPLAY_WIDTH - 1;
+ }
+
+ if (end_y > DISPLAY_HEIGHT - 1) {
+ end_y = DISPLAY_HEIGHT - 1;
+ }
+
+ return coords_create(end_x, end_y);
+}
+
+coords_t image_get_screen_coords(image_t *image, image_zoom_t zoom,
+ coords_t image_coords) {
+ coords_t beg = coords_get_image_screen_beg_coord(image, zoom);
+ coords_t end = coords_get_image_screen_end_coords(image, zoom);
+
+ image_region_t image_region =
+ image_get_zoom_region(image, zoom);
+ double relative_x = (double)(image_coords.x - (int32_t)image_region.x) / image_region.width;
+ double relative_y = (double)(image_coords.y - (int32_t)image_region.y) / image_region.height;
+ printf("(%d - %hu) - %hu = %f\r\n", image_coords.x, image_region.x, image_region.width, relative_x);
+ printf("image: %f %f\r\n", relative_x, relative_y);
+
+ coords_t screen_coords = coords_create(beg.x + relative_x * (end.x - beg.x),
+ beg.y + relative_y * (end.y - beg.y));
+ return screen_coords;
+}
+
+coords_t image_get_image_coords(image_t *image, image_zoom_t zoom,
+ coords_t screen_coords) {
+ coords_t beg = coords_get_image_screen_beg_coord(image, zoom);
+ coords_t end = coords_get_image_screen_end_coords(image, zoom);
+
+ image_region_t image_region =
+ image_get_zoom_region(image, zoom);
+ double relative_x = (double)(screen_coords.x - beg.x) / (end.x - beg.x);
+ double relative_y = (double)(screen_coords.y - beg.y) / (end.y - beg.y);
+ printf("screen: %f %f\r\n", relative_x, relative_y);
+
+ coords_t image_coords =
+ coords_create(image_region.x + relative_x * image_region.width,
+ image_region.y + relative_y * image_region.height);
+ return image_coords;
+}
M image-viewer/src/cursor.c => image-viewer/src/cursor.c +14 -7
@@ 2,6 2,7 @@
#include "direction.h"
#include "display_utils.h"
#include "image.h"
+#include "coords.h"
const display_pixel_t CURSOR_COLOR = {.fields = {.r = (uint8_t)DISPLAY_MAX_RED, .g = 0, .b = 0}};
@@ 43,13 44,16 @@ bool cursor_move(cursor_t *cursor, image_region_t region, direction_t direction,
return moved;
}
-void cursor_show(cursor_t *cursor, display_t *display) {
- cursor_hide(cursor, display);
+void cursor_show(cursor_t *cursor, image_t *image, image_zoom_t zoom,
+ display_t *display) {
+ cursor_hide(cursor, image, zoom, display);
cursor->shown_at = time(NULL);
cursor->shown = true;
- uint16_t base_x = cursor->x;
- uint16_t base_y = cursor->y;
+ coords_t screen_coords =
+ image_get_screen_coords(image, zoom, coords_create(cursor->x, cursor->y));
+ uint16_t base_x = screen_coords.x;
+ uint16_t base_y = screen_coords.y;
uint16_t first_x = base_x - CURSOR_SIZE / 2;
uint16_t first_y = base_y - CURSOR_SIZE / 2;
@@ 66,13 70,16 @@ void cursor_show(cursor_t *cursor, display_t *display) {
}
}
-void cursor_hide(cursor_t *cursor, display_t *display) {
+void cursor_hide(cursor_t *cursor, image_t *image, image_zoom_t zoom,
+ display_t *display) {
if (!cursor->shown) {
return;
}
- uint16_t base_x = cursor->x;
- uint16_t base_y = cursor->y;
+ coords_t screen_coords =
+ image_get_screen_coords(image, zoom, coords_create(cursor->x, cursor->y));
+ uint16_t base_x = screen_coords.x;
+ uint16_t base_y = screen_coords.y;
uint16_t first_x = base_x - CURSOR_SIZE / 2;
uint16_t first_y = base_y - CURSOR_SIZE / 2;
M image-viewer/src/image.c => image-viewer/src/image.c +64 -22
@@ 76,21 76,6 @@ void image_set_pixel(image_t *image, uint16_t x, uint16_t y,
image->pixels[y * image->width + x] = pixel;
}
-double get_scale_factor(uint16_t w, uint16_t h, image_region_t display_region) {
- double scale_x = (double)display_region.width / (double)w;
- double scale_y = (double)display_region.height / (double)h;
-
- double max = scale_x > scale_y ? scale_x : scale_y;
- double min = scale_x <= scale_y ? scale_x : scale_y;
- double scale = max;
-
- if (w * max > display_region.width || h * max > display_region.height) {
- scale = min;
- }
-
- return scale;
-}
-
static void image_write_downscale(image_t *image, display_t *display,
image_region_t region, image_region_t display_region, double scale_factor) {
float downscale_factor = 1 / scale_factor;
@@ 148,17 133,74 @@ static void image_write_direct(image_t *image, display_t *display,
}
}
-double image_write_to_display(image_t *image, display_t *display,
- image_region_t region, image_region_t display_region) {
+double min(double a, double b) {
+ return a < b ? a : b;
+}
+
+image_zoom_t image_get_initial_zoom(image_t *image) {
+ double scale_x = (double)DISPLAY_WIDTH / image->width;
+ double scale_y = (double)DISPLAY_HEIGHT / image->height;
+
+ double scale = min(min(scale_x, scale_y), 1);
+
+ image_zoom_t zoom = {
+ .scale = scale,
+ .x = 0,
+ .y = 0,
+ };
+
+ return zoom;
+}
+
+image_region_t image_get_zoom_region(image_t *image, image_zoom_t zoom) {
+ double fits_screen_width = DISPLAY_WIDTH / (double)(image->width * zoom.scale);
+ double fits_screen_height =
+ DISPLAY_HEIGHT / (double)(image->height * zoom.scale);
+
+ uint16_t width = fits_screen_width * image->width;
+ uint16_t height = fits_screen_height * image->height;
+
+ if (fits_screen_width > 1) {
+ width = image->width;
+ }
+
+ if (fits_screen_height > 1) {
+ height = image->height;
+ }
+
+ image_region_t region = {
+ .x = zoom.x,
+ .y = zoom.y,
+ .width = width,
+ .height = height
+ };
+
+ if (region.x + region.width > image->width) {
+ region.x = image->width - region.width;
+ }
+
+ if (region.y + region.height > image->height) {
+ region.y = image->height - region.height;
+ }
+
+ return region;
+}
+
+image_zoom_t image_write_to_display(image_t *image, display_t *display,
+ image_zoom_t zoom) {
display_clear(display, false);
- uint16_t w = region.width, h = region.height;
- if (w == display_region.width && h == display_region.height) {
+ image_region_t region = image_get_zoom_region(image, zoom);
+ zoom.x = region.x;
+ zoom.y = region.y;
+
+ image_region_t display_region = image_region_create(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT);
+ if (zoom.scale == 1) {
// write directly to image
image_write_direct(image, display, region, display_region);
- return 1;
+ return zoom;
}
- double scale = get_scale_factor(w, h, display_region);
+ double scale = zoom.scale;
// scaling
if (scale < 1) {
@@ 167,5 209,5 @@ double image_write_to_display(image_t *image, display_t *display,
image_write_upscale(image, display, region, display_region, scale);
}
- return scale;
+ return zoom;
}
M image-viewer/src/image_viewer.c => image-viewer/src/image_viewer.c +92 -13
@@ 1,34 1,38 @@
#include "image_viewer.h"
#include "cursor.h"
+#include "direction.h"
#include "display_utils.h"
#include "image.h"
#include "input.h"
#include "logger.h"
#include "image_loader.h"
+#include "coords.h"
#include <time.h>
#include <stdlib.h>
#define COMMANDS_NUM 30
#define CURSOR_SHOW_DURATION 3 // seconds
+#define MAX_ZOOM 10
+#define MIN_ZOOM 0.02
+
image_viewer_t image_viewer_create(char *filename, display_t *display, logger_t *logger) {
image_viewer_t viewer = {
.display = display,
.image = image_create(filename),
.cursor = cursor_create(),
- .region = image_region_create(0, 0, 0, 0),
.logger = logger,
.display_region = image_region_create(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT),
.image_region = image_region_create(0, 0, 0, 0),
- .scale_factor = 0
};
viewer.error = image_loader_load(&viewer.image);
if (viewer.error == IMERR_SUCCESS) {
- viewer.region = viewer.image_region =
+ viewer.image_region =
image_region_create(0, 0, viewer.image.width, viewer.image.height);
- cursor_center(&viewer.cursor, viewer.display_region);
+ viewer.scale = image_get_initial_zoom(&viewer.image);
+ cursor_center(&viewer.cursor, viewer.image_region);
}
return viewer;
@@ 41,13 45,18 @@ void image_viewer_destroy(image_viewer_t *viewer) {
void command_handler_move_cursor(void *data, direction_t direction, int amount) {
image_viewer_t *viewer = (image_viewer_t *)data;
- cursor_hide(&viewer->cursor, viewer->display);
- if (!cursor_move(&viewer->cursor, viewer->display_region, direction, amount)) {
- image_region_move_within(&viewer->region, direction, (int)(amount * viewer->scale_factor), &viewer->display_region);
+ cursor_hide(&viewer->cursor, &viewer->image, viewer->scale, viewer->display);
+ if (!cursor_move(&viewer->cursor,
+ image_get_zoom_region(&viewer->image, viewer->scale),
+ direction, amount / viewer->scale.scale)) {
+ direction_move_xy(direction, (int32_t*)&viewer->scale.x, (int32_t*)&viewer->scale.y, amount / viewer->scale.scale);
+ cursor_move(&viewer->cursor,
+ image_get_zoom_region(&viewer->image, viewer->scale), direction,
+ amount / viewer->scale.scale);
image_viewer_display_image(viewer);
}
- cursor_show(&viewer->cursor, viewer->display);
+ cursor_show(&viewer->cursor, &viewer->image, viewer->scale, viewer->display);
display_render(viewer->display);
}
@@ 79,32 88,102 @@ void command_handler_move_down(void *data, int amount) {
command_handler_move_cursor(data, DOWN, amount);
}
+
void command_handler_exit(void *data, int amount) {
image_viewer_t *viewer = (image_viewer_t *)data;
viewer->running = false;
}
+void zoom(image_viewer_t *viewer, int amount) {
+ double zoom = viewer->scale.scale;
+ double new_zoom = zoom * (1 + amount * 0.05);
+
+ if (new_zoom > MAX_ZOOM) {
+ logger_warn(viewer->logger, __FILE__, __FUNCTION__, __LINE__,
+ "Cannot zoom more than %f", MAX_ZOOM);
+ new_zoom = MAX_ZOOM;
+ }
+
+ if (new_zoom < MIN_ZOOM) {
+ logger_warn(viewer->logger, __FILE__, __FUNCTION__, __LINE__,
+ "Cannot zoom less than %f", MIN_ZOOM);
+ new_zoom = MIN_ZOOM;
+ }
+
+ image_zoom_t tmp = {
+ .scale = new_zoom,
+ .x = viewer->scale.x,
+ .y = viewer->scale.y,
+ };
+
+ image_region_t current_region = image_get_zoom_region(&viewer->image, viewer->scale);
+ image_region_t new_region =
+ image_get_zoom_region(&viewer->image, tmp);
+
+ uint16_t scaled_w = (uint16_t)(zoom * viewer->image.width),
+ scaled_h = (uint16_t)(zoom * viewer->image.height);
+
+ int32_t beg_x = ((double)DISPLAY_WIDTH - (double)(scaled_w)) / 2;
+ int32_t beg_y = ((double)DISPLAY_HEIGHT - (double)(scaled_h)) / 2;
+
+ if (beg_x < 0) {
+ beg_x = 0;
+ }
+
+ if (beg_y < 0) {
+ beg_y = 0;
+ }
+
+ if (scaled_w > DISPLAY_WIDTH) {
+ scaled_w = DISPLAY_WIDTH;
+ }
+
+ if (scaled_h > DISPLAY_HEIGHT) {
+ scaled_h = DISPLAY_HEIGHT;
+ }
+
+ int32_t diff_w = current_region.width - new_region.width;
+ int32_t diff_h = current_region.height - new_region.height;
+
+ double side_percentage_x =
+ (double)(viewer->cursor.x - current_region.x) / current_region.width;
+ double side_percentage_y =
+ (double)(viewer->cursor.y - current_region.y) / current_region.height;
+
+ tmp.x += side_percentage_x * diff_w;
+ tmp.y += side_percentage_y * diff_h;
+ viewer->scale = tmp;
+
+ image_viewer_display_image(viewer);
+ cursor_show(&viewer->cursor, &viewer->image, viewer->scale, viewer->display);
+}
+
// TODO: implement zoom functions
void command_handler_zoom_in(void *data, int amount) {
// hide cursor, zoom, show cursor
image_viewer_t *viewer = (image_viewer_t *)data;
logger_debug(viewer->logger, __FILE__, __FUNCTION__, __LINE__,
"Zooming in by %d", amount);
+
+ zoom(viewer, amount);
}
void command_handler_zoom_out(void *data, int amount) {
image_viewer_t *viewer = (image_viewer_t *)data;
logger_debug(viewer->logger, __FILE__, __FUNCTION__, __LINE__,
"Zooming out by %d", amount);
+
+ zoom(viewer, -amount);
}
void command_handler_zoom_reset(void *data, int amount) {
image_viewer_t *viewer = (image_viewer_t *)data;
logger_debug(viewer->logger, __FILE__, __FUNCTION__, __LINE__,
"Zoom reset by %d", amount);
- viewer->region = image_region_create(0, 0, viewer->image.width, viewer->image.height);
+ viewer->scale = image_get_initial_zoom(&viewer->image);
image_viewer_display_image(viewer);
- cursor_show(&viewer->cursor, viewer->display);
+ cursor_center(&viewer->cursor, viewer->image_region);
+ cursor_show(&viewer->cursor, &viewer->image, viewer->scale, viewer->display);
}
void image_viewer_register_commands(image_viewer_t *viewer, commands_t *commands) {
@@ 155,14 234,14 @@ void image_viewer_start_loop(image_viewer_t *viewer, void *reg_knobs_base) {
now = time(NULL);
if (viewer->cursor.shown && difftime(now, viewer->cursor.shown_at) >= CURSOR_SHOW_DURATION) {
- cursor_hide(&viewer->cursor, viewer->display);
+ cursor_hide(&viewer->cursor, &viewer->image, viewer->scale, viewer->display);
display_render(viewer->display);
}
}
}
void image_viewer_display_image(image_viewer_t *viewer) {
- cursor_hide(&viewer->cursor, viewer->display);
- viewer->scale_factor = image_write_to_display(&viewer->image, viewer->display, viewer->region, viewer->display_region);
+ cursor_hide(&viewer->cursor, &viewer->image, viewer->scale, viewer->display);
+ viewer->scale = image_write_to_display(&viewer->image, viewer->display, viewer->scale);
display_render(viewer->display);
}
M image-viewer/src/input.c => image-viewer/src/input.c +1 -0
@@ 3,6 3,7 @@
#include <stdint.h>
#include <time.h>
#include <unistd.h>
+#include <stdio.h>
#define ROTATION_DELTA 0
#define ENCODERS_MAX 255