GCC Code Coverage Report


Directory: src/gate/
File: src/gate/graphics/jpegimages.c
Date: 2026-05-04 21:11:01
Exec Total Coverage
Lines: 150 284 52.8%
Functions: 11 20 55.0%
Branches: 29 110 26.4%

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/jpegimages.h"
30 #include "gate/results.h"
31 #include "gate/debugging.h"
32
33 #if defined(GATE_EXTLIB_LIBJPEG)
34 # define GATE_GRAPHICS_JPEG_USE_LIBJPEG 1
35 #else
36 # if defined(GATE_SYS_WIN) && !defined(GATE_SYS_WIN16)
37 # define GATE_GRAPHICS_JPEG_USE_OLE_IPICTURE 1
38 # else
39 # define GATE_GRAPHICS_JPEG_NO_IMPL 1
40 # endif
41 #endif
42
43 #if defined(GATE_GRAPHICS_JPEG_USE_LIBJPEG)
44
45 #include <stdio.h>
46 #include "jpeglib.h"
47 #include "jerror.h"
48 #include <setjmp.h>
49
50 typedef struct gate_jpeg_param_class
51 {
52 gate_stream_t* stream;
53 unsigned char buffer[GATE_MAX_STACK_COPYBUFFER_LENGTH];
54 gate_result_t result;
55 jmp_buf emergency_exit;
56 } gate_jpeg_param_t;
57
58 typedef struct gate_jpeg_error_mgr_class
59 {
60 struct jpeg_error_mgr error_mgr;
61 gate_jpeg_param_t* ptr_param;
62 } gate_jpeg_error_mgr_t;
63
64 static void gate_jpeg_error_exit(j_common_ptr cinfo)
65 {
66 /* just do nothing (instead of terminating the process which is the default) */
67 gate_jpeg_error_mgr_t* ptr_err;
68 gate_jpeg_param_t* param;
69
70 GATE_DEBUG_ASSERT(cinfo != NULL);
71 ptr_err = (gate_jpeg_error_mgr_t*)cinfo->err;
72 GATE_DEBUG_ASSERT(ptr_err != NULL);
73 param = ptr_err->ptr_param;
74 GATE_DEBUG_ASSERT(param != NULL);
75
76 GATE_DEBUG_TRACE_MSG_VALUE("jpeg_error", cinfo->err->msg_code);
77
78 switch (cinfo->err->msg_code)
79 {
80 case JERR_UNKNOWN_MARKER:
81 {
82 GATE_DEBUG_TRACE("ignore jpeg_error: unknown marker");
83 /* ignore, do nothing */
84 break;
85 }
86 case JERR_SOI_DUPLICATE:
87 {
88 GATE_DEBUG_TRACE("ignore jpeg_error: soi duplicate");
89 /* ignore, do nothing*/
90 break;
91 }
92 case JERR_BAD_LIB_VERSION:
93 {
94 GATE_DEBUG_TRACE_MSG_VALUE("jpeg_error: bad lib version", JPEG_LIB_VERSION);
95 /* the program was compiled with a different ABI than we have now available */
96 /* no break ! abort required */
97 }
98 default:
99 {
100 param->result = GATE_RESULT_FAILED;
101 longjmp(param->emergency_exit, 1);
102 }
103 }
104 }
105
106 3 static void gate_jpeg_init_source(struct jpeg_decompress_struct* decompress)
107 {
108 3 gate_jpeg_param_t* user_param = (gate_jpeg_param_t*)decompress->client_data;
109 3 decompress->src->next_input_byte = user_param->buffer;
110 3 decompress->src->bytes_in_buffer = 0;
111 3 }
112
113 3 static boolean gate_jpeg_fill_input_buffer(struct jpeg_decompress_struct* decompress)
114 {
115 3 gate_jpeg_param_t* user_param = (gate_jpeg_param_t*)decompress->client_data;
116 gate_size_t bufferused;
117 3 gate_result_t result = gate_stream_read_block(user_param->stream, (char*)&user_param->buffer[0], sizeof(user_param->buffer), &bufferused);
118
119
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (GATE_FAILED(result))
120 {
121 user_param->result = result;
122 return FALSE;
123 }
124 else
125 {
126 3 decompress->src->next_input_byte = user_param->buffer;
127 3 decompress->src->bytes_in_buffer = bufferused;
128 3 return TRUE;
129 }
130 }
131 static void gate_jpeg_skip_input_data(struct jpeg_decompress_struct* decompress, long num_bytes)
132 {
133 if (num_bytes > 0)
134 {
135 size_t nbytes = (size_t)num_bytes;
136 while (nbytes > decompress->src->bytes_in_buffer)
137 {
138 nbytes -= decompress->src->bytes_in_buffer;
139 if (!(*decompress->src->fill_input_buffer)(decompress))
140 {
141 /* error or EOF */
142 decompress->src->bytes_in_buffer = 0;
143 return;
144 }
145 }
146 decompress->src->next_input_byte += nbytes;
147 decompress->src->bytes_in_buffer -= nbytes;
148 }
149 }
150 static boolean gate_jpeg_resync_to_restart(struct jpeg_decompress_struct* decompress, int desired)
151 {
152 GATE_UNUSED_ARG(decompress);
153 GATE_UNUSED_ARG(desired);
154 return TRUE;
155 }
156 3 static void gate_jpeg_term_source(struct jpeg_decompress_struct* decompress)
157 {
158 GATE_UNUSED_ARG(decompress);
159 3 }
160
161 static boolean gate_jpeg_marker_parser(j_decompress_ptr cinfo)
162 {
163 GATE_UNUSED_ARG(cinfo);
164 /* additional markers are just "accepted" */
165 return TRUE;
166 }
167
168 static unsigned short rd16_le(unsigned char const* p)
169 {
170 return (unsigned short)p[0] | ((unsigned short)p[1] << 8);
171 }
172
173 static unsigned short rd16_be(unsigned char const* p)
174 {
175 return (unsigned short)p[1] | ((unsigned short)p[0] << 8);
176 }
177
178 static unsigned long rd32_le(unsigned char const* p)
179 {
180 return (unsigned long)p[0]
181 | ((unsigned long)p[1] << 8)
182 | ((unsigned long)p[2] << 16)
183 | ((unsigned long)p[3] << 24);
184 }
185
186 static unsigned long rd32_be(unsigned char const* p)
187 {
188 return (unsigned long)p[3]
189 | ((unsigned long)p[2] << 8)
190 | ((unsigned long)p[1] << 16)
191 | ((unsigned long)p[0] << 24);
192 }
193
194 3 static int gate_jpeg_read_orientation(j_decompress_ptr cinfo)
195 {
196 jpeg_saved_marker_ptr marker;
197
198
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 for (marker = cinfo->marker_list; marker; marker = marker->next)
199 {
200 if (marker->marker != JPEG_APP0 + 1)
201 {
202 /* other marker -> skip */
203 continue;
204 }
205 if (marker->data_length <= 6 || !gate_str_starts_with((char const*)marker->data, 6, "Exif\0\0", 6))
206 {
207 /* marker requirements not fulfilled */
208 continue;
209 }
210 else
211 {
212 int i;
213 const unsigned char *p = marker->data + 6; // TIFF header
214 int is_be = (p[0] == 'M' && p[1] == 'M');
215 unsigned short (*rd16)(const unsigned char*) = is_be ? rd16_be : rd16_le;
216 unsigned long (*rd32)(const unsigned char*) = is_be ? rd32_be : rd32_le;
217
218 unsigned int ifd0_offset = rd32(p + 4);
219 const unsigned char *ifd0 = p + ifd0_offset;
220
221 int num_entries = rd16(ifd0);
222 const unsigned char *entry = ifd0 + 2;
223
224 for (i = 0; i < num_entries; i++, entry += 12) {
225 unsigned short tag = rd16(entry);
226 if (tag == 0x0112) { // Orientation
227 unsigned short value = rd16(entry + 8);
228 return value;
229 }
230 }
231 }
232 }
233 3 return 1; // default orientation
234 }
235
236 3 gate_result_t gate_jpegimage_load_data(struct jpeg_decompress_struct* decompress, gate_jpeg_param_t* user_param, gate_rasterimage_t* image)
237 {
238 3 gate_result_t ret = GATE_RESULT_FAILED;
239 char buffer[4096 * 3];
240 3 char* ptrbuffer = &buffer[0];
241 3 gate_rasterimage_t raster = GATE_INIT_EMPTY;
242 3 int orientation = 1;
243
244 do
245 {
246 int jpeg_result;
247 gate_uint32_t scanline_length;
248 gate_color_t* ptrpixels;
249
250 3 jpeg_result = jpeg_read_header(decompress, TRUE);
251
252
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (jpeg_result != JPEG_HEADER_OK)
253 {
254 ret = GATE_RESULT_INVALIDHEADER;
255 break;
256 }
257
258 3 orientation = gate_jpeg_read_orientation(decompress);
259
260
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 if (FALSE == jpeg_start_decompress(decompress))
261 {
262 ret = GATE_RESULT_FAILED;
263 break;
264 }
265
266
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (NULL == gate_rasterimage_create(&raster, GATE_IMAGE_PIXELFORMAT_DEFAULT,
267 3 (gate_uint32_t)decompress->output_width,
268 3 (gate_uint32_t)decompress->output_height, NULL))
269 {
270 ret = GATE_RESULT_OUTOFMEMORY;
271 break;
272 }
273 3 ptrpixels = (gate_color_t*)gate_rasterimage_get_line_ptr(&raster, 0);
274
275 3 scanline_length = (gate_uint32_t)decompress->output_components * raster.width;
276
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (scanline_length > sizeof(buffer))
277 {
278 ptrbuffer = (char*)gate_mem_alloc(scanline_length);
279 if (ptrbuffer == NULL)
280 {
281 ret = GATE_RESULT_OUTOFMEMORY;
282 break;
283 }
284 }
285
286
2/2
✓ Branch 0 taken 288 times.
✓ Branch 1 taken 3 times.
291 while (decompress->output_scanline < decompress->output_height)
287 {
288 static const JDIMENSION jpeg_lines_to_read = 1;
289 gate_uint32_t x;
290 char* ptrbytes;
291
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 288 times.
288 if (jpeg_lines_to_read != jpeg_read_scanlines(decompress, (JSAMPARRAY)&ptrbuffer, jpeg_lines_to_read))
292 {
293 if (GATE_SUCCEEDED(user_param->result))
294 {
295 user_param->result = GATE_RESULT_INVALIDINPUT;
296 }
297 break;
298 }
299 288 ptrbytes = ptrbuffer;
300
1/3
✗ Branch 0 not taken.
✓ Branch 1 taken 288 times.
✗ Branch 2 not taken.
288 switch (decompress->output_components)
301 {
302 case 1:
303 {
304 for (x = 0; x != raster.width; ++x)
305 {
306 ptrpixels->r = *ptrbytes;
307 ptrpixels->g = *ptrbytes;
308 ptrpixels->b = *ptrbytes;
309 ptrpixels->a = 255;
310 ++ptrbytes;
311 ++ptrpixels;
312 }
313 break;
314 }
315 288 case 3:
316 {
317
2/2
✓ Branch 0 taken 34816 times.
✓ Branch 1 taken 288 times.
35104 for (x = 0; x != raster.width; ++x)
318 {
319 34816 ptrpixels->r = *(ptrbytes++);
320 34816 ptrpixels->g = *(ptrbytes++);
321 34816 ptrpixels->b = *(ptrbytes++);
322 34816 ptrpixels->a = 255;
323 34816 ++ptrpixels;
324 }
325 288 break;
326 }
327 default:
328 {
329 decompress->output_scanline = raster.height;
330 user_param->result = GATE_RESULT_NOTSUPPORTED;
331 break;
332 }
333 }
334 }
335
336 3 jpeg_finish_decompress(decompress);
337
338 3 ret = user_param->result;
339
340 } while (0);
341
342
343
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (GATE_SUCCEEDED(ret))
344 {
345
1/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
3 switch(orientation)
346 {
347 case 3:
348 {
349 /* rotation 180 */
350 gate_rasterimage_roll_over(&raster, &raster);
351 gate_mem_copy(image, &raster, sizeof(raster)); /* take ownership */
352 gate_mem_clear(&raster, sizeof(raster)); /* data was moved, clear previous owner */
353 break;
354 }
355 case 6:
356 {
357 /* rotation 90 */
358 gate_rasterimage_rotate_left(image, &raster); /* create new image */
359 break;
360 }
361 case 8:
362 {
363 /* rotation 270 */
364 ret = gate_rasterimage_rotate_right(image, &raster); /* create new image */
365 break;
366 }
367 3 default:
368 {
369 /* take as is */
370 3 gate_mem_copy(image, &raster, sizeof(raster)); /* take ownership */
371 3 gate_mem_clear(&raster, sizeof(raster)); /* data was moved, clear previous owner */
372 3 break;
373 }
374 }
375 }
376
377 3 gate_rasterimage_release(&raster); /* release temporary image */
378
379
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
3 if ((ptrbuffer != &buffer[0]) && (ptrbuffer != NULL))
380 {
381 gate_mem_dealloc(ptrbuffer);
382 }
383
384 3 return ret;
385 }
386
387 3 gate_result_t gate_jpegimage_load(gate_stream_t* srcstream, gate_rasterimage_t* image, gate_enumint_t flags)
388 {
389 3 gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED;
390 3 gate_jpeg_error_mgr_t error_mgr = GATE_INIT_EMPTY;
391 3 struct jpeg_source_mgr source_mgr = GATE_INIT_EMPTY;
392 3 struct jpeg_decompress_struct decompress = GATE_INIT_EMPTY;
393 3 gate_jpeg_param_t user_param = GATE_INIT_EMPTY;
394
395 3 user_param.stream = srcstream;
396 3 user_param.result = GATE_RESULT_OK;
397
398 3 decompress.err = jpeg_std_error(&error_mgr.error_mgr);
399 3 error_mgr.error_mgr.error_exit = &gate_jpeg_error_exit;
400 3 error_mgr.ptr_param = &user_param;
401
402 3 jpeg_create_decompress(&decompress);
403
404 3 source_mgr.fill_input_buffer = &gate_jpeg_fill_input_buffer;
405 3 source_mgr.init_source = &gate_jpeg_init_source;
406 3 source_mgr.resync_to_restart = &gate_jpeg_resync_to_restart;
407 3 source_mgr.skip_input_data = &gate_jpeg_skip_input_data;
408 3 source_mgr.term_source = &gate_jpeg_term_source;
409 3 source_mgr.bytes_in_buffer = 0;
410 3 source_mgr.next_input_byte = NULL;
411
412 3 decompress.src = &source_mgr;
413 3 decompress.client_data = &user_param;
414
415 3 jpeg_set_marker_processor(&decompress, JPEG_COM, &gate_jpeg_marker_parser);
416 3 jpeg_set_marker_processor(&decompress, JPEG_APP0 + 12, &gate_jpeg_marker_parser);
417 3 jpeg_save_markers(&decompress, JPEG_APP0 + 1, 0xFFFF);
418
419 do
420 {
421
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 if (0 == setjmp(user_param.emergency_exit))
422 {
423 3 ret = gate_jpegimage_load_data(&decompress, &user_param, image);
424 }
425 else /* setjmp error case */
426 {
427 /* jpeg emergency exit point reached */
428 ret = GATE_RESULT_CRITICALERROR;
429 }
430 } while (0);
431
432 3 jpeg_destroy_decompress(&decompress);
433 3 return ret;
434 }
435
436
437
438
439
440 6 static void gate_jpeg_init_destination(struct jpeg_compress_struct* compress)
441 {
442 6 gate_jpeg_param_t* user_param = (gate_jpeg_param_t*)compress->client_data;
443 6 compress->dest->free_in_buffer = sizeof(user_param->buffer);
444 6 compress->dest->next_output_byte = &user_param->buffer[0];
445 6 }
446
447 3 static boolean gate_jpeg_flush_output_buffer(struct jpeg_compress_struct* compress, gate_jpeg_param_t* user_param, gate_size_t bufferused)
448 {
449
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (bufferused != 0)
450 {
451 gate_size_t byteswritten;
452 3 gate_result_t result = gate_stream_write_block(user_param->stream, (char const*)user_param->buffer, bufferused, &byteswritten);
453
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (GATE_FAILED(result))
454 {
455 user_param->result = result;
456 return FALSE;
457 }
458 }
459 3 gate_jpeg_init_destination(compress);
460 3 return TRUE;
461 }
462
463 static boolean gate_jpeg_empty_output_buffer(struct jpeg_compress_struct* compress)
464 {
465 gate_jpeg_param_t* user_param = (gate_jpeg_param_t*)compress->client_data;
466 return gate_jpeg_flush_output_buffer(compress, user_param, sizeof(user_param->buffer));
467 }
468
469 3 static void gate_jpeg_term_destination(struct jpeg_compress_struct* compress)
470 {
471 3 gate_jpeg_param_t* user_param = (gate_jpeg_param_t*)compress->client_data;
472
473
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 GATE_DEBUG_ASSERT(sizeof(user_param->buffer) >= compress->dest->free_in_buffer);
474 3 gate_jpeg_flush_output_buffer(compress, user_param, sizeof(user_param->buffer) - compress->dest->free_in_buffer);
475 3 }
476
477 3 static gate_result_t gate_jpegimage_save_data(gate_rasterimage_t const* image,
478 struct jpeg_destination_mgr* destination_mgr,
479 struct jpeg_compress_struct* compress,
480 gate_jpeg_param_t* user_param,
481 gate_uint8_t qualitypercent)
482 {
483 3 gate_result_t ret = GATE_RESULT_FAILED;
484 unsigned char buffer[4096 * 3];
485 3 unsigned char* ptrbuffer = &buffer[0];
486
487 do
488 {
489 gate_size_t required_buffer_size;
490 unsigned int y;
491 3 void(*line_writer)(gate_uint8_t*, gate_uint8_t const*, gate_size_t) = NULL;
492
493
2/11
✓ Branch 0 taken 2 times.
✗ 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.
3 switch (image->pixel_format)
494 {
495 2 case GATE_IMAGE_PIXELFORMAT_RGBA:
496 2 case GATE_IMAGE_PIXELFORMAT_RGB32: line_writer = &gate_color_convert_rgb_from_rgba_32; break;
497 case GATE_IMAGE_PIXELFORMAT_BGRA:
498 case GATE_IMAGE_PIXELFORMAT_BGR32: line_writer = &gate_color_convert_rgb_from_bgra_32; break;
499
500 1 case GATE_IMAGE_PIXELFORMAT_RGB24: line_writer = &gate_color_convert_rgb_from_rgb_24; break;
501 case GATE_IMAGE_PIXELFORMAT_BGR24: line_writer = &gate_color_convert_rgb_from_bgr_24; break;
502
503 case GATE_IMAGE_PIXELFORMAT_RGB555: line_writer = &gate_color_convert_rgb_from_rgb_15; break;
504 case GATE_IMAGE_PIXELFORMAT_RGB565: line_writer = &gate_color_convert_rgb_from_rgb_16; break;
505 case GATE_IMAGE_PIXELFORMAT_ARGB4: line_writer = &gate_color_convert_rgb_from_argb_16; break;
506 case GATE_IMAGE_PIXELFORMAT_YUV2: line_writer = &gate_color_convert_rgb_from_yuv2_16; break;
507
508 case GATE_IMAGE_PIXELFORMAT_PAL8: line_writer = &gate_color_convert_rgb_from_pal_8; break;
509 case GATE_IMAGE_PIXELFORMAT_GRAY8: line_writer = &gate_color_convert_rgb_from_gray_8; break;
510 default: break;
511 }
512
513
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (NULL == line_writer)
514 {
515 ret = GATE_RESULT_NOTSUPPORTED;
516 break;
517 }
518
519 3 required_buffer_size = (gate_size_t)image->width * 3;
520
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (required_buffer_size > sizeof(buffer))
521 {
522 ptrbuffer = (unsigned char*)gate_mem_alloc(required_buffer_size);
523 if (ptrbuffer == NULL)
524 {
525 ret = GATE_RESULT_OUTOFMEMORY;
526 break;
527 }
528 }
529
530 3 jpeg_create_compress(compress);
531 3 compress->in_color_space = JCS_RGB;
532 3 compress->input_components = 3;
533 3 compress->image_width = (JDIMENSION)image->width;
534 3 compress->image_height = (JDIMENSION)image->height;
535 3 compress->dct_method = JDCT_FLOAT;
536
537 3 jpeg_set_defaults(compress);
538 3 compress->client_data = user_param;
539 3 compress->dest = destination_mgr;
540 3 jpeg_set_quality(compress, (int)((qualitypercent > 100) ? 100 : qualitypercent), TRUE);
541
542 3 jpeg_start_compress(compress, TRUE);
543
544
545
546
2/2
✓ Branch 0 taken 288 times.
✓ Branch 1 taken 3 times.
291 for (y = 0; y != image->height; ++y)
547 {
548 288 gate_uint8_t const* ptrpixels = (gate_uint8_t const*)gate_rasterimage_get_line_ptr(image, y);
549 288 line_writer(ptrbuffer, ptrpixels, image->width);
550
551
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 288 times.
288 if (1 != jpeg_write_scanlines(compress, (JSAMPARRAY)&ptrbuffer, 1))
552 {
553 /* failed to write one line */
554 if (GATE_SUCCEEDED(user_param->result))
555 {
556 user_param->result = GATE_RESULT_INVALIDOUTPUT;
557 break;
558 }
559 }
560 }
561
562 3 jpeg_finish_compress(compress);
563 3 jpeg_destroy_compress(compress);
564
565 3 ret = user_param->result;
566 } while (0);
567
568
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
3 if ((ptrbuffer != &buffer[0]) && (ptrbuffer != NULL))
569 {
570 gate_mem_dealloc(ptrbuffer);
571 }
572 3 return ret;
573 }
574
575 3 gate_result_t gate_jpegimage_save(gate_rasterimage_t const* image, gate_stream_t* deststream, gate_enumint_t flags)
576 {
577 gate_result_t ret;
578 3 gate_jpeg_param_t user_param = GATE_INIT_EMPTY;
579 3 gate_jpeg_error_mgr_t error_mgr = GATE_INIT_EMPTY;
580 3 struct jpeg_destination_mgr destination_mgr = GATE_INIT_EMPTY;
581 3 struct jpeg_compress_struct compress = GATE_INIT_EMPTY;
582 3 const gate_uint16_t qa0to15 = (gate_uint16_t)GATE_IMAGE_FLAG_DECODE_QUALITY(flags);
583
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 const gate_uint8_t qualitypercent = (qa0to15 > 0)
584 ? (gate_uint8_t)(qa0to15 * 100 / 15)
585 : 90;
586
587 3 user_param.result = GATE_RESULT_OK;
588 3 user_param.stream = deststream;
589
590 3 compress.err = jpeg_std_error(&error_mgr.error_mgr);
591 3 error_mgr.error_mgr.error_exit = &gate_jpeg_error_exit;
592 3 error_mgr.ptr_param = &user_param;
593
594 3 destination_mgr.empty_output_buffer = &gate_jpeg_empty_output_buffer;
595 3 destination_mgr.init_destination = &gate_jpeg_init_destination;
596 3 destination_mgr.term_destination = &gate_jpeg_term_destination;
597 3 destination_mgr.free_in_buffer = 0;
598 3 destination_mgr.next_output_byte = NULL;
599
600 do
601 {
602
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 if (0 == setjmp(user_param.emergency_exit))
603 {
604 3 ret = gate_jpegimage_save_data(image, &destination_mgr, &compress, &user_param, qualitypercent);
605 }
606 else /* setjmp error case */
607 {
608 /* jpeg emergency exit point reached */
609 ret = GATE_RESULT_CRITICALERROR;
610 }
611 } while (0);
612 3 return ret;
613 }
614
615 #endif /* GATE_GRAPHICS_JPEG_USE_LIBJPEG */
616
617
618
619 #if defined(GATE_GRAPHICS_JPEG_USE_OLE_IPICTURE)
620
621 #include "gate/graphics/platform/win32_olepicture.h"
622
623 gate_result_t gate_jpegimage_load(gate_stream_t* srcstream, gate_rasterimage_t* image, gate_enumint_t flags)
624 {
625 return gate_win32_load_ole_picture_file(srcstream, image);
626 }
627
628 gate_result_t gate_jpegimage_save(gate_rasterimage_t const* image, gate_stream_t* deststream, gate_enumint_t flags)
629 {
630 (void)image;
631 (void)deststream;
632 (void)flags;
633 return GATE_RESULT_NOTIMPLEMENTED;
634 }
635
636 #endif /* GATE_GRAPHICS_JPEG_USE_OLE_IPICTURE */
637
638
639
640 #if defined(GATE_GRAPHICS_JPEG_NO_IMPL)
641
642 gate_result_t gate_jpegimage_load(gate_stream_t* srcstream, gate_rasterimage_t* image, gate_enumint_t flags)
643 {
644 (void)srcstream;
645 (void)image;
646 (void)flags;
647 return GATE_RESULT_NOTIMPLEMENTED;
648 }
649
650 gate_result_t gate_jpegimage_save(gate_rasterimage_t const* image, gate_stream_t* deststream, gate_enumint_t flags)
651 {
652 (void)image;
653 (void)deststream;
654 (void)flags;
655 return GATE_RESULT_NOTIMPLEMENTED;
656 }
657
658 #endif
659
660