1 /*
2 * Copyright © 2016 Jerome Flesch
3 *
4 * Pypillowfight is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, version 2 of the License.
7 *
8 * Pypillowfight is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, see <http://www.gnu.org/licenses/>.
15 */
16
17 #include <assert.h>
18 #include <errno.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22
23 #include <pillowfight/util.h>
24
25 const union pf_pixel g_pf_default_white_pixel = {
26 PF_WHOLE_WHITE,
27 };
28
29 #ifndef NO_PYTHON
30
from_py_buffer(const Py_buffer * buffer,int x,int y)31 struct pf_bitmap from_py_buffer(const Py_buffer *buffer, int x, int y)
32 {
33 struct pf_bitmap out;
34
35 assert(x * y * 4 == buffer->len);
36
37 out.size.x = x;
38 out.size.y = y;
39 out.pixels = buffer->buf;
40
41 return out;
42 }
43
44 #endif
45
46
pf_clear_rect(struct pf_bitmap * img,int left,int top,int right,int bottom)47 void pf_clear_rect(struct pf_bitmap *img, int left, int top, int right, int bottom)
48 {
49 int x;
50 int y;
51
52 if (left < 0)
53 left = 0;
54 if (top < 0)
55 top = 0;
56 if (right > img->size.x)
57 right = img->size.x;
58 if (bottom > img->size.y)
59 bottom = img->size.y;
60
61 for (y = top; y < bottom; y++) {
62 for (x = left; x < right; x++) {
63 PF_SET_PIXEL(img, x, y, PF_WHOLE_WHITE);
64 }
65 }
66 }
67
68
pf_count_pixels_rect(int left,int top,int right,int bottom,int max_brightness,const struct pf_bitmap * img)69 int pf_count_pixels_rect(int left, int top, int right, int bottom,
70 int max_brightness, const struct pf_bitmap *img)
71 {
72 int x;
73 int y;
74 int count = 0;
75 int pixel;
76
77 for (y = top; y <= bottom; y++) {
78 for (x = left; x <= right; x++) {
79 pixel = PF_GET_PIXEL_GRAYSCALE(img, x, y);
80 if ((pixel >= 0) && (pixel <= max_brightness)) {
81 count++;
82 }
83 }
84 }
85 return count;
86 }
87
88
pf_apply_mask(struct pf_bitmap * img,const struct pf_rectangle * mask)89 void pf_apply_mask(struct pf_bitmap *img, const struct pf_rectangle *mask) {
90 int x;
91 int y;
92
93 for (y=0 ; y < img->size.y ; y++) {
94 for (x=0 ; x < img->size.x ; x++) {
95 if (!(PF_IS_IN(x, mask->a.x, mask->b.x)
96 && PF_IS_IN(y, mask->a.y, mask->b.y))) {
97 PF_SET_PIXEL(img, x, y, PF_WHOLE_WHITE);
98 }
99 }
100 }
101 }
102
103
pf_dbl_matrix_new(int x,int y)104 struct pf_dbl_matrix pf_dbl_matrix_new(int x, int y)
105 {
106 struct pf_dbl_matrix out;
107 out.size.x = x;
108 out.size.y = y;
109 out.values = calloc(x * y, sizeof(out.values[0]));
110 return out;
111 }
112
113
pf_dbl_matrix_free(struct pf_dbl_matrix * matrix)114 void pf_dbl_matrix_free(struct pf_dbl_matrix *matrix)
115 {
116 free(matrix->values);
117 }
118
119
pf_dbl_matrix_copy(const struct pf_dbl_matrix * in)120 struct pf_dbl_matrix pf_dbl_matrix_copy(const struct pf_dbl_matrix *in)
121 {
122 struct pf_dbl_matrix out;
123
124 out = pf_dbl_matrix_new(in->size.x, in->size.y);
125 memcpy(out.values, in->values, in->size.x * in->size.y * sizeof(out.values[0]));
126
127 return out;
128 }
129
130
dbl_matrix_transpose(const struct pf_dbl_matrix * in)131 struct pf_dbl_matrix dbl_matrix_transpose(const struct pf_dbl_matrix *in)
132 {
133 struct pf_dbl_matrix out;
134 int x, y;
135 double val;
136
137 out = pf_dbl_matrix_new(in->size.y, in->size.x);
138 for (x = 0 ; x < in->size.x ; x++) {
139 for (y = 0; y < in->size.y ; y++) {
140 val = PF_MATRIX_GET(in, x, y);
141 PF_MATRIX_SET(&out, y, x, val);
142 }
143 }
144
145 return out;
146 }
147
148 /*!
149 * Ref: https://en.wikipedia.org/wiki/Kernel_%28image_processing%29#Convolution
150 * Ref: http://www.songho.ca/dsp/convolution/convolution2d_example.html
151 */
pf_dbl_matrix_convolution(const struct pf_dbl_matrix * img,const struct pf_dbl_matrix * kernel)152 struct pf_dbl_matrix pf_dbl_matrix_convolution(
153 const struct pf_dbl_matrix *img,
154 const struct pf_dbl_matrix *kernel)
155 {
156 struct pf_dbl_matrix out;
157 int img_y, kernel_y;
158 int img_x, kernel_x;
159 double img_val, kernel_val;
160 double val;
161
162 out = pf_dbl_matrix_new(img->size.x, img->size.y);
163
164 for (img_x = 0 ; img_x < img->size.x ; img_x++) {
165 for (img_y = 0 ; img_y < img->size.y ; img_y++) {
166
167 val = 0;
168
169 for (kernel_x = 0 ; kernel_x < kernel->size.x ; kernel_x++) {
170 if (((img_x - kernel_x + (kernel->size.x / 2)) < 0)
171 || ((img_x - kernel_x + (kernel->size.x / 2)) >= img->size.x))
172 break;
173
174 for (kernel_y = 0 ; kernel_y < kernel->size.y ; kernel_y++) {
175
176 if (((img_y - kernel_y + (kernel->size.y / 2)) < 0)
177 || ((img_y - kernel_y + (kernel->size.y / 2)) >= img->size.y))
178 break;
179
180 img_val = PF_MATRIX_GET(
181 img,
182 img_x - kernel_x + (kernel->size.x / 2),
183 img_y - kernel_y + (kernel->size.y / 2)
184 );
185
186 kernel_val = PF_MATRIX_GET(
187 kernel,
188 kernel_x,
189 kernel_y
190 );
191
192 val += (img_val * kernel_val);
193
194 }
195 }
196
197 PF_MATRIX_SET(&out, img_x, img_y, val);
198 }
199 }
200
201 return out;
202 }
203
pf_rgb_bitmap_to_grayscale_dbl_matrix(const struct pf_bitmap * in,struct pf_dbl_matrix * out)204 void pf_rgb_bitmap_to_grayscale_dbl_matrix(const struct pf_bitmap *in, struct pf_dbl_matrix *out)
205 {
206 int x, y;
207 int value;
208
209 assert(out->size.x == in->size.x);
210 assert(out->size.y == in->size.y);
211
212 for (x = 0 ; x < in->size.x ; x++) {
213 for (y = 0 ; y < in->size.y ; y++) {
214 value = PF_GET_PIXEL_GRAYSCALE(in, x, y);
215 PF_MATRIX_SET(
216 out, x, y,
217 value
218 );
219 }
220 }
221 }
222
pf_grayscale_dbl_matrix_to_rgb_bitmap(const struct pf_dbl_matrix * in,struct pf_bitmap * out)223 void pf_grayscale_dbl_matrix_to_rgb_bitmap(const struct pf_dbl_matrix *in, struct pf_bitmap *out)
224 {
225 int x, y;
226 int value;
227
228 assert(out->size.x == in->size.x);
229 assert(out->size.y == in->size.y);
230
231 for (x = 0 ; x < in->size.x ; x++) {
232 for (y = 0 ; y < in->size.y ; y++) {
233 value = PF_MATRIX_GET(in, x, y);
234 if (value < 0)
235 value = 0;
236 if (value >= 256)
237 value = 255;
238 PF_SET_COLOR(out, x, y, COLOR_R, value);
239 PF_SET_COLOR(out, x, y, COLOR_G, value);
240 PF_SET_COLOR(out, x, y, COLOR_B, value);
241 PF_SET_COLOR(out, x, y, COLOR_A, 0xFF);
242 }
243 }
244 }
245
246
pf_bitmap_channel_to_dbl_matrix(const struct pf_bitmap * in,struct pf_dbl_matrix * out,enum pf_color color)247 void pf_bitmap_channel_to_dbl_matrix(
248 const struct pf_bitmap *in, struct pf_dbl_matrix *out, enum pf_color color
249 )
250 {
251 int x, y;
252 int value;
253
254 assert(out->size.x == in->size.x);
255 assert(out->size.y == in->size.y);
256
257 for (x = 0 ; x < in->size.x ; x++) {
258 for (y = 0 ; y < in->size.y ; y++) {
259 value = PF_GET_COLOR(in, x, y, color);
260 PF_MATRIX_SET(
261 out, x, y,
262 value
263 );
264 }
265 }
266 }
267
268
pf_matrix_to_rgb_bitmap(const struct pf_dbl_matrix * in,struct pf_bitmap * out,enum pf_color color)269 void pf_matrix_to_rgb_bitmap(const struct pf_dbl_matrix *in, struct pf_bitmap *out, enum pf_color color)
270 {
271 int x, y;
272 int value;
273
274 assert(out->size.x == in->size.x);
275 assert(out->size.y == in->size.y);
276
277 for (x = 0 ; x < out->size.x ; x++) {
278 for (y = 0 ; y < out->size.y ; y++) {
279 value = PF_MATRIX_GET(in, x, y);
280 if (value < 0)
281 value = 0;
282 if (value >= 256)
283 value = 255;
284 PF_SET_COLOR(out, x, y, color, value);
285 PF_SET_COLOR(out, x, y, COLOR_A, 0xFF);
286 }
287 }
288 }
289
pf_write_bitmap_to_ppm(const char * filepath,const struct pf_bitmap * in)290 void pf_write_bitmap_to_ppm(const char *filepath, const struct pf_bitmap *in)
291 {
292 FILE *fp;
293 int x, y;
294 int pixel;
295
296 fp = fopen(filepath, "w");
297 if (fp == NULL) {
298 fprintf(stderr, "Failed to write [%s]: %d, %s\n",
299 filepath, errno, strerror(errno));
300 }
301
302 fprintf(fp, "P6\n");
303 fprintf(fp, "%d %d\n", in->size.x, in->size.y);
304 fprintf(fp, "255\n");
305
306 for (y = 0 ; y < in->size.y ; y++) {
307 for (x = 0 ; x < in->size.x ; x++) {
308 pixel = PF_GET_PIXEL(in, x, y).whole;
309 fwrite(&pixel, 3, 1, fp);
310 }
311 }
312
313 fclose(fp);
314 }
315
pf_write_matrix_to_pgm(const char * filepath,const struct pf_dbl_matrix * in,double factor)316 void pf_write_matrix_to_pgm(const char *filepath, const struct pf_dbl_matrix *in, double factor)
317 {
318 FILE *fp;
319 int x, y;
320 double val;
321 uint8_t val8;
322
323 fp = fopen(filepath, "w");
324 if (fp == NULL) {
325 fprintf(stderr, "Failed to write [%s]: %d, %s\n",
326 filepath, errno, strerror(errno));
327 }
328
329 fprintf(fp, "P5\n");
330 fprintf(fp, "%d %d\n", in->size.x, in->size.y);
331 fprintf(fp, "255\n");
332
333 for (y = 0 ; y < in->size.y ; y++) {
334 for (x = 0 ; x < in->size.x ; x++) {
335 val = PF_MATRIX_GET(in, x, y);
336 val *= factor;
337 if (val > 255.0)
338 val = 255.0;
339 else if (val < 0)
340 val = 0.0;
341 val8 = val;
342 fwrite(&val8, 1, 1, fp);
343 }
344 }
345
346 fclose(fp);
347 }
348
pf_normalize(const struct pf_dbl_matrix * in,double factor,double out_min,double out_max)349 struct pf_dbl_matrix pf_normalize(const struct pf_dbl_matrix *in, double factor, double out_min, double out_max)
350 {
351 struct pf_dbl_matrix out;
352 int x, y;
353 double val;
354 double in_min = out_min, in_max = out_max;
355
356 if (factor == 0.0) {
357 in_min = MAXDOUBLE;
358 in_max = -MAXDOUBLE;
359 for (x = 0; x < in->size.x ; x++) {
360 for (y = 0 ; y < in->size.y ; y++) {
361 val = PF_MATRIX_GET(in, x, y);
362 in_min = MIN(in_min, val);
363 in_max = MAX(in_max, val);
364 }
365 }
366
367 factor = (out_max - out_min) / (in_max - in_min);
368 }
369
370 out = pf_dbl_matrix_new(in->size.x, in->size.y);
371 for (x = 0; x < in->size.x ; x++) {
372 for (y = 0 ; y < in->size.y ; y++) {
373 val = PF_MATRIX_GET(in, x, y);
374 val -= in_min;
375 val *= factor;
376 val += out_min;
377 PF_MATRIX_SET(&out, x, y, val);
378 }
379 }
380
381 return out;
382 }
383
pf_grayscale_reverse(const struct pf_dbl_matrix * in)384 struct pf_dbl_matrix pf_grayscale_reverse(const struct pf_dbl_matrix *in)
385 {
386 struct pf_dbl_matrix out;
387 int x, y;
388 double val;
389 double in_min, in_max;
390 double factor;
391
392 in_min = DBL_MAX;
393 in_max = -DBL_MAX;
394 for (x = 0; x < in->size.x ; x++) {
395 for (y = 0 ; y < in->size.y ; y++) {
396 val = PF_MATRIX_GET(in, x, y);
397 in_min = MIN(in_min, val);
398 in_max = MAX(in_max, val);
399 }
400 }
401
402 factor = (in_min - in_max) / (in_max - in_min);
403
404 out = pf_dbl_matrix_new(in->size.x, in->size.y);
405 for (x = 0; x < in->size.x ; x++) {
406 for (y = 0 ; y < in->size.y ; y++) {
407 val = PF_MATRIX_GET(in, x, y);
408 val *= factor;
409 val += in_max;
410 PF_MATRIX_SET(&out, x, y, val);
411 }
412 }
413
414 return out;
415 }
416