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 = ©_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 |