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/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 | ||
35 | #else | ||
36 | # define GATE_GRAPHICS_JPEG_NO_IMPL | ||
37 | #endif | ||
38 | |||
39 | #if defined(GATE_GRAPHICS_JPEG_USE_LIBJPEG) | ||
40 | |||
41 | #include <stdio.h> | ||
42 | #include "jpeglib.h" | ||
43 | #include "jerror.h" | ||
44 | #include <setjmp.h> | ||
45 | |||
46 | typedef struct gate_jpeg_param_class | ||
47 | { | ||
48 | gate_stream_t* stream; | ||
49 | unsigned char buffer[GATE_MAX_STACK_COPYBUFFER_LENGTH]; | ||
50 | gate_result_t result; | ||
51 | jmp_buf emergency_exit; | ||
52 | } gate_jpeg_param_t; | ||
53 | |||
54 | typedef struct gate_jpeg_error_mgr_class | ||
55 | { | ||
56 | struct jpeg_error_mgr error_mgr; | ||
57 | gate_jpeg_param_t* ptr_param; | ||
58 | } gate_jpeg_error_mgr_t; | ||
59 | |||
60 | ✗ | static void gate_jpeg_error_exit(j_common_ptr cinfo) | |
61 | { | ||
62 | /* just do nothing (instead of terminating the process which is the default) */ | ||
63 | gate_jpeg_error_mgr_t* ptr_err; | ||
64 | gate_jpeg_param_t* param; | ||
65 | |||
66 | ✗ | GATE_DEBUG_ASSERT(cinfo != NULL); | |
67 | ✗ | ptr_err = (gate_jpeg_error_mgr_t*)cinfo->err; | |
68 | ✗ | GATE_DEBUG_ASSERT(ptr_err != NULL); | |
69 | ✗ | param = ptr_err->ptr_param; | |
70 | ✗ | GATE_DEBUG_ASSERT(param != NULL); | |
71 | |||
72 | ✗ | GATE_DEBUG_TRACE_MSG_VALUE("jpeg_error", cinfo->err->msg_code); | |
73 | |||
74 | ✗ | switch (cinfo->err->msg_code) | |
75 | { | ||
76 | ✗ | case JERR_UNKNOWN_MARKER: | |
77 | { | ||
78 | ✗ | GATE_DEBUG_TRACE("ignore jpeg_error: unknown marker"); | |
79 | /* ignore, do nothing */ | ||
80 | ✗ | break; | |
81 | } | ||
82 | ✗ | case JERR_SOI_DUPLICATE: | |
83 | { | ||
84 | ✗ | GATE_DEBUG_TRACE("ignore jpeg_error: soi duplicate"); | |
85 | /* ignore, do nothing*/ | ||
86 | ✗ | break; | |
87 | } | ||
88 | ✗ | case JERR_BAD_LIB_VERSION: | |
89 | { | ||
90 | ✗ | GATE_DEBUG_TRACE_MSG_VALUE("jpeg_error: bad lib version", JPEG_LIB_VERSION); | |
91 | /* no break ! */ | ||
92 | } | ||
93 | ✗ | default: | |
94 | { | ||
95 | ✗ | param->result = GATE_RESULT_FAILED; | |
96 | ✗ | longjmp(param->emergency_exit, 1); | |
97 | break; | ||
98 | } | ||
99 | } | ||
100 | ✗ | } | |
101 | |||
102 | 1 | static void gate_jpeg_init_source(struct jpeg_decompress_struct* decompress) | |
103 | { | ||
104 | 1 | gate_jpeg_param_t* user_param = (gate_jpeg_param_t*)decompress->client_data; | |
105 | 1 | decompress->src->next_input_byte = user_param->buffer; | |
106 | 1 | decompress->src->bytes_in_buffer = 0; | |
107 | 1 | } | |
108 | |||
109 | 1 | static boolean gate_jpeg_fill_input_buffer(struct jpeg_decompress_struct* decompress) | |
110 | { | ||
111 | 1 | gate_jpeg_param_t* user_param = (gate_jpeg_param_t*)decompress->client_data; | |
112 | gate_size_t bufferused; | ||
113 | 1 | gate_result_t result = gate_stream_read_block(user_param->stream, (char*)&user_param->buffer[0], sizeof(user_param->buffer), &bufferused); | |
114 | |||
115 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (GATE_FAILED(result)) |
116 | { | ||
117 | ✗ | user_param->result = result; | |
118 | ✗ | return FALSE; | |
119 | } | ||
120 | else | ||
121 | { | ||
122 | 1 | decompress->src->next_input_byte = user_param->buffer; | |
123 | 1 | decompress->src->bytes_in_buffer = bufferused; | |
124 | 1 | return TRUE; | |
125 | } | ||
126 | } | ||
127 | ✗ | static void gate_jpeg_skip_input_data(struct jpeg_decompress_struct* decompress, long num_bytes) | |
128 | { | ||
129 | size_t nbytes; | ||
130 | ✗ | if (num_bytes > 0) | |
131 | { | ||
132 | ✗ | nbytes = (size_t)num_bytes; | |
133 | ✗ | while (nbytes > decompress->src->bytes_in_buffer) | |
134 | { | ||
135 | ✗ | nbytes -= decompress->src->bytes_in_buffer; | |
136 | ✗ | if (!(*decompress->src->fill_input_buffer)(decompress)) | |
137 | { | ||
138 | /* error or EOF */ | ||
139 | ✗ | decompress->src->bytes_in_buffer = 0; | |
140 | ✗ | return; | |
141 | } | ||
142 | } | ||
143 | ✗ | decompress->src->next_input_byte += nbytes; | |
144 | ✗ | decompress->src->bytes_in_buffer -= nbytes; | |
145 | } | ||
146 | } | ||
147 | ✗ | static boolean gate_jpeg_resync_to_restart(struct jpeg_decompress_struct* decompress, int desired) | |
148 | { | ||
149 | GATE_UNUSED_ARG(decompress); | ||
150 | GATE_UNUSED_ARG(desired); | ||
151 | ✗ | return TRUE; | |
152 | } | ||
153 | 1 | static void gate_jpeg_term_source(struct jpeg_decompress_struct* decompress) | |
154 | { | ||
155 | GATE_UNUSED_ARG(decompress); | ||
156 | 1 | } | |
157 | |||
158 | ✗ | static boolean gate_jpeg_marker_parser(j_decompress_ptr cinfo) | |
159 | { | ||
160 | GATE_UNUSED_ARG(cinfo); | ||
161 | /* additional markers are just "accepted" */ | ||
162 | ✗ | return TRUE; | |
163 | } | ||
164 | |||
165 | 1 | gate_result_t gate_jpegimage_load_data(struct jpeg_decompress_struct* decompress, gate_jpeg_param_t* user_param, gate_rasterimage_t* image) | |
166 | { | ||
167 | 1 | gate_result_t ret = GATE_RESULT_FAILED; | |
168 | static const JDIMENSION jpeg_lines_to_read = 1; | ||
169 | char buffer[4096 * 3]; | ||
170 | 1 | char* ptrbuffer = &buffer[0]; | |
171 | int jpeg_result; | ||
172 | gate_uint32_t scanline_length; | ||
173 | char* ptrbytes; | ||
174 | gate_color_t* ptrpixels; | ||
175 | gate_uint32_t x; | ||
176 | 1 | gate_rasterimage_t raster = GATE_INIT_EMPTY; | |
177 | |||
178 | do | ||
179 | { | ||
180 | 1 | jpeg_result = jpeg_read_header(decompress, TRUE); | |
181 | |||
182 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (jpeg_result != JPEG_HEADER_OK) |
183 | { | ||
184 | ✗ | ret = GATE_RESULT_INVALIDHEADER; | |
185 | ✗ | break; | |
186 | } | ||
187 | |||
188 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | if (FALSE == jpeg_start_decompress(decompress)) |
189 | { | ||
190 | ✗ | ret = GATE_RESULT_FAILED; | |
191 | ✗ | break; | |
192 | } | ||
193 | |||
194 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (NULL == gate_rasterimage_create(&raster, GATE_IMAGE_PIXELFORMAT_DEFAULT, |
195 | 1 | (gate_uint32_t)decompress->output_width, | |
196 | 1 | (gate_uint32_t)decompress->output_height, NULL)) | |
197 | { | ||
198 | ✗ | ret = GATE_RESULT_OUTOFMEMORY; | |
199 | ✗ | break; | |
200 | } | ||
201 | 1 | ptrpixels = (gate_color_t*)gate_rasterimage_get_line_ptr(&raster, 0); | |
202 | |||
203 | 1 | scanline_length = (gate_uint32_t)decompress->output_components * raster.width; | |
204 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (scanline_length > sizeof(buffer)) |
205 | { | ||
206 | ✗ | ptrbuffer = (char*)gate_mem_alloc(scanline_length); | |
207 | ✗ | if (ptrbuffer == NULL) | |
208 | { | ||
209 | ✗ | ret = GATE_RESULT_OUTOFMEMORY; | |
210 | ✗ | break; | |
211 | } | ||
212 | } | ||
213 | |||
214 |
2/2✓ Branch 0 taken 32 times.
✓ Branch 1 taken 1 times.
|
33 | while (decompress->output_scanline < decompress->output_height) |
215 | { | ||
216 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 32 times.
|
32 | if (jpeg_lines_to_read != jpeg_read_scanlines(decompress, (JSAMPARRAY)&ptrbuffer, jpeg_lines_to_read)) |
217 | { | ||
218 | ✗ | if (GATE_SUCCEEDED(user_param->result)) | |
219 | { | ||
220 | ✗ | user_param->result = GATE_RESULT_INVALIDINPUT; | |
221 | } | ||
222 | ✗ | break; | |
223 | } | ||
224 | 32 | ptrbytes = ptrbuffer; | |
225 |
1/3✗ Branch 0 not taken.
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
|
32 | switch (decompress->output_components) |
226 | { | ||
227 | ✗ | case 1: | |
228 | { | ||
229 | ✗ | for (x = 0; x != raster.width; ++x) | |
230 | { | ||
231 | ✗ | ptrpixels->r = *ptrbytes; | |
232 | ✗ | ptrpixels->g = *ptrbytes; | |
233 | ✗ | ptrpixels->b = *ptrbytes; | |
234 | ✗ | ptrpixels->a = 255; | |
235 | ✗ | ++ptrbytes; | |
236 | ✗ | ++ptrpixels; | |
237 | } | ||
238 | ✗ | break; | |
239 | } | ||
240 | 32 | case 3: | |
241 | { | ||
242 |
2/2✓ Branch 0 taken 2048 times.
✓ Branch 1 taken 32 times.
|
2080 | for (x = 0; x != raster.width; ++x) |
243 | { | ||
244 | 2048 | ptrpixels->r = *(ptrbytes++); | |
245 | 2048 | ptrpixels->g = *(ptrbytes++); | |
246 | 2048 | ptrpixels->b = *(ptrbytes++); | |
247 | 2048 | ptrpixels->a = 255; | |
248 | 2048 | ++ptrpixels; | |
249 | } | ||
250 | 32 | break; | |
251 | } | ||
252 | ✗ | default: | |
253 | { | ||
254 | ✗ | decompress->output_scanline = raster.height; | |
255 | ✗ | user_param->result = GATE_RESULT_NOTSUPPORTED; | |
256 | ✗ | break; | |
257 | } | ||
258 | } | ||
259 | |||
260 | } | ||
261 | |||
262 | 1 | jpeg_finish_decompress(decompress); | |
263 | |||
264 | 1 | ret = user_param->result; | |
265 | |||
266 | } while (0); | ||
267 | |||
268 | |||
269 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (GATE_SUCCEEDED(ret)) |
270 | { | ||
271 | 1 | gate_mem_copy(image, &raster, sizeof(raster)); | |
272 | 1 | gate_mem_clear(&raster, sizeof(raster)); | |
273 | } | ||
274 | |||
275 | 1 | gate_rasterimage_release(&raster); | |
276 | |||
277 |
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)) |
278 | { | ||
279 | ✗ | gate_mem_dealloc(ptrbuffer); | |
280 | } | ||
281 | |||
282 | 1 | return ret; | |
283 | } | ||
284 | |||
285 | 1 | gate_result_t gate_jpegimage_load(gate_stream_t* srcstream, gate_rasterimage_t* image, gate_enumint_t flags) | |
286 | { | ||
287 | 1 | gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED; | |
288 | 1 | gate_jpeg_error_mgr_t error_mgr = GATE_INIT_EMPTY; | |
289 | 1 | struct jpeg_source_mgr source_mgr = GATE_INIT_EMPTY; | |
290 | 1 | struct jpeg_decompress_struct decompress = GATE_INIT_EMPTY; | |
291 | 1 | gate_jpeg_param_t user_param = GATE_INIT_EMPTY; | |
292 | |||
293 | 1 | user_param.stream = srcstream; | |
294 | 1 | user_param.result = GATE_RESULT_OK; | |
295 | |||
296 | 1 | decompress.err = jpeg_std_error(&error_mgr.error_mgr); | |
297 | 1 | error_mgr.error_mgr.error_exit = &gate_jpeg_error_exit; | |
298 | 1 | error_mgr.ptr_param = &user_param; | |
299 | |||
300 | 1 | jpeg_create_decompress(&decompress); | |
301 | |||
302 | 1 | source_mgr.fill_input_buffer = &gate_jpeg_fill_input_buffer; | |
303 | 1 | source_mgr.init_source = &gate_jpeg_init_source; | |
304 | 1 | source_mgr.resync_to_restart = &gate_jpeg_resync_to_restart; | |
305 | 1 | source_mgr.skip_input_data = &gate_jpeg_skip_input_data; | |
306 | 1 | source_mgr.term_source = &gate_jpeg_term_source; | |
307 | 1 | source_mgr.bytes_in_buffer = 0; | |
308 | 1 | source_mgr.next_input_byte = NULL; | |
309 | |||
310 | 1 | decompress.src = &source_mgr; | |
311 | 1 | decompress.client_data = &user_param; | |
312 | |||
313 | 1 | jpeg_set_marker_processor(&decompress, JPEG_COM, &gate_jpeg_marker_parser); | |
314 | 1 | jpeg_set_marker_processor(&decompress, JPEG_APP0 + 12, &gate_jpeg_marker_parser); | |
315 | |||
316 | do | ||
317 | { | ||
318 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | if (0 == setjmp(user_param.emergency_exit)) |
319 | { | ||
320 | 1 | ret = gate_jpegimage_load_data(&decompress, &user_param, image); | |
321 | } | ||
322 | else /* setjmp error case */ | ||
323 | { | ||
324 | /* jpeg emergency exit point reached */ | ||
325 | ✗ | ret = GATE_RESULT_CRITICALERROR; | |
326 | } | ||
327 | } while (0); | ||
328 | |||
329 | 1 | jpeg_destroy_decompress(&decompress); | |
330 | 1 | return ret; | |
331 | } | ||
332 | |||
333 | |||
334 | |||
335 | |||
336 | |||
337 | 2 | static void gate_jpeg_init_destination(struct jpeg_compress_struct* compress) | |
338 | { | ||
339 | 2 | gate_jpeg_param_t* user_param = (gate_jpeg_param_t*)compress->client_data; | |
340 | 2 | compress->dest->free_in_buffer = sizeof(user_param->buffer); | |
341 | 2 | compress->dest->next_output_byte = &user_param->buffer[0]; | |
342 | 2 | } | |
343 | |||
344 | 1 | static boolean gate_jpeg_flush_output_buffer(struct jpeg_compress_struct* compress, gate_jpeg_param_t* user_param, gate_size_t bufferused) | |
345 | { | ||
346 | gate_result_t result; | ||
347 | gate_size_t byteswritten; | ||
348 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (bufferused != 0) |
349 | { | ||
350 | 1 | result = gate_stream_write_block(user_param->stream, (char const*)user_param->buffer, bufferused, &byteswritten); | |
351 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (GATE_FAILED(result)) |
352 | { | ||
353 | ✗ | user_param->result = result; | |
354 | ✗ | return FALSE; | |
355 | } | ||
356 | } | ||
357 | 1 | gate_jpeg_init_destination(compress); | |
358 | 1 | return TRUE; | |
359 | } | ||
360 | |||
361 | ✗ | static boolean gate_jpeg_empty_output_buffer(struct jpeg_compress_struct* compress) | |
362 | { | ||
363 | ✗ | gate_jpeg_param_t* user_param = (gate_jpeg_param_t*)compress->client_data; | |
364 | ✗ | return gate_jpeg_flush_output_buffer(compress, user_param, sizeof(user_param->buffer)); | |
365 | } | ||
366 | |||
367 | 1 | static void gate_jpeg_term_destination(struct jpeg_compress_struct* compress) | |
368 | { | ||
369 | 1 | gate_jpeg_param_t* user_param = (gate_jpeg_param_t*)compress->client_data; | |
370 | |||
371 | 1 | GATE_DEBUG_ASSERT(sizeof(user_param->buffer) >= compress->dest->free_in_buffer); | |
372 | 1 | gate_jpeg_flush_output_buffer(compress, user_param, sizeof(user_param->buffer) - compress->dest->free_in_buffer); | |
373 | 1 | } | |
374 | |||
375 | 1 | static gate_result_t gate_jpegimage_save_data(gate_rasterimage_t const* image, | |
376 | struct jpeg_destination_mgr* destination_mgr, | ||
377 | struct jpeg_compress_struct* compress, | ||
378 | gate_jpeg_param_t* user_param, | ||
379 | gate_uint8_t qualitypercent) | ||
380 | { | ||
381 | 1 | gate_result_t ret = GATE_RESULT_FAILED; | |
382 | unsigned char buffer[4096 * 3]; | ||
383 | 1 | unsigned char* ptrbuffer = &buffer[0]; | |
384 | gate_size_t required_buffer_size; | ||
385 | unsigned int y; | ||
386 | gate_uint8_t const* ptrpixels; | ||
387 | 1 | void(*line_writer)(gate_uint8_t*, gate_uint8_t const*, gate_size_t) = NULL; | |
388 | |||
389 | do | ||
390 | { | ||
391 |
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) |
392 | { | ||
393 | ✗ | case GATE_IMAGE_PIXELFORMAT_RGBA: | |
394 | ✗ | case GATE_IMAGE_PIXELFORMAT_RGB32: line_writer = &gate_color_convert_rgb_from_rgba_32; break; | |
395 | ✗ | case GATE_IMAGE_PIXELFORMAT_BGRA: | |
396 | ✗ | case GATE_IMAGE_PIXELFORMAT_BGR32: line_writer = &gate_color_convert_rgb_from_bgra_32; break; | |
397 | |||
398 | 1 | case GATE_IMAGE_PIXELFORMAT_RGB24: line_writer = &gate_color_convert_rgb_from_rgb_24; break; | |
399 | ✗ | case GATE_IMAGE_PIXELFORMAT_BGR24: line_writer = &gate_color_convert_rgb_from_bgr_24; break; | |
400 | |||
401 | ✗ | case GATE_IMAGE_PIXELFORMAT_RGB555: line_writer = &gate_color_convert_rgb_from_rgb_15; break; | |
402 | ✗ | case GATE_IMAGE_PIXELFORMAT_RGB565: line_writer = &gate_color_convert_rgb_from_rgb_16; break; | |
403 | ✗ | case GATE_IMAGE_PIXELFORMAT_ARGB4: line_writer = &gate_color_convert_rgb_from_argb_16; break; | |
404 | ✗ | case GATE_IMAGE_PIXELFORMAT_YUV2: line_writer = &gate_color_convert_rgb_from_yuv2_16; break; | |
405 | |||
406 | ✗ | case GATE_IMAGE_PIXELFORMAT_PAL8: line_writer = &gate_color_convert_rgb_from_pal_8; break; | |
407 | ✗ | case GATE_IMAGE_PIXELFORMAT_GRAY8: line_writer = &gate_color_convert_rgb_from_gray_8; break; | |
408 | ✗ | default: | |
409 | ✗ | break; | |
410 | } | ||
411 | |||
412 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (NULL == line_writer) |
413 | { | ||
414 | ✗ | ret = GATE_RESULT_NOTSUPPORTED; | |
415 | ✗ | break; | |
416 | } | ||
417 | |||
418 | 1 | required_buffer_size = (gate_size_t)image->width * 3; | |
419 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (required_buffer_size > sizeof(buffer)) |
420 | { | ||
421 | ✗ | ptrbuffer = (unsigned char*)gate_mem_alloc(required_buffer_size); | |
422 | ✗ | if (ptrbuffer == NULL) | |
423 | { | ||
424 | ✗ | ret = GATE_RESULT_OUTOFMEMORY; | |
425 | ✗ | break; | |
426 | } | ||
427 | } | ||
428 | |||
429 | 1 | jpeg_create_compress(compress); | |
430 | 1 | compress->in_color_space = JCS_RGB; | |
431 | 1 | compress->input_components = 3; | |
432 | 1 | compress->image_width = (JDIMENSION)image->width; | |
433 | 1 | compress->image_height = (JDIMENSION)image->height; | |
434 | 1 | compress->dct_method = JDCT_FLOAT; | |
435 | |||
436 | 1 | jpeg_set_defaults(compress); | |
437 | 1 | compress->client_data = user_param; | |
438 | 1 | compress->dest = destination_mgr; | |
439 | 1 | jpeg_set_quality(compress, (int)((qualitypercent > 100) ? 100 : qualitypercent), TRUE); | |
440 | |||
441 | 1 | jpeg_start_compress(compress, TRUE); | |
442 | |||
443 | |||
444 | |||
445 |
2/2✓ Branch 0 taken 32 times.
✓ Branch 1 taken 1 times.
|
33 | for (y = 0; y != image->height; ++y) |
446 | { | ||
447 | 32 | ptrpixels = (gate_uint8_t const*)gate_rasterimage_get_line_ptr(image, y); | |
448 | 32 | line_writer(ptrbuffer, ptrpixels, image->width); | |
449 | |||
450 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 32 times.
|
32 | if (1 != jpeg_write_scanlines(compress, (JSAMPARRAY)&ptrbuffer, 1)) |
451 | { | ||
452 | /* failed to write one line */ | ||
453 | ✗ | if (GATE_SUCCEEDED(user_param->result)) | |
454 | { | ||
455 | ✗ | user_param->result = GATE_RESULT_INVALIDOUTPUT; | |
456 | ✗ | break; | |
457 | } | ||
458 | } | ||
459 | } | ||
460 | |||
461 | 1 | jpeg_finish_compress(compress); | |
462 | 1 | jpeg_destroy_compress(compress); | |
463 | |||
464 | 1 | ret = user_param->result; | |
465 | } while (0); | ||
466 | |||
467 |
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)) |
468 | { | ||
469 | ✗ | gate_mem_dealloc(ptrbuffer); | |
470 | } | ||
471 | 1 | return ret; | |
472 | } | ||
473 | |||
474 | 1 | gate_result_t gate_jpegimage_save(gate_rasterimage_t const* image, gate_stream_t* deststream, gate_enumint_t flags) | |
475 | { | ||
476 | gate_result_t ret; | ||
477 | 1 | gate_jpeg_param_t user_param = GATE_INIT_EMPTY; | |
478 | 1 | gate_jpeg_error_mgr_t error_mgr = GATE_INIT_EMPTY; | |
479 | 1 | struct jpeg_destination_mgr destination_mgr = GATE_INIT_EMPTY; | |
480 | 1 | struct jpeg_compress_struct compress = GATE_INIT_EMPTY; | |
481 | 1 | const gate_uint16_t qa0to15 = (gate_uint16_t)GATE_IMAGE_FLAG_DECODE_QUALITY(flags); | |
482 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | const gate_uint8_t qualitypercent = (qa0to15 > 0) |
483 | ✗ | ? (gate_uint8_t)(qa0to15 * 100 / 15) | |
484 | : 90; | ||
485 | |||
486 | 1 | user_param.result = GATE_RESULT_OK; | |
487 | 1 | user_param.stream = deststream; | |
488 | |||
489 | 1 | compress.err = jpeg_std_error(&error_mgr.error_mgr); | |
490 | 1 | error_mgr.error_mgr.error_exit = &gate_jpeg_error_exit; | |
491 | 1 | error_mgr.ptr_param = &user_param; | |
492 | |||
493 | 1 | destination_mgr.empty_output_buffer = &gate_jpeg_empty_output_buffer; | |
494 | 1 | destination_mgr.init_destination = &gate_jpeg_init_destination; | |
495 | 1 | destination_mgr.term_destination = &gate_jpeg_term_destination; | |
496 | 1 | destination_mgr.free_in_buffer = 0; | |
497 | 1 | destination_mgr.next_output_byte = NULL; | |
498 | |||
499 | do | ||
500 | { | ||
501 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | if (0 == setjmp(user_param.emergency_exit)) |
502 | { | ||
503 | 1 | ret = gate_jpegimage_save_data(image, &destination_mgr, &compress, &user_param, qualitypercent); | |
504 | } | ||
505 | else /* setjmp error case */ | ||
506 | { | ||
507 | /* jpeg emergency exit point reached */ | ||
508 | ✗ | ret = GATE_RESULT_CRITICALERROR; | |
509 | } | ||
510 | } while (0); | ||
511 | 1 | return ret; | |
512 | } | ||
513 | |||
514 | #endif /* GATE_GRAPHICS_JPEG_USE_LIBJPEG */ | ||
515 | |||
516 | #if defined(GATE_GRAPHICS_JPEG_NO_IMPL) | ||
517 | |||
518 | gate_result_t gate_jpegimage_load(gate_stream_t* srcstream, gate_rasterimage_t* image, gate_enumint_t flags) | ||
519 | { | ||
520 | (void)srcstream; | ||
521 | (void)image; | ||
522 | (void)flags; | ||
523 | return GATE_RESULT_NOTIMPLEMENTED; | ||
524 | } | ||
525 | |||
526 | gate_result_t gate_jpegimage_save(gate_rasterimage_t const* image, gate_stream_t* deststream, gate_enumint_t flags) | ||
527 | { | ||
528 | (void)image; | ||
529 | (void)deststream; | ||
530 | (void)flags; | ||
531 | return GATE_RESULT_NOTIMPLEMENTED; | ||
532 | } | ||
533 | |||
534 | #endif | ||
535 | |||
536 |