GCC Code Coverage Report


Directory: src/gate/
File: src/gate/graphics/pngimages.c
Date: 2025-09-14 13:10:38
Exec Total Coverage
Lines: 99 304 32.6%
Functions: 4 9 44.4%
Branches: 35 164 21.3%

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/pngimages.h"
30 #include "gate/results.h"
31 #include "gate/debugging.h"
32
33 #if defined(GATE_EXTLIB_LIBPNG)
34 # define GATE_GRAPHICS_PNG_USE_LIBPNG 1
35 #else
36 # define GATE_GRAPHICS_PNG_NO_IMPL 1
37 #endif
38
39
40 #if defined(GATE_GRAPHICS_PNG_USE_LIBPNG)
41
42 #if !defined(GATE_SYS_WINCE) || defined(GATE_COMPILER_MSVC)
43 # define GATE_GRAPHICS_PNG_SETJMP 1
44 #endif
45 #include "png.h"
46
47
48
49 typedef struct gate_png_param_class
50 {
51 gate_stream_t* stream;
52 gate_result_t result;
53 } gate_png_param_t;
54
55 9 static void gate_png_stream_read_data(png_structp png, png_bytep data, png_size_t length)
56 {
57 9 gate_png_param_t* user_param = (gate_png_param_t*)png_get_io_ptr(png);
58 gate_size_t bytesreturned;
59 gate_result_t result;
60
61 9 result = gate_stream_read_block(user_param->stream, (char*)data, length, &bytesreturned);
62
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if (GATE_FAILED(result))
63 {
64 user_param->result = result;
65 }
66 else
67 {
68
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if (bytesreturned != length)
69 {
70 user_param->result = GATE_RESULT_ENDOFSTREAM;
71 }
72 }
73 9 }
74
75 9 static void gate_png_stream_write_data(png_structp png, png_bytep data, png_size_t length)
76 {
77 9 gate_png_param_t* user_param = (gate_png_param_t*)png_get_io_ptr(png);
78 gate_size_t byteswritten;
79 gate_result_t result;
80
81 9 result = gate_stream_write_block(user_param->stream, (char const*)data, length, &byteswritten);
82
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if (GATE_FAILED(result))
83 {
84 user_param->result = result;
85 }
86 else
87 {
88
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if (byteswritten != length)
89 {
90 user_param->result = GATE_RESULT_ENDOFSTREAM;
91 }
92 }
93 9 }
94
95 static void gate_png_stream_flush(png_structp png)
96 {
97 gate_png_param_t* user_param = (gate_png_param_t*)png_get_io_ptr(png);
98 gate_stream_flush(user_param->stream);
99
100 }
101
102 static void gate_png_error_handler(png_structp png, png_const_charp msg)
103 {
104 void* error_ptr = png_get_error_ptr(png);
105 GATE_UNUSED_ARG(msg);
106 if (error_ptr == NULL)
107 {
108 GATE_DEBUG_BREAKPOINT;
109 }
110 else
111 {
112 #if defined(GATE_GRAPHICS_PNG_SETJMP)
113 jmp_buf* jmpbuffer = (jmp_buf*)(error_ptr);
114 longjmp(*jmpbuffer, 1);
115 #endif
116 }
117 }
118
119 static void gate_png_warning_handler(png_structp png, png_const_charp msg)
120 {
121 (void)png;
122 (void)msg;
123 }
124
125
126 1 gate_result_t gate_pngimage_load(gate_stream_t* srcstream, gate_rasterimage_t* image, gate_enumint_t flags)
127 {
128 gate_result_t ret;
129 gate_rasterimage_t raster;
130 gate_png_param_t user_param;
131 #if defined(GATE_GRAPHICS_PNG_SETJMP)
132 jmp_buf jmpbuffer;
133 #endif
134
135 1 png_structp png = NULL;
136 1 png_infop png_info = NULL;
137 1 png_infop png_info_end = NULL;
138
139 unsigned char png_interlace_type;
140 unsigned char png_color_type;
141 unsigned char png_bit_depth;
142
143 gate_size_t linebytes;
144 png_byte buffer[4096 * 3];
145 1 png_byte* ptrbuffer = &buffer[0];
146 gate_color_t* ptrpixels;
147 gate_uint32_t x, y;
148 png_bytep ptrbytes;
149 png_colorp png_palette;
150 int png_palette_size;
151 int png_number_of_passes;
152 int ndx;
153
154 1 user_param.stream = srcstream;
155 1 user_param.result = GATE_RESULT_OK;
156
157 1 gate_rasterimage_create(&raster, GATE_IMAGE_PIXELFORMAT_DEFAULT, 0, 0, NULL);
158
159
160 do
161 {
162 1 png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
163
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (png == NULL)
164 {
165 ret = GATE_RESULT_OUTOFMEMORY;
166 break;
167 }
168
169 1 png_info = png_create_info_struct(png);
170 1 png_info_end = png_create_info_struct(png);
171
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (png_info == NULL)
172 {
173 ret = GATE_RESULT_OUTOFMEMORY;
174 break;
175 }
176
177 #if defined(GATE_GRAPHICS_PNG_SETJMP)
178
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (setjmp(jmpbuffer) != 0)
179 {
180 ret = GATE_RESULT_CRITICALERROR;
181 break;
182 }
183 1 png_set_error_fn(png, &jmpbuffer, &gate_png_error_handler, &gate_png_warning_handler);
184 #endif
185
186 1 png_set_read_fn(png, (png_voidp)&user_param, &gate_png_stream_read_data);
187 1 png_read_info(png, png_info);
188
189
1/2
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
1 if (NULL == gate_rasterimage_create(&raster, GATE_IMAGE_PIXELFORMAT_DEFAULT,
190 png_get_image_width(png, png_info),
191 png_get_image_height(png, png_info), NULL))
192 {
193 ret = GATE_RESULT_OUTOFMEMORY;
194 break;
195 }
196
197 1 png_interlace_type = png_get_interlace_type(png, png_info);
198 1 png_color_type = png_get_color_type(png, png_info);
199
200
201
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (png_interlace_type == PNG_INTERLACE_ADAM7)
202 {
203 /* skip smaller preview images */
204 linebytes = png_get_rowbytes(png, png_info);
205 if (linebytes > sizeof(buffer))
206 {
207 ptrbuffer = gate_mem_alloc(linebytes);
208 if (ptrbuffer == NULL)
209 {
210 ret = GATE_RESULT_OUTOFMEMORY;
211 break;
212 }
213 }
214
215 png_number_of_passes = png_set_interlace_handling(png);
216 for (ndx = 1; ndx != png_number_of_passes; ++ndx)
217 {
218 for (y = 0; y != raster.height; ++y)
219 {
220 ptrbytes = (png_bytep)ptrbuffer;
221 png_read_row(png, ptrbuffer, NULL);
222 }
223 }
224
225 if (ptrbuffer != &buffer[0])
226 {
227 gate_mem_dealloc(ptrbuffer);
228 ptrbuffer = &buffer[0];
229 }
230 }
231
232 1 ret = GATE_RESULT_OK;
233
234 1 png_bit_depth = png_get_bit_depth(png, png_info);
235
1/5
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
1 switch (png_color_type)
236 {
237 case PNG_COLOR_TYPE_PALETTE:
238 { // we have a palette
239 if (png_bit_depth < 8)
240 {
241 png_set_packing(png);
242 }
243 if (png_bit_depth > 8)
244 {
245 ret = GATE_RESULT_NOTSUPPORTED;
246 break;
247 }
248
249 linebytes = raster.width;
250 if (linebytes > sizeof(buffer))
251 {
252 ptrbuffer = gate_mem_alloc(linebytes);
253 if (ptrbuffer == NULL)
254 {
255 ret = GATE_RESULT_OUTOFMEMORY;
256 break;
257 }
258 }
259 ptrpixels = (gate_color_t*)gate_rasterimage_get_line_ptr(&raster, 0);
260 png_get_PLTE(png, png_info, &png_palette, &png_palette_size);
261 for (y = 0; y < raster.height; ++y)
262 {
263 ptrbytes = (png_bytep)ptrbuffer;
264 png_read_row(png, ptrbuffer, NULL);
265 for (x = 0; x < raster.width; ++x)
266 {
267 if (*ptrbytes < png_palette_size)
268 {
269 ptrpixels->r = (gate_uint8_t)(png_palette[*ptrbytes].red);
270 ptrpixels->g = (gate_uint8_t)(png_palette[*ptrbytes].green);
271 ptrpixels->b = (gate_uint8_t)(png_palette[*ptrbytes].blue);
272 }
273 else
274 {
275 ptrpixels->r = 255;
276 ptrpixels->g = 255;
277 ptrpixels->b = 255;
278 }
279 ptrpixels->a = 255;
280 ++ptrpixels;
281 ++ptrbytes;
282 }
283 }
284 png_read_end(png, png_info_end);
285 break;
286 }
287 case PNG_COLOR_TYPE_RGB:
288 {
289 png_set_strip_16(png);
290 linebytes = png_get_rowbytes(png, png_info);
291 if (linebytes > sizeof(buffer))
292 {
293 ptrbuffer = gate_mem_alloc(linebytes);
294 if (ptrbuffer == NULL)
295 {
296 ret = GATE_RESULT_OUTOFMEMORY;
297 break;
298 }
299 }
300 ptrpixels = (gate_color_t*)gate_rasterimage_get_line_ptr(&raster, 0);
301 for (y = 0; y < raster.height; ++y)
302 {
303 ptrbytes = (png_bytep)ptrbuffer;
304 png_read_row(png, ptrbuffer, NULL);
305 for (x = 0; x < raster.width; ++x)
306 {
307 ptrpixels->r = (gate_uint8_t) * (ptrbytes++);
308 ptrpixels->g = (gate_uint8_t) * (ptrbytes++);
309 ptrpixels->b = (gate_uint8_t) * (ptrbytes++);
310 ptrpixels->a = 255;
311 ++ptrpixels;
312 }
313 }
314 png_read_end(png, png_info_end);
315 break;
316 }
317
318 1 case PNG_COLOR_TYPE_RGB_ALPHA:
319 {
320 1 png_set_strip_16(png);
321 1 linebytes = png_get_rowbytes(png, png_info);
322
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (linebytes > sizeof(buffer))
323 {
324 ptrbuffer = gate_mem_alloc(linebytes);
325 if (ptrbuffer == NULL)
326 {
327 ret = GATE_RESULT_OUTOFMEMORY;
328 break;
329 }
330 }
331 1 ptrpixels = (gate_color_t*)gate_rasterimage_get_line_ptr(&raster, 0);
332
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 1 times.
33 for (y = 0; y < raster.height; ++y)
333 {
334 32 ptrbytes = (png_bytep)ptrbuffer;
335 32 png_read_row(png, ptrbuffer, NULL);
336
2/2
✓ Branch 0 taken 2048 times.
✓ Branch 1 taken 32 times.
2080 for (x = 0; x < raster.width; ++x)
337 {
338 2048 ptrpixels->r = (gate_uint8_t) * (ptrbytes++);
339 2048 ptrpixels->g = (gate_uint8_t) * (ptrbytes++);
340 2048 ptrpixels->b = (gate_uint8_t) * (ptrbytes++);
341 2048 ptrpixels->a = (gate_uint8_t) * (ptrbytes++);
342 2048 ++ptrpixels;
343 }
344 }
345 1 png_read_end(png, png_info_end);
346 1 break;
347 }
348 case PNG_COLOR_TYPE_GRAY:
349 {
350 if (png_bit_depth > 8)
351 {
352 linebytes = png_get_rowbytes(png, png_info);
353 if (linebytes > sizeof(buffer))
354 {
355 ptrbuffer = gate_mem_alloc(linebytes);
356 if (ptrbuffer == NULL)
357 {
358 ret = GATE_RESULT_OUTOFMEMORY;
359 break;
360 }
361 }
362 ptrpixels = (gate_color_t*)gate_rasterimage_get_line_ptr(&raster, 0);
363 for (y = 0; y < raster.height; ++y)
364 {
365 ptrbytes = (png_bytep)ptrbuffer;
366 png_read_row(png, ptrbuffer, NULL);
367 for (x = 0; x < raster.width; ++x)
368 {
369 ptrpixels->r = (gate_uint8_t)*ptrbytes;
370 ptrpixels->g = (gate_uint8_t)*ptrbytes;
371 ptrpixels->b = (gate_uint8_t)*ptrbytes;
372 ptrpixels->a = 255;
373 ++ptrpixels;
374 ptrbytes += 2;
375 }
376 }
377 }
378 else
379 {
380 if (png_bit_depth < 8)
381 {
382 png_set_expand(png);
383 }
384
385 linebytes = png_get_rowbytes(png, png_info);
386 if (linebytes > sizeof(buffer))
387 {
388 ptrbuffer = gate_mem_alloc(linebytes);
389 if (ptrbuffer == NULL)
390 {
391 ret = GATE_RESULT_OUTOFMEMORY;
392 break;
393 }
394 }
395 ptrpixels = (gate_color_t*)gate_rasterimage_get_line_ptr(&raster, 0);
396 for (y = 0; y < raster.height; ++y)
397 {
398 ptrbytes = (png_bytep)ptrbuffer;
399 png_read_row(png, ptrbuffer, NULL);
400 for (x = 0; x < raster.width; ++x)
401 {
402 ptrpixels->r = (gate_uint8_t) * (ptrbytes);
403 ptrpixels->g = (gate_uint8_t) * (ptrbytes);
404 ptrpixels->b = (gate_uint8_t) * (ptrbytes);
405 ptrpixels->a = (gate_uint8_t) * (ptrbytes);
406 ++ptrpixels;
407 ++ptrbytes;
408 }
409 }
410 }
411 png_read_end(png, png_info_end);
412 break;
413 }
414 default:
415 {
416 ret = GATE_RESULT_NOTSUPPORTED;
417 break;
418 }
419
420 } // switch(info->color_type)
421
422
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (GATE_SUCCEEDED(ret))
423 {
424 1 gate_mem_copy(image, &raster, sizeof(raster));
425 1 gate_mem_clear(&raster, sizeof(raster));
426 }
427
428 } while (0);
429
430
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (png != NULL)
431 {
432 1 png_destroy_read_struct(&png, &png_info, &png_info_end);
433 }
434
435
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 if ((ptrbuffer != &buffer[0]) && (ptrbuffer != NULL))
436 {
437 gate_mem_dealloc(ptrbuffer);
438 }
439
440 1 gate_rasterimage_release(&raster);
441
442 1 return ret;
443 }
444
445 static gate_bool_t gate_png_equals_color(png_color const* pngcolor, gate_color_t const* gatecolor)
446 {
447 return (pngcolor->red == gatecolor->r)
448 && (pngcolor->green == gatecolor->g)
449 && (pngcolor->blue == gatecolor->b)
450 ;
451 }
452
453 static void copy_rgba(gate_uint8_t* dst, gate_uint8_t const* src, gate_size_t pixel_count)
454 {
455 gate_mem_copy(dst, src, pixel_count * 4);
456 }
457
458 1 gate_result_t gate_pngimage_save(gate_rasterimage_t const* image, gate_stream_t* deststream, gate_enumint_t flags)
459 {
460 1 gate_result_t ret = GATE_RESULT_OK;
461 gate_png_param_t user_param;
462 1 png_structp png = NULL;
463 1 png_infop png_info = NULL;
464 #if defined(GATE_GRAPHICS_PNG_SETJMP)
465 jmp_buf jmpbuffer;
466 #endif
467
468 png_color png_palette[256];
469 png_byte buffer[4096];
470 1 gate_uint8_t* ptr_buffer = NULL;
471 gate_uint8_t const* ptr_line;
472 gate_size_t buffer_required_len;
473 int p;
474 1 int png_palette_size = 0;
475 1 png_const_colorp ptrpalette = NULL;
476 gate_uint32_t imagesize;
477
478 gate_color_t const* ptrpixels;
479 gate_bool_t found;
480 unsigned x, y;
481 1 void(*line_writer)(gate_uint8_t*, gate_uint8_t const*, gate_size_t) = NULL;
482
483 do
484 {
485
3/6
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
1 if ((image->width == 0) || (image->height == 0) || (image->data == NULL))
486 {
487 ret = GATE_RESULT_INVALIDDATA;
488 break;
489 }
490
491
1/11
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
1 switch (image->pixel_format)
492 {
493 case GATE_IMAGE_PIXELFORMAT_RGBA:
494 case GATE_IMAGE_PIXELFORMAT_RGB32: line_writer = &copy_rgba; break;
495 case GATE_IMAGE_PIXELFORMAT_BGRA:
496 case GATE_IMAGE_PIXELFORMAT_BGR32: line_writer = &gate_color_convert_rgba_from_bgra_32; break;
497
498 1 case GATE_IMAGE_PIXELFORMAT_RGB24: line_writer = &gate_color_convert_rgba_from_rgb_24; break;
499 case GATE_IMAGE_PIXELFORMAT_BGR24: line_writer = &gate_color_convert_rgba_from_bgr_24; break;
500
501 case GATE_IMAGE_PIXELFORMAT_RGB555: line_writer = &gate_color_convert_rgba_from_rgb_15; break;
502 case GATE_IMAGE_PIXELFORMAT_RGB565: line_writer = &gate_color_convert_rgba_from_rgb_16; break;
503 case GATE_IMAGE_PIXELFORMAT_ARGB4: line_writer = &gate_color_convert_rgba_from_argb_16; break;
504 case GATE_IMAGE_PIXELFORMAT_YUV2: line_writer = &gate_color_convert_rgba_from_yuv2_16; break;
505
506 case GATE_IMAGE_PIXELFORMAT_PAL8: line_writer = &gate_color_convert_rgba_from_pal_8; break;
507 case GATE_IMAGE_PIXELFORMAT_GRAY8: line_writer = &gate_color_convert_rgba_from_gray_8; break;
508 default:
509 break;
510 }
511
512
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (line_writer == NULL)
513 {
514 ret = GATE_RESULT_NOTSUPPORTED;
515 break;
516 }
517
518 1 buffer_required_len = (gate_size_t)image->width * 4u;
519
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (buffer_required_len <= sizeof(buffer))
520 {
521 1 ptr_buffer = &buffer[0];
522 }
523 else
524 {
525 ptr_buffer = gate_mem_alloc(buffer_required_len);
526 if (ptr_buffer == NULL)
527 {
528 ret = GATE_RESULT_OUTOFMEMORY;
529 break;
530 }
531 }
532
533 1 imagesize = image->width * image->height;
534 1 user_param.stream = deststream;
535 1 user_param.result = GATE_RESULT_OK;
536 1 png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
537
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (png == NULL)
538 {
539 ret = GATE_RESULT_FAILED;
540 break;
541 }
542 1 png_info = png_create_info_struct(png);
543
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (png_info == NULL)
544 {
545 ret = GATE_RESULT_INVALIDHEADER;
546 break;
547 }
548
549 #if defined(GATE_GRAPHICS_PNG_SETJMP)
550
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (setjmp(jmpbuffer) != 0)
551 {
552 ret = GATE_RESULT_FAILED;
553 break;
554 }
555 1 png_set_error_fn(png, &jmpbuffer, &gate_png_error_handler, &gate_png_warning_handler);
556 #endif
557
558 1 png_set_write_fn(png, &user_param, &gate_png_stream_write_data, &gate_png_stream_flush);
559
560
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (GATE_FLAG_ENABLED(flags, GATE_IMAGE_FLAG_PALETTE))
561 {
562 ptrpixels = (gate_color_t const*)gate_rasterimage_get_line_ptr(image, 0);
563 ptrpalette = &png_palette[0];
564 for (y = 0; (y != image->height) && (ptrpalette != NULL); ++y)
565 {
566 ptr_line = (gate_uint8_t const*)gate_rasterimage_get_line_ptr(image, y);
567 line_writer(ptr_buffer, ptr_line, image->width);
568 ptrpixels = (gate_color_t const*)ptr_buffer;
569 for (x = 0; x != image->width; ++x)
570 {
571 found = false;
572 for (p = 0; p != png_palette_size; ++p)
573 {
574 if (gate_png_equals_color(&png_palette[p], &ptrpixels[x]))
575 {
576 found = true;
577 break;
578 }
579 }
580 if (!found)
581 {
582 png_palette[png_palette_size].red = ptrpixels[x].r;
583 png_palette[png_palette_size].green = ptrpixels[x].g;
584 png_palette[png_palette_size].blue = ptrpixels[x].b;
585 ++png_palette_size;
586 if (png_palette_size >= 256)
587 {
588 ptrpalette = NULL;
589 break;
590 }
591 }
592 }
593 }
594 }
595
596
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ptrpalette != NULL)
597 {
598 /* write an indexed palette image */
599
600 png_set_IHDR(png, png_info, image->width, image->height, 8, PNG_COLOR_TYPE_PALETTE,
601 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
602
603 png_set_PLTE(png, png_info, ptrpalette, png_palette_size);
604 png_write_info(png, png_info);
605
606 for (y = 0; y != image->height; ++y)
607 {
608 ptr_line = (gate_uint8_t const*)gate_rasterimage_get_line_ptr(image, 0);
609 line_writer(ptr_buffer, ptr_line, image->width);
610 for (x = 0; x != image->width; ++x)
611 {
612 for (p = 0; p != png_palette_size; ++p)
613 {
614 if (gate_png_equals_color(&png_palette[p], (gate_color_t const*)&ptr_buffer[x * 4]))
615 {
616 ptr_buffer[x] = (png_byte)p;
617 break;
618 }
619 }
620 }
621 png_write_row(png, ptr_buffer);
622 }
623 }
624 else
625 {
626
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (line_writer == NULL)
627 {
628 ret = GATE_RESULT_NOTSUPPORTED;
629 }
630 else
631 {
632 1 png_set_IHDR(png, png_info, image->width, image->height, 8, PNG_COLOR_TYPE_RGB_ALPHA,
633 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
634 1 png_write_info(png, png_info);
635
636
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 1 times.
33 for (y = 0; y != image->height; ++y)
637 {
638 32 ptr_line = (gate_uint8_t const*)gate_rasterimage_get_line_ptr(image, y);
639 32 line_writer(ptr_buffer, ptr_line, image->width);
640
641 32 png_write_row(png, (png_bytep)ptr_buffer);
642 }
643 }
644 }
645 1 png_write_end(png, png_info);
646
647 } while (0);
648
649
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
1 if (ptr_buffer && (ptr_buffer != &buffer[0]))
650 {
651 gate_mem_dealloc(ptr_buffer);
652 }
653
654
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (png != NULL)
655 {
656 1 png_destroy_write_struct(&png, &png_info);
657 }
658
659 1 return ret;
660 }
661
662 #endif /* GATE_GRAPHICS_PNG_USE_LIBPNG */
663
664
665 #if defined(GATE_GRAPHICS_PNG_NO_IMPL)
666
667 gate_result_t gate_pngimage_load(gate_stream_t* srcstream, gate_rasterimage_t* image, gate_enumint_t flags)
668 {
669 (void)srcstream;
670 (void)image;
671 (void)flags;
672 return GATE_RESULT_NOTIMPLEMENTED;
673 }
674
675 gate_result_t gate_pngimage_save(gate_rasterimage_t const* image, gate_stream_t* deststream, gate_enumint_t flags)
676 {
677 (void)image;
678 (void)deststream;
679 (void)flags;
680 return GATE_RESULT_NOTIMPLEMENTED;
681
682 }
683
684
685 #endif /* GATE_GRAPHICS_PNG_NO_IMPL */
686
687