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