~ruther/CTU-FEE-B0B35APO-Semestral-project

ref: e813054aac05d60f94a8f2f1abc2ddadb358da07 CTU-FEE-B0B35APO-Semestral-project/image-viewer/src/image.c -rw-r--r-- 3.9 KiB
e813054a — František Boháček feat: add image downscale using average 3 years ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#include "image.h"
#include "display_utils.h"
#include <stdlib.h>



image_t image_create(char *path) {
  image_t image = {
    .path = path,
    .width = 0,
    .height = 0,
    .pixels = NULL,
    .type = IMG_UNKNOWN,
  };

  return image;
}

void image_destroy(image_t *image) {
  if (image->pixels == NULL) {
    free(image->pixels);
  }
}

image_region_t image_region_create(uint16_t x, uint16_t y, uint16_t width,
                                   uint16_t height) {
  image_region_t region = {
    .x = x,
    .y = y,
    .width = width,
    .height = height,
  };

  return region;
}

bool image_region_move_within(image_region_t *to_move, direction_t direction,
                              int amount, image_region_t *border) {
  uint16_t x = to_move->x;
  uint16_t y = to_move->y;

  if (x < border->x) {
    x = border->x;
  } else if (x + to_move->width >= border->width + border->x) {
    x = border->x + border->width - 1;
  }

  if (y < border->y) {
    y = border->y;
  } else if (y + to_move->height >= border->height + border->y) {
    y = border->x + border->height - 1;
  }

  bool changed = to_move->x != x || to_move->y != y;
  to_move->x = x;
  to_move->y = y;

  return changed;
}

display_pixel_t image_get_pixel(image_t *image, uint16_t x, uint16_t y) {
  return image->pixels[y * image->width + x];
}

void image_set_pixel(image_t *image, uint16_t x, uint16_t y,
                       display_pixel_t pixel) {
  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;
}

bool image_write_to_display(image_t *image, display_t *display,
static void image_write_downscale(image_t *image, display_t *display,
                                  image_region_t region, double scale_factor) {
  float downscale_factor = 1 / scale_factor;
  uint16_t avg_pixels = downscale_factor;
  uint16_t w = region.width, h = region.height;
  uint16_t sw = (uint16_t)(scale_factor * w), sh = (uint16_t)(scale_factor * h);

  unsigned long avg_range = ((unsigned long)downscale_factor);
  if (scale_factor - avg_range >= 0.5) {
    avg_range++;
  }

  uint32_t avg_count = avg_pixels * avg_pixels;
  uint32_t downhalf = downscale_factor / 2;

  uint16_t beg_x = (DISPLAY_WIDTH - sw) / 2;
  uint16_t beg_y = (DISPLAY_HEIGHT - sh) / 2;

  for (int y = 0; y < sh; y++) {
    for (int x = 0; x < sw; x++) {
      uint16_t px = (uint16_t)(downscale_factor * (x + 0.5f)) + region.x;
      uint16_t py = (uint16_t)(downscale_factor * (y + 0.5f)) + region.y;
      raw_pixel_t result = {.red = 0, .green = 0, .blue = 0};

      for (int avg_x = 0; avg_x < avg_pixels; avg_x++) {
        for (int avg_y = 0; avg_y < avg_pixels; avg_y++) {
          display_pixel_t pixel = image_get_pixel(image, px + avg_x - downhalf, py + avg_y - downhalf);

          result.red += pixel.fields.r;
          result.green += pixel.fields.g;
          result.blue += pixel.fields.b;
        }
      }

      result.red /= avg_count;
      result.green /= avg_count;
      result.blue /= avg_count;

      display_pixel_t result_display = {.fields = {.r = result.red, .g = result.green, .b = result.blue}};
      display_set_pixel(display, x + beg_x, y + beg_y, result_display);
    }
  }
}
                            image_region_t region) {
  uint16_t w = region.width, h = region.height;
  uint16_t x = region.x, y = region.y;

  image_region_t display_region = image_region_create(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT);
  double scale = get_scale_factor(w, h, display_region);

  uint16_t sw = (uint16_t)(scale * w), sh = (uint16_t)(scale * h);

  // scaling
  return true;
}
Do not follow this link