diff --git a/src/common/iop_order.c b/src/common/iop_order.c index 7a824af8a339..b0837fdb00dc 100644 --- a/src/common/iop_order.c +++ b/src/common/iop_order.c @@ -57,7 +57,8 @@ const char *iop_order_string[] = { N_("custom"), N_("legacy"), - N_("v3.0") + N_("v3.0 RAW"), + N_("v3.0 JPEG") }; const char *dt_iop_order_string(const dt_iop_order_t order) @@ -164,6 +165,7 @@ const dt_iop_order_entry_t legacy_order[] = { { { 0.0f }, "", 0} }; +// default order for RAW files, assumed to be linear from start const dt_iop_order_entry_t v30_order[] = { { { 1.0 }, "rawprepare", 0}, { { 2.0 }, "invert", 0}, @@ -269,6 +271,120 @@ const dt_iop_order_entry_t v30_order[] = { { { 0.0f }, "", 0 } }; +// default order for JPEG/TIFF/PNG files, non-linear before colorin +const dt_iop_order_entry_t v30_jpg_order[] = { + // the following modules are not used anyway for non-RAW images : + { { 1.0 }, "rawprepare", 0 }, + { { 2.0 }, "invert", 0 }, + { { 3.0f }, "temperature", 0 }, + { { 4.0f }, "highlights", 0 }, + { { 5.0f }, "cacorrect", 0 }, + { { 6.0f }, "hotpixels", 0 }, + { { 7.0f }, "rawdenoise", 0 }, + { { 8.0f }, "demosaic", 0 }, + // all the modules between [8; 28] expect linear RGB, so they need to be moved after colorin + { { 28.0f }, "colorin", 0 }, + // moved modules : (copy-pasted in the same order) + { { 28.0f }, "denoiseprofile", 0}, + { { 28.0f }, "bilateral", 0}, + { { 28.0f }, "rotatepixels", 0}, + { { 28.0f }, "scalepixels", 0}, + { { 28.0f }, "lens", 0}, + { { 28.0f }, "cacorrectrgb", 0}, // correct chromatic aberrations after lens correction so that lensfun + // does not reintroduce chromatic aberrations when trying to correct them + { { 28.0f }, "hazeremoval", 0}, + { { 28.0f }, "ashift", 0}, + { { 28.0f }, "flip", 0}, + { { 28.0f }, "clipping", 0}, + { { 28.0f }, "liquify", 0}, + { { 28.0f }, "spots", 0}, + { { 28.0f }, "retouch", 0}, + { { 28.0f }, "exposure", 0}, + { { 28.0f }, "mask_manager", 0}, + { { 28.0f }, "tonemap", 0}, + { { 28.0f }, "toneequal", 0}, // last module that need enlarged roi_in + { { 28.0f }, "crop", 0}, // should go after all modules that may need a wider roi_in + { { 28.0f }, "graduatednd", 0}, + { { 28.0f }, "profile_gamma", 0}, + { { 28.0f }, "equalizer", 0}, + // from there, it's the same as the raw order + { { 28.5f }, "diffuse", 0 }, + { { 28.5f }, "channelmixerrgb", 0 }, + { { 28.5f }, "censorize", 0 }, + { { 28.5f }, "negadoctor", 0 }, // Cineon film encoding comes after scanner input color profile + { { 28.5f }, "blurs", 0 }, // physically-accurate blurs (motion and lens) + { { 29.0f }, "nlmeans", 0 }, // signal processing (denoising) + // -> needs a signal as scene-referred as possible (even if it works in Lab) + { { 30.0f }, "colorchecker", 0 }, // calibration to "neutral" exchange colour space + // -> improve colour calibration of colorin and reproductibility + // of further edits (styles etc.) + { { 31.0f }, "defringe", 0 }, // desaturate fringes in Lab, so needs properly calibrated colours + // in order for chromaticity to be meaningful, + { { 32.0f }, "atrous", 0 }, // frequential operation, needs a signal as scene-referred as possible to avoid halos + { { 33.0f }, "lowpass", 0 }, // same + { { 34.0f }, "highpass", 0 }, // same + { { 35.0f }, "sharpen", 0 }, // same, worst than atrous in same use-case, less control overall + { { 36.0f }, "lut3d", 0 }, // apply a creative style or film emulation, possibly non-linear, + // so better move it after frequential ops that need L2 Hilbert spaces + // of square summable functions + { { 37.0f }, "colortransfer", 0 }, // probably better if source and destination colours are neutralized in the + // same + // colour exchange space, hence after colorin and colorcheckr, + // but apply after frequential ops in case it does non-linear witchcraft, + // just to be safe + { { 38.0f }, "colormapping", 0 }, // same + { { 39.0f }, "channelmixer", 0 }, // does exactly the same thing as colorin, aka RGB to RGB matrix conversion, + // but coefs are user-defined instead of calibrated and read from ICC + // profile. Really versatile yet under-used module, doing linear ops, very + // good in scene-referred workflow + { { 40.0f }, "basicadj", 0 }, // module mixing view/model/control at once, usage should be discouraged + { { 41.0f }, "colorbalance", 0 }, // scene-referred color manipulation + { { 41.5f }, "colorbalancergb", 0 }, // scene-referred color manipulation + { { 42.0f }, "rgbcurve", 0 }, // really versatile way to edit colour in scene-referred and display-referred + // workflow + { { 43.0f }, "rgblevels", 0 }, // same + { { 44.0f }, "basecurve", 0 }, // conversion from scene-referred to display referred, reverse-engineered + // on camera JPEG default look + { { 45.0f }, "filmic", 0 }, // same, but different (parametric) approach + { { 46.0f }, "filmicrgb", 0 }, // same, upgraded + { { 47.0f }, "colisa", 0 }, // edit contrast while damaging colour + { { 48.0f }, "tonecurve", 0 }, // same + { { 49.0f }, "levels", 0 }, // same + { { 50.0f }, "shadhi", 0 }, // same + { { 51.0f }, "zonesystem", 0 }, // same + { { 52.0f }, "globaltonemap", 0 }, // same + { { 53.0f }, "relight", 0 }, // flatten local contrast while pretending do add lightness + { { 54.0f }, "bilat", 0 }, // improve clarity/local contrast after all the bad things we have done + // to it with tonemapping + { { 55.0f }, "colorcorrection", 0 }, // now that the colours have been damaged by contrast manipulations, + // try to recover them - global adjustment of white balance for shadows and + // highlights + { { 56.0f }, "colorcontrast", 0 }, // adjust chrominance globally + { { 57.0f }, "velvia", 0 }, // same + { { 58.0f }, "vibrance", 0 }, // same, but more subtle + { { 60.0f }, "colorzones", 0 }, // same, but locally + { { 61.0f }, "bloom", 0 }, // creative module + { { 62.0f }, "colorize", 0 }, // creative module + { { 63.0f }, "lowlight", 0 }, // creative module + { { 64.0f }, "monochrome", 0 }, // creative module + { { 65.0f }, "grain", 0 }, // creative module + { { 66.0f }, "soften", 0 }, // creative module + { { 67.0f }, "splittoning", 0 }, // creative module + { { 68.0f }, "vignette", 0 }, // creative module + { { 69.0f }, "colorreconstruct", 0 }, // try to salvage blown areas before ICC intents in LittleCMS2 do things + // with them. + { { 70.0f }, "colorout", 0 }, + { { 71.0f }, "clahe", 0 }, + { { 72.0f }, "finalscale", 0 }, + { { 73.0f }, "overexposed", 0 }, + { { 74.0f }, "rawoverexposed", 0 }, + { { 75.0f }, "dither", 0 }, + { { 76.0f }, "borders", 0 }, + { { 77.0f }, "watermark", 0 }, + { { 78.0f }, "gamma", 0 }, + { { 0.0f }, "", 0 } +}; + static void *_dup_iop_order_entry(const void *src, gpointer data); static int _count_entries_operation(GList *e_list, const char *operation); @@ -447,7 +563,7 @@ gint dt_sort_iop_list_by_order_f(gconstpointer a, gconstpointer b) dt_iop_order_t dt_ioppr_get_iop_order_list_kind(GList *iop_order_list) { - // first check if this is the v30 order + // first check if this is the v30 order RAW int k = 0; GList *l = iop_order_list; gboolean ok = TRUE; @@ -473,6 +589,32 @@ dt_iop_order_t dt_ioppr_get_iop_order_list_kind(GList *iop_order_list) if(ok) return DT_IOP_ORDER_V30; + // then check if this is the v30 order JPG + k = 0; + l = iop_order_list; + ok = TRUE; + while(l) + { + const dt_iop_order_entry_t *const restrict entry = (dt_iop_order_entry_t *)l->data; + if(strcmp(v30_jpg_order[k].operation, entry->operation)) + { + ok = FALSE; + break; + } + else + { + // skip all the other instance of same module if any + while(g_list_next(l) + && !strcmp(v30_jpg_order[k].operation, ((dt_iop_order_entry_t *)(g_list_next(l)->data))->operation)) + l = g_list_next(l); + } + + k++; + l = g_list_next(l); + } + + if(ok) return DT_IOP_ORDER_V30_JPG; + // then check if this is the legacy order k = 0; l = iop_order_list; @@ -596,6 +738,10 @@ GList *dt_ioppr_get_iop_order_list_version(dt_iop_order_t version) { iop_order_list = _table_to_list(v30_order); } + else if(version == DT_IOP_ORDER_V30_JPG) + { + iop_order_list = _table_to_list(v30_jpg_order); + } return iop_order_list; } @@ -677,6 +823,10 @@ GList *dt_ioppr_get_iop_order_list(int32_t imgid, gboolean sorted) { iop_order_list = _table_to_list(v30_order); } + else if(version == DT_IOP_ORDER_V30_JPG) + { + iop_order_list = _table_to_list(v30_jpg_order); + } else fprintf(stderr, "[dt_ioppr_get_iop_order_list] invalid iop order version %d for imgid %d\n", version, imgid); diff --git a/src/common/iop_order.h b/src/common/iop_order.h index 7590eaa4ce70..98d0ca8b5e5e 100644 --- a/src/common/iop_order.h +++ b/src/common/iop_order.h @@ -133,7 +133,8 @@ typedef enum dt_iop_order_t DT_IOP_ORDER_CUSTOM = 0, // a customr order (re-ordering the pipe) DT_IOP_ORDER_LEGACY = 1, // up to dt 2.6.3 DT_IOP_ORDER_V30 = 2, // starts with dt 3.0 - DT_IOP_ORDER_LAST = 3 + DT_IOP_ORDER_V30_JPG = 3, // same as previous but tuned for non-linear input + DT_IOP_ORDER_LAST = 4 } dt_iop_order_t; typedef struct dt_iop_order_entry_t diff --git a/src/libs/ioporder.c b/src/libs/ioporder.c index 272446525c8d..2ef9ac994a92 100644 --- a/src/libs/ioporder.c +++ b/src/libs/ioporder.c @@ -117,6 +117,11 @@ void update(dt_lib_module_t *self) d->current_mode = kind; gtk_label_set_text(GTK_LABEL(d->widget), _(dt_iop_order_string(DT_IOP_ORDER_V30))); } + else if(kind == DT_IOP_ORDER_V30_JPG) + { + d->current_mode = kind; + gtk_label_set_text(GTK_LABEL(d->widget), _(dt_iop_order_string(DT_IOP_ORDER_V30_JPG))); + } } static void _image_loaded_callback(gpointer instance, gpointer user_data) @@ -190,7 +195,12 @@ void init_presets(dt_lib_module_t *self) list = dt_ioppr_get_iop_order_list_version(DT_IOP_ORDER_V30); params = dt_ioppr_serialize_iop_order_list(list, &size); - dt_lib_presets_add(_("v3.0 (default)"), self->plugin_name, self->version(), (const char *)params, (int32_t)size, + dt_lib_presets_add(_("v3.0 for RAW input (default)"), self->plugin_name, self->version(), (const char *)params, (int32_t)size, + TRUE); + + list = dt_ioppr_get_iop_order_list_version(DT_IOP_ORDER_V30_JPG); + params = dt_ioppr_serialize_iop_order_list(list, &size); + dt_lib_presets_add(_("v3.0 for JPEG/non-RAW input"), self->plugin_name, self->version(), (const char *)params, (int32_t)size, TRUE); free(params); }