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