44#include <glib/gstdio.h>
52 struct jpeg_error_mgr
pub;
61 (*cinfo->err->output_message)(cinfo);
71 fprintf(stderr,
"[imageio_jpeg] output buffer full!\n");
88 ssize_t
i = cinfo->src->bytes_in_buffer - num_bytes;
90 cinfo->src->bytes_in_buffer =
i;
91 cinfo->src->next_input_byte += num_bytes;
111#define EXIF_MARKER (JPEG_APP0 + 1)
112#define ICC_MARKER (JPEG_APP0 + 2)
113#define ICC_OVERHEAD_LEN 14
114#define MAX_BYTES_IN_MARKER 65533
115#define MAX_DATA_BYTES_IN_MARKER (MAX_BYTES_IN_MARKER - ICC_OVERHEAD_LEN)
141 jpeg_create_decompress(&(jpg->
dinfo));
145 jpg->
src.resync_to_restart = jpeg_resync_to_restart;
147 jpg->
src.next_input_byte = (JOCTET *)in;
148 jpg->
src.bytes_in_buffer = length;
151 jpg->
dinfo.err = jpeg_std_error(&jerr.
pub);
155 jpeg_destroy_decompress(&(jpg->
dinfo));
164 jpg->
dinfo.out_color_space = JCS_EXT_RGBX;
165 jpg->
dinfo.out_color_components = 4;
167 jpg->
dinfo.out_color_space = JCS_RGB;
168 jpg->
dinfo.out_color_components = 3;
180 while(jpg->
dinfo.output_scanline < jpg->
dinfo.image_height)
182 if(jpeg_read_scanlines(&(jpg->
dinfo), &tmp, 1) != 1)
186 tmp += 4 * jpg->
width;
194 JSAMPROW row_pointer[1];
196 (
size_t)jpg->
dinfo.output_width * jpg->
dinfo.num_components, 0);
197 if(row_pointer[0] == NULL)
return 1;
199 while(jpg->
dinfo.output_scanline < jpg->
dinfo.image_height)
201 if(jpeg_read_scanlines(&(jpg->
dinfo), row_pointer, 1) != 1)
206 for(
unsigned int i = 0;
i < jpg->
dinfo.image_width;
i++)
208 for(
int k = 0;
k < 3;
k++) tmp[4 *
i +
k] = row_pointer[0][3 *
i +
k];
210 tmp += 4 * jpg->
width;
220 jpg->
dinfo.err = jpeg_std_error(&jerr.
pub);
224 jpeg_destroy_decompress(&(jpg->
dinfo));
233 int jcs_alpha_valid = 1;
236 if(jpg->
dinfo.out_color_space == JCS_EXT_RGBX && jpg->
dinfo.out_color_components == 4)
239 jpg->
dinfo.out_color_components = 3;
240 jpg->
dinfo.out_color_space = JCS_RGB;
245 jpeg_destroy_decompress(&(jpg->
dinfo));
251 (
void)jpeg_start_decompress(&(jpg->
dinfo));
255 jpeg_destroy_decompress(&(jpg->
dinfo));
262 if(decompress_jsc(jpg,
out))
return 1;
274 jpeg_destroy_decompress(&(jpg->
dinfo));
279 (
void)jpeg_finish_decompress(&(jpg->
dinfo));
280 jpeg_destroy_decompress(&(jpg->
dinfo));
293 jpg.dest.next_output_byte = (JOCTET *)
out;
294 jpg.dest.free_in_buffer =
sizeof(uint8_t) * 4 *
width *
height;
296 jpg.cinfo.err = jpeg_std_error(&jerr.
pub);
300 jpeg_destroy_compress(&(jpg.cinfo));
303 jpeg_create_compress(&(jpg.cinfo));
304 jpg.cinfo.dest = &(jpg.dest);
306 jpg.cinfo.image_width =
width;
307 jpg.cinfo.image_height =
height;
308 jpg.cinfo.input_components = 3;
309 jpg.cinfo.in_color_space = JCS_RGB;
310 jpeg_set_defaults(&(jpg.cinfo));
311 jpeg_set_quality(&(jpg.cinfo), quality,
TRUE);
312 if(quality > 90) jpg.cinfo.comp_info[0].v_samp_factor = 1;
313 if(quality > 92) jpg.cinfo.comp_info[0].h_samp_factor = 1;
314 jpeg_start_compress(&(jpg.cinfo),
TRUE);
315 JSAMPARRAY
row = (*jpg.cinfo.mem->alloc_sarray)((j_common_ptr)&jpg.cinfo, JPOOL_IMAGE,
316 (JDIMENSION)(3 *
width), 1);
318 while(jpg.cinfo.next_scanline < jpg.cinfo.image_height)
320 buf = in + jpg.cinfo.next_scanline * jpg.cinfo.image_width * 4;
322 for(
int k = 0;
k < 3;
k++)
row[0][3 *
i +
k] = buf[4 *
i +
k];
323 jpeg_write_scanlines(&(jpg.cinfo),
row, 1);
325 jpeg_finish_compress(&(jpg.cinfo));
326 jpeg_destroy_compress(&(jpg.cinfo));
327 return sizeof(uint8_t) * 4 *
width *
height - jpg.dest.free_in_buffer;
339static void write_icc_profile(j_compress_ptr cinfo,
const JOCTET *icc_data_ptr,
unsigned int icc_data_len)
341 unsigned int num_markers;
348 while(icc_data_len > 0)
351 unsigned int length = icc_data_len;
353 icc_data_len -= length;
362 jpeg_write_m_byte(cinfo, 0x49);
363 jpeg_write_m_byte(cinfo, 0x43);
364 jpeg_write_m_byte(cinfo, 0x43);
365 jpeg_write_m_byte(cinfo, 0x5F);
366 jpeg_write_m_byte(cinfo, 0x50);
367 jpeg_write_m_byte(cinfo, 0x52);
368 jpeg_write_m_byte(cinfo, 0x4F);
369 jpeg_write_m_byte(cinfo, 0x46);
370 jpeg_write_m_byte(cinfo, 0x49);
371 jpeg_write_m_byte(cinfo, 0x4C);
372 jpeg_write_m_byte(cinfo, 0x45);
373 jpeg_write_m_byte(cinfo, 0x0);
376 jpeg_write_m_byte(cinfo, cur_marker);
377 jpeg_write_m_byte(cinfo, (
int)num_markers);
382 jpeg_write_m_byte(cinfo, *icc_data_ptr);
399 GETJOCTET(marker->data[0]) == 0x49 && GETJOCTET(marker->data[1]) == 0x43
400 && GETJOCTET(marker->data[2]) == 0x43 && GETJOCTET(marker->data[3]) == 0x5F
401 && GETJOCTET(marker->data[4]) == 0x50 && GETJOCTET(marker->data[5]) == 0x52
402 && GETJOCTET(marker->data[6]) == 0x4F && GETJOCTET(marker->data[7]) == 0x46
403 && GETJOCTET(marker->data[8]) == 0x49 && GETJOCTET(marker->data[9]) == 0x4C
404 && GETJOCTET(marker->data[10]) == 0x45 && GETJOCTET(marker->data[11]) == 0x0;
427static boolean read_icc_profile(j_decompress_ptr dinfo, JOCTET **icc_data_ptr,
unsigned int *icc_data_len)
429 jpeg_saved_marker_ptr marker;
433 unsigned int total_length;
434#define MAX_SEQ_NO 255
439 *icc_data_ptr = NULL;
446 for(seq_no = 1; seq_no <=
MAX_SEQ_NO; seq_no++) marker_present[seq_no] = 0;
448 for(marker = dinfo->marker_list; !
IS_NULL_PTR(marker); marker = marker->next)
453 num_markers = GETJOCTET(marker->data[13]);
454 else if(num_markers != GETJOCTET(marker->data[13]))
456 seq_no = GETJOCTET(marker->data[12]);
457 if(seq_no <= 0 || seq_no > num_markers)
return FALSE;
458 if(marker_present[seq_no])
return FALSE;
459 marker_present[seq_no] = 1;
464 if(num_markers == 0)
return FALSE;
471 for(seq_no = 1; seq_no <= num_markers; seq_no++)
473 if(marker_present[seq_no] == 0)
return FALSE;
474 data_offset[seq_no] = total_length;
475 total_length += data_length[seq_no];
478 if(total_length == 0)
return FALSE;
481 icc_data = (JOCTET *)g_malloc(total_length *
sizeof(JOCTET));
484 for(marker = dinfo->marker_list; !
IS_NULL_PTR(marker); marker = marker->next)
491 seq_no = GETJOCTET(marker->data[12]);
492 dst_ptr = icc_data + data_offset[seq_no];
494 length = data_length[seq_no];
497 *dst_ptr++ = *src_ptr++;
502 *icc_data_ptr = icc_data;
503 *icc_data_len = total_length;
508#undef ICC_OVERHEAD_LEN
509#undef MAX_BYTES_IN_MARKER
510#undef MAX_DATA_BYTES_IN_MARKER
515 const int height,
const int quality,
const void *exif,
int exif_len,
521 jpg.
cinfo.err = jpeg_std_error(&jerr.
pub);
525 jpeg_destroy_compress(&(jpg.cinfo));
528 jpeg_create_compress(&(jpg.cinfo));
529 FILE *
f = g_fopen(filename,
"wb");
531 jpeg_stdio_dest(&(jpg.cinfo),
f);
533 jpg.cinfo.image_width =
width;
534 jpg.cinfo.image_height =
height;
535 jpg.cinfo.input_components = 3;
536 jpg.cinfo.in_color_space = JCS_RGB;
537 jpeg_set_defaults(&(jpg.cinfo));
538 jpeg_set_quality(&(jpg.cinfo), quality,
TRUE);
539 if(quality > 90) jpg.cinfo.comp_info[0].v_samp_factor = 1;
540 if(quality > 92) jpg.cinfo.comp_info[0].h_samp_factor = 1;
541 jpeg_start_compress(&(jpg.cinfo),
TRUE);
550 cmsSaveProfileToMem(out_profile, 0, &len);
554 cmsSaveProfileToMem(out_profile, buf, &len);
560 if(exif && exif_len > 0 && exif_len < 65534) jpeg_write_marker(&(jpg.cinfo), JPEG_APP0 + 1, exif, exif_len);
562 JSAMPARRAY
row = (*jpg.cinfo.mem->alloc_sarray)((j_common_ptr)&jpg.cinfo, JPOOL_IMAGE,
563 (JDIMENSION)(3 *
width), 1);
565 while(jpg.cinfo.next_scanline < jpg.cinfo.image_height)
567 buf = in + jpg.cinfo.next_scanline * jpg.cinfo.image_width * 4;
569 for(
int k = 0;
k < 3;
k++)
row[0][3 *
i +
k] = buf[4 *
i +
k];
570 jpeg_write_scanlines(&(jpg.cinfo),
row, 1);
572 jpeg_finish_compress(&(jpg.cinfo));
573 jpeg_destroy_compress(&(jpg.cinfo));
579 const int quality,
const void *exif,
int exif_len)
586 jpg->
f = g_fopen(filename,
"rb");
590 jpg->
dinfo.err = jpeg_std_error(&jerr.
pub);
594 jpeg_destroy_decompress(&(jpg->
dinfo));
598 jpeg_create_decompress(&(jpg->
dinfo));
599 jpeg_stdio_src(&(jpg->
dinfo), jpg->
f);
605 jpg->
dinfo.out_color_space = JCS_EXT_RGBX;
606 jpg->
dinfo.out_color_components = 4;
608 jpg->
dinfo.out_color_space = JCS_RGB;
609 jpg->
dinfo.out_color_components = 3;
620 while(jpg->
dinfo.output_scanline < jpg->
dinfo.image_height)
622 if(jpeg_read_scanlines(&(jpg->
dinfo), &tmp, 1) != 1)
626 tmp += 4 * jpg->
width;
634 JSAMPROW row_pointer[1];
636 (
size_t)jpg->
dinfo.output_width * jpg->
dinfo.num_components, 0);
638 while(jpg->
dinfo.output_scanline < jpg->
dinfo.image_height)
640 if(jpeg_read_scanlines(&(jpg->
dinfo), row_pointer, 1) != 1)
642 jpeg_destroy_decompress(&(jpg->
dinfo));
647 for(
unsigned int i = 0;
i < jpg->
dinfo.image_width;
i++)
648 for(
int k = 0;
k < 3;
k++) tmp[4 *
i +
k] = row_pointer[0][3 *
i +
k];
649 tmp += 4 * jpg->
width;
658 jpg->
dinfo.err = jpeg_std_error(&jerr.
pub);
662 jpeg_destroy_decompress(&(jpg->
dinfo));
672 int jcs_alpha_valid = 1;
675 if(jpg->
dinfo.out_color_space == JCS_EXT_RGBX && jpg->
dinfo.out_color_components == 4)
678 jpg->
dinfo.out_color_components = 3;
679 jpg->
dinfo.out_color_space = JCS_RGB;
684 jpeg_destroy_decompress(&(jpg->
dinfo));
689 (
void)jpeg_start_decompress(&(jpg->
dinfo));
693 jpeg_destroy_decompress(&(jpg->
dinfo));
713 jpeg_destroy_decompress(&(jpg->
dinfo));
718 (
void)jpeg_finish_decompress(&(jpg->
dinfo));
720 jpeg_destroy_decompress(&(jpg->
dinfo));
727 unsigned int length = 0;
729 jpeg_destroy_decompress(&(jpg->
dinfo));
731 return res ? length : 0;
736 for(jpeg_saved_marker_ptr marker = jpg->
dinfo.marker_list; !
IS_NULL_PTR(marker); marker = marker->next)
738 if(marker->marker ==
EXIF_MARKER && marker->data_length > 6)
747 const char *ext = filename + strlen(filename);
748 while(*ext !=
'.' && ext > filename) ext--;
749 if(strncmp(ext,
".jpg", 4) && strncmp(ext,
".JPG", 4) && strncmp(ext,
".jpeg", 5)
750 && strncmp(ext,
".JPEG", 5))
762 img->
dsc.
bpp = 4 *
sizeof(float);
765 img->
flags &= ~DT_IMAGE_RAW;
766 img->
flags &= ~DT_IMAGE_S_RAW;
767 img->
flags &= ~DT_IMAGE_HDR;
773 jpeg_destroy_decompress(&(jpg.
dinfo));
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
const dt_colormatrix_t dt_aligned_pixel_t out
dt_colorspaces_color_profile_type_t dt_exif_get_color_space(const uint8_t *data, size_t size)
int dt_exif_read(dt_image_t *img, const char *path)
What a photograph says about itself: the EXIF, IPTC and XMP tags a camera and a cataloguer write,...
@ DT_IMAGEIO_FILE_CORRUPTED
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)
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)
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)
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)
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)
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)
_lib_location_type_t type
float *const restrict const size_t k
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
void * dt_mipmap_cache_alloc(dt_mipmap_buffer_t *buf, const dt_image_t *img)
#define dt_pixelpipe_cache_alloc_align_cache(size, id)
#define dt_pixelpipe_cache_free_align(mem)
dt_colorspaces_color_profile_type_t
@ DT_COLORSPACE_DISPLAY
The monitor profile – the one list entry that mutates after init.
@ DT_COLORSPACE_NONE
No profile / "take it from the image settings". Never matches a list entry.
cmsHPROFILE profile
the actual profile; NULL for the three category entries
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
dt_iop_buffer_type_t datatype