46#include <glib/gstdio.h>
72 struct jpeg_source_mgr src;
73 struct jpeg_destination_mgr dest;
74 struct jpeg_decompress_struct dinfo;
75 struct jpeg_compress_struct cinfo;
88 struct jpeg_error_mgr
pub;
97 (*cinfo->err->output_message)(cinfo);
114#define ICC_MARKER (JPEG_APP0 + 2)
115#define ICC_OVERHEAD_LEN 14
116#define MAX_BYTES_IN_MARKER 65533
117#define MAX_DATA_BYTES_IN_MARKER (MAX_BYTES_IN_MARKER - ICC_OVERHEAD_LEN)
128static void write_icc_profile(j_compress_ptr cinfo,
const JOCTET *icc_data_ptr,
unsigned int icc_data_len)
136 while(icc_data_len > 0)
139 unsigned int length = icc_data_len;
142 icc_data_len -= length;
151 jpeg_write_m_byte(cinfo, 0x49);
152 jpeg_write_m_byte(cinfo, 0x43);
153 jpeg_write_m_byte(cinfo, 0x43);
154 jpeg_write_m_byte(cinfo, 0x5F);
155 jpeg_write_m_byte(cinfo, 0x50);
156 jpeg_write_m_byte(cinfo, 0x52);
157 jpeg_write_m_byte(cinfo, 0x4F);
158 jpeg_write_m_byte(cinfo, 0x46);
159 jpeg_write_m_byte(cinfo, 0x49);
160 jpeg_write_m_byte(cinfo, 0x4C);
161 jpeg_write_m_byte(cinfo, 0x45);
162 jpeg_write_m_byte(cinfo, 0x0);
165 jpeg_write_m_byte(cinfo, cur_marker);
166 jpeg_write_m_byte(cinfo, (
int)num_markers);
171 jpeg_write_m_byte(cinfo, *icc_data_ptr);
203 GETJOCTET(marker->data[0]) == 0x49 &&
204 GETJOCTET(marker->data[1]) == 0x43 &&
205 GETJOCTET(marker->data[2]) == 0x43 &&
206 GETJOCTET(marker->data[3]) == 0x5F &&
207 GETJOCTET(marker->data[4]) == 0x50 &&
208 GETJOCTET(marker->data[5]) == 0x52 &&
209 GETJOCTET(marker->data[6]) == 0x4F &&
210 GETJOCTET(marker->data[7]) == 0x46 &&
211 GETJOCTET(marker->data[8]) == 0x49 &&
212 GETJOCTET(marker->data[9]) == 0x4C &&
213 GETJOCTET(marker->data[10]) == 0x45 &&
214 GETJOCTET(marker->data[11]) == 0x0;
239 JOCTET **icc_data_ptr,
240 unsigned int *icc_data_len)
243#define MAX_SEQ_NO 255
248 *icc_data_ptr = NULL;
255 for(
int seq_no = 1; seq_no <=
MAX_SEQ_NO; seq_no++)
256 marker_present[seq_no] = 0;
258 for(jpeg_saved_marker_ptr marker = cinfo->marker_list; !
IS_NULL_PTR(marker); marker = marker->next)
263 num_markers = GETJOCTET(marker->data[13]);
264 else if(num_markers != GETJOCTET(marker->data[13]))
266 const int seq_no = GETJOCTET(marker->data[12]);
267 if(seq_no <= 0 || seq_no > num_markers)
269 if(marker_present[seq_no])
271 marker_present[seq_no] = 1;
283 unsigned int total_length = 0;
284 for(
int seq_no = 1; seq_no <= num_markers; seq_no++)
286 if(marker_present[seq_no] == 0)
288 data_offset[seq_no] = total_length;
289 total_length += data_length[seq_no];
292 if(total_length <= 0)
296 JOCTET *icc_data = (JOCTET *)calloc(total_length,
sizeof(JOCTET));
301 for(jpeg_saved_marker_ptr marker = cinfo->marker_list; !
IS_NULL_PTR(marker); marker = marker->next)
305 const int seq_no = GETJOCTET(marker->data[12]);
306 JOCTET *dst_ptr = icc_data + data_offset[seq_no];
308 unsigned int length = data_length[seq_no];
311 *dst_ptr++ = *src_ptr++;
316 *icc_data_ptr = icc_data;
317 *icc_data_len = total_length;
323#undef ICC_OVERHEAD_LEN
324#undef MAX_BYTES_IN_MARKER
325#undef MAX_DATA_BYTES_IN_MARKER
331 void *exif,
int exif_len, int32_t imgid,
int num,
int total,
struct dt_dev_pixelpipe_t *pipe,
332 const gboolean export_masks)
335 const uint8_t *in = (
const uint8_t *)in_tmp;
338 jpg->
cinfo.err = jpeg_std_error(&jerr.
pub);
342 jpeg_destroy_compress(&(jpg->
cinfo));
345 jpeg_create_compress(&(jpg->
cinfo));
346 FILE *
f = g_fopen(filename,
"wb");
348 jpeg_stdio_dest(&(jpg->
cinfo),
f);
352 jpg->
cinfo.input_components = 3;
353 jpg->
cinfo.in_color_space = JCS_RGB;
354 jpeg_set_defaults(&(jpg->
cinfo));
356 if(jpg->
quality > 90) jpg->
cinfo.comp_info[0].v_samp_factor = 1;
357 if(jpg->
quality > 92) jpg->
cinfo.comp_info[0].h_samp_factor = 1;
358 if(jpg->
quality > 95) jpg->
cinfo.dct_method = JDCT_FLOAT;
359 if(jpg->
quality < 50) jpg->
cinfo.dct_method = JDCT_IFAST;
363 jpg->
cinfo.optimize_coding = 1;
366 jpg->
cinfo.density_unit = 1;
367 jpg->
cinfo.X_density = resolution;
368 jpg->
cinfo.Y_density = resolution;
370 jpeg_start_compress(&(jpg->
cinfo),
TRUE);
374 cmsSaveProfileToMem(out_profile, NULL, &len);
377 unsigned char *buf = malloc(
sizeof(
unsigned char) * len);
380 cmsSaveProfileToMem(out_profile, buf, &len);
388 while(
row && jpg->
cinfo.next_scanline < jpg->
cinfo.image_height)
391 buf = in + (size_t)jpg->
cinfo.next_scanline * jpg->
cinfo.image_width * 4;
393 for(
int k = 0;
k < 3;
k++)
row[3 *
i +
k] = buf[4 *
i +
k];
395 jpeg_write_scanlines(&(jpg->
cinfo), tmp, 1);
397 jpeg_finish_compress(&(jpg->
cinfo));
399 jpeg_destroy_compress(&(jpg->
cinfo));
409 jpg->
f = g_fopen(filename,
"rb");
413 jpg->
dinfo.err = jpeg_std_error(&jerr.
pub);
417 jpeg_destroy_decompress(&(jpg->
dinfo));
421 jpeg_create_decompress(&(jpg->
dinfo));
422 jpeg_stdio_src(&(jpg->
dinfo), jpg->
f);
434 jpg->
dinfo.err = jpeg_std_error(&jerr.
pub);
438 jpeg_destroy_decompress(&(jpg->
dinfo));
442 (
void)jpeg_start_decompress(&(jpg->
dinfo));
443 JSAMPROW row_pointer[1];
445 (
size_t)jpg->
dinfo.output_width * jpg->
dinfo.num_components, 0);
447 while(row_pointer[0] && jpg->
dinfo.output_scanline < jpg->
dinfo.image_height)
449 if(jpeg_read_scanlines(&(jpg->
dinfo), row_pointer, 1) != 1)
return 1;
450 if(jpg->
dinfo.num_components < 3)
451 for(JDIMENSION
i = 0;
i < jpg->
dinfo.image_width;
i++)
452 for(
int k = 0;
k < 3;
k++) tmp[4 *
i +
k] = row_pointer[0][jpg->
dinfo.num_components *
i + 0];
454 for(JDIMENSION
i = 0;
i < jpg->
dinfo.image_width;
i++)
455 for(
int k = 0;
k < 3;
k++) tmp[4 *
i +
k] = row_pointer[0][3 *
i +
k];
460 jpeg_destroy_decompress(&(jpg->
dinfo));
465 (
void)jpeg_finish_decompress(&(jpg->
dinfo));
466 jpeg_destroy_decompress(&(jpg->
dinfo));
478 const size_t old_params_size,
const int old_version,
const int new_version,
481 if(old_version == 1 && new_version == 2)
483 typedef struct dt_imageio_jpeg_v1_t
485 int max_width, max_height;
489 struct jpeg_source_mgr src;
490 struct jpeg_destination_mgr dest;
491 struct jpeg_decompress_struct dinfo;
492 struct jpeg_compress_struct cinfo;
494 } dt_imageio_jpeg_v1_t;
496 const dt_imageio_jpeg_v1_t *o = (dt_imageio_jpeg_v1_t *)old_params;
500 n->global.max_height = o->max_height;
501 n->global.width = o->width;
502 n->global.height = o->height;
503 g_strlcpy(
n->global.style, o->style,
sizeof(o->style));
504 n->quality = o->quality;
510 *new_size = self->params_size(self);
521 if(
d->quality <= 0 ||
d->quality > 100)
d->quality = 100;
532 if(
size != self->params_size(self))
return 1;
578 return _(
"JPEG (8-bit)");
604 gtk_box_pack_start(GTK_BOX(box), GTK_WIDGET(
g->quality),
TRUE,
TRUE, 0);
605 g_signal_connect(G_OBJECT(
g->quality),
"value-changed", G_CALLBACK(
quality_changed), NULL);
void dt_bauhaus_slider_set_default(GtkWidget *widget, float def)
float dt_bauhaus_slider_get(GtkWidget *widget)
void dt_bauhaus_slider_set(GtkWidget *widget, float pos)
void dt_bauhaus_widget_set_label(GtkWidget *widget, const char *label)
GtkWidget * dt_bauhaus_slider_new_with_range(dt_bauhaus_t *bh, dt_gui_module_t *self, float min, float max, float step, float defval, int digits)
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
The colour-profile module's API: which profiles exist, and how to apply one.
struct _GtkWidget GtkWidget
GtkWidget, opaque, spelled exactly as GTK spells it.
const dt_colormatrix_t dt_aligned_pixel_t out
void dt_conf_set_int(const char *name, int val)
int dt_conf_get_int(const char *name)
Integer for name, clamped to the bounds declared in the XML.
int dt_confgen_get_int(const char *name, dt_confgen_value_kind_t kind)
struct dt_bauhaus_t * dt_bauhaus_get_global(void)
int dt_exif_write_blob(uint8_t *blob, uint32_t size, const char *path, const int compressed)
What a photograph says about itself: the EXIF, IPTC and XMP tags a camera and a cataloguer write,...
static void setup_read_icc_profile(j_decompress_ptr cinfo)
static boolean marker_is_icc(jpeg_saved_marker_ptr marker)
static boolean read_icc_profile(j_decompress_ptr dinfo, JOCTET **icc_data_ptr, unsigned int *icc_data_len)
@ FORMAT_FLAGS_SUPPORT_XMP
int read_header(const char *filename, dt_imageio_png_t *png)
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)
const char * mime(dt_imageio_module_data_t *data)
size_t params_size(dt_imageio_module_format_t *self)
struct dt_imageio_jpeg_error_mgr dt_imageio_jpeg_error_mgr
struct dt_imageio_jpeg_t dt_imageio_jpeg_t
void gui_reset(dt_imageio_module_format_t *self)
static void dt_imageio_jpeg_error_exit(j_common_ptr cinfo)
void gui_init(dt_imageio_module_format_t *self)
const char * extension(dt_imageio_module_data_t *data)
int read_image(dt_imageio_module_data_t *jpg_tmp, uint8_t *out)
int set_params(dt_imageio_module_format_t *self, const void *params, const int size)
int write_image(dt_imageio_module_data_t *jpg_tmp, const char *filename, const void *in_tmp, dt_colorspaces_color_profile_type_t over_type, const char *over_filename, void *exif, int exif_len, int32_t imgid, int num, int total, struct dt_dev_pixelpipe_t *pipe, const gboolean export_masks)
void cleanup(dt_imageio_module_format_t *self)
int levels(dt_imageio_module_data_t *p)
void * legacy_params(dt_imageio_module_format_t *self, const void *const old_params, const size_t old_params_size, const int old_version, const int new_version, size_t *new_size)
void free_params(dt_imageio_module_format_t *self, dt_imageio_module_data_t *params)
struct dt_imageio_jpeg_error_mgr * dt_imageio_jpeg_error_ptr
void init(dt_imageio_module_format_t *self)
void * get_params(dt_imageio_module_format_t *self)
static void write_icc_profile(j_compress_ptr cinfo, const JOCTET *icc_data_ptr, unsigned int icc_data_len)
void gui_cleanup(dt_imageio_module_format_t *self)
#define MAX_DATA_BYTES_IN_MARKER
static void quality_changed(GtkWidget *slider, gpointer user_data)
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...
#define dt_free(ptr)
g_free() ptr and set it to NULL, skipping both if it is already NULL.
dt_mipmap_buffer_dsc_flags flags
#define DT_MODULE(MODVER)
Instantiate the version handshake every module must export. Use once, at file scope,...
#define dt_pixelpipe_cache_alloc_align_cache(size, id)
#define dt_pixelpipe_cache_free_align(mem)
dt_colorspaces_color_profile_type_t
float dt_aligned_pixel_simd_t __attribute__((vector_size(16), aligned(16)))
Apply one channel's tone curve to each of the three colour channels, or pass the channel through unto...
cmsHPROFILE profile
the actual profile; NULL for the three category entries
struct jpeg_error_mgr pub
struct jpeg_decompress_struct dinfo
dt_imageio_module_data_t global
struct jpeg_compress_struct cinfo