In my experimental darktable fork (Libre DT-Lab), I am working towards a cleaner, hybrid workflow following this pipeline philosophy:
[Upstream modules] → Linear Scene-referred → Tone Mapper (TM) → Display-referred → [Downstream modules]
To make this seamless, I have implemented a unified Tone Mapper Selector and cleaned up some legacy exposure behaviors. I would love to get your feedback on the concept and implementation!
The Goal
Instead of manually enabling/disabling various tone mapping modules and cluttering the history stack, the user can now choose the underlying tone mapping philosophy from a single dedicated UI control.
How it works
I added a dropdown selector represented by a funnel/filter icon located in the darkroom, just above the module list and to the right of the module search bar. It offers 6 modes:
Index
Target Module
Config Key (plugins/darkroom/workflow)
0
none
"none"
1
filmicrgb
"scene-referred (filmic)"
2
sigmoid
"scene-referred (sigmoid)"
3
AGX
"scene-referred (agx)"
4
basecurve
"scene-referred (basecurve)"
5
3DCF
"scene-referred (3DCF)"
When a workflow/TM is selected:
It automatically disables all other existing TM modules (filmicrgb, sigmoid, agx, basecurve, 3dcf) and closes their UI expanders.
It updates the global workflow configuration string.
It loads, enables, and expands the chosen TM module (unless “none” is selected), adding it properly to the history stack.
Standardizing the Exposure Shift (+0.7 EV)
Historically, darktable’s exposure module automatically added a +0.7 EV boost when running in scene-referred mode. To achieve a truly neutral baseline, I removed this automatic behavior from exposure.c (now strictly defaults to 0.0 EV).
To allow seamless shifting/switching from one TM to another while preserving visual consistency across previous edits, I implemented the following compensation:
filmicrgb, sigmoid, agx: Introduced a hardcoded, hidden input_exposure = +0.7 EV multiplier directly inside their respective process() functions to maintain their traditional anchoring.
basecurve & 3DCF: Accounted for the +0.7 EV difference as well, ensuring that when a user switches between any of the 5 tone mappers or bypasses them completely (none), the global image brightness remains visually consistent.
Code Architecture
src/libs/workflow_helpers.c / .h: Core business logic for module swapping and status sync.
src/libs/modulegroups.c: UI implementation (funnel popup next to the search bar).
src/iop/{filmicrgb,sigmoid,agx}.c: Added the internal exposure offset & legacy history migration path.
src/iop/exposure.c: Stripped the auto-exposure legacy logic.
What do you think? Feel free to share your comments and technical feedback!
Here’s a short video to illustrate the concept
The latest version is available on GitHub
Greetings from the Luberon
Christian
Hi Christian. I am unsure what problem or issue is being solved here and it seems a similar number of clicks is being used to switch between tone mappers. In the end I don’t see it improving edits so not a big fan of this suggestion, but I am certainly willing to consider others viewpoints on this.
I can see the edvantages of such an approach, but I’m not so sure about the moving of the exposure correction.
If I understood the proposal correctly, you’d get a fixed and hidden 0.7 EV added in the tone mappers. But that exposure compensation in the exposure module was added to compensate for cameras “cheating”, and the amount of cheating varies between cameras and camera settings. The 0.7 EV came out as the most common case. But e.g. mine needs +1 EV.
In practice the EV correction varies between images over a range of at least 0.7-1.2 EV. So many would still have to add an exposure correction.
It also makes compatibility with old images more complicated: each tonemapper gets a new version, as would the exposure module. So more code with (for me) no actual simplification in the workflow (i’d still need an exposure preset, but now at 0.3 EV).
You could modify the basecurve to account for differences with the other tonemappers (and 3DCF isn’t in the main build yet, so no issues there), so you have changes in only one module.
Standardizing the exposure shift is, I think, not really a standardization, it’s probably only thought for when you start editing and want to compare different tone mappers. Once you’ve selected one you may anyway have to go back to the exposure module and adjust. That’s where I see the advantage of having all tone mappers in one module.
On the other hand I use only AgX or no tone mapper and maybe 3DCF if it makes it into a stable version. So having the tone mappers as separate modules doesn’t bother me too much.
From what I saw, the change is not so much replacing the tonemapper modules with one module, as it is adding a layer on top that allows you to easily switch between tonemappers and does some or most of the associated housekeeping (switching off the other tonemappers).
I just don’t think the proposed changes to the tone mapper modules themselves are needed or useful.
That was my understanding too, but I don’t see it as an problem that needs fixing. Below is my tone group modules and find it easy enough to switch between them. Also I have discovered that Base Curve and AgX on some occasions can be effectively be used together, so I want the option to turn on two tone mappers on rare occasions.
From the description, I’d expect it, until you use that menu to select another tone mapper. In that case, I’d expect that both base curve and AgX would be deselected (just because that looks like the easiest way to implement something like that).
It also implies that if you do not use the selector, dt works just as it does now.
Sorry for the late reaction, but I was so focused on ACES 2.0 that I implemented it as faithfully as possible.
My goal isn’t to solve a problem, but to be able to easily compare the different renderings produced by tone mappers.
Yes, exactly. I simply moved the 0.7 EV addition so that I can easily switch between tone mappers or test without a tone mapper.
Among other things, this eliminates the need to adjust the mask in the Tone EQ module.
My goal is to be able to start processing under the same conditions for all workflows.
Exactly, but we shouldn’t use the selector anymore.
Like all the experiments I’m conducting in this experimental branch, these are just proposals that can be tested and discussed before any implementation. That’s the primary purpose of this fork. An idea can also be reworked or serve as a source of inspiration for another project.
Hi Christian …
another interesting approach , I quite like it in general .
Not that I do , or would use all tone mappers … but cool to have option easy to implement .
So thumbs up from my side !!!
And if one does not want to go that route , just use a different module set up
What " bothers " me a tiny bit , just a personal thing , the basic contrast is quite strong chosen in all of your modules ?!
With every shot I have to bring the image to a more " neutral or soft starting point " … and then adding building up the contrast and the tonal range to my personal liking .
Is there a way to have a more neutral starting point by default … in all of your tone mappers ? Would be really cool .
Not sure if that would be technically possible ?
Ohlala Christian … a new " module " appeared to my surprise
Not sure what to think of it … but hey your fork is a lovely playground at times
Would be nice if you could shed some light on how to use it ?!
Just another tonemapper , with VERY SPECIFIC usecase ?
Can or should it be used in conjunction with other tonemappers ?
I did some more testing with the Tone Mapper Selector on a variety of different images, some not yet and others already edited.
For non edited images I found this quite helpful to select the TM which gives you the best starting point. For already edited images it keeps the old edits in the then selected TM but it may help to quickly and easily check out other TMs. In some cases I went back to filmic which I probably wouldn’t have tried without this TM Selector.
So I think now this is really a cool addition workflow wise.
At one time when I was experimenting I used to just add all 3 TM at the time as autopresets in the inactive state…Then I saw the image unmapped out of the gate and or I could simply activate the one I wanted with the default preset that I wanted… during experimentation I would just work through them and then toggle them on or off… I have not had any time to look at this method …
After reading them, I thought it might be best to add a slider for the input exposure. That way, we can adjust it without affecting the various upstream settings.