Working with modules from Lua scripts in darktable

Yes, my work laptop is much faster, ryzen 4500, the home laptop has a i5 from 2016. The problem can also be reproduced on an even older desktop PC.

Started looking into events today, RFH: Instrumenting to determine when an image analysis/processing action is complete · Issue #13745 · darktable-org/darktable · GitHub. Made some discoveries. Still testing to make sure I understand what’s happening and how to best proceed forward.

4 Likes

Okay, I set the sleep timers in:

local function ProcessWorkflowSteps()
– process current image
LogInfo(“==============================”)
LogInfo(“process workflow steps”)

dt.control.sleep(500)

– execute all workflow steps
– the order is from bottom to top, along the pixel pipeline.
for i = 1, #WorkflowSteps do
step = WorkflowSteps[#WorkflowSteps + 1 - i]
step:Run()
end

dt.control.sleep(500)

LogScreen(“initial workflow - done”)
LogInfo(“initial workflow - done”)
LogInfo(“==============================”)
end

from 500 to 2000, and this 100% fixed the problem on my slow PC. So, this clearly is a timing problem. I wonder if other steps in the script are also not completed, because the script moves on before the action is fully executed.

Anyway, thanks so much to Uli and Bill for working on this. I love this community and how much volunteer work goes into it. It’s highly appreciated.

3 Likes

@dterrahe figured out a new home for the pixelpipe-processing-complete event trigger that seems to accurately tell when the pixelpipe processing is truly complete. I tested it against all the routines that I used sleeps in and got them all running without any sleeps. Then I selected 10 images in lighttable and looped through loading each image and adding 0.5 ev of exposure without any problems. The PR is submitted.

5 Likes

That’s very good! Did you consider “darkroom-image-loaded”? Do we still need it?

1 Like

How do I get this script

It’s linked in this thread just scroll up

darkroom-image-loaded is needed if you want to run a script from lighttable view and have it cycle through a set of images and apply edits.

The sequence works like this:

  • request an image to be loaded
  • the image is loaded and the darkroom-image-loaded event is fired along with a flag that tells whether the image was cleanly loaded or not. If it’s not cleanly loaded, then you need to ask for it to be reloaded.
  • once the image is loaded it has to be processed through the pixelpipe to generate the center display and the navigation preview, so you need to catch pixelpipe-processing-complete to make sure the image is ready to have edits applied to it.
  • apply edits catching pixelpipe-processing-complete between each action call

The problem with setting spot exposure in measurement mode is that it only uses the preview pixelpipe, so until the new PR is merged there isn’t a way to catch that event.

When you are running/testing scripts if you run darktable in a terminal with the -d lua -d perf flags you can click in the GUI and see what’s happening from the messages, which is how I figured out the spot exposure measurement problem.

Here comes a new version with some changes:

  • it should support dt 4.2.1 and dt 4.3+801 now

  • with DT 4.2 there is a timing problem, if you run it with older hardware you might run into errors. To avoid this, there are some sleeping times included. You can find some dt.control.sleep(1000) within the code. You could increase the waiting time to your needs. This will be fixed with later dt versions.

You can find the script file in the attachment:

InitialWorkflowModule.zip (10.5 KB)

or you can download it from github (as of today):

3 Likes

It’s linked in this thread just scroll up

tks, got it.

I understand that we have to wait for both events.

How can I read the flag to detect the image was cleanly loaded or not? The callback gets two parameters, event and image. Where can I find the flag?

How can I reload it if the image didn’t load cleanly?

Here’s a script that uses it

display_in_darkroom.zip (1.2 KB)

1 Like

thanks! The callback function now has 3 parameters? Is it new for dt 4.3?

No, actually it’s in 4.2. It was merged 10/14/22. To better understand what “clean” is, here’s the commit message

Added triggers for the darkroom-image-loaded lua event. Researching
_dev_change_image I found that it’s possible to load an image without
having locks on the pixel pipes, which means that if you immediately
do any processing it gets applied to the previous image. So I added
a status (boolean) to the event that lets the caller know if the load
was clean (got pixel pipe locks) or not.

This got added when I started playing with darktable.gui.action() and started having edits show up on the wrong images

2 Likes

seems like that’s a good thing for the next script version :slight_smile: , I will integrate it.

1 Like

In my lua script I try to set “global chroma” in color balance rgb module. The script sets the value and waits for “pixelpipe-processing-complete”. That works fine, but if I set an already set value again, the event is not sent. I’m now trying to read the current value beforehand to avoid the set command, but I don’t get the exact value from the GUI:

example: value in user interface = 1.23%
luaValue = dt.gui.action(“iop/colorbalancergb/global chroma”,0,“value”,“”,0/0)
luaValue is returned as 2.5123000144958

I tried other values:
1.23% => 2.5123000144958
2.34% => 2.5234000682831

There seems to be an offset of 2.5 and a small rounding error?
How can I get the current value of this slider? Is it the same for other modules?

EDIT: I could round the value and subtract out the offset and %, but maybe there’s a more direct way?

EDIT: Contrast Equalizer Mix needs offset and factor :slight_smile:

Color Balance RGB chroma:
value = Round((dt.gui.action(…) - 2.5) * 1)

Contrast Equalizer Mix:
value = Round((dt.gui.action(…) - 2.5) * 4)

value = dt.gui.action(“iop/atrous/mix”,0,“value”,“”,0/0)
converted = value - 2.5
converted = converted * 4
converted = math.floor(converted * 10000 + 0.5) / 10000

The normal return from dt.gui.action is an encoded value of the location on the 0-1 range and includes an indication on whether this is a percentage or a ± value. This is used to correctly set rotor lights on midi encoders.

The only exception is the “set” effect, which takes and returns an actual parameter value (which might be different from what is shown on the screen, because that sometimes contains further scaling/offset).

So for your case the following should work (though I haven’t tested)
luaValue = dt.gui.action(“iop/colorbalancergb/global chroma”,“value”,“set”)

1 Like

that works, thank you!

1 Like

one more thing:

I use the following command to configure channel mixer rgb:
dt.gui.action(“iop/channelmixerrgb/illuminant”,0,“selection”,“item:D (daylight)”,1,000)

If the same value is already configured, no pixelpipe-processing-complete event is sent.

How can I detect the current value?

dt.gui.action(“iop/channelmixerrgb/illuminant”, 0, “selection”, 0/0)

returns decimal values, but I would prefer a string like “item:D (daylight)”.

Sorry, you can’t; dt.gui.action can only return values as in c return types are fixed. This would require somebody to write a completely separate function. Or you would have to copy and maintain the list of names in lua.