Skip to content

Commit

Permalink
iop order: add pipe default pipe order for v3.0 JPEG
Browse files Browse the repository at this point in the history
I have been told that many Fuji users prefer to edit OOC JPEGs rathen than RAWs.
The default v3.0 pipe order assumes linear (RAW) input. For non-linear input, many modules need to be moved after colorin (which removes EOTF/gamma).

This introduces a very similar order as the default v3.0 but tuned for JPEG input.
  • Loading branch information
aurelienpierre authored and TurboGit committed Jul 25, 2021
1 parent 14fe465 commit 480e894
Show file tree
Hide file tree
Showing 3 changed files with 165 additions and 4 deletions.
154 changes: 152 additions & 2 deletions src/common/iop_order.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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},
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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);

Expand Down
3 changes: 2 additions & 1 deletion src/common/iop_order.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
12 changes: 11 additions & 1 deletion src/libs/ioporder.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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);
}
Expand Down

0 comments on commit 480e894

Please sign in to comment.