GCC Code Coverage Report


Directory: src/gate/
File: src/gate/graphics/images.c
Date: 2025-12-12 23:40:09
Exec Total Coverage
Lines: 253 673 37.6%
Functions: 29 54 53.7%
Branches: 71 259 27.4%

Line Branch Exec Source
1 /* GATE PROJECT LICENSE:
2 +----------------------------------------------------------------------------+
3 | Copyright(c) 2018-2025, Stefan Meislinger |
4 | All rights reserved. |
5 | |
6 | Redistribution and use in source and binary forms, with or without |
7 | modification, are permitted provided that the following conditions are met:|
8 | |
9 | 1. Redistributions of source code must retain the above copyright notice, |
10 | this list of conditions and the following disclaimer. |
11 | 2. Redistributions in binary form must reproduce the above copyright |
12 | notice, this list of conditions and the following disclaimer in the |
13 | documentation and/or other materials provided with the distribution. |
14 | |
15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"|
16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
18 | ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
19 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
20 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
21 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
22 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
23 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
24 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
25 | THE POSSIBILITY OF SUCH DAMAGE. |
26 +----------------------------------------------------------------------------+
27 */
28
29 #include "gate/graphics/images.h"
30 #include "gate/memalloc.h"
31 #include "gate/results.h"
32
33 19 static gate_image_databuffer_t* gate_image_databuffer_create(gate_uint32_t bits_per_pixel, gate_uint32_t width, gate_uint32_t height)
34 {
35 19 gate_image_databuffer_t* ret = NULL;
36
37 do
38 {
39 19 unsigned bits_per_line = (unsigned)(width * bits_per_pixel);
40 19 unsigned bytes_per_line = bits_per_line / 8;
41 19 unsigned diff = bits_per_line % 8;
42 19 unsigned padding = 0;
43 gate_uint32_t data_size;
44
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19 times.
19 if (diff != 0)
45 {
46 ++bytes_per_line;
47 }
48 19 diff = bytes_per_line % 4;
49
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 18 times.
19 if (diff != 0)
50 {
51 1 padding = (4 - diff);
52 1 bytes_per_line += padding;
53 }
54
55 19 data_size = (gate_uint32_t)bytes_per_line * height;
56
57 19 ret = (gate_image_databuffer_t*)gate_mem_alloc(sizeof(gate_image_databuffer_t) + data_size);
58
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19 times.
19 if (NULL == ret)
59 {
60 break;
61 }
62 19 gate_mem_clear(ret, sizeof(gate_image_databuffer_t) + data_size);
63 19 gate_atomic_int_init(&ret->ref_counter, 1);
64 19 ret->bits_per_pixel = bits_per_pixel;
65 19 ret->bytes_per_line = bytes_per_line;
66 19 ret->padding_per_line = padding;
67 19 ret->width = width;
68 19 ret->height = height;
69 } while (0);
70
71 19 return ret;
72 }
73
74 2 static gate_int32_t gate_image_databuffer_retain(gate_image_databuffer_t* buffer)
75 {
76 2 gate_int32_t ret = 0;
77
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (buffer)
78 {
79 2 ret = gate_atomic_int_inc(&buffer->ref_counter);
80 }
81 2 return ret;
82 }
83
84 21 static void gate_image_databuffer_release(gate_image_databuffer_t* buffer)
85 {
86
1/2
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
21 if (buffer)
87 {
88
2/2
✓ Branch 1 taken 19 times.
✓ Branch 2 taken 2 times.
21 if (0 == gate_atomic_int_dec(&buffer->ref_counter))
89 {
90 19 gate_mem_dealloc(buffer);
91 }
92 }
93 21 }
94
95
96 1526 static gate_uint8_t* rgba_bgra_get_ptr(gate_uint8_t* data, unsigned width, unsigned height, unsigned line_pad, unsigned x, unsigned y)
97 {
98 1526 const unsigned linelen = width * 4 + line_pad;
99 GATE_UNUSED_ARG(height);
100 1526 return data + (gate_size_t)(y * linelen + x * 4u);
101 }
102 20732 static void rgba_write_pixel(gate_uint8_t* data, gate_color_t const* col)
103 {
104 20732 *((gate_color_t*)data) = *col;
105 20732 }
106 17185 static void rgba_read_pixel(gate_uint8_t const* data, gate_color_t* col)
107 {
108 17185 *col = *((gate_color_t*)data);
109 17185 }
110
111 static void bgra_write_pixel(gate_uint8_t* data, gate_color_t const* col)
112 {
113 data[0] = col->b;
114 data[1] = col->g;
115 data[2] = col->r;
116 data[3] = col->a;
117 }
118 static void bgra_read_pixel(gate_uint8_t const* data, gate_color_t* col)
119 {
120 col->b = data[0];
121 col->g = data[1];
122 col->r = data[2];
123 col->a = data[3];
124 }
125
126 790 static gate_uint8_t* rgb_bgr_get_ptr(gate_uint8_t* data, unsigned width, unsigned height, unsigned line_pad, unsigned x, unsigned y)
127 {
128 790 const unsigned linelen = width * 3 + line_pad;
129 GATE_UNUSED_ARG(height);
130 790 return data + (gate_size_t)y * linelen + (gate_size_t)x * 3u;
131 }
132 10870 static void rgb_write_pixel(gate_uint8_t* data, gate_color_t const* col)
133 {
134 10870 data[0] = col->r;
135 10870 data[1] = col->g;
136 10870 data[2] = col->b;
137 10870 }
138 630 static void rgb_read_pixel(gate_uint8_t const* data, gate_color_t* col)
139 {
140 630 col->r = data[0];
141 630 col->g = data[1];
142 630 col->b = data[2];
143 630 }
144 static void bgr_write_pixel(gate_uint8_t* data, gate_color_t const* col)
145 {
146 data[0] = col->b;
147 data[1] = col->g;
148 data[2] = col->r;
149 }
150 static void bgr_read_pixel(gate_uint8_t const* data, gate_color_t* col)
151 {
152 col->b = data[0];
153 col->g = data[1];
154 col->r = data[2];
155 }
156
157 static gate_uint8_t* col16_get_ptr(gate_uint8_t* data, unsigned width, unsigned height, unsigned line_pad, unsigned x, unsigned y)
158 {
159 const unsigned linelen = width * 2 + line_pad;
160 GATE_UNUSED_ARG(height);
161 return data + (gate_size_t)y * linelen + (gate_size_t)x * 2u;
162 }
163 static void rgb555_write_pixel(gate_uint8_t* data, gate_color_t const* col)
164 {
165 unsigned num = ((unsigned)(col->r >> 3)) << 10
166 | ((unsigned)(col->g >> 3)) << 5
167 | ((unsigned)(col->b >> 3));
168 data[0] = (gate_uint8_t)(num & 0xff);
169 data[1] = (gate_uint8_t)(num >> 8);
170 }
171 static void rgb555_read_pixel(gate_uint8_t const* data, gate_color_t* col)
172 {
173 static unsigned short const red_mask = 0x7C00;
174 static unsigned short const green_mask = 0x3E0;
175 static unsigned short const blue_mask = 0x1F;
176
177 unsigned short pixel = (unsigned)data[0] | (((unsigned)data[1]) << 8);
178
179 unsigned short r = (pixel & red_mask) >> 10;
180 unsigned short g = (pixel & green_mask) >> 5;
181 unsigned short b = (pixel & blue_mask);
182
183 col->r = (gate_uint8_t)((r << 3) | (r >> 2));
184 col->g = (gate_uint8_t)((g << 3) | (g >> 2));
185 col->b = (gate_uint8_t)((b << 3) | (b >> 2));
186 col->a = 255;
187 }
188 static void rgb565_write_pixel(gate_uint8_t* data, gate_color_t const* col)
189 {
190 unsigned num = ((unsigned)(col->r >> 3)) << 11
191 | ((unsigned)(col->g >> 2)) << 5
192 | ((unsigned)(col->b >> 3));
193 data[0] = (gate_uint8_t)(num & 0xff);
194 data[1] = (gate_uint8_t)(num >> 8);
195 }
196 static void rgb565_read_pixel(gate_uint8_t const* data, gate_color_t* col)
197 {
198 static unsigned short const red_mask = 0xF800;
199 static unsigned short const green_mask = 0x7E0;
200 static unsigned short const blue_mask = 0x1F;
201
202 unsigned short pixel = (unsigned)data[0] | (((unsigned)data[1]) << 8);
203
204 unsigned short r = (pixel & red_mask) >> 11;
205 unsigned short g = (pixel & green_mask) >> 5;
206 unsigned short b = (pixel & blue_mask);
207
208 col->r = (gate_uint8_t)((r << 3) | (r >> 2));
209 col->g = (gate_uint8_t)((g << 2) | (g >> 4));
210 col->b = (gate_uint8_t)((b << 3) | (b >> 2));
211 col->a = 255;
212 }
213 static void argb4_write_pixel(gate_uint8_t* data, gate_color_t const* col)
214 {
215 unsigned pixel = ((unsigned)(col->a & 0xF0)) << 8
216 | ((unsigned)(col->r & 0xF0)) << 4
217 | ((unsigned)(col->g & 0xF0))
218 | ((unsigned)(col->b & 0xF0)) >> 4;
219 data[0] = (gate_uint8_t)(pixel & 0xff);
220 data[1] = (gate_uint8_t)(pixel >> 8);
221 }
222 static void argb4_read_pixel(gate_uint8_t const* data, gate_color_t* col)
223 {
224 static unsigned short const alpha_mask = 0xF000;
225 static unsigned short const red_mask = 0x0F00;
226 static unsigned short const green_mask = 0x00F0;
227 static unsigned short const blue_mask = 0x000F;
228
229 unsigned short pixel = (unsigned)data[0] | (((unsigned)data[1]) << 8);
230 unsigned short a = (pixel & alpha_mask) >> 8;
231 unsigned short r = (pixel & red_mask) >> 4;
232 unsigned short g = (pixel & green_mask);
233 unsigned short b = (pixel & blue_mask) << 4;
234 col->r = (gate_uint8_t)(r | (r >> 4));
235 col->g = (gate_uint8_t)(g | (g >> 4));
236 col->b = (gate_uint8_t)(b | (b >> 4));
237 col->a = (gate_uint8_t)(a | (a >> 4));
238 }
239 static void yuv2_write_pixel(gate_uint8_t* data, gate_color_t const* col)
240 {
241 data[0] = col->b;
242 data[1] = col->g;
243 data[2] = col->r;
244 }
245 static void yuv2_read_pixel(gate_uint8_t const* data, gate_color_t* col)
246 {
247 col->b = data[0];
248 col->g = data[1];
249 col->r = data[2];
250 }
251 7700 static gate_uint8_t* col8_get_ptr(gate_uint8_t* data, unsigned width, unsigned height, unsigned line_pad, unsigned x, unsigned y)
252 {
253 7700 const unsigned linelen = width + line_pad;
254 GATE_UNUSED_ARG(height);
255 7700 return data + (gate_size_t)y * linelen + (gate_size_t)x;
256 }
257 static void pal8_write_pixel(gate_uint8_t* data, gate_color_t const* col)
258 {
259 unsigned r = (((unsigned)col->r) + 25) / 51;
260 unsigned g = (((unsigned)col->g) + 25) / 51;
261 unsigned b = (((unsigned)col->b) + 25) / 51;
262 data[0] = (gate_uint8_t)(16 + (r * 36 + g * 6 + b));
263 }
264 static void pal8_read_pixel(gate_uint8_t const* data, gate_color_t* col)
265 {
266 unsigned index = ((unsigned)*data);
267 if (index >= 16)
268 {
269 index -= 16;
270 col->r = (gate_uint8_t)((index / 36) * 51);
271 col->g = (gate_uint8_t)(((index % 36) / 6) * 51);
272 col->b = (gate_uint8_t)(((index % 36) % 6) * 51);
273 col->a = 255u;
274 }
275 }
276 7591 static void gray_write_pixel(gate_uint8_t* data, gate_color_t const* col)
277 {
278 7591 data[0] = (gate_uint8_t)(((unsigned)col->b + (unsigned)col->g + (unsigned)col->r) / 3);
279 7591 }
280 135 static void gray_read_pixel(gate_uint8_t const* data, gate_color_t* col)
281 {
282 135 col->r = col->g = col->b = data[0];
283 135 }
284
285
286 32 gate_rasterimage_t* gate_rasterimage_create(gate_rasterimage_t* image, gate_enumint_t pixel_format,
287 unsigned width, unsigned height,
288 gate_color_t const* copypixels)
289 {
290 32 gate_rasterimage_t* ret = NULL;
291
292 do
293 {
294 32 gate_rasterimage_get_ptr_t get_ptr = NULL;
295 32 gate_rasterimage_write_pixel_t write_pixel = NULL;
296 32 gate_rasterimage_read_pixel_t read_pixel = NULL;
297 32 unsigned bits_per_pixel = 0;
298 32 unsigned bytes_per_line = 0;
299 32 gate_bool_t direct_copy = false;
300
301
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32 times.
32 if (image == NULL)
302 {
303 break;
304 }
305
306
3/4
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 19 times.
32 if ((width == 0) || (height == 0))
307 {
308 13 gate_mem_clear(image, sizeof(gate_rasterimage_t));
309 13 ret = image;
310 13 break;
311 }
312
5/12
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 times.
✓ Branch 10 taken 2 times.
✗ Branch 11 not taken.
19 switch (pixel_format)
313 {
314 4 case GATE_IMAGE_PIXELFORMAT_DEFAULT:
315 {
316 4 pixel_format = GATE_IMAGE_PIXELFORMAT_RGB32;
317 /* fall-through desired! */
318 }
319 11 case GATE_IMAGE_PIXELFORMAT_RGB32:
320 case GATE_IMAGE_PIXELFORMAT_RGBA:
321 {
322 11 get_ptr = &rgba_bgra_get_ptr;
323 11 read_pixel = &rgba_read_pixel;
324 11 write_pixel = &rgba_write_pixel;
325 11 bits_per_pixel = 32;
326 11 direct_copy = true;
327 11 break;
328 }
329 case GATE_IMAGE_PIXELFORMAT_BGR32:
330 case GATE_IMAGE_PIXELFORMAT_BGRA:
331 {
332 get_ptr = &rgba_bgra_get_ptr;
333 read_pixel = &bgra_read_pixel;
334 write_pixel = &bgra_write_pixel;
335 bits_per_pixel = 32;
336 direct_copy = true;
337 break;
338 }
339
340 5 case GATE_IMAGE_PIXELFORMAT_RGB24:
341 {
342 5 get_ptr = &rgb_bgr_get_ptr;
343 5 read_pixel = &rgb_read_pixel;
344 5 write_pixel = &rgb_write_pixel;
345 5 bits_per_pixel = 24;
346 5 direct_copy = true;
347 5 break;
348 }
349 case GATE_IMAGE_PIXELFORMAT_BGR24:
350 {
351 get_ptr = &rgb_bgr_get_ptr;
352 read_pixel = &bgr_read_pixel;
353 write_pixel = &bgr_write_pixel;
354 bits_per_pixel = 24;
355 direct_copy = true;
356 break;
357 }
358
359 case GATE_IMAGE_PIXELFORMAT_RGB555:
360 {
361 get_ptr = &col16_get_ptr;
362 read_pixel = &rgb555_read_pixel;
363 write_pixel = &rgb555_write_pixel;
364 bits_per_pixel = 16;
365 direct_copy = true;
366 break;
367 }
368 case GATE_IMAGE_PIXELFORMAT_RGB565:
369 {
370 get_ptr = &col16_get_ptr;
371 read_pixel = &rgb565_read_pixel;
372 write_pixel = &rgb565_write_pixel;
373 bits_per_pixel = 16;
374 direct_copy = true;
375 break;
376 }
377 case GATE_IMAGE_PIXELFORMAT_ARGB4:
378 {
379 get_ptr = &col16_get_ptr;
380 read_pixel = &argb4_read_pixel;
381 write_pixel = &argb4_write_pixel;
382 bits_per_pixel = 16;
383 direct_copy = true;
384 break;
385 }
386 case GATE_IMAGE_PIXELFORMAT_YUV2:
387 {
388 get_ptr = &col16_get_ptr;
389 read_pixel = &yuv2_read_pixel;
390 write_pixel = &yuv2_write_pixel;
391 bits_per_pixel = 16;
392 direct_copy = true;
393 break;
394 }
395
396 1 case GATE_IMAGE_PIXELFORMAT_PAL8:
397 {
398 1 get_ptr = &col8_get_ptr;
399 1 read_pixel = &pal8_read_pixel;
400 1 write_pixel = &pal8_write_pixel;
401 1 bits_per_pixel = 8;
402 1 direct_copy = true;
403 1 break;
404 }
405 2 case GATE_IMAGE_PIXELFORMAT_GRAY8:
406 {
407 2 get_ptr = &col8_get_ptr;
408 2 read_pixel = &gray_read_pixel;
409 2 write_pixel = &gray_write_pixel;
410 2 bits_per_pixel = 8;
411 2 direct_copy = true;
412 2 break;
413 }
414
415 default:
416 return NULL;
417 }
418
419 19 image->databuffer = gate_image_databuffer_create(bits_per_pixel, width, height);
420
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19 times.
19 if (image->databuffer == NULL)
421 {
422 break;
423 }
424
425 19 image->width = width;
426 19 image->height = height;
427 19 image->bits_per_pixel = (gate_uint16_t)(image->databuffer->bits_per_pixel);
428 19 image->line_padding = (gate_uint16_t)(image->databuffer->padding_per_line);
429 19 bytes_per_line = image->databuffer->bytes_per_line;
430 19 image->pixel_format = (gate_uint16_t)pixel_format;
431 19 image->pixel_length = (gate_uint16_t)((image->databuffer->bits_per_pixel + 7) / 8);
432 19 image->get_ptr = get_ptr;
433 19 image->read_pixel = read_pixel;
434 19 image->write_pixel = write_pixel;
435 19 image->data = &image->databuffer->data[0];
436
437
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19 times.
19 if (copypixels)
438 {
439 if (direct_copy)
440 {
441 gate_mem_copy(image->data, copypixels, (gate_size_t)bytes_per_line * height);
442 }
443 else
444 {
445 unsigned y;
446 for (y = 0; y < height; ++y)
447 {
448 unsigned x;
449 for (x = 0; x < width; ++x)
450 {
451 gate_uint8_t* ptr_data = image->get_ptr(image->data, image->width, image->height, image->line_padding, x, y);
452 image->write_pixel(ptr_data, copypixels);
453 ++copypixels;
454 }
455 }
456 }
457 }
458 19 ret = image;
459 } while (0);
460 32 return ret;
461 }
462
463
464 27 void gate_rasterimage_release(gate_rasterimage_t* image)
465 {
466
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 6 times.
27 if (image->databuffer)
467 {
468 21 gate_image_databuffer_release(image->databuffer);
469 }
470 27 gate_mem_clear(image, sizeof(gate_rasterimage_t));
471 27 }
472
473 2 gate_rasterimage_t* gate_rasterimage_duplicate(gate_rasterimage_t* dest_image, gate_rasterimage_t const* src_image)
474 {
475 2 gate_mem_copy(dest_image, src_image, sizeof(gate_rasterimage_t));
476 2 gate_image_databuffer_retain(dest_image->databuffer);
477 2 return dest_image;
478 }
479 gate_rasterimage_t* gate_rasterimage_copy(gate_rasterimage_t* dest_image, gate_rasterimage_t const* src_image)
480 {
481 gate_rasterimage_t* ret = gate_rasterimage_create(dest_image, src_image->pixel_format, src_image->width, src_image->height, NULL);
482 if (ret)
483 {
484 gate_size_t const line_length = (src_image->bits_per_pixel * src_image->width + 7) / 8;
485 unsigned y;
486 for (y = 0; y != src_image->height; ++y)
487 {
488 gate_uint8_t const* ptr_src = src_image->get_ptr(src_image->data, src_image->width, src_image->height, src_image->line_padding, 0, y);
489 gate_uint8_t* ptr_dest = dest_image->get_ptr(dest_image->data, dest_image->width, dest_image->height, src_image->line_padding, 0, y);
490 gate_mem_copy(ptr_dest, ptr_src, line_length);
491 }
492 }
493 return ret;
494 }
495
496 gate_rasterimage_t* gate_rasterimage_convert(gate_rasterimage_t* dest_image, gate_enumint_t pixel_format, gate_rasterimage_t const* src_image)
497 {
498 gate_rasterimage_t* ret = NULL;
499
500 ret = gate_rasterimage_create(dest_image, pixel_format, src_image->width, src_image->height, NULL);
501 if (ret != NULL)
502 {
503 unsigned const src_pixel_len = src_image->pixel_length;
504 unsigned const dest_pixel_len = dest_image->pixel_length;
505 unsigned y;
506
507 for (y = 0; y != src_image->height; ++y)
508 {
509 unsigned x;
510 gate_uint8_t* ptr_src = src_image->get_ptr(src_image->data, src_image->width, src_image->height, src_image->line_padding, 0, y);
511 gate_uint8_t* ptr_dest = dest_image->get_ptr(dest_image->data, dest_image->width, dest_image->height, dest_image->line_padding, 0, y);
512
513 for (x = 0; x != src_image->width; ++x)
514 {
515 gate_color_t col;
516 src_image->read_pixel(ptr_src, &col);
517 dest_image->write_pixel(ptr_dest, &col);
518 ptr_src += src_pixel_len;
519 ptr_dest += dest_pixel_len;
520 }
521 }
522 }
523 return ret;
524 }
525
526 gate_result_t gate_rasterimage_subset(gate_rasterimage_t* dest_image, gate_rasterimage_t const* src_image, unsigned x, unsigned y, unsigned width, unsigned height)
527 {
528 unsigned ny;
529
530 if (!dest_image || !src_image)
531 {
532 return GATE_RESULT_INVALIDARG;
533 }
534
535 if (x >= src_image->width) return GATE_RESULT_INVALIDARG;
536 if (y >= src_image->height) return GATE_RESULT_INVALIDARG;
537 if ((x + width) > src_image->width) width = src_image->width - (x + width);
538 if ((y + height) > src_image->height) height = src_image->height - (x + height);
539
540 if ((x == 0) && (width == src_image->width))
541 {
542 /* try a line-based slice */
543 gate_mem_copy(dest_image, src_image, sizeof(gate_rasterimage_t));
544 dest_image->width = width;
545 dest_image->height = height;
546 if (dest_image->databuffer)
547 {
548 gate_image_databuffer_retain(dest_image->databuffer);
549 }
550 dest_image->data = (gate_uint8_t*)gate_rasterimage_get_line_ptr(src_image, y);
551 return GATE_RESULT_OK;
552 }
553
554 if (src_image->bits_per_pixel >= 8)
555 {
556 gate_uint8_t const* end_line;
557 gate_uint8_t const* next_line;
558 /* try to build a padded subset image */
559 gate_mem_copy(dest_image, src_image, sizeof(gate_rasterimage_t));
560 dest_image->width = width;
561 dest_image->height = height;
562 if (dest_image->databuffer)
563 {
564 gate_image_databuffer_retain(dest_image->databuffer);
565 }
566 end_line = (gate_uint8_t const*)gate_rasterimage_get_pixel_ptr(src_image, x + width - 1, 0);
567 next_line = (gate_uint8_t const*)gate_rasterimage_get_pixel_ptr(src_image, x, 1);
568 dest_image->data = (gate_uint8_t*)gate_rasterimage_get_pixel_ptr(src_image, x, y);
569 dest_image->line_padding = (gate_uint16_t)((unsigned)(next_line - end_line)) - src_image->pixel_length;
570 return GATE_RESULT_OK;
571 }
572
573 /* create a new image with a copy of the subset */
574 if (NULL == gate_rasterimage_create(dest_image, src_image->pixel_format, width, height, NULL))
575 {
576 return GATE_RESULT_OUTOFMEMORY;
577 }
578 for (ny = y; ny < height; ++ny)
579 {
580 void const* ptr_src = gate_rasterimage_get_pixel_ptr(src_image, x, ny);
581 void* ptr_dst = gate_rasterimage_get_pixel_ptr(dest_image, 0, ny - y);
582 unsigned len = (((unsigned)src_image->bits_per_pixel * width + 7) / 8);
583 gate_mem_copy(ptr_dst, ptr_src, len);
584 }
585 return GATE_RESULT_OK;
586 }
587
588
589
590 284 void* gate_rasterimage_get_line_ptr(gate_rasterimage_t const* image, unsigned y)
591 {
592 284 gate_size_t line_width = (gate_size_t)(image->bits_per_pixel / 8) * (gate_size_t)image->width;
593 284 gate_uint8_t* ptr = NULL;
594
1/2
✓ Branch 0 taken 284 times.
✗ Branch 1 not taken.
284 if (y < image->height)
595 {
596 284 ptr = image->data + (line_width + image->line_padding) * y;
597 }
598 284 return (void*)ptr;
599 }
600
601 1 gate_enumint_t gate_rasterimage_format(gate_rasterimage_t const* image)
602 {
603
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (image != NULL)
604 {
605 1 return image->pixel_format;
606 }
607 else
608 {
609 return GATE_IMAGE_PIXELFORMAT_UNKNOWN;
610 }
611 }
612
613 17 unsigned int gate_rasterimage_width(gate_rasterimage_t const* image)
614 {
615 17 unsigned int ret = 0;
616
1/2
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
17 if (image != NULL)
617 {
618 17 ret = image->width;
619 }
620 17 return ret;
621 }
622
623 17 unsigned int gate_rasterimage_height(gate_rasterimage_t const* image)
624 {
625 17 unsigned int ret = 0;
626
1/2
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
17 if (image != NULL)
627 {
628 17 ret = image->height;
629 }
630 17 return ret;
631 }
632
633 void* gate_rasterimage_get_pixel_ptr(gate_rasterimage_t const* image, unsigned x, unsigned y)
634 {
635 if (image && image->get_ptr)
636 {
637 return image->get_ptr(image->data, image->width, image->height, image->line_padding, x, y);
638 }
639 return NULL;
640 }
641
642 879 gate_result_t gate_rasterimage_get_pixel(gate_rasterimage_t const* image, unsigned x, unsigned y, gate_color_t* out_pixel)
643 {
644 gate_uint8_t* ptr_pixel;
645
5/10
✓ Branch 0 taken 879 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 879 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 879 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 879 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 879 times.
879 if (!image || !image->read_pixel || !out_pixel || (x > image->width) || (y > image->height))
646 {
647 return GATE_RESULT_INVALIDARG;
648 }
649 879 ptr_pixel = image->get_ptr(image->data, image->width, image->height, image->line_padding, x, y);
650 879 image->read_pixel(ptr_pixel, out_pixel);
651 879 return GATE_RESULT_OK;
652 }
653
654 7565 gate_result_t gate_rasterimage_set_pixel(gate_rasterimage_t* image, unsigned x, unsigned y, gate_color_t const* pixel)
655 {
656 gate_uint8_t* ptr_pixel;
657
5/10
✓ Branch 0 taken 7565 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7565 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7565 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 7565 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 7565 times.
7565 if (!image || !image->write_pixel || !pixel || (x > image->width) || (y > image->height))
658 {
659 return GATE_RESULT_INVALIDARG;
660 }
661 7565 ptr_pixel = image->get_ptr(image->data, image->width, image->height, image->line_padding, x, y);
662 7565 image->write_pixel(ptr_pixel, pixel);
663 7565 return GATE_RESULT_OK;
664 }
665
666 gate_result_t gate_rasterimage_paste_image(gate_rasterimage_t* dst_image, gate_rasterimage_t const* src_image,
667 int dst_x, int dst_y,
668 int src_x, int src_y,
669 int width, int height,
670 gate_bool_t transparent)
671 {
672 gate_result_t ret = GATE_RESULT_OK;
673
674 do
675 {
676 int dst_width = (int)dst_image->width;
677 int dst_height = (int)dst_image->height;
678 int src_width = (int)src_image->width;
679 int src_height = (int)src_image->height;
680 int x_offset = 0;
681 int y_offset = 0;
682 int x_len = 0;
683 int y_len = 0;
684 int x, y;
685 unsigned src_pixel_length;
686 unsigned dst_pixel_length;
687 gate_bool_t equal_format;
688
689 /* source x/y outside of real source image*/
690 if (src_x >= src_width) break;
691 if (src_y >= src_height) break;
692
693 if (width > 0) width = src_width; else width += src_width;
694 if (height > 0) height = src_height; else height += src_height;
695
696 if (src_x < 0)
697 {
698 width += src_x;
699 src_x = 0;
700 }
701 if (src_y < 0)
702 {
703 height += src_y;
704 src_y = 0;
705 }
706
707 if (src_x + width < 0) break;
708 if (src_y + height < 0) break;
709 if (src_x + width > src_width) width = src_width - src_x;
710 if (src_y + height > src_height) height = src_height - src_y;
711
712 if (dst_x > dst_width) break;
713 if (dst_y > dst_height) break;
714 if (dst_x + width < 0) break;
715 if (dst_y + height < 0) break;
716
717 if (dst_x < 0)
718 {
719 x_offset = -dst_x;
720 width += dst_x;
721 dst_x = 0;
722 }
723 if (dst_y < 0)
724 {
725 y_offset = -dst_y;
726 height += dst_y;
727 dst_y = 0;
728 }
729
730 if (dst_x + width > dst_width) width = dst_width - dst_x;
731 if (dst_y + height > dst_height) height = dst_height - dst_y;
732
733 x_len = (int)width;
734 y_len = (int)height;
735
736 src_pixel_length = src_image->pixel_length;
737 dst_pixel_length = dst_image->pixel_length;
738
739 equal_format = (src_pixel_length == dst_pixel_length)
740 && (src_image->pixel_format == dst_image->pixel_format);
741
742 for (y = 0; y != y_len; ++y)
743 {
744 gate_uint8_t* src_data = src_image->get_ptr(src_image->data,
745 src_image->width, src_image->height, src_image->line_padding, x_offset + src_x, y + src_y + y_offset);
746 gate_uint8_t* dst_data = dst_image->get_ptr(dst_image->data,
747 dst_image->width, dst_image->height, dst_image->line_padding, dst_x, y + dst_y);
748
749 if (equal_format && !transparent)
750 {
751 /* optimized mem-copy */
752 gate_mem_copy(dst_data, src_data, (gate_size_t)x_len * src_pixel_length);
753 }
754 else
755 {
756 /* transform pixel by pixel */
757 for (x = 0; x != x_len; ++x)
758 {
759 gate_color_t col;
760 src_image->read_pixel(src_data, &col);
761 dst_image->write_pixel(dst_data, &col);
762 src_data += src_pixel_length;
763 dst_data += dst_pixel_length;
764 }
765 }
766 }
767
768 } while (0);
769
770 return ret;
771 }
772
773
774 3 gate_bool_t gate_rasterimage_is_empty(gate_rasterimage_t const* image)
775 {
776
4/6
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
3 return (image->width == 0) || (image->height == 0) || (image->data == NULL);
777 }
778
779
780 gate_result_t gate_rasterimage_to_grayscale(gate_rasterimage_t* image)
781 {
782 gate_result_t ret = GATE_RESULT_OK;
783 unsigned const width = image->width;
784 unsigned const height = image->height;
785 unsigned const pixellength = image->pixel_length;
786 unsigned y;
787
788 for (y = 0; y != height; ++y)
789 {
790 unsigned x;
791 gate_uint8_t* ptrpixel = image->get_ptr(image->data, width, height, image->line_padding, 0, y);
792 for (x = image->width; x != 0; --x)
793 {
794 gate_color_t col;
795 gate_uint8_t gray;
796 image->read_pixel(ptrpixel, &col);
797 gray = gate_color_to_grayscale(&col);
798 col.r = gray;
799 col.g = gray;
800 col.b = gray;
801 image->write_pixel(ptrpixel, &col);
802 ptrpixel += pixellength;
803 }
804 }
805 return ret;
806 }
807
808 static void update_pixel(gate_rasterimage_t* image, gate_uint8_t* ptrpixel, int value)
809 {
810 gate_color_t col;
811 int oldvalue;
812 int newvalue;
813
814 image->read_pixel(ptrpixel, &col);
815 oldvalue = ((int)col.r + (int)col.g + (int)col.b) / 3;
816 newvalue = (int)oldvalue + value;
817 if (newvalue < 0) newvalue = 0;
818 if (newvalue > 255) newvalue = 0;
819 col.r = (gate_uint8_t)newvalue;
820 col.g = (gate_uint8_t)newvalue;
821 col.b = (gate_uint8_t)newvalue;
822 image->write_pixel(ptrpixel, &col);
823 }
824
825 gate_result_t gate_rasterimage_to_monochrome(gate_rasterimage_t* image)
826 {
827 gate_result_t ret = GATE_RESULT_OK;
828 gate_size_t pixelcount;
829 gate_uint8_t* ptrpixel /*= image->get_ptr(image->data, image->width, image->height, image->line_padding, 0, 0)*/;
830 gate_uint8_t* ptrpixel1 /*= image->get_ptr(image->data, image->width, image->height, image->line_padding, 1, 0)*/;
831 gate_uint8_t* ptrpixel4 /*= image->get_ptr(image->data, image->width, image->height, image->line_padding, 1, 1)*/;
832 gate_uint8_t* ptrpixel3 /*= image->get_ptr(image->data, image->width, image->height, image->line_padding, 1, 0)*/;
833 gate_uint8_t* ptrpixel2 /*= image->get_ptr(image->data, image->width, image->height, image->line_padding, image->width - 1, 0)*/;
834 gate_uint64_t pixelsum = 0;
835 gate_uint8_t avgpixel;
836 unsigned x, y;
837 unsigned const pixel_length = image->pixel_length;
838 gate_color_t col;
839
840 for (y = 0; y != image->height; ++y)
841 {
842 ptrpixel = image->get_ptr(image->data, image->width, image->height, image->line_padding, 0, y);
843 for (x = 0; x != image->width; ++x)
844 {
845 image->read_pixel(ptrpixel, &col);
846 pixelsum += ((gate_uint16_t)col.r + (gate_uint16_t)col.g + (gate_uint16_t)col.b) / 3;
847 ptrpixel += pixel_length;
848 }
849 }
850
851 pixelcount = (gate_size_t)image->width * (gate_size_t)image->height;
852 avgpixel = (gate_uint8_t)(pixelsum / (gate_uint64_t)pixelcount);
853 if (avgpixel < 64) avgpixel = 64;
854 if (avgpixel > 192) avgpixel = 192;
855 ptrpixel = image->get_ptr(image->data, image->width, image->height, image->line_padding, 0, 0);
856
857 update_pixel(image, ptrpixel, 0); /* make first pixel gray-scale */
858
859 for (y = 0; y != image->height; ++y)
860 {
861 ptrpixel = image->get_ptr(image->data, image->width, image->height, image->line_padding, 0, y);
862 ptrpixel1 = ptrpixel + pixel_length;
863 ptrpixel3 = image->get_ptr(image->data, image->width, image->height, image->line_padding, 0, y + 1);
864 ptrpixel2 = ptrpixel3 - pixel_length;
865 ptrpixel4 = ptrpixel3 + pixel_length;
866
867 for (x = 0; x != image->width; ++x)
868 {
869 gate_uint8_t curpixel;
870 gate_uint8_t newpixel;
871 int qerror;
872
873 image->read_pixel(ptrpixel, &col);
874 curpixel = col.r; /* all color-values are already equal*/
875 if (curpixel < avgpixel)
876 {
877 newpixel = 0;
878 }
879 else
880 {
881 newpixel = 255;
882 }
883 col.r = col.g = col.b = newpixel;
884 image->write_pixel(ptrpixel, &col);
885 qerror = curpixel - newpixel;
886
887
888 if ((y != image->height - 1) && (x != image->width - 1))
889 {
890 update_pixel(image, ptrpixel1, qerror * 7 / 16);
891 }
892
893 if (y != image->height - 1)
894 {
895 update_pixel(image, ptrpixel2, qerror * 3 / 16);
896 update_pixel(image, ptrpixel3, qerror * 5 / 16);
897 if ((y != image->height - 2) && (x != image->width - 1))
898 {
899 update_pixel(image, ptrpixel4, qerror * 1 / 16);
900 }
901 }
902
903 ptrpixel += pixel_length;
904 ptrpixel1 += pixel_length;
905 ptrpixel2 += pixel_length;
906 ptrpixel3 += pixel_length;
907 ptrpixel4 += pixel_length;
908 }
909 }
910 return ret;
911 }
912
913 static void gate_rasterimage_clear_pal8(gate_rasterimage_t* dest, gate_color_t const* clear_color)
914 {
915 gate_size_t line_len = (gate_size_t)dest->pixel_length * (gate_size_t)dest->width + dest->line_padding;
916 gate_size_t buffer_len = line_len * (gate_size_t)dest->height;
917 gate_uint8_t pix;
918 pal8_write_pixel(&pix, clear_color);
919 gate_mem_fill(dest->data, (char)pix, buffer_len);
920 }
921 2 static void gate_rasterimage_clear_gray8(gate_rasterimage_t* dest, gate_color_t const* clear_color)
922 {
923 2 gate_size_t line_len = (gate_size_t)dest->pixel_length * (gate_size_t)dest->width + dest->line_padding;
924 2 gate_size_t buffer_len = line_len * (gate_size_t)dest->height;
925 gate_uint8_t pix;
926 2 gray_write_pixel(&pix, clear_color);
927 2 gate_mem_fill(dest->data, (char)pix, buffer_len);
928 2 }
929
930 8 gate_result_t gate_rasterimage_clear(gate_rasterimage_t* dest, gate_color_t const* clear_color)
931 {
932 8 unsigned const width = dest->width;
933 8 unsigned const height = dest->height;
934 8 unsigned const pixel_length = dest->pixel_length;
935 gate_color_t col;
936
937
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 if (clear_color)
938 {
939 8 col = *clear_color;
940 }
941 else
942 {
943 gate_mem_clear(&col, sizeof(gate_color_t));
944 }
945
946
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 6 times.
8 switch (dest->pixel_format)
947 {
948 case GATE_IMAGE_PIXELFORMAT_PAL8:
949 {
950 gate_rasterimage_clear_pal8(dest, &col);
951 break;
952 }
953 2 case GATE_IMAGE_PIXELFORMAT_GRAY8:
954 {
955 2 gate_rasterimage_clear_gray8(dest, &col);
956 2 break;
957 }
958 6 default:
959 {
960 unsigned y;
961 /* generic implementation */
962
2/2
✓ Branch 0 taken 224 times.
✓ Branch 1 taken 6 times.
230 for (y = 0; y != height; ++y)
963 {
964 unsigned x;
965 224 gate_uint8_t* ptr = dest->get_ptr(dest->data, width, height, dest->line_padding, 0, y);
966
2/2
✓ Branch 0 taken 14336 times.
✓ Branch 1 taken 224 times.
14560 for (x = 0; x != width; ++x)
967 {
968 14336 dest->write_pixel(ptr, &col);
969 14336 ptr += pixel_length;
970 }
971 }
972 6 break;
973 }
974 }
975 8 return GATE_RESULT_OK;
976 }
977
978
979 1 gate_result_t gate_rasterimage_rotate_left(gate_rasterimage_t* dst, gate_rasterimage_t const* src)
980 {
981 unsigned y;
982 1 unsigned const dst_width = src->height;
983 1 unsigned const dst_height = src->width;
984 1 unsigned src_line_length = src->width * sizeof(gate_color_t) + src->line_padding;
985 1 unsigned dst_pixel_length = src->pixel_length;
986
987
988
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (NULL == gate_rasterimage_create(dst, src->pixel_format, dst_width, dst_height, NULL))
989 {
990 return GATE_RESULT_OUTOFMEMORY;
991 }
992
993
2/2
✓ Branch 0 taken 64 times.
✓ Branch 1 taken 1 times.
65 for (y = 0; y != dst_height; ++y)
994 {
995 unsigned x;
996 64 gate_uint8_t const* ptr_src = src->get_ptr(src->data, src->width, src->height, src->line_padding, src->width - 1 - y, 0);
997 64 gate_uint8_t* ptr_dst = dst->get_ptr(dst->data, dst_width, dst_height, dst->line_padding, 0, y);
998
2/2
✓ Branch 0 taken 4096 times.
✓ Branch 1 taken 64 times.
4160 for (x = 0; x != dst_width; ++x)
999 {
1000 gate_color_t col;
1001 4096 src->read_pixel(ptr_src, &col);
1002 4096 dst->write_pixel(ptr_dst, &col);
1003 4096 ptr_dst += dst_pixel_length;
1004 4096 ptr_src += src_line_length;
1005 }
1006 }
1007 1 return GATE_RESULT_OK;
1008 }
1009
1010 1 gate_result_t gate_rasterimage_rotate_right(gate_rasterimage_t* dst, gate_rasterimage_t const* src)
1011 {
1012 unsigned y;
1013 1 unsigned const width = src->height;
1014 1 unsigned const height = src->width;
1015 1 unsigned const pixel_len = src->pixel_length;
1016 1 unsigned const line_length = ((src->width * (unsigned)src->bits_per_pixel + 7) / 8) + src->line_padding;
1017 gate_color_t col;
1018
1019
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (NULL == gate_rasterimage_create(dst, src->pixel_format, width, height, NULL))
1020 {
1021 return GATE_RESULT_OUTOFMEMORY;
1022 }
1023
1024
2/2
✓ Branch 0 taken 64 times.
✓ Branch 1 taken 1 times.
65 for (y = 0; y != height; ++y)
1025 {
1026 unsigned x;
1027 64 gate_uint8_t const* ptr_src = src->get_ptr(src->data, src->width, src->height, src->line_padding, y, src->height - 1);
1028 64 gate_uint8_t* ptr_dst = dst->get_ptr(dst->data, dst->width, dst->height, dst->line_padding, 0, y);
1029
2/2
✓ Branch 0 taken 4096 times.
✓ Branch 1 taken 64 times.
4160 for (x = 0; x != dst->width; ++x)
1030 {
1031 4096 src->read_pixel(ptr_src, &col);
1032 4096 dst->write_pixel(ptr_dst, &col);
1033 4096 ptr_dst += pixel_len;
1034 4096 ptr_src -= line_length;
1035 }
1036 }
1037 1 return GATE_RESULT_OK;
1038 }
1039
1040 1 gate_result_t gate_rasterimage_roll_over(gate_rasterimage_t* dst, gate_rasterimage_t const* src)
1041 {
1042 1 unsigned const width = src->width;
1043 1 unsigned const height = src->height;
1044 1 unsigned const pixel_len = src->pixel_length;
1045 unsigned y;
1046
1047
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (NULL == gate_rasterimage_create(dst, src->pixel_format, width, height, NULL))
1048 {
1049 return GATE_RESULT_OUTOFMEMORY;
1050 }
1051
1052
2/2
✓ Branch 0 taken 64 times.
✓ Branch 1 taken 1 times.
65 for (y = 0; y != height; ++y)
1053 {
1054 unsigned x;
1055 64 gate_uint8_t const* ptr_src = src->get_ptr(src->data, width, height, src->line_padding, width - 1, height - 1 - y);
1056 64 gate_uint8_t* ptr_dst = dst->get_ptr(dst->data, width, height, dst->line_padding, 0, y);
1057
2/2
✓ Branch 0 taken 4096 times.
✓ Branch 1 taken 64 times.
4160 for (x = 0; x != width; ++x)
1058 {
1059 gate_color_t col;
1060 4096 src->read_pixel(ptr_src, &col);
1061 4096 dst->write_pixel(ptr_dst, &col);
1062 4096 ptr_src -= pixel_len;
1063 4096 ptr_dst += pixel_len;
1064 }
1065 }
1066 1 return GATE_RESULT_OK;
1067 }
1068
1069 1 gate_result_t gate_rasterimage_flip_x(gate_rasterimage_t* dst, gate_rasterimage_t const* src)
1070 {
1071 unsigned x, y;
1072 gate_uint8_t* ptr_left;
1073 gate_uint8_t* ptr_right;
1074 1 unsigned const pixel_len = src->pixel_length;
1075 gate_color_t col_a;
1076
1077
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (src == dst)
1078 {
1079 unsigned const len = dst->width / 2;
1080 for (y = 0; y != dst->height; ++y)
1081 {
1082 ptr_left = dst->get_ptr(dst->data, dst->width, dst->height, dst->line_padding, 0, y);
1083 ptr_right = dst->get_ptr(dst->data, dst->width, dst->height, dst->line_padding, dst->width - 1, y);
1084 for (x = 0; x != len; ++x)
1085 {
1086 gate_color_t col_b;
1087 dst->read_pixel(ptr_left, &col_a);
1088 dst->read_pixel(ptr_right, &col_b);
1089 dst->write_pixel(ptr_left, &col_b);
1090 dst->write_pixel(ptr_right, &col_a);
1091 ptr_left += pixel_len;
1092 ptr_right -= pixel_len;
1093 }
1094 }
1095 }
1096 else
1097 {
1098
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (NULL == gate_rasterimage_create(dst, src->pixel_format, src->width, src->height, NULL))
1099 {
1100 return GATE_RESULT_OUTOFMEMORY;
1101 }
1102
2/2
✓ Branch 0 taken 64 times.
✓ Branch 1 taken 1 times.
65 for (y = 0; y != src->height; ++y)
1103 {
1104 64 ptr_left = src->get_ptr(src->data, src->width, src->height, src->line_padding, src->width - 1, y);
1105 64 ptr_right = dst->get_ptr(dst->data, dst->width, dst->height, dst->line_padding, 0, y);
1106
2/2
✓ Branch 0 taken 4096 times.
✓ Branch 1 taken 64 times.
4160 for (x = 0; x != src->width; ++x)
1107 {
1108 4096 src->read_pixel(ptr_left, &col_a);
1109 4096 dst->write_pixel(ptr_right, &col_a);
1110 4096 ptr_left -= pixel_len;
1111 4096 ptr_right += pixel_len;
1112 }
1113 }
1114 }
1115 1 return GATE_RESULT_OK;
1116 }
1117
1118 1 gate_result_t gate_rasterimage_flip_y(gate_rasterimage_t* dst, gate_rasterimage_t const* src)
1119 {
1120 unsigned y;
1121 gate_uint8_t* ptr_top;
1122 gate_uint8_t* ptr_bottom;
1123 unsigned length;
1124
1125
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (src == dst)
1126 {
1127 unsigned const count = dst->height / 2;
1128 length = dst->pixel_length;
1129
1130 for (y = 0; y != count; ++y)
1131 {
1132 unsigned x;
1133 ptr_top = dst->get_ptr(dst->data, dst->width, dst->height, dst->line_padding, 0, 0);
1134 ptr_bottom = dst->get_ptr(dst->data, dst->width, dst->height, dst->line_padding, 0, dst->height - 1);
1135
1136 for (x = 0; x != dst->width; ++x)
1137 {
1138 gate_color_t col_a;
1139 gate_color_t col_b;
1140 dst->read_pixel(ptr_top, &col_a);
1141 dst->read_pixel(ptr_bottom, &col_b);
1142 dst->write_pixel(ptr_bottom, &col_a);
1143 dst->write_pixel(ptr_top, &col_b);
1144 ptr_top += length;
1145 ptr_bottom += length;
1146 }
1147 }
1148 }
1149 else
1150 {
1151
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (NULL == gate_rasterimage_create(dst, src->pixel_format, src->width, src->height, NULL))
1152 {
1153 return GATE_RESULT_OUTOFMEMORY;
1154 }
1155
1156 1 length = src->pixel_length * src->width;
1157
1158
2/2
✓ Branch 0 taken 64 times.
✓ Branch 1 taken 1 times.
65 for (y = 0; y != src->height; ++y)
1159 {
1160 64 ptr_bottom = src->get_ptr(src->data, src->width, src->height, src->line_padding, 0, src->height - 1 - y);
1161 64 ptr_top = dst->get_ptr(dst->data, dst->width, dst->height, dst->line_padding, 0, y);
1162 64 gate_mem_copy(ptr_top, ptr_bottom, length);
1163 }
1164 }
1165 1 return GATE_RESULT_OK;
1166 }
1167
1168 gate_result_t gate_rasterimage_resample(gate_rasterimage_t* dest, gate_rasterimage_t const* src)
1169 {
1170 unsigned x, y;
1171 float dx, dy;
1172
1173 dx = (float)src->width / (float)dest->width;
1174 dy = (float)src->height / (float)dest->height;
1175
1176 for (y = 0; y < dest->height; ++y)
1177 {
1178 gate_uint8_t* ptr_out = dest->get_ptr(dest->data, dest->width, dest->height, dest->line_padding, 0, y);
1179 unsigned const miny = (unsigned)((float)y * dy);
1180 unsigned maxy = (unsigned)((float)(y + 1) * dy);
1181 if (maxy >= src->height)
1182 {
1183 maxy = src->height - 1;
1184 }
1185
1186 for (x = 0; x < dest->width; ++x)
1187 {
1188 float r = 0.0f, g = 0.0f, b = 0.0f, count = 0.0f;
1189 gate_color_t col;
1190 unsigned sy;
1191 unsigned const minx = (unsigned)((float)x * dx);
1192 unsigned maxx = (unsigned)((float)(x + 1) * dy);
1193 if (maxx >= src->width)
1194 {
1195 maxx = src->width - 1;
1196 }
1197
1198 for (sy = miny; sy <= maxy; ++sy)
1199 {
1200 unsigned sx;
1201 gate_uint8_t const* ptr_in = src->get_ptr(src->data, src->width, src->height, src->line_padding, minx, sy);
1202 for (sx = minx; sx <= maxx; ++sx)
1203 {
1204 src->read_pixel(ptr_in, &col);
1205 r += (float)col.r;
1206 g += (float)col.g;
1207 b += (float)col.b;
1208 count += 1.0f;
1209 ptr_in += src->pixel_length;
1210 }
1211 }
1212 col.r = (gate_uint8_t)(unsigned)(r / count + 0.5f);
1213 col.g = (gate_uint8_t)(unsigned)(g / count + 0.5f);
1214 col.b = (gate_uint8_t)(unsigned)(b / count + 0.5f);
1215 col.a = 255;
1216 dest->write_pixel(ptr_out, &col);
1217 ptr_out += dest->pixel_length;
1218 }
1219 }
1220 return GATE_RESULT_OK;
1221 }
1222