Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
imageio_jpeg.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2009-2011, 2014 johannes hanika.
4 Copyright (C) 2010 Henrik Andersson.
5 Copyright (C) 2012 Christian Tellefsen.
6 Copyright (C) 2012 Michal Babej.
7 Copyright (C) 2012 Richard Wonka.
8 Copyright (C) 2012, 2014-2017 Tobias Ellinghaus.
9 Copyright (C) 2012 Ulrich Pegelow.
10 Copyright (C) 2013-2016 Roman Lebedev.
11 Copyright (C) 2019, 2022, 2025-2026 Aurélien PIERRE.
12 Copyright (C) 2019-2021 Pascal Obry.
13 Copyright (C) 2019 Philippe Weyland.
14 Copyright (C) 2020 Heiko Bauke.
15 Copyright (C) 2020 Hubert Kowalski.
16 Copyright (C) 2021 Miloš Komarčević.
17 Copyright (C) 2022 Martin Bařinka.
18 Copyright (C) 2023-2024 Alynx Zhou.
19
20 darktable is free software: you can redistribute it and/or modify
21 it under the terms of the GNU General Public License as published by
22 the Free Software Foundation, either version 3 of the License, or
23 (at your option) any later version.
24
25 darktable is distributed in the hope that it will be useful,
26 but WITHOUT ANY WARRANTY; without even the implied warranty of
27 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 GNU General Public License for more details.
29
30 You should have received a copy of the GNU General Public License
31 along with darktable. If not, see <http://www.gnu.org/licenses/>.
32*/
33
34
35
36#ifdef HAVE_CONFIG_H
37#include "config.h"
38#endif
39#include "common/exif.h"
40#include "common/imageio.h"
41#include "common/imageio_jpeg.h"
42#include "develop/imageop.h" // for IOP_CS_RGB
43#include <setjmp.h>
44
45// error functions
46
52
54
55static void dt_imageio_jpeg_error_exit(j_common_ptr cinfo)
56{
58 (*cinfo->err->output_message)(cinfo);
59 longjmp(myerr->setjmp_buffer, 1);
60}
61
62// destination functions
63static void dt_imageio_jpeg_init_destination(j_compress_ptr cinfo)
64{
65}
66static boolean dt_imageio_jpeg_empty_output_buffer(j_compress_ptr cinfo)
67{
68 fprintf(stderr, "[imageio_jpeg] output buffer full!\n");
69 return FALSE;
70}
71static void dt_imageio_jpeg_term_destination(j_compress_ptr cinfo)
72{
73}
74
75// source functions
76static void dt_imageio_jpeg_init_source(j_decompress_ptr cinfo)
77{
78}
79static boolean dt_imageio_jpeg_fill_input_buffer(j_decompress_ptr cinfo)
80{
81 return 1;
82}
83static void dt_imageio_jpeg_skip_input_data(j_decompress_ptr cinfo, long num_bytes)
84{
85 ssize_t i = cinfo->src->bytes_in_buffer - num_bytes;
86 if(i < 0) i = 0;
87 cinfo->src->bytes_in_buffer = i;
88 cinfo->src->next_input_byte += num_bytes;
89}
90static void dt_imageio_jpeg_term_source(j_decompress_ptr cinfo)
91{
92}
93
94
95/*
96 * Since an ICC profile can be larger than the maximum size of a JPEG marker
97 * (64K), we need provisions to split it into multiple markers. The format
98 * defined by the ICC specifies one or more APP2 markers containing the
99 * following data:
100 * Identifying string ASCII "ICC_PROFILE\0" (12 bytes)
101 * Marker sequence number 1 for first APP2, 2 for next, etc (1 byte)
102 * Number of markers Total number of APP2's used (1 byte)
103 * Profile data (remainder of APP2 data)
104 * Decoders should use the marker sequence numbers to reassemble the profile,
105 * rather than assuming that the APP2 markers appear in the correct sequence.
106 */
107
108#define EXIF_MARKER (JPEG_APP0 + 1) /* JPEG marker code for Exif */
109#define ICC_MARKER (JPEG_APP0 + 2) /* JPEG marker code for ICC */
110#define ICC_OVERHEAD_LEN 14 /* size of non-profile data in APP2 */
111#define MAX_BYTES_IN_MARKER 65533 /* maximum data len of a JPEG marker */
112#define MAX_DATA_BYTES_IN_MARKER (MAX_BYTES_IN_MARKER - ICC_OVERHEAD_LEN)
113
114
115/*
116 * Prepare for reading an ICC profile
117 */
118
119static void setup_read_icc_profile(j_decompress_ptr cinfo)
120{
121 /* Tell the library to keep any APP2 data it may find */
122 jpeg_save_markers(cinfo, ICC_MARKER, 0xFFFF);
123}
124
125/*
126 * Prepare for reading an Exif blob
127 */
128
129static void setup_read_exif(j_decompress_ptr cinfo)
130{
131 /* Tell the library to keep any APP1 data it may find */
132 jpeg_save_markers(cinfo, EXIF_MARKER, 0xFFFF);
133}
134
135
136int dt_imageio_jpeg_decompress_header(const void *in, size_t length, dt_imageio_jpeg_t *jpg)
137{
138 jpeg_create_decompress(&(jpg->dinfo));
139 jpg->src.init_source = dt_imageio_jpeg_init_source;
140 jpg->src.fill_input_buffer = dt_imageio_jpeg_fill_input_buffer;
141 jpg->src.skip_input_data = dt_imageio_jpeg_skip_input_data;
142 jpg->src.resync_to_restart = jpeg_resync_to_restart;
143 jpg->src.term_source = dt_imageio_jpeg_term_source;
144 jpg->src.next_input_byte = (JOCTET *)in;
145 jpg->src.bytes_in_buffer = length;
146
147 struct dt_imageio_jpeg_error_mgr jerr;
148 jpg->dinfo.err = jpeg_std_error(&jerr.pub);
149 jerr.pub.error_exit = dt_imageio_jpeg_error_exit;
150 if(setjmp(jerr.setjmp_buffer))
151 {
152 jpeg_destroy_decompress(&(jpg->dinfo));
153 return 1;
154 }
155
156 jpg->dinfo.src = &(jpg->src);
157 setup_read_exif(&(jpg->dinfo));
159 jpeg_read_header(&(jpg->dinfo), TRUE);
160#ifdef JCS_EXTENSIONS
161 jpg->dinfo.out_color_space = JCS_EXT_RGBX;
162 jpg->dinfo.out_color_components = 4;
163#else
164 jpg->dinfo.out_color_space = JCS_RGB;
165 jpg->dinfo.out_color_components = 3;
166#endif
167 // jpg->dinfo.buffered_image = TRUE;
168 jpg->width = jpg->dinfo.image_width;
169 jpg->height = jpg->dinfo.image_height;
170 return 0;
171}
172
173#ifdef JCS_EXTENSIONS
174static int decompress_jsc(dt_imageio_jpeg_t *jpg, uint8_t *out)
175{
176 uint8_t *tmp = out;
177 while(jpg->dinfo.output_scanline < jpg->dinfo.image_height)
178 {
179 if(jpeg_read_scanlines(&(jpg->dinfo), &tmp, 1) != 1)
180 {
181 return 1;
182 }
183 tmp += 4 * jpg->width;
184 }
185 return 0;
186}
187#endif
188
189static int decompress_plain(dt_imageio_jpeg_t *jpg, uint8_t *out)
190{
191 JSAMPROW row_pointer[1];
192 row_pointer[0] = (uint8_t *)dt_pixelpipe_cache_alloc_align_cache(
193 (size_t)jpg->dinfo.output_width * jpg->dinfo.num_components, 0);
194 if(row_pointer[0] == NULL) return 1;
195 uint8_t *tmp = out;
196 while(jpg->dinfo.output_scanline < jpg->dinfo.image_height)
197 {
198 if(jpeg_read_scanlines(&(jpg->dinfo), row_pointer, 1) != 1)
199 {
200 dt_pixelpipe_cache_free_align(row_pointer[0]);
201 return 1;
202 }
203 for(unsigned int i = 0; i < jpg->dinfo.image_width; i++)
204 {
205 for(int k = 0; k < 3; k++) tmp[4 * i + k] = row_pointer[0][3 * i + k];
206 }
207 tmp += 4 * jpg->width;
208 }
209
210 dt_pixelpipe_cache_free_align(row_pointer[0]);
211 return 0;
212}
213
215{
216 struct dt_imageio_jpeg_error_mgr jerr;
217 jpg->dinfo.err = jpeg_std_error(&jerr.pub);
218 jerr.pub.error_exit = dt_imageio_jpeg_error_exit;
219 if(setjmp(jerr.setjmp_buffer))
220 {
221 jpeg_destroy_decompress(&(jpg->dinfo));
222 return 1;
223 }
224
225#ifdef JCS_EXTENSIONS
226 /*
227 * Do a run-time detection for JCS_EXTENSIONS:
228 * it might have been only available at build-time
229 */
230 int jcs_alpha_valid = 1;
231 if(setjmp(jerr.setjmp_buffer))
232 {
233 if(jpg->dinfo.out_color_space == JCS_EXT_RGBX && jpg->dinfo.out_color_components == 4)
234 {
235 // ok, no JCS_EXTENSIONS, fall-back to slow plain code.
236 jpg->dinfo.out_color_components = 3;
237 jpg->dinfo.out_color_space = JCS_RGB;
238 jcs_alpha_valid = 0;
239 }
240 else
241 {
242 jpeg_destroy_decompress(&(jpg->dinfo));
243 return 1;
244 }
245 }
246#endif
247
248 (void)jpeg_start_decompress(&(jpg->dinfo));
249
250 if(setjmp(jerr.setjmp_buffer))
251 {
252 jpeg_destroy_decompress(&(jpg->dinfo));
253 return 1;
254 }
255
256#ifdef JCS_EXTENSIONS
257 if(jcs_alpha_valid)
258 {
259 if(decompress_jsc(jpg, out)) return 1;
260 }
261 else
262 {
263 if(decompress_plain(jpg, out)) return 1;
264 }
265#else
266 if(decompress_plain(jpg, out)) return 1;
267#endif
268
269 if(setjmp(jerr.setjmp_buffer))
270 {
271 jpeg_destroy_decompress(&(jpg->dinfo));
272 return 1;
273 }
274
275 // jpg->dinfo.src = NULL;
276 (void)jpeg_finish_decompress(&(jpg->dinfo));
277 jpeg_destroy_decompress(&(jpg->dinfo));
278 return 0;
279}
280
281// TODO: find out why this function is not used anymore. Where do we compress ???
282int dt_imageio_jpeg_compress(const uint8_t *in, uint8_t *out, const int width, const int height,
283 const int quality)
284{
285 struct dt_imageio_jpeg_error_mgr jerr;
287 jpg.dest.init_destination = dt_imageio_jpeg_init_destination;
288 jpg.dest.empty_output_buffer = dt_imageio_jpeg_empty_output_buffer;
289 jpg.dest.term_destination = dt_imageio_jpeg_term_destination;
290 jpg.dest.next_output_byte = (JOCTET *)out;
291 jpg.dest.free_in_buffer = sizeof(uint8_t) * 4 * width * height;
292
293 jpg.cinfo.err = jpeg_std_error(&jerr.pub);
294 jerr.pub.error_exit = dt_imageio_jpeg_error_exit;
295 if(setjmp(jerr.setjmp_buffer))
296 {
297 jpeg_destroy_compress(&(jpg.cinfo));
298 return 1;
299 }
300 jpeg_create_compress(&(jpg.cinfo));
301 jpg.cinfo.dest = &(jpg.dest);
302
303 jpg.cinfo.image_width = width;
304 jpg.cinfo.image_height = height;
305 jpg.cinfo.input_components = 3;
306 jpg.cinfo.in_color_space = JCS_RGB;
307 jpeg_set_defaults(&(jpg.cinfo));
308 jpeg_set_quality(&(jpg.cinfo), quality, TRUE);
309 if(quality > 90) jpg.cinfo.comp_info[0].v_samp_factor = 1;
310 if(quality > 92) jpg.cinfo.comp_info[0].h_samp_factor = 1;
311 jpeg_start_compress(&(jpg.cinfo), TRUE);
312 JSAMPARRAY row = (*jpg.cinfo.mem->alloc_sarray)((j_common_ptr)&jpg.cinfo, JPOOL_IMAGE,
313 (JDIMENSION)(3 * width), 1);
314 const uint8_t *buf;
315 while(jpg.cinfo.next_scanline < jpg.cinfo.image_height)
316 {
317 buf = in + jpg.cinfo.next_scanline * jpg.cinfo.image_width * 4;
318 for(int i = 0; i < width; i++)
319 for(int k = 0; k < 3; k++) row[0][3 * i + k] = buf[4 * i + k];
320 jpeg_write_scanlines(&(jpg.cinfo), row, 1);
321 }
322 jpeg_finish_compress(&(jpg.cinfo));
323 jpeg_destroy_compress(&(jpg.cinfo));
324 return sizeof(uint8_t) * 4 * width * height - jpg.dest.free_in_buffer;
325}
326
327
328/*
329 * This routine writes the given ICC profile data into a JPEG file.
330 * It *must* be called AFTER calling jpeg_start_compress() and BEFORE
331 * the first call to jpeg_write_scanlines().
332 * (This ordering ensures that the APP2 marker(s) will appear after the
333 * SOI and JFIF or Adobe markers, but before all else.)
334 */
335
336static void write_icc_profile(j_compress_ptr cinfo, const JOCTET *icc_data_ptr, unsigned int icc_data_len)
337{
338 unsigned int num_markers; /* total number of markers we'll write */
339 int cur_marker = 1; /* per spec, counting starts at 1 */
340
341 /* Calculate the number of markers we'll need, rounding up of course */
342 num_markers = icc_data_len / MAX_DATA_BYTES_IN_MARKER;
343 if(num_markers * MAX_DATA_BYTES_IN_MARKER != icc_data_len) num_markers++;
344
345 while(icc_data_len > 0)
346 {
347 /* length of profile to put in this marker */
348 unsigned int length = icc_data_len;
350 icc_data_len -= length;
351
352 /* Write the JPEG marker header (APP2 code and marker length) */
353 jpeg_write_m_header(cinfo, ICC_MARKER, (unsigned int)(length + ICC_OVERHEAD_LEN));
354
355 /* Write the marker identifying string "ICC_PROFILE" (null-terminated).
356 * We code it in this less-than-transparent way so that the code works
357 * even if the local character set is not ASCII.
358 */
359 jpeg_write_m_byte(cinfo, 0x49);
360 jpeg_write_m_byte(cinfo, 0x43);
361 jpeg_write_m_byte(cinfo, 0x43);
362 jpeg_write_m_byte(cinfo, 0x5F);
363 jpeg_write_m_byte(cinfo, 0x50);
364 jpeg_write_m_byte(cinfo, 0x52);
365 jpeg_write_m_byte(cinfo, 0x4F);
366 jpeg_write_m_byte(cinfo, 0x46);
367 jpeg_write_m_byte(cinfo, 0x49);
368 jpeg_write_m_byte(cinfo, 0x4C);
369 jpeg_write_m_byte(cinfo, 0x45);
370 jpeg_write_m_byte(cinfo, 0x0);
371
372 /* Add the sequencing info */
373 jpeg_write_m_byte(cinfo, cur_marker);
374 jpeg_write_m_byte(cinfo, (int)num_markers);
375
376 /* Add the profile data */
377 while(length--)
378 {
379 jpeg_write_m_byte(cinfo, *icc_data_ptr);
380 icc_data_ptr++;
381 }
382 cur_marker++;
383 }
384}
385
386
387/*
388 * Handy subroutine to test whether a saved marker is an ICC profile marker.
389 */
390
391static boolean marker_is_icc(jpeg_saved_marker_ptr marker)
392{
393 return marker->marker == ICC_MARKER && marker->data_length >= ICC_OVERHEAD_LEN
394 &&
395 /* verify the identifying string */
396 GETJOCTET(marker->data[0]) == 0x49 && GETJOCTET(marker->data[1]) == 0x43
397 && GETJOCTET(marker->data[2]) == 0x43 && GETJOCTET(marker->data[3]) == 0x5F
398 && GETJOCTET(marker->data[4]) == 0x50 && GETJOCTET(marker->data[5]) == 0x52
399 && GETJOCTET(marker->data[6]) == 0x4F && GETJOCTET(marker->data[7]) == 0x46
400 && GETJOCTET(marker->data[8]) == 0x49 && GETJOCTET(marker->data[9]) == 0x4C
401 && GETJOCTET(marker->data[10]) == 0x45 && GETJOCTET(marker->data[11]) == 0x0;
402}
403
404
405/*
406 * See if there was an ICC profile in the JPEG file being read;
407 * if so, reassemble and return the profile data.
408 *
409 * TRUE is returned if an ICC profile was found, FALSE if not.
410 * If TRUE is returned, *icc_data_ptr is set to point to the
411 * returned data, and *icc_data_len is set to its length.
412 *
413 * IMPORTANT: the data at **icc_data_ptr has been allocated with malloc()
414 * and must be freed by the caller with g_free() when the caller no longer
415 * needs it. (Alternatively, we could write this routine to use the
416 * IJG library's memory allocator, so that the data would be freed implicitly
417 * at jpeg_finish_decompress() time. But it seems likely that many apps
418 * will prefer to have the data stick around after decompression finishes.)
419 *
420 * NOTE: if the file contains invalid ICC APP2 markers, we just silently
421 * return FALSE. You might want to issue an error message instead.
422 */
423
424static boolean read_icc_profile(j_decompress_ptr dinfo, JOCTET **icc_data_ptr, unsigned int *icc_data_len)
425{
426 jpeg_saved_marker_ptr marker;
427 int num_markers = 0;
428 int seq_no;
429 JOCTET *icc_data;
430 unsigned int total_length;
431#define MAX_SEQ_NO 255 /* sufficient since marker numbers are bytes */
432 char marker_present[MAX_SEQ_NO + 1]; /* 1 if marker found */
433 unsigned int data_length[MAX_SEQ_NO + 1]; /* size of profile data in marker */
434 unsigned int data_offset[MAX_SEQ_NO + 1]; /* offset for data in marker */
435
436 *icc_data_ptr = NULL; /* avoid confusion if FALSE return */
437 *icc_data_len = 0;
438
439 /* This first pass over the saved markers discovers whether there are
440 * any ICC markers and verifies the consistency of the marker numbering.
441 */
442
443 for(seq_no = 1; seq_no <= MAX_SEQ_NO; seq_no++) marker_present[seq_no] = 0;
444
445 for(marker = dinfo->marker_list; !IS_NULL_PTR(marker); marker = marker->next)
446 {
447 if(marker_is_icc(marker))
448 {
449 if(num_markers == 0)
450 num_markers = GETJOCTET(marker->data[13]);
451 else if(num_markers != GETJOCTET(marker->data[13]))
452 return FALSE; /* inconsistent num_markers fields */
453 seq_no = GETJOCTET(marker->data[12]);
454 if(seq_no <= 0 || seq_no > num_markers) return FALSE; /* bogus sequence number */
455 if(marker_present[seq_no]) return FALSE; /* duplicate sequence numbers */
456 marker_present[seq_no] = 1;
457 data_length[seq_no] = marker->data_length - ICC_OVERHEAD_LEN;
458 }
459 }
460
461 if(num_markers == 0) return FALSE;
462
463 /* Check for missing markers, count total space needed,
464 * compute offset of each marker's part of the data.
465 */
466
467 total_length = 0;
468 for(seq_no = 1; seq_no <= num_markers; seq_no++)
469 {
470 if(marker_present[seq_no] == 0) return FALSE; /* missing sequence number */
471 data_offset[seq_no] = total_length;
472 total_length += data_length[seq_no];
473 }
474
475 if(total_length == 0) return FALSE; /* found only empty markers? */
476
477 /* Allocate space for assembled data */
478 icc_data = (JOCTET *)g_malloc(total_length * sizeof(JOCTET));
479
480 /* and fill it in */
481 for(marker = dinfo->marker_list; !IS_NULL_PTR(marker); marker = marker->next)
482 {
483 if(marker_is_icc(marker))
484 {
485 JOCTET FAR *src_ptr;
486 JOCTET *dst_ptr;
487 unsigned int length;
488 seq_no = GETJOCTET(marker->data[12]);
489 dst_ptr = icc_data + data_offset[seq_no];
490 src_ptr = marker->data + ICC_OVERHEAD_LEN;
491 length = data_length[seq_no];
492 while(length--)
493 {
494 *dst_ptr++ = *src_ptr++;
495 }
496 }
497 }
498
499 *icc_data_ptr = icc_data;
500 *icc_data_len = total_length;
501
502 return TRUE;
503}
504#undef ICC_MARKER
505#undef ICC_OVERHEAD_LEN
506#undef MAX_BYTES_IN_MARKER
507#undef MAX_DATA_BYTES_IN_MARKER
508#undef MAX_SEQ_NO
509
510
511int dt_imageio_jpeg_write_with_icc_profile(const char *filename, const uint8_t *in, const int width,
512 const int height, const int quality, const void *exif, int exif_len,
513 int32_t imgid)
514{
515 struct dt_imageio_jpeg_error_mgr jerr;
517
518 jpg.cinfo.err = jpeg_std_error(&jerr.pub);
519 jerr.pub.error_exit = dt_imageio_jpeg_error_exit;
520 if(setjmp(jerr.setjmp_buffer))
521 {
522 jpeg_destroy_compress(&(jpg.cinfo));
523 return 1;
524 }
525 jpeg_create_compress(&(jpg.cinfo));
526 FILE *f = g_fopen(filename, "wb");
527 if(IS_NULL_PTR(f)) return 1;
528 jpeg_stdio_dest(&(jpg.cinfo), f);
529
530 jpg.cinfo.image_width = width;
531 jpg.cinfo.image_height = height;
532 jpg.cinfo.input_components = 3;
533 jpg.cinfo.in_color_space = JCS_RGB;
534 jpeg_set_defaults(&(jpg.cinfo));
535 jpeg_set_quality(&(jpg.cinfo), quality, TRUE);
536 if(quality > 90) jpg.cinfo.comp_info[0].v_samp_factor = 1;
537 if(quality > 92) jpg.cinfo.comp_info[0].h_samp_factor = 1;
538 jpeg_start_compress(&(jpg.cinfo), TRUE);
539
540 if(imgid > 0)
541 {
542 // the code in this block is never being used. should that ever change make sure to honour the
543 // color profile overwriting the one set in colorout, too. dt_colorspaces_get_output_profile() doesn't do that!
545 cmsHPROFILE out_profile = dt_colorspaces_get_output_profile(imgid, &type, "")->profile;
546 uint32_t len = 0;
547 cmsSaveProfileToMem(out_profile, 0, &len);
548 if(len > 0)
549 {
550 unsigned char *buf = dt_pixelpipe_cache_alloc_align_cache(sizeof(unsigned char) * len, 0);
551 cmsSaveProfileToMem(out_profile, buf, &len);
552 write_icc_profile(&(jpg.cinfo), buf, len);
554 }
555 }
556
557 if(exif && exif_len > 0 && exif_len < 65534) jpeg_write_marker(&(jpg.cinfo), JPEG_APP0 + 1, exif, exif_len);
558
559 JSAMPARRAY row = (*jpg.cinfo.mem->alloc_sarray)((j_common_ptr)&jpg.cinfo, JPOOL_IMAGE,
560 (JDIMENSION)(3 * width), 1);
561 const uint8_t *buf;
562 while(jpg.cinfo.next_scanline < jpg.cinfo.image_height)
563 {
564 buf = in + jpg.cinfo.next_scanline * jpg.cinfo.image_width * 4;
565 for(int i = 0; i < width; i++)
566 for(int k = 0; k < 3; k++) row[0][3 * i + k] = buf[4 * i + k];
567 jpeg_write_scanlines(&(jpg.cinfo), row, 1);
568 }
569 jpeg_finish_compress(&(jpg.cinfo));
570 jpeg_destroy_compress(&(jpg.cinfo));
571 fclose(f);
572 return 0;
573}
574
575int dt_imageio_jpeg_write(const char *filename, const uint8_t *in, const int width, const int height,
576 const int quality, const void *exif, int exif_len)
577{
578 return dt_imageio_jpeg_write_with_icc_profile(filename, in, width, height, quality, exif, exif_len, -1);
579}
580
581int dt_imageio_jpeg_read_header(const char *filename, dt_imageio_jpeg_t *jpg)
582{
583 jpg->f = g_fopen(filename, "rb");
584 if(IS_NULL_PTR(jpg->f)) return 1;
585
586 struct dt_imageio_jpeg_error_mgr jerr;
587 jpg->dinfo.err = jpeg_std_error(&jerr.pub);
588 jerr.pub.error_exit = dt_imageio_jpeg_error_exit;
589 if(setjmp(jerr.setjmp_buffer))
590 {
591 jpeg_destroy_decompress(&(jpg->dinfo));
592 fclose(jpg->f);
593 return 1;
594 }
595 jpeg_create_decompress(&(jpg->dinfo));
596 jpeg_stdio_src(&(jpg->dinfo), jpg->f);
597 setup_read_exif(&(jpg->dinfo));
599 // jpg->dinfo.buffered_image = TRUE;
600 jpeg_read_header(&(jpg->dinfo), TRUE);
601#ifdef JCS_EXTENSIONS
602 jpg->dinfo.out_color_space = JCS_EXT_RGBX;
603 jpg->dinfo.out_color_components = 4;
604#else
605 jpg->dinfo.out_color_space = JCS_RGB;
606 jpg->dinfo.out_color_components = 3;
607#endif
608 jpg->width = jpg->dinfo.image_width;
609 jpg->height = jpg->dinfo.image_height;
610 return 0;
611}
612
613#ifdef JCS_EXTENSIONS
614static int read_jsc(dt_imageio_jpeg_t *jpg, uint8_t *out)
615{
616 uint8_t *tmp = out;
617 while(jpg->dinfo.output_scanline < jpg->dinfo.image_height)
618 {
619 if(jpeg_read_scanlines(&(jpg->dinfo), &tmp, 1) != 1)
620 {
621 return 1;
622 }
623 tmp += 4 * jpg->width;
624 }
625 return 0;
626}
627#endif
628
629static int read_plain(dt_imageio_jpeg_t *jpg, uint8_t *out)
630{
631 JSAMPROW row_pointer[1];
632 row_pointer[0] = (uint8_t *)dt_pixelpipe_cache_alloc_align_cache(
633 (size_t)jpg->dinfo.output_width * jpg->dinfo.num_components, 0);
634 uint8_t *tmp = out;
635 while(jpg->dinfo.output_scanline < jpg->dinfo.image_height)
636 {
637 if(jpeg_read_scanlines(&(jpg->dinfo), row_pointer, 1) != 1)
638 {
639 jpeg_destroy_decompress(&(jpg->dinfo));
640 dt_pixelpipe_cache_free_align(row_pointer[0]);
641 fclose(jpg->f);
642 return 1;
643 }
644 for(unsigned int i = 0; i < jpg->dinfo.image_width; i++)
645 for(int k = 0; k < 3; k++) tmp[4 * i + k] = row_pointer[0][3 * i + k];
646 tmp += 4 * jpg->width;
647 }
648 dt_pixelpipe_cache_free_align(row_pointer[0]);
649 return 0;
650}
651
653{
654 struct dt_imageio_jpeg_error_mgr jerr;
655 jpg->dinfo.err = jpeg_std_error(&jerr.pub);
656 jerr.pub.error_exit = dt_imageio_jpeg_error_exit;
657 if(setjmp(jerr.setjmp_buffer))
658 {
659 jpeg_destroy_decompress(&(jpg->dinfo));
660 fclose(jpg->f);
661 return 1;
662 }
663
664#ifdef JCS_EXTENSIONS
665 /*
666 * Do a run-time detection for JCS_EXTENSIONS:
667 * it might have been only available at build-time
668 */
669 int jcs_alpha_valid = 1;
670 if(setjmp(jerr.setjmp_buffer))
671 {
672 if(jpg->dinfo.out_color_space == JCS_EXT_RGBX && jpg->dinfo.out_color_components == 4)
673 {
674 // ok, no JCS_EXTENSIONS, fall-back to slow plain code.
675 jpg->dinfo.out_color_components = 3;
676 jpg->dinfo.out_color_space = JCS_RGB;
677 jcs_alpha_valid = 0;
678 }
679 else
680 {
681 jpeg_destroy_decompress(&(jpg->dinfo));
682 return 1;
683 }
684 }
685#endif
686 (void)jpeg_start_decompress(&(jpg->dinfo));
687
688 if(setjmp(jerr.setjmp_buffer))
689 {
690 jpeg_destroy_decompress(&(jpg->dinfo));
691 fclose(jpg->f);
692 return 1;
693 }
694
695#ifdef JCS_EXTENSIONS
696 if(jcs_alpha_valid)
697 {
698 read_jsc(jpg, out);
699 }
700 else
701 {
702 read_plain(jpg, out);
703 }
704#else
705 read_plain(jpg, out);
706#endif
707
708 if(setjmp(jerr.setjmp_buffer))
709 {
710 jpeg_destroy_decompress(&(jpg->dinfo));
711 fclose(jpg->f);
712 return 1;
713 }
714
715 (void)jpeg_finish_decompress(&(jpg->dinfo));
716
717 jpeg_destroy_decompress(&(jpg->dinfo));
718 fclose(jpg->f);
719 return 0;
720}
721
723{
724 unsigned int length = 0;
725 boolean res = read_icc_profile(&(jpg->dinfo), out, &length);
726 jpeg_destroy_decompress(&(jpg->dinfo));
727 fclose(jpg->f);
728 return res ? length : 0;
729}
730
732{
733 for(jpeg_saved_marker_ptr marker = jpg->dinfo.marker_list; !IS_NULL_PTR(marker); marker = marker->next)
734 {
735 if(marker->marker == EXIF_MARKER && marker->data_length > 6)
736 return dt_exif_get_color_space(marker->data + 6, marker->data_length - 6);
737 }
738
739 return DT_COLORSPACE_DISPLAY; // nothing embedded
740}
741
743{
744 const char *ext = filename + strlen(filename);
745 while(*ext != '.' && ext > filename) ext--;
746 if(strncmp(ext, ".jpg", 4) && strncmp(ext, ".JPG", 4) && strncmp(ext, ".jpeg", 5)
747 && strncmp(ext, ".JPEG", 5))
749
750 if(!img->exif_inited) (void)dt_exif_read(img, filename);
751
754 img->width = jpg.width;
755 img->height = jpg.height;
756
757 img->dsc.channels = 4;
758 img->dsc.datatype = TYPE_FLOAT;
759 img->dsc.bpp = 4 * sizeof(float);
760 img->dsc.cst = IOP_CS_RGB; // jpeg is always RGB
761 img->dsc.filters = 0u;
762 img->flags &= ~DT_IMAGE_RAW;
763 img->flags &= ~DT_IMAGE_S_RAW;
764 img->flags &= ~DT_IMAGE_HDR;
765 img->flags |= DT_IMAGE_LDR;
766 img->loader = LOADER_JPEG;
767
768 if(IS_NULL_PTR(mbuf))
769 {
770 jpeg_destroy_decompress(&(jpg.dinfo));
771 fclose(jpg.f);
772 return DT_IMAGEIO_OK;
773 }
774
775 uint8_t *tmp = (uint8_t *)dt_pixelpipe_cache_alloc_align_cache(
776 sizeof(uint8_t) * 4 * jpg.width * jpg.height,
777 0);
778 if(dt_imageio_jpeg_read(&jpg, tmp))
779 {
782 }
783
784 void *buf = dt_mipmap_cache_alloc(mbuf, img);
785 if(IS_NULL_PTR(buf))
786 {
789 }
790
791 dt_imageio_flip_buffers_ui8_to_float((float *)buf, tmp, 0.0f, 255.0f, 4, jpg.width, jpg.height, jpg.width,
792 jpg.height, 4 * jpg.width, 0);
793
795 return DT_IMAGEIO_OK;
796}
797
798
799
800// clang-format off
801// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
802// vim: shiftwidth=2 expandtab tabstop=2 cindent
803// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
804// clang-format on
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
int width
Definition bilateral.h:1
int height
Definition bilateral.h:1
@ IOP_CS_RGB
const dt_colorspaces_color_profile_t * dt_colorspaces_get_output_profile(const int32_t imgid, dt_colorspaces_color_profile_type_t *over_type, const char *over_filename)
dt_colorspaces_color_profile_type_t
Definition colorspaces.h:81
@ DT_COLORSPACE_DISPLAY
Definition colorspaces.h:91
@ DT_COLORSPACE_NONE
Definition colorspaces.h:82
const dt_aligned_pixel_t f
const dt_colormatrix_t dt_aligned_pixel_t out
static const int row
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
int type
#define dt_pixelpipe_cache_alloc_align_cache(size, id)
Definition darktable.h:433
#define dt_pixelpipe_cache_free_align(mem)
Definition darktable.h:453
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
Definition darktable.h:281
dt_colorspaces_color_profile_type_t dt_exif_get_color_space(const uint8_t *data, size_t size)
Definition exif.cc:4592
int dt_exif_read(dt_image_t *img, const char *path)
Definition exif.cc:1753
@ TYPE_FLOAT
Definition format.h:46
dt_imageio_retval_t
Definition image.h:78
@ DT_IMAGEIO_OK
Definition image.h:79
@ DT_IMAGEIO_CACHE_FULL
Definition image.h:82
@ DT_IMAGEIO_FILE_CORRUPTED
Definition image.h:81
@ DT_IMAGE_LDR
Definition image.h:109
@ LOADER_JPEG
Definition image.h:226
void dt_imageio_flip_buffers_ui8_to_float(float *out, const uint8_t *in, const float black, const float white, const int ch, const int wd, const int ht, const int fwd, const int fht, const int stride, const dt_image_orientation_t orientation)
Definition imageio.c:439
int dt_imageio_jpeg_write_with_icc_profile(const char *filename, const uint8_t *in, const int width, const int height, const int quality, const void *exif, int exif_len, int32_t imgid)
struct dt_imageio_jpeg_error_mgr dt_imageio_jpeg_error_mgr
static void dt_imageio_jpeg_init_destination(j_compress_ptr cinfo)
static void setup_read_icc_profile(j_decompress_ptr cinfo)
int dt_imageio_jpeg_read_profile(dt_imageio_jpeg_t *jpg, uint8_t **out)
#define ICC_MARKER
static int read_plain(dt_imageio_jpeg_t *jpg, uint8_t *out)
static void dt_imageio_jpeg_error_exit(j_common_ptr cinfo)
static void dt_imageio_jpeg_term_source(j_decompress_ptr cinfo)
static void dt_imageio_jpeg_skip_input_data(j_decompress_ptr cinfo, long num_bytes)
int dt_imageio_jpeg_read(dt_imageio_jpeg_t *jpg, uint8_t *out)
#define MAX_SEQ_NO
static void setup_read_exif(j_decompress_ptr cinfo)
int dt_imageio_jpeg_read_header(const char *filename, dt_imageio_jpeg_t *jpg)
static boolean marker_is_icc(jpeg_saved_marker_ptr marker)
static void dt_imageio_jpeg_term_destination(j_compress_ptr cinfo)
static void dt_imageio_jpeg_init_source(j_decompress_ptr cinfo)
static int decompress_plain(dt_imageio_jpeg_t *jpg, uint8_t *out)
dt_colorspaces_color_profile_type_t dt_imageio_jpeg_read_color_space(dt_imageio_jpeg_t *jpg)
struct dt_imageio_jpeg_error_mgr * dt_imageio_jpeg_error_ptr
int dt_imageio_jpeg_decompress_header(const void *in, size_t length, dt_imageio_jpeg_t *jpg)
dt_imageio_retval_t dt_imageio_open_jpeg(dt_image_t *img, const char *filename, dt_mipmap_buffer_t *mbuf)
static void write_icc_profile(j_compress_ptr cinfo, const JOCTET *icc_data_ptr, unsigned int icc_data_len)
int dt_imageio_jpeg_compress(const uint8_t *in, uint8_t *out, const int width, const int height, const int quality)
int dt_imageio_jpeg_decompress(dt_imageio_jpeg_t *jpg, uint8_t *out)
int dt_imageio_jpeg_write(const char *filename, const uint8_t *in, const int width, const int height, const int quality, const void *exif, int exif_len)
#define MAX_DATA_BYTES_IN_MARKER
static boolean read_icc_profile(j_decompress_ptr dinfo, JOCTET **icc_data_ptr, unsigned int *icc_data_len)
static boolean dt_imageio_jpeg_fill_input_buffer(j_decompress_ptr cinfo)
static boolean dt_imageio_jpeg_empty_output_buffer(j_compress_ptr cinfo)
#define ICC_OVERHEAD_LEN
#define EXIF_MARKER
float *const restrict const size_t k
void * dt_mipmap_cache_alloc(dt_mipmap_buffer_t *buf, const dt_image_t *img)
int32_t height
Definition image.h:315
dt_image_loader_t loader
Definition image.h:335
int32_t exif_inited
Definition image.h:283
int32_t flags
Definition image.h:319
int32_t width
Definition image.h:315
dt_iop_buffer_dsc_t dsc
Definition image.h:337
struct jpeg_error_mgr pub
struct jpeg_decompress_struct dinfo
struct jpeg_compress_struct cinfo
struct jpeg_source_mgr src
struct jpeg_destination_mgr dest
uint32_t filters
Definition format.h:60
unsigned int channels
Definition format.h:54
dt_iop_buffer_type_t datatype
Definition format.h:56