Support grouping images into stacks by different criteria (or forcing the selection to be interpreted as a single UltraHDR stack).

This commit is contained in:
Krzysztof Kotowicz
2024-09-21 09:49:06 +02:00
parent 08726427aa
commit 44e442e7eb

View File

@@ -60,6 +60,7 @@ local GUI = {
optionwidgets = { optionwidgets = {
settings_label = {}, settings_label = {},
encoding_variant_combo = {}, encoding_variant_combo = {},
selection_type_combo = {},
encoding_settings_box = {}, encoding_settings_box = {},
output_settings_label = {}, output_settings_label = {},
output_settings_box = {}, output_settings_box = {},
@@ -96,6 +97,9 @@ local ENCODING_VARIANT_SDR_AND_GAINMAP = 1
local ENCODING_VARIANT_SDR_AND_HDR = 2 local ENCODING_VARIANT_SDR_AND_HDR = 2
local ENCODING_VARIANT_SDR_AUTO_GAINMAP = 3 local ENCODING_VARIANT_SDR_AUTO_GAINMAP = 3
local SELECTION_TYPE_ONE_STACK = 1
local SELECTION_TYPE_GROUP_BY_FNAME = 2
local function generate_metadata_file() local function generate_metadata_file()
local default_metadata_file = [[--maxContentBoost 6.0 local default_metadata_file = [[--maxContentBoost 6.0
--minContentBoost 1.0 --minContentBoost 1.0
@@ -118,6 +122,7 @@ end
local function save_preferences() local function save_preferences()
dt.preferences.write(namespace, "encoding_variant", "integer", GUI.optionwidgets.encoding_variant_combo.selected) dt.preferences.write(namespace, "encoding_variant", "integer", GUI.optionwidgets.encoding_variant_combo.selected)
dt.preferences.write(namespace, "selection_type", "integer", GUI.optionwidgets.selection_type_combo.selected)
if GUI.optionwidgets.metadata_path_widget.value then if GUI.optionwidgets.metadata_path_widget.value then
dt.preferences.write(namespace, "metadata_path", "string", GUI.optionwidgets.metadata_path_widget.value) dt.preferences.write(namespace, "metadata_path", "string", GUI.optionwidgets.metadata_path_widget.value)
end end
@@ -133,6 +138,9 @@ local function load_preferences()
-- Since the option #1 is the default, and empty numeric prefs are 0, we can use math.max -- Since the option #1 is the default, and empty numeric prefs are 0, we can use math.max
GUI.optionwidgets.encoding_variant_combo.selected = math.max( GUI.optionwidgets.encoding_variant_combo.selected = math.max(
dt.preferences.read(namespace, "encoding_variant", "integer"), ENCODING_VARIANT_SDR_AND_GAINMAP) dt.preferences.read(namespace, "encoding_variant", "integer"), ENCODING_VARIANT_SDR_AND_GAINMAP)
GUI.optionwidgets.selection_type_combo.selected = math.max(
dt.preferences.read(namespace, "selection_type", "integer"), SELECTION_TYPE_ONE_STACK)
GUI.optionwidgets.metadata_path_widget.value = dt.preferences.read(namespace, "metadata_path", "string") GUI.optionwidgets.metadata_path_widget.value = dt.preferences.read(namespace, "metadata_path", "string")
if not GUI.optionwidgets.metadata_path_widget.value then -- file widgets reset "" value to nil if not GUI.optionwidgets.metadata_path_widget.value then -- file widgets reset "" value to nil
GUI.optionwidgets.metadata_path_widget.value = generate_metadata_file() GUI.optionwidgets.metadata_path_widget.value = generate_metadata_file()
@@ -148,10 +156,6 @@ local function load_preferences()
GUI.optionwidgets.copy_exif.value = dt.preferences.read(namespace, "copy_exif", "bool") GUI.optionwidgets.copy_exif.value = dt.preferences.read(namespace, "copy_exif", "bool")
end end
local function get_encoding_variant()
return GUI.optionwidgets.encoding_variant_combo.selected
end
local function assert_settings_correct(encoding_variant) local function assert_settings_correct(encoding_variant)
local errors = {} local errors = {}
local settings = { local settings = {
@@ -210,8 +214,8 @@ local function get_stacks(images, encoding_variant, selection_type)
end end
local tags = nil local tags = nil
-- Group images into sdr, extra pairs based on their original filename, ignoring the extension -- Group images into (sdr [,extra]) stacks
-- Assume that the first encountered image from each filename is an sdr one, unless it has a tag matching the expected extra_image_type, or has the expected extension -- Assume that the first encountered image from each stack is an sdr one, unless it has a tag matching the expected extra_image_type, or has the expected extension
for k, v in pairs(images) do for k, v in pairs(images) do
local is_extra = false local is_extra = false
tags = dt.tags.get_tags(v) tags = dt.tags.get_tags(v)
@@ -224,7 +228,12 @@ local function get_stacks(images, encoding_variant, selection_type)
is_extra = true is_extra = true
end end
-- We assume every image in the stack is generated from the same source image file -- We assume every image in the stack is generated from the same source image file
local key = df.chop_filetype(v.path .. PS .. v.filename) local key
if selection_type == SELECTION_TYPE_GROUP_BY_FNAME then
key = df.chop_filetype(v.path .. PS .. v.filename)
elseif selection_type == SELECTION_TYPE_ONE_STACK then
key = "the_one_and_only"
end
if stacks[key] == nil then if stacks[key] == nil then
stacks[key] = {} stacks[key] = {}
end end
@@ -407,8 +416,9 @@ local function main()
save_preferences() save_preferences()
local encoding_variant = get_encoding_variant() local selection_type = GUI.optionwidgets.selection_type_combo.selected
log.msg(log.info, string.format("using encoding variant %d", encoding_variant)) local encoding_variant = GUI.optionwidgets.encoding_variant_combo.selected
log.msg(log.info, string.format("using selection type %d, encoding variant %d", selection_type, encoding_variant))
local settings, errors = assert_settings_correct(encoding_variant) local settings, errors = assert_settings_correct(encoding_variant)
if not settings then if not settings then
@@ -417,7 +427,7 @@ local function main()
return return
end end
local stacks, stack_count = get_stacks(dt.gui.selection(), encoding_variant) local stacks, stack_count = get_stacks(dt.gui.selection(), encoding_variant, selection_type)
dt.print(string.format(_("Detected %d image stack(s)"), stack_count)) dt.print(string.format(_("Detected %d image stack(s)"), stack_count))
if stack_count == 0 then if stack_count == 0 then
log.log_level(saved_log_level) log.log_level(saved_log_level)
@@ -513,20 +523,17 @@ GUI.optionwidgets.metadata_path_box = dt.new_widget("box") {
} }
GUI.optionwidgets.encoding_variant_combo = dt.new_widget("combobox") { GUI.optionwidgets.encoding_variant_combo = dt.new_widget("combobox") {
label = _("Source images"), label = _("Each stack contains"),
tooltip = string.format(_([[Select types of images in the selection. tooltip = string.format(_([[Select the types of images in each stack.
This will determine the method used to generate UltraHDR.
- %s: SDR image paired with a gain map image - %s: SDR image paired with a gain map image.
- %s: SDR image paired with a JPEG-XL HDR image (10-bit, 'PQ P3 RGB' profile recommended) - %s: SDR image paired with a JPEG-XL HDR image (10-bit, 'PQ P3 RGB' profile recommended).
- %s: SDR images only. Gainmaps will be copies of SDR images (the simplest option). - %s: SDR images only. Gainmaps will be copies of SDR images (the simplest option).
UltraHDR image will be created for each pair of images that: By default, the first image in a stack is treated as SDR, and the second one is a gainmap/HDR.
- have the same underlying image path + filename (ignoring file extension) You can force the image into a specific stack slot by attaching "hdr" / "gainmap" tags to them.
- have the same dimensions ]]), _("SDR + gainmap"), _("SDR + JPEG-XL HDR"), _("SDR only")),
By default, the first image in a pair is treated as SDR, and the second one stores extra gainmap/HDR data.
You can force the image into a specific slot by attaching "hdr" / "gainmap" tags.
]]), _("SDR + gainmap"), _("SDR + JPEG-XL HDR"), _("SDR (auto gainmap)")),
selected = 0, selected = 0,
changed_callback = function(self) changed_callback = function(self)
GUI.run.sensitive = self.selected and self.selected > 0 GUI.run.sensitive = self.selected and self.selected > 0
@@ -538,11 +545,28 @@ You can force the image into a specific slot by attaching "hdr" / "gainmap" tags
end, end,
_("SDR + gainmap"), -- ENCODING_VARIANT_SDR_AND_GAINMAP _("SDR + gainmap"), -- ENCODING_VARIANT_SDR_AND_GAINMAP
_("SDR + JPEG-XL HDR"), -- ENCODING_VARIANT_SDR_AND_HDR _("SDR + JPEG-XL HDR"), -- ENCODING_VARIANT_SDR_AND_HDR
_("SDR (auto gainmap)") -- ENCODING_VARIANT_SDR_AUTO_GAINMAP _("SDR only") -- ENCODING_VARIANT_SDR_AUTO_GAINMAP
}
GUI.optionwidgets.selection_type_combo = dt.new_widget("combobox") {
label = _("Selection contains"),
tooltip = string.format(_([[Select types of images selected in Darktable.
This determines how the plugin groups images into separate stacks (each stack will produce a single UltraHDR image).
- %s: All selected image(s) belong to one stack. There will be 1 output UltraHDR image.
- %s: Group images into stacks, using the source image path + filename (ignoring extension).
Use this method if the source images for a given stack are Darktable duplicates.
As an added precaution, each image in a stack needs to have the same dimensions.
]]), _("one stack"), _("multiple stacks (use filename)")),
selected = 0,
_("one stack"), -- SELECTION_TYPE_ONE_STACK
_("multiple stacks (use filename)") -- SELECTION_TYPE_GROUP_BY_FNAME
} }
GUI.optionwidgets.encoding_settings_box = dt.new_widget("box") { GUI.optionwidgets.encoding_settings_box = dt.new_widget("box") {
orientation = "vertical", orientation = "vertical",
GUI.optionwidgets.selection_type_combo,
GUI.optionwidgets.encoding_variant_combo, GUI.optionwidgets.encoding_variant_combo,
GUI.optionwidgets.metadata_path_box GUI.optionwidgets.metadata_path_box
} }