49 struct jpeg_error_mgr
pub;
58 (*cinfo->err->output_message)(cinfo);
68 fprintf(stderr,
"[imageio_jpeg] output buffer full!\n");
85 ssize_t
i = cinfo->src->bytes_in_buffer - num_bytes;
87 cinfo->src->bytes_in_buffer =
i;
88 cinfo->src->next_input_byte += num_bytes;
108#define EXIF_MARKER (JPEG_APP0 + 1)
109#define ICC_MARKER (JPEG_APP0 + 2)
110#define ICC_OVERHEAD_LEN 14
111#define MAX_BYTES_IN_MARKER 65533
112#define MAX_DATA_BYTES_IN_MARKER (MAX_BYTES_IN_MARKER - ICC_OVERHEAD_LEN)
138 jpeg_create_decompress(&(jpg->
dinfo));
142 jpg->
src.resync_to_restart = jpeg_resync_to_restart;
144 jpg->
src.next_input_byte = (JOCTET *)in;
145 jpg->
src.bytes_in_buffer = length;
148 jpg->
dinfo.err = jpeg_std_error(&jerr.
pub);
152 jpeg_destroy_decompress(&(jpg->
dinfo));
161 jpg->
dinfo.out_color_space = JCS_EXT_RGBX;
162 jpg->
dinfo.out_color_components = 4;
164 jpg->
dinfo.out_color_space = JCS_RGB;
165 jpg->
dinfo.out_color_components = 3;
177 while(jpg->
dinfo.output_scanline < jpg->
dinfo.image_height)
179 if(jpeg_read_scanlines(&(jpg->
dinfo), &tmp, 1) != 1)
183 tmp += 4 * jpg->
width;
191 JSAMPROW row_pointer[1];
193 (
size_t)jpg->
dinfo.output_width * jpg->
dinfo.num_components, 0);
194 if(row_pointer[0] == NULL)
return 1;
196 while(jpg->
dinfo.output_scanline < jpg->
dinfo.image_height)
198 if(jpeg_read_scanlines(&(jpg->
dinfo), row_pointer, 1) != 1)
203 for(
unsigned int i = 0;
i < jpg->
dinfo.image_width;
i++)
205 for(
int k = 0;
k < 3;
k++) tmp[4 *
i +
k] = row_pointer[0][3 *
i +
k];
207 tmp += 4 * jpg->
width;
217 jpg->
dinfo.err = jpeg_std_error(&jerr.
pub);
221 jpeg_destroy_decompress(&(jpg->
dinfo));
230 int jcs_alpha_valid = 1;
233 if(jpg->
dinfo.out_color_space == JCS_EXT_RGBX && jpg->
dinfo.out_color_components == 4)
236 jpg->
dinfo.out_color_components = 3;
237 jpg->
dinfo.out_color_space = JCS_RGB;
242 jpeg_destroy_decompress(&(jpg->
dinfo));
248 (
void)jpeg_start_decompress(&(jpg->
dinfo));
252 jpeg_destroy_decompress(&(jpg->
dinfo));
259 if(decompress_jsc(jpg,
out))
return 1;
271 jpeg_destroy_decompress(&(jpg->
dinfo));
276 (
void)jpeg_finish_decompress(&(jpg->
dinfo));
277 jpeg_destroy_decompress(&(jpg->
dinfo));
290 jpg.dest.next_output_byte = (JOCTET *)
out;
291 jpg.dest.free_in_buffer =
sizeof(uint8_t) * 4 *
width *
height;
293 jpg.cinfo.err = jpeg_std_error(&jerr.
pub);
297 jpeg_destroy_compress(&(jpg.cinfo));
300 jpeg_create_compress(&(jpg.cinfo));
301 jpg.cinfo.dest = &(jpg.dest);
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);
315 while(jpg.cinfo.next_scanline < jpg.cinfo.image_height)
317 buf = in + jpg.cinfo.next_scanline * jpg.cinfo.image_width * 4;
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);
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;
336static void write_icc_profile(j_compress_ptr cinfo,
const JOCTET *icc_data_ptr,
unsigned int icc_data_len)
338 unsigned int num_markers;
345 while(icc_data_len > 0)
348 unsigned int length = icc_data_len;
350 icc_data_len -= length;
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);
373 jpeg_write_m_byte(cinfo, cur_marker);
374 jpeg_write_m_byte(cinfo, (
int)num_markers);
379 jpeg_write_m_byte(cinfo, *icc_data_ptr);
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;
424static boolean read_icc_profile(j_decompress_ptr dinfo, JOCTET **icc_data_ptr,
unsigned int *icc_data_len)
426 jpeg_saved_marker_ptr marker;
430 unsigned int total_length;
431#define MAX_SEQ_NO 255
436 *icc_data_ptr = NULL;
443 for(seq_no = 1; seq_no <=
MAX_SEQ_NO; seq_no++) marker_present[seq_no] = 0;
445 for(marker = dinfo->marker_list; !
IS_NULL_PTR(marker); marker = marker->next)
450 num_markers = GETJOCTET(marker->data[13]);
451 else if(num_markers != GETJOCTET(marker->data[13]))
453 seq_no = GETJOCTET(marker->data[12]);
454 if(seq_no <= 0 || seq_no > num_markers)
return FALSE;
455 if(marker_present[seq_no])
return FALSE;
456 marker_present[seq_no] = 1;
461 if(num_markers == 0)
return FALSE;
468 for(seq_no = 1; seq_no <= num_markers; seq_no++)
470 if(marker_present[seq_no] == 0)
return FALSE;
471 data_offset[seq_no] = total_length;
472 total_length += data_length[seq_no];
475 if(total_length == 0)
return FALSE;
478 icc_data = (JOCTET *)g_malloc(total_length *
sizeof(JOCTET));
481 for(marker = dinfo->marker_list; !
IS_NULL_PTR(marker); marker = marker->next)
488 seq_no = GETJOCTET(marker->data[12]);
489 dst_ptr = icc_data + data_offset[seq_no];
491 length = data_length[seq_no];
494 *dst_ptr++ = *src_ptr++;
499 *icc_data_ptr = icc_data;
500 *icc_data_len = total_length;
505#undef ICC_OVERHEAD_LEN
506#undef MAX_BYTES_IN_MARKER
507#undef MAX_DATA_BYTES_IN_MARKER
512 const int height,
const int quality,
const void *exif,
int exif_len,
518 jpg.
cinfo.err = jpeg_std_error(&jerr.
pub);
522 jpeg_destroy_compress(&(jpg.cinfo));
525 jpeg_create_compress(&(jpg.cinfo));
526 FILE *
f = g_fopen(filename,
"wb");
528 jpeg_stdio_dest(&(jpg.cinfo),
f);
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);
547 cmsSaveProfileToMem(out_profile, 0, &len);
551 cmsSaveProfileToMem(out_profile, buf, &len);
557 if(exif && exif_len > 0 && exif_len < 65534) jpeg_write_marker(&(jpg.cinfo), JPEG_APP0 + 1, exif, exif_len);
559 JSAMPARRAY
row = (*jpg.cinfo.mem->alloc_sarray)((j_common_ptr)&jpg.cinfo, JPOOL_IMAGE,
560 (JDIMENSION)(3 *
width), 1);
562 while(jpg.cinfo.next_scanline < jpg.cinfo.image_height)
564 buf = in + jpg.cinfo.next_scanline * jpg.cinfo.image_width * 4;
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);
569 jpeg_finish_compress(&(jpg.cinfo));
570 jpeg_destroy_compress(&(jpg.cinfo));
576 const int quality,
const void *exif,
int exif_len)
583 jpg->
f = g_fopen(filename,
"rb");
587 jpg->
dinfo.err = jpeg_std_error(&jerr.
pub);
591 jpeg_destroy_decompress(&(jpg->
dinfo));
595 jpeg_create_decompress(&(jpg->
dinfo));
596 jpeg_stdio_src(&(jpg->
dinfo), jpg->
f);
602 jpg->
dinfo.out_color_space = JCS_EXT_RGBX;
603 jpg->
dinfo.out_color_components = 4;
605 jpg->
dinfo.out_color_space = JCS_RGB;
606 jpg->
dinfo.out_color_components = 3;
617 while(jpg->
dinfo.output_scanline < jpg->
dinfo.image_height)
619 if(jpeg_read_scanlines(&(jpg->
dinfo), &tmp, 1) != 1)
623 tmp += 4 * jpg->
width;
631 JSAMPROW row_pointer[1];
633 (
size_t)jpg->
dinfo.output_width * jpg->
dinfo.num_components, 0);
635 while(jpg->
dinfo.output_scanline < jpg->
dinfo.image_height)
637 if(jpeg_read_scanlines(&(jpg->
dinfo), row_pointer, 1) != 1)
639 jpeg_destroy_decompress(&(jpg->
dinfo));
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;
655 jpg->
dinfo.err = jpeg_std_error(&jerr.
pub);
659 jpeg_destroy_decompress(&(jpg->
dinfo));
669 int jcs_alpha_valid = 1;
672 if(jpg->
dinfo.out_color_space == JCS_EXT_RGBX && jpg->
dinfo.out_color_components == 4)
675 jpg->
dinfo.out_color_components = 3;
676 jpg->
dinfo.out_color_space = JCS_RGB;
681 jpeg_destroy_decompress(&(jpg->
dinfo));
686 (
void)jpeg_start_decompress(&(jpg->
dinfo));
690 jpeg_destroy_decompress(&(jpg->
dinfo));
710 jpeg_destroy_decompress(&(jpg->
dinfo));
715 (
void)jpeg_finish_decompress(&(jpg->
dinfo));
717 jpeg_destroy_decompress(&(jpg->
dinfo));
724 unsigned int length = 0;
726 jpeg_destroy_decompress(&(jpg->
dinfo));
728 return res ? length : 0;
733 for(jpeg_saved_marker_ptr marker = jpg->
dinfo.marker_list; !
IS_NULL_PTR(marker); marker = marker->next)
735 if(marker->marker ==
EXIF_MARKER && marker->data_length > 6)
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))
759 img->
dsc.
bpp = 4 *
sizeof(float);
762 img->
flags &= ~DT_IMAGE_RAW;
763 img->
flags &= ~DT_IMAGE_S_RAW;
764 img->
flags &= ~DT_IMAGE_HDR;
770 jpeg_destroy_decompress(&(jpg.
dinfo));
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
const dt_aligned_pixel_t f
const dt_colormatrix_t dt_aligned_pixel_t out
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
#define dt_pixelpipe_cache_alloc_align_cache(size, id)
#define dt_pixelpipe_cache_free_align(mem)
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
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)
@ 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)
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)
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)
float *const restrict const size_t k
void * dt_mipmap_cache_alloc(dt_mipmap_buffer_t *buf, const dt_image_t *img)
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