GCC Code Coverage Report


Directory: src/gate/
File: src/gate/graphics/bitmapimages.c
Date: 2026-09-21 06:26:40
Exec Total Coverage
Lines: 205 372 55.1%
Functions: 4 5 80.0%
Branches: 57 125 45.6%

Line Branch Exec Source
1 /* GATE PROJECT LICENSE:
2 +----------------------------------------------------------------------------+
3 | Copyright(c) 2018-2026, 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/bitmapimages.h"
30 #include "gate/results.h"
31 #include "gate/serializers.h"
32 #include "gate/debugging.h"
33 #include "gate/mathematics.h"
34 #include "gate/localbuffer.h"
35
36 typedef struct gate_bmp_header_class
37 {
38 gate_uint32_t header_sz;
39 gate_int32_t width;
40 gate_int32_t height;
41 gate_uint16_t nplanes;
42 gate_uint16_t bitspp;
43 gate_uint32_t compress_type;
44 gate_uint32_t bmp_bytesz;
45 gate_int32_t hres;
46 gate_int32_t vres;
47 gate_uint32_t ncolors;
48 gate_uint32_t nimpcolors;
49 } gate_bmp_header_t;
50
51
52
53 19 static gate_result_t load_bitmap_as_rgba_image(
54 gate_stream_t* srcstream,
55 gate_bmp_header_t const* ptr_header,
56 char const* palette,
57 gate_size_t linelen,
58 gate_rasterimage_t* image)
59 {
60 19 gate_result_t result = GATE_RESULT_FAILED;
61 19 const unsigned width = ptr_header->width < 0 ? (unsigned)(-ptr_header->width) : (unsigned)ptr_header->width;
62 19 const unsigned height = ptr_header->height < 0 ? (unsigned)(-ptr_header->height) : (unsigned)ptr_header->height;
63 gate_rasterimage_t raster;
64 gate_index_t lineadd;
65 gate_color_t* ptrpixel;
66 gate_color_t* ptrline;
67 unsigned x, y, z;
68 gate_size_t lenread;
69 gate_localbuffer_t buffer;
70 19 char* ptr_buffer = NULL;
71 gate_uint8_t const* ptrbytes;
72 gate_uint8_t const* ptrpal;
73 19 gate_bool_t all_alphas_are_zero = true;
74
75 do
76 {
77 19 gate_mem_clear(&raster, sizeof(raster));
78 19 ptr_buffer = (char*)gate_localbuffer_create(&buffer, linelen);
79
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19 times.
19 if (ptr_buffer == NULL)
80 {
81 result = GATE_RESULT_OUTOFMEMORY;
82 break;
83 }
84
85
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 19 times.
19 if (NULL == gate_rasterimage_create(&raster, GATE_IMAGE_PIXELFORMAT_RGBA, width, height, NULL))
86 {
87 result = GATE_RESULT_OUTOFMEMORY;
88 break;
89 }
90
91
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19 times.
19 if (ptr_header->height < 0)
92 {
93 ptrpixel = (gate_color_t*)gate_rasterimage_get_line_ptr(&raster, 0);
94 lineadd = width;
95 }
96 else
97 {
98 19 ptrpixel = (gate_color_t*)gate_rasterimage_get_line_ptr(&raster, (height - 1));
99 19 lineadd = -(gate_index_t)width;
100 }
101
102 19 result = GATE_RESULT_OK;
103
2/2
✓ Branch 0 taken 1280 times.
✓ Branch 1 taken 19 times.
1299 for (y = 0; y != height; ++y)
104 {
105
106 1280 result = gate_stream_read_block(srcstream, ptr_buffer, linelen, &lenread);
107
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1280 times.
1280 if (GATE_FAILED(result))
108 {
109 break;
110 }
111
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1280 times.
1280 if (lenread < linelen)
112 {
113 result = GATE_RESULT_ENDOFSTREAM;
114 break;
115 }
116 1280 ptrline = ptrpixel;
117 1280 ptrbytes = (gate_uint8_t const*)ptr_buffer;
118
119
2/2
✓ Branch 0 taken 102016 times.
✓ Branch 1 taken 1280 times.
103296 for (x = 0; x < width; ++x)
120 {
121
4/7
✗ Branch 0 not taken.
✓ Branch 1 taken 128 times.
✓ Branch 2 taken 512 times.
✓ Branch 3 taken 1024 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 100352 times.
102016 switch (ptr_header->bitspp)
122 {
123 default:
124 {
125 ptrline->b = 0;
126 ptrline->g = 0;
127 ptrline->r = 0;
128 ptrline->a = 255;
129 ++ptrline;
130 break;
131 }
132 128 case 1:
133 {
134
2/2
✓ Branch 0 taken 1024 times.
✓ Branch 1 taken 128 times.
1152 for (z = 0; z != 8; ++z)
135 {
136
2/2
✓ Branch 0 taken 798 times.
✓ Branch 1 taken 226 times.
1024 if (*ptrbytes & (gate_uint8_t)(1 << (7 - z)))
137 {
138 798 ptrpal = (gate_uint8_t const*)&palette[4];
139 }
140 else
141 {
142 226 ptrpal = (gate_uint8_t const*)&palette[0];
143 }
144 1024 ptrline->b = ptrpal[0];
145 1024 ptrline->g = ptrpal[1];
146 1024 ptrline->r = ptrpal[2];
147 1024 ptrline->a = ptrpal[3];
148 1024 all_alphas_are_zero &= ((ptrline->a == 0) ? true : false);
149 1024 ++ptrline;
150 }
151 128 ++ptrbytes;
152 128 x += 7;
153 128 break;
154 }
155 512 case 4:
156 {
157 512 ptrpal = (gate_uint8_t const*)&palette[4 * (unsigned)(*ptrbytes >> 4)];
158 512 ptrline->b = ptrpal[0];
159 512 ptrline->g = ptrpal[1];
160 512 ptrline->r = ptrpal[2];
161 512 ptrline->a = ptrpal[3];
162 512 all_alphas_are_zero &= ((ptrline->a == 0) ? true : false);
163 512 ++ptrline;
164
165 512 ptrpal = (gate_uint8_t const*)&palette[4 * (unsigned)(*ptrbytes & 0x0f)];
166 512 ptrline->b = ptrpal[0];
167 512 ptrline->g = ptrpal[1];
168 512 ptrline->r = ptrpal[2];
169 512 ptrline->a = ptrpal[3];
170 512 all_alphas_are_zero &= ((ptrline->a == 0) ? true : false);
171 512 ++ptrline;
172
173 512 ++ptrbytes;
174 512 ++x;
175 512 break;
176 }
177 1024 case 8:
178 {
179 1024 ptrpal = (gate_uint8_t const*)&palette[4 * (gate_size_t)*ptrbytes];
180 1024 ++ptrbytes;
181 1024 ptrline->b = ptrpal[0];
182 1024 ptrline->g = ptrpal[1];
183 1024 ptrline->r = ptrpal[2];
184 1024 ptrline->a = ptrpal[3];
185 1024 all_alphas_are_zero &= ((ptrline->a == 0) ? true : false);
186 1024 ++ptrline;
187 1024 break;
188 }
189 case 15:
190 case 16:
191 {
192 ptrline->b = (ptrbytes[0] & 0x1f) << 3;
193 ptrline->g = ((ptrbytes[0] >> 5) | ((ptrbytes[1] & 0x03) << 3)) << 3;
194 ptrline->r = (ptrbytes[1] & 0x7c) << 1;
195 ptrline->a = 255;
196 ++ptrline;
197 break;
198 }
199 case 24:
200 {
201 ptrline->b = *ptrbytes++;
202 ptrline->g = *ptrbytes++;
203 ptrline->r = *ptrbytes++;
204 ptrline->a = 255;
205 ++ptrline;
206 break;
207 }
208 100352 case 32:
209 {
210 100352 ptrline->b = *ptrbytes++;
211 100352 ptrline->g = *ptrbytes++;
212 100352 ptrline->r = *ptrbytes++;
213 100352 ptrline->a = *ptrbytes++;
214 100352 all_alphas_are_zero &= ((ptrline->a == 0) ? true : false);
215 100352 ++ptrline;
216 100352 break;
217 }
218 }
219 } /* for(x) */
220
221 1280 ptrpixel += lineadd;
222 } /* for(y) */
223
224
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19 times.
19 GATE_BREAK_IF_FAILED(result);
225
226
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 16 times.
19 if (all_alphas_are_zero)
227 {
228 /* all alpha values are zero means, that
229 the soruce stream had no alpha-values stored
230 and all the reserved bits were zero.
231 Therfore we just patch all alpha-values to 255
232 */
233 3 gate_size_t pixelcount = (gate_size_t)raster.width * (gate_size_t)raster.height;
234 3 ptrpixel = (gate_color_t*)gate_rasterimage_get_line_ptr(&raster, 0);
235
2/2
✓ Branch 0 taken 3072 times.
✓ Branch 1 taken 3 times.
3075 while (pixelcount-- != 0)
236 {
237 3072 ptrpixel->a = 255;
238 3072 ++ptrpixel;
239 }
240 }
241
242 /* success case, transfer local image object into output object */
243 19 gate_mem_copy(image, &raster, sizeof(raster));
244 19 gate_mem_clear(&raster, sizeof(raster));
245 19 result = GATE_RESULT_OK;
246 } while (0);
247
248 19 gate_localbuffer_destroy(&buffer);
249 19 gate_rasterimage_release(&raster);
250
251 19 return result;
252 }
253
254
255 static gate_result_t load_bitmap_generic(
256 gate_stream_t* srcstream,
257 gate_bmp_header_t const* ptr_header,
258 char const* palette,
259 gate_size_t linelen,
260 gate_enumint_t pixel_format,
261 gate_rasterimage_t* image)
262 {
263 gate_result_t result = GATE_RESULT_FAILED;
264 const unsigned width = ptr_header->width < 0 ? (unsigned)(-ptr_header->width) : (unsigned)ptr_header->width;
265 const unsigned height = ptr_header->height < 0 ? (unsigned)(-ptr_header->height) : (unsigned)ptr_header->height;
266 gate_rasterimage_t raster;
267 unsigned x, y, z;
268 gate_size_t lenread;
269 gate_color_t current_pixel;
270 char buffer[8192];
271 char* ptr_buffer = &buffer[0];
272 gate_uint8_t const* ptrpal;
273
274 do
275 {
276 gate_mem_clear(&raster, sizeof(raster));
277
278 if (NULL == gate_rasterimage_create(&raster, pixel_format, width, height, NULL))
279 {
280 result = GATE_RESULT_OUTOFMEMORY;
281 break;
282 }
283
284 if (linelen > sizeof(buffer))
285 {
286 ptr_buffer = gate_mem_alloc(linelen);
287 if (NULL == ptr_buffer)
288 {
289 result = GATE_RESULT_OUTOFMEMORY;
290 break;
291 }
292 }
293
294 result = GATE_RESULT_OK;
295 for (y = 0; y != height; ++y)
296 {
297 const unsigned dest_y = (ptr_header->height < 0) ? y : height - y - 1;
298 gate_uint8_t const* ptr_line_bytes = (gate_uint8_t const*)ptr_buffer;
299
300 result = gate_stream_read_block(srcstream, ptr_buffer, linelen, &lenread);
301 if (GATE_FAILED(result))
302 {
303 break;
304 }
305 if (lenread < linelen)
306 {
307 result = GATE_RESULT_ENDOFSTREAM;
308 break;
309 }
310
311 for (x = 0; x < width; ++x)
312 {
313 switch (ptr_header->bitspp)
314 {
315 default:
316 {
317 current_pixel.b = 0;
318 current_pixel.g = 0;
319 current_pixel.r = 0;
320 current_pixel.a = 255;
321 ++ptr_line_bytes;
322 break;
323 }
324 case 1:
325 {
326 for (z = 0; z != 8; ++z)
327 {
328 if (*ptr_line_bytes & (gate_uint8_t)(1 << (7 - z)))
329 {
330 ptrpal = (gate_uint8_t const*)&palette[4];
331 }
332 else
333 {
334 ptrpal = (gate_uint8_t const*)&palette[0];
335 }
336 current_pixel.b = ptrpal[0];
337 current_pixel.g = ptrpal[1];
338 current_pixel.r = ptrpal[2];
339 current_pixel.a = 255;
340
341 gate_rasterimage_set_pixel(&raster, x + z, dest_y, &current_pixel);
342 }
343 ++ptr_line_bytes;
344 x += 7;
345 break;
346 }
347 case 4:
348 {
349 ptrpal = (gate_uint8_t const*)&palette[4 * (unsigned)(*ptr_line_bytes >> 4)];
350 current_pixel.b = ptrpal[0];
351 current_pixel.g = ptrpal[1];
352 current_pixel.r = ptrpal[2];
353 current_pixel.a = 255;
354 gate_rasterimage_set_pixel(&raster, x, dest_y, &current_pixel);
355 ++ptr_line_bytes;
356 ++x;
357
358 ptrpal = (gate_uint8_t const*)&palette[4 * (unsigned)(*ptr_line_bytes & 0x0f)];
359 current_pixel.b = ptrpal[0];
360 current_pixel.g = ptrpal[1];
361 current_pixel.r = ptrpal[2];
362 current_pixel.a = 255;
363 ++ptr_line_bytes;
364 break;
365 }
366 case 8:
367 {
368 ptrpal = (gate_uint8_t const*)&palette[4 * (gate_size_t)*ptr_line_bytes];
369 current_pixel.b = ptrpal[0];
370 current_pixel.g = ptrpal[1];
371 current_pixel.r = ptrpal[2];
372 current_pixel.a = 255;
373 ++ptr_line_bytes;
374 break;
375 }
376 case 15:
377 case 16:
378 {
379 current_pixel.b = (ptr_line_bytes[0] & 0x1f) << 3;
380 current_pixel.g = ((ptr_line_bytes[0] >> 5) | ((ptr_line_bytes[1] & 0x03) << 3)) << 3;
381 current_pixel.r = (ptr_line_bytes[1] & 0x7c) << 1;
382 current_pixel.a = 255;
383 ptr_line_bytes += 2;
384 break;
385 }
386 case 24:
387 {
388 current_pixel.b = ptr_line_bytes[0];
389 current_pixel.g = ptr_line_bytes[1];
390 current_pixel.r = ptr_line_bytes[2];
391 current_pixel.a = 255;
392 ptr_line_bytes += 3;
393 break;
394 }
395 case 32:
396 {
397 current_pixel.b = ptr_line_bytes[0];
398 current_pixel.g = ptr_line_bytes[1];
399 current_pixel.r = ptr_line_bytes[2];
400 current_pixel.a = ptr_line_bytes[3];
401 ptr_line_bytes += 4;
402 break;
403 }
404 }
405
406 gate_rasterimage_set_pixel(&raster, x, y, &current_pixel);
407 } /* for(x) */
408 } /* for(y) */
409 GATE_BREAK_IF_FAILED(result);
410
411 /* success case, transfer local image object into output object */
412 gate_mem_copy(image, &raster, sizeof(raster));
413 gate_mem_clear(&raster, sizeof(raster));
414 result = GATE_RESULT_OK;
415 } while (0);
416
417 if ((ptr_buffer != NULL) & (ptr_buffer != &buffer[0]))
418 {
419 gate_mem_dealloc(ptr_buffer);
420 }
421 gate_rasterimage_release(&raster);
422
423 return result;
424 }
425
426
427 19 gate_result_t gate_bitmapimage_load(gate_stream_t* srcstream, gate_rasterimage_t* image, gate_enumint_t flags)
428 {
429 static gate_size_t const header_min_size = 54;
430 char palette[1024];
431 19 char* ptr_buffer = &palette[0];
432 gate_result_t result;
433 gate_uint32_t filesize;
434 gate_uint32_t creatorid;
435 gate_uint32_t bmpoffset;
436 gate_size_t bufferused;
437 gate_bmp_header_t header;
438
439 gate_size_t linelen;
440 gate_size_t remain;
441 19 const gate_enumint_t load_pixel_format = flags & GATE_IMAGE_FLAG_DEPTHMASK;
442
443 (void)flags;
444
445 do
446 {
447 19 gate_rasterimage_create(image, GATE_IMAGE_PIXELFORMAT_DEFAULT, 0, 0, NULL);
448
449 19 result = gate_stream_read_block(srcstream, ptr_buffer, header_min_size, &bufferused);
450
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19 times.
19 if (GATE_FAILED(result))
451 {
452 result = GATE_RESULT_INVALIDINPUT;
453 break;
454 }
455
3/6
✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 19 times.
19 if (bufferused < header_min_size || (ptr_buffer[0] != 'B') || (ptr_buffer[1] != 'M'))
456 {
457 result = GATE_RESULT_INVALIDHEADER;
458 break;
459 }
460 19 gate_deserialize_uint32_l(&ptr_buffer[2], 4, &filesize);
461 19 gate_deserialize_uint32_l(&ptr_buffer[6], 4, &creatorid);
462 19 gate_deserialize_uint32_l(&ptr_buffer[10], 4, &bmpoffset);
463
464
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19 times.
19 if (bmpoffset < header_min_size)
465 {
466 result = GATE_RESULT_INVALIDHEADER;
467 break;
468 }
469
470 19 gate_deserialize_uint32_l(&ptr_buffer[14], 4, &header.header_sz);
471 19 gate_deserialize_int32_l(&ptr_buffer[18], 4, &header.width);
472 19 gate_deserialize_int32_l(&ptr_buffer[22], 4, &header.height);
473 19 gate_deserialize_uint16_l(&ptr_buffer[26], 2, &header.nplanes);
474 19 gate_deserialize_uint16_l(&ptr_buffer[28], 2, &header.bitspp);
475 19 gate_deserialize_uint32_l(&ptr_buffer[30], 4, &header.compress_type);
476 19 gate_deserialize_uint32_l(&ptr_buffer[34], 4, &header.bmp_bytesz);
477 19 gate_deserialize_int32_l(&ptr_buffer[38], 4, &header.hres);
478 19 gate_deserialize_int32_l(&ptr_buffer[42], 4, &header.vres);
479 19 gate_deserialize_uint32_l(&ptr_buffer[46], 4, &header.ncolors);
480 19 gate_deserialize_uint32_l(&ptr_buffer[50], 4, &header.nimpcolors);
481
482 19 result = GATE_RESULT_OK;
483
1/2
✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
19 switch (header.compress_type)
484 {
485 19 case 0: /* BI_RGB */
486 {
487 /* supported */
488 19 break;
489 }
490 case 1: /* BI_RLE8 */
491 case 2: /* BI_RLE4 */
492 case 3: /* BI_BITFIELDS */
493 case 4: /* BI_JPEG */
494 case 5: /* BI_PNG */
495 default: /* unknown */
496 {
497 /* unsupported encoding */
498 result = GATE_RESULT_NOTSUPPORTED;
499 break;
500 }
501 }
502
503
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19 times.
19 GATE_BREAK_IF_FAILED(result);
504
505
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 16 times.
19 if (bmpoffset > header_min_size)
506 {
507 3 result = gate_stream_read_block(srcstream, palette, bmpoffset - header_min_size, &bufferused);
508
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (GATE_FAILED(result))
509 {
510 result = GATE_RESULT_INVALIDHEADER;
511 break;
512 }
513
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (bufferused < (bmpoffset - header_min_size))
514 {
515 result = GATE_RESULT_INVALIDINPUT;
516 break;
517 }
518 }
519
520 19 linelen = 0;
521
522
4/7
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 16 times.
✗ Branch 6 not taken.
19 switch (header.bitspp)
523 {
524 1 case 1:
525 {
526 1 linelen = (header.width + 7) / 8;
527 1 break;
528 }
529 1 case 4:
530 {
531 1 linelen = (header.width + 1) / 2;
532 1 break;
533 }
534 1 case 8:
535 {
536 1 linelen = header.width;
537 1 break;
538 }
539 case 15:
540 case 16:
541 {
542 linelen = (gate_size_t)gate_math_abs_i32(header.width) * 2;
543 break;
544 }
545 case 24:
546 {
547 linelen = (gate_size_t)gate_math_abs_i32(header.width) * 3;
548 break;
549 }
550 16 case 32:
551 {
552 16 linelen = (gate_size_t)gate_math_abs_i32(header.width) * 4;
553 16 break;
554 }
555 }
556
557 19 remain = linelen % 4;
558
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19 times.
19 if (remain != 0)
559 {
560 linelen += 4 - remain;
561 }
562
563
1/5
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 19 times.
19 switch (load_pixel_format)
564 {
565 case GATE_IMAGE_FLAG_DEPTH_8GRAY: result = load_bitmap_generic(srcstream, &header, palette, linelen, GATE_IMAGE_PIXELFORMAT_GRAY8, image); break;
566 case GATE_IMAGE_FLAG_DEPTH_24RGB: result = load_bitmap_generic(srcstream, &header, palette, linelen, GATE_IMAGE_PIXELFORMAT_RGB24, image); break;
567 case GATE_IMAGE_FLAG_DEPTH_15RGB: result = load_bitmap_generic(srcstream, &header, palette, linelen, GATE_IMAGE_PIXELFORMAT_RGB555, image); break;
568 case GATE_IMAGE_FLAG_DEPTH_4COL:
569 case GATE_IMAGE_FLAG_DEPTH_8COL: result = load_bitmap_generic(srcstream, &header, palette, linelen, GATE_IMAGE_PIXELFORMAT_PAL8, image); break;
570 19 case GATE_IMAGE_FLAG_DEPTH_32RGBA:
571 case GATE_IMAGE_FLAG_DEPTH_DEF:
572 19 default: result = load_bitmap_as_rgba_image(srcstream, &header, palette, linelen, image); break;
573 }
574
575 } while (0);
576
577 19 return result;
578 }
579
580
581 128 static void GATE_CALL load_bgra_line(gate_uint8_t* bmp_buffer, gate_uint8_t const* ptr_line, gate_size_t length)
582 {
583 128 gate_mem_copy(bmp_buffer, ptr_line, length * 4);
584 128 }
585
586 16 gate_result_t gate_bitmapimage_save(gate_rasterimage_t const* image, gate_stream_t* deststream, gate_enumint_t flags)
587 {
588 gate_result_t result;
589 gate_size_t byteswritten;
590 char buffer[12288];
591 16 char* ptrbuffer = &buffer[0];
592
593 16 char header[54] = GATE_INIT_EMPTY;
594 gate_bmp_header_t bmp;
595 16 const gate_size_t bmp_linelen = (gate_size_t)image->width * 4; /* 4 bytes per pixel */
596 16 const gate_size_t bmp_datasize = bmp_linelen * image->height;
597
598 16 const gate_uint32_t filesize = (gate_uint32_t)bmp_datasize + 54;
599 16 gate_uint32_t creator = 0;
600 16 gate_uint32_t offset = 54;
601
602 16 void(GATE_CALL *line_writer)(gate_uint8_t*, gate_uint8_t const*, gate_size_t) = NULL;
603
604 (void)flags;
605
606 16 bmp.header_sz = 40;
607 16 bmp.width = (gate_int32_t)image->width;
608 16 bmp.height = (gate_int32_t)image->height;
609 16 bmp.nplanes = 1;
610 16 bmp.bitspp = 32;
611 16 bmp.compress_type = 0; /* no compression */
612 16 bmp.bmp_bytesz = (gate_uint32_t)bmp_datasize;
613 16 bmp.hres = 0;
614 16 bmp.vres = 0;
615 16 bmp.ncolors = 0;
616 16 bmp.nimpcolors = 0;
617
618 16 header[0] = 'B';
619 16 header[1] = 'M';
620 16 gate_serialize_uint32_l(&header[2], 4, &filesize);
621 16 gate_serialize_uint32_l(&header[6], 4, &creator);
622 16 gate_serialize_uint32_l(&header[10], 4, &offset);
623
624 16 gate_serialize_uint32_l(&header[14], 4, &bmp.header_sz);
625 16 gate_serialize_int32_l(&header[18], 4, &bmp.width);
626 16 gate_serialize_int32_l(&header[22], 4, &bmp.height);
627 16 gate_serialize_uint16_l(&header[26], 2, &bmp.nplanes);
628 16 gate_serialize_uint16_l(&header[28], 2, &bmp.bitspp);
629 16 gate_serialize_uint32_l(&header[30], 4, &bmp.compress_type);
630 16 gate_serialize_uint32_l(&header[34], 4, &bmp.bmp_bytesz);
631
632 16 gate_serialize_int32_l(&header[38], 4, &bmp.hres);
633 16 gate_serialize_int32_l(&header[42], 4, &bmp.vres);
634 16 gate_serialize_uint32_l(&header[46], 4, &bmp.ncolors);
635 16 gate_serialize_uint32_l(&header[50], 4, &bmp.nimpcolors);
636
637 do
638 {
639 16 const gate_size_t img_linelen =
640 16 (gate_size_t)(image->width * (unsigned)image->bits_per_pixel / 8u + (unsigned)image->line_padding);
641 gate_uint8_t const* ptrline;
642 gate_uint32_t y;
643
644
10/11
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 1 times.
✓ Branch 8 taken 1 times.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
16 switch (image->pixel_format)
645 {
646 5 case GATE_IMAGE_PIXELFORMAT_RGBA:
647 5 case GATE_IMAGE_PIXELFORMAT_RGB32: line_writer = &gate_color_convert_bgra_from_rgba_32; break;
648 2 case GATE_IMAGE_PIXELFORMAT_BGRA:
649 2 case GATE_IMAGE_PIXELFORMAT_BGR32: line_writer = &load_bgra_line; break;
650
651 2 case GATE_IMAGE_PIXELFORMAT_RGB24: line_writer = &gate_color_convert_bgra_from_rgb_24; break;
652 1 case GATE_IMAGE_PIXELFORMAT_BGR24: line_writer = &gate_color_convert_bgra_from_bgr_24; break;
653
654 1 case GATE_IMAGE_PIXELFORMAT_RGB555: line_writer = &gate_color_convert_bgra_from_rgb_15; break;
655 1 case GATE_IMAGE_PIXELFORMAT_RGB565: line_writer = &gate_color_convert_bgra_from_rgb_16; break;
656 1 case GATE_IMAGE_PIXELFORMAT_ARGB4: line_writer = &gate_color_convert_bgra_from_argb_16; break;
657 1 case GATE_IMAGE_PIXELFORMAT_YUV2: line_writer = &gate_color_convert_bgra_from_yuv2_16; break;
658
659 1 case GATE_IMAGE_PIXELFORMAT_PAL8: line_writer = &gate_color_convert_bgra_from_pal_8; break;
660 1 case GATE_IMAGE_PIXELFORMAT_GRAY8: line_writer = &gate_color_convert_bgra_from_gray_8; break;
661 default: break;
662 }
663
664
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
16 if (line_writer == NULL)
665 {
666 result = GATE_RESULT_INVALIDCONTENT;
667 break;
668 }
669
670
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
16 if (bmp_linelen > sizeof(buffer))
671 {
672 ptrbuffer = gate_mem_alloc(bmp_linelen);
673 if (ptrbuffer == NULL)
674 {
675 result = GATE_RESULT_OUTOFMEMORY;
676 break;
677 }
678 }
679
680 16 result = gate_stream_write_block(deststream, header, sizeof(header), &byteswritten);
681
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
16 if (GATE_FAILED(result))
682 {
683 result = GATE_RESULT_INVALIDOUTPUT;
684 break;
685 }
686
687 16 ptrline = (gate_uint8_t const*)gate_rasterimage_get_line_ptr(image, (image->height - 1));
688
689
2/2
✓ Branch 0 taken 1184 times.
✓ Branch 1 taken 16 times.
1200 for (y = 0; y != image->height; ++y)
690 {
691 1184 gate_uint8_t* ptrbyte = (gate_uint8_t*)ptrbuffer;
692 1184 line_writer(ptrbyte, ptrline, image->width);
693
694 1184 result = gate_stream_write_block(deststream, ptrbuffer, bmp_linelen, &byteswritten);
695
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1184 times.
1184 if (GATE_FAILED(result))
696 {
697 result = GATE_RESULT_INVALIDOUTPUT;
698 break;
699 }
700
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1184 times.
1184 GATE_DEBUG_ASSERT(bmp_linelen == byteswritten);
701
702 1184 ptrline -= img_linelen;
703 }
704 } while (0);
705
706
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
16 if ((ptrbuffer != &buffer[0]) && (ptrbuffer != NULL))
707 {
708 gate_mem_dealloc(ptrbuffer);
709 }
710
711 16 return result;
712 }
713