From bc4c04f795d0562bfc5d9f9aaae1de41f603f370 Mon Sep 17 00:00:00 2001 From: "U-DESKTOP-HQME86J\\marco" Date: Sat, 18 Jan 2020 12:45:58 +0100 Subject: [PATCH 001/445] error fix --- contrib/ext_editor.lua | 614 ++++++++++++++++++++--------------------- 1 file changed, 307 insertions(+), 307 deletions(-) diff --git a/contrib/ext_editor.lua b/contrib/ext_editor.lua index b5e8eb23..f9a96dd9 100644 --- a/contrib/ext_editor.lua +++ b/contrib/ext_editor.lua @@ -1,64 +1,64 @@ --[[ - DESCRIPTION + DESCRIPTION ext_editor.lua - edit images with external editors This script provides helpers to edit image files with programs external to darktable. - It adds: - - a new target storage "collection". Image exported will be reimported to collection for - further edit with external programs - - a new lighttable module "external editors", to select a program from a list of up to - - 9 external editors and run it on a selected image - - a set of lua preferences in order to configure name and path of up to 9 external editors - - a set of lua shortcuts in order to quick launch the external editors - - USAGE + It adds: + - a new target storage "collection". Image exported will be reimported to collection for + further edit with external programs + - a new lighttable module "external editors", to select a program from a list of up to + - 9 external editors and run it on a selected image (adjust this limit by changing MAX_EDITORS) + - a set of lua preferences in order to configure name and path of up to 9 external editors + - a set of lua shortcuts in order to quick launch the external editors + + USAGE * require this script from main lua file - - -- setup -- - * in "preferences/lua options" configure name and path/command of external programs - * note that if a program name is left empty, that and all following entries will be ignored - * in "preferences/shortcuts/lua" configure shortcuts for external programs (optional) - * whenever programs preferences are changed, in lighttable/external editors, press "update list" - - -- use -- + + -- setup -- + * in "preferences/lua options" configure name and path/command of external programs + * note that if a program name is left empty, that and all following entries will be ignored + * in "preferences/shortcuts/lua" configure shortcuts for external programs (optional) + * whenever programs preferences are changed, in lighttable/external editors, press "update list" + + -- use -- * in the export dialog choose "collection" and select the format and bit depth for the exported image * press "export" - * the exported image will be imported into collection and grouped with the original image + * the exported image will be imported into collection and grouped with the original image - * select an image for editing with en external program, and: - * in lighttable/external editors, select program and press "edit" - * edit the image with the external editor, overwite the file, quit the external program - * the selected image will be updated - or - * in lighttable/external editors, select program and press "edit a copy" - * edit the image with the external editor, overwite the file, quit the external program - * a copy of the selected image will be created and updated - or - * in lighttable select target storage "collection" - * enter in darkroom - * to create an export or a copy press CRTL+E - * use the shortcut to edit the current image with the corresponding external editor - * overwite the file, quit the external program - * the darkroom view will be updated - - * warning: mouseover on lighttable/filmstrip will prevail on current image - * this is the default DT behavior, not a bug of this script + * select an image for editing with en external program, and: + * in lighttable/external editors, select program and press "edit" + * edit the image with the external editor, overwite the file, quit the external program + * the selected image will be updated + or + * in lighttable/external editors, select program and press "edit a copy" + * edit the image with the external editor, overwite the file, quit the external program + * a copy of the selected image will be created and updated + or + * in lighttable select target storage "collection" + * enter in darkroom + * to create an export or a copy press CRTL+E + * use the shortcut to edit the current image with the corresponding external editor + * overwite the file, quit the external program + * the darkroom view will be updated + + * warning: mouseover on lighttable/filmstrip will prevail on current image + * this is the default DT behavior, not a bug of this script CAVEATS - * MAC compatibility not tested - - TODO - * send multiple images to the same program, maybe - + * MAC compatibility not tested + + TODO + * send multiple images to the same program, maybe + BUGS, COMMENTS, SUGGESTIONS * send to Marco Carrarini, marco.carrarini@gmail.com CHANGES * 20191224 - initial version - * 20191227 - added button "update list", better error handling, fixed bug with groups/tags in "edit" - + * 20191227 - added button "update list", better error handling, fixed bug with groups/tags in "edit" + ]] @@ -87,341 +87,341 @@ local function _(msgid) return gettext.dgettext(MODULE_NAME, msgid) end +-- maximum number of external programs +local MAX_EDITORS = 9 -- number of valid entries in the list of external programs local n_entries -- allowed file extensions, to exclude RAW, which cannot be edited externally -local allowed_file_types = {"JPG", "jpg", "JPEG", "jpeg", "TIF", "tif", "TIFF", "tiff", "EXR", "exr"} +local allowed_file_types = {"JPG", "jpg", "JPEG", "jpeg", "TIF", "tif", "TIFF", "tiff", "EXR", "exr", "PNG", "png"} -- last used editor initialization if not dt.preferences.read(MODULE_NAME,"initialized", "bool") then - dt.preferences.write(MODULE_NAME,"lastchoice", "integer", 0) - dt.preferences.write(MODULE_NAME,"initialized", "bool", true) - end + dt.preferences.write(MODULE_NAME,"lastchoice", "integer", 0) + dt.preferences.write(MODULE_NAME,"initialized", "bool", true) + end local lastchoice = 0 -- update lists of program names and paths, as well as combobox --------------- local function UpdateProgramList(combobox, button_edit, button_edit_copy, update_button_pressed) - -- initialize lists - program_names = {} - program_paths = {} - - -- build lists from preferences - local name - local last = false - n_entries = 0 - for i = 1, 9 do - name = dt.preferences.read(MODULE_NAME,"program_name_"..i, "string") - if (name == "" or name == nil) then last = true end - if last then - if combobox[n_entries + 1] then combobox[n_entries + 1] = nil end -- remove extra combobox entries - else - combobox[i] = i..": "..name - program_names[i] = name - program_paths[i] = df.sanitize_filename(dt.preferences.read(MODULE_NAME, "program_path_"..i, "string")) - n_entries = i - end - end - - lastchoice = dt.preferences.read(MODULE_NAME, "lastchoice", "integer") - if lastchoice == 0 and n_entries > 0 then lastchoice = 1 end - if lastchoice > n_entries then lastchoice = n_entries end - dt.preferences.write(MODULE_NAME, "lastchoice", "integer", lastchoice) - - -- widgets enabled if there is at least one program configured - combobox.selected = lastchoice - local active = n_entries > 0 + -- initialize lists + program_names = {} + program_paths = {} + + -- build lists from preferences + local name + local last = false + n_entries = 0 + for i = 1, MAX_EDITORS do + name = dt.preferences.read(MODULE_NAME,"program_name_"..i, "string") + if (name == "" or name == nil) then last = true end + if last then + if combobox[n_entries + 1] then combobox[n_entries + 1] = nil end -- remove extra combobox entries + else + combobox[i] = i..": "..name + program_names[i] = name + program_paths[i] = df.sanitize_filename(dt.preferences.read(MODULE_NAME, "program_path_"..i, "string")) + n_entries = i + end + end + + lastchoice = dt.preferences.read(MODULE_NAME, "lastchoice", "integer") + if lastchoice == 0 and n_entries > 0 then lastchoice = 1 end + if lastchoice > n_entries then lastchoice = n_entries end + dt.preferences.write(MODULE_NAME, "lastchoice", "integer", lastchoice) + + -- widgets enabled if there is at least one program configured + combobox.selected = lastchoice + local active = n_entries > 0 combobox.sensitive = active button_edit.sensitive = active button_edit_copy.sensitive = active - if update_button_pressed then dt.print(n_entries.._(" editors configured")) end - end - - --- shows export progress ------------------------------------------------------ -local function show_status(storage, image, format, filename, number, total, high_quality, extra_data) - - dt.print(_("exporting image ").. number.." / "..total.." ...") - end + if update_button_pressed then dt.print(n_entries.._(" editors configured")) end + end -- callback for buttons "edit" and "edit a copy" ------------------------------ local function OpenWith(images, choice, copy) - - -- check choice is valid, return if not - if choice > n_entries then - dt.print(_("not a valid choice")) - return - end - - -- check if one image is selected, return if not - if #images ~= 1 then - dt.print(_("please select one image")) - return - end - - local bin = program_paths[choice] - local friendly_name = program_names[choice] - - -- check if external program executable exists, return if not - if not df.check_if_bin_exists(bin) then - dt.print(friendly_name.._(" not found")) - return - end - - -- image to be edited - local image - i, image = next(images) - local name = image.path..PS..image.filename - - -- check if image is raw, return if it is - -- please note that the image property image.is_raw fails when filepath contains spaces - -- so as a workaround we allow only TIF, JPG and EXR - local file_ext = df.get_filetype (image.filename) - local allowed = false - for i,v in pairs(allowed_file_types) do - if v == file_ext then - allowed = true - break - end - end - if not allowed then - dt.print(_("file type not allowed")) - return - end - - -- save image tags, rating and color - local tags = {} + + -- check choice is valid, return if not + if choice > n_entries then + dt.print(_("not a valid choice")) + return + end + + -- check if one image is selected, return if not + if #images ~= 1 then + dt.print(_("please select one image")) + return + end + + local bin = program_paths[choice] + local friendly_name = program_names[choice] + + -- check if external program executable exists, return if not + if not df.check_if_bin_exists(bin) then + dt.print(friendly_name.._(" not found")) + return + end + + -- image to be edited + local image + i, image = next(images) + local name = image.path..PS..image.filename + + -- check if image is raw, return if it is + -- please note that the image property image.is_raw fails when filepath contains spaces + -- so as a workaround we allow only TIF, JPG and EXR + local file_ext = df.get_filetype (image.filename) + local allowed = false + for i,v in pairs(allowed_file_types) do + if v == file_ext then + allowed = true + break + end + end + if not allowed then + dt.print(_("file type not allowed")) + return + end + + -- save image tags, rating and color + local tags = {} for i, tag in ipairs(dt.tags.get_tags(image)) do - if not (string.sub(tag.name, 1, 9) == "darktable") then table.insert(tags, tag) end - end - local rating = image.rating - local red = image.red - local blue = image.blue - local green = image.green - local yellow = image.yellow - local purple = image.purple + if not (string.sub(tag.name, 1, 9) == "darktable") then table.insert(tags, tag) end + end + local rating = image.rating + local red = image.red + local blue = image.blue + local green = image.green + local yellow = image.yellow + local purple = image.purple -- new image local new_name = name - local new_image = image + local new_image = image if copy then - -- create unique filename - while true do -- dirty solution to workaround issue in lib function check_if_file_exists() - if dt.configuration.running_os == "windows" then - if not df.check_if_file_exists(df.sanitize_filename(new_name)) then break end - else - if not df.check_if_file_exists(new_name) then break end - end - new_name = df.filename_increment(new_name) - -- limit to 50 more exports of the original export - if string.match(df.get_basename(new_name), "_%d%d$") == "_50" then break end - end - - -- physical copy, check result, return if error - local copy_success = df.file_copy(name, new_name) - if not copy_success then - dt.print(_("error copying file ")..name) - return - end + -- create unique filename + while true do -- dirty solution to workaround issue in lib function check_if_file_exists() + if dt.configuration.running_os == "windows" then + if not df.check_if_file_exists(df.sanitize_filename(new_name)) then break end + else + if not df.check_if_file_exists(new_name) then break end + end + new_name = df.filename_increment(new_name) + -- limit to 50 more exports of the original export + if string.match(df.get_basename(new_name), "_%d%d$") == "_50" then break end + end + + -- physical copy, check result, return if error + local copy_success = df.file_copy(name, new_name) + if not copy_success then + dt.print(_("error copying file ")..name) + return + end end - -- launch the external editor, check result, return if error - local run_cmd = bin.." "..df.sanitize_filename(new_name) - dt.print(_("launching ")..friendly_name.."...") - local result = dtsys.external_command(run_cmd) - if result ~= 0 then - dt.print(_("error launching ")..friendly_name) - return - end + -- launch the external editor, check result, return if error + local run_cmd = bin.." "..df.sanitize_filename(new_name) + dt.print(_("launching ")..friendly_name.."...") + local result = dtsys.external_command(run_cmd) + if result ~= 0 then + dt.print(_("error launching ")..friendly_name) + return + end if copy then - -- import in database and group - new_image = dt.database.import(new_name) - new_image:group_with(image) + -- import in database and group + new_image = dt.database.import(new_name) + new_image:group_with(image) else -- refresh the image view - -- note that only image:drop_cache() is not enough to refresh view in darkroom mode - -- therefore image must be deleted and reimported to force refresh + -- note that only image:drop_cache() is not enough to refresh view in darkroom mode + -- therefore image must be deleted and reimported to force refresh -- find the grouping status - local image_leader = image.group_leader - local group_members = image:get_group_members() - local new_leader - local index = nil - local found = false - - -- membership status, three different cases - if image_leader == image then - if #group_members > 1 then - -- case 1: image is leader in a group with more members - while not found do - index, new_leader = next(group_members, index) - if new_leader ~= image_leader then found = true end - end - new_leader:make_group_leader() - image:delete() - new_image = dt.database.import(name) - new_image:group_with(new_leader) - new_image:make_group_leader() - else - -- case 2: image is the only member in group - image:delete() - new_image = dt.database.import(name) - new_image:group_with() - end - else - -- case 3: image is in a group but is not leader - image:delete() - new_image = dt.database.import(name) - new_image:group_with(image_leader) - end - -- refresh darkroom view - if dt.gui.current_view() == dt.gui.views.darkroom then - dt.gui.views.darkroom.display_image(new_image) - end - end - - -- restore image tags, rating and color, must be put after refresh darkroom view - for i, tag in ipairs(tags) do dt.tags.attach(tag, new_image) end - new_image.rating = rating - new_image.red = red - new_image.blue = blue - new_image.green = green - new_image.yellow = yellow - new_image.purple = purple + local image_leader = image.group_leader + local group_members = image:get_group_members() + local new_leader + local index = nil + local found = false + + -- membership status, three different cases + if image_leader == image then + if #group_members > 1 then + -- case 1: image is leader in a group with more members + while not found do + index, new_leader = next(group_members, index) + if new_leader ~= image_leader then found = true end + end + new_leader:make_group_leader() + image:delete() + if image.local_copy then image:drop_cache() end -- to fix fail to allocate cache error + new_image = dt.database.import(name) + new_image:group_with(new_leader) + new_image:make_group_leader() + else + -- case 2: image is the only member in group + image:delete() + if image.local_copy then image:drop_cache() end -- to fix fail to allocate cache error + new_image = dt.database.import(name) + new_image:group_with() + end + else + -- case 3: image is in a group but is not leader + image:delete() + if image.local_copy then image:drop_cache() end -- to fix fail to allocate cache error + new_image = dt.database.import(name) + new_image:group_with(image_leader) + end + -- refresh darkroom view + if dt.gui.current_view() == dt.gui.views.darkroom then + dt.gui.views.darkroom.display_image(new_image) + end + end + + -- restore image tags, rating and color, must be put after refresh darkroom view + for i, tag in ipairs(tags) do dt.tags.attach(tag, new_image) end + new_image.rating = rating + new_image.red = red + new_image.blue = blue + new_image.green = green + new_image.yellow = yellow + new_image.purple = purple -- select the new image - local selection = {} - table.insert(selection, new_image) - dt.gui.selection (selection) + local selection = {} + table.insert(selection, new_image) + dt.gui.selection (selection) - end + end -- callback function for shortcuts -------------------------------------------- local function program_shortcut(event, shortcut) - OpenWith(dt.gui.action_images, tonumber(string.sub(shortcut, -1)), false) - end + OpenWith(dt.gui.action_images, tonumber(string.sub(shortcut, -1)), false) + end -- export images and reimport in collection ----------------------------------- local function export2collection(storage, image_table, extra_data) - local new_name, new_image, result + local new_name, new_image, result - for image, temp_name in pairs(image_table) do + for image, temp_name in pairs(image_table) do - -- images are first exported in temp folder then moved to collection folder + -- images are first exported in temp folder then moved to collection folder - -- create unique filename - new_name = image.path..PS..df.get_filename(temp_name) - while true do -- dirty solution to workaround issue in lib function check_if_file_exists() - if dt.configuration.running_os == "windows" then - if not df.check_if_file_exists(df.sanitize_filename(new_name)) then break end - else - if not df.check_if_file_exists(new_name) then break end - end - new_name = df.filename_increment(new_name) - -- limit to 50 more exports of the original export - if string.match(df.get_basename(new_name), "_%d%d$") == "_50" then break end - end - - -- move image to collection folder, check result, return if error - move_success = df.file_move(temp_name, new_name) - if not move_success then - dt.print(_("error moving file ")..temp_name) - return - end - - -- import in database and group - new_image = dt.database.import(new_name) - new_image:group_with(image.group_leader) - end - end + -- create unique filename + new_name = image.path..PS..df.get_filename(temp_name) + while true do -- dirty solution to workaround issue in lib function check_if_file_exists() + if dt.configuration.running_os == "windows" then + if not df.check_if_file_exists(df.sanitize_filename(new_name)) then break end + else + if not df.check_if_file_exists(new_name) then break end + end + new_name = df.filename_increment(new_name) + -- limit to 50 more exports of the original export + if string.match(df.get_basename(new_name), "_%d%d$") == "_50" then break end + end + + -- move image to collection folder, check result, return if error + move_success = df.file_move(temp_name, new_name) + if not move_success then + dt.print(_("error moving file ")..temp_name) + return + end + + -- import in database and group + new_image = dt.database.import(new_name) + new_image:group_with(image.group_leader) + end + + dt.print (_("finished exporting")) + end -- register new storage ------------------------------------------------------- -- note that placing this declaration later makes the export selected module -- not to remember the choice "collection" when restarting DT, don't know why -dt.register_storage("exp2coll", _("collection"), show_status, export2collection) +dt.register_storage("exp2coll", _("collection"), null, export2collection) -- combobox, with variable number of entries ---------------------------------- local combobox = dt.new_widget("combobox") { - label = _("choose program"), - tooltip = _("select the external editor from the list"), - changed_callback = function(self) - dt.preferences.write(MODULE_NAME, "lastchoice", "integer", self.selected) - end, - "" - } + label = _("choose program"), + tooltip = _("select the external editor from the list"), + changed_callback = function(self) + dt.preferences.write(MODULE_NAME, "lastchoice", "integer", self.selected) + end, + "" + } -- button edit ---------------------------------------------------------------- local button_edit = dt.new_widget("button") { - label = _("edit"), - tooltip = _("open the selected image in external editor"), - --sensitive = false, - clicked_callback = function() - OpenWith(dt.gui.action_images, combobox.selected, false) - end - } + label = _("edit"), + tooltip = _("open the selected image in external editor"), + --sensitive = false, + clicked_callback = function() + OpenWith(dt.gui.action_images, combobox.selected, false) + end + } -- button edit a copy --------------------------------------------------------- local button_edit_copy = dt.new_widget("button") { - label = _("edit a copy"), - tooltip = _("create a copy of the selected image and open it in external editor"), - clicked_callback = function() - OpenWith(dt.gui.action_images, combobox.selected, true) - end - } + label = _("edit a copy"), + tooltip = _("create a copy of the selected image and open it in external editor"), + clicked_callback = function() + OpenWith(dt.gui.action_images, combobox.selected, true) + end + } -- button update list --------------------------------------------------------- local button_update_list = dt.new_widget("button") { - label = _("update list"), - tooltip = _("update list of programs if lua preferences are changed"), - clicked_callback = function() - UpdateProgramList(combobox, button_edit, button_edit_copy, true) - end - } + label = _("update list"), + tooltip = _("update list of programs if lua preferences are changed"), + clicked_callback = function() + UpdateProgramList(combobox, button_edit, button_edit_copy, true) + end + } -- box for the buttons -------------------------------------------------------- -- it doesn't seem there is a way to make the buttons equal in size local box1 = dt.new_widget("box") { orientation = "horizontal", - button_edit, - button_edit_copy, - button_update_list - } + button_edit, + button_edit_copy, + button_update_list + } -- register new module "external editors" in lighttable ------------------------ dt.register_lib( - MODULE_NAME, - _("external editors"), - true, -- expandable - false, -- resetable - {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, - dt.new_widget("box") { - orientation = "vertical", - combobox, - box1 - }, - nil, -- view_enter - nil -- view_leave - ) + MODULE_NAME, + _("external editors"), + true, -- expandable + false, -- resetable + {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, + dt.new_widget("box") { + orientation = "vertical", + combobox, + box1 + }, + nil, -- view_enter + nil -- view_leave + ) -- initialize list of programs and widgets ------------------------------------ @@ -429,23 +429,23 @@ UpdateProgramList(combobox, button_edit, button_edit_copy, false) -- register the new preferences ----------------------------------------------- -for i = 9, 1, -1 do - dt.preferences.register(MODULE_NAME, "program_path_"..i, "file", - _("executable for external editor ")..i, - _("select executable for external editor") , _("(None)")) - dt.preferences.register(MODULE_NAME, "program_name_"..i, "string", - _("name of external editor ")..i, - _("friendly name of external editor"), "") - end +for i = MAX_EDITORS, 1, -1 do + dt.preferences.register(MODULE_NAME, "program_path_"..i, "file", + _("executable for external editor ")..i, + _("select executable for external editor") , _("(None)")) + dt.preferences.register(MODULE_NAME, "program_name_"..i, "string", + _("name of external editor ")..i, + _("friendly name of external editor"), "") + end --- register the new shortcuts ------------------------------------------------- -for i = 1, 9 do - dt.register_event("shortcut", program_shortcut, _("edit with program ")..i) - end +-- register the new shortcuts ------------------------------------------------- +for i = 1, MAX_EDITORS do + dt.register_event("shortcut", program_shortcut, _("edit with program ")..i) + end -- end of script -------------------------------------------------------------- --- vim: shiftwidth=4 expandtab tabstop=4 cindent syntax=lua +-- vim: shiftwidth=2 expandtab tabstop=2 cindent syntax=lua -- kate: hl Lua; From 5b977733b304ab890fc2a203a1360f7ad310f209 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sun, 19 Jan 2020 23:11:41 -0500 Subject: [PATCH 002/445] Rewrote sanitize and is_not_sanitized to handle strings with embedded operatings system quotes. Fixes #216. --- lib/dtutils/string.lua | 47 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 41 insertions(+), 6 deletions(-) diff --git a/lib/dtutils/string.lua b/lib/dtutils/string.lua index 89af3a7b..ba4cd675 100644 --- a/lib/dtutils/string.lua +++ b/lib/dtutils/string.lua @@ -193,11 +193,29 @@ dtutils_string.libdoc.functions["sanitize"] = { } function dtutils_string.sanitize(str) - local result = "" + local result = str local os_quote = dt.configuration.running_os == "windows" and '"' or "'" + local escaped_os_quote = "\\" .. os_quote - if dtutils_string.is_not_sanitized(str) then - result = os_quote .. str .. os_quote + if dtutils_string.is_not_sanitized(result) then + local pos = string.find(result, os_quote) + if not pos or pos > 1 then + result = os_quote .. result + end + pos = string.find(result, os_quote, string.len(result)) + if not pos then + result = result .. os_quote + end + + if dtutils_string.is_not_sanitized(result) then --check for embedded os_quotes + pos = string.find(result, os_quote, 2) + while pos < string.len(result) do + if not string.find(result, escaped_os_quote, pos - 1) then + result = string.format("%s\\%s", string.sub(result, 1, pos -1), string.sub(result, pos)) + end + pos = string.find(result, os_quote, pos+2) + end + end end return result @@ -222,12 +240,29 @@ dtutils_string.libdoc.functions["is_not_sanitized"] = { function dtutils_string.is_not_sanitized(str) local os_quote = dt.configuration.running_os == "windows" and '"' or "'" + local escaped_os_quote = "\\" .. os_quote + local length = string.len(str) + local not_sanitized = false - if string.match(str, os_quote .. ".*" .. os_quote) then - return false + local pos = string.find(str, os_quote) + if pos == 1 then + if string.find(str, os_quote, length) then + pos = string.find(str, os_quote, 2) + while pos ~= length do + if not string.find(str, escaped_os_quote, pos - 1) then + not_sanitized = true + end + pos = string.find(str, os_quote, pos + 1) + end + else + not_sanitized = true + end else - return true + not_sanitized = true end + +return not_sanitized + end From 847c39749daa4130549b518c1650642b6c9d8b3a Mon Sep 17 00:00:00 2001 From: August Schwerdfeger Date: Tue, 21 Jan 2020 00:29:18 -0600 Subject: [PATCH 003/445] Corrected escaping of command-line arguments in the 'sanitize' and 'is_not_sanitized' functions. --- lib/dtutils/string.lua | 98 ++++++++++++++++++++++-------------------- 1 file changed, 51 insertions(+), 47 deletions(-) diff --git a/lib/dtutils/string.lua b/lib/dtutils/string.lua index ba4cd675..2da4c909 100644 --- a/lib/dtutils/string.lua +++ b/lib/dtutils/string.lua @@ -192,33 +192,28 @@ dtutils_string.libdoc.functions["sanitize"] = { Copyright = [[]], } -function dtutils_string.sanitize(str) - local result = str - local os_quote = dt.configuration.running_os == "windows" and '"' or "'" - local escaped_os_quote = "\\" .. os_quote +function dtutils_string.sanitize_posix(str) + if dtutils_string.is_not_sanitized(str) then + return "'" .. string.gsub(str, "'", "'\\''") .. "'" + else + return str + end +end - if dtutils_string.is_not_sanitized(result) then - local pos = string.find(result, os_quote) - if not pos or pos > 1 then - result = os_quote .. result - end - pos = string.find(result, os_quote, string.len(result)) - if not pos then - result = result .. os_quote - end - - if dtutils_string.is_not_sanitized(result) then --check for embedded os_quotes - pos = string.find(result, os_quote, 2) - while pos < string.len(result) do - if not string.find(result, escaped_os_quote, pos - 1) then - result = string.format("%s\\%s", string.sub(result, 1, pos -1), string.sub(result, pos)) - end - pos = string.find(result, os_quote, pos+2) - end - end +function dtutils_string.sanitize_windows(str) + if dtutils_string.is_not_sanitized(str) then + return "\"" .. string.gsub(str, "\"", "\"^\"\"") .. "\"" + else + return str + end +end + +function dtutils_string.sanitize(str) + if dt.configuration.running_os == "windows" then + return dtutils_string.sanitize_windows(str) + else + return dtutils_string.sanitize_posix(str) end - - return result end dtutils_string.libdoc.functions["is_not_sanitized"] = { @@ -238,31 +233,40 @@ dtutils_string.libdoc.functions["is_not_sanitized"] = { Copyright = [[]], } -function dtutils_string.is_not_sanitized(str) - local os_quote = dt.configuration.running_os == "windows" and '"' or "'" - local escaped_os_quote = "\\" .. os_quote - local length = string.len(str) - local not_sanitized = false +function dtutils_string.is_not_sanitized_posix(str) + -- A sanitized string must be quoted. + if not string.match(str, "^'.*'$") then + return true + -- A quoted string containing no quote characters within is sanitized. + elseif string.match(str, "^'[^']*'$") then + return false + end + + -- Any quote characters within a sanitized string must be properly + -- escaped. + local quotesStripped = string.sub(str, 2, -2) + local escapedQuotesRemoved = string.gsub(quotesStripped, "'\\''", "") + if string.find(escapedQuotesRemoved, "'") then + return true + else + return false + end +end - local pos = string.find(str, os_quote) - if pos == 1 then - if string.find(str, os_quote, length) then - pos = string.find(str, os_quote, 2) - while pos ~= length do - if not string.find(str, escaped_os_quote, pos - 1) then - not_sanitized = true - end - pos = string.find(str, os_quote, pos + 1) - end - else - not_sanitized = true - end +function dtutils_string.is_not_sanitized_windows(str) + if not string.match(str, "^\".*\"$") then + return true + else + return false + end +end + +function dtutils_string.is_not_sanitized(str) + if dt.configuration.running_os == "windows" then + return dtutils_string.is_not_sanitized_windows(str) else - not_sanitized = true + return dtutils_string.is_not_sanitized_posix(str) end - -return not_sanitized - end From 51eda4e755f34c38886c1f04d447a6a9937a72a9 Mon Sep 17 00:00:00 2001 From: August Schwerdfeger Date: Tue, 21 Jan 2020 22:17:12 -0600 Subject: [PATCH 004/445] Made Windows- and POSIX-specific sanitization functions local; moved the 'sanitize' functions after the 'is_not_sanitized' functions that they call. --- lib/dtutils/string.lua | 92 +++++++++++++++++++++--------------------- 1 file changed, 46 insertions(+), 46 deletions(-) diff --git a/lib/dtutils/string.lua b/lib/dtutils/string.lua index 2da4c909..f58f38cd 100644 --- a/lib/dtutils/string.lua +++ b/lib/dtutils/string.lua @@ -174,48 +174,6 @@ function dtutils_string.urlencode(str) end -dtutils_string.libdoc.functions["sanitize"] = { - Name = [[sanitize]], - Synopsis = [[surround a string in quotes making it safe to pass as an argument]], - Usage = [[local ds = require "lib/dtutils.string" - - local result = ds.sanitize(str) - str - string - the string that needs to be made safe]], - Description = [[sanitize converts a string into a version suitable for - use passing as an argument in a system command.]], - Return_Value = [[result - string - a websafe string]], - Limitations = [[]], - Example = [[]], - See_Also = [[]], - Reference = [[]], - License = [[]], - Copyright = [[]], -} - -function dtutils_string.sanitize_posix(str) - if dtutils_string.is_not_sanitized(str) then - return "'" .. string.gsub(str, "'", "'\\''") .. "'" - else - return str - end -end - -function dtutils_string.sanitize_windows(str) - if dtutils_string.is_not_sanitized(str) then - return "\"" .. string.gsub(str, "\"", "\"^\"\"") .. "\"" - else - return str - end -end - -function dtutils_string.sanitize(str) - if dt.configuration.running_os == "windows" then - return dtutils_string.sanitize_windows(str) - else - return dtutils_string.sanitize_posix(str) - end -end - dtutils_string.libdoc.functions["is_not_sanitized"] = { Name = [[is_not_sanitized]], Synopsis = [[Check if a string has been sanitized]], @@ -233,7 +191,7 @@ dtutils_string.libdoc.functions["is_not_sanitized"] = { Copyright = [[]], } -function dtutils_string.is_not_sanitized_posix(str) +local function _is_not_sanitized_posix(str) -- A sanitized string must be quoted. if not string.match(str, "^'.*'$") then return true @@ -253,7 +211,7 @@ function dtutils_string.is_not_sanitized_posix(str) end end -function dtutils_string.is_not_sanitized_windows(str) +local function _is_not_sanitized_windows(str) if not string.match(str, "^\".*\"$") then return true else @@ -263,9 +221,51 @@ end function dtutils_string.is_not_sanitized(str) if dt.configuration.running_os == "windows" then - return dtutils_string.is_not_sanitized_windows(str) + return _is_not_sanitized_windows(str) + else + return _is_not_sanitized_posix(str) + end +end + +dtutils_string.libdoc.functions["sanitize"] = { + Name = [[sanitize]], + Synopsis = [[surround a string in quotes making it safe to pass as an argument]], + Usage = [[local ds = require "lib/dtutils.string" + + local result = ds.sanitize(str) + str - string - the string that needs to be made safe]], + Description = [[sanitize converts a string into a version suitable for + use passing as an argument in a system command.]], + Return_Value = [[result - string - a websafe string]], + Limitations = [[]], + Example = [[]], + See_Also = [[]], + Reference = [[]], + License = [[]], + Copyright = [[]], +} + +local function _sanitize_posix(str) + if _is_not_sanitized_posix(str) then + return "'" .. string.gsub(str, "'", "'\\''") .. "'" + else + return str + end +end + +local function _sanitize_windows(str) + if _is_not_sanitized_windows(str) then + return "\"" .. string.gsub(str, "\"", "\"^\"\"") .. "\"" + else + return str + end +end + +function dtutils_string.sanitize(str) + if dt.configuration.running_os == "windows" then + return _sanitize_windows(str) else - return dtutils_string.is_not_sanitized_posix(str) + return _sanitize_posix(str) end end From 1eafae6c6f2b38be49b2e709d7a26a436046cff1 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Wed, 22 Jan 2020 13:15:14 -0500 Subject: [PATCH 005/445] Add check for WARNING lines complaining about files with no faces in the faces directory --- contrib/face_recognition.lua | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/contrib/face_recognition.lua b/contrib/face_recognition.lua index 45229b6a..8379f1b6 100644 --- a/contrib/face_recognition.lua +++ b/contrib/face_recognition.lua @@ -259,13 +259,15 @@ local function face_recognition () dt.print(_("processing results...")) local result = {} for line in io.lines(OUTPUT) do - local file, tag = string.match (line, "(.*),(.*)$") - tag = string.gsub (tag, "%d*$", "") - dt.print_log ("File:"..file .." Tag:".. tag) - if result[file] ~= nil then - table.insert (result[file], tag) - else - result[file] = {tag} + if not string.match(line, "^WARNING:") then + local file, tag = string.match (line, "(.*),(.*)$") + tag = string.gsub (tag, "%d*$", "") + dt.print_log ("File:"..file .." Tag:".. tag) + if result[file] ~= nil then + table.insert (result[file], tag) + else + result[file] = {tag} + end end end From 470811080443b2107d2034fa15790f65da909f5d Mon Sep 17 00:00:00 2001 From: Piter Dias Date: Thu, 23 Jan 2020 21:12:49 -0300 Subject: [PATCH 006/445] 1. Add "no persons found" entry for the situations that no persons are detected in the photos 2. Check if the tags to applied are non empty and skip otherwise. It applies to empty entries in the GUI ("unknown person tag" and "no persons found"), when the user types something and then deletes it 3. Change the string "togs of images to ignore" to "tags of images to ignore" --- contrib/face_recognition.lua | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/contrib/face_recognition.lua b/contrib/face_recognition.lua index 8379f1b6..526c0f95 100644 --- a/contrib/face_recognition.lua +++ b/contrib/face_recognition.lua @@ -78,6 +78,7 @@ if not dt.preferences.read(MODULE, "initialized", "bool") then dt.preferences.write(MODULE, "max_width", "integer", 1000) dt.preferences.write(MODULE, "max_height", "integer", 1000) dt.preferences.write(MODULE, "initialized", "bool", true) + dt.preferences.write(MODULE, "no_persons_found_tag", "string", "no_persons_found") end local function build_image_table(images) @@ -158,6 +159,7 @@ local function save_preferences() dt.preferences.write(MODULE, "max_width", "integer", tonumber(fc.width.text)) dt.preferences.write(MODULE, "max_height", "integer", tonumber(fc.height.text)) dt.preferences.write(MODULE, "num_cores", "integer", fc.num_cores.value) + dt.preferences.write(MODULE, "no_persons_found_tag", "string", fc.no_persons_found_tag.text) local val = fc.tolerance.value val = string.gsub(tostring(val), ",", ".") dt.preferences.write(MODULE, "tolerance", "float", tonumber(val)) @@ -205,6 +207,7 @@ local function face_recognition () local nrCores = dt.preferences.read(MODULE, "num_cores", "integer") local ignoreTagString = dt.preferences.read(MODULE, "ignore_tags", "string") local unknownTag = dt.preferences.read(MODULE, "unknown_tag", "string") + local nonpersonsfoundTag = dt.preferences.read(MODULE, "no_persons_found_tag", "string") -- face_recognition uses -1 for all cores, we use 0 in preferences if nrCores < 1 then @@ -285,10 +288,16 @@ local function face_recognition () if t == "unknown_person" then t = unknownTag end - dt.print_log ("ImgId:" .. img.id .. " Tag:".. t) - -- Create tag if it does not exists - local tag = dt.tags.create (t) - img:attach_tag (tag) + -- Check of unrecognized no_persons_found + if t == "no_persons_found" then + t = nonpersonsfoundTag + end + if t ~= "" and t ~= nil then + dt.print_log ("ImgId:" .. img.id .. " Tag:".. t) + -- Create tag if it does not exists + local tag = dt.tags.create (t) + img:attach_tag (tag) + end end end end @@ -316,6 +325,12 @@ fc.unknown_tag = dt.new_widget("entry"){ editable = true, } +fc.no_persons_found_tag = dt.new_widget("entry"){ + text = dt.preferences.read(MODULE, "no_persons_found_tag", "string"), + tooltip = _("tag to be used when no persons are found"), + editable = true, +} + fc.ignore_tags = dt.new_widget("entry"){ text = dt.preferences.read(MODULE, "ignore_tags", "string"), tooltip = _("tags of images to ignore"), @@ -388,7 +403,9 @@ fc.execute = dt.new_widget("button"){ local widgets = { dt.new_widget("label"){ label = _("unknown person tag")}, fc.unknown_tag, - dt.new_widget("label"){ label = _("togs of images to ignore")}, + dt.new_widget("label"){ label = _("no persons found tag")}, + fc.no_persons_found_tag, + dt.new_widget("label"){ label = _("tags of images to ignore")}, fc.ignore_tags, dt.new_widget("label"){ label = _("face data directory")}, fc.known_image_path, From e96b78b175a744d856802c4583f799655b7e0416 Mon Sep 17 00:00:00 2001 From: Piter Dias Date: Mon, 27 Jan 2020 17:44:49 -0300 Subject: [PATCH 007/445] Add reset callback to face recognition widget and show the default values in the GUI. --- contrib/face_recognition.lua | 41 +++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/contrib/face_recognition.lua b/contrib/face_recognition.lua index 526c0f95..fe1e9f6e 100644 --- a/contrib/face_recognition.lua +++ b/contrib/face_recognition.lua @@ -69,16 +69,9 @@ end -- preferences if not dt.preferences.read(MODULE, "initialized", "bool") then - dt.preferences.write(MODULE, "unknown_tag", "string", "unknown_person") - dt.preferences.write(MODULE, "ignore_tags", "string", "") - dt.preferences.write(MODULE, "tolerance", "float", 0.6) - dt.preferences.write(MODULE, "num_cores", "integer", 0) - dt.preferences.write(MODULE, "known_image_path", "directory", dt.configuration.config_dir .. "/face_recognition") - dt.preferences.write(MODULE, "export_format", "integer", 1) - dt.preferences.write(MODULE, "max_width", "integer", 1000) - dt.preferences.write(MODULE, "max_height", "integer", 1000) + reset_preferences() + save_preferences() dt.preferences.write(MODULE, "initialized", "bool", true) - dt.preferences.write(MODULE, "no_persons_found_tag", "string", "no_persons_found") end local function build_image_table(images) @@ -155,14 +148,29 @@ end local function save_preferences() dt.preferences.write(MODULE, "unknown_tag", "string", fc.unknown_tag.text) - dt.preferences.write(MODULE, "ignore_tags", "string", fc.ignore_tags.text) - dt.preferences.write(MODULE, "max_width", "integer", tonumber(fc.width.text)) - dt.preferences.write(MODULE, "max_height", "integer", tonumber(fc.height.text)) - dt.preferences.write(MODULE, "num_cores", "integer", fc.num_cores.value) dt.preferences.write(MODULE, "no_persons_found_tag", "string", fc.no_persons_found_tag.text) + dt.preferences.write(MODULE, "ignore_tags", "string", fc.ignore_tags.text) + dt.preferences.write(MODULE, "known_image_path", "directory", fc.known_image_path.value) local val = fc.tolerance.value val = string.gsub(tostring(val), ",", ".") dt.preferences.write(MODULE, "tolerance", "float", tonumber(val)) + dt.preferences.write(MODULE, "num_cores", "integer", fc.num_cores.value) + dt.preferences.write(MODULE, "export_format", "integer", fc.export_format.selected) + dt.preferences.write(MODULE, "max_width", "integer", tonumber(fc.width.text)) + dt.preferences.write(MODULE, "max_height", "integer", tonumber(fc.height.text)) +end + +local function reset_preferences() + fc.unknown_tag.text = "unknown_person" + fc.no_persons_found_tag.text = "no_persons_found" + fc.ignore_tags.text = "" + fc.known_image_path.value = dt.configuration.config_dir .. "/face_recognition" + fc.tolerance.value = 0.6 + fc.num_cores.value = -1 + fc.export_format.selected = 1 + fc.width.text = 1000 + fc.height.text = 1000 + save_preferences() end -- Check if image has ignored tag attached @@ -432,7 +440,10 @@ table.insert(widgets, fc.execute) fc.widget = dt.new_widget("box"){ orientation = vertical, - table.unpack(widgets) + reset_callback = function(this) + reset_preferences() + end, + table.unpack(widgets), } --fc.tolerance.value = dt.preferences.read(MODULE, "tolerance", "float") @@ -444,7 +455,7 @@ dt.register_lib( "face_recognition", -- Module name _("face recognition"), -- Visible name true, -- expandable - false, -- resetable + true, -- resetable {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 300}}, -- containers fc.widget, nil,-- view_enter From d32e0eb5ab7711570285ad3f00ddff87c97b4dac Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Tue, 28 Jan 2020 12:11:33 -0500 Subject: [PATCH 008/445] Removed include_all.lua since we now run cross platform and not all scripts run on all operating systems. --- include_all.lua | 61 ------------------------------------------------- 1 file changed, 61 deletions(-) delete mode 100644 include_all.lua diff --git a/include_all.lua b/include_all.lua deleted file mode 100644 index c25dd54d..00000000 --- a/include_all.lua +++ /dev/null @@ -1,61 +0,0 @@ ---[[ - This file is part of darktable, - copyright (c) 2014 Jérémy Rosen - copyright (c) 2018 Bill Ferguson - - darktable is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - darktable is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with darktable. If not, see . -]] ---[[ -INCLUDE ALL -Automatically include all scripts in the script repository - -This is intended for debugging purpose - - -USAGE -* require this file from your main lua config file: -* go to configuration => preferences -* Enable the scripts you want to use -* restart darktable - -Note that you need to restart DT for your changes to enabled scripts to take effect - -]] -local dt = require "darktable" -local io = require "io" - --- must be loaded for scripts using darktable.control_execute to work -require "official/yield" - -dt.configuration.check_version(...,{3,0,0},{4,0,0},{5,0,0}) - --- find all scripts, but skip the lib and tools directories -local output = io.popen("cd "..dt.configuration.config_dir.."/lua ;find . -name lib -prune -o -name tools -prune -o -name \\*.lua -print") - -local my_name={...} -my_name = my_name[1] -for line in output:lines() do - local req_name = line:sub(3,-5) - if req_name ~= my_name and not string.match(req_name, "yield") then - dt.preferences.register(my_name,req_name,"bool","enable "..req_name, - "Should the script "..req_name.." be enabled at next startup",false) - - if dt.preferences.read(my_name,req_name,"bool") then - require(req_name) - end - end -end - --- --- vim: shiftwidth=2 expandtab tabstop=2 cindent syntax=lua From 430f44391641c814104b7f2c75b29ec5c2ae1691 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Tue, 28 Jan 2020 14:14:47 -0500 Subject: [PATCH 009/445] Added Stefan Klinger's darktable lua scripts repository --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 75770267..8acac4b5 100644 --- a/README.md +++ b/README.md @@ -105,6 +105,7 @@ The following third-party projects are listed for information only. Think of thi * [johnnyrun/darktable_lua_gimp](https://github.com/johnnyrun/darktable_lua_gimp) – GIMP export * [arru/darktable-scripts](https://github.com/arru/darktable-scripts) * [nbremond77/darktable](https://github.com/nbremond77/darktable/tree/master/scripts) +* [s5k6/dtscripts](https://github.com/s5k6/dtscripts) ## Download and Install From e586e0479db920c94b73300e7e994d7df11ea4f9 Mon Sep 17 00:00:00 2001 From: "U-DESKTOP-HQME86J\\marco" Date: Fri, 7 Feb 2020 21:13:19 +0100 Subject: [PATCH 010/445] allow more that 9 editors --- contrib/ext_editor.lua | 626 ++++++++++++++++++++--------------------- 1 file changed, 307 insertions(+), 319 deletions(-) diff --git a/contrib/ext_editor.lua b/contrib/ext_editor.lua index b5e8eb23..29368000 100644 --- a/contrib/ext_editor.lua +++ b/contrib/ext_editor.lua @@ -1,64 +1,64 @@ --[[ - DESCRIPTION + DESCRIPTION ext_editor.lua - edit images with external editors This script provides helpers to edit image files with programs external to darktable. - It adds: - - a new target storage "collection". Image exported will be reimported to collection for - further edit with external programs - - a new lighttable module "external editors", to select a program from a list of up to - - 9 external editors and run it on a selected image - - a set of lua preferences in order to configure name and path of up to 9 external editors - - a set of lua shortcuts in order to quick launch the external editors - - USAGE + It adds: + - a new target storage "collection". Image exported will be reimported to collection for + further edit with external programs + - a new lighttable module "external editors", to select a program from a list of up to + - 9 external editors and run it on a selected image (adjust this limit by changing MAX_EDITORS) + - a set of lua preferences in order to configure name and path of up to 9 external editors + - a set of lua shortcuts in order to quick launch the external editors + + USAGE * require this script from main lua file - - -- setup -- - * in "preferences/lua options" configure name and path/command of external programs - * note that if a program name is left empty, that and all following entries will be ignored - * in "preferences/shortcuts/lua" configure shortcuts for external programs (optional) - * whenever programs preferences are changed, in lighttable/external editors, press "update list" - - -- use -- + + -- setup -- + * in "preferences/lua options" configure name and path/command of external programs + * note that if a program name is left empty, that and all following entries will be ignored + * in "preferences/shortcuts/lua" configure shortcuts for external programs (optional) + * whenever programs preferences are changed, in lighttable/external editors, press "update list" + + -- use -- * in the export dialog choose "collection" and select the format and bit depth for the exported image * press "export" - * the exported image will be imported into collection and grouped with the original image + * the exported image will be imported into collection and grouped with the original image - * select an image for editing with en external program, and: - * in lighttable/external editors, select program and press "edit" - * edit the image with the external editor, overwite the file, quit the external program - * the selected image will be updated - or - * in lighttable/external editors, select program and press "edit a copy" - * edit the image with the external editor, overwite the file, quit the external program - * a copy of the selected image will be created and updated - or - * in lighttable select target storage "collection" - * enter in darkroom - * to create an export or a copy press CRTL+E - * use the shortcut to edit the current image with the corresponding external editor - * overwite the file, quit the external program - * the darkroom view will be updated - - * warning: mouseover on lighttable/filmstrip will prevail on current image - * this is the default DT behavior, not a bug of this script + * select an image for editing with en external program, and: + * in lighttable/external editors, select program and press "edit" + * edit the image with the external editor, overwite the file, quit the external program + * the selected image will be updated + or + * in lighttable/external editors, select program and press "edit a copy" + * edit the image with the external editor, overwite the file, quit the external program + * a copy of the selected image will be created and updated + or + * in lighttable select target storage "collection" + * enter in darkroom + * to create an export or a copy press CRTL+E + * use the shortcut to edit the current image with the corresponding external editor + * overwite the file, quit the external program + * the darkroom view will be updated + + * warning: mouseover on lighttable/filmstrip will prevail on current image + * this is the default DT behavior, not a bug of this script CAVEATS - * MAC compatibility not tested - - TODO - * send multiple images to the same program, maybe - + * MAC compatibility not tested + + TODO + * send multiple images to the same program, maybe + BUGS, COMMENTS, SUGGESTIONS * send to Marco Carrarini, marco.carrarini@gmail.com CHANGES * 20191224 - initial version - * 20191227 - added button "update list", better error handling, fixed bug with groups/tags in "edit" - + * 20191227 - added button "update list", better error handling, fixed bug with groups/tags in "edit" + ]] @@ -85,343 +85,331 @@ local gettext = dt.gettext gettext.bindtextdomain(MODULE_NAME, dt.configuration.config_dir..PS.."lua"..PS.."locale"..PS) local function _(msgid) return gettext.dgettext(MODULE_NAME, msgid) -end + end +-- maximum number of external programs, can be increased to necessity +local MAX_EDITORS = 10 -- number of valid entries in the list of external programs local n_entries --- allowed file extensions, to exclude RAW, which cannot be edited externally -local allowed_file_types = {"JPG", "jpg", "JPEG", "jpeg", "TIF", "tif", "TIFF", "tiff", "EXR", "exr"} +-- allowed file extensions for external editors +local allowed_file_types = {"JPG", "jpg", "JPEG", "jpeg", "TIF", "tif", "TIFF", "tiff", "EXR", "exr", "PNG", "png"} -- last used editor initialization -if not dt.preferences.read(MODULE_NAME,"initialized", "bool") then - dt.preferences.write(MODULE_NAME,"lastchoice", "integer", 0) - dt.preferences.write(MODULE_NAME,"initialized", "bool", true) - end +if not dt.preferences.read(MODULE_NAME, "initialized", "bool") then + dt.preferences.write(MODULE_NAME, "lastchoice", "integer", 0) + dt.preferences.write(MODULE_NAME, "initialized", "bool", true) + end local lastchoice = 0 -- update lists of program names and paths, as well as combobox --------------- local function UpdateProgramList(combobox, button_edit, button_edit_copy, update_button_pressed) - -- initialize lists - program_names = {} - program_paths = {} - - -- build lists from preferences - local name - local last = false - n_entries = 0 - for i = 1, 9 do - name = dt.preferences.read(MODULE_NAME,"program_name_"..i, "string") - if (name == "" or name == nil) then last = true end - if last then - if combobox[n_entries + 1] then combobox[n_entries + 1] = nil end -- remove extra combobox entries - else - combobox[i] = i..": "..name - program_names[i] = name - program_paths[i] = df.sanitize_filename(dt.preferences.read(MODULE_NAME, "program_path_"..i, "string")) - n_entries = i - end - end - - lastchoice = dt.preferences.read(MODULE_NAME, "lastchoice", "integer") - if lastchoice == 0 and n_entries > 0 then lastchoice = 1 end - if lastchoice > n_entries then lastchoice = n_entries end - dt.preferences.write(MODULE_NAME, "lastchoice", "integer", lastchoice) - - -- widgets enabled if there is at least one program configured - combobox.selected = lastchoice - local active = n_entries > 0 + -- initialize lists + program_names = {} + program_paths = {} + + -- build lists from preferences + local name + local last = false + n_entries = 0 + for i = 1, MAX_EDITORS do + name = dt.preferences.read(MODULE_NAME, "program_name_"..i, "string") + if (name == "" or name == nil) then last = true end + if last then + if combobox[n_entries + 1] then combobox[n_entries + 1] = nil end -- remove extra combobox entries + else + combobox[i] = i..": "..name + program_names[i] = name + program_paths[i] = df.sanitize_filename(dt.preferences.read(MODULE_NAME, "program_path_"..i, "string")) + n_entries = i + end + end + + lastchoice = dt.preferences.read(MODULE_NAME, "lastchoice", "integer") + if lastchoice == 0 and n_entries > 0 then lastchoice = 1 end + if lastchoice > n_entries then lastchoice = n_entries end + dt.preferences.write(MODULE_NAME, "lastchoice", "integer", lastchoice) + + -- widgets enabled if there is at least one program configured + combobox.selected = lastchoice + local active = n_entries > 0 combobox.sensitive = active button_edit.sensitive = active button_edit_copy.sensitive = active - if update_button_pressed then dt.print(n_entries.._(" editors configured")) end - end - - --- shows export progress ------------------------------------------------------ -local function show_status(storage, image, format, filename, number, total, high_quality, extra_data) - - dt.print(_("exporting image ").. number.." / "..total.." ...") - end + if update_button_pressed then dt.print(n_entries.._(" editors configured")) end + end -- callback for buttons "edit" and "edit a copy" ------------------------------ local function OpenWith(images, choice, copy) - - -- check choice is valid, return if not - if choice > n_entries then - dt.print(_("not a valid choice")) - return - end - - -- check if one image is selected, return if not - if #images ~= 1 then - dt.print(_("please select one image")) - return - end - - local bin = program_paths[choice] - local friendly_name = program_names[choice] - - -- check if external program executable exists, return if not - if not df.check_if_bin_exists(bin) then - dt.print(friendly_name.._(" not found")) - return - end - - -- image to be edited - local image - i, image = next(images) - local name = image.path..PS..image.filename - - -- check if image is raw, return if it is - -- please note that the image property image.is_raw fails when filepath contains spaces - -- so as a workaround we allow only TIF, JPG and EXR - local file_ext = df.get_filetype (image.filename) - local allowed = false - for i,v in pairs(allowed_file_types) do - if v == file_ext then - allowed = true - break - end - end - if not allowed then - dt.print(_("file type not allowed")) - return - end - - -- save image tags, rating and color - local tags = {} + + -- check choice is valid, return if not + if choice > n_entries then + dt.print(_("not a valid choice")) + return + end + + -- check if one image is selected, return if not + if #images ~= 1 then + dt.print(_("please select one image")) + return + end + + local bin = program_paths[choice] + local friendly_name = program_names[choice] + + -- check if external program executable exists, return if not + if not df.check_if_bin_exists(bin) then + dt.print(friendly_name.._(" not found")) + return + end + + -- image to be edited + local image + i, image = next(images) + local name = image.path..PS..image.filename + + -- check if image format is allowed + local file_ext = df.get_filetype (image.filename) + local allowed = false + for i,v in pairs(allowed_file_types) do + if v == file_ext then + allowed = true + break + end + end + if not allowed then + dt.print(_("file type not allowed")) + return + end + + -- save image tags, rating and color + local tags = {} for i, tag in ipairs(dt.tags.get_tags(image)) do - if not (string.sub(tag.name, 1, 9) == "darktable") then table.insert(tags, tag) end - end - local rating = image.rating - local red = image.red - local blue = image.blue - local green = image.green - local yellow = image.yellow - local purple = image.purple - - -- new image - local new_name = name - local new_image = image + if not (string.sub(tag.name, 1, 9) == "darktable") then table.insert(tags, tag) end + end + local rating = image.rating + local red = image.red + local blue = image.blue + local green = image.green + local yellow = image.yellow + local purple = image.purple + + -- new image + local new_name = name + local new_image = image + + if copy then + + -- create unique filename + while df.check_if_file_exists(df.sanitize_filename(new_name)) do + new_name = df.filename_increment(new_name) + -- limit to 50 more exports of the original export + if string.match(df.get_basename(new_name), "_%d%d$") == "_50" then break end + end + + -- physical copy, check result, return if error + local copy_success = df.file_copy(name, new_name) + if not copy_success then + dt.print(_("error copying file ")..name) + return + end + end + + -- launch the external editor, check result, return if error + local run_cmd = bin.." "..df.sanitize_filename(new_name) + dt.print(_("launching ")..friendly_name.."...") + local result = dtsys.external_command(run_cmd) + if result ~= 0 then + dt.print(_("error launching ")..friendly_name) + return + end + + if copy then + -- import in database and group + new_image = dt.database.import(new_name) + new_image:group_with(image) + else + -- refresh the image view + -- note that only image:drop_cache() is not enough to refresh view in darkroom mode + -- therefore image must be deleted and reimported to force refresh + + -- find the grouping status + local image_leader = image.group_leader + local group_members = image:get_group_members() + local new_leader + local index = nil + local found = false - if copy then - - -- create unique filename - while true do -- dirty solution to workaround issue in lib function check_if_file_exists() - if dt.configuration.running_os == "windows" then - if not df.check_if_file_exists(df.sanitize_filename(new_name)) then break end - else - if not df.check_if_file_exists(new_name) then break end - end - new_name = df.filename_increment(new_name) - -- limit to 50 more exports of the original export - if string.match(df.get_basename(new_name), "_%d%d$") == "_50" then break end - end - - -- physical copy, check result, return if error - local copy_success = df.file_copy(name, new_name) - if not copy_success then - dt.print(_("error copying file ")..name) - return - end + -- membership status, three different cases + if image_leader == image then + if #group_members > 1 then + -- case 1: image is leader in a group with more members + while not found do + index, new_leader = next(group_members, index) + if new_leader ~= image_leader then found = true end + end + new_leader:make_group_leader() + image:delete() + if image.local_copy then image:drop_cache() end -- to fix fail to allocate cache error + new_image = dt.database.import(name) + new_image:group_with(new_leader) + new_image:make_group_leader() + else + -- case 2: image is the only member in group + image:delete() + if image.local_copy then image:drop_cache() end -- to fix fail to allocate cache error + new_image = dt.database.import(name) + new_image:group_with() end - - -- launch the external editor, check result, return if error - local run_cmd = bin.." "..df.sanitize_filename(new_name) - dt.print(_("launching ")..friendly_name.."...") - local result = dtsys.external_command(run_cmd) - if result ~= 0 then - dt.print(_("error launching ")..friendly_name) - return - end - - if copy then - -- import in database and group - new_image = dt.database.import(new_name) - new_image:group_with(image) else - -- refresh the image view - -- note that only image:drop_cache() is not enough to refresh view in darkroom mode - -- therefore image must be deleted and reimported to force refresh - - -- find the grouping status - local image_leader = image.group_leader - local group_members = image:get_group_members() - local new_leader - local index = nil - local found = false - - -- membership status, three different cases - if image_leader == image then - if #group_members > 1 then - -- case 1: image is leader in a group with more members - while not found do - index, new_leader = next(group_members, index) - if new_leader ~= image_leader then found = true end - end - new_leader:make_group_leader() - image:delete() - new_image = dt.database.import(name) - new_image:group_with(new_leader) - new_image:make_group_leader() - else - -- case 2: image is the only member in group - image:delete() - new_image = dt.database.import(name) - new_image:group_with() - end - else - -- case 3: image is in a group but is not leader - image:delete() - new_image = dt.database.import(name) - new_image:group_with(image_leader) - end - -- refresh darkroom view - if dt.gui.current_view() == dt.gui.views.darkroom then - dt.gui.views.darkroom.display_image(new_image) - end - end - - -- restore image tags, rating and color, must be put after refresh darkroom view - for i, tag in ipairs(tags) do dt.tags.attach(tag, new_image) end - new_image.rating = rating - new_image.red = red - new_image.blue = blue - new_image.green = green - new_image.yellow = yellow - new_image.purple = purple + -- case 3: image is in a group but is not leader + image:delete() + if image.local_copy then image:drop_cache() end -- to fix fail to allocate cache error + new_image = dt.database.import(name) + new_image:group_with(image_leader) + end + -- refresh darkroom view + if dt.gui.current_view() == dt.gui.views.darkroom then + dt.gui.views.darkroom.display_image(new_image) + end + end + + -- restore image tags, rating and color, must be put after refresh darkroom view + for i, tag in ipairs(tags) do dt.tags.attach(tag, new_image) end + new_image.rating = rating + new_image.red = red + new_image.blue = blue + new_image.green = green + new_image.yellow = yellow + new_image.purple = purple -- select the new image - local selection = {} - table.insert(selection, new_image) - dt.gui.selection (selection) + local selection = {} + table.insert(selection, new_image) + dt.gui.selection (selection) - end + end -- callback function for shortcuts -------------------------------------------- local function program_shortcut(event, shortcut) - OpenWith(dt.gui.action_images, tonumber(string.sub(shortcut, -1)), false) - end + OpenWith(dt.gui.action_images, tonumber(string.sub(shortcut, -2)), false) + end -- export images and reimport in collection ----------------------------------- local function export2collection(storage, image_table, extra_data) - local new_name, new_image, result + local new_name, new_image, result - for image, temp_name in pairs(image_table) do + for image, temp_name in pairs(image_table) do - -- images are first exported in temp folder then moved to collection folder + -- images are first exported in temp folder then moved to collection folder - -- create unique filename - new_name = image.path..PS..df.get_filename(temp_name) - while true do -- dirty solution to workaround issue in lib function check_if_file_exists() - if dt.configuration.running_os == "windows" then - if not df.check_if_file_exists(df.sanitize_filename(new_name)) then break end - else - if not df.check_if_file_exists(new_name) then break end - end - new_name = df.filename_increment(new_name) - -- limit to 50 more exports of the original export - if string.match(df.get_basename(new_name), "_%d%d$") == "_50" then break end - end + -- create unique filename + new_name = image.path..PS..df.get_filename(temp_name) + while df.check_if_file_exists(df.sanitize_filename(new_name)) do + new_name = df.filename_increment(new_name) + -- limit to 50 more exports of the original export + if string.match(df.get_basename(new_name), "_%d%d$") == "_50" then break end + end - -- move image to collection folder, check result, return if error - move_success = df.file_move(temp_name, new_name) - if not move_success then - dt.print(_("error moving file ")..temp_name) - return - end + -- move image to collection folder, check result, return if error + move_success = df.file_move(temp_name, new_name) + if not move_success then + dt.print(_("error moving file ")..temp_name) + return + end - -- import in database and group - new_image = dt.database.import(new_name) - new_image:group_with(image.group_leader) - end - end + -- import in database and group + new_image = dt.database.import(new_name) + new_image:group_with(image.group_leader) + end + + dt.print (_("finished exporting")) + end -- register new storage ------------------------------------------------------- -- note that placing this declaration later makes the export selected module -- not to remember the choice "collection" when restarting DT, don't know why -dt.register_storage("exp2coll", _("collection"), show_status, export2collection) +dt.register_storage("exp2coll", _("collection"), null, export2collection) -- combobox, with variable number of entries ---------------------------------- local combobox = dt.new_widget("combobox") { - label = _("choose program"), - tooltip = _("select the external editor from the list"), - changed_callback = function(self) - dt.preferences.write(MODULE_NAME, "lastchoice", "integer", self.selected) - end, - "" - } + label = _("choose program"), + tooltip = _("select the external editor from the list"), + changed_callback = function(self) + dt.preferences.write(MODULE_NAME, "lastchoice", "integer", self.selected) + end, + "" + } -- button edit ---------------------------------------------------------------- local button_edit = dt.new_widget("button") { - label = _("edit"), - tooltip = _("open the selected image in external editor"), - --sensitive = false, - clicked_callback = function() - OpenWith(dt.gui.action_images, combobox.selected, false) - end - } + label = _("edit"), + tooltip = _("open the selected image in external editor"), + --sensitive = false, + clicked_callback = function() + OpenWith(dt.gui.action_images, combobox.selected, false) + end + } -- button edit a copy --------------------------------------------------------- local button_edit_copy = dt.new_widget("button") { - label = _("edit a copy"), - tooltip = _("create a copy of the selected image and open it in external editor"), - clicked_callback = function() - OpenWith(dt.gui.action_images, combobox.selected, true) - end - } + label = _("edit a copy"), + tooltip = _("create a copy of the selected image and open it in external editor"), + clicked_callback = function() + OpenWith(dt.gui.action_images, combobox.selected, true) + end + } -- button update list --------------------------------------------------------- local button_update_list = dt.new_widget("button") { - label = _("update list"), - tooltip = _("update list of programs if lua preferences are changed"), - clicked_callback = function() - UpdateProgramList(combobox, button_edit, button_edit_copy, true) - end - } + label = _("update list"), + tooltip = _("update list of programs if lua preferences are changed"), + clicked_callback = function() + UpdateProgramList(combobox, button_edit, button_edit_copy, true) + end + } -- box for the buttons -------------------------------------------------------- -- it doesn't seem there is a way to make the buttons equal in size local box1 = dt.new_widget("box") { orientation = "horizontal", - button_edit, - button_edit_copy, - button_update_list - } + button_edit, + button_edit_copy, + button_update_list + } -- register new module "external editors" in lighttable ------------------------ dt.register_lib( - MODULE_NAME, - _("external editors"), - true, -- expandable - false, -- resetable - {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, - dt.new_widget("box") { - orientation = "vertical", - combobox, - box1 - }, - nil, -- view_enter - nil -- view_leave - ) + MODULE_NAME, + _("external editors"), + true, -- expandable + false, -- resetable + {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, + dt.new_widget("box") { + orientation = "vertical", + combobox, + box1 + }, + nil, -- view_enter + nil -- view_leave + ) -- initialize list of programs and widgets ------------------------------------ @@ -429,23 +417,23 @@ UpdateProgramList(combobox, button_edit, button_edit_copy, false) -- register the new preferences ----------------------------------------------- -for i = 9, 1, -1 do - dt.preferences.register(MODULE_NAME, "program_path_"..i, "file", - _("executable for external editor ")..i, - _("select executable for external editor") , _("(None)")) - dt.preferences.register(MODULE_NAME, "program_name_"..i, "string", - _("name of external editor ")..i, - _("friendly name of external editor"), "") - end +for i = MAX_EDITORS, 1, -1 do + dt.preferences.register(MODULE_NAME, "program_path_"..i, "file", + _("executable for external editor ")..i, + _("select executable for external editor") , _("(None)")) + dt.preferences.register(MODULE_NAME, "program_name_"..i, "string", + _("name of external editor ")..i, + _("friendly name of external editor"), "") + end --- register the new shortcuts ------------------------------------------------- -for i = 1, 9 do - dt.register_event("shortcut", program_shortcut, _("edit with program ")..i) - end +-- register the new shortcuts ------------------------------------------------- +for i = 1, MAX_EDITORS do + dt.register_event("shortcut", program_shortcut, _("edit with program ")..string.format("%02d", i)) + end -- end of script -------------------------------------------------------------- --- vim: shiftwidth=4 expandtab tabstop=4 cindent syntax=lua +-- vim: shiftwidth=2 expandtab tabstop=2 cindent syntax=lua -- kate: hl Lua; From e97f2f3fc61b0852db6c428d58db8be9e2e56208 Mon Sep 17 00:00:00 2001 From: "jefffermo@gmail.com" Date: Thu, 27 Feb 2020 13:26:37 +0800 Subject: [PATCH 011/445] * make enfuse output file unique(fairly) * add option --blend-colorspace of situation like this https://monochrome.sutic.nu/2019/06/18/enblend-4.2-color-space-blending-bug.html --- official/enfuse.lua | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/official/enfuse.lua b/official/enfuse.lua index 935f3405..3b5bb7c2 100644 --- a/official/enfuse.lua +++ b/official/enfuse.lua @@ -114,6 +114,14 @@ if enfuse_installed then "8", "16", "32" } + local blend_colorspace = dt.new_widget("combobox") + { + label = "blend colorspace", + tooltip = "Force blending in selected colorspace", + changed_callback = function(w) dt.preferences.write("enfuse", "blend_colorspace", "string", w.selected) end, + "", "identity", "ciecam" + } + local enfuse_button = dt.new_widget("button") { label = enfuse_installed and "run enfuse" or "enfuse not installed", @@ -186,13 +194,18 @@ if enfuse_installed then -- call enfuse on the response file -- TODO: find something nicer local ugly_decimal_point_hack = string.gsub(string.format("%.04f", mu), ",", ".") - -- TODO: make filename unique - local output_image = target_dir.. PS .. "enfuse.tif" + local output_image_date = os.date("%Y%m%d%H%M%S") + local output_image = target_dir.. PS .. "enfuse-"..output_image_date..".tif" local exposure_option = " --exposure-optimum " + local blend_colorspace_option = "" + if #blend_colorspace.value > 1 then + blend_colorspace_option = " --blend-colorspace="..blend_colorspace.value + end if version < "4.2" then exposure_option = " --exposure-mu " end local command = enfuse_installed.." --depth "..depth.value..exposure_option..ugly_decimal_point_hack + ..blend_colorspace_option .." -o \""..output_image.."\" \"@"..response_file.."\"" if dtsys.external_command( command) > 0 then dt.print(_("Enfuse failed, see terminal output for details")) @@ -220,6 +233,7 @@ if enfuse_installed then end table.insert(lib_widgets, exposure_mu) table.insert(lib_widgets, depth) + table.insert(lib_widgets, blend_colorspace) table.insert(lib_widgets, enfuse_button) From 635ea3f23117c3288bafe1138d67eb1845cde48c Mon Sep 17 00:00:00 2001 From: "U-DESKTOP-HQME86J\\marco" Date: Sat, 7 Mar 2020 08:57:03 +0100 Subject: [PATCH 012/445] fix #229 --- lib/dtutils/file.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/dtutils/file.lua b/lib/dtutils/file.lua index 1d9fa5bc..9fa2c269 100644 --- a/lib/dtutils/file.lua +++ b/lib/dtutils/file.lua @@ -230,7 +230,7 @@ function dtutils_file.check_if_file_exists(filepath) local result = false if (dt.configuration.running_os == 'windows') then filepath = string.gsub(filepath, '[\\/]+', '\\') - local p = io.popen("if exist " .. filepath .. " (echo 'yes') else (echo 'no')") + local p = io.popen("if exist " .. dtutils_file.sanitize_filename(filepath) .. " (echo 'yes') else (echo 'no')") local ans = p:read("*all") p:close() if string.match(ans, "yes") then From 3b6dd856aa473850c4a6b38c689f6e472e107edc Mon Sep 17 00:00:00 2001 From: "U-DESKTOP-HQME86J\\marco" Date: Tue, 10 Mar 2020 12:54:53 +0100 Subject: [PATCH 013/445] Add RL output sharpening script --- README.md | 1 + contrib/RL_out_sharp.lua | 208 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 209 insertions(+) create mode 100644 contrib/RL_out_sharp.lua diff --git a/README.md b/README.md index 8acac4b5..6c2bc003 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,7 @@ pdf_slideshow|No|LM|Export images to a PDF slideshow quicktag|Yes|LMW|Create shortcuts for quickly applying tags rate_group|Yes|LMW|Apply or remove a star rating from grouped images rename-tags|Yes|LMW|Change a tag name +RL_out_sharp|No|LW|Output sharpening using GMic (Richardson-Lucy algorithm) select_untagged|Yes|LMW|Enable selection of untagged images slideshowMusic|No|L|Play music during a slideshow video_ffmpeg|No|LMW|Export video from darktable diff --git a/contrib/RL_out_sharp.lua b/contrib/RL_out_sharp.lua new file mode 100644 index 00000000..5fe30e92 --- /dev/null +++ b/contrib/RL_out_sharp.lua @@ -0,0 +1,208 @@ +--[[ + + DESCRIPTION + RL_out_sharp.lua - Richardson-Lucy output sharpening using GMic + + This script provides a new target storage "RL output sharpen". + Images exported will be sharpened using GMic (RL deblur algorithm) + + USAGE + * require this script from main lua file + * in lua preferences, select the GMic cli executable + * from "export selected", choose "RL output sharpen" + * configure output folder + * configure RL parameters with sliders + * configure temp files format and quality, jpg 8bpp (good quality) + and tif 16bpp (best quality) are supported + * configure other export options (size, etc.) + * export, images will be first exported in the temp format, then sharpened + * sharpened images will be stored in jpg format in the output folder + + EXAMPLE + set sigma = 0.7, iterations = 10, jpeg output quality = 95, + that will be sufficient for most uses + + CAVEATS + MAC compatibility not tested + + BUGS, COMMENTS, SUGGESTIONS + send to Marco Carrarini, marco.carrarini@gmail.com + + CHANGES + * 20200308 - initial version + +]] + +local dt = require "darktable" +local du = require "lib/dtutils" +local df = require "lib/dtutils.file" +local dtsys = require "lib/dtutils.system" + +-- module name +local MODULE_NAME = "RL_out_sharp" + +-- check API version +du.check_min_api_version("5.0.2", MODULE_NAME) -- darktable 3.x + +-- OS compatibility +local PS = dt.configuration.running_os == "windows" and "\\" or "/" + +-- translation +local gettext = dt.gettext +gettext.bindtextdomain(MODULE_NAME, dt.configuration.config_dir..PS.."lua"..PS.."locale"..PS) +local function _(msgid) + return gettext.dgettext(MODULE_NAME, msgid) + end + +-- initialize module preferences +if not dt.preferences.read(MODULE_NAME, "initialized", "bool") then + dt.preferences.write(MODULE_NAME, "sigma", "string", "0.7") + dt.preferences.write(MODULE_NAME, "iterations", "string", "10") + dt.preferences.write(MODULE_NAME, "jpg_quality", "string", "95") + dt.preferences.write(MODULE_NAME, "initialized", "bool", true) + end + + +-- setup export --------------------------------------------------------------- +local function setup_export(storage, img_format, image_table, high_quality, extra_data) + -- set 16bpp if format is tif + if img_format.extension == "tif" then + img_format.bpp = 16 + end + end + + +-- temp export formats: jpg and tif are supported ----------------------------- +local function supported(storage, img_format) + return (img_format.extension == "jpg") or (img_format.extension == "tif") + end + + +-- export and sharpen images -------------------------------------------------- +local function export2RL(storage, image_table, extra_data) + + local temp_name, new_name, run_cmd, result + local input_file, output_file, options + + -- read parameters + local gmic = df.sanitize_filename(dt.preferences.read(MODULE_NAME, "gmic_exe", "string")) + local output_folder = output_folder_selector.value + local sigma_str = string.gsub(string.format("%.2f", sigma_slider.value), ",", ".") + local iterations_str = string.format("%.0f", iterations_slider.value) + local jpg_quality_str = string.format("%.0f", jpg_quality_slider.value) + + -- save preferences + dt.preferences.write(MODULE_NAME, "sigma", "string", sigma_str) + dt.preferences.write(MODULE_NAME, "iterations", "string", iterations_str) + dt.preferences.write(MODULE_NAME, "jpg_quality", "string", jpg_quality_str) + + local gmic_operation = " -deblur_richardsonlucy "..sigma_str..","..iterations_str..",1" + + local i = 0 + for image, temp_name in pairs(image_table) do + + i = i + 1 + dt.print(_("sharpening image ")..i.." ...") + -- create unique filename + new_name = output_folder..PS..df.get_basename(temp_name)..".jpg" + while df.check_if_file_exists(new_name) do + new_name = df.filename_increment(new_name) + -- limit to 50 more exports of the original export + if string.match(df.get_basename(new_name), "_%d%d$") == "_50" then break end + end + + -- build the GMic command string + input_file = df.sanitize_filename(temp_name) + output_file = df.sanitize_filename(new_name) + options = " cut 0,255 round " + if df.get_filetype(temp_name) == "tif" then options = " -/ 256"..options end + + run_cmd = gmic.." "..input_file..gmic_operation..options.."o "..output_file..","..jpg_quality_str + + result = dtsys.external_command(run_cmd) + if result ~= 0 then + dt.print(_("sharpening error")) + return + end + + -- delete temp image + os.remove(temp_name) + + end + + dt.print(_("finished exporting")) + end + +-- new widgets ---------------------------------------------------------------- + +output_folder_selector = dt.new_widget("file_chooser_button"){ + title = _("select output folder"), + tooltip = _("select output folder"), + value = dt.preferences.read(MODULE_NAME, "output_folder", "string"), + is_directory = true, + changed_callback = function(self) + dt.preferences.write(MODULE_NAME, "output_folder", "string", self.value) + end + } + +sigma_slider = dt.new_widget("slider"){ + label = _("sigma"), + tooltip = _("sigma parameter in RL algorithm"), + soft_min = 0.3, + soft_max = 1.0, + hard_min = 0.0, + hard_max = 3.0, + step = 0.05, + digits = 2, + value = 0.7 + } + +iterations_slider = dt.new_widget("slider"){ + label = _("iterations"), + tooltip = _("increase for better sharpening, but slower"), + soft_min = 0, + soft_max = 100, + hard_min = 0, + hard_max = 100, + step = 5, + digits = 0, + value = 10.0 + } + +jpg_quality_slider = dt.new_widget("slider"){ + label = _("output jpg quality"), + tooltip = _("quality of the output jpg file"), + soft_min = 70, + soft_max = 100, + hard_min = 70, + hard_max = 100, + step = 2, + digits = 0, + value = 95.0 + } + +local storage_widget = dt.new_widget("box"){ + orientation = "vertical", + output_folder_selector, + sigma_slider, + iterations_slider, + jpg_quality_slider + } + +-- register new storage ------------------------------------------------------- +dt.register_storage("exp2RL", _("RL output sharpen"), nil, export2RL, supported, save_preferences, storage_widget) + +-- register the new preferences ----------------------------------------------- +dt.preferences.register(MODULE_NAME, "gmic_exe", "file", +_("executable for GMic CLI"), +_("select executable for GMic command line version") , _("(None)")) + +-- set sliders to the last used value ----------------------------------------- +sigma_slider.value = dt.preferences.read(MODULE_NAME, "sigma", "float") +iterations_slider.value = dt.preferences.read(MODULE_NAME, "iterations", "float") +jpg_quality_slider.value = dt.preferences.read(MODULE_NAME, "jpg_quality", "float") + +-- end of script -------------------------------------------------------------- + +-- vim: shiftwidth=2 expandtab tabstop=2 cindent syntax=lua +-- kate: hl Lua; From 3e1746fc6e36c38f13c994e421666ca27bdcde8f Mon Sep 17 00:00:00 2001 From: "U-DESKTOP-HQME86J\\marco" Date: Tue, 10 Mar 2020 20:34:13 +0100 Subject: [PATCH 014/445] changed min API version --- contrib/RL_out_sharp.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/RL_out_sharp.lua b/contrib/RL_out_sharp.lua index 5fe30e92..e119fdbd 100644 --- a/contrib/RL_out_sharp.lua +++ b/contrib/RL_out_sharp.lua @@ -42,7 +42,7 @@ local dtsys = require "lib/dtutils.system" local MODULE_NAME = "RL_out_sharp" -- check API version -du.check_min_api_version("5.0.2", MODULE_NAME) -- darktable 3.x +du.check_min_api_version("5.0.0", MODULE_NAME) -- darktable 3.x -- OS compatibility local PS = dt.configuration.running_os == "windows" and "\\" or "/" From 4065bd5e11c97a68a98bf0e5b33b5b6ebf52165c Mon Sep 17 00:00:00 2001 From: "U-DESKTOP-HQME86J\\marco" Date: Tue, 10 Mar 2020 21:21:41 +0100 Subject: [PATCH 015/445] test for GMIc executable --- contrib/RL_out_sharp.lua | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/contrib/RL_out_sharp.lua b/contrib/RL_out_sharp.lua index e119fdbd..9168cc74 100644 --- a/contrib/RL_out_sharp.lua +++ b/contrib/RL_out_sharp.lua @@ -42,7 +42,7 @@ local dtsys = require "lib/dtutils.system" local MODULE_NAME = "RL_out_sharp" -- check API version -du.check_min_api_version("5.0.0", MODULE_NAME) -- darktable 3.x +du.check_min_api_version("5.0.0", MODULE_NAME) -- OS compatibility local PS = dt.configuration.running_os == "windows" and "\\" or "/" @@ -85,7 +85,12 @@ local function export2RL(storage, image_table, extra_data) local input_file, output_file, options -- read parameters - local gmic = df.sanitize_filename(dt.preferences.read(MODULE_NAME, "gmic_exe", "string")) + local gmic = dt.preferences.read(MODULE_NAME, "gmic_exe", "string") + if gmic == "" then + dt.print (_("GMic executable not configured")) + return + end + gmic = df.sanitize_filename(gmic) local output_folder = output_folder_selector.value local sigma_str = string.gsub(string.format("%.2f", sigma_slider.value), ",", ".") local iterations_str = string.format("%.0f", iterations_slider.value) @@ -195,7 +200,7 @@ dt.register_storage("exp2RL", _("RL output sharpen"), nil, export2RL, supported, -- register the new preferences ----------------------------------------------- dt.preferences.register(MODULE_NAME, "gmic_exe", "file", _("executable for GMic CLI"), -_("select executable for GMic command line version") , _("(None)")) +_("select executable for GMic command line version") , "") -- set sliders to the last used value ----------------------------------------- sigma_slider.value = dt.preferences.read(MODULE_NAME, "sigma", "float") From 51f28a386b0660e28640849315076b64e0ec55a0 Mon Sep 17 00:00:00 2001 From: "U-DESKTOP-HQME86J\\marco" Date: Wed, 11 Mar 2020 16:53:55 +0100 Subject: [PATCH 016/445] requested modifications --- contrib/RL_out_sharp.lua | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/contrib/RL_out_sharp.lua b/contrib/RL_out_sharp.lua index 9168cc74..b5d0fe9f 100644 --- a/contrib/RL_out_sharp.lua +++ b/contrib/RL_out_sharp.lua @@ -24,6 +24,9 @@ CAVEATS MAC compatibility not tested + Although Darktable can handle file names containing spaces, GMic cli cannot, + so if you want to use this script please make sure that your images do not + have spaces in the file name and path BUGS, COMMENTS, SUGGESTIONS send to Marco Carrarini, marco.carrarini@gmail.com @@ -87,7 +90,7 @@ local function export2RL(storage, image_table, extra_data) -- read parameters local gmic = dt.preferences.read(MODULE_NAME, "gmic_exe", "string") if gmic == "" then - dt.print (_("GMic executable not configured")) + dt.print(_("GMic executable not configured")) return end gmic = df.sanitize_filename(gmic) @@ -110,11 +113,7 @@ local function export2RL(storage, image_table, extra_data) dt.print(_("sharpening image ")..i.." ...") -- create unique filename new_name = output_folder..PS..df.get_basename(temp_name)..".jpg" - while df.check_if_file_exists(new_name) do - new_name = df.filename_increment(new_name) - -- limit to 50 more exports of the original export - if string.match(df.get_basename(new_name), "_%d%d$") == "_50" then break end - end + new_name = df.create_unique_filename(new_name) -- build the GMic command string input_file = df.sanitize_filename(temp_name) @@ -152,7 +151,7 @@ output_folder_selector = dt.new_widget("file_chooser_button"){ sigma_slider = dt.new_widget("slider"){ label = _("sigma"), - tooltip = _("sigma parameter in RL algorithm"), + tooltip = _("controls the width of the blur that's applied"), soft_min = 0.3, soft_max = 1.0, hard_min = 0.0, @@ -202,7 +201,7 @@ dt.preferences.register(MODULE_NAME, "gmic_exe", "file", _("executable for GMic CLI"), _("select executable for GMic command line version") , "") --- set sliders to the last used value ----------------------------------------- +-- set sliders to the last used value at startup ------------------------------ sigma_slider.value = dt.preferences.read(MODULE_NAME, "sigma", "float") iterations_slider.value = dt.preferences.read(MODULE_NAME, "iterations", "float") jpg_quality_slider.value = dt.preferences.read(MODULE_NAME, "jpg_quality", "float") From 093593dcef9e4f6fd6a453f46e3e15744363ca16 Mon Sep 17 00:00:00 2001 From: August Schwerdfeger Date: Fri, 13 Mar 2020 23:49:24 -0500 Subject: [PATCH 017/445] New script: 'transfer_hierarchy'. --- README.md | 1 + contrib/transfer_hierarchy.lua | 347 +++++++++++++++++++++++++++++++++ 2 files changed, 348 insertions(+) create mode 100755 contrib/transfer_hierarchy.lua diff --git a/README.md b/README.md index 8acac4b5..f33628b7 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,7 @@ rate_group|Yes|LMW|Apply or remove a star rating from grouped images rename-tags|Yes|LMW|Change a tag name select_untagged|Yes|LMW|Enable selection of untagged images slideshowMusic|No|L|Play music during a slideshow +transfer_hierarchy|Yes|LMW|Image move/copy preserving directory hierarchy video_ffmpeg|No|LMW|Export video from darktable ### Example Scripts diff --git a/contrib/transfer_hierarchy.lua b/contrib/transfer_hierarchy.lua new file mode 100755 index 00000000..382bc2cf --- /dev/null +++ b/contrib/transfer_hierarchy.lua @@ -0,0 +1,347 @@ +--[[ + TRANSFER HIERARCHY + Allows the moving or copying of images from one directory + tree to another, while preserving the existing hierarchy. + + AUTHOR + August Schwerdfeger (august@schwerdfeger.name) + + ADDITIONAL SOFTWARE NEEDED FOR THIS SCRIPT + None. + + USAGE + darktable's native operations for moving and copying images in + batches allow only one directory to be specified as the destination + for each batch. Those wanting to move or copy images from a _hierarchy_ + of directories within darktable while preserving the directory structure, + must take the laborious step of performing the operation one individual + directory at a time. + + This module allows the intact moving and copying of whole directory trees. + It was designed for the specific use case of rapidly transferring images + from a customary source (e.g., a staging directory on the local disk) + to a customary destination (e.g., a directory on a NAS device). + + Instructions for operation: + + 1. Select the set of images you want to copy. + + 2. Click the "calculate" button. This will calculate the + lowest directory in the hierarchy that contains every selected + file (i.e., the common prefix of all the images' pathnames), and + write its path into the "existing root" text box. + + 3. If (a) you have specified the "customary source root" and "customary + destination root" preferences, and (b) the selected images are all + contained under the directory specified as the customary source + root, then the "root of destination" text box will also be + automatically filled out. + + For example, suppose that you have specified '/home/user/Staging' + as your customary source root and '/mnt/storage' as your customary + destination root. If all selected images fell under the directory + '/home/user/Staging/2020/Roll0001', the "root of destination" would + be automatically filled out with '/mnt/storage/2020/Roll0001'. + + But if all selected images fall under a directory outside the + specified customary source root (e.g., '/opt/other'), the "root + of destination" text box must be filled out manually. + + It is also possible to edit the "root of destination" further once + it has been automatically filled out. + + 4. Click the "move" or "copy" button. + + Before moving or copying any images, the module will first + replicate the necessary directory hierarchy by creating all + destination directories that do not already exist; should a + directory creation attempt fail, the operation will be + aborted, but any directories already created will not be + removed. + + During the actual move/copy operation, the module transfers an + image by taking its path and replacing the string in the "existing + root" text box with that in the "root of destination" text box + (e.g., '/home/user/Staging/2020/Roll0001/DSC_0001.jpg' would be + transferred to '/mnt/storage/2020/Roll0001/DSC_0001.jpg'). + + LICENSE + LGPLv2+ +]] + + +-- Header material: BEGIN + +local darktable = require("darktable") +local dtutils = require("lib/dtutils") +local dtutils_file = require("lib/dtutils.file") +local dtutils_system = require("lib/dtutils.system") + +local LIB_ID = "transfer_hierarchy" +dtutils.check_min_api_version("5.0.0", LIB_ID) + +local MKDIR_COMMAND = darktable.configuration.running_os == "windows" and "mkdir " or "mkdir -p " +local PATH_SEPARATOR = darktable.configuration.running_os == "windows" and "\\\\" or "/" +local PATH_SEGMENT_REGEX = "(" .. PATH_SEPARATOR .. "?)([^" .. PATH_SEPARATOR .. "]+)" + +unpack = unpack or table.unpack +gmatch = string.gfind or string.gmatch + +-- Header material: END + + + +-- Helper functions: BEGIN + +local function pathExists(path) + local success, err, errno = os.rename(path, path) + if not success then + if errno == 13 then + return true + end + end + return success, err +end + +local function pathIsDirectory(path) + return pathExists(path..PATH_SEPARATOR) +end + +local function createDirectory(path) + local errorlevel = dtutils_system.external_command(MKDIR_COMMAND .. dtutils_file.sanitize_filename(path)) + if errorlevel == 0 and pathIsDirectory(path) then + return path + else + return nil + end +end + +-- Helper functions: END + + +-- Widgets and business logic: BEGIN + +local sourceTextBox = darktable.new_widget("entry") { + tooltip = "Lowest directory containing all selected images", + editable = false + } +sourceTextBox.reset_callback = function() sourceTextBox.text = "" end + +local destinationTextBox = darktable.new_widget("entry") { + text = "" +} +destinationTextBox.reset_callback = function() destinationTextBox.text = "" end + + + + + + + + + +local function findRootPath(films) + local commonSegments = nil + local prefix = "" + for film, _ in pairs(films) do + local path = film.path + if commonSegments == nil then + commonSegments = {} + local firstMatchIndex = string.find(path, PATH_SEGMENT_REGEX) + if firstMatchIndex ~= nil then + prefix = string.sub(path, 1, firstMatchIndex-1) + end + string.gsub(path, PATH_SEGMENT_REGEX, function(w, x) + if w ~= "" then table.insert(commonSegments, w) end + table.insert(commonSegments, x) + end) + else + local matcher = gmatch(path, PATH_SEGMENT_REGEX) + local i = 1 + while i < #commonSegments do + match, match2 = matcher() + if match == nil then + while i <= #commonSegments do + table.remove(commonSegments, #commonSegments) + end + break + elseif match ~= "" then + if commonSegments[i] ~= match then + while i <= #commonSegments do + table.remove(commonSegments, #commonSegments) + end + break + else + i = i+1 + end + end + if match2 == nil or commonSegments[i] ~= match2 then + while i <= #commonSegments do + table.remove(commonSegments, #commonSegments) + end + break + else + i = i+1 + end + end + end + end + if commonSegments == nil then + return prefix + end + if commonSegments[#commonSegments] == PATH_SEPARATOR then + table.remove(commonSegments, #commonSegments) + end + rv = prefix .. table.concat(commonSegments) + return rv +end + +local function calculateRoot() + films = {} + for _,img in ipairs(darktable.gui.action_images) do + films[img.film] = true + end + return findRootPath(films), films +end + +local function doCalculate() + local rootPath = calculateRoot() + if rootPath ~= nil then + sourceTextBox.text = rootPath + local sourceBase = darktable.preferences.read(LIB_ID, "source_base", "directory") + local destBase = darktable.preferences.read(LIB_ID, "destination_base", "directory") + if sourceBase ~= nil and sourceBase ~= "" and + destBase ~= nil and destBase ~= "" and + string.sub(rootPath, 1, #sourceBase) == sourceBase then + destinationTextBox.text = destBase .. string.sub(rootPath, #sourceBase+1) + end + end +end + +local function stopTransfer(transferJob) + job.valid = false +end + +local function doTransfer(transferFunc) + rootPath, films = calculateRoot() + if rootPath ~= sourceTextBox.text then + darktable.print("transfer hierarchy: ERROR: existing root is out of sync -- click 'calculate' to update") + return + end + if destinationTextBox.text == "" then + darktable.print("transfer hierarchy: ERROR: destination not specified") + return + end + local sourceBase = sourceTextBox.text + local destBase = destinationTextBox.text + local destFilms = {} + for film, _ in pairs(films) do + films[film] = destBase .. string.sub(film.path, #sourceBase+1) + if not pathExists(films[film]) then + if createDirectory(films[film]) == nil then + darktable.print("transfer hierarchy: ERROR: could not create directory: " .. films[film]) + return + end + end + if not pathIsDirectory(films[film]) then + darktable.print("transfer hierarchy: ERROR: not a directory: " .. films[film]) + return + end + destFilms[film] = darktable.films.new(films[film]) + if destFilms[film] == nil then + darktable.print("transfer hierarchy: ERROR: could not create film: " .. film.path) + end + end + + local job = darktable.gui.create_job(string.format("transfer hierarchy (%d image" .. (#(darktable.gui.action_images) == 1 and "" or "s") .. ")", #(darktable.gui.action_images)), true, stopTransfer) + job.percent = 0.0 + local pctIncrement = 1.0 / #(darktable.gui.action_images) + for _,img in ipairs(darktable.gui.action_images) do + if job.valid then + destFilm = destFilms[img.film] + transferFunc(img, destFilm) + job.percent = job.percent + pctIncrement + end + end + job.valid = false + local filterRules = darktable.gui.libs.collect.filter() + darktable.gui.libs.collect.filter(filterRules) +end + +local function doMove() + doTransfer(darktable.database.move_image) +end + +local function doCopy() + doTransfer(darktable.database.copy_image) +end + + + + + + +local transfer_widget = darktable.new_widget("box") { + orientation = "vertical", + darktable.new_widget("button") { + label = "calculate", + clicked_callback = doCalculate + }, + darktable.new_widget("label") { + label = "existing root", + halign = "start" + }, + sourceTextBox, + darktable.new_widget("label") { + label = "root of destination", + halign = "start" + }, + destinationTextBox, + darktable.new_widget("button") { + label = "move", + tooltip = "Move all selected images", + clicked_callback = doMove + }, + darktable.new_widget("button") { + label = "copy", + tooltip = "Copy all selected images", + clicked_callback = doCopy + } +} + +-- Widgets and business logic: END + + + + + + +-- Preferences: BEGIN + +darktable.preferences.register( + LIB_ID, + "source_base", + "string", + "[transfer hierarchy] Customary source root", + "", + "") + +darktable.preferences.register( + LIB_ID, + "destination_base", + "string", + "[transfer hierarchy] Customary destination root", + "", + "") + +-- Preferences: END + + + + + + +darktable.register_lib(LIB_ID, + "transfer hierarchy", true, true, { + [darktable.gui.views.lighttable] = { "DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 1000 } + }, transfer_widget, nil, nil) From 19a1be1f743da672e07e33ec30780b7e703f6e8b Mon Sep 17 00:00:00 2001 From: August Schwerdfeger Date: Sat, 14 Mar 2020 00:28:53 -0500 Subject: [PATCH 018/445] Corrected a variable name. --- contrib/transfer_hierarchy.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/transfer_hierarchy.lua b/contrib/transfer_hierarchy.lua index 382bc2cf..d7485906 100755 --- a/contrib/transfer_hierarchy.lua +++ b/contrib/transfer_hierarchy.lua @@ -219,7 +219,7 @@ local function doCalculate() end local function stopTransfer(transferJob) - job.valid = false + transferJob.valid = false end local function doTransfer(transferFunc) From 050175802f932316d9c11c027064c7b32aed56e8 Mon Sep 17 00:00:00 2001 From: August Schwerdfeger Date: Sun, 15 Mar 2020 22:39:07 -0500 Subject: [PATCH 019/445] Repositioned the 'transfer hierarchy' module below 'select' and 'selected image[s]'; added a translatability layer for strings; corrected behavior in the case of images with multiple versions. --- contrib/transfer_hierarchy.lua | 41 +++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/contrib/transfer_hierarchy.lua b/contrib/transfer_hierarchy.lua index d7485906..c2ba9cb9 100755 --- a/contrib/transfer_hierarchy.lua +++ b/contrib/transfer_hierarchy.lua @@ -87,6 +87,12 @@ local PATH_SEGMENT_REGEX = "(" .. PATH_SEPARATOR .. "?)([^" .. PATH_SEPARATOR .. unpack = unpack or table.unpack gmatch = string.gfind or string.gmatch +darktable.gettext.bindtextdomain(LIB_ID, darktable.configuration.config_dir .. PATH_SEPARATOR .. "lua" .. PATH_SEPARATOR .. "locale" .. PATH_SEPARATOR) + +local function _(msgid) + return darktable.gettext.dgettext(LIB_ID, msgid) +end + -- Header material: END @@ -122,7 +128,7 @@ end -- Widgets and business logic: BEGIN local sourceTextBox = darktable.new_widget("entry") { - tooltip = "Lowest directory containing all selected images", + tooltip = _("Lowest directory containing all selected images"), editable = false } sourceTextBox.reset_callback = function() sourceTextBox.text = "" end @@ -225,11 +231,11 @@ end local function doTransfer(transferFunc) rootPath, films = calculateRoot() if rootPath ~= sourceTextBox.text then - darktable.print("transfer hierarchy: ERROR: existing root is out of sync -- click 'calculate' to update") + darktable.print(_("transfer hierarchy: ERROR: existing root is out of sync -- click 'calculate' to update")) return end if destinationTextBox.text == "" then - darktable.print("transfer hierarchy: ERROR: destination not specified") + darktable.print(_("transfer hierarchy: ERROR: destination not specified")) return end local sourceBase = sourceTextBox.text @@ -239,25 +245,30 @@ local function doTransfer(transferFunc) films[film] = destBase .. string.sub(film.path, #sourceBase+1) if not pathExists(films[film]) then if createDirectory(films[film]) == nil then - darktable.print("transfer hierarchy: ERROR: could not create directory: " .. films[film]) + darktable.print(_("transfer hierarchy: ERROR: could not create directory: " .. films[film])) return end end if not pathIsDirectory(films[film]) then - darktable.print("transfer hierarchy: ERROR: not a directory: " .. films[film]) + darktable.print(_("transfer hierarchy: ERROR: not a directory: " .. films[film])) return end destFilms[film] = darktable.films.new(films[film]) if destFilms[film] == nil then - darktable.print("transfer hierarchy: ERROR: could not create film: " .. film.path) + darktable.print(_("transfer hierarchy: ERROR: could not create film: " .. film.path)) end end - local job = darktable.gui.create_job(string.format("transfer hierarchy (%d image" .. (#(darktable.gui.action_images) == 1 and "" or "s") .. ")", #(darktable.gui.action_images)), true, stopTransfer) + local srcFilms = {} + for _,img in ipairs(darktable.gui.action_images) do + srcFilms[img] = img.film + end + + local job = darktable.gui.create_job(string.format(_("transfer hierarchy") .. " (%d image" .. (#(darktable.gui.action_images) == 1 and "" or "s") .. ")", #(darktable.gui.action_images)), true, stopTransfer) job.percent = 0.0 local pctIncrement = 1.0 / #(darktable.gui.action_images) for _,img in ipairs(darktable.gui.action_images) do - if job.valid then + if job.valid and img.film == srcFilms[img] then destFilm = destFilms[img.film] transferFunc(img, destFilm) job.percent = job.percent + pctIncrement @@ -284,27 +295,27 @@ end local transfer_widget = darktable.new_widget("box") { orientation = "vertical", darktable.new_widget("button") { - label = "calculate", + label = _("calculate"), clicked_callback = doCalculate }, darktable.new_widget("label") { - label = "existing root", + label = _("existing root"), halign = "start" }, sourceTextBox, darktable.new_widget("label") { - label = "root of destination", + label = _("root of destination"), halign = "start" }, destinationTextBox, darktable.new_widget("button") { - label = "move", + label = _("move"), tooltip = "Move all selected images", clicked_callback = doMove }, darktable.new_widget("button") { - label = "copy", - tooltip = "Copy all selected images", + label = _("copy"), + tooltip = _("Copy all selected images"), clicked_callback = doCopy } } @@ -343,5 +354,5 @@ darktable.preferences.register( darktable.register_lib(LIB_ID, "transfer hierarchy", true, true, { - [darktable.gui.views.lighttable] = { "DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 1000 } + [darktable.gui.views.lighttable] = { "DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 700 } }, transfer_widget, nil, nil) From ebd33c4c169c6381871dad19eb1cfcfeb0063ed3 Mon Sep 17 00:00:00 2001 From: "U-DESKTOP-HQME86J\\marco" Date: Sun, 22 Mar 2020 17:21:30 +0100 Subject: [PATCH 020/445] changed default sigma --- contrib/RL_out_sharp.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/contrib/RL_out_sharp.lua b/contrib/RL_out_sharp.lua index b5d0fe9f..fcc553e4 100644 --- a/contrib/RL_out_sharp.lua +++ b/contrib/RL_out_sharp.lua @@ -20,7 +20,7 @@ EXAMPLE set sigma = 0.7, iterations = 10, jpeg output quality = 95, - that will be sufficient for most uses + to correct blur due to image resize for web usage CAVEATS MAC compatibility not tested @@ -153,12 +153,12 @@ sigma_slider = dt.new_widget("slider"){ label = _("sigma"), tooltip = _("controls the width of the blur that's applied"), soft_min = 0.3, - soft_max = 1.0, + soft_max = 2.0, hard_min = 0.0, hard_max = 3.0, - step = 0.05, + step = 0.1, digits = 2, - value = 0.7 + value = 1.0 } iterations_slider = dt.new_widget("slider"){ From 2d695364898ae18134be6224dbd7542607f4fa48 Mon Sep 17 00:00:00 2001 From: "U-DESKTOP-HQME86J\\marco" Date: Sun, 22 Mar 2020 17:50:51 +0100 Subject: [PATCH 021/445] fixes and code cleaning --- contrib/ext_editor.lua | 123 ++++++++++++++++++----------------------- 1 file changed, 55 insertions(+), 68 deletions(-) diff --git a/contrib/ext_editor.lua b/contrib/ext_editor.lua index 45755423..8cbd55fe 100644 --- a/contrib/ext_editor.lua +++ b/contrib/ext_editor.lua @@ -3,61 +3,60 @@ DESCRIPTION ext_editor.lua - edit images with external editors - This script provides helpers to edit image files with programs external to darktable. - It adds: - - a new target storage "collection". Image exported will be reimported to collection for - further edit with external programs - - a new lighttable module "external editors", to select a program from a list of up to - - 9 external editors and run it on a selected image (adjust this limit by changing MAX_EDITORS) - - a set of lua preferences in order to configure name and path of up to 9 external editors - - a set of lua shortcuts in order to quick launch the external editors + This script provides helpers to edit image files with programs external to darktable. It adds: + - a new target storage "collection". Image exported will be reimported to collection for + further edit with external programs + - a new lighttable module "external editors", to select a program from a list of up to + - 9 external editors and run it on a selected image (adjust this limit by changing MAX_EDITORS) + - a set of lua preferences in order to configure name and path of up to 9 external editors + - a set of lua shortcuts in order to quick launch the external editors USAGE * require this script from main lua file - -- setup -- - * in "preferences/lua options" configure name and path/command of external programs - * note that if a program name is left empty, that and all following entries will be ignored - * in "preferences/shortcuts/lua" configure shortcuts for external programs (optional) - * whenever programs preferences are changed, in lighttable/external editors, press "update list" - - -- use -- - * in the export dialog choose "collection" and select the format and bit depth for the - exported image - * press "export" - * the exported image will be imported into collection and grouped with the original image + -- setup -- + * in "preferences/lua options" configure name and path/command of external programs + * note that if a program name is left empty, that and all following entries will be ignored + * in "preferences/shortcuts/lua" configure shortcuts for external programs (optional) + * whenever programs preferences are changed, in lighttable/external editors, press "update list" + + -- use -- + * in the export dialog choose "collection" and select the format and bit depth for the + exported image + * press "export" + * the exported image will be imported into collection and grouped with the original image + + * select an image for editing with en external program, and: + * in lighttable/external editors, select program and press "edit" + * edit the image with the external editor, overwite the file, quit the external program + * the selected image will be updated + or + * in lighttable/external editors, select program and press "edit a copy" + * edit the image with the external editor, overwite the file, quit the external program + * a copy of the selected image will be created and updated + or + * in lighttable select target storage "collection" + * enter in darkroom + * to create an export or a copy press CRTL+E + * use the shortcut to edit the current image with the corresponding external editor + * overwite the file, quit the external program + * the darkroom view will be updated - * select an image for editing with en external program, and: - * in lighttable/external editors, select program and press "edit" - * edit the image with the external editor, overwite the file, quit the external program - * the selected image will be updated - or - * in lighttable/external editors, select program and press "edit a copy" - * edit the image with the external editor, overwite the file, quit the external program - * a copy of the selected image will be created and updated - or - * in lighttable select target storage "collection" - * enter in darkroom - * to create an export or a copy press CRTL+E - * use the shortcut to edit the current image with the corresponding external editor - * overwite the file, quit the external program - * the darkroom view will be updated - - * warning: mouseover on lighttable/filmstrip will prevail on current image - * this is the default DT behavior, not a bug of this script + * warning: mouseover on lighttable/filmstrip will prevail on current image + * this is the default DT behavior, not a bug of this script - CAVEATS - * MAC compatibility not tested + CAVEATS + * MAC compatibility not tested TODO - * send multiple images to the same program, maybe + * send multiple images to the same program, maybe - BUGS, COMMENTS, SUGGESTIONS + BUGS, COMMENTS, SUGGESTIONS * send to Marco Carrarini, marco.carrarini@gmail.com - CHANGES + CHANGES * 20191224 - initial version - * 20191227 - added button "update list", better error handling, fixed bug with groups/tags in "edit" + * 20191227 - added button "update list", better error handling, fixed bug with groups/tags in "edit" ]] @@ -73,7 +72,7 @@ local MODULE_NAME = "ext_editor" -- check API version -du.check_min_api_version("5.0.2", MODULE_NAME) -- darktable 3.0 +du.check_min_api_version("5.0.2", MODULE_NAME) -- darktable 3.x -- OS compatibility @@ -88,7 +87,7 @@ local function _(msgid) end -- maximum number of external programs, can be increased to necessity -local MAX_EDITORS = 9 +local MAX_EDITORS = 11 -- number of valid entries in the list of external programs local n_entries @@ -98,6 +97,7 @@ local n_entries local allowed_file_types = {"JPG", "jpg", "JPEG", "jpeg", "TIF", "tif", "TIFF", "tiff", "EXR", "exr", "PNG", "png"} +-- last used editor initialization if not dt.preferences.read(MODULE_NAME, "initialized", "bool") then dt.preferences.write(MODULE_NAME, "lastchoice", "integer", 0) dt.preferences.write(MODULE_NAME, "initialized", "bool", true) @@ -163,11 +163,7 @@ local function OpenWith(images, choice, copy) local bin = program_paths[choice] local friendly_name = program_names[choice] - -- check if external program executable exists, return if not - if not df.check_if_bin_exists(bin) then - dt.print(friendly_name.._(" not found")) - return - end + if dt.configuration.running_os == "macos" then bin = "open -W -a "..bin end -- image to be edited local image @@ -175,7 +171,7 @@ local function OpenWith(images, choice, copy) local name = image.path..PS..image.filename -- check if image format is allowed - local file_ext = df.get_filetype (image.filename) + local file_ext = df.get_filetype(image.filename) local allowed = false for i,v in pairs(allowed_file_types) do if v == file_ext then @@ -207,11 +203,7 @@ local function OpenWith(images, choice, copy) if copy then -- create unique filename - while df.check_if_file_exists(df.sanitize_filename(new_name)) do - new_name = df.filename_increment(new_name) - -- limit to 50 more exports of the original export - if string.match(df.get_basename(new_name), "_%d%d$") == "_50" then break end - end + new_name = df.create_unique_filename(new_name) -- physical copy, check result, return if error local copy_success = df.file_copy(name, new_name) @@ -306,7 +298,7 @@ local function program_shortcut(event, shortcut) -- export images and reimport in collection ----------------------------------- local function export2collection(storage, image_table, extra_data) - local new_name, new_image, result + local temp_name, new_name, new_image, move_success for image, temp_name in pairs(image_table) do @@ -314,11 +306,7 @@ local function export2collection(storage, image_table, extra_data) -- create unique filename new_name = image.path..PS..df.get_filename(temp_name) - while df.check_if_file_exists(df.sanitize_filename(new_name)) do - new_name = df.filename_increment(new_name) - -- limit to 50 more exports of the original export - if string.match(df.get_basename(new_name), "_%d%d$") == "_50" then break end - end + new_name = df.create_unique_filename(new_name) -- move image to collection folder, check result, return if error move_success = df.file_move(temp_name, new_name) @@ -336,12 +324,6 @@ local function export2collection(storage, image_table, extra_data) end --- register new storage ------------------------------------------------------- --- note that placing this declaration later makes the export selected module --- not to remember the choice "collection" when restarting DT, don't know why -dt.register_storage("exp2coll", _("collection"), null, export2collection) - - -- combobox, with variable number of entries ---------------------------------- local combobox = dt.new_widget("combobox") { label = _("choose program"), @@ -415,11 +397,16 @@ dt.register_lib( UpdateProgramList(combobox, button_edit, button_edit_copy, false) +-- register new storage ------------------------------------------------------- +dt.register_storage("exp2coll", _("collection"), nil, export2collection) + + -- register the new preferences ----------------------------------------------- for i = MAX_EDITORS, 1, -1 do dt.preferences.register(MODULE_NAME, "program_path_"..i, "file", _("executable for external editor ")..i, _("select executable for external editor") , _("(None)")) + dt.preferences.register(MODULE_NAME, "program_name_"..i, "string", _("name of external editor ")..i, _("friendly name of external editor"), "") From a8e5a9b45341a141843614fcb80fba8e168cf953 Mon Sep 17 00:00:00 2001 From: "U-DESKTOP-HQME86J\\marco" Date: Sun, 22 Mar 2020 17:55:15 +0100 Subject: [PATCH 022/445] default no. of editors --- contrib/ext_editor.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/ext_editor.lua b/contrib/ext_editor.lua index 8cbd55fe..19e711c4 100644 --- a/contrib/ext_editor.lua +++ b/contrib/ext_editor.lua @@ -87,7 +87,7 @@ local function _(msgid) end -- maximum number of external programs, can be increased to necessity -local MAX_EDITORS = 11 +local MAX_EDITORS = 9 -- number of valid entries in the list of external programs local n_entries From 224dce1b765ca4cf561d56e1c875e38995ea1644 Mon Sep 17 00:00:00 2001 From: preklov <63585095+preklov@users.noreply.github.com> Date: Tue, 14 Apr 2020 15:04:31 +0200 Subject: [PATCH 023/445] Delete OpenInExplorer.lua --- contrib/OpenInExplorer.lua | 113 ------------------------------------- 1 file changed, 113 deletions(-) delete mode 100644 contrib/OpenInExplorer.lua diff --git a/contrib/OpenInExplorer.lua b/contrib/OpenInExplorer.lua deleted file mode 100644 index 11f004f4..00000000 --- a/contrib/OpenInExplorer.lua +++ /dev/null @@ -1,113 +0,0 @@ ---[[ -OpenInExplorer plugin for darktable - - copyright (c) 2018 Kevin Ertel - - darktable is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - darktable is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with darktable. If not, see . -]] - ---[[About this plugin -This plugin adds the module "OpenInExplorer" to darktable's lighttable view - -----REQUIRED SOFTWARE---- -Microsoft Windows or Linux with installed Nautilus - -----USAGE---- -Install: (see here for more detail: https://github.com/darktable-org/lua-scripts ) - 1) Copy this file in to your "lua/contrib" folder where all other scripts reside. - 2) Require this file in your luarc file, as with any other dt plug-in - -Select the photo(s) you wish to find in explorer and press "Go to Folder". -A file explorer window will be opened for each selected file at the file's location; the file will be highlighted. - -----KNOWN ISSUES---- -]] - -local dt = require "darktable" -local du = require "lib/dtutils" -local df = require "lib/dtutils.file" -local dsys = require "lib/dtutils.system" - ---Check API version -du.check_min_api_version("5.0.0", "OpenInExplorer") - -local PS = dt.configuration.running_os == "windows" and "\\" or "/" - ---Detect OS and modify accordingly-- -local proper_install = false -if dt.configuration.running_os ~= "macos" then - proper_install = true -else - dt.print_error('OpenInExplorer plug-in only supports Windows and Linux at this time') - return -end - - --- FUNCTIONS -- - -local function open_in_explorer() --Open in Explorer - local images = dt.gui.selection() - local curr_image = "" - if #images == 0 then - dt.print('please select an image') - elseif #images <= 15 then - for _,image in pairs(images) do - curr_image = image.path..PS..image.filename - local run_cmd = "explorer.exe /select, "..curr_image - dt.print_log("OpenInExplorer run_cmd = "..run_cmd) - resp = dsys.external_command(run_cmd) - end - else - dt.print('please select fewer images (max 15)') - end -end - -local function open_in_nautilus() --Open in Nautilus - local images = dt.gui.selection() - local curr_image = "" - if #images == 0 then - dt.print('please select an image') - elseif #images <= 15 then - for _,image in pairs(images) do - curr_image = image.path..PS..image.filename - local run_cmd = [[busctl --user call org.freedesktop.FileManager1 /org/freedesktop/FileManager1 org.freedesktop.FileManager1 ShowItems ass 1 ]] .. df.sanitize_filename("file://"..curr_image) .. [[ ""]] - dt.print_log("OpenInExplorer run_cmd = "..run_cmd) - resp = dsys.external_command(run_cmd) - end - else - dt.print('please select fewer images (max 15)') - end -end - -local function open_in_filemanager() --Open - --Inits-- - if not proper_install then - return - end - - if (dt.configuration.running_os == "windows") then - open_in_explorer() - elseif (dt.configuration.running_os == "linux") then - open_in_nautilus() - end -end - --- GUI -- -if proper_install then - dt.gui.libs.image.register_action( - "show in file explorer", - function() open_in_filemanager() end, - "Opens File Explorer at the selected image's location" - ) -end From fb331710e11ead8fa910ddd18166df32b3bbc41d Mon Sep 17 00:00:00 2001 From: preklov <63585095+preklov@users.noreply.github.com> Date: Tue, 14 Apr 2020 15:07:22 +0200 Subject: [PATCH 024/445] Add files via upload --- contrib/OpenInExplorer.lua | 98 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 contrib/OpenInExplorer.lua diff --git a/contrib/OpenInExplorer.lua b/contrib/OpenInExplorer.lua new file mode 100644 index 00000000..65449c70 --- /dev/null +++ b/contrib/OpenInExplorer.lua @@ -0,0 +1,98 @@ +--[[ +OpenInExplorer plugin for darktable + + copyright (c) 2018 Kevin Ertel + Update 2020: copyright (c) 2020 Volker Lenhardt + + darktable is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + darktable is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with darktable. If not, see . +]] + +--[[About this plugin +This plugin adds the module "OpenInExplorer" to darktable's lighttable view + +----REQUIRED SOFTWARE---- +Microsoft Windows or Linux with installed Nautilus + +----USAGE---- +Install: (see here for more detail: https://github.com/darktable-org/lua-scripts ) + 1) Copy this file in to your "lua/contrib" folder where all other scripts reside. + 2) Require this file in your luarc file, as with any other dt plug-in + +Select the photo(s) you wish to find in explorer and press "Go to Folder". +A file explorer window will be opened for each selected file at the file's location; the file will be highlighted. + +----KNOWN ISSUES---- +Under macOS the file manager Finder opens only once and selects the file name of the last in DT selected image. +]] + +local dt = require "darktable" +local du = require "lib/dtutils" +local df = require "lib/dtutils.file" +local dsys = require "lib/dtutils.system" +local gettext = dt.gettext + +--Check API version +du.check_min_api_version("5.0.0", "OpenInExplorer") + +gettext.bindtextdomain("OpenInExplorer",dt.configuration.config_dir.."/lua/locale/") + +local function _(msgid) + return gettext.dgettext("OpenInExplorer", msgid) +end + +local act_os = dt.configuration.running_os +local PS = act_os == "windows" and "\\" or "/" + +--Detect OS and modify accordingly-- +local proper_install = true +if act_os ~= "macos" and act_os ~= "windows" and act_os ~= "linux" then + proper_install = false + dt.print_error(_('OpenInExplorer plug-in only supports Windows and Linux at this time')) + return +end + +--The commands to open the OSes' file managers +local fmng_cmd = {} +fmng_cmd.linux = [[busctl --user call org.freedesktop.FileManager1 /org/freedesktop/FileManager1 org.freedesktop.FileManager1 ShowItems ass 1 ]] +fmng_cmd.macos = 'open -R -n ' +fmng_cmd.windows = 'explorer.exe /select, ' + +--The working function that opens the file manager with the image file name selected. +local function open_in_fmanager(os, fmcmd) + local images = dt.gui.selection() + local curr_image = "" + if #images == 0 then + dt.print(_('Please select an image')) + elseif #images <= 15 then + for _,image in pairs(images) do + curr_image = df.sanitize_filename(image.path..PS..image.filename) + local run_cmd = fmcmd..curr_image + if os == 'linux' then run_cmd = run_cmd .. [[ ""]] end + dt.print_log("OpenInExplorer run_cmd = "..run_cmd) + resp = dsys.external_command(run_cmd) + end + else + dt.print(_('Please select fewer images (max 15)')) + end +end + + +-- GUI -- +if proper_install then + dt.gui.libs.image.register_action( + _("Show in file explorer"), + function() open_in_fmanager(act_os, fmng_cmd[act_os]) end, + _("Opens File Explorer at the selected image's location") + ) +end From afa95d5d3419f3ba6e03c9fb3199209ea358251e Mon Sep 17 00:00:00 2001 From: preklov <63585095+preklov@users.noreply.github.com> Date: Tue, 14 Apr 2020 15:26:28 +0200 Subject: [PATCH 025/445] Update OpenInExplorer.lua --- contrib/OpenInExplorer.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/OpenInExplorer.lua b/contrib/OpenInExplorer.lua index 65449c70..6f6912fc 100644 --- a/contrib/OpenInExplorer.lua +++ b/contrib/OpenInExplorer.lua @@ -65,7 +65,7 @@ end --The commands to open the OSes' file managers local fmng_cmd = {} fmng_cmd.linux = [[busctl --user call org.freedesktop.FileManager1 /org/freedesktop/FileManager1 org.freedesktop.FileManager1 ShowItems ass 1 ]] -fmng_cmd.macos = 'open -R -n ' +fmng_cmd.macos = 'open -R ' fmng_cmd.windows = 'explorer.exe /select, ' --The working function that opens the file manager with the image file name selected. From bd5bef279c53f896277d4f20e4a3a70b88adb994 Mon Sep 17 00:00:00 2001 From: preklov <63585095+preklov@users.noreply.github.com> Date: Tue, 14 Apr 2020 15:36:48 +0200 Subject: [PATCH 026/445] Delete OpenInExplorer.lua --- contrib/OpenInExplorer.lua | 98 -------------------------------------- 1 file changed, 98 deletions(-) delete mode 100644 contrib/OpenInExplorer.lua diff --git a/contrib/OpenInExplorer.lua b/contrib/OpenInExplorer.lua deleted file mode 100644 index 6f6912fc..00000000 --- a/contrib/OpenInExplorer.lua +++ /dev/null @@ -1,98 +0,0 @@ ---[[ -OpenInExplorer plugin for darktable - - copyright (c) 2018 Kevin Ertel - Update 2020: copyright (c) 2020 Volker Lenhardt - - darktable is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - darktable is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with darktable. If not, see . -]] - ---[[About this plugin -This plugin adds the module "OpenInExplorer" to darktable's lighttable view - -----REQUIRED SOFTWARE---- -Microsoft Windows or Linux with installed Nautilus - -----USAGE---- -Install: (see here for more detail: https://github.com/darktable-org/lua-scripts ) - 1) Copy this file in to your "lua/contrib" folder where all other scripts reside. - 2) Require this file in your luarc file, as with any other dt plug-in - -Select the photo(s) you wish to find in explorer and press "Go to Folder". -A file explorer window will be opened for each selected file at the file's location; the file will be highlighted. - -----KNOWN ISSUES---- -Under macOS the file manager Finder opens only once and selects the file name of the last in DT selected image. -]] - -local dt = require "darktable" -local du = require "lib/dtutils" -local df = require "lib/dtutils.file" -local dsys = require "lib/dtutils.system" -local gettext = dt.gettext - ---Check API version -du.check_min_api_version("5.0.0", "OpenInExplorer") - -gettext.bindtextdomain("OpenInExplorer",dt.configuration.config_dir.."/lua/locale/") - -local function _(msgid) - return gettext.dgettext("OpenInExplorer", msgid) -end - -local act_os = dt.configuration.running_os -local PS = act_os == "windows" and "\\" or "/" - ---Detect OS and modify accordingly-- -local proper_install = true -if act_os ~= "macos" and act_os ~= "windows" and act_os ~= "linux" then - proper_install = false - dt.print_error(_('OpenInExplorer plug-in only supports Windows and Linux at this time')) - return -end - ---The commands to open the OSes' file managers -local fmng_cmd = {} -fmng_cmd.linux = [[busctl --user call org.freedesktop.FileManager1 /org/freedesktop/FileManager1 org.freedesktop.FileManager1 ShowItems ass 1 ]] -fmng_cmd.macos = 'open -R ' -fmng_cmd.windows = 'explorer.exe /select, ' - ---The working function that opens the file manager with the image file name selected. -local function open_in_fmanager(os, fmcmd) - local images = dt.gui.selection() - local curr_image = "" - if #images == 0 then - dt.print(_('Please select an image')) - elseif #images <= 15 then - for _,image in pairs(images) do - curr_image = df.sanitize_filename(image.path..PS..image.filename) - local run_cmd = fmcmd..curr_image - if os == 'linux' then run_cmd = run_cmd .. [[ ""]] end - dt.print_log("OpenInExplorer run_cmd = "..run_cmd) - resp = dsys.external_command(run_cmd) - end - else - dt.print(_('Please select fewer images (max 15)')) - end -end - - --- GUI -- -if proper_install then - dt.gui.libs.image.register_action( - _("Show in file explorer"), - function() open_in_fmanager(act_os, fmng_cmd[act_os]) end, - _("Opens File Explorer at the selected image's location") - ) -end From bbfa81f0514d9dac617baced03d84ae8072bfce5 Mon Sep 17 00:00:00 2001 From: preklov <63585095+preklov@users.noreply.github.com> Date: Tue, 14 Apr 2020 15:46:41 +0200 Subject: [PATCH 027/445] Add files via upload --- OpenInExplorer.lua | 98 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 OpenInExplorer.lua diff --git a/OpenInExplorer.lua b/OpenInExplorer.lua new file mode 100644 index 00000000..d9652fa9 --- /dev/null +++ b/OpenInExplorer.lua @@ -0,0 +1,98 @@ +--[[ +OpenInExplorer plugin for darktable + + copyright (c) 2018 Kevin Ertel + Update 2020: copyright (c) 2020 Volker Lenhardt + + darktable is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + darktable is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with darktable. If not, see . +]] + +--[[About this plugin +This plugin adds the module "OpenInExplorer" to darktable's lighttable view + +----REQUIRED SOFTWARE---- +Apple macOS, Microsoft Windows or Linux with installed Nautilus + +----USAGE---- +Install: (see here for more detail: https://github.com/darktable-org/lua-scripts ) + 1) Copy this file in to your "lua/contrib" folder where all other scripts reside. + 2) Require this file in your luarc file, as with any other dt plug-in + +Select the photo(s) you wish to find in explorer and press "Go to Folder". +A file explorer window will be opened for each selected file at the file's location; the file will be highlighted. + +----KNOWN ISSUES---- +Under macOS the file manager Finder opens only once and selects the file name of the last in DT selected image. +]] + +local dt = require "darktable" +local du = require "lib/dtutils" +local df = require "lib/dtutils.file" +local dsys = require "lib/dtutils.system" +local gettext = dt.gettext + +--Check API version +du.check_min_api_version("5.0.0", "OpenInExplorer") + +gettext.bindtextdomain("OpenInExplorer",dt.configuration.config_dir.."/lua/locale/") + +local function _(msgid) + return gettext.dgettext("OpenInExplorer", msgid) +end + +local act_os = dt.configuration.running_os +local PS = act_os == "windows" and "\\" or "/" + +--Detect OS and modify accordingly-- +local proper_install = true +if act_os ~= "macos" and act_os ~= "windows" and act_os ~= "linux" then + proper_install = false + dt.print_error(_('OpenInExplorer plug-in only supports Windows and Linux at this time')) + return +end + +--The commands to open the OSes' file managers +local fmng_cmd = {} +fmng_cmd.linux = [[busctl --user call org.freedesktop.FileManager1 /org/freedesktop/FileManager1 org.freedesktop.FileManager1 ShowItems ass 1 ]] +fmng_cmd.macos = 'open -R ' +fmng_cmd.windows = 'explorer.exe /select, ' + +--The working function that opens the file manager with the image file name selected. +local function open_in_fmanager(os, fmcmd) + local images = dt.gui.selection() + local curr_image = "" + if #images == 0 then + dt.print(_('Please select an image')) + elseif #images <= 15 then + for _,image in pairs(images) do + curr_image = df.sanitize_filename(image.path..PS..image.filename) + local run_cmd = fmcmd..curr_image + if os == 'linux' then run_cmd = run_cmd .. [[ ""]] end + dt.print_log("OpenInExplorer run_cmd = "..run_cmd) + resp = dsys.external_command(run_cmd) + end + else + dt.print(_('Please select fewer images (max 15)')) + end +end + + +-- GUI -- +if proper_install then + dt.gui.libs.image.register_action( + _("Show in file explorer"), + function() open_in_fmanager(act_os, fmng_cmd[act_os]) end, + _("Opens File Explorer at the selected image's location") + ) +end From ec0fe0b04751f8b55b530e179121559f4a32091e Mon Sep 17 00:00:00 2001 From: preklov <63585095+preklov@users.noreply.github.com> Date: Tue, 14 Apr 2020 16:15:45 +0200 Subject: [PATCH 028/445] Rename OpenInExplorer.lua to contrib/OpenInExplorer.lua --- OpenInExplorer.lua => contrib/OpenInExplorer.lua | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename OpenInExplorer.lua => contrib/OpenInExplorer.lua (100%) diff --git a/OpenInExplorer.lua b/contrib/OpenInExplorer.lua similarity index 100% rename from OpenInExplorer.lua rename to contrib/OpenInExplorer.lua From 2b171aef7cb57a049916476422027fb3e4a7bf1a Mon Sep 17 00:00:00 2001 From: preklov <63585095+preklov@users.noreply.github.com> Date: Tue, 14 Apr 2020 19:33:54 +0200 Subject: [PATCH 029/445] German translation of OpenInExplorer.lua --- locale/de_DE/LC_MESSAGES/OpenInExplorer.po | 38 ++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 locale/de_DE/LC_MESSAGES/OpenInExplorer.po diff --git a/locale/de_DE/LC_MESSAGES/OpenInExplorer.po b/locale/de_DE/LC_MESSAGES/OpenInExplorer.po new file mode 100644 index 00000000..3cb5901b --- /dev/null +++ b/locale/de_DE/LC_MESSAGES/OpenInExplorer.po @@ -0,0 +1,38 @@ +# OpenInExplorer Darktable Plug-In. +# Copyright (C) 2020 Volker Lenhardt +# This file is distributed under the same license as the PACKAGE package. +# Volker Lenhardt , 2020. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: OpenInExplorer\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2020-04-14 14:35+0200\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Volker Lenhardt \n" +"Language-Team: LANGUAGE \n" +"Language: de_DE\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: OpenInExplorer.lua:59 +msgid "OpenInExplorer plug-in only supports Windows and Linux at this time" +msgstr "OpenInExplorer-Plug-in kann nur unter macOS, Linux oder Windows laufen" + +#: OpenInExplorer.lua:75 +msgid "Please select an image" +msgstr "Bitte mindestens 1 Bild auswählen" + +#: OpenInExplorer.lua:85 +msgid "Please select fewer images (max 15)" +msgstr "Bitte nicht mehr als 15 Bilder auswählen" + +#: OpenInExplorer.lua:93 +msgid "Show in file explorer" +msgstr "Im Dateimanager anzeigen" + +#: OpenInExplorer.lua:95 +msgid "Opens File Explorer at the selected image's location" +msgstr "Öffnet den Dateimanager mit dem ausgewählten Dateinamen" From c7eb101920da42aa37604ac6b72d00d0b997bbe8 Mon Sep 17 00:00:00 2001 From: supertobi Date: Wed, 15 Apr 2020 17:42:42 +0200 Subject: [PATCH 030/445] Updated the "USAGE" section in the header of enfuseAdvanced.lua --- contrib/enfuseAdvanced.lua | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/contrib/enfuseAdvanced.lua b/contrib/enfuseAdvanced.lua index 9fb49c0a..932a6cdd 100644 --- a/contrib/enfuseAdvanced.lua +++ b/contrib/enfuseAdvanced.lua @@ -26,10 +26,11 @@ enfuse ver. 4.2 or greater exiftool ----USAGE---- -Install: (see here for more detail: https://github.com/darktable-org/lua-scripts ) - 1) Copy this file in to your 'lua/contrib' folder where all other scripts reside. - 2) Require this file in your luarc file, as with any other dt plug-in -On the initial startup go to darktable settings > lua options and set your executable paths and other preferences, then restart darktable +Install: + 1) Get the Lua scripts: https://github.com/darktable-org/lua-scripts#download-and-install + 2) Require this file in your luarc file, as with any other dt plug-in: require "contrib/enfuseAdvanced" + 3) Then select "DRI or DFF image" as storage option + 4) On the initial startup set your executable paths DRI = Dynamic Range Increase (Blend multiple bracket images into a single LDR file) DFF = Depth From Focus ('Focus Stacking' - Blend multiple images with different focus into a single image) From 9870ddbe861f74381bd8d55d6751d6dc15dc755f Mon Sep 17 00:00:00 2001 From: Piter Dias Date: Wed, 15 Apr 2020 14:03:58 -0300 Subject: [PATCH 031/445] =?UTF-8?q?face=5Frecognition.lua=20script=20face?= =?UTF-8?q?=20some=20stability=20and=20performance=20issues=20on=20an=20i5?= =?UTF-8?q?-6600,=2032=20GB=20and=20GTX=201060=206GB:=20=20=20=20=201.=20T?= =?UTF-8?q?aking=20to=20much=20time=20=E2=80=93=20almost=20a=20day=20for?= =?UTF-8?q?=203000=20images=20=20=20=20=202.=20Crashing=20due=20to=20lines?= =?UTF-8?q?=20malformation=20in=20facerecognition.txt=20=E2=80=93=20some?= =?UTF-8?q?=20times=20face=5Frecognition=20Python=20script=20concatenates?= =?UTF-8?q?=20two=20output=20lines=20in=20just=20once,=20what=20is=20not?= =?UTF-8?q?=20expected=20by=20face=5Frecognition.lua=20script=20=20=20=20?= =?UTF-8?q?=203.=20Crashing=20the=20whole=20system=20in=20Linux=20?= =?UTF-8?q?=E2=80=93=20I=20keep=20receiving=20=E2=80=9Cbash:=20fork:=20res?= =?UTF-8?q?ource=20temporarily=20unavailable=E2=80=9D=20trying=20to=20proc?= =?UTF-8?q?ess=20a=20too=20big=20(starting=20from=20some=20hundreds)=20ima?= =?UTF-8?q?ge=20list.=20Some=20other=20applications=20starts=20to=20crash?= =?UTF-8?q?=20at=20this=20point.=20It=20seems=20related=20to=20the=20attac?= =?UTF-8?q?h=20tag=20call=20because=20commenting=20this=20instruction=20(f?= =?UTF-8?q?or=20debugging=20purposes)=20eliminates=20the=20crashes.=20Afte?= =?UTF-8?q?r=20debugging=20the=20Lua=20script=20and=20checking=20Lua=20and?= =?UTF-8?q?=20SQL=20darktable=20out=20logs,=20I=20decided=20to=20make=20th?= =?UTF-8?q?e=20following=20changes:=20=20=20=20=201.=20Remove=20an=20inner?= =?UTF-8?q?=20loop=20in=20the=20processing=20results=20step=20=E2=80=93=20?= =?UTF-8?q?helps=20preventing=20issue=201=20=20=20=20=202.=20Remove=20a=20?= =?UTF-8?q?loop=20in=20the=20export=20step=20=E2=80=93=20helps=20preventin?= =?UTF-8?q?g=20issue=201=20=20=20=20=203.=20Remove=20duplicate=20tags=20(w?= =?UTF-8?q?hen=20there=20are=20more=20more=20than=20a=20reference=20face?= =?UTF-8?q?=20for=20each=20person)=20while=20facerecognition.txt=20is=20re?= =?UTF-8?q?ad=20=E2=80=93=20helps=20preventing=20issue=201=20and=203=20=20?= =?UTF-8?q?=20=20=204.=20Make=20a=20sanity=20check=20with=20processing=20i?= =?UTF-8?q?mages,=20skip=20any=20malformation=20data=20=E2=80=93=20helps?= =?UTF-8?q?=20preventing=20issue=202=20=20=20=20=205.=20Reduces=20the=20sq?= =?UTF-8?q?lite=20access=20by=20caching=20tags=20that=20where=20already=20?= =?UTF-8?q?created=20for=20a=20previous=20image=20=E2=80=93=20helps=20prev?= =?UTF-8?q?enting=20issue=203?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Those changes allowed may thousands (more than 30K) of images to be processed in half a day instead of several days. --- contrib/face_recognition.lua | 140 ++++++++++++++++++----------------- 1 file changed, 73 insertions(+), 67 deletions(-) diff --git a/contrib/face_recognition.lua b/contrib/face_recognition.lua index fe1e9f6e..64fefeae 100644 --- a/contrib/face_recognition.lua +++ b/contrib/face_recognition.lua @@ -63,7 +63,7 @@ du.check_min_api_version("5.0.0", "face_recognition") gettext.bindtextdomain("face_recognition", dt.configuration.config_dir.."/lua/locale/") local function _(msgid) - return gettext.dgettext("face_recognition", msgid) + return gettext.dgettext("face_recognition", msgid) end -- preferences @@ -92,8 +92,10 @@ local function build_image_table(images) end for _,img in ipairs(images) do - image_table[img] = tmp_dir .. df.get_basename(img.filename) .. file_extension - cnt = cnt + 1 + if img ~= nil then + image_table[tmp_dir .. df.get_basename(img.filename) .. file_extension] = img + cnt = cnt + 1 + end end return image_table, cnt @@ -103,17 +105,12 @@ local function stop_job(job) job.valid = false end -local function do_export(img_tbl) +local function do_export(img_tbl, images) local exporter = nil local upsize = false - local upscale = false local ff = fc.export_format.value local height = dt.preferences.read(MODULE, "max_height", "integer") local width = dt.preferences.read(MODULE, "max_width", "integer") - local images = 0 - for k,v in pairs(img_tbl) do - images = images + 1 - end -- get the export format parameters if string.match(ff, "JPEG") then @@ -134,7 +131,7 @@ local function do_export(img_tbl) local exp_cnt = 0 local percent_step = 1.0 / images job.percent = 0.0 - for img,export in pairs(img_tbl) do + for export,img in pairs(img_tbl) do exp_cnt = exp_cnt + 1 dt.print(string.format(_("Exporting image %i of %i images"), exp_cnt, images)) exporter:write_image(img, export, upsize) @@ -188,7 +185,7 @@ local function ignoreByTag (image, ignoreTags) end end end - + return ignoreImage end @@ -221,25 +218,25 @@ local function face_recognition () if nrCores < 1 then nrCores = -1 end - + -- Split ignore tags (if any) ignoreTags = {} for tag in string.gmatch(ignoreTagString, '([^,]+)') do table.insert (ignoreTags, tag) dt.print_log ("Face recognition: Ignore tag: " .. tag) end - + -- list of exported images local image_table, cnt = build_image_table(dt.gui.action_images) if cnt > 0 then - local success = do_export(image_table) + local success = do_export(image_table, cnt) if success then -- do the face recognition local img_list = {} - for img,v in pairs(image_table) do + for v,_ in pairs(image_table) do table.insert (img_list, v) end @@ -248,7 +245,7 @@ local function face_recognition () dt.print_log ("Face recognition: Path to unknown images: " .. path) os.setlocale("C") local tolerance = dt.preferences.read(MODULE, "tolerance", "float") - + local command = bin_path .. " --cpus " .. nrCores .. " --tolerance " .. tolerance .. " " .. knownPath .. " " .. path .. " > " .. OUTPUT os.setlocale() dt.print_log("Face recognition: Running command: " .. command) @@ -258,61 +255,77 @@ local function face_recognition () -- Open output file local f = io.open(OUTPUT, "rb") - + if not f then dt.print(_("Face recognition failed")) else dt.print(_("Face recognition finished")) f:close () end - + -- Read output dt.print(_("processing results...")) local result = {} - for line in io.lines(OUTPUT) do - if not string.match(line, "^WARNING:") then + local tags_list = {} + local tag_object = {} + for line in io.lines(OUTPUT) do + if not string.match(line, "^WARNING:") and line ~= "" and line ~= nil then local file, tag = string.match (line, "(.*),(.*)$") tag = string.gsub (tag, "%d*$", "") dt.print_log ("File:"..file .." Tag:".. tag) - if result[file] ~= nil then - table.insert (result[file], tag) + tag_object = {} + if result[file] == nil then + tag_object[tag] = true + result[file] = tag_object else - result[file] = {tag} + tag_object = result[file] + tag_object[tag] = true + result[file] = tag_object end end end - + -- Attach tags + local result_index = 0 for file,tags in pairs(result) do + result_index = result_index +1 -- Find image in table - for img,file2 in pairs(image_table) do - if file == file2 then - for _,t in ipairs (tags) do - -- Check if image is ignored - if ignoreByTag (img, ignoreTags) then - dt.print_log("Face recognition: Ignoring image with ID " .. img.id) - else - -- Check of unrecognized unknown_person - if t == "unknown_person" then - t = unknownTag - end - -- Check of unrecognized no_persons_found - if t == "no_persons_found" then - t = nonpersonsfoundTag - end - if t ~= "" and t ~= nil then - dt.print_log ("ImgId:" .. img.id .. " Tag:".. t) - -- Create tag if it does not exists - local tag = dt.tags.create (t) - img:attach_tag (tag) + img = image_table[file] + if img == nil then + dt.print_log("Face recognition: Ignoring face recognition entry: " .. file) + else + for t,_ in pairs (tags) do + -- Check if image is ignored + if ignoreByTag (img, ignoreTags) then + dt.print_log("Face recognition: Ignoring image with ID " .. img.id) + else + -- Check of unrecognized unknown_person + if t == "unknown_person" then + t = unknownTag + end + -- Check of unrecognized no_persons_found + if t == "no_persons_found" then + t = nonpersonsfoundTag + end + if t ~= "" and t ~= nil then + dt.print_log ("ImgId:" .. img.id .. " Tag:".. t) + -- Create tag if it does not exist + if tags_list[t] == nil then + tag = dt.tags.create (t) + tags_list[t] = tag + else + tag = tags_list[t] end + img:attach_tag (tag) end end end end end - dt.print(_("face recognition complete")) cleanup(img_list) + dt.print_log("img_list cleaned-up") + dt.print_log("face recognition complete") + dt.print(_("face recognition complete")) else dt.print(_("image export failed")) return @@ -321,8 +334,6 @@ local function face_recognition () dt.print(_("no images selected")) return end - - end -- build the interface @@ -376,7 +387,7 @@ fc.known_image_path = dt.new_widget("file_chooser_button"){ is_directory = true, changed_callback = function(this) dt.preferences.write(MODULE, "known_image_path", "directory", this.value) - end +end } fc.export_format = dt.new_widget("combobox"){ @@ -403,9 +414,9 @@ fc.height = dt.new_widget("entry"){ fc.execute = dt.new_widget("button"){ label = "detect faces", - clicked_callback = function(this) + clicked_callback = function(this) face_recognition() - end +end } local widgets = { @@ -422,14 +433,14 @@ local widgets = { if dt.configuration.running_os == "windows" or dt.configuration.running_os == "macos" then table.insert(widgets, df.executable_path_widget({"face_recognition"})) end -table.insert(widgets, dt.new_widget("section_label"){ label = _("processing options")}) -table.insert(widgets, fc.tolerance) -table.insert(widgets, fc.num_cores) -table.insert(widgets, fc.export_format) -table.insert(widgets, dt.new_widget("box"){ - orientation = "horizontal", - dt.new_widget("label"){ label = _("width ")}, - fc.width, + table.insert(widgets, dt.new_widget("section_label"){ label = _("processing options")}) + table.insert(widgets, fc.tolerance) + table.insert(widgets, fc.num_cores) + table.insert(widgets, fc.export_format) + table.insert(widgets, dt.new_widget("box"){ + orientation = "horizontal", + dt.new_widget("label"){ label = _("width ")}, + fc.width, }) table.insert(widgets, dt.new_widget("box"){ orientation = "horizontal", @@ -439,18 +450,13 @@ table.insert(widgets, dt.new_widget("box"){ table.insert(widgets, fc.execute) fc.widget = dt.new_widget("box"){ - orientation = vertical, - reset_callback = function(this) + orientation = vertical, + reset_callback = function(this) reset_preferences() - end, - table.unpack(widgets), + end, + table.unpack(widgets), } ---fc.tolerance.value = dt.preferences.read(MODULE, "tolerance", "float") - --- Register ---dt.register_storage("module_face_recognition", _("Face recognition"), show_status, face_recognition) - dt.register_lib( "face_recognition", -- Module name _("face recognition"), -- Visible name From 8c75b9316dad27bdf7e06b0a801628527b7cffc9 Mon Sep 17 00:00:00 2001 From: Piter Dias Date: Thu, 16 Apr 2020 01:46:45 -0300 Subject: [PATCH 032/445] Rollback some indentation changes --- contrib/face_recognition.lua | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/contrib/face_recognition.lua b/contrib/face_recognition.lua index 64fefeae..de98f0b3 100644 --- a/contrib/face_recognition.lua +++ b/contrib/face_recognition.lua @@ -387,7 +387,7 @@ fc.known_image_path = dt.new_widget("file_chooser_button"){ is_directory = true, changed_callback = function(this) dt.preferences.write(MODULE, "known_image_path", "directory", this.value) -end + end } fc.export_format = dt.new_widget("combobox"){ @@ -414,9 +414,9 @@ fc.height = dt.new_widget("entry"){ fc.execute = dt.new_widget("button"){ label = "detect faces", - clicked_callback = function(this) + clicked_callback = function(this) face_recognition() -end + end } local widgets = { @@ -433,14 +433,14 @@ local widgets = { if dt.configuration.running_os == "windows" or dt.configuration.running_os == "macos" then table.insert(widgets, df.executable_path_widget({"face_recognition"})) end - table.insert(widgets, dt.new_widget("section_label"){ label = _("processing options")}) - table.insert(widgets, fc.tolerance) - table.insert(widgets, fc.num_cores) - table.insert(widgets, fc.export_format) - table.insert(widgets, dt.new_widget("box"){ - orientation = "horizontal", - dt.new_widget("label"){ label = _("width ")}, - fc.width, +table.insert(widgets, dt.new_widget("section_label"){ label = _("processing options")}) +table.insert(widgets, fc.tolerance) +table.insert(widgets, fc.num_cores) +table.insert(widgets, fc.export_format) +table.insert(widgets, dt.new_widget("box"){ + orientation = "horizontal", + dt.new_widget("label"){ label = _("width ")}, + fc.width, }) table.insert(widgets, dt.new_widget("box"){ orientation = "horizontal", @@ -450,11 +450,11 @@ table.insert(widgets, dt.new_widget("box"){ table.insert(widgets, fc.execute) fc.widget = dt.new_widget("box"){ - orientation = vertical, - reset_callback = function(this) + orientation = vertical, + reset_callback = function(this) reset_preferences() - end, - table.unpack(widgets), + end, + table.unpack(widgets), } dt.register_lib( From 91ab85c82503dfa0a20a0ef10307815b09a59faa Mon Sep 17 00:00:00 2001 From: preklov <63585095+preklov@users.noreply.github.com> Date: Thu, 16 Apr 2020 14:07:41 +0200 Subject: [PATCH 033/445] Update OpenInExplorer.lua --- contrib/OpenInExplorer.lua | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/contrib/OpenInExplorer.lua b/contrib/OpenInExplorer.lua index d9652fa9..2766fb2d 100644 --- a/contrib/OpenInExplorer.lua +++ b/contrib/OpenInExplorer.lua @@ -54,11 +54,11 @@ end local act_os = dt.configuration.running_os local PS = act_os == "windows" and "\\" or "/" ---Detect OS and modify accordingly-- +--Detect OS and quit if not one of macOS, Windows or Linux-- local proper_install = true if act_os ~= "macos" and act_os ~= "windows" and act_os ~= "linux" then proper_install = false - dt.print_error(_('OpenInExplorer plug-in only supports Windows and Linux at this time')) + dt.print_error(_('OpenInExplorer plug-in only supports macOS, Windows and Linux at this time')) return end @@ -72,13 +72,17 @@ fmng_cmd.windows = 'explorer.exe /select, ' local function open_in_fmanager(os, fmcmd) local images = dt.gui.selection() local curr_image = "" + local run_cmd = "" if #images == 0 then dt.print(_('Please select an image')) elseif #images <= 15 then - for _,image in pairs(images) do - curr_image = df.sanitize_filename(image.path..PS..image.filename) - local run_cmd = fmcmd..curr_image - if os == 'linux' then run_cmd = run_cmd .. [[ ""]] end + for _,image in pairs(images) do + curr_image = image.path..PS..image.filename + if os == 'linux' then + run_cmd = fmcmd .. df.sanitize_filename("file://"..curr_image) .. [[ ""]] + else + run_cmd = fmcmd .. df.sanitize_filename(curr_image) + end dt.print_log("OpenInExplorer run_cmd = "..run_cmd) resp = dsys.external_command(run_cmd) end @@ -91,7 +95,7 @@ end -- GUI -- if proper_install then dt.gui.libs.image.register_action( - _("Show in file explorer"), + _("show in file explorer"), function() open_in_fmanager(act_os, fmng_cmd[act_os]) end, _("Opens File Explorer at the selected image's location") ) From 33b99a97e4af3d6ae13b43f420c6d9a1d75a1702 Mon Sep 17 00:00:00 2001 From: Noah Date: Thu, 16 Apr 2020 17:51:09 -0700 Subject: [PATCH 034/445] initial module minus style picker --- contrib/exportLUT.lua | 131 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 contrib/exportLUT.lua diff --git a/contrib/exportLUT.lua b/contrib/exportLUT.lua new file mode 100644 index 00000000..c2688ed3 --- /dev/null +++ b/contrib/exportLUT.lua @@ -0,0 +1,131 @@ +--[[ + This file is part of darktable, + copyright (c) 2016 Tobias Jakobs + + darktable is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + darktable is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with darktable. If not, see . +]] +--[[ + +USAGE +* require this script from your main lua file + To do this add this line to the file .config/darktable/luarc: +require "moduleExample" + +* it creates a new example lighttable module + +More informations about building user interface elements: +https://www.darktable.org/usermanual/ch09.html.php#lua_gui_example +And about new_widget here: +https://www.darktable.org/lua-api/index.html.php#darktable_new_widget +]] + +local dt = require "darktable" +local du = require "lib/dtutils" + +du.check_min_api_version("3.0.0", "moduleExample") + +-- add a new lib + +local combobox = dt.new_widget("combobox"){label = "on conflict", value = 1, "skip", "overwrite"} + +--https://www.darktable.org/lua-api/ar01s02s54.html.php + +local file_chooser_button = dt.new_widget("file_chooser_button") +{ + title = "Identity_file_chooser", -- The title of the window when choosing a file + value = "", -- The currently selected file + is_directory = false -- True if the file chooser button only allows directories to be selecte +} + +local export_chooser_button = dt.new_widget("file_chooser_button") +{ + title = "Export_location_chooser", -- The title of the window when choosing a file + value = "", -- The currently selected file + is_directory = true -- True if the file chooser button only allows directories to be selecte +} + +local identity_label = dt.new_widget("label"){ + label = "choose the identity haldclut file" +} + +local output_label = dt.new_widget("label"){ + label = "choose the output location" +} + +local separator = dt.new_widget("separator"){} + +if (dt.configuration.api_version_major >= 6) then + local section_label = dt.new_widget("section_label") + { + label = "MySectionLabel" + } + + dt.register_lib( + "export haldclut", -- Module name + "export haldclut", -- name + true, -- expandable + false, -- resetable + {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, -- containers + identity_label, + file_chooser_button, + output_label, + export_chooser_button, + combobox, + separator, + dt.new_widget("box") -- widget + { + orientation = "vertical", + dt.new_widget("button") + { + label = "export", + clicked_callback = function (_) + dt.print("Button clicked") + end + }, + section_label + }, + nil,-- view_enter + nil -- view_leave + ) +else + dt.register_lib( + "export haldclut", -- Module name + "export haldclut", -- name + true, -- expandable + false, -- resetable + {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, -- containers + dt.new_widget("box") -- widget + { + orientation = "vertical", + identity_label, + file_chooser_button, + output_label, + export_chooser_button, + combobox, + separator, + dt.new_widget("button") + { + label = "export", + clicked_callback = function (_) + dt.print("Button clicked") + end + } + }, + nil,-- view_enter + nil -- view_leave + ) +end + +-- vim: shiftwidth=2 expandtab tabstop=2 cindent syntax=lua +-- kate: hl Lua; From 792e782e8c101f7a333b583674feb4aaa81e8b37 Mon Sep 17 00:00:00 2001 From: Noah Date: Thu, 16 Apr 2020 22:27:57 -0700 Subject: [PATCH 035/445] basic frontend --- contrib/exportLUT.lua | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/contrib/exportLUT.lua b/contrib/exportLUT.lua index c2688ed3..adb05340 100644 --- a/contrib/exportLUT.lua +++ b/contrib/exportLUT.lua @@ -33,7 +33,7 @@ https://www.darktable.org/lua-api/index.html.php#darktable_new_widget local dt = require "darktable" local du = require "lib/dtutils" -du.check_min_api_version("3.0.0", "moduleExample") +du.check_min_api_version("3.0.0", "exportLUT") -- add a new lib @@ -63,7 +63,27 @@ local output_label = dt.new_widget("label"){ label = "choose the output location" } -local separator = dt.new_widget("separator"){} +local separator = dt.new_widget("separator"){ + +} + +local function create_lut(style, haldclut) + haldclut.reset + dt.styles.apply(style, haldclut) +end + +local function export_lut(haldclut) + +end + +local function export_luts() + identity = dt.database.import(file_chooser_button) + for style_num, style in ipairs(dt.styles) do + identity = create_lut(style, identity) + export_lut(identity) + dt.print(style.name) + end +end if (dt.configuration.api_version_major >= 6) then local section_label = dt.new_widget("section_label") @@ -117,9 +137,7 @@ else dt.new_widget("button") { label = "export", - clicked_callback = function (_) - dt.print("Button clicked") - end + clicked_callback = export_luts } }, nil,-- view_enter From fe97e2965484384122bbdd8931918ff432b27d63 Mon Sep 17 00:00:00 2001 From: Noah Date: Thu, 16 Apr 2020 22:59:33 -0700 Subject: [PATCH 036/445] Working? version --- contrib/exportLUT.lua | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/contrib/exportLUT.lua b/contrib/exportLUT.lua index adb05340..35981ab2 100644 --- a/contrib/exportLUT.lua +++ b/contrib/exportLUT.lua @@ -35,12 +35,12 @@ local du = require "lib/dtutils" du.check_min_api_version("3.0.0", "exportLUT") --- add a new lib +-- Thanks Kevin Ertel for this trick +local os_path_seperator = '/' +if dt.configuration.running_os == 'windows' then os_path_seperator = '\\' end local combobox = dt.new_widget("combobox"){label = "on conflict", value = 1, "skip", "overwrite"} ---https://www.darktable.org/lua-api/ar01s02s54.html.php - local file_chooser_button = dt.new_widget("file_chooser_button") { title = "Identity_file_chooser", -- The title of the window when choosing a file @@ -64,24 +64,20 @@ local output_label = dt.new_widget("label"){ } local separator = dt.new_widget("separator"){ - } -local function create_lut(style, haldclut) - haldclut.reset - dt.styles.apply(style, haldclut) -end - -local function export_lut(haldclut) - -end - local function export_luts() - identity = dt.database.import(file_chooser_button) + identity = dt.database.import(file_chooser_button.value) for style_num, style in ipairs(dt.styles) do - identity = create_lut(style, identity) - export_lut(identity) - dt.print(style.name) + + identity:reset() + dt.styles.apply(style, identity) + + io_lut = dt.new_format("png") + dt.print(export_chooser_button.value .. os_path_seperator .. style.name) + io_lut:write_image(identity, export_chooser_button.value .. os_path_seperator .. style.name) + + dt.print(export_chooser_button.value .. os_path_seperator .. style.name) end end From 28b9073010eb5cf26281a18ed057d10467ab0994 Mon Sep 17 00:00:00 2001 From: Noah Date: Thu, 16 Apr 2020 23:42:51 -0700 Subject: [PATCH 037/445] Code and UI cleanup --- contrib/exportLUT.lua | 111 ++++++++++++++++-------------------------- 1 file changed, 41 insertions(+), 70 deletions(-) diff --git a/contrib/exportLUT.lua b/contrib/exportLUT.lua index 35981ab2..ab63fcee 100644 --- a/contrib/exportLUT.lua +++ b/contrib/exportLUT.lua @@ -1,6 +1,6 @@ --[[ This file is part of darktable, - copyright (c) 2016 Tobias Jakobs + copyright (c) 2020 Noah Clarke darktable is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -16,18 +16,14 @@ along with darktable. If not, see . ]] --[[ +Add the following line to .config/darktable/luarc to enable this lightable module: + require "exportLut" -USAGE -* require this script from your main lua file - To do this add this line to the file .config/darktable/luarc: -require "moduleExample" +Given a haldCLUT identity file this script generates haldCLUTS from all the user's +styles and exports them to a location of their choosing. -* it creates a new example lighttable module - -More informations about building user interface elements: -https://www.darktable.org/usermanual/ch09.html.php#lua_gui_example -And about new_widget here: -https://www.darktable.org/lua-api/index.html.php#darktable_new_widget +Warning: during export if a naming collision occurs the older file is automatically +overwritten silently. ]] local dt = require "darktable" @@ -35,24 +31,20 @@ local du = require "lib/dtutils" du.check_min_api_version("3.0.0", "exportLUT") --- Thanks Kevin Ertel for this trick +-- Thanks Kevin Ertel for this bit local os_path_seperator = '/' if dt.configuration.running_os == 'windows' then os_path_seperator = '\\' end -local combobox = dt.new_widget("combobox"){label = "on conflict", value = 1, "skip", "overwrite"} - -local file_chooser_button = dt.new_widget("file_chooser_button") -{ - title = "Identity_file_chooser", -- The title of the window when choosing a file - value = "", -- The currently selected file - is_directory = false -- True if the file chooser button only allows directories to be selecte +local file_chooser_button = dt.new_widget("file_chooser_button"){ + title = "Identity_file_chooser", + value = "", + is_directory = false } -local export_chooser_button = dt.new_widget("file_chooser_button") -{ - title = "Export_location_chooser", -- The title of the window when choosing a file - value = "", -- The currently selected file - is_directory = true -- True if the file chooser button only allows directories to be selecte +local export_chooser_button = dt.new_widget("file_chooser_button"){ + title = "Export_location_chooser", + value = "", + is_directory = true } local identity_label = dt.new_widget("label"){ @@ -63,7 +55,9 @@ local output_label = dt.new_widget("label"){ label = "choose the output location" } -local separator = dt.new_widget("separator"){ +local export_button = dt.new_widget("button"){ + label = "export", + clicked_callback = export_luts } local function export_luts() @@ -74,72 +68,49 @@ local function export_luts() dt.styles.apply(style, identity) io_lut = dt.new_format("png") - dt.print(export_chooser_button.value .. os_path_seperator .. style.name) - io_lut:write_image(identity, export_chooser_button.value .. os_path_seperator .. style.name) - - dt.print(export_chooser_button.value .. os_path_seperator .. style.name) + dt.print("Exporting: " .. export_chooser_button.value .. os_path_seperator .. style.name .. ".png") + io_lut:write_image(identity, export_chooser_button.value .. os_path_seperator .. style.name .. ".png") end + identity:reset() end if (dt.configuration.api_version_major >= 6) then - local section_label = dt.new_widget("section_label") - { - label = "MySectionLabel" - } dt.register_lib( - "export haldclut", -- Module name - "export haldclut", -- name - true, -- expandable - false, -- resetable - {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, -- containers + "export haldclut", + "export haldclut", + true, + false, + {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, identity_label, file_chooser_button, output_label, export_chooser_button, - combobox, - separator, - dt.new_widget("box") -- widget + dt.new_widget("box") { orientation = "vertical", - dt.new_widget("button") - { - label = "export", - clicked_callback = function (_) - dt.print("Button clicked") - end - }, - section_label + export_button }, - nil,-- view_enter - nil -- view_leave + nil, + nil ) else dt.register_lib( - "export haldclut", -- Module name - "export haldclut", -- name - true, -- expandable - false, -- resetable - {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, -- containers - dt.new_widget("box") -- widget + "export haldclut", + "export haldclut", + true, + false, + {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, + dt.new_widget("box") { orientation = "vertical", identity_label, file_chooser_button, output_label, export_chooser_button, - combobox, - separator, - dt.new_widget("button") - { - label = "export", - clicked_callback = export_luts - } + export_button }, - nil,-- view_enter - nil -- view_leave + nil, + nil ) -end - --- vim: shiftwidth=2 expandtab tabstop=2 cindent syntax=lua --- kate: hl Lua; +end \ No newline at end of file From 286ef7766302819b90b6d892afe462d110cefbf3 Mon Sep 17 00:00:00 2001 From: Noah Date: Sun, 19 Apr 2020 00:36:47 -0700 Subject: [PATCH 038/445] Some error checking and warnings --- contrib/exportLUT.lua | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/contrib/exportLUT.lua b/contrib/exportLUT.lua index ab63fcee..65a4f57d 100644 --- a/contrib/exportLUT.lua +++ b/contrib/exportLUT.lua @@ -55,25 +55,33 @@ local output_label = dt.new_widget("label"){ label = "choose the output location" } -local export_button = dt.new_widget("button"){ - label = "export", - clicked_callback = export_luts +local warning_label = dt.new_widget("label"){ + label = "WARNING: files may be silently overwritten" } local function export_luts() identity = dt.database.import(file_chooser_button.value) - for style_num, style in ipairs(dt.styles) do - + if(type(identity) ~= "userdata") then + dt.print("Invalid identity lut file") + else + for style_num, style in ipairs(dt.styles) do + + identity:reset() + dt.styles.apply(style, identity) + + io_lut = dt.new_format("png") + dt.print("Exporting: " .. export_chooser_button.value .. os_path_seperator .. style.name .. ".png") + io_lut:write_image(identity, export_chooser_button.value .. os_path_seperator .. style.name .. ".png") + end identity:reset() - dt.styles.apply(style, identity) - - io_lut = dt.new_format("png") - dt.print("Exporting: " .. export_chooser_button.value .. os_path_seperator .. style.name .. ".png") - io_lut:write_image(identity, export_chooser_button.value .. os_path_seperator .. style.name .. ".png") end - identity:reset() end +local export_button = dt.new_widget("button"){ + label = "export", + clicked_callback = export_luts +} + if (dt.configuration.api_version_major >= 6) then dt.register_lib( @@ -86,6 +94,7 @@ if (dt.configuration.api_version_major >= 6) then file_chooser_button, output_label, export_chooser_button, + warning_label, dt.new_widget("box") { orientation = "vertical", @@ -108,6 +117,7 @@ else file_chooser_button, output_label, export_chooser_button, + warning_label, export_button }, nil, From 90880ff4d19c99f43f9b479818cf267850a1c29c Mon Sep 17 00:00:00 2001 From: preklov <63585095+preklov@users.noreply.github.com> Date: Mon, 20 Apr 2020 16:03:25 +0200 Subject: [PATCH 039/445] Delete OpenInExplorer.lua --- contrib/OpenInExplorer.lua | 102 ------------------------------------- 1 file changed, 102 deletions(-) delete mode 100644 contrib/OpenInExplorer.lua diff --git a/contrib/OpenInExplorer.lua b/contrib/OpenInExplorer.lua deleted file mode 100644 index 2766fb2d..00000000 --- a/contrib/OpenInExplorer.lua +++ /dev/null @@ -1,102 +0,0 @@ ---[[ -OpenInExplorer plugin for darktable - - copyright (c) 2018 Kevin Ertel - Update 2020: copyright (c) 2020 Volker Lenhardt - - darktable is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - darktable is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with darktable. If not, see . -]] - ---[[About this plugin -This plugin adds the module "OpenInExplorer" to darktable's lighttable view - -----REQUIRED SOFTWARE---- -Apple macOS, Microsoft Windows or Linux with installed Nautilus - -----USAGE---- -Install: (see here for more detail: https://github.com/darktable-org/lua-scripts ) - 1) Copy this file in to your "lua/contrib" folder where all other scripts reside. - 2) Require this file in your luarc file, as with any other dt plug-in - -Select the photo(s) you wish to find in explorer and press "Go to Folder". -A file explorer window will be opened for each selected file at the file's location; the file will be highlighted. - -----KNOWN ISSUES---- -Under macOS the file manager Finder opens only once and selects the file name of the last in DT selected image. -]] - -local dt = require "darktable" -local du = require "lib/dtutils" -local df = require "lib/dtutils.file" -local dsys = require "lib/dtutils.system" -local gettext = dt.gettext - ---Check API version -du.check_min_api_version("5.0.0", "OpenInExplorer") - -gettext.bindtextdomain("OpenInExplorer",dt.configuration.config_dir.."/lua/locale/") - -local function _(msgid) - return gettext.dgettext("OpenInExplorer", msgid) -end - -local act_os = dt.configuration.running_os -local PS = act_os == "windows" and "\\" or "/" - ---Detect OS and quit if not one of macOS, Windows or Linux-- -local proper_install = true -if act_os ~= "macos" and act_os ~= "windows" and act_os ~= "linux" then - proper_install = false - dt.print_error(_('OpenInExplorer plug-in only supports macOS, Windows and Linux at this time')) - return -end - ---The commands to open the OSes' file managers -local fmng_cmd = {} -fmng_cmd.linux = [[busctl --user call org.freedesktop.FileManager1 /org/freedesktop/FileManager1 org.freedesktop.FileManager1 ShowItems ass 1 ]] -fmng_cmd.macos = 'open -R ' -fmng_cmd.windows = 'explorer.exe /select, ' - ---The working function that opens the file manager with the image file name selected. -local function open_in_fmanager(os, fmcmd) - local images = dt.gui.selection() - local curr_image = "" - local run_cmd = "" - if #images == 0 then - dt.print(_('Please select an image')) - elseif #images <= 15 then - for _,image in pairs(images) do - curr_image = image.path..PS..image.filename - if os == 'linux' then - run_cmd = fmcmd .. df.sanitize_filename("file://"..curr_image) .. [[ ""]] - else - run_cmd = fmcmd .. df.sanitize_filename(curr_image) - end - dt.print_log("OpenInExplorer run_cmd = "..run_cmd) - resp = dsys.external_command(run_cmd) - end - else - dt.print(_('Please select fewer images (max 15)')) - end -end - - --- GUI -- -if proper_install then - dt.gui.libs.image.register_action( - _("show in file explorer"), - function() open_in_fmanager(act_os, fmng_cmd[act_os]) end, - _("Opens File Explorer at the selected image's location") - ) -end From b8d29ca831ebda328e16e0de575346aaa582ac92 Mon Sep 17 00:00:00 2001 From: preklov <63585095+preklov@users.noreply.github.com> Date: Mon, 20 Apr 2020 16:06:38 +0200 Subject: [PATCH 040/445] Add files via upload The new and I hope the finished version for now. --- contrib/OpenInExplorer.lua | 111 +++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 contrib/OpenInExplorer.lua diff --git a/contrib/OpenInExplorer.lua b/contrib/OpenInExplorer.lua new file mode 100644 index 00000000..d456911e --- /dev/null +++ b/contrib/OpenInExplorer.lua @@ -0,0 +1,111 @@ +--[[ +OpenInExplorer plugin for darktable + + copyright (c) 2018 Kevin Ertel + Update 2020 and macOS support by Volker Lenhardt + Linux support 2020 by Bill Ferguson + + darktable is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + darktable is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with darktable. If not, see . +]] + +--[[About this plugin +This plugin adds the module "OpenInExplorer" to darktable's lighttable view. + +----REQUIRED SOFTWARE---- +Apple macOS, Microsoft Windows or Linux + +----USAGE---- +Install: (see here for more detail: https://github.com/darktable-org/lua-scripts ) + 1) Copy this file into your "lua/contrib" folder where all other scripts reside. + 2) Require this file in your luarc file, as with any other dt plug-in + +Select the photo(s) you wish to find in your operating system's file manager and press "show in file explorer" in the "selected images" section. + +- Nautilus (Linux), Explorer (Windows), and Finder (macOS before Catalina) will open one window for each selected image at the file's location. The file name will be highlighted. + +- On macOS Catalina the Finder will open one window for each different directory. In these windows only the last one of the corresponding files will be highlighted (bug or feature?). + +- Dolphin (Linux) will open one window with tabs for the different directories. All the selected images' file names are highlighted in their respective directories. + +----KNOWN ISSUES---- +]] + +local dt = require "darktable" +local du = require "lib/dtutils" +local df = require "lib/dtutils.file" +local dsys = require "lib/dtutils.system" +local gettext = dt.gettext + +--Check API version +du.check_min_api_version("5.0.0", "OpenInExplorer") + +gettext.bindtextdomain("OpenInExplorer",dt.configuration.config_dir.."/lua/locale/") + +local function _(msgid) + return gettext.dgettext("OpenInExplorer", msgid) +end + +local act_os = dt.configuration.running_os +local PS = act_os == "windows" and "\\" or "/" + +--Detect OS and quit if it is not supported-- +local proper_install = true +if act_os ~= "macos" and act_os ~= "windows" and act_os ~= "linux" then + proper_install = false + dt.print_error(_('OpenInExplorer plug-in only supports Linux, macOS, and Windows at this time')) + return +end + +--Format strings for the commands to open the corresponding OS' file manager +local fmng_cmd = {} +fmng_cmd.linux = [[busctl --user call org.freedesktop.FileManager1 /org/freedesktop/FileManager1 org.freedesktop.FileManager1 ShowItems ass %d %s""]] +fmng_cmd.macos = 'open -Rn %s' +fmng_cmd.windows = 'explorer.exe /select, %s' + +--The working function that opens the file manager windows with the selected image file names highlighted. +local function open_in_fmanager(op_sys, fmcmd) + local images = dt.gui.selection() + local curr_image, run_cmd, file_uris = '', '', '' + if #images == 0 then + dt.print(_('Please select an image')) + elseif #images <= 15 then + for _,image in pairs(images) do + curr_image = image.path..PS..image.filename + if op_sys == 'linux' then + file_uris = file_uris .. df.sanitize_filename("file://" .. curr_image) .. " " + dt.print_log("file_uris is " .. file_uris) + else + run_cmd = string.format(fmcmd, df.sanitize_filename(curr_image)) + dt.print_log("OpenInExplorer run_cmd = "..run_cmd) + dsys.external_command(run_cmd) + end + end + if op_sys == 'linux' then + run_cmd = string.format(fmcmd, #images, file_uris) + dt.print_log("OpenInExplorer run_cmd = "..run_cmd) + dsys.external_command(run_cmd) + end + else + dt.print(_('Please select fewer images (max 15)')) + end +end + +-- GUI -- +if proper_install then + dt.gui.libs.image.register_action( + _("show in file explorer"), + function() open_in_fmanager(act_os, fmng_cmd[act_os]) end, + _("Opens the file manager at the selected image's location") + ) +end From a3f57665a9fbfdf82a24da42a4a6f0030050def5 Mon Sep 17 00:00:00 2001 From: preklov <63585095+preklov@users.noreply.github.com> Date: Mon, 20 Apr 2020 16:13:05 +0200 Subject: [PATCH 041/445] Delete OpenInExplorer.po --- locale/de_DE/LC_MESSAGES/OpenInExplorer.po | 38 ---------------------- 1 file changed, 38 deletions(-) delete mode 100644 locale/de_DE/LC_MESSAGES/OpenInExplorer.po diff --git a/locale/de_DE/LC_MESSAGES/OpenInExplorer.po b/locale/de_DE/LC_MESSAGES/OpenInExplorer.po deleted file mode 100644 index 3cb5901b..00000000 --- a/locale/de_DE/LC_MESSAGES/OpenInExplorer.po +++ /dev/null @@ -1,38 +0,0 @@ -# OpenInExplorer Darktable Plug-In. -# Copyright (C) 2020 Volker Lenhardt -# This file is distributed under the same license as the PACKAGE package. -# Volker Lenhardt , 2020. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: OpenInExplorer\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-04-14 14:35+0200\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: Volker Lenhardt \n" -"Language-Team: LANGUAGE \n" -"Language: de_DE\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" - -#: OpenInExplorer.lua:59 -msgid "OpenInExplorer plug-in only supports Windows and Linux at this time" -msgstr "OpenInExplorer-Plug-in kann nur unter macOS, Linux oder Windows laufen" - -#: OpenInExplorer.lua:75 -msgid "Please select an image" -msgstr "Bitte mindestens 1 Bild auswählen" - -#: OpenInExplorer.lua:85 -msgid "Please select fewer images (max 15)" -msgstr "Bitte nicht mehr als 15 Bilder auswählen" - -#: OpenInExplorer.lua:93 -msgid "Show in file explorer" -msgstr "Im Dateimanager anzeigen" - -#: OpenInExplorer.lua:95 -msgid "Opens File Explorer at the selected image's location" -msgstr "Öffnet den Dateimanager mit dem ausgewählten Dateinamen" From c1b59256be457bc6e5482a40c67e5747431a6a77 Mon Sep 17 00:00:00 2001 From: preklov <63585095+preklov@users.noreply.github.com> Date: Mon, 20 Apr 2020 16:14:32 +0200 Subject: [PATCH 042/445] Add files via upload The translation of the finished version of OpenInExplorer.lua --- locale/de_DE/LC_MESSAGES/OpenInExplorer.po | 39 ++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 locale/de_DE/LC_MESSAGES/OpenInExplorer.po diff --git a/locale/de_DE/LC_MESSAGES/OpenInExplorer.po b/locale/de_DE/LC_MESSAGES/OpenInExplorer.po new file mode 100644 index 00000000..07d451ab --- /dev/null +++ b/locale/de_DE/LC_MESSAGES/OpenInExplorer.po @@ -0,0 +1,39 @@ +# OpenInExplorer Darktable Plug-In. +# Copyright (C) 2020 Volker Lenhardt +# This file is distributed under the same license as the PACKAGE package. +# Volker Lenhardt , 2020. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: OpenInExplorer\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2020-04-19 14:43+0200\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Volker Lenhardt \n" +"Language-Team: LANGUAGE \n" +"Language: de_DE\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: OpenInExplorer.lua:64 +msgid "" +"OpenInExplorer plug-in only supports Linux, macOS, and Windows at this time" +msgstr "OpenInExplorer-Plug-in kann nur auf macOS, Linux oder Windows laufen" + +#: OpenInExplorer.lua:79 +msgid "Please select an image" +msgstr "Es wurde kein Bild ausgewählt" + +#: OpenInExplorer.lua:98 +msgid "Please select fewer images (max 15)" +msgstr "Bitte nicht mehr als 15 Bilder auswählen" + +#: OpenInExplorer.lua:105 +msgid "show in file explorer" +msgstr "im Dateimanager anzeigen" + +#: OpenInExplorer.lua:107 +msgid "Opens the file manager at the selected image's location" +msgstr "Öffnet den Dateimanager an der Position des ausgewählten Bildes" From 71207e8f57cb59e1e75b52d363b559cb72986938 Mon Sep 17 00:00:00 2001 From: Piter Dias Date: Sat, 25 Apr 2020 19:57:14 -0300 Subject: [PATCH 043/445] 1 - face_recognition.lua fails to run in a fresh installation of darktable. It is due to pull request #221 where reset_preferences() and save_preferences() are called before being defined. This is actually a expected behavior because compiles script is one pass instead of two pass (like some other languages, like C). Moving a small piece of preferences setting code to the end of file solves the issue, because all required objects and functions are defined at that point. 2 - Add some more logs --- contrib/face_recognition.lua | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/contrib/face_recognition.lua b/contrib/face_recognition.lua index de98f0b3..449b3996 100644 --- a/contrib/face_recognition.lua +++ b/contrib/face_recognition.lua @@ -66,14 +66,6 @@ local function _(msgid) return gettext.dgettext("face_recognition", msgid) end --- preferences - -if not dt.preferences.read(MODULE, "initialized", "bool") then - reset_preferences() - save_preferences() - dt.preferences.write(MODULE, "initialized", "bool", true) -end - local function build_image_table(images) local image_table = {} local file_extension = "" @@ -242,7 +234,10 @@ local function face_recognition () -- Get path of exported images local path = df.get_path (img_list[1]) + dt.print_log ("Face recognition: Path to known faces: " .. knownPath) dt.print_log ("Face recognition: Path to unknown images: " .. path) + dt.print_log ("Face recognition: Tag used for unknown faces: " .. unknownTag) + dt.print_log ("Face recognition: Tag used if non person is found: " .. nonpersonsfoundTag) os.setlocale("C") local tolerance = dt.preferences.read(MODULE, "tolerance", "float") @@ -470,5 +465,13 @@ dt.register_lib( fc.tolerance.value = dt.preferences.read(MODULE, "tolerance", "float") +-- preferences + +if not dt.preferences.read(MODULE, "initialized", "bool") then + reset_preferences() + save_preferences() + dt.preferences.write(MODULE, "initialized", "bool", true) +end + -- -- vim: shiftwidth=2 expandtab tabstop=2 cindent syntax=lua From 01184bee721d217dc1d1e29d60e7e40bded6756f Mon Sep 17 00:00:00 2001 From: Noah Date: Mon, 4 May 2020 23:58:52 -0700 Subject: [PATCH 044/445] Updated API version check and forced PNG to 16 bits --- contrib/exportLUT.lua | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/contrib/exportLUT.lua b/contrib/exportLUT.lua index 65a4f57d..e2f599e7 100644 --- a/contrib/exportLUT.lua +++ b/contrib/exportLUT.lua @@ -29,7 +29,7 @@ overwritten silently. local dt = require "darktable" local du = require "lib/dtutils" -du.check_min_api_version("3.0.0", "exportLUT") +du.check_min_api_version("5.0.0", "exportLUT") -- Thanks Kevin Ertel for this bit local os_path_seperator = '/' @@ -70,8 +70,9 @@ local function export_luts() dt.styles.apply(style, identity) io_lut = dt.new_format("png") - dt.print("Exporting: " .. export_chooser_button.value .. os_path_seperator .. style.name .. ".png") + io_lut.bpp = 16 io_lut:write_image(identity, export_chooser_button.value .. os_path_seperator .. style.name .. ".png") + dt.print("Exported: " .. export_chooser_button.value .. os_path_seperator .. style.name .. ".png") end identity:reset() end From 5709cfebd4b6f1304732b509e0905c23e48d944d Mon Sep 17 00:00:00 2001 From: Noah Date: Tue, 5 May 2020 00:02:47 -0700 Subject: [PATCH 045/445] Remove unneeded API check --- contrib/exportLUT.lua | 51 ++++++++++++------------------------------- 1 file changed, 14 insertions(+), 37 deletions(-) diff --git a/contrib/exportLUT.lua b/contrib/exportLUT.lua index e2f599e7..da187f1b 100644 --- a/contrib/exportLUT.lua +++ b/contrib/exportLUT.lua @@ -83,45 +83,22 @@ local export_button = dt.new_widget("button"){ clicked_callback = export_luts } -if (dt.configuration.api_version_major >= 6) then - - dt.register_lib( - "export haldclut", - "export haldclut", - true, - false, - {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, +dt.register_lib( + "export haldclut", + "export haldclut", + true, + false, + {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, + dt.new_widget("box") + { + orientation = "vertical", identity_label, file_chooser_button, output_label, export_chooser_button, warning_label, - dt.new_widget("box") - { - orientation = "vertical", - export_button - }, - nil, - nil - ) -else - dt.register_lib( - "export haldclut", - "export haldclut", - true, - false, - {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, - dt.new_widget("box") - { - orientation = "vertical", - identity_label, - file_chooser_button, - output_label, - export_chooser_button, - warning_label, - export_button - }, - nil, - nil - ) -end \ No newline at end of file + export_button + }, + nil, + nil +) \ No newline at end of file From 4455347930947099fa2f67a9eb86d05ed5d08cf3 Mon Sep 17 00:00:00 2001 From: Noah Date: Wed, 6 May 2020 01:14:34 -0700 Subject: [PATCH 046/445] Exporting luts now creates a job --- contrib/exportLUT.lua | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/contrib/exportLUT.lua b/contrib/exportLUT.lua index da187f1b..eaacf449 100644 --- a/contrib/exportLUT.lua +++ b/contrib/exportLUT.lua @@ -59,21 +59,38 @@ local warning_label = dt.new_widget("label"){ label = "WARNING: files may be silently overwritten" } +local function end_job(job) + job.valid = false +end + local function export_luts() - identity = dt.database.import(file_chooser_button.value) + local identity = dt.database.import(file_chooser_button.value) if(type(identity) ~= "userdata") then dt.print("Invalid identity lut file") else + local job = dt.gui.create_job('Exporting styles as haldCLUTs', true, end_job) + + local size = 1 + + for style_num, style in ipairs(dt.styles) do + size = size + 1 + end + + local count = 0 for style_num, style in ipairs(dt.styles) do identity:reset() dt.styles.apply(style, identity) - io_lut = dt.new_format("png") + local io_lut = dt.new_format("png") io_lut.bpp = 16 io_lut:write_image(identity, export_chooser_button.value .. os_path_seperator .. style.name .. ".png") + count = count + 1 + job.percent = count / size dt.print("Exported: " .. export_chooser_button.value .. os_path_seperator .. style.name .. ".png") end + dt.print("Done exporting haldCLUTs") + job.valid = false identity:reset() end end From d579b257a874a337801fc5ac7b72ee1d9201dce5 Mon Sep 17 00:00:00 2001 From: Stephan Bolten Date: Wed, 6 May 2020 18:57:50 +0200 Subject: [PATCH 047/445] Added "People" category to tag routine Added field in GUI to provide "People" category Changed label of tag category Changed Tooltip --- contrib/face_recognition.lua | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/contrib/face_recognition.lua b/contrib/face_recognition.lua index 449b3996..89b20417 100644 --- a/contrib/face_recognition.lua +++ b/contrib/face_recognition.lua @@ -139,6 +139,7 @@ local function save_preferences() dt.preferences.write(MODULE, "unknown_tag", "string", fc.unknown_tag.text) dt.preferences.write(MODULE, "no_persons_found_tag", "string", fc.no_persons_found_tag.text) dt.preferences.write(MODULE, "ignore_tags", "string", fc.ignore_tags.text) + dt.preferences.write(MODULE, "category_tags", "string", fc.category_tags.text) dt.preferences.write(MODULE, "known_image_path", "directory", fc.known_image_path.value) local val = fc.tolerance.value val = string.gsub(tostring(val), ",", ".") @@ -153,6 +154,7 @@ local function reset_preferences() fc.unknown_tag.text = "unknown_person" fc.no_persons_found_tag.text = "no_persons_found" fc.ignore_tags.text = "" + fc.category_tags.text = "People" fc.known_image_path.value = dt.configuration.config_dir .. "/face_recognition" fc.tolerance.value = 0.6 fc.num_cores.value = -1 @@ -203,6 +205,7 @@ local function face_recognition () local knownPath = dt.preferences.read(MODULE, "known_image_path", "directory") local nrCores = dt.preferences.read(MODULE, "num_cores", "integer") local ignoreTagString = dt.preferences.read(MODULE, "ignore_tags", "string") + local categoryTagString = dt.preferences.read(MODULE, "category_tags", "string") local unknownTag = dt.preferences.read(MODULE, "unknown_tag", "string") local nonpersonsfoundTag = dt.preferences.read(MODULE, "no_persons_found_tag", "string") @@ -303,6 +306,9 @@ local function face_recognition () t = nonpersonsfoundTag end if t ~= "" and t ~= nil then + if categoryTagString ~= "" then + t = categoryTagString .. "|" .. t + end dt.print_log ("ImgId:" .. img.id .. " Tag:".. t) -- Create tag if it does not exist if tags_list[t] == nil then @@ -351,6 +357,12 @@ fc.ignore_tags = dt.new_widget("entry"){ editable = true, } +fc.category_tags = dt.new_widget("entry"){ + text = dt.preferences.read(MODULE, "category_tags", "string"), + tooltip = _("tag category"), + editable = true, +} + fc.tolerance = dt.new_widget("slider"){ label = _("tolerance"), tooltip = ("detection tolerance - 0.6 default - lower if too many faces detected"), @@ -421,6 +433,8 @@ local widgets = { fc.no_persons_found_tag, dt.new_widget("label"){ label = _("tags of images to ignore")}, fc.ignore_tags, + dt.new_widget("label"){ label = _("tag category")}, + fc.category_tags, dt.new_widget("label"){ label = _("face data directory")}, fc.known_image_path, } From aef7363beee9a8f88fa4983c401b347ea395175e Mon Sep 17 00:00:00 2001 From: Noah Date: Wed, 6 May 2020 13:19:12 -0700 Subject: [PATCH 048/445] make 8bit not 16bit luts (extra depth uneeded) --- contrib/exportLUT.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/exportLUT.lua b/contrib/exportLUT.lua index eaacf449..25741bce 100644 --- a/contrib/exportLUT.lua +++ b/contrib/exportLUT.lua @@ -83,7 +83,7 @@ local function export_luts() dt.styles.apply(style, identity) local io_lut = dt.new_format("png") - io_lut.bpp = 16 + io_lut.bpp = 8 io_lut:write_image(identity, export_chooser_button.value .. os_path_seperator .. style.name .. ".png") count = count + 1 job.percent = count / size From 23131a301bcd2770e44b3e60c217a7b77805d229 Mon Sep 17 00:00:00 2001 From: Noah Clarke Date: Thu, 7 May 2020 12:15:31 -0700 Subject: [PATCH 049/445] Fix include path --- contrib/exportLUT.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contrib/exportLUT.lua b/contrib/exportLUT.lua index 25741bce..6d29647d 100644 --- a/contrib/exportLUT.lua +++ b/contrib/exportLUT.lua @@ -17,7 +17,7 @@ ]] --[[ Add the following line to .config/darktable/luarc to enable this lightable module: - require "exportLut" + require "contrib/exportLut" Given a haldCLUT identity file this script generates haldCLUTS from all the user's styles and exports them to a location of their choosing. @@ -118,4 +118,4 @@ dt.register_lib( }, nil, nil -) \ No newline at end of file +) From 0856858e73c164a8adcec93f42d69ce69b3ae420 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Fri, 8 May 2020 00:15:31 -0400 Subject: [PATCH 050/445] Updated comments to reflect current usage practices. Added/updated links to the online manual for each of the widgets. Added translation. Removed reference to api_major_version 6 --- examples/moduleExample.lua | 127 ++++++++++++++++--------------------- 1 file changed, 56 insertions(+), 71 deletions(-) diff --git a/examples/moduleExample.lua b/examples/moduleExample.lua index ecc2ac35..2c46a08a 100644 --- a/examples/moduleExample.lua +++ b/examples/moduleExample.lua @@ -18,9 +18,9 @@ --[[ USAGE -* require this script from your main lua file +* require this script from your luarc file To do this add this line to the file .config/darktable/luarc: -require "moduleExample" +require "examples/moduleExample" * it creates a new example lighttable module @@ -35,35 +35,54 @@ local du = require "lib/dtutils" du.check_min_api_version("3.0.0", "moduleExample") --- add a new lib -local check_button = dt.new_widget("check_button"){label = "MyCheck_button", value = true} -local combobox = dt.new_widget("combobox"){label = "MyCombobox", value = 2, "8", "16", "32"} +-- translation ---https://www.darktable.org/lua-api/ar01s02s54.html.php +-- https://www.darktable.org/lua-api/index.html#darktable_gettext +local gettext = dt.gettext + +gettext.bindtextdomain("moduleExample", dt.configuration.config_dir .. "/lua/locale/") + +local function _(msgid) + return gettext.dgettext("moduleExample", msgid) +end + + +-- https://www.darktable.org/lua-api/types_lua_check_button.html +local check_button = dt.new_widget("check_button"){label = _("MyCheck_button"), value = true} + +-- https://www.darktable.org/lua-api/types_lua_combobox.html +local combobox = dt.new_widget("combobox"){label = _("MyCombobox"), value = 2, "8", "16", "32"} + +-- https://www.darktable.org/lua-api/types_lua_entry.html local entry = dt.new_widget("entry") { text = "test", - placeholder = "placeholder", + placeholder = _("placeholder"), is_password = false, editable = true, - tooltip = "Tooltip Text", + tooltip = _("Tooltip Text"), reset_callback = function(self) self.text = "text" end } +-- https://www.darktable.org/lua-api/types_lua_file_chooser_button.html local file_chooser_button = dt.new_widget("file_chooser_button") { - title = "MyFile_chooser_button", -- The title of the window when choosing a file + title = _("MyFile_chooser_button"), -- The title of the window when choosing a file value = "", -- The currently selected file is_directory = false -- True if the file chooser button only allows directories to be selecte } +-- https://www.darktable.org/lua-api/types_lua_label.html local label = dt.new_widget("label") -label.label = "MyLabel" -- This is an alternative way to the "{}" syntax to set a property +label.label = _("MyLabel") -- This is an alternative way to the "{}" syntax to set a property +-- https://www.darktable.org/lua-api/types_lua_separator.html local separator = dt.new_widget("separator"){} + +-- https://www.darktable.org/lua-api/types_lua_slider.html local slider = dt.new_widget("slider") { - label = "MySlider", + label = _("MySlider"), soft_min = 10, -- The soft minimum value for the slider, the slider can't go beyond this point soft_max = 100, -- The soft maximum value for the slider, the slider can't go beyond this point hard_min = 0, -- The hard minimum value for the slider, the user can't manually enter a value beyond this point @@ -71,69 +90,35 @@ local slider = dt.new_widget("slider") value = 52 -- The current value of the slider } -if (dt.configuration.api_version_major >= 6) then - local section_label = dt.new_widget("section_label") +-- https://www.darktable.org/lua-api/index.html#darktable_register_lib +dt.register_lib( + "exampleModule", -- Module name + "exampleModule", -- name + true, -- expandable + false, -- resetable + {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, -- containers + -- https://www.darktable.org/lua-api/types_lua_box.html + dt.new_widget("box") -- widget { - label = "MySectionLabel" - } - - dt.register_lib( - "exampleModule", -- Module name - "exampleModule", -- name - true, -- expandable - false, -- resetable - {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, -- containers - dt.new_widget("box") -- widget + orientation = "vertical", + dt.new_widget("button") { - orientation = "vertical", - dt.new_widget("button") - { - label = "MyButton", - clicked_callback = function (_) - dt.print("Button clicked") - end - }, - check_button, - combobox, - entry, - file_chooser_button, - label, - separator, - slider, - section_label + label = _("MyButton"), + clicked_callback = function (_) + dt.print(_("Button clicked")) + end }, - nil,-- view_enter - nil -- view_leave - ) -else - dt.register_lib( - "exampleModule", -- Module name - "exampleModule", -- name - true, -- expandable - false, -- resetable - {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, -- containers - dt.new_widget("box") -- widget - { - orientation = "vertical", - dt.new_widget("button") - { - label = "MyButton", - clicked_callback = function (_) - dt.print("Button clicked") - end - }, - check_button, - combobox, - entry, - file_chooser_button, - label, - separator, - slider - }, - nil,-- view_enter - nil -- view_leave - ) -end + check_button, + combobox, + entry, + file_chooser_button, + label, + separator, + slider + }, + nil,-- view_enter + nil -- view_leave +) -- vim: shiftwidth=2 expandtab tabstop=2 cindent syntax=lua -- kate: hl Lua; From 54a66f9ab21aa78dc74197c512ab993836cd70ea Mon Sep 17 00:00:00 2001 From: Stephan Bolten Date: Sat, 9 May 2020 19:58:57 +0200 Subject: [PATCH 051/445] Category Tag default & no_person_found 1 - empty by default 2 - not added when no_person_found --- contrib/face_recognition.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contrib/face_recognition.lua b/contrib/face_recognition.lua index 89b20417..26caff60 100644 --- a/contrib/face_recognition.lua +++ b/contrib/face_recognition.lua @@ -154,7 +154,7 @@ local function reset_preferences() fc.unknown_tag.text = "unknown_person" fc.no_persons_found_tag.text = "no_persons_found" fc.ignore_tags.text = "" - fc.category_tags.text = "People" + fc.category_tags.text = "" fc.known_image_path.value = dt.configuration.config_dir .. "/face_recognition" fc.tolerance.value = 0.6 fc.num_cores.value = -1 @@ -306,7 +306,7 @@ local function face_recognition () t = nonpersonsfoundTag end if t ~= "" and t ~= nil then - if categoryTagString ~= "" then + if categoryTagString ~= "" and t ~= nonpersonsfoundTag then t = categoryTagString .. "|" .. t end dt.print_log ("ImgId:" .. img.id .. " Tag:".. t) From 4a81b560f9790e95f73e9664524d7ba52bffc33c Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sat, 23 May 2020 16:54:24 -0400 Subject: [PATCH 052/445] Changed position of script manager to the center section of the left panel at the bottom of the section. This takes care of the problem of darktable exceeding the vertical screen size and not being scrollable. --- tools/script_manager.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/script_manager.lua b/tools/script_manager.lua index e16b0cca..9759b887 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -747,7 +747,7 @@ dt.register_lib( "script manager", -- Visible name true, -- expandable false, -- resetable - {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_LEFT_BOTTOM", 100}}, -- containers + {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_LEFT_CENTER", 0}}, -- containers dt.new_widget("box") -- widget { orientation = "vertical", From a02176fc6331dd6f4c8c73fdf3b3cc98a0eb753d Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sat, 30 May 2020 20:12:39 -0400 Subject: [PATCH 053/445] Added instructions for using script_manager.lua as the luarc file. --- README.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 6b0e20f3..49551e5a 100644 --- a/README.md +++ b/README.md @@ -116,7 +116,7 @@ are met as well as providing an easy update path. Single scripts listed as stand ### snap packages -The snap version of darktable comes with lua included starting with version 2.4.3snap2. It is currently in the edge channel, but should reach the stable channel soon. +The snap version of darktable comes with lua included starting with version 2.4.3snap2. Ensure git is installed on your system. If it isn't, use the package manager to install it. Then open a terminal and: @@ -138,8 +138,6 @@ Ensure git is installed on your system. If it isn't, use the package manager to Ensure git is installed on your system. Git can be obtained from https://gitforwindows.org/, as well as other places. If you use the gitforwindows.org distribution, install the Git Bash Shell also as it will aid in debugging the scripts if necessary. Then open a command prompt and run: -Open a command prompt. - cd %LOCALAPPDATA%\darktable git clone https://github.com/darktable-org/lua-scripts.git lua @@ -154,11 +152,19 @@ You can also create or add lines to the luarc file from the command line: `echo 'require "contrib/gimp"' > ~/.config/darktable/luarc` to create the file with a gimp entry\ or `echo 'require "contrib/hugin"' >> ~/.config/darktable/luarc` to add an entry for hugin. +Alteratively you can use script_manager.lua as your luarc file. script_manager.lua provides a point and click interface for managing the lua scripts. To use it: + + ln -s $HOME/.config/darktable/lua/tools/script_manager.lua $HOME/.config/darktable/luarc + On windows from a command prompt: `echo require "contrib/gimp" > %LOCALAPPDATA%\darktable\luarc` to create the file with a gimp entry\ or `echo require "contrib/hugin" >> %LOCALAPPDATA%\darktable\luarc` to add an entry for hugin. +Alteratively you can use script_manager.lua as your luarc file. script_manager.lua provides a point and click interface for managing the lua scripts. To use it: + + copy %LOCALAPPDATA%\darktable\lua\tools\script_manager.lua %LOCALAPPDATA%\darktable\luarc + ## Disabling To disable a script open the luarc file in your text editor and insert `--` at the start of the line containing the script you wish to disable, then save the file. From 33f91af1af429500686025114fe4d49e9ab744a1 Mon Sep 17 00:00:00 2001 From: Tobias Scheck Date: Sat, 6 Jun 2020 12:39:26 +0200 Subject: [PATCH 054/445] add photils plugin --- README.md | 1 + contrib/photils.lua | 416 ++++++++++++++++++++++++++++ locale/de_DE/LC_MESSAGES/photils.po | 83 ++++++ 3 files changed, 500 insertions(+) create mode 100644 contrib/photils.lua create mode 100644 locale/de_DE/LC_MESSAGES/photils.po diff --git a/README.md b/README.md index 49551e5a..2381dbc4 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,7 @@ LabelsToTags|Yes|LMW|Apply tags based on color labels and ratings OpenInExplorer|No|LMW|Open the selected images in the system file manager passport_guide|Yes|LMW|Add passport cropping guide to darkroom crop tool pdf_slideshow|No|LM|Export images to a PDF slideshow +[photils](https://github.com/scheckmedia/photils-dt)|No|LM|Automatic tag suggestions for your images quicktag|Yes|LMW|Create shortcuts for quickly applying tags rate_group|Yes|LMW|Apply or remove a star rating from grouped images rename-tags|Yes|LMW|Change a tag name diff --git a/contrib/photils.lua b/contrib/photils.lua new file mode 100644 index 00000000..102bd4d5 --- /dev/null +++ b/contrib/photils.lua @@ -0,0 +1,416 @@ +--[[ photils Auto Tagging plugin + copyright (c) 2020 Tobias Scheck + + darktable is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + darktable is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with darktable. If not, see . +--]] + +--[[ + A darktable plugin which tries to predict keywords based on the selected image. + This plugin uses photils-cli to handle this task. Photils-cli is an application + which passes the image through a neural network and generates a feature vector. + This feature vector will be used to find similar images in a self-hosted online + database and the corresponding tags. The usage of the feature vector has this advantage + that at no time your selected image will leave the PC. Rather a representation + of the image is sent. + + ADDITIONAL SOFTWARE NEEDED FOR THIS SCRIPT + * photils-cli - https://github.com/scheckmedia/photils-cli + + USAGE + * require this script from your main lua file + To do this add this line to the file .config/darktable/luarc: + require "contrib/photils" + * Select an image + * Press "Get Tags" + * Select the tags you want from a list of suggestions + * Press "Attach .. Tags" to add the selected tags to your image +--]] + +local dt = require "darktable" +local du = require "lib/dtutils" +local df = require "lib/dtutils.file" +local dtsys = require "lib/dtutils.system" + +local MODULE_NAME = "photils" +du.check_min_api_version("5.0.0", MODULE_NAME) + +local PS = dt.configuration.running_os == "windows" and "\\" or "/" +local gettext = dt.gettext +gettext.bindtextdomain(MODULE_NAME, + dt.configuration.config_dir .. PS .. "lua" .. PS .. "locale" .. PS) + +local exporter = dt.new_format("jpeg") +exporter.quality = 80 +exporter.max_height = 224 +exporter.max_width = 224 + +-- helper functions + +local function _(msgid) + return gettext.dgettext(MODULE_NAME, msgid) +end + +local function num_keys(tbl) + local num = 0 + for _ in pairs(tbl) do num = num + 1 end + return num +end + +local function has_key(tbl, value) + for k, _ in pairs(tbl) do + if k == value then + return true + end + end + + return false +end + +local photils_installed = df.check_if_bin_exists("photils-cli") + +--[[ + local state object + + maybe per_page is a preference variable but I think 10 + is a good value for the ui +]] +local PHOTILS = { + tags = {}, + page = 1, + per_page = 10, + selected_tags = {}, + in_pagination = false, + tagged_image = "" +} + +local GUI = { + container = dt.new_widget("box") { + orientation = "vertical", + sensitive = true, + dt.new_widget("button") { + label = _("Get Tags"), + sensitive = photils_installed, + clicked_callback = function() PHOTILS.on_tags_clicked() end + }, + reset_callback = function() PHOTILS.on_reset(true) end + }, + stack = dt.new_widget("stack"), + prev_button = dt.new_widget("button") { + label = "<", + sensitive = false, + clicked_callback = function() + PHOTILS.page = PHOTILS.page - 1 + PHOTILS.paginate() + end + }, + next_button = dt.new_widget("button") { + label = ">", + sensitive = false, + clicked_callback = function() + PHOTILS.page = PHOTILS.page + 1 + PHOTILS.paginate() + end + }, + tag_box = dt.new_widget("box") {orientation = "vertical"}, + tag_view = dt.new_widget("box") {orientation = "vertical"}, + page_label = dt.new_widget("label") {label = ""}, + error_view = dt.new_widget("box") {orientation = "vertical"}, + warning_label = dt.new_widget("label") { + label = "" + }, + restart_required_label = dt.new_widget("label") { + label = _("requires a restart to be applied") + }, + attach_button = dt.new_widget("button") { + label = "", + sensitive = false, + clicked_callback = function() PHOTILS.attach_tags() end + }, + confidence_slider = dt.new_widget("slider") { + step = 1, + digits = 0, + value = 90, + hard_max = 100, + hard_min = 0, + soft_max = 100, + soft_min = 0, + label = _("Min Confidence Value") + }, + warning = dt.new_widget("label") +} + +function PHOTILS.image_changed() + local current_image = tostring(dt.gui.selection()[1]) + if current_image ~= PHOTILS.tagged_image then + if PHOTILS.tagged_image ~= "" then + PHOTILS.tagged_image_has_changed() + end + + PHOTILS.tagged_image = tostring(current_image) + end +end + +function PHOTILS.tagged_image_has_changed() + GUI.warning.label = _( + "The suggested tags were not generated\n for the currently selected image!") +end + +function PHOTILS.paginate() + PHOTILS.in_pagination = true + local num_pages = math.ceil(#PHOTILS.tags / PHOTILS.per_page) + GUI.page_label.label = string.format(_(" Page %s of %s "), PHOTILS.page, + num_pages) + + if PHOTILS.page <= 1 then + PHOTILS.page = 1 + GUI.prev_button.sensitive = false + else + GUI.prev_button.sensitive = true + end + + if PHOTILS.page > num_pages - 1 then + PHOTILS.page = num_pages + GUI.next_button.sensitive = false + else + GUI.next_button.sensitive = true + end + + local offset = ((PHOTILS.page - 1) * PHOTILS.per_page) + 1 + local tag_index = 1 + for i = offset, offset + PHOTILS.per_page - 1, 1 do + local tag = PHOTILS.tags[i] + GUI.tag_box[tag_index].value = has_key(PHOTILS.selected_tags, tag) + + if tag then + GUI.tag_box[tag_index].label = tag + GUI.tag_box[tag_index].sensitive = true + else + GUI.tag_box[tag_index].label = "" + GUI.tag_box[tag_index].sensitive = false + end + tag_index = tag_index + 1 + end + + PHOTILS.in_pagination = false +end + +function PHOTILS.attach_tags() + local image = dt.gui.selection()[1] + for tag, _ in pairs(PHOTILS.selected_tags) do + local dt_tag = dt.tags.create(tag) + dt.tags.attach(dt_tag, image) + end + + dt.print(_("Tags successfully attached to image")) +end + +function PHOTILS.get_tmp_file() + local tmp_file = os.tmpname() + if dt.configuration.running_os == "windows" then + tmp_file = dt.configuration.tmp_dir .. tmp_file -- windows os.tmpname() defaults to root directory + end + + local f = io.open(tmp_file, "w") + if not f then + dt.print_log(string.format(_("Error writing to `%s`"), tmp_file)) + os.remove(tmp_file) + return nil + end + + return tmp_file +end + +function PHOTILS.get_tags(image, with_export) + local tmp_file = PHOTILS.get_tmp_file() + local in_arg = df.sanitize_filename(tostring(image)) + local out_arg = df.sanitize_filename(tmp_file) + local executable = photils_installed + + if dt.configuration.running_os == "macos" then + executable = executable .. "/Contents/MacOS/photils-cli" + end + + if with_export then + dt.print_log("use export to for prediction") + local export_file = PHOTILS.get_tmp_file() + exporter:write_image(image, export_file) + in_arg = df.sanitize_filename(tostring(export_file)) + end + + local command = executable .. " -c " .. " -i " .. in_arg .. " -o " .. out_arg + + local ret = dtsys.external_command(command) + if ret > 0 then + dt.print_error(string.format("command %s returned error code %d", command, ret)) + os.remove(tmp_file) + + -- try to export the image and run tagging + if not with_export then + return PHOTILS.get_tags(image, true) + end + + return false + end + + for i = #PHOTILS.tags, 1, -1 do + PHOTILS.tags[i] = nil + end + + for tag in io.lines(tmp_file) do + local splitted = du.split(tag, ":") + if 100 * tonumber(splitted[2]) >= GUI.confidence_slider.value then + PHOTILS.tags[#PHOTILS.tags + 1] = splitted[1] + end + end + + dt.print(string.format(_("%s found %d tags for your image"), MODULE_NAME, + #PHOTILS.tags)) + os.remove(tmp_file) + + return true +end + +function PHOTILS.on_tags_clicked() + PHOTILS.page = 1 + GUI.warning.label = "" + + PHOTILS.on_reset(false) + + local images = dt.gui.selection() + + if #images == 0 then + dt.print(_("No image selected.")) + dt.control.sleep(2000) + else + if #images > 1 then + dt.print(_("This plugin can only handle a single image.")) + dt.gui.selection({images[1]}) + dt.control.sleep(2000) + end + + if not PHOTILS.get_tags(images[1], true) then + local msg = string.format(_("%s failed, see terminal output for details"), MODULE_NAME) + GUI.warning_label.label = msg + GUI.stack.active = GUI.error_view + dt.print(msg) + return + end + + if #PHOTILS.tags == 0 then + local msg = string.format(_("No tags where found"), MODULE_NAME) + GUI.warning_label.label = msg + GUI.stack.active = GUI.error_view + return + end + + GUI.stack.active = GUI.tag_view + PHOTILS.paginate() + end +end + +function PHOTILS.tag_selected(tag_button) + if PHOTILS.in_pagination then return end + + if tag_button.value then + PHOTILS.selected_tags[tag_button.label] = tag_button.label + else + PHOTILS.selected_tags[tag_button.label] = nil + end + + local num_selected = num_keys(PHOTILS.selected_tags) + if num_selected == 0 then + GUI.attach_button.label = "" + GUI.attach_button.sensitive = false + else + GUI.attach_button.label = string.format(_("Attach %d Tags"), + num_selected) + GUI.attach_button.sensitive = true + end +end + +function PHOTILS.on_reset(with_view) + if with_view then GUI.stack.active = 1 end + + for k, _ in pairs(PHOTILS.selected_tags) do + PHOTILS.selected_tags[k] = nil + end + + for _, v in ipairs(GUI.tag_box) do + v.value = false + end + + GUI.attach_button.label = "" + GUI.attach_button.sensitive = false +end + +-- add a fix number of buttons +for _ = 1, PHOTILS.per_page, 1 do + local btn_tag = dt.new_widget("check_button") { + label = "", + sensitive = false, + clicked_callback = PHOTILS.tag_selected + } + + table.insert(GUI.tag_box, btn_tag) +end + +if not photils_installed then + GUI.warning_label.label = _("photils-cli not found") + dt.print_log(_("photils-cli not found")) +else + GUI.warning_label.label = _("Select an image, click \"Get Tags\" and get \nsuggestions for tags.") +end + +GUI.pagination = dt.new_widget("box") { + orientation = "horizontal", + GUI.prev_button, + GUI.page_label, + GUI.next_button +} + + +table.insert(GUI.error_view, GUI.warning_label) +if not photils_installed then + table.insert(GUI.error_view, df.executable_path_widget({"photils-cli"})) + table.insert(GUI.error_view, GUI.restart_required_label) +end +table.insert(GUI.stack, GUI.error_view) +table.insert(GUI.stack, GUI.tag_view) + +table.insert(GUI.tag_view, GUI.pagination) +table.insert(GUI.tag_view, GUI.tag_box) +table.insert(GUI.tag_view, GUI.attach_button) +table.insert(GUI.tag_view, GUI.warning) + +table.insert(GUI.container, GUI.confidence_slider) +table.insert(GUI.container, GUI.stack) + +GUI.stack.active = 1 + +local plugin_display_views = { + [dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}, + [dt.gui.views.darkroom] = {"DT_UI_CONTAINER_PANEL_LEFT_CENTER", 100} +} + +-- dt.control.dispatch(PHOTILS.image_changed) +dt.register_event("mouse-over-image-changed",PHOTILS.image_changed) +dt.register_lib(MODULE_NAME, + "photils autotagger", + true, + true, + plugin_display_views, + GUI.container, + nil, + nil +) diff --git a/locale/de_DE/LC_MESSAGES/photils.po b/locale/de_DE/LC_MESSAGES/photils.po new file mode 100644 index 00000000..f1480a12 --- /dev/null +++ b/locale/de_DE/LC_MESSAGES/photils.po @@ -0,0 +1,83 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: Lua photils\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2020-05-12 13:12+0200\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: \n" +"Language-Team: \n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: ../../../contrib/photils.lua:97 +msgid "Get Tags" +msgstr "Hole Stichwörter" + +#: ../../../contrib/photils.lua:128 +msgid "requires a restart to be applied" +msgstr "erfordert die Neustart um angewendet zu werden" + +#: ../../../contrib/photils.lua:155 +msgid "" +"The suggested tags were not generated\n" +" for the currently selected image!" +msgstr "" +"Die vorgeschlagenen Stichwörter wurden für das\n" +"aktuell ausgewählte Bild nicht generiert!" + +#: ../../../contrib/photils.lua:161 +#, lua-format +msgid " Page %s of %s " +msgstr " Seite %s von %s " + +#: ../../../contrib/photils.lua:204 +msgid "Tags successfully attached to image" +msgstr "Stichwörter erfolgreich an Bild angefügt" + +#: ../../../contrib/photils.lua:215 +#, lua-format +msgid "Error writing to `%s`" +msgstr "Fehler beim Schreiben in `%s`" + +#: ../../../contrib/photils.lua:229 +#, lua-format +msgid "%s failed, see terminal output for details" +msgstr "%s fehlgeschlagen, siehe Terminal-Ausgabe für Details" + +#: ../../../contrib/photils.lua:243 +#, lua-format +msgid "%s found %d tags for your image" +msgstr "%s gefunden %d-Stichwörter für Ihr Bild" + +#: ../../../contrib/photils.lua:257 +msgid "No image selected." +msgstr "Kein Bild ausgewählt." + +#: ../../../contrib/photils.lua:262 +msgid "This plugin can only handle a single image." +msgstr "Dieses Plugin kann nur ein einziges Bild verarbeiten." + +#: ../../../contrib/photils.lua:293 +#, lua-format +msgid "Attach %d Tags" +msgstr "%d-Stichwörter anhängen" + +#: ../../../contrib/photils.lua:326 ../../../contrib/photils.lua:327 +msgid "photils-cli not found" +msgstr "photils-cli nicht gefunden" + +#: ../../../contrib/photils.lua:329 +msgid "" +"Select an image, click \"Get Tags\" and get \n" +"suggestions for tags." +msgstr "" +"Wählen Sie ein Bild aus, drücken Sie \"Hole Stichwörter\"\n" +" und erhalten Sie Vorschläge für Stichwörter." From 4c536b41bccb2ca4627ffdeaf263f149ccc4b87f Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Mon, 8 Jun 2020 12:45:49 -0400 Subject: [PATCH 055/445] checkpoint --- lib/dtutils/file.lua | 61 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 52 insertions(+), 9 deletions(-) diff --git a/lib/dtutils/file.lua b/lib/dtutils/file.lua index 9fa2c269..aaf7f011 100644 --- a/lib/dtutils/file.lua +++ b/lib/dtutils/file.lua @@ -57,35 +57,78 @@ dtutils_file.libdoc.functions["check_if_bin_exists"] = { Copyright = [[]], } -function dtutils_file.check_if_bin_exists(bin) +local function _check_if_bin_exists_windows(bin) local result = false local path = nil - if string.match(bin, "/") or string.match(bin, "\\") then + if string.match(bin, "\\") then path = bin else path = dtutils_file.get_executable_path_preference(bin) end - if string.len(path) > 0 then + if (string.match(path, ".exe$") or string.match(path, ".EXE$")) or + (string.match(path, ".com$") or string.match(path, ".COM$")) or + (string.match(path, ".bat$") or string.match(path, ".BAT$")) or + (string.match(path, ".cmd$") or string.match(path, ".CMD$")) then if dtutils_file.check_if_file_exists(path) then - if (string.match(path, ".exe$") or string.match(path, ".EXE$")) and dt.configuration.running_os ~= "windows" then - result = dtutils_file.sanitize_filename("wine " .. path) - else + result = dtutils_file.sanitize_filename(path) + end + end + return result +end + +-- check_if_bin_exists for unix like systems (linux, macos) +local function _check_if_bin_exists_nix(bin) + local result = false + local path = nil + + if string.match(bin, "/") then + path = bin + else + path = dtutils_file.get_executable_path_preference(bin) + end + + if path then dt.print_log("path is " .. path) end + + if string.len(path) > 0 then + -- check for windows executable to run under wine + if string.match(path, ".exe$") or string.match(path, ".EXE$") then + if dtutils_file.check_if_file_exists(path) then result = dtutils_file.sanitize_filename(path) end + else + if dtutils_file.check_if_file_exists(path) then + local spath = dtutils_file.sanitize_filename(path) + -- check that it's an executable file + if os.execute("test -f " .. spath .. " && test -x " .. spath) then + result = spath + end + end end - elseif dt.configuration.running_os == "linux" then + end + if not result then local p = io.popen("which " .. bin) local output = p:read("*a") p:close() if string.len(output) > 0 then - result = dtutils_file.sanitize_filename(output:sub(1,-2)) + local spath = dtutils_file.sanitize_filename(output:sub(1,-2)) + if os.execute("test -f " .. spath .. " && test -x " .. spath) then + result = spath + end end end return result end +function dtutils_file.check_if_bin_exists(bin) + if dt.configuration.running_os == "windows" then + return _check_if_bin_exists_windows(bin) + else + return _check_if_bin_exists_nix(bin) + end +end + dtutils_file.libdoc.functions["split_filepath"] = { Name = [[split_filepath]], Synopsis = [[split a filepath into parts]], @@ -542,7 +585,7 @@ function dtutils_file.executable_path_widget(executables) is_directory = false, changed_callback = function(self) if dtutils_file.check_if_bin_exists(self.value) then - dtutils_file.set_executable_path_preference(executable, self.value) + dtutils_file.set_executable_path_preference(executable, dtutils_file.check_if_bin_exists(self.value)) end end} ) From 60fa4b9ee02fe67b4844ff639a7cd77db3030818 Mon Sep 17 00:00:00 2001 From: Tobias Scheck Date: Tue, 9 Jun 2020 08:50:26 +0200 Subject: [PATCH 056/445] update description --- contrib/photils.lua | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/contrib/photils.lua b/contrib/photils.lua index 102bd4d5..f4a046e6 100644 --- a/contrib/photils.lua +++ b/contrib/photils.lua @@ -16,13 +16,11 @@ --]] --[[ - A darktable plugin which tries to predict keywords based on the selected image. - This plugin uses photils-cli to handle this task. Photils-cli is an application - which passes the image through a neural network and generates a feature vector. - This feature vector will be used to find similar images in a self-hosted online - database and the corresponding tags. The usage of the feature vector has this advantage - that at no time your selected image will leave the PC. Rather a representation - of the image is sent. + A darktable plugin that tries to predict keywords based on the selected image. + This plugin uses photils-cli to handle this task. Photils-cli is an application + that passes the image through a neural network, classifies it, and extracts the + suggested tags. Everything happens offline without the need that your data are + sent over the internet. ADDITIONAL SOFTWARE NEEDED FOR THIS SCRIPT * photils-cli - https://github.com/scheckmedia/photils-cli From 1c9042c496e2b798ec08b53e7b4d9c7cf0da3bc4 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Tue, 9 Jun 2020 20:22:02 -0400 Subject: [PATCH 057/445] Added a sanitize_lua function to the string library for sanitizing strings of lua "magic" characters before using the string in a string function that involves matching. script_manager needs the path to the lua directory sanitized of lua "magic" characters to prevent failure to extract the category and script names. --- lib/dtutils/string.lua | 26 ++++++++++++++++++++++++++ tools/script_manager.lua | 3 ++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/lib/dtutils/string.lua b/lib/dtutils/string.lua index f58f38cd..e3cc8170 100644 --- a/lib/dtutils/string.lua +++ b/lib/dtutils/string.lua @@ -269,5 +269,31 @@ function dtutils_string.sanitize(str) end end +dtutils_string.libdoc.functions["sanitize_lua"] = { + Name = [[sanitize_lua]], + Synopsis = [[escape lua 'magic' characters from a pattern string]], + Usage = [[local ds = require "lib/dtutils.string" + + local result = ds.sanitize_lua(str) + str - string - the string that needs to be made safe]], + Description = [[sanitize_lua escapes lua 'magic' characters so that + a string may be used in lua string/patten matching.]], + Return_Value = [[result - string - a lua pattern safe string]], + Limitations = [[]], + Example = [[]], + See_Also = [[]], + Reference = [[]], + License = [[]], + Copyright = [[]], +} + +function dtutils_string.sanitize_lua(str) + str = string.gsub(str, "%-", "%%-") + str = string.gsub(str, "%(", "%%(") + str = string.gsub(str, "%)", "%%)") + return str +end + + return dtutils_string diff --git a/tools/script_manager.lua b/tools/script_manager.lua index 9759b887..0946ae51 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -39,6 +39,7 @@ local dt = require "darktable" local du = require "lib/dtutils" local df = require "lib/dtutils.file" +local ds = require "lib/dtutils.string" local dtsys = require "lib/dtutils.system" local gettext = dt.gettext @@ -215,7 +216,7 @@ local function scan_scripts() -- scan the scripts local output = io.popen(find_cmd) for line in output:lines() do - local l = string.gsub(line, LUA_DIR .. PS, "") -- strip the lua dir off + local l = string.gsub(line, ds.sanitize_lua(LUA_DIR) .. PS, "") -- strip the lua dir off local script_file = l:sub(1,-5) if not string.match(script_file, "script_manager") then -- let's not include ourself if not string.match(script_file, "plugins") then -- skip plugins From fd97ac18da3c87a039b756a512a9a18aa15f3cf9 Mon Sep 17 00:00:00 2001 From: Tobias Scheck Date: Wed, 10 Jun 2020 14:48:18 +0200 Subject: [PATCH 058/445] add comments for clarification; formatting --- contrib/photils.lua | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/contrib/photils.lua b/contrib/photils.lua index f4a046e6..f4989032 100644 --- a/contrib/photils.lua +++ b/contrib/photils.lua @@ -160,8 +160,7 @@ function PHOTILS.image_changed() end function PHOTILS.tagged_image_has_changed() - GUI.warning.label = _( - "The suggested tags were not generated\n for the currently selected image!") + GUI.warning.label = _("The suggested tags were not generated\n for the currently selected image!") end function PHOTILS.paginate() @@ -184,6 +183,13 @@ function PHOTILS.paginate() GUI.next_button.sensitive = true end + --[[ + calculates the start positon in the tag array based on the current page + and takes N tags from that array to show these in darktable + e.g. page 1 goes from 1 to 10, page 2 from 11 to 20 a.s.o. + the paginaton approach is related to a problem with the dynamic addition + of mutliple widgets https://github.com/darktable-org/darktable/issues/4934#event-3318100463 + ]]-- local offset = ((PHOTILS.page - 1) * PHOTILS.per_page) + 1 local tag_index = 1 for i = offset, offset + PHOTILS.per_page - 1, 1 do From 2e27b812d6f619737d37ab3823545fce5937bba4 Mon Sep 17 00:00:00 2001 From: Tobias Scheck Date: Wed, 10 Jun 2020 14:48:27 +0200 Subject: [PATCH 059/445] fix spelling --- locale/de_DE/LC_MESSAGES/photils.po | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locale/de_DE/LC_MESSAGES/photils.po b/locale/de_DE/LC_MESSAGES/photils.po index f1480a12..0acd02a1 100644 --- a/locale/de_DE/LC_MESSAGES/photils.po +++ b/locale/de_DE/LC_MESSAGES/photils.po @@ -23,7 +23,7 @@ msgstr "Hole Stichwörter" #: ../../../contrib/photils.lua:128 msgid "requires a restart to be applied" -msgstr "erfordert die Neustart um angewendet zu werden" +msgstr "erfordert einen Neustart um angewendet zu werden" #: ../../../contrib/photils.lua:155 msgid "" From 26d97b8cdf2c427878c76c7df10bb3fc05360890 Mon Sep 17 00:00:00 2001 From: GLLM Date: Thu, 11 Jun 2020 22:06:00 +0200 Subject: [PATCH 060/445] Update OpenInExplorer.lua Add the possibility to define a shortcut for this LUA script. --- contrib/OpenInExplorer.lua | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/contrib/OpenInExplorer.lua b/contrib/OpenInExplorer.lua index d456911e..496bc798 100644 --- a/contrib/OpenInExplorer.lua +++ b/contrib/OpenInExplorer.lua @@ -108,4 +108,9 @@ if proper_install then function() open_in_fmanager(act_os, fmng_cmd[act_os]) end, _("Opens the file manager at the selected image's location") ) + dt.register_event( + "shortcut", + function(event, shortcut) open_in_fmanager(act_os, fmng_cmd[act_os]) end, + "OpenInExplorer" + ) end From 1378441dfa74fa72f8cce5afbdba895eee071bd3 Mon Sep 17 00:00:00 2001 From: Tobias Scheck Date: Sun, 14 Jun 2020 07:47:28 +0200 Subject: [PATCH 061/445] change labels to lower case to fit darktable style --- contrib/photils.lua | 14 +++++++------- locale/de_DE/LC_MESSAGES/photils.po | 28 +++++++++------------------- 2 files changed, 16 insertions(+), 26 deletions(-) diff --git a/contrib/photils.lua b/contrib/photils.lua index f4989032..39b71b91 100644 --- a/contrib/photils.lua +++ b/contrib/photils.lua @@ -30,7 +30,7 @@ To do this add this line to the file .config/darktable/luarc: require "contrib/photils" * Select an image - * Press "Get Tags" + * Press "get tags" * Select the tags you want from a list of suggestions * Press "Attach .. Tags" to add the selected tags to your image --]] @@ -97,7 +97,7 @@ local GUI = { orientation = "vertical", sensitive = true, dt.new_widget("button") { - label = _("Get Tags"), + label = _("get tags"), sensitive = photils_installed, clicked_callback = function() PHOTILS.on_tags_clicked() end }, @@ -143,7 +143,7 @@ local GUI = { hard_min = 0, soft_max = 100, soft_min = 0, - label = _("Min Confidence Value") + label = _("min confidence value") }, warning = dt.new_widget("label") } @@ -166,7 +166,7 @@ end function PHOTILS.paginate() PHOTILS.in_pagination = true local num_pages = math.ceil(#PHOTILS.tags / PHOTILS.per_page) - GUI.page_label.label = string.format(_(" Page %s of %s "), PHOTILS.page, + GUI.page_label.label = string.format(_(" page %s of %s "), PHOTILS.page, num_pages) if PHOTILS.page <= 1 then @@ -312,7 +312,7 @@ function PHOTILS.on_tags_clicked() end if #PHOTILS.tags == 0 then - local msg = string.format(_("No tags where found"), MODULE_NAME) + local msg = string.format(_("no tags where found"), MODULE_NAME) GUI.warning_label.label = msg GUI.stack.active = GUI.error_view return @@ -337,7 +337,7 @@ function PHOTILS.tag_selected(tag_button) GUI.attach_button.label = "" GUI.attach_button.sensitive = false else - GUI.attach_button.label = string.format(_("Attach %d Tags"), + GUI.attach_button.label = string.format(_("attach %d tags"), num_selected) GUI.attach_button.sensitive = true end @@ -373,7 +373,7 @@ if not photils_installed then GUI.warning_label.label = _("photils-cli not found") dt.print_log(_("photils-cli not found")) else - GUI.warning_label.label = _("Select an image, click \"Get Tags\" and get \nsuggestions for tags.") + GUI.warning_label.label = _("Select an image, click \"get tags\" and get \nsuggestions for tags.") end GUI.pagination = dt.new_widget("box") { diff --git a/locale/de_DE/LC_MESSAGES/photils.po b/locale/de_DE/LC_MESSAGES/photils.po index 0acd02a1..b81dbc70 100644 --- a/locale/de_DE/LC_MESSAGES/photils.po +++ b/locale/de_DE/LC_MESSAGES/photils.po @@ -17,15 +17,15 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: ../../../contrib/photils.lua:97 -msgid "Get Tags" -msgstr "Hole Stichwörter" +msgid "get tags" +msgstr "hole stichwörter" -#: ../../../contrib/photils.lua:128 msgid "requires a restart to be applied" msgstr "erfordert einen Neustart um angewendet zu werden" -#: ../../../contrib/photils.lua:155 +msgid "min confidence value" +msgstr "min vertrauenswert" + msgid "" "The suggested tags were not generated\n" " for the currently selected image!" @@ -33,48 +33,38 @@ msgstr "" "Die vorgeschlagenen Stichwörter wurden für das\n" "aktuell ausgewählte Bild nicht generiert!" -#: ../../../contrib/photils.lua:161 #, lua-format -msgid " Page %s of %s " -msgstr " Seite %s von %s " +msgid " page %s of %s " +msgstr " seite %s von %s " -#: ../../../contrib/photils.lua:204 msgid "Tags successfully attached to image" msgstr "Stichwörter erfolgreich an Bild angefügt" -#: ../../../contrib/photils.lua:215 #, lua-format msgid "Error writing to `%s`" msgstr "Fehler beim Schreiben in `%s`" -#: ../../../contrib/photils.lua:229 #, lua-format msgid "%s failed, see terminal output for details" msgstr "%s fehlgeschlagen, siehe Terminal-Ausgabe für Details" -#: ../../../contrib/photils.lua:243 #, lua-format msgid "%s found %d tags for your image" msgstr "%s gefunden %d-Stichwörter für Ihr Bild" -#: ../../../contrib/photils.lua:257 msgid "No image selected." msgstr "Kein Bild ausgewählt." -#: ../../../contrib/photils.lua:262 msgid "This plugin can only handle a single image." msgstr "Dieses Plugin kann nur ein einziges Bild verarbeiten." -#: ../../../contrib/photils.lua:293 #, lua-format -msgid "Attach %d Tags" -msgstr "%d-Stichwörter anhängen" +msgid "attach %d tags" +msgstr "%d stichwörter anhängen" -#: ../../../contrib/photils.lua:326 ../../../contrib/photils.lua:327 msgid "photils-cli not found" msgstr "photils-cli nicht gefunden" -#: ../../../contrib/photils.lua:329 msgid "" "Select an image, click \"Get Tags\" and get \n" "suggestions for tags." From 72bd66d3f567a885e060baf94c893257ef1f1e10 Mon Sep 17 00:00:00 2001 From: Tobias Scheck Date: Sun, 14 Jun 2020 08:57:17 +0200 Subject: [PATCH 062/445] add option to display confidence value, add notice that windows version is not available yet --- contrib/photils.lua | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/contrib/photils.lua b/contrib/photils.lua index 39b71b91..85a2275a 100644 --- a/contrib/photils.lua +++ b/contrib/photils.lua @@ -23,12 +23,13 @@ sent over the internet. ADDITIONAL SOFTWARE NEEDED FOR THIS SCRIPT - * photils-cli - https://github.com/scheckmedia/photils-cli + * photils-cli - https://github.com/scheckmedia/photils-cli at the moment only + available for Linux and MacOS USAGE * require this script from your main lua file - To do this add this line to the file .config/darktable/luarc: - require "contrib/photils" + To do this add this line to the file .config/darktable/luarc: + require "contrib/photils" * Select an image * Press "get tags" * Select the tags you want from a list of suggestions @@ -85,6 +86,7 @@ local photils_installed = df.check_if_bin_exists("photils-cli") ]] local PHOTILS = { tags = {}, + confidences = {}, page = 1, per_page = 10, selected_tags = {}, @@ -194,9 +196,15 @@ function PHOTILS.paginate() local tag_index = 1 for i = offset, offset + PHOTILS.per_page - 1, 1 do local tag = PHOTILS.tags[i] + local conf = PHOTILS.confidences[i] + GUI.tag_box[tag_index].value = has_key(PHOTILS.selected_tags, tag) if tag then + if dt.preferences.read(MODULE_NAME, "show_confidence", "bool") then + tag = tag .. string.format(" (%.3f)", conf) + end + GUI.tag_box[tag_index].label = tag GUI.tag_box[tag_index].sensitive = true else @@ -269,12 +277,14 @@ function PHOTILS.get_tags(image, with_export) for i = #PHOTILS.tags, 1, -1 do PHOTILS.tags[i] = nil + PHOTILS.confidences[i] = nil end for tag in io.lines(tmp_file) do local splitted = du.split(tag, ":") if 100 * tonumber(splitted[2]) >= GUI.confidence_slider.value then PHOTILS.tags[#PHOTILS.tags + 1] = splitted[1] + PHOTILS.confidences[#PHOTILS.confidences+1] = splitted[2] end end @@ -327,7 +337,13 @@ function PHOTILS.tag_selected(tag_button) if PHOTILS.in_pagination then return end if tag_button.value then - PHOTILS.selected_tags[tag_button.label] = tag_button.label + local tag = tag_button.label + if dt.preferences.read(MODULE_NAME, "show_confidence", "bool") then + local idx = string.find(tag, "%(") - 2 + tag = string.sub(tag, 0, idx) + end + + PHOTILS.selected_tags[tag] = tag else PHOTILS.selected_tags[tag_button.label] = nil end @@ -407,7 +423,15 @@ local plugin_display_views = { [dt.gui.views.darkroom] = {"DT_UI_CONTAINER_PANEL_LEFT_CENTER", 100} } --- dt.control.dispatch(PHOTILS.image_changed) + +-- uses photils: prefix because script settings are all together and not seperated by script +dt.preferences.register(MODULE_NAME, + "show_confidence", + "bool", + _("photils: show confidence value"), + _("if enabled, the confidence value for each tag is displayed"), + true) + dt.register_event("mouse-over-image-changed",PHOTILS.image_changed) dt.register_lib(MODULE_NAME, "photils autotagger", From 87502fb17f4f85442e8f48c0054cfa05cf69c8b4 Mon Sep 17 00:00:00 2001 From: Tobias Scheck Date: Mon, 15 Jun 2020 11:16:14 +0200 Subject: [PATCH 063/445] move function to create temp files to dtutils/file.lua --- contrib/photils.lua | 20 ++-------------- lib/dtutils/file.lua | 55 ++++++++++++++++++++++++++++++++++---------- 2 files changed, 45 insertions(+), 30 deletions(-) diff --git a/contrib/photils.lua b/contrib/photils.lua index 85a2275a..1c72f4b7 100644 --- a/contrib/photils.lua +++ b/contrib/photils.lua @@ -227,24 +227,8 @@ function PHOTILS.attach_tags() dt.print(_("Tags successfully attached to image")) end -function PHOTILS.get_tmp_file() - local tmp_file = os.tmpname() - if dt.configuration.running_os == "windows" then - tmp_file = dt.configuration.tmp_dir .. tmp_file -- windows os.tmpname() defaults to root directory - end - - local f = io.open(tmp_file, "w") - if not f then - dt.print_log(string.format(_("Error writing to `%s`"), tmp_file)) - os.remove(tmp_file) - return nil - end - - return tmp_file -end - function PHOTILS.get_tags(image, with_export) - local tmp_file = PHOTILS.get_tmp_file() + local tmp_file = df.create_tmp_file() local in_arg = df.sanitize_filename(tostring(image)) local out_arg = df.sanitize_filename(tmp_file) local executable = photils_installed @@ -255,7 +239,7 @@ function PHOTILS.get_tags(image, with_export) if with_export then dt.print_log("use export to for prediction") - local export_file = PHOTILS.get_tmp_file() + local export_file = df.create_tmp_file() exporter:write_image(image, export_file) in_arg = df.sanitize_filename(tostring(export_file)) end diff --git a/lib/dtutils/file.lua b/lib/dtutils/file.lua index 9fa2c269..423e834e 100644 --- a/lib/dtutils/file.lua +++ b/lib/dtutils/file.lua @@ -44,7 +44,7 @@ dtutils_file.libdoc.functions["check_if_bin_exists"] = { bin - string - the binary to check for]], Description = [[check_if_bin_exists checks to see if the specified binary exists. check_if_bin_exists first checks to see if a preference for the binary has been - registered and uses that if found. The presence of the file is verified, then + registered and uses that if found. The presence of the file is verified, then quoted and returned. If no preference is specified and the operating system is linux then the which command is used to check for a binary in the path. If found that path is returned. If no binary is found, false is returned.]], @@ -61,7 +61,7 @@ function dtutils_file.check_if_bin_exists(bin) local result = false local path = nil - if string.match(bin, "/") or string.match(bin, "\\") then + if string.match(bin, "/") or string.match(bin, "\\") then path = bin else path = dtutils_file.get_executable_path_preference(bin) @@ -233,7 +233,7 @@ function dtutils_file.check_if_file_exists(filepath) local p = io.popen("if exist " .. dtutils_file.sanitize_filename(filepath) .. " (echo 'yes') else (echo 'no')") local ans = p:read("*all") p:close() - if string.match(ans, "yes") then + if string.match(ans, "yes") then result = true end -- result = os.execute('if exist "'..filepath..'" (cmd /c exit 0) else (cmd /c exit 1)') @@ -383,8 +383,8 @@ dtutils_file.libdoc.functions["filename_increment"] = { local result = df.filename_increment(filepath) filepath - string - filename to increment]], - Description = [[filename_increment solves the problem of filename confllict by adding an - increment to the filename. If the supplied filename has no increment then + Description = [[filename_increment solves the problem of filename confllict by adding an + increment to the filename. If the supplied filename has no increment then "01" is added to the basename. If the filename already has an increment, then 1 is added to it and the filename returned.]], Return_Value = [[result - string - the incremented filename]], @@ -436,7 +436,7 @@ dtutils_file.libdoc.functions["create_unique_filename"] = { filepath - string - the path and filename requested]], Description = [[create_unique_filename takes a requested filepath and checks to see if it exists. If if doesn't then it's returned intact. If it already exists, then a two - digit increment is added to the filename and it is tested again. The increment keeps + digit increment is added to the filename and it is tested again. The increment keeps increasing until either a unique filename is found or there have been 100 attempts.]], Return_Value = [[result - string - the incremented filename]], Limitations = [[create_unique_filename will only attempt 100 increments.]], @@ -515,7 +515,7 @@ dtutils_file.libdoc.functions["executable_path_widget"] = { local widget = df.executable_path_widget(executables) executables - table - a table of strings that are executable names]], Description = [[executable_path_widget takes a table of executable names - and builds a set of file selector widgets to get the path to the executable. + and builds a set of file selector widgets to get the path to the executable. The resulting widgets are wrapped in a box widget and returned.]], Return_Value = [[widget - widget - a widget containing a file selector widget for each executable.]], @@ -530,10 +530,10 @@ dtutils_file.libdoc.functions["executable_path_widget"] = { function dtutils_file.executable_path_widget(executables) local box_widgets = {} table.insert(box_widgets, dt.new_widget("section_label"){label = "select executable(s)"}) - for _, executable in pairs(executables) do + for _, executable in pairs(executables) do table.insert(box_widgets, dt.new_widget("label"){label = "select " .. executable .. " executable"}) local path = dtutils_file.get_executable_path_preference(executable) - if not path then + if not path then path = "" end table.insert(box_widgets, dt.new_widget("file_chooser_button"){ @@ -562,7 +562,7 @@ dtutils_file.libdoc.functions["sanitize_filename"] = { local sanitized_filename = df.sanitize_filename(filename) filename - string - a filepath and filename]], Description = [[sanitize_file places quotes around the filename in an - operating system specific manner. The result is safe to pass as + operating system specific manner. The result is safe to pass as an argument to the operating system.]], Return_Value = [[sanitized_filename - string - quoted filename]], Limitations = [[]], @@ -584,7 +584,7 @@ dtutils_file.libdoc.functions["mkdir"] = { df.mkdir(path) path - string - a directory path]], - Description = [[mkdir creates directories if not already exists. It + Description = [[mkdir creates directories if not already exists. It create whole parents subtree if needed ]], Return_Value = [[path - string - a directory path]], @@ -596,7 +596,7 @@ dtutils_file.libdoc.functions["mkdir"] = { Copyright = [[]], } -function dtutils_file.mkdir(path) +function dtutils_file.mkdir(path) if not dtutils_file.check_if_file_exists(path) then local mkdir_cmd = dt.configuration.running_os == "windows" and "mkdir" or "mkdir -p" return dsys.external_command(mkdir_cmd.." "..path) @@ -627,6 +627,37 @@ function dtutils_file.rmdir(path) return dsys.external_command(rm_cmd.." "..path) end +dtutils_file.libdoc.functions["create_tmp_file"] = { + Name = [[create_tmp_file]], + Synopsis = [[creates a temporary file]], + Usage = [[local df = require "lib/dtutils.file + + local result = df.create_tmp_file()]], + Description = [[create_tmp_file can be used to create temporary files]], + Return_Value = [[result - string - path to the created temporary file.]], + Limitations = [[]], + Example = [[]], + See_Also = [[]], + Reference = [[]], + License = [[]], + Copyright = [[]], +} + +function dtutils_file.create_tmp_file() + local tmp_file = os.tmpname() + if dt.configuration.running_os == "windows" then + tmp_file = dt.configuration.tmp_dir .. tmp_file -- windows os.tmpname() defaults to root directory + end + + local f = io.open(tmp_file, "w") + if not f then + log.msg(log.error, string.format("Error writing to `%s`", tmp_file)) + os.remove(tmp_file) + return nil + end + + return tmp_file +end return dtutils_file From 71e72b688f74c217462373d966b2251138c36426 Mon Sep 17 00:00:00 2001 From: Noah Date: Tue, 16 Jun 2020 01:50:59 -0700 Subject: [PATCH 064/445] Exported luts now have folder hierarchy --- contrib/exportLUT.lua | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/contrib/exportLUT.lua b/contrib/exportLUT.lua index 6d29647d..dd452aad 100644 --- a/contrib/exportLUT.lua +++ b/contrib/exportLUT.lua @@ -28,12 +28,16 @@ overwritten silently. local dt = require "darktable" local du = require "lib/dtutils" +local df = require("lib/dtutils.file") +local ds = require("lib/dtutils.system") du.check_min_api_version("5.0.0", "exportLUT") -- Thanks Kevin Ertel for this bit local os_path_seperator = '/' if dt.configuration.running_os == 'windows' then os_path_seperator = '\\' end +local mkdir_command = 'mkdir -p ' +if dt.configuration.running_os == 'windows' then mkdir_command = 'mkdir ' end local file_chooser_button = dt.new_widget("file_chooser_button"){ title = "Identity_file_chooser", @@ -63,6 +67,18 @@ local function end_job(job) job.valid = false end +local function output_path(style_name, job) + local output_location = export_chooser_button.value .. os_path_seperator .. style_name .. ".png" + output_location = string.gsub(output_location, "|", os_path_seperator) + local output_dir = string.reverse(output_location) + output_dir = string.gsub(output_dir, ".-" .. os_path_seperator, os_path_seperator, 1) + output_dir = string.reverse(output_dir) + if(output_dir ~= "") then + df.mkdir(df.sanitize_filename(output_dir)) + end + return output_location +end + local function export_luts() local identity = dt.database.import(file_chooser_button.value) if(type(identity) ~= "userdata") then @@ -81,13 +97,13 @@ local function export_luts() identity:reset() dt.styles.apply(style, identity) - local io_lut = dt.new_format("png") io_lut.bpp = 8 - io_lut:write_image(identity, export_chooser_button.value .. os_path_seperator .. style.name .. ".png") + + io_lut:write_image(identity, output_path(style.name, job)) count = count + 1 job.percent = count / size - dt.print("Exported: " .. export_chooser_button.value .. os_path_seperator .. style.name .. ".png") + dt.print("Exported: " .. output_path(style.name, job)) end dt.print("Done exporting haldCLUTs") job.valid = false From 802c17d5905dafc1bf30223a9e0f08db8931ccd7 Mon Sep 17 00:00:00 2001 From: Noah Date: Tue, 16 Jun 2020 01:59:43 -0700 Subject: [PATCH 065/445] Added translated text --- contrib/exportLUT.lua | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/contrib/exportLUT.lua b/contrib/exportLUT.lua index dd452aad..5d85bdc9 100644 --- a/contrib/exportLUT.lua +++ b/contrib/exportLUT.lua @@ -31,6 +31,8 @@ local du = require "lib/dtutils" local df = require("lib/dtutils.file") local ds = require("lib/dtutils.system") +local gettext = dt.gettext + du.check_min_api_version("5.0.0", "exportLUT") -- Thanks Kevin Ertel for this bit @@ -40,27 +42,27 @@ local mkdir_command = 'mkdir -p ' if dt.configuration.running_os == 'windows' then mkdir_command = 'mkdir ' end local file_chooser_button = dt.new_widget("file_chooser_button"){ - title = "Identity_file_chooser", + title = gettext.gettext("Identity_file_chooser"), value = "", is_directory = false } local export_chooser_button = dt.new_widget("file_chooser_button"){ - title = "Export_location_chooser", + title = gettext.gettext("Export_location_chooser"), value = "", is_directory = true } local identity_label = dt.new_widget("label"){ - label = "choose the identity haldclut file" + label = gettext.gettext("choose the identity haldclut file") } local output_label = dt.new_widget("label"){ - label = "choose the output location" + label = gettext.gettext("choose the output location") } local warning_label = dt.new_widget("label"){ - label = "WARNING: files may be silently overwritten" + label = gettext.gettext("WARNING: files may be silently overwritten") } local function end_job(job) @@ -82,9 +84,9 @@ end local function export_luts() local identity = dt.database.import(file_chooser_button.value) if(type(identity) ~= "userdata") then - dt.print("Invalid identity lut file") + dt.print(gettext.gettext("Invalid identity lut file")) else - local job = dt.gui.create_job('Exporting styles as haldCLUTs', true, end_job) + local job = dt.gui.create_job(gettext.gettext('Exporting styles as haldCLUTs'), true, end_job) local size = 1 @@ -103,22 +105,22 @@ local function export_luts() io_lut:write_image(identity, output_path(style.name, job)) count = count + 1 job.percent = count / size - dt.print("Exported: " .. output_path(style.name, job)) + dt.print(gettext.gettext("Exported: ") .. output_path(style.name, job)) end - dt.print("Done exporting haldCLUTs") + dt.print(gettext.gettext("Done exporting haldCLUTs")) job.valid = false identity:reset() end end local export_button = dt.new_widget("button"){ - label = "export", + label = gettext.gettext("export"), clicked_callback = export_luts } dt.register_lib( - "export haldclut", - "export haldclut", + gettext.gettext("export haldclut"), + gettext.gettext("export haldclut"), true, false, {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, From 948e8690dd0d274d7207987e74472b00d8e65fd3 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sat, 20 Jun 2020 14:49:31 -0400 Subject: [PATCH 066/445] Pulled preklov's branch, resolved conflicts, then merged into new branch with only 1 commit, essentially squashing the delete and replace file commits. --- contrib/OpenInExplorer.lua | 181 ++++++++++++++++----- locale/de_DE/LC_MESSAGES/OpenInExplorer.po | 67 ++++++-- 2 files changed, 193 insertions(+), 55 deletions(-) diff --git a/contrib/OpenInExplorer.lua b/contrib/OpenInExplorer.lua index 496bc798..425ba546 100644 --- a/contrib/OpenInExplorer.lua +++ b/contrib/OpenInExplorer.lua @@ -32,12 +32,18 @@ Install: (see here for more detail: https://github.com/darktable-org/lua-scripts Select the photo(s) you wish to find in your operating system's file manager and press "show in file explorer" in the "selected images" section. -- Nautilus (Linux), Explorer (Windows), and Finder (macOS before Catalina) will open one window for each selected image at the file's location. The file name will be highlighted. +- Nautilus (Linux), Explorer (Windows), and Finder (macOS prior to Mojave) will open one window for each selected image at the file's location. The file name will be highlighted. -- On macOS Catalina the Finder will open one window for each different directory. In these windows only the last one of the corresponding files will be highlighted (bug or feature?). +- On macOS Mojave and Catalina the Finder will open one window for each different directory. In these windows only the last one of the corresponding files will be highlighted (bug or feature?). - Dolphin (Linux) will open one window with tabs for the different directories. All the selected images' file names are highlighted in their respective directories. +As an alternative option you can choose to show the image file names as symbolic links in an arbitrary directory. Go to preferences|Lua options. This option is not available for Windows users as on Windows solely admins are allowed to create links. + +- Pros: You do not clutter up your display with multiple windows. So there is no need to limit the number of selections. + +- Cons: If you want to work with the files you are one step behind the original data. + ----KNOWN ISSUES---- ]] @@ -50,6 +56,7 @@ local gettext = dt.gettext --Check API version du.check_min_api_version("5.0.0", "OpenInExplorer") +-- Tell gettext where to find the .mo file translating messages for a particular domain gettext.bindtextdomain("OpenInExplorer",dt.configuration.config_dir.."/lua/locale/") local function _(msgid) @@ -59,58 +66,150 @@ end local act_os = dt.configuration.running_os local PS = act_os == "windows" and "\\" or "/" ---Detect OS and quit if it is not supported-- -local proper_install = true +--Detect OS and quit if it is not supported. if act_os ~= "macos" and act_os ~= "windows" and act_os ~= "linux" then - proper_install = false - dt.print_error(_('OpenInExplorer plug-in only supports Linux, macOS, and Windows at this time')) + dt.print(_("OpenInExplorer plug-in only supports Linux, macOS, and Windows at this time")) + dt.print_error("OpenInExplorer plug-in only supports Linux, macOS, and Windows at this time") return end ---Format strings for the commands to open the corresponding OS' file manager -local fmng_cmd = {} -fmng_cmd.linux = [[busctl --user call org.freedesktop.FileManager1 /org/freedesktop/FileManager1 org.freedesktop.FileManager1 ShowItems ass %d %s""]] -fmng_cmd.macos = 'open -Rn %s' -fmng_cmd.windows = 'explorer.exe /select, %s' +local use_links, links_dir = false, "" +if act_os ~= "windows" then + use_links = dt.preferences.read("OpenInExplorer", "use_links", "bool") + links_dir = dt.preferences.read("OpenInExplorer", "linked_image_files_dir", "string") +end + +--Check if the directory exists that was chosen for the file links. Return boolean. +local function check_if_links_dir_exists() + local dir_exists = true + if not links_dir then + --Just for paranoic reasons. I tried, but I couldn't devise a setting for a nil value. + dt.print(_("No links directory selected.\nPlease check the dt preferences (lua options)")) + dt.print_error("OpenInExplorer: No links directory selected") + dir_exists = false + elseif not df.check_if_file_exists(links_dir) then + dt.print(string.format(_("Links directory '%s' not found.\nPlease check the dt preferences (lua options)"), links_dir)) + dt.print_error(string.format("OpenInExplorer: Links directory '%s' not found", links_dir)) + dir_exists = false + end + return dir_exists +end + +--Format strings for the commands to open the corresponding OS's file manager. +local open_dir = {} +open_dir.windows = "explorer.exe /n, %s" +open_dir.macos = "open %s" +open_dir.linux = [[busctl --user call org.freedesktop.FileManager1 /org/freedesktop/FileManager1 org.freedesktop.FileManager1 ShowFolders ass 1 %s ""]] + +local open_files = {} +open_files.windows = "explorer.exe /select, %s" +open_files.macos = "open -Rn %s" +open_files.linux = [[busctl --user call org.freedesktop.FileManager1 /org/freedesktop/FileManager1 org.freedesktop.FileManager1 ShowItems ass %d %s ""]] + +--Call the file mangager for each selected image on Linux. +--There is one call to busctl containing a list of all the image file names. +local function call_list_of_files(selected_images) + local current_image, file_uris, run_cmd = "", "", "" + for _, image in pairs(selected_images) do + current_image = image.path..PS..image.filename + file_uris = file_uris .. df.sanitize_filename("file://" .. current_image) .. " " + dt.print_log("file_uris is " .. file_uris) + end + run_cmd = string.format(open_files.linux, #selected_images, file_uris) + dt.print_log("OpenInExplorer run_cmd = "..run_cmd) + dsys.external_command(run_cmd) +end + +--Call the file manager for each selected image on Windows and macOS. +local function call_file_by_file(selected_images) + local current_image, run_cmd = "", "" + for _, image in pairs(selected_images) do + current_image = image.path..PS..image.filename + run_cmd = string.format(open_files[act_os], df.sanitize_filename(current_image)) + dt.print_log("OpenInExplorer run_cmd = "..run_cmd) + dsys.external_command(run_cmd) + end +end + +--Create a link for each selected image, and finally call the file manager. +local function set_links(selected_images) + local current_image, link_target, run_cmd, k = "", "", "", nil + for k, image in pairs(selected_images) do + current_image = image.path..PS..image.filename + link_target = df.create_unique_filename(links_dir .. PS .. image.filename) + run_cmd = string.format("ln -s %s %s", df.sanitize_filename(current_image), df.sanitize_filename(link_target)) + --[[ + In case Windows will allow normal users to create soft links: + if act_os == "windows" then + run_cmd = string.format("mklink %s %s", df.sanitize_filename(link_target), df.sanitize_filename(current_image)) + end + ]] + if dsys.external_command(run_cmd) ~= 0 then + dt.print(_("Failed to create links. Missing rights?")) + dt.print_error("OpenInExplorer: Failed to create links") + return + end + end + --The URI format is necessary only for the Linux busctl command. + --But it is accepted by the Windows Explorer and macOS's Finder all the same. + run_cmd = string.format(open_dir[act_os], df.sanitize_filename("file://"..links_dir)) + dt.print_log("OpenInExplorer run_cmd = "..run_cmd) + dsys.external_command(run_cmd) +end ---The working function that opens the file manager windows with the selected image file names highlighted. -local function open_in_fmanager(op_sys, fmcmd) +--The working function that starts the particular task. +local function open_in_fmanager() local images = dt.gui.selection() - local curr_image, run_cmd, file_uris = '', '', '' if #images == 0 then - dt.print(_('Please select an image')) - elseif #images <= 15 then - for _,image in pairs(images) do - curr_image = image.path..PS..image.filename - if op_sys == 'linux' then - file_uris = file_uris .. df.sanitize_filename("file://" .. curr_image) .. " " - dt.print_log("file_uris is " .. file_uris) + dt.print(_("Please select an image")) + else + if use_links and not check_if_links_dir_exists() then + return + end + if #images > 15 and not use_links then + dt.print(_("Please select fewer images (max. 15)")) + elseif use_links then + set_links(images) + else + if act_os == "linux" then + call_list_of_files(images) else - run_cmd = string.format(fmcmd, df.sanitize_filename(curr_image)) - dt.print_log("OpenInExplorer run_cmd = "..run_cmd) - dsys.external_command(run_cmd) + call_file_by_file(images) end end - if op_sys == 'linux' then - run_cmd = string.format(fmcmd, #images, file_uris) - dt.print_log("OpenInExplorer run_cmd = "..run_cmd) - dsys.external_command(run_cmd) - end - else - dt.print(_('Please select fewer images (max 15)')) end end + -- GUI -- -if proper_install then - dt.gui.libs.image.register_action( - _("show in file explorer"), - function() open_in_fmanager(act_os, fmng_cmd[act_os]) end, - _("Opens the file manager at the selected image's location") +dt.gui.libs.image.register_action( + _("show in file explorer"), + function() open_in_fmanager() end, + _("Open the file manager at the selected image's location") +) +if act_os ~= "windows" then + dt.preferences.register("OpenInExplorer", "linked_image_files_dir", -- name + "directory", -- type + _("OpenInExplorer: linked files directory"), -- label + _("Directory to store the links to the file names. Requires restart to take effect"), -- tooltip + "Links to image files", -- default + dt.new_widget("file_chooser_button"){ + title = _("Select directory"), + is_directory = true, + } + ) + dt.preferences.register("OpenInExplorer", "use_links", -- name + "bool", -- type + _("OpenInExplorer: use links"), -- label + _("Use links instead of multiple windows. Requires restart to take effect"), -- tooltip + false, -- default + "" ) - dt.register_event( - "shortcut", - function(event, shortcut) open_in_fmanager(act_os, fmng_cmd[act_os]) end, - "OpenInExplorer" - ) end + +dt.register_event( + "shortcut", + function(event, shortcut) open_in_fmanager(act_os, fmng_cmd[act_os]) end, + "OpenInExplorer" +) + diff --git a/locale/de_DE/LC_MESSAGES/OpenInExplorer.po b/locale/de_DE/LC_MESSAGES/OpenInExplorer.po index 07d451ab..f0dc8ef1 100644 --- a/locale/de_DE/LC_MESSAGES/OpenInExplorer.po +++ b/locale/de_DE/LC_MESSAGES/OpenInExplorer.po @@ -1,39 +1,78 @@ -# OpenInExplorer Darktable Plug-In. -# Copyright (C) 2020 Volker Lenhardt +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # Volker Lenhardt , 2020. # #, fuzzy msgid "" msgstr "" -"Project-Id-Version: OpenInExplorer\n" +"Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-04-19 14:43+0200\n" +"POT-Creation-Date: 2020-06-11 19:07+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: Volker Lenhardt \n" +"Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: de_DE\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: OpenInExplorer.lua:64 +#: OpenInExplorer.lua:71 msgid "" -"OpenInExplorer plug-in only supports Linux, macOS, and Windows at this time" -msgstr "OpenInExplorer-Plug-in kann nur auf macOS, Linux oder Windows laufen" +"OpenInExplorer plug-in only supports Linux and macOS, and Windows at this time" +msgstr "OpenInExplorer-Plug-in unterstützt zur Zeit nur Linux, macOS oder Windows" -#: OpenInExplorer.lua:79 +#: OpenInExplorer.lua:87 +msgid "" +"No links directory selected.\n" +"Please check the dt preferences (lua options)" +msgstr "Kein Verknüpfungs-Verzeichnis ausgewählt.\nBitte die dt-Voreinstellungen überprüfen (Lua-Optionen)" + +#: OpenInExplorer.lua:91 +#, lua-format +msgid "" +"Links directory '%s' not found.\n" +"Please check the dt preferences (lua options)" +msgstr "Das Verknüpfungs-Verzeichnis '%s' konnte nicht gefunden werden.\nBitte die dt-Voreinstellungen überprüfen (Lua-Optionen)" + +#: OpenInExplorer.lua:148 +msgid "Failed to create links. Missing rights?" +msgstr "Die Verknüpfungen konnten nicht erstellt werden. Fehlende Rechte?" + +#: OpenInExplorer.lua:164 msgid "Please select an image" msgstr "Es wurde kein Bild ausgewählt" -#: OpenInExplorer.lua:98 -msgid "Please select fewer images (max 15)" +#: OpenInExplorer.lua:170 +msgid "Please select fewer images (max. 15)" msgstr "Bitte nicht mehr als 15 Bilder auswählen" -#: OpenInExplorer.lua:105 +#: OpenInExplorer.lua:186 msgid "show in file explorer" msgstr "im Dateimanager anzeigen" -#: OpenInExplorer.lua:107 -msgid "Opens the file manager at the selected image's location" +#: OpenInExplorer.lua:188 +msgid "Open the file manager at the selected image's location" msgstr "Öffnet den Dateimanager an der Position des ausgewählten Bildes" + +#: OpenInExplorer.lua:193 +msgid "OpenInExplorer: linked files directory" +msgstr "OpenInExplorer: Verknüpfungs-Verzeichnis" + +#: OpenInExplorer.lua:194 +msgid "" +"Directory to store the links to the file names. Requires restart to take " +"effect" +msgstr "Verzeichnis für die Verknüpfungen zu den Dateinamen. Erfordert dt-Neustart" + +#: OpenInExplorer.lua:197 +msgid "Select directory" +msgstr "Verzeichnis auswählen" + +#: OpenInExplorer.lua:203 +msgid "OpenInExplorer: use links" +msgstr "OpenInExplorer: Verknüpfungen nutzen" + +#: OpenInExplorer.lua:204 +msgid "Use links instead of multiple windows. Requires restart to take effect" +msgstr "Verknüpfungen statt einzelner Fenster nutzen. Erfordert dt-Neustart" From 497dbc8eaa5c24a7ec32da568ed8796545026a3e Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sun, 21 Jun 2020 16:32:14 -0400 Subject: [PATCH 067/445] Fixed function call arguments in shortcut. --- contrib/OpenInExplorer.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/OpenInExplorer.lua b/contrib/OpenInExplorer.lua index 425ba546..f1430cf5 100644 --- a/contrib/OpenInExplorer.lua +++ b/contrib/OpenInExplorer.lua @@ -209,7 +209,7 @@ end dt.register_event( "shortcut", - function(event, shortcut) open_in_fmanager(act_os, fmng_cmd[act_os]) end, + function(event, shortcut) open_in_fmanager() end, "OpenInExplorer" ) From 14b97cdbd92954647c0245b110b6d3ab88bf070c Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sun, 21 Jun 2020 17:14:36 -0400 Subject: [PATCH 068/445] Created image_time.lua to adjust non-destructively adjust image time. --- contrib/image_time.lua | 516 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 516 insertions(+) create mode 100644 contrib/image_time.lua diff --git a/contrib/image_time.lua b/contrib/image_time.lua new file mode 100644 index 00000000..62f2e2d8 --- /dev/null +++ b/contrib/image_time.lua @@ -0,0 +1,516 @@ +--[[ + + image_time.lua - synchronize image time for images shot with different cameras + + Copyright (C) 2019, 2020 Bill Ferguson . + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +]] +--[[ + image_time - non-destructively modify the image time + + DESCRIPTION + + image_time non destructively adjusts image times by modifying the + database image exif_datetime_taken field. There are 4 modes: adjust time, + set time, synchronize time, and reset time. + + ADJUST TIME + + adjust time mode lets you chose an offset in terms of years, months, + days, hours, minutes, and seconds. The adjustment can be added or + subtracted. + + WARNING: When adding and subtracting months the result will usually + be what is expected unless the time being adjusted is at the end of + the month. This is because a month is a variable amount of time that + can be 28, 29, 30 or 31 days depending on the month. Example: It's + March 31st and I subtract a month which not sets the time to February + 31st. When that gets set to a valid time, then the date changes to + March 3rd. + + SET TIME + + set time mode allows you to pick a date and time and set the image + time accordingly. Fields may be left out. This is useful when + importing scanned images that don't have an embedded date. + + SYNCHRONIZE TIME + + I recently purchased a 7DmkII to replace my aging 7D. My 7D was still + serviceable, so I bought a remote control and figured I'd try shooting + events from 2 different perspectives. I didn't think to synchonize the + time between the 2 cameras, so when I loaded the images and sorted by + time it was a disaster. I hacked a script together with hard coded values + to adjust the exif_datetime_taken value in the database for the 7D images + so that everything sorted properly. I've tried shooting with 2 cameras + several times since that first attempt. I've gotten better at getting the + camera times close, but still haven't managed to get them to sync. So I + decided to think the problem through and write a proper script to take + care of the problem. + + RESET TIME + + Select the images and click reset. + + USAGE + + ADJUST TIME + + Change the year, month, day, hour, minute, second dropdowns to the amount + of change desired. Select add or subtract. Select the images. Click + adjust. + + SET TIME + + Set the time fields to the desired time. Select the images to change. Click + set. + + SYNCHRONIZE TIME + + Select 2 images, one from each camera, of the same moment in time. Click + the Calculate button to calculate the time difference. The difference is + displayed in the difference entry. You can manually adjust it by changing + the value if necessary. + + Select the images that need their time adjusted. Determine which way to adjust + adjust the time (add or subtract) and select the appropriate choice. + + If the image times get messed up and you just want to start over, select reset time + from the mode and reset the image times. + + RESET TIME + + Select the images and click reset. + + ADDITIONAL SOFTWARE REQUIRED + * exiv2 + + BUGS, COMMENTS, SUGGESTIONS + * Send to Bill Ferguson, wpferguson@gmail.com + + CHANGES + +]] +local dt = require "darktable" +local du = require "lib/dtutils" +local df = require "lib/dtutils.file" +local ds = require "lib/dtutils.string" +local gettext = dt.gettext + +local adj_time = {} + +du.check_min_api_version("3.0.0", "image_time") + + +-- Tell gettext where to find the .mo file translating messages for a particular domain +gettext.bindtextdomain("image_time",dt.configuration.config_dir.."/lua/locale/") + +local function _(msgid) + return gettext.dgettext("image_time", msgid) +end + +local PS = dt.configuration.runnin_os == "windows" and "\\" or "/" +local ERROR = -1 + +-- function to convert from exif time to system time +local function exiftime2systime(exiftime) + local yr,mo,dy,h,m,s = string.match(exiftime, "(%d-):(%d-):(%d-) (%d-):(%d-):(%d+)") + return(os.time{year=yr, month=mo, day=dy, hour=h, min=m, sec=s}) +end + +-- function to convert from systime to exif time +local function systime2exiftime(systime) + local t = os.date("*t", systime) + return(string.format("%4d:%02d:%02d %02d:%02d:%02d", t.year, t.month, t.day, t.hour, t.min, t.sec)) +end + +local function vars2exiftime(year, month, day, hour, min, sec) + local y = tonumber(year) and string.format("%4d", year) or " " + local mo = tonumber(month) and string.format("%02d", month) or " " + local d = tonumber(day) and string.format("%02d", day) or " " + local h = tonumber(hour) and string.format("%02d", hour) or " " + local m = tonumber(min) and string.format("%02d", min) or " " + local s = tonumber(sec) and string.format("%02d", sec) or " " + return(y .. ":" .. mo .. ":" .. d .. " " .. h .. ":" .. m .. ":" .. s) +end + +local function exiftime2vars(exiftime) + return string.match(exiftime, "(%d+):(%d+):(%d+) (%d+):(%d+):(%d+)") +end + +local function calc_time_difference(image1, image2) + return math.abs(exiftime2systime(image1.exif_datetime_taken) - exiftime2systime(image2.exif_datetime_taken)) +end + +local function adjust_image_time(image, difference) + image.exif_datetime_taken = systime2exiftime(exiftime2systime(image.exif_datetime_taken) + difference) + return +end + +local function calculate_difference(images) + if #images == 2 then + adj_time.diff_entry.text = calc_time_difference(images[1], images[2]) + adj_time.btn.sensitive = true + else + dt.print(_("Error: 2 images must be selected")) + end +end + +local function synchronize_times(images, difference) + for _, image in ipairs(images) do + adjust_image_time(image, difference) + end +end + +local function synchronize_time(images) + local sign = 1 + if adj_time.sdir.value == "subtract" then + sign = -1 + end + synchronize_times(images, tonumber(adj_time.diff_entry.text) * sign) +end + +local function add_time(images) + synchronize_times(images, tonumber(adj_time.diff_entry.text)) +end + +local function year_month2months(year, month) + year_months = tonumber(year) and year * 12 or 0 + local months = tonumber(month) and tonumber(month) or 0 + + return year_months + months +end + +local function months2year_month(months) + dt.print_log("months is " .. months) + local year = math.floor(months / 12) + local month = months - (year * 12) + + return year, month +end + +local function get_image_taken_time(image) + -- get original image time + local datetime = nil + + local exiv2 = df.check_if_bin_exists("exiv2") + if exiv2 then + p = io.popen(exiv2 .. " -K Exif.Image.DateTime " .. image.path .. PS .. image.filename) + if p then + for line in p:lines() do + if string.match(line, "Exif.Image.DateTime") then + datetime = string.match(line, "(%d-:%d-:%d- %d-:%d-:%d+)") + end + end + p:close() + end + else + dt.print(_("unable to detect exiv2")) + datetime = ERROR + end + return datetime +end + +local function _get_windows_image_file_creation_time(image) + local datetime = nil + local p = io.popen("dir " .. image.path .. PS .. image.filename) + if p then + for line in p:lines() do + if string.match(line, ds.sanitize_lua(image.filename)) then + local mo, day, yr, hr, min, apm = string.match(line, "(%d+)/(%d+)/(%d+) (%d-):(%d+) (%S+)") + if apm == "PM" then + hr = hr + 12 + end + datetime = vars2exiftime(yr, mo, day, hr, min, 0) + end + end + p:close() + else + dt.print(_("unable to get information for ") .. image.filename) + datetime = ERROR + end + return datetime +end + +local function _get_nix_image_file_creation_time(image) + local datetime = nil + local p = io.popen("ls -lL --time-style=full-iso " .. image.path .. PS .. image.filename) + if p then + for line in p:lines() do + if string.match(line, ds.sanitize_lua(image.filename)) then + datetime = vars2exiftime(string.match(line, "(%d+)%-(%d-)%-(%d-) (%d-):(%d-):(%d+).")) + end + end + p:close() + else + dt.print(_("unable to get information for ") .. image.filename) + datetime = ERROR + end + return datetime +end + +local function get_image_file_creation_time(image) + -- no exif time in the image file so get the creation time + local datetime = nil + if dt.configuration.running_os == "windows" then + datetime = _get_windows_image_file_creation_time(image) + else + datetime = _get_nix_image_file_creation_time(image) + end + return datetime +end + +local function get_original_image_time(image) + local image_time = image.exif_datetime_taken + local reset_time = nil + + reset_time = get_image_taken_time(image) + + if reset_time then + if reset_time == ERROR then + return image_time + else + return reset_time + end + else + reset_time = get_image_file_creation_time(image) + + if reset_time then + if reset_time == ERROR then + return image_time + else + return reset_time + end + end + end +end + +local function reset_time(images) + if #images > 0 then + for _, image in ipairs(images) do + image.exif_datetime_taken = get_original_image_time(image) + end + else + dt.print_error(_("reset time: no images selected")) + dt.print(_("please select the images that need their time reset")) + end +end + +local function adjust_time(images) + local SEC_MIN = 60 + local SEC_HR = SEC_MIN * 60 + local SEC_DY = SEC_HR * 24 + + local offset = nil + local sign = 1 + + if #images < 1 then + dt.print(_("please select some images and try again")) + return + end + + if adj_time.adir.value == _("subtract") then + sign = -1 + end + + for _, image in ipairs(images) do + local y, mo, d, h, m, s = exiftime2vars(image.exif_datetime_taken) + local image_months = year_month2months(y, mo) + local months_diff = year_month2months(adj_time.ayr.value, adj_time.amo.value) + y, mo = months2year_month(image_months + (months_diff * sign)) + local exif_new = vars2exiftime(y, mo, d, h, m, s) + offset = adj_time.ady.value * SEC_DY + offset = offset + adj_time.ahr.value * SEC_HR + offset = offset + adj_time.amn.value * SEC_MIN + offset = offset + adj_time.asc.value + offset = offset * sign + image.exif_datetime_taken = systime2exiftime(exiftime2systime(exif_new) + offset) + end +end + +local function set_time(images) + if #images < 1 then + dt.print(_("please select some images and try again")) + return + end + + local y = adj_time.syr.value + local mo = adj_time.smo.value + local d = adj_time.sdy.value + local h = adj_time.shr.value + local m = adj_time.smn.value + local s = adj_time.ssc.value + + for _, image in ipairs(images) do + image.exif_datetime_taken = vars2exiftime(y, mo, d, h, m, s) + end +end + +local function seq(first, last) + local result = {} + + local num = first + + while num <= last do + table.insert(result, num) + num = num + 1 + end + + return table.unpack(result) +end + +-- widgets + +adj_time.widgets = { + -- name, type, tooltip, placeholder, + {"ayr", "combobox", _("years"), _("years to adjust by, 0 - ?"), {seq(0,20)}, 1}, + {"amo", "combobox", _("months"), ("months to adjust by, 0-12"), {seq(0,12)}, 1}, + {"ady", "combobox", _("days"), ("days to adjust by, 0-31"), {seq(0,31)}, 1}, + {"ahr", "combobox", _("hours"), _("hours to adjust by, 0-23"), {seq(0,23)}, 1}, + {"amn", "combobox", _("minutes"), _("minutes to adjust by, 0-59"), {seq(0,59)}, 1}, + {"asc", "combobox", _("seconds"), _("seconds to adjust by, 0-59"), {seq(0,59)}, 1}, + {"adir", "combobox", _("add/subtract"), _("add or subtract time"), {_("add"), _("subtract")}, 1}, + {"syr", "combobox", _("year"), _("year to set, 1900 - now"), {" ", seq(1900,os.date("*t", os.time()).year)}, 122}, + {"smo", "combobox", _("month"), _("month to set, 1-12"), {" ", seq(1,12)}, 1}, + {"sdy", "combobox", _("day"), _("day to set, 1-31"), {" ", seq(1,31)}, 1}, + {"shr", "combobox", _("hour"), _("hour to set, 0-23"), {" ", seq(0,23)}, 1}, + {"smn", "combobox", _("minute"), _("minutes to set, 0-59"), {" ", seq(0, 59)}, 1}, + {"ssc", "combobox", _("seconds"), _("seconds to set, 0-59"), {" ", seq(0,59)}, 1}, + {"sdir", "combobox", _("add/subtract"), _("add or subtract time"), {_("add"), _("subtract")}, 1}, +} + +for _, widget in ipairs(adj_time.widgets) do + adj_time[widget[1]] = dt.new_widget(widget[2]){ + label = widget[3], + tooltip = widget[4], + selected = widget[6], + table.unpack(widget[5]) + } +end + +adj_time.diff_entry = dt.new_widget("entry"){ + tooltip = _("Time difference between images in seconds"), + placeholder = _("Select 2 images and use the calculate button"), + text = "", +} + +adj_time.calc_btn = dt.new_widget("button"){ + label = _("Calculate"), + tooltip = _("calculate time difference between 2 images"), + clicked_callback = function() + calculate_difference(dt.gui.action_images) + end +} + +adj_time.btn = dt.new_widget("button"){ + label = _("synchronize image times"), + tooltip = _("apply the time difference from selected images"), + sensitive = false, + clicked_callback = function() + synchronize_time(dt.gui.action_images) + end +} + +adj_time.stack = dt.new_widget("stack"){ + dt.new_widget("box"){ + orientation = "vertical", + dt.new_widget("label"){label = _("adjust time")}, + dt.new_widget("section_label"){label = _("days, months, years")}, + adj_time.ady, + adj_time.amo, + adj_time.ayr, + dt.new_widget("section_label"){label = _("hours, minutes, seconds")}, + adj_time.ahr, + adj_time.amn, + adj_time.asc, + dt.new_widget("section_label"){label = _("adjustment direction")}, + adj_time.adir, + dt.new_widget("button"){ + label = _("adjust"), + clicked_callback = function() + adjust_time(dt.gui.action_images) + end + } + }, + dt.new_widget("box"){ + orientation = "vertical", + dt.new_widget("label"){label = _("set time")}, + dt.new_widget("section_label"){label = _("date: ")}, + adj_time.sdy, + adj_time.smo, + adj_time.syr, + dt.new_widget("section_label"){label = _("time:")}, + adj_time.shr, + adj_time.smn, + adj_time.ssc, + dt.new_widget("button"){ + label = _("set"), + clicked_callback = function() + set_time(dt.gui.action_images) + end + } + }, + dt.new_widget("box"){ + orientation = "vertical", + dt.new_widget("label"){label = _("synchronize image time")}, + dt.new_widget("section_label"){label = _("calculate difference between images")}, + adj_time.diff_entry, + adj_time.calc_btn, + dt.new_widget("section_label"){label = _("apply difference")}, + adj_time.sdir, + adj_time.btn, + }, + dt.new_widget("box"){ + orientation = "vertical", + dt.new_widget("label"){label = _("reset to original time")}, + dt.new_widget("separator"){}, + dt.new_widget("button"){ + label = _("reset"), + clicked_callback = function() + reset_time(dt.gui.action_images) + end + } + }, +} + +adj_time.mode = dt.new_widget("combobox"){ + label = _("mode"), + tooltip = _("select mode"), + selected = 1, + changed_callback = function(this) + adj_time.stack.active = this.selected + end, + _("adjust time"), + _("set time"), + _("synchronize time"), + _("reset time") +} + +adj_time.widget = dt.new_widget("box"){ + orientation = "vertical", + adj_time.mode, + adj_time.stack, +} + +dt.register_lib( + "image_time", -- Module name + _("image time"), -- Visible name + true, -- expandable + false, -- resetable + {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, -- containers + adj_time.widget, + nil,-- view_enter + nil -- view_leave +) From e5ab30006bce8962d79f269e1b496688c7b4d25e Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Wed, 24 Jun 2020 21:51:40 -0400 Subject: [PATCH 069/445] Added reset function. Changed namespace to img_time. --- contrib/image_time.lua | 124 ++++++++++++++++++++++++----------------- 1 file changed, 74 insertions(+), 50 deletions(-) diff --git a/contrib/image_time.lua b/contrib/image_time.lua index 62f2e2d8..a13a79aa 100644 --- a/contrib/image_time.lua +++ b/contrib/image_time.lua @@ -109,7 +109,7 @@ local df = require "lib/dtutils.file" local ds = require "lib/dtutils.string" local gettext = dt.gettext -local adj_time = {} +local img_time = {} du.check_min_api_version("3.0.0", "image_time") @@ -161,8 +161,8 @@ end local function calculate_difference(images) if #images == 2 then - adj_time.diff_entry.text = calc_time_difference(images[1], images[2]) - adj_time.btn.sensitive = true + img_time.diff_entry.text = calc_time_difference(images[1], images[2]) + img_time.btn.sensitive = true else dt.print(_("Error: 2 images must be selected")) end @@ -176,14 +176,14 @@ end local function synchronize_time(images) local sign = 1 - if adj_time.sdir.value == "subtract" then + if img_time.sdir.value == "subtract" then sign = -1 end - synchronize_times(images, tonumber(adj_time.diff_entry.text) * sign) + synchronize_times(images, tonumber(img_time.diff_entry.text) * sign) end local function add_time(images) - synchronize_times(images, tonumber(adj_time.diff_entry.text)) + synchronize_times(images, tonumber(img_time.diff_entry.text)) end local function year_month2months(year, month) @@ -321,20 +321,20 @@ local function adjust_time(images) return end - if adj_time.adir.value == _("subtract") then + if img_time.adir.value == _("subtract") then sign = -1 end for _, image in ipairs(images) do local y, mo, d, h, m, s = exiftime2vars(image.exif_datetime_taken) local image_months = year_month2months(y, mo) - local months_diff = year_month2months(adj_time.ayr.value, adj_time.amo.value) + local months_diff = year_month2months(img_time.ayr.value, img_time.amo.value) y, mo = months2year_month(image_months + (months_diff * sign)) local exif_new = vars2exiftime(y, mo, d, h, m, s) - offset = adj_time.ady.value * SEC_DY - offset = offset + adj_time.ahr.value * SEC_HR - offset = offset + adj_time.amn.value * SEC_MIN - offset = offset + adj_time.asc.value + offset = img_time.ady.value * SEC_DY + offset = offset + img_time.ahr.value * SEC_HR + offset = offset + img_time.amn.value * SEC_MIN + offset = offset + img_time.asc.value offset = offset * sign image.exif_datetime_taken = systime2exiftime(exiftime2systime(exif_new) + offset) end @@ -346,12 +346,12 @@ local function set_time(images) return end - local y = adj_time.syr.value - local mo = adj_time.smo.value - local d = adj_time.sdy.value - local h = adj_time.shr.value - local m = adj_time.smn.value - local s = adj_time.ssc.value + local y = img_time.syr.value + local mo = img_time.smo.value + local d = img_time.sdy.value + local h = img_time.shr.value + local m = img_time.smn.value + local s = img_time.ssc.value for _, image in ipairs(images) do image.exif_datetime_taken = vars2exiftime(y, mo, d, h, m, s) @@ -371,9 +371,28 @@ local function seq(first, last) return table.unpack(result) end +local function reset_widgets() + dt.print_log("took the reset function") + img_time.ayr.selected = 1 + img_time.amo.selected = 1 + img_time.ady.selected = 1 + img_time.ahr.selected = 1 + img_time.ayr.selected = 1 + img_time.amn.selected = 1 + img_time.asc.selected = 1 + img_time.adir.selected = 1 + img_time.syr.selected = #img_time.syr + img_time.smo.selected = 1 + img_time.sdy.selected = 1 + img_time.shr.selected = 1 + img_time.smn.selected = 1 + img_time.ssc.selected = 1 + img_time.adir.selected = 1 +end + -- widgets -adj_time.widgets = { +img_time.widgets = { -- name, type, tooltip, placeholder, {"ayr", "combobox", _("years"), _("years to adjust by, 0 - ?"), {seq(0,20)}, 1}, {"amo", "combobox", _("months"), ("months to adjust by, 0-12"), {seq(0,12)}, 1}, @@ -382,7 +401,7 @@ adj_time.widgets = { {"amn", "combobox", _("minutes"), _("minutes to adjust by, 0-59"), {seq(0,59)}, 1}, {"asc", "combobox", _("seconds"), _("seconds to adjust by, 0-59"), {seq(0,59)}, 1}, {"adir", "combobox", _("add/subtract"), _("add or subtract time"), {_("add"), _("subtract")}, 1}, - {"syr", "combobox", _("year"), _("year to set, 1900 - now"), {" ", seq(1900,os.date("*t", os.time()).year)}, 122}, + {"syr", "combobox", _("year"), _("year to set, 1900 - now"), {" ", seq(1900,os.date("*t", os.time()).year)}, 1}, {"smo", "combobox", _("month"), _("month to set, 1-12"), {" ", seq(1,12)}, 1}, {"sdy", "combobox", _("day"), _("day to set, 1-31"), {" ", seq(1,31)}, 1}, {"shr", "combobox", _("hour"), _("hour to set, 0-23"), {" ", seq(0,23)}, 1}, @@ -391,8 +410,8 @@ adj_time.widgets = { {"sdir", "combobox", _("add/subtract"), _("add or subtract time"), {_("add"), _("subtract")}, 1}, } -for _, widget in ipairs(adj_time.widgets) do - adj_time[widget[1]] = dt.new_widget(widget[2]){ +for _, widget in ipairs(img_time.widgets) do + img_time[widget[1]] = dt.new_widget(widget[2]){ label = widget[3], tooltip = widget[4], selected = widget[6], @@ -400,13 +419,15 @@ for _, widget in ipairs(adj_time.widgets) do } end -adj_time.diff_entry = dt.new_widget("entry"){ +img_time.syr.selected = #img_time.syr + +img_time.diff_entry = dt.new_widget("entry"){ tooltip = _("Time difference between images in seconds"), placeholder = _("Select 2 images and use the calculate button"), text = "", } -adj_time.calc_btn = dt.new_widget("button"){ +img_time.calc_btn = dt.new_widget("button"){ label = _("Calculate"), tooltip = _("calculate time difference between 2 images"), clicked_callback = function() @@ -414,7 +435,7 @@ adj_time.calc_btn = dt.new_widget("button"){ end } -adj_time.btn = dt.new_widget("button"){ +img_time.btn = dt.new_widget("button"){ label = _("synchronize image times"), tooltip = _("apply the time difference from selected images"), sensitive = false, @@ -423,20 +444,20 @@ adj_time.btn = dt.new_widget("button"){ end } -adj_time.stack = dt.new_widget("stack"){ +img_time.stack = dt.new_widget("stack"){ dt.new_widget("box"){ orientation = "vertical", dt.new_widget("label"){label = _("adjust time")}, dt.new_widget("section_label"){label = _("days, months, years")}, - adj_time.ady, - adj_time.amo, - adj_time.ayr, + img_time.ady, + img_time.amo, + img_time.ayr, dt.new_widget("section_label"){label = _("hours, minutes, seconds")}, - adj_time.ahr, - adj_time.amn, - adj_time.asc, + img_time.ahr, + img_time.amn, + img_time.asc, dt.new_widget("section_label"){label = _("adjustment direction")}, - adj_time.adir, + img_time.adir, dt.new_widget("button"){ label = _("adjust"), clicked_callback = function() @@ -448,13 +469,13 @@ adj_time.stack = dt.new_widget("stack"){ orientation = "vertical", dt.new_widget("label"){label = _("set time")}, dt.new_widget("section_label"){label = _("date: ")}, - adj_time.sdy, - adj_time.smo, - adj_time.syr, + img_time.sdy, + img_time.smo, + img_time.syr, dt.new_widget("section_label"){label = _("time:")}, - adj_time.shr, - adj_time.smn, - adj_time.ssc, + img_time.shr, + img_time.smn, + img_time.ssc, dt.new_widget("button"){ label = _("set"), clicked_callback = function() @@ -466,11 +487,11 @@ adj_time.stack = dt.new_widget("stack"){ orientation = "vertical", dt.new_widget("label"){label = _("synchronize image time")}, dt.new_widget("section_label"){label = _("calculate difference between images")}, - adj_time.diff_entry, - adj_time.calc_btn, + img_time.diff_entry, + img_time.calc_btn, dt.new_widget("section_label"){label = _("apply difference")}, - adj_time.sdir, - adj_time.btn, + img_time.sdir, + img_time.btn, }, dt.new_widget("box"){ orientation = "vertical", @@ -485,12 +506,12 @@ adj_time.stack = dt.new_widget("stack"){ }, } -adj_time.mode = dt.new_widget("combobox"){ +img_time.mode = dt.new_widget("combobox"){ label = _("mode"), tooltip = _("select mode"), selected = 1, changed_callback = function(this) - adj_time.stack.active = this.selected + img_time.stack.active = this.selected end, _("adjust time"), _("set time"), @@ -498,19 +519,22 @@ adj_time.mode = dt.new_widget("combobox"){ _("reset time") } -adj_time.widget = dt.new_widget("box"){ +img_time.widget = dt.new_widget("box"){ orientation = "vertical", - adj_time.mode, - adj_time.stack, + reset_callback = function(this) + reset_widgets() + end, + img_time.mode, + img_time.stack, } dt.register_lib( "image_time", -- Module name _("image time"), -- Visible name true, -- expandable - false, -- resetable + true, -- resetable {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, -- containers - adj_time.widget, + img_time.widget, nil,-- view_enter nil -- view_leave ) From 323c8b68456f38de6852ceeab31f2fe63932b60e Mon Sep 17 00:00:00 2001 From: "U-DESKTOP-HQME86J\\marco" Date: Sat, 4 Jul 2020 10:27:06 +0200 Subject: [PATCH 070/445] add doc comments --- contrib/RL_out_sharp.lua | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/contrib/RL_out_sharp.lua b/contrib/RL_out_sharp.lua index fcc553e4..75446d12 100644 --- a/contrib/RL_out_sharp.lua +++ b/contrib/RL_out_sharp.lua @@ -1,10 +1,29 @@ --[[ + Richardson-Lucy output sharpening for darktable using GMic + darktable is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + darktable is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with darktable. If not, see . +]] + +--[[ DESCRIPTION RL_out_sharp.lua - Richardson-Lucy output sharpening using GMic This script provides a new target storage "RL output sharpen". Images exported will be sharpened using GMic (RL deblur algorithm) + + REQUIRED SOFTWARE + GMic command line interface (CLI) https://gmic.eu/download.shtml USAGE * require this script from main lua file @@ -33,7 +52,6 @@ CHANGES * 20200308 - initial version - ]] local dt = require "darktable" @@ -156,7 +174,7 @@ sigma_slider = dt.new_widget("slider"){ soft_max = 2.0, hard_min = 0.0, hard_max = 3.0, - step = 0.1, + step = 0.05, digits = 2, value = 1.0 } From 2d49b49bec1a2967ad4f65f6df17bf8ec523c7f6 Mon Sep 17 00:00:00 2001 From: "U-DESKTOP-HQME86J\\marco" Date: Sat, 4 Jul 2020 10:45:59 +0200 Subject: [PATCH 071/445] add doc comments to ext_editor --- contrib/ext_editor.lua | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/contrib/ext_editor.lua b/contrib/ext_editor.lua index 19e711c4..4035c228 100644 --- a/contrib/ext_editor.lua +++ b/contrib/ext_editor.lua @@ -1,11 +1,25 @@ --[[ + ext_editor.lua - edit images with external editors - DESCRIPTION + darktable is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + darktable is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with darktable. If not, see . +]] + +--[[ ext_editor.lua - edit images with external editors This script provides helpers to edit image files with programs external to darktable. It adds: - - a new target storage "collection". Image exported will be reimported to collection for - further edit with external programs + - a new target storage "collection". Image exported will be reimported to collection for further edit with external programs - a new lighttable module "external editors", to select a program from a list of up to - 9 external editors and run it on a selected image (adjust this limit by changing MAX_EDITORS) - a set of lua preferences in order to configure name and path of up to 9 external editors @@ -48,16 +62,8 @@ CAVEATS * MAC compatibility not tested - TODO - * send multiple images to the same program, maybe - BUGS, COMMENTS, SUGGESTIONS * send to Marco Carrarini, marco.carrarini@gmail.com - - CHANGES - * 20191224 - initial version - * 20191227 - added button "update list", better error handling, fixed bug with groups/tags in "edit" - ]] From 593917db9a50426fd77b0752dddf65d73f4914eb Mon Sep 17 00:00:00 2001 From: Noah Date: Sat, 4 Jul 2020 23:20:30 -0700 Subject: [PATCH 072/445] Fix gettext implementation --- contrib/exportLUT.lua | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/contrib/exportLUT.lua b/contrib/exportLUT.lua index 5d85bdc9..aa76b0d3 100644 --- a/contrib/exportLUT.lua +++ b/contrib/exportLUT.lua @@ -33,6 +33,12 @@ local ds = require("lib/dtutils.system") local gettext = dt.gettext +gettext.bindtextdomain("exportLUT",dt.configuration.config_dir.."/lua/locale/") + +local function _(msgid) + return gettext.dgettext("exportLUT", msgid) +end + du.check_min_api_version("5.0.0", "exportLUT") -- Thanks Kevin Ertel for this bit @@ -42,27 +48,27 @@ local mkdir_command = 'mkdir -p ' if dt.configuration.running_os == 'windows' then mkdir_command = 'mkdir ' end local file_chooser_button = dt.new_widget("file_chooser_button"){ - title = gettext.gettext("Identity_file_chooser"), + title = _("Identity_file_chooser"), value = "", is_directory = false } local export_chooser_button = dt.new_widget("file_chooser_button"){ - title = gettext.gettext("Export_location_chooser"), + title = _("Export_location_chooser"), value = "", is_directory = true } local identity_label = dt.new_widget("label"){ - label = gettext.gettext("choose the identity haldclut file") + label = _("choose the identity haldclut file") } local output_label = dt.new_widget("label"){ - label = gettext.gettext("choose the output location") + label = _("choose the output location") } local warning_label = dt.new_widget("label"){ - label = gettext.gettext("WARNING: files may be silently overwritten") + label = _("WARNING: files may be silently overwritten") } local function end_job(job) @@ -84,9 +90,9 @@ end local function export_luts() local identity = dt.database.import(file_chooser_button.value) if(type(identity) ~= "userdata") then - dt.print(gettext.gettext("Invalid identity lut file")) + dt.print(_("Invalid identity lut file")) else - local job = dt.gui.create_job(gettext.gettext('Exporting styles as haldCLUTs'), true, end_job) + local job = dt.gui.create_job(_('Exporting styles as haldCLUTs'), true, end_job) local size = 1 @@ -105,22 +111,22 @@ local function export_luts() io_lut:write_image(identity, output_path(style.name, job)) count = count + 1 job.percent = count / size - dt.print(gettext.gettext("Exported: ") .. output_path(style.name, job)) + dt.print(_("Exported: ") .. output_path(style.name, job)) end - dt.print(gettext.gettext("Done exporting haldCLUTs")) + dt.print(_("Done exporting haldCLUTs")) job.valid = false identity:reset() end end local export_button = dt.new_widget("button"){ - label = gettext.gettext("export"), + label = _("export"), clicked_callback = export_luts } dt.register_lib( - gettext.gettext("export haldclut"), - gettext.gettext("export haldclut"), + _("export haldclut"), + _("export haldclut"), true, false, {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, From a40fe3099de49b8041013b29f27dd19ca36d275d Mon Sep 17 00:00:00 2001 From: Cameron Chamberlain Date: Sun, 19 Jul 2020 10:54:48 +1000 Subject: [PATCH 073/445] Typo in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2381dbc4..2439e05d 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ geoJSON_export|No|L|Create a geo JSON script with thumbnails for use in ... geoToolbox|No|LMW|A toolbox of geo functions gimp|No|LMW|Open an image in GIMP for editing and return the result gpx_export|No|LMW|Export a GPX track file from selected images GPS data -HDRMerge|No|LMW|Combind the selected images into an HDR DNG and return the result +HDRMerge|No|LMW|Combine the selected images into an HDR DNG and return the result hugin|No|LMW|Combine selected images into a panorama and return the result image_stack|No|LMW|Combine a stack of images to remove noise or transient objects kml_export|No|L|Export photos with a KML file for usage in Google Earth From 53bb95e6fd544998000be2fdff60699903b9a3d8 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sun, 19 Jul 2020 13:13:24 -0400 Subject: [PATCH 074/445] Added entry widget to display the current setting, or a placeholder specifying what would or should happen depending on operating system to provide visual feedback. --- tools/executable_manager.lua | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tools/executable_manager.lua b/tools/executable_manager.lua index 03e35f66..d037d002 100644 --- a/tools/executable_manager.lua +++ b/tools/executable_manager.lua @@ -117,8 +117,15 @@ for _,pref in ipairs(matches) do end local executable_path_widgets = {} +local executable_path_values = {} +local placeholder_text = dt.configuration.running_os == windows and "select an executable" or "search path for executable" for i,exec in ipairs(exec_table) do + executable_path_values[exec] = dt.new_widget("entry"){ + text = df.get_executable_path_preference(exec), + placeholder = placeholder_text, + editable = false + } executable_path_widgets[exec] = dt.new_widget("file_chooser_button"){ title = _("select ") .. exec .. _(" executable"), value = df.get_executable_path_preference(exec), @@ -126,6 +133,7 @@ for i,exec in ipairs(exec_table) do changed_callback = function(self) if df.check_if_bin_exists(self.value) then df.set_executable_path_preference(exec, self.value) + executable_path_values[exec].text = df.get_executable_path_preference(exec) end end } @@ -155,13 +163,18 @@ exec_man.selector = dt.new_widget("combobox"){ for i,exec in ipairs(exec_table) do exec_man.stack[i] = dt.new_widget("box"){ + dt.new_widget("section_label"){label = "current"}, + executable_path_values[exec], + dt.new_widget("section_label"){label = "select"}, executable_path_widgets[exec], + dt.new_widget("section_label"){label = "reset"}, dt.new_widget("button"){ label = "clear", tooltip = _("Clear path for ") .. exec, clicked_callback = function() df.set_executable_path_preference(exec, "") executable_path_widgets[exec].value = "" + executable_path_values[exec].text = "" end } From 57a9a8495c8330e21474c368e6ef5f6ee0263b88 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sun, 19 Jul 2020 15:38:08 -0400 Subject: [PATCH 075/445] made newly added strings translatable --- tools/executable_manager.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/executable_manager.lua b/tools/executable_manager.lua index d037d002..f45ecb61 100644 --- a/tools/executable_manager.lua +++ b/tools/executable_manager.lua @@ -118,7 +118,7 @@ end local executable_path_widgets = {} local executable_path_values = {} -local placeholder_text = dt.configuration.running_os == windows and "select an executable" or "search path for executable" +local placeholder_text = dt.configuration.running_os == windows and _("select an executable") or _("search path for executable") for i,exec in ipairs(exec_table) do executable_path_values[exec] = dt.new_widget("entry"){ @@ -163,11 +163,11 @@ exec_man.selector = dt.new_widget("combobox"){ for i,exec in ipairs(exec_table) do exec_man.stack[i] = dt.new_widget("box"){ - dt.new_widget("section_label"){label = "current"}, + dt.new_widget("section_label"){label = _("current")}, executable_path_values[exec], - dt.new_widget("section_label"){label = "select"}, + dt.new_widget("section_label"){label = _("select")}, executable_path_widgets[exec], - dt.new_widget("section_label"){label = "reset"}, + dt.new_widget("section_label"){label = _("reset")}, dt.new_widget("button"){ label = "clear", tooltip = _("Clear path for ") .. exec, From 04525e12585c7e9bc904657d3627cdc5c9f3f4e1 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Tue, 21 Jul 2020 16:39:34 -0400 Subject: [PATCH 076/445] Added functions is_file(path), is_dir(path, and is_executable(path) to ensure a path is a file, directory, or executable respectively. Replaced code in check_if_bin_exists with these functions to reduce the lines of code and make it more understandable. --- lib/dtutils/file.lua | 180 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 169 insertions(+), 11 deletions(-) diff --git a/lib/dtutils/file.lua b/lib/dtutils/file.lua index aaf7f011..a6e24045 100644 --- a/lib/dtutils/file.lua +++ b/lib/dtutils/file.lua @@ -35,6 +35,112 @@ local function _(msgid) return gettext.dgettext("dtutils.file", msgid) end +dtutils_file.libdoc.functions["is_dir"] = { + Name = [[is_dir]], + Synopsis = [[check if a path is a directory]], + Usage = [[local df = require "lib/dtutils.file" + + local result = df.is_dir(path) + path - string - the path to check]], + Description = [[is_dir checks a path to see if it is a directory]], + Return_Value = [[result - boolean - true if path is a directory, nil if not]], + Limitations = [[]], + Example = [[]], + See_Also = [[]], + Reference = [[]], + License = [[]], + Copyright = [[]], +} + +function dtutils_file.is_dir(path) + local cmd = nil + + if dt.configuration.running_os == "windows" then + cmd = "if exist " .. ds.sanitize(path .. "\\*") + else + cmd = "test -d " .. ds.sanitize(path) + end + + return os.execute(cmd) +end + +dtutils_file.libdoc.functions["is_file"] = { + Name = [[is_file]], + Synopsis = [[check if a path is a file]], + Usage = [[local df = require "lib/dtutils.file" + + local result = df.is_file(path) + path - string - the path to check]], + Description = [[is_file checks a path to see if it is a file]], + Return_Value = [[result - boolean - true if path is a file, nil if not]], + Limitations = [[]], + Example = [[]], + See_Also = [[]], + Reference = [[]], + License = [[]], + Copyright = [[]], +} + +function dtutils_file.is_file(path) + local cmd = nil + + if dt.configuration.running_os == "windows" then + if not dtutils_file.is_dir(path) then + cmd = "if exist " .. ds.sanitize(path) + else + return nil + end + else + cmd = "test -f " .. ds.sanitize(path) + end + + return os.execute(cmd) +end + +dtutils_file.libdoc.functions["is_executable"] = { + Name = [[is_executable]], + Synopsis = [[check if a path is a executable]], + Usage = [[local df = require "lib/dtutils.file" + + local result = df.is_executable(path) + path - string - the path to check]], + Description = [[is_executable checks a path to see if it is an executable]], + Return_Value = [[result - boolean - true if path is an executable, nil if not]], + Limitations = [[]], + Example = [[]], + See_Also = [[]], + Reference = [[]], + License = [[]], + Copyright = [[]], +} + +local function _is_windows_executable(path) + local result = nil + + if (string.match(path, ".exe$") or string.match(path, ".EXE$")) or + (string.match(path, ".com$") or string.match(path, ".COM$")) or + (string.match(path, ".bat$") or string.match(path, ".BAT$")) or + (string.match(path, ".cmd$") or string.match(path, ".CMD$")) then + result = true + end + return result +end + + +function dtutils_file.is_executable(path) + + local result = nil + + if dt.configuration.running_os == "windows" then + if _is_windows_executable(path) then + result = true + end + else + result = os.execute("test -x " .. ds.sanitize(path)) + end + return result +end + dtutils_file.libdoc.functions["check_if_bin_exists"] = { Name = [[check_if_bin_exists]], Synopsis = [[check if an executable exists]], @@ -67,11 +173,9 @@ local function _check_if_bin_exists_windows(bin) path = dtutils_file.get_executable_path_preference(bin) end - if (string.match(path, ".exe$") or string.match(path, ".EXE$")) or - (string.match(path, ".com$") or string.match(path, ".COM$")) or - (string.match(path, ".bat$") or string.match(path, ".BAT$")) or - (string.match(path, ".cmd$") or string.match(path, ".CMD$")) then - if dtutils_file.check_if_file_exists(path) then + + if dtutils_file.check_if_file_exists(path) then + if dtutils_file.is-executable(path) then result = dtutils_file.sanitize_filename(path) end end @@ -93,16 +197,14 @@ local function _check_if_bin_exists_nix(bin) if string.len(path) > 0 then -- check for windows executable to run under wine - if string.match(path, ".exe$") or string.match(path, ".EXE$") then + if _is-windows_executable(path) then if dtutils_file.check_if_file_exists(path) then result = dtutils_file.sanitize_filename(path) end else if dtutils_file.check_if_file_exists(path) then - local spath = dtutils_file.sanitize_filename(path) - -- check that it's an executable file - if os.execute("test -f " .. spath .. " && test -x " .. spath) then - result = spath + if dtutils_file.is_file(path) and dtutils_file.is_executable(path) then + result = ds.sanitize(path) end end end @@ -112,8 +214,9 @@ local function _check_if_bin_exists_nix(bin) local output = p:read("*a") p:close() if string.len(output) > 0 then + local spath = dtutils_file.sanitize_filename(output:sub(1,-2)) - if os.execute("test -f " .. spath .. " && test -x " .. spath) then + if dtutils_file.is_file(spath) and dtutils_file.is_executable(spath) then result = spath end end @@ -670,6 +773,61 @@ function dtutils_file.rmdir(path) return dsys.external_command(rm_cmd.." "..path) end +function dtutils_file.is_dir(path) + local cmd = nil + + if dt.configuration.running_os == "windows" then + cmd = "if exist " .. ds.sanitize(path .. "\\*") + else + cmd = "test -d " .. ds.sanitize(path) + end + + return os.execute(cmd) +end + +function dtutils_file.is_file(path) + local cmd = nil + + if dt.configuration.running_os == "windows" then + if not dtutils_file.is_dir(path) then + cmd = "if exist " .. ds.sanitize(path) + else + return nil + end + else + cmd = "test -f " .. ds.sanitize(path) + end + + return os.execute(cmd) +end + +local function is_windows_executable(path) + local result = nil + + if (string.match(path, ".exe$") or string.match(path, ".EXE$")) or + (string.match(path, ".com$") or string.match(path, ".COM$")) or + (string.match(path, ".bat$") or string.match(path, ".BAT$")) or + (string.match(path, ".cmd$") or string.match(path, ".CMD$")) then + result = true + end + return result +end + + +function dtutils_file.is_executable(path) + + local result = nil + + if dt.configuration.running_os == "windows" then + if _is_windows_executable(path) then + result = true + end + else + result = os.execute("test -x " .. ds.sanitize(path)) + end + return result +end + return dtutils_file From 1d5192a39cf57cbf3074094de7f300fe8e0cade6 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Tue, 21 Jul 2020 20:40:22 -0400 Subject: [PATCH 077/445] removed duplpicate copies of the is_ functions --- lib/dtutils/file.lua | 56 -------------------------------------------- 1 file changed, 56 deletions(-) diff --git a/lib/dtutils/file.lua b/lib/dtutils/file.lua index a6e24045..9f02bfd8 100644 --- a/lib/dtutils/file.lua +++ b/lib/dtutils/file.lua @@ -773,61 +773,5 @@ function dtutils_file.rmdir(path) return dsys.external_command(rm_cmd.." "..path) end -function dtutils_file.is_dir(path) - local cmd = nil - - if dt.configuration.running_os == "windows" then - cmd = "if exist " .. ds.sanitize(path .. "\\*") - else - cmd = "test -d " .. ds.sanitize(path) - end - - return os.execute(cmd) -end - -function dtutils_file.is_file(path) - local cmd = nil - - if dt.configuration.running_os == "windows" then - if not dtutils_file.is_dir(path) then - cmd = "if exist " .. ds.sanitize(path) - else - return nil - end - else - cmd = "test -f " .. ds.sanitize(path) - end - - return os.execute(cmd) -end - -local function is_windows_executable(path) - local result = nil - - if (string.match(path, ".exe$") or string.match(path, ".EXE$")) or - (string.match(path, ".com$") or string.match(path, ".COM$")) or - (string.match(path, ".bat$") or string.match(path, ".BAT$")) or - (string.match(path, ".cmd$") or string.match(path, ".CMD$")) then - result = true - end - return result -end - - -function dtutils_file.is_executable(path) - - local result = nil - - if dt.configuration.running_os == "windows" then - if _is_windows_executable(path) then - result = true - end - else - result = os.execute("test -x " .. ds.sanitize(path)) - end - return result -end - - return dtutils_file From 7790c9700ba5bca77478f0e230012518cc1a6b29 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sun, 2 Aug 2020 18:33:49 -0400 Subject: [PATCH 078/445] Separated check_if_bin_exists() into 2 functions, one to check the returned executable_path variable and another to search for the binary if it wasn't detected. All results are checked to ensure they exist, are a file, and are executable. This fixes the situation where a directory gets stored as an executable path. Search functions are operating system specific. Executable paths are saved for MacOS and Windows to make for shorter searches in the future. --- lib/dtutils/file.lua | 181 +++++++++++++++++++++++++++++++------------ 1 file changed, 132 insertions(+), 49 deletions(-) diff --git a/lib/dtutils/file.lua b/lib/dtutils/file.lua index 9f02bfd8..05f229f1 100644 --- a/lib/dtutils/file.lua +++ b/lib/dtutils/file.lua @@ -83,18 +83,27 @@ dtutils_file.libdoc.functions["is_file"] = { function dtutils_file.is_file(path) local cmd = nil + local result = false if dt.configuration.running_os == "windows" then if not dtutils_file.is_dir(path) then - cmd = "if exist " .. ds.sanitize(path) + cmd = "if exist " .. ds.sanitize(path) .. " echo true" + local p = io.popen(cmd) + output = p:read("*a") + p:close() + if string.match(output, "true") then + result = true + else + result = false + end else - return nil + return false end else - cmd = "test -f " .. ds.sanitize(path) + result = os.execute("test -f " .. ds.sanitize(path)) end - return os.execute(cmd) + return result end dtutils_file.libdoc.functions["is_executable"] = { @@ -116,17 +125,17 @@ dtutils_file.libdoc.functions["is_executable"] = { local function _is_windows_executable(path) local result = nil + dt.print_log("checking " .. path) - if (string.match(path, ".exe$") or string.match(path, ".EXE$")) or - (string.match(path, ".com$") or string.match(path, ".COM$")) or - (string.match(path, ".bat$") or string.match(path, ".BAT$")) or - (string.match(path, ".cmd$") or string.match(path, ".CMD$")) then + if string.match(path, ".exe$") or string.match(path, ".EXE$") or + string.match(path, ".com$") or string.match(path, ".COM$") or + string.match(path, ".bat$") or string.match(path, ".BAT$") or + string.match(path, ".cmd$") or string.match(path, ".CMD$") then result = true end return result end - function dtutils_file.is_executable(path) local result = nil @@ -163,73 +172,146 @@ dtutils_file.libdoc.functions["check_if_bin_exists"] = { Copyright = [[]], } -local function _check_if_bin_exists_windows(bin) +local function _search_for_bin_windows(bin) local result = false - local path = nil + -- use where on path + -- use where on program files + -- use where on program files (x86) + local args = {"", '/R "C:\\Program Files"', '/R "C:\\Program Files (x86)"'} + + for _,arg in ipairs(args) do + local cmd = "where " .. arg .. " " .. ds.sanitize(bin) + local p = io.popen(cmd) + local output = p:read("*a") + p:close() + local lines = du.split(output, "\n") + for _,line in ipairs(lines) do + if string.match(line, bin) then + if dtutils_file.is_file(line) and dtutils_file.is_executable(line) then + dtutils_file.set_executable_path_preference(bin, line) -- save it so we don't have to search again + return line + end + end + end + end + return result +end - if string.match(bin, "\\") then - path = bin - else - path = dtutils_file.get_executable_path_preference(bin) +local function _search_for_bin_nix(bin) + local result = false + local p = io.popen("which " .. bin) + local output = p:read("*a") + p:close() + if string.len(output) > 0 then + local spath = dtutils_file.sanitize_filename(output:sub(1,-2)) + if dtutils_file.is_file(spath) and dtutils_file.is_executable(spath) then + result = spath + end end + return result +end +local function _search_for_bin_macos(bin) + local result = false + + result = _search_for_bin_nix(bin) - if dtutils_file.check_if_file_exists(path) then - if dtutils_file.is-executable(path) then - result = dtutils_file.sanitize_filename(path) + if not result then + local search_start = "/Applications" + + if dtutils_file.check_if_file_exists("/Applications/" .. bin .. ".app") then + search_start = "/Applications/" .. bin .. ".app" + end + + local p = io.popen("find " .. search_start .. " -type f -name " .. bin .. " -print") + local output = p:read("*a") + p:close() + local lines = du.split(output, "\n") + + for _,line in ipairs(lines) do + local spath = dtutils_file.sanitize_filename(line:sub(1, -2)) + if dtutils_file.is_executable(spath) then + dtutils_file.set_executable_path_preference(bin, spath) + result = spath + end end end + return result end --- check_if_bin_exists for unix like systems (linux, macos) -local function _check_if_bin_exists_nix(bin) +local function _search_for_bin(bin) local result = false - local path = nil - if string.match(bin, "/") then - path = bin + if dt.configuration.running_os == "windows" then + result = _search_for_bin_windows(bin) + elseif dt.configuration.running_os == "macos" then + result = _search_for_bin_macos(bin) else - path = dtutils_file.get_executable_path_preference(bin) + result = _search_for_bin_nix(bin) end - if path then dt.print_log("path is " .. path) end + return result +end + +local function _check_path_for_wine_bin(path) + local result = false if string.len(path) > 0 then -- check for windows executable to run under wine - if _is-windows_executable(path) then - if dtutils_file.check_if_file_exists(path) then - result = dtutils_file.sanitize_filename(path) - end - else + if _is_windows_executable(path) then if dtutils_file.check_if_file_exists(path) then - if dtutils_file.is_file(path) and dtutils_file.is_executable(path) then - result = ds.sanitize(path) - end + result = "wine " .. dtutils_file.sanitize_filename(path) end end end - if not result then - local p = io.popen("which " .. bin) - local output = p:read("*a") - p:close() - if string.len(output) > 0 then + return result +end - local spath = dtutils_file.sanitize_filename(output:sub(1,-2)) - if dtutils_file.is_file(spath) and dtutils_file.is_executable(spath) then - result = spath - end +local function _check_path_for_bin(bin) + local result = false + local path = nil + + local PS = dt.configuration.running_os == "windows" and "\\" or "/" + + if string.match(bin, PS) then + path = bin + else + path = dtutils_file.get_executable_path_preference(bin) + -- reset path preference is the returned preference is a directory + if dtutils_file.is_dir(path) then + dtutils_file.set_executable_path_preference(bin, "") + path = nil + end + end + + if path and dtutils_file.is_dir(path) then + path = nil + end + + if path and dt.configuration.running_os ~= "windows" then + result = _check_path_for_wine_bin(path) + end + + if path and not result then + if dtutils_file.is_executable(path) then + result = dtutils_file.sanitize_filename(path) end end + return result end function dtutils_file.check_if_bin_exists(bin) - if dt.configuration.running_os == "windows" then - return _check_if_bin_exists_windows(bin) - else - return _check_if_bin_exists_nix(bin) + local result = false + + result = _check_path_for_bin(bin) + + if not result then + result = _search_for_bin(bin) end + + return result end dtutils_file.libdoc.functions["split_filepath"] = { @@ -688,10 +770,11 @@ function dtutils_file.executable_path_widget(executables) is_directory = false, changed_callback = function(self) if dtutils_file.check_if_bin_exists(self.value) then - dtutils_file.set_executable_path_preference(executable, dtutils_file.check_if_bin_exists(self.value)) + dtutils_file.set_executable_path_preference(executable, self.value) end - end} - ) + end + } + ) end local box = dt.new_widget("box"){ orientation = "vertical", From b23595ff54e3b3228dda5a8659c6dcf5944808be Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Mon, 3 Aug 2020 18:52:28 -0400 Subject: [PATCH 079/445] Added latest scripts --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 2439e05d..6b9a0f3a 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,7 @@ CollectHelper|Yes|LMW|Add buttons to selected images module to manipulate the co copy_attach_detach_tags|Yes|LMW|Copy and paste tags from/to images cr2hdr|Yes|L|Process image created with Magic Lantern Dual ISO enfuseAdvanced|No|LMW|Merge multiple images into Dynamic Range Increase (DRI) or Depth From Focus (DFF) images +exportLUT|Yes|LMW|Create a LUT from a style and export it ext_editor|No|LW|Export pictures to collection and edit them with up to nine user-defined external editors face_recognition|No|LM|Identify and tag images using facial recognition fujifilm_ratings|No|LM|Support importing Fujifilm ratings @@ -49,6 +50,7 @@ gpx_export|No|LMW|Export a GPX track file from selected images GPS data HDRMerge|No|LMW|Combine the selected images into an HDR DNG and return the result hugin|No|LMW|Combine selected images into a panorama and return the result image_stack|No|LMW|Combine a stack of images to remove noise or transient objects +image_time|Yes|LMW|Adjust the EXIF image time kml_export|No|L|Export photos with a KML file for usage in Google Earth LabelsToTags|Yes|LMW|Apply tags based on color labels and ratings OpenInExplorer|No|LMW|Open the selected images in the system file manager @@ -215,7 +217,7 @@ Open a terminal and start darktable with the command `darktable -d lua`. This pr ### Windows -Open the Git Bash Shell. Start darktable with the command `/c/Program\ Files/darktable/bin/darktable -d lua`. This provides debugging information to give you insight into what is happening. +Open a command prompt. Start darktable with the command C:\"Program Files\darktable\bind\darktable" -d lua > log.txt. This provides debugging information to give you insight into what is happening. ## Contributing From 797d668ebb71720e749eb6728d81f3aae2cfb8f9 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Tue, 4 Aug 2020 11:11:41 -0400 Subject: [PATCH 080/445] Fixed typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6b9a0f3a..438f5087 100644 --- a/README.md +++ b/README.md @@ -217,7 +217,7 @@ Open a terminal and start darktable with the command `darktable -d lua`. This pr ### Windows -Open a command prompt. Start darktable with the command C:\"Program Files\darktable\bind\darktable" -d lua > log.txt. This provides debugging information to give you insight into what is happening. +Open a command prompt. Start darktable with the command "C:\Program Files\darktable\bin\darktable" -d lua > log.txt. This provides debugging information to give you insight into what is happening. ## Contributing From d1e330eee07bdae2792b2204fe97edd473e21b17 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sat, 8 Aug 2020 22:01:58 -0400 Subject: [PATCH 081/445] Added check to ensure we are in lighttable view prior to callling darktable.register_lib. If darktable was invoked in single image (darkroom) mode, then an event handler is registered to detect the change from darkroom mode to lighttable mode so that we can then call darktable.register_lib. --- tools/script_manager.lua | 52 ++++++++++++++++++++++++++++------------ 1 file changed, 37 insertions(+), 15 deletions(-) diff --git a/tools/script_manager.lua b/tools/script_manager.lua index 0946ae51..9592a7ef 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -450,6 +450,26 @@ local function link_downloads_directory() os.execute("ln -s " .. "$HOME/Downloads " .. LUA_DIR .. "/downloads") end +local function install_module() + if not sm.module_installed then + dt.register_lib( + "script_manager", -- Module name + "script manager", -- Visible name + true, -- expandable + false, -- resetable + {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_LEFT_CENTER", 0}}, -- containers + dt.new_widget("box") -- widget + { + orientation = "vertical", + sm.main_box, + }, + nil,-- view_enter + nil -- view_leave + ) + sm.module_installed = true + end +end + -- - - - - - - - - - - - - - - - - - - - - - - - -- M A I N P R O G R A M -- - - - - - - - - - - - - - - - - - - - - - - - @@ -466,6 +486,8 @@ sm.script_names = {} sm.script_paths = {} sm.main_menu_choices = {} sm.main_stack_items = {} +sm.event_registered = false +sm.module_installed = false -- see if we've run this before @@ -742,21 +764,21 @@ sm.main_box = dt.new_widget("box"){ -- D A R K T A B L E I N T E G R A T I O N -- - - - - - - - - - - - - - - - - - - - - - - - --- register the module -dt.register_lib( - "script_manager", -- Module name - "script manager", -- Visible name - true, -- expandable - false, -- resetable - {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_LEFT_CENTER", 0}}, -- containers - dt.new_widget("box") -- widget - { - orientation = "vertical", - sm.main_box, - }, - nil,-- view_enter - nil -- view_leave -) +if dt.gui.current_view().name == "lighttable" then + install_module() +else + if not sm.event_registered then + dt.register_event( + "view-changed", + function(event, old_view, new_view) + if new_view.name == "lighttable" and old_view.name == "darkroom" then + install_module() + end + end + ) + sm.event_registered = true + end +end -- set up the scripts block if we have them otherwise we'll wait until we download them From 50be8a924044a0bd2b919e2513d9bb89aaa99ae0 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sat, 8 Aug 2020 22:11:29 -0400 Subject: [PATCH 082/445] Added check to ensure we are in lighttable view prior to callling darktable.register_lib. If darktable was invoked in single image (darkroom) mode, then an event handler is registered to detect the change from darkroom mode to lighttable mode so that we can then call darktable.register_lib. --- official/enfuse.lua | 66 +++++++++++++++++++++++++++++++-------------- 1 file changed, 46 insertions(+), 20 deletions(-) diff --git a/official/enfuse.lua b/official/enfuse.lua index 3b5bb7c2..7432a1e3 100644 --- a/official/enfuse.lua +++ b/official/enfuse.lua @@ -46,10 +46,35 @@ du.check_min_api_version("3.0.0", "enfuse") -- Tell gettext where to find the .mo file translating messages for a particular domain gettext.bindtextdomain("enfuse",dt.configuration.config_dir..PS .. "lua" .. PS .. "locale" .. PS) +local enf = {} +enf.event_registered = false +enf.module_installed = false +enf.lib_widgets = {} + local function _(msgid) return gettext.dgettext("enfuse", msgid) end +local function install_module() + if not enf.module_installed then + dt.register_lib( + "enfuse", -- plugin name + "enfuse", -- name + true, -- expandable + false, -- resetable + {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, -- containers + dt.new_widget("box") -- widget + { + orientation = "vertical", + sensitive = enfuse_installed, + table.unpack(enf.lib_widgets) + }, + nil,-- view_enter + nil -- view_leave + ) + enf.module_installed = true + end +end -- add a new lib -- is enfuse installed? local enfuse_installed = df.check_if_bin_exists("enfuse") @@ -229,30 +254,31 @@ if enfuse_installed then local lib_widgets = {} if not enfuse_installed then - table.insert(lib_widgets, df.executable_path_widget({"ffmpeg"})) + table.insert(enf.lib_widgets, df.executable_path_widget({"ffmpeg"})) end - table.insert(lib_widgets, exposure_mu) - table.insert(lib_widgets, depth) - table.insert(lib_widgets, blend_colorspace) - table.insert(lib_widgets, enfuse_button) + table.insert(enf.lib_widgets, exposure_mu) + table.insert(enf.lib_widgets, depth) + table.insert(enf.lib_widgets, blend_colorspace) + table.insert(enf.lib_widgets, enfuse_button) -- ... and tell dt about it all - dt.register_lib( - "enfuse", -- plugin name - "enfuse", -- name - true, -- expandable - false, -- resetable - {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, -- containers - dt.new_widget("box") -- widget - { - orientation = "vertical", - sensitive = enfuse_installed, - table.unpack(lib_widgets) - }, - nil,-- view_enter - nil -- view_leave - ) + if dt.gui.current_view().name == "lighttable" then + install_module() + else + if not enf.event_registered then + dt.register_event( + "view-changed", + function(event, old_view, new_view) + if new_view.name == "lighttable" and old_view.name == "darkroom" then + dt.print_log("view changed from darkroom to lighttable") + install_module() + end + end + ) + enf.event_registered = true + end + end else dt.print_error("enfuse executable not found") error("enfuse executable not found") From 4e68e420ccf2236641fe3c2c525aee9a631ece23 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sat, 8 Aug 2020 22:40:40 -0400 Subject: [PATCH 083/445] removed debugging print statemant --- official/enfuse.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/official/enfuse.lua b/official/enfuse.lua index 7432a1e3..4213b480 100644 --- a/official/enfuse.lua +++ b/official/enfuse.lua @@ -271,7 +271,6 @@ if enfuse_installed then "view-changed", function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then - dt.print_log("view changed from darkroom to lighttable") install_module() end end From 2ddd0965cd16302304c16925f9d9ff2cccc3e089 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sat, 8 Aug 2020 22:40:54 -0400 Subject: [PATCH 084/445] Added check to ensure we are in lighttable view prior to callling darktable.register_lib. If darktable was invoked in single image (darkroom) mode, then an event handler is registered to detect the change from darkroom mode to lighttable mode so that we can then call darktable.register_lib. --- examples/moduleExample.lua | 94 ++++++++++++++++++++++++++------------ 1 file changed, 66 insertions(+), 28 deletions(-) diff --git a/examples/moduleExample.lua b/examples/moduleExample.lua index 2c46a08a..12de6828 100644 --- a/examples/moduleExample.lua +++ b/examples/moduleExample.lua @@ -46,6 +46,44 @@ local function _(msgid) return gettext.dgettext("moduleExample", msgid) end +-- declare a local namespace and a couple of variables we'll need to install the module +local mE = {} +mE.widgets = {} +mE.event_registered = false -- keep track of whether we've added an event callback or not +mE.module_installed = false -- keep track of whether the module is module_installed + +--[[ We have to create the module in one of two ways depending on which view darktable starts + in. In orker to not repeat code, we wrap the darktable.register_lib in a local function. + ]] + +local function install_module() + if not mE.module_installed then + -- https://www.darktable.org/lua-api/index.html#darktable_register_lib + dt.register_lib( + "exampleModule", -- Module name + "exampleModule", -- name + true, -- expandable + false, -- resetable + {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, -- containers + -- https://www.darktable.org/lua-api/types_lua_box.html + dt.new_widget("box") -- widget + { + orientation = "vertical", + dt.new_widget("button") + { + label = _("MyButton"), + clicked_callback = function (_) + dt.print(_("Button clicked")) + end + }, + table.unpack(mE.widgets), + }, + nil,-- view_enter + nil -- view_leave + ) + mE.module_installed = true + end +end -- https://www.darktable.org/lua-api/types_lua_check_button.html local check_button = dt.new_widget("check_button"){label = _("MyCheck_button"), value = true} @@ -90,35 +128,35 @@ local slider = dt.new_widget("slider") value = 52 -- The current value of the slider } --- https://www.darktable.org/lua-api/index.html#darktable_register_lib -dt.register_lib( - "exampleModule", -- Module name - "exampleModule", -- name - true, -- expandable - false, -- resetable - {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, -- containers - -- https://www.darktable.org/lua-api/types_lua_box.html - dt.new_widget("box") -- widget - { - orientation = "vertical", - dt.new_widget("button") - { - label = _("MyButton"), - clicked_callback = function (_) - dt.print(_("Button clicked")) +-- pack the widgets in a table for loading in the module + +table.insert(mE.widgets, check_button) +table.insert(mE.widgets, combobox) +table.insert(mE.widgets, entry) +table.insert(mE.widgets, file_chooser_button) +table.insert(mE.widgets, label) +table.insert(mE.widgets, separator) +table.insert(mE.widgets, slider) + +-- ... and tell dt about it all + + +if dt.gui.current_view().name == "lighttable" then -- make sure we are in lighttable view + install_module() -- register the lib +else + if not mE.event_registered then -- if we are not in lighttable view then register an event to signal when we might be + -- https://www.darktable.org/lua-api/index.html#darktable_register_event + dt.register_event( + "view-changed", -- we want to be informed when the view changes + function(event, old_view, new_view) + if new_view.name == "lighttable" and old_view.name == "darkroom" then -- if the view changes from darkroom to lighttable + install_module() -- register the lib + end end - }, - check_button, - combobox, - entry, - file_chooser_button, - label, - separator, - slider - }, - nil,-- view_enter - nil -- view_leave -) + ) + mE.event_registered = true -- keep track of whether we have an event handler installed + end +end -- vim: shiftwidth=2 expandtab tabstop=2 cindent syntax=lua -- kate: hl Lua; From cc4f1d7251e24e74a1a8510129e234ff832a5d9a Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sat, 8 Aug 2020 23:11:33 -0400 Subject: [PATCH 085/445] Added check to ensure we are in lighttable view prior to callling darktable.register_lib. If darktable was invoked in single image (darkroom) mode, then an event handler is registered to detect the change from darkroom mode to lighttable mode so that we can then call darktable.register_lib. --- official/image_path_in_ui.lua | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/official/image_path_in_ui.lua b/official/image_path_in_ui.lua index 18e57cae..60bcce69 100644 --- a/official/image_path_in_ui.lua +++ b/official/image_path_in_ui.lua @@ -33,8 +33,22 @@ local du = require "lib/dtutils" du.check_min_api_version("2.0.0", "image_path_in_ui") +local ipiu = {} +ipiu.module_installed = false +ipiu.event_registered = false + local main_label = dt.new_widget("label"){selectable = true, ellipsize = "middle", halign = "start"} +local function install_module() + if not ipiu.module_installed then + dt.register_lib("image_path_no_ui","Selected Images path",true,false,{ + [dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_LEFT_CENTER",300} + }, main_label + ) + ipiu.module_installed = true + end +end + local function reset_widget() local selection = dt.gui.selection() local result = "" @@ -54,10 +68,21 @@ end main_label.reset_callback = reset_widget -dt.register_lib("image_path_no_ui","Selected Images path",true,false,{ - [dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_LEFT_CENTER",300} - }, main_label - ); +if dt.gui.current_view().name == "lighttable" then + install_module() +else + if not ipiu.event_registered then + dt.register_event( + "view-changed", + function(event, old_view, new_view) + if new_view.name == "lighttable" and old_view.name == "darkroom" then + install_module() + end + end + ) + ipiu.event_registered = true + end +end dt.register_event("mouse-over-image-changed",reset_widget); From d05536bed4697f2ce2b802775b5f799d0d073d82 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sat, 8 Aug 2020 23:21:54 -0400 Subject: [PATCH 086/445] Added check to ensure we are in lighttable view prior to callling darktable.register_lib. If darktable was invoked in single image (darkroom) mode, then an event handler is registered to detect the change from darkroom mode to lighttable mode so that we can then call darktable.register_lib. --- contrib/AutoGrouper.lua | 65 +++++++++++++++++++++++++++++------------ 1 file changed, 47 insertions(+), 18 deletions(-) diff --git a/contrib/AutoGrouper.lua b/contrib/AutoGrouper.lua index 0d929150..18ff103d 100644 --- a/contrib/AutoGrouper.lua +++ b/contrib/AutoGrouper.lua @@ -45,6 +45,17 @@ local function _(msgid) return gettext.dgettext("AutoGrouper", msgid) end +local Ag = {} +Ag.module_installed = false +Ag.event_registered = false + +local GUI = { + gap = {}, + selected = {}, + collection = {} +} + + local function InRange(test, low, high) --tests if test value is within range of low and high (inclusive) if test >= low and test <= high then return true @@ -111,12 +122,26 @@ local function main(on_collection) end end +local function install_module() + if not Ag.module_installed then + dt.register_lib( + 'AutoGroup_Lib', -- Module name + _('auto group'), -- name + true, -- expandable + true, -- resetable + {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 99}}, -- containers + dt.new_widget("box"){ + orientation = "vertical", + GUI.gap, + GUI.selected, + GUI.collection + } + ) + Ag.module_installed = true + end +end + -- GUI -- -GUI = { - gap = {}, - selected = {}, - collection = {} -} temp = dt.preferences.read(MOD, 'active_gap', 'integer') if not InRange(temp, 1, 86400) then temp = 3 end GUI.gap = dt.new_widget('slider'){ @@ -143,16 +168,20 @@ GUI.collection = dt.new_widget("button"){ tooltip =_('auto group the entire collection'), clicked_callback = function() main(true) end } -dt.register_lib( - 'AutoGroup_Lib', -- Module name - _('auto group'), -- name - true, -- expandable - true, -- resetable - {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 99}}, -- containers - dt.new_widget("box"){ - orientation = "vertical", - GUI.gap, - GUI.selected, - GUI.collection - } -) + +if dt.gui.current_view().name == "lighttable" then + install_module() +else + if not Ag.event_registered then + dt.register_event( + "view-changed", + function(event, old_view, new_view) + if new_view.name == "lighttable" and old_view.name == "darkroom" then + install_module() + end + end + ) + Ag.event_registered = true + end +end + From 994b9c6472da4b99750b7ec155671ccdc498ebe8 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sat, 8 Aug 2020 23:28:50 -0400 Subject: [PATCH 087/445] Added check to ensure we are in lighttable view prior to callling darktable.register_lib. If darktable was invoked in single image (darkroom) mode, then an event handler is registered to detect the change from darkroom mode to lighttable mode so that we can then call darktable.register_lib. --- contrib/quicktag.lua | 66 ++++++++++++++++++++++++++++++-------------- 1 file changed, 46 insertions(+), 20 deletions(-) diff --git a/contrib/quicktag.lua b/contrib/quicktag.lua index 31a4b790..104c4fe0 100644 --- a/contrib/quicktag.lua +++ b/contrib/quicktag.lua @@ -47,6 +47,12 @@ local dt = require "darktable" local du = require "lib/dtutils" local debug = require "darktable.debug" +local qt = {} +qt.module_installed = false +qt.event_registered = false +qt.widget_table = {} + + local gettext = dt.gettext @@ -177,6 +183,27 @@ local function update_quicktag_list() end end +local function install_module() + if not qt.module_installed then + dt.register_lib( + "quicktag", -- Module name + "quicktag", -- name + true, -- expandable + false, -- resetable + {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 490}}, + + dt.new_widget("box"){ + orientation = "vertical", + table.unpack(qt.widget_table), + + }, + nil,-- view_enter + nil -- view_leave + ) + qt.module_installed = true + end +end + update_quicktag_list() local new_quicktag = dt.new_widget("entry"){ @@ -213,33 +240,32 @@ local new_qt_widget = dt.new_widget ("box") { -- back UI elements in a table -- thanks to wpferguson for the hint -local widget_table = {} for i=1,qnr do - widget_table[#widget_table + 1] = button[i] + qt.widget_table[#qt.widget_table + 1] = button[i] end -widget_table[#widget_table + 1] = dt.new_widget("separator"){} -widget_table[#widget_table + 1] = old_quicktag -widget_table[#widget_table + 1] = new_qt_widget +qt.widget_table[#qt.widget_table + 1] = dt.new_widget("separator"){} +qt.widget_table[#qt.widget_table + 1] = old_quicktag +qt.widget_table[#qt.widget_table + 1] = new_qt_widget --create module -dt.register_lib( - "quicktag", -- Module name - "quicktag", -- name - true, -- expandable - false, -- resetable - {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 490}}, - - dt.new_widget("box"){ - orientation = "vertical", - table.unpack(widget_table), - - }, - nil,-- view_enter - nil -- view_leave -) +if dt.gui.current_view().name == "lighttable" then + install_module() +else + if not qt.event_registered then + dt.register_event( + "view-changed", + function(event, old_view, new_view) + if new_view.name == "lighttable" and old_view.name == "darkroom" then + install_module() + end + end + ) + qt.event_registered = true + end +end -- create shortcuts for i=1,qnr do From be5557080b1afb3486568e4d5f169402d87faa92 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sat, 8 Aug 2020 23:38:48 -0400 Subject: [PATCH 088/445] Added check to ensure we are in lighttable view prior to callling darktable.register_lib. If darktable was invoked in single image (darkroom) mode, then an event handler is registered to detect the change from darkroom mode to lighttable mode so that we can then call darktable.register_lib. --- contrib/transfer_hierarchy.lua | 40 +++++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/contrib/transfer_hierarchy.lua b/contrib/transfer_hierarchy.lua index c2ba9cb9..70bb598d 100755 --- a/contrib/transfer_hierarchy.lua +++ b/contrib/transfer_hierarchy.lua @@ -99,6 +99,10 @@ end -- Helper functions: BEGIN +local th = {} +th.module_installed = false +th.event_registered = false + local function pathExists(path) local success, err, errno = os.rename(path, path) if not success then @@ -122,6 +126,16 @@ local function createDirectory(path) end end +local function install_module() + if not th.module_installed then + darktable.register_lib(LIB_ID, + "transfer hierarchy", true, true, { + [darktable.gui.views.lighttable] = { "DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 700 } + }, th.transfer_widget, nil, nil) + th.module_installed = true + end +end + -- Helper functions: END @@ -292,7 +306,7 @@ end -local transfer_widget = darktable.new_widget("box") { +th.transfer_widget = darktable.new_widget("box") { orientation = "vertical", darktable.new_widget("button") { label = _("calculate"), @@ -347,12 +361,18 @@ darktable.preferences.register( -- Preferences: END - - - - - -darktable.register_lib(LIB_ID, - "transfer hierarchy", true, true, { - [darktable.gui.views.lighttable] = { "DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 700 } - }, transfer_widget, nil, nil) +if darktable.gui.current_view().name == "lighttable" then + install_module() +else + if not th.event_registered then + darktable.register_event( + "view-changed", + function(event, old_view, new_view) + if new_view.name == "lighttable" and old_view.name == "darkroom" then + install_module() + end + end + ) + th.event_registered = true + end +end From 8a710798f7f01924b9d0cd76ee4b54cce2955984 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sun, 9 Aug 2020 00:17:34 -0400 Subject: [PATCH 089/445] Added check to ensure we are in lighttable view prior to callling darktable.register_lib. If darktable was invoked in single image (darkroom) mode, then an event handler is registered to detect the change from darkroom mode to lighttable mode so that we can then call darktable.register_lib. --- contrib/ext_editor.lua | 58 ++++++++++++++++++++++++++++++++---------- 1 file changed, 44 insertions(+), 14 deletions(-) diff --git a/contrib/ext_editor.lua b/contrib/ext_editor.lua index 4035c228..6999c05e 100644 --- a/contrib/ext_editor.lua +++ b/contrib/ext_editor.lua @@ -84,6 +84,12 @@ du.check_min_api_version("5.0.2", MODULE_NAME) -- darktable 3.x -- OS compatibility local PS = dt.configuration.running_os == "windows" and "\\" or "/" +-- namespace +local ee = {} +ee.module_installed = false +ee.event_registered = false +ee.widgets = {} + -- translation local gettext = dt.gettext @@ -329,6 +335,26 @@ local function export2collection(storage, image_table, extra_data) dt.print (_("finished exporting")) end +-- install the module in the UI +local function install_module() + if not ee.module_installed then + -- register new module "external editors" in lighttable ------------------------ + dt.register_lib( + MODULE_NAME, + _("external editors"), + true, -- expandable + false, -- resetable + {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, + dt.new_widget("box") { + orientation = "vertical", + table.unpack(ee.widgets), + }, + nil, -- view_enter + nil -- view_leave + ) + ee.module_installed = true + end +end -- combobox, with variable number of entries ---------------------------------- local combobox = dt.new_widget("combobox") { @@ -381,22 +407,26 @@ local box1 = dt.new_widget("box") { button_update_list } +table.insert(ee.widgets, combobox) +table.insert(ee.widgets, box1) -- register new module "external editors" in lighttable ------------------------ -dt.register_lib( - MODULE_NAME, - _("external editors"), - true, -- expandable - false, -- resetable - {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, - dt.new_widget("box") { - orientation = "vertical", - combobox, - box1 - }, - nil, -- view_enter - nil -- view_leave - ) +if dt.gui.current_view().name == "lighttable" then + install_module() +else + if not ee.event_registered then + dt.register_event( + "view-changed", + function(event, old_view, new_view) + if new_view.name == "lighttable" and old_view.name == "darkroom" then + install_module() + end + end + ) + ee.event_registered = true + end +end + -- initialize list of programs and widgets ------------------------------------ From 138b23674a2b428c2440f8674af4b20890f1be97 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sun, 9 Aug 2020 00:36:43 -0400 Subject: [PATCH 090/445] Added check to ensure we are in lighttable view prior to callling darktable.register_lib. If darktable was invoked in single image (darkroom) mode, then an event handler is registered to detect the change from darkroom mode to lighttable mode so that we can then call darktable.register_lib. --- contrib/photils.lua | 53 +++++++++++++++++++++++++++++++++------------ 1 file changed, 39 insertions(+), 14 deletions(-) diff --git a/contrib/photils.lua b/contrib/photils.lua index 1c72f4b7..cc41b34c 100644 --- a/contrib/photils.lua +++ b/contrib/photils.lua @@ -91,7 +91,13 @@ local PHOTILS = { per_page = 10, selected_tags = {}, in_pagination = false, - tagged_image = "" + tagged_image = "", + module_installed = false, + event_registered = false, + plugin_display_views = { + [dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}, + [dt.gui.views.darkroom] = {"DT_UI_CONTAINER_PANEL_LEFT_CENTER", 100} + }, } local GUI = { @@ -358,6 +364,21 @@ function PHOTILS.on_reset(with_view) GUI.attach_button.sensitive = false end +local function install_module() + if not PHOTILS.module_installed then + dt.register_lib(MODULE_NAME, + "photils autotagger", + true, + true, + PHOTILS.plugin_display_views, + GUI.container, + nil, + nil + ) + PHOTILS.module_installed = true + end +end + -- add a fix number of buttons for _ = 1, PHOTILS.per_page, 1 do local btn_tag = dt.new_widget("check_button") { @@ -402,10 +423,6 @@ table.insert(GUI.container, GUI.stack) GUI.stack.active = 1 -local plugin_display_views = { - [dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}, - [dt.gui.views.darkroom] = {"DT_UI_CONTAINER_PANEL_LEFT_CENTER", 100} -} -- uses photils: prefix because script settings are all together and not seperated by script @@ -417,12 +434,20 @@ dt.preferences.register(MODULE_NAME, true) dt.register_event("mouse-over-image-changed",PHOTILS.image_changed) -dt.register_lib(MODULE_NAME, - "photils autotagger", - true, - true, - plugin_display_views, - GUI.container, - nil, - nil -) + +if dt.gui.current_view().name == "lighttable" then + install_module() +else + if not PHOTILS.event_registered then + dt.register_event( + "view-changed", + function(event, old_view, new_view) + if new_view.name == "lighttable" and old_view.name == "darkroom" then + install_module() + end + end + ) + PHOTILS.event_registered = true + end +end + From 52acdb9036b463e528e2fb27cc44bc4507ecb141 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sun, 9 Aug 2020 00:45:27 -0400 Subject: [PATCH 091/445] Added check to ensure we are in lighttable view prior to callling darktable.register_lib. If darktable was invoked in single image (darkroom) mode, then an event handler is registered to detect the change from darkroom mode to lighttable mode so that we can then call darktable.register_lib. --- contrib/copy_attach_detach_tags.lua | 65 ++++++++++++++++++++--------- 1 file changed, 45 insertions(+), 20 deletions(-) diff --git a/contrib/copy_attach_detach_tags.lua b/contrib/copy_attach_detach_tags.lua index 2fb83301..9b43c470 100644 --- a/contrib/copy_attach_detach_tags.lua +++ b/contrib/copy_attach_detach_tags.lua @@ -51,6 +51,11 @@ local function _(msgid) return gettext.dgettext("copy_attach_detach_tags", msgid) end +local cadt = {} +cadt.module_installed = false +cadt.event_registered = false +cadt.widget_table = {} + local image_tags = {} @@ -156,6 +161,26 @@ local function replace_tags() dt.print(_('Tags replaced')) end +local function install_module() + if not cadt.module_installed then + dt.register_lib("tagging_addon","Tagging addon",true,true,{ + [dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER",500} + }, + dt.new_widget("box") { + -- orientation = "vertical", + reset_callback = function() + taglist_label.label = "" + image_tags = {} + end, + table.unpack(cadt.widget_table), + }, + nil, + nil + ) + cadt.module_installed = true + end +end + -- create modul Tagging addons taglist_label.reset_callback = mcopy_tags @@ -190,31 +215,31 @@ local box2 = dt.new_widget("box"){ local sep = dt.new_widget("separator"){} -- pack elements into widget table for a nicer layout -local widget_table = {} -widget_table[1] = box1 -widget_table[#widget_table+1] = box2 +cadt.widget_table[1] = box1 +cadt.widget_table[#cadt.widget_table+1] = box2 -widget_table[#widget_table+1] = sep -widget_table[#widget_table+1] = taglabel -widget_table[#widget_table+1] = taglist_label +cadt.widget_table[#cadt.widget_table+1] = sep +cadt.widget_table[#cadt.widget_table+1] = taglabel +cadt.widget_table[#cadt.widget_table+1] = taglist_label -- create modul -dt.register_lib("tagging_addon","Tagging addon",true,true,{ - [dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER",500} - }, - dt.new_widget("box") { - -- orientation = "vertical", - reset_callback = function() - taglist_label.label = "" - image_tags = {} - end, - table.unpack(widget_table), - }, - nil, - nil - ) +if dt.gui.current_view().name == "lighttable" then + install_module() +else + if not cadt.event_registered then + dt.register_event( + "view-changed", + function(event, old_view, new_view) + if new_view.name == "lighttable" and old_view.name == "darkroom" then + install_module() + end + end + ) + cadt.event_registered = true + end +end -- shortcut for copy From 5f5ad426bf1acbbfa3b28a7717a9d2aa83a9d007 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sun, 9 Aug 2020 01:01:33 -0400 Subject: [PATCH 092/445] Added check to ensure we are in lighttable view prior to callling darktable.register_lib. If darktable was invoked in single image (darkroom) mode, then an event handler is registered to detect the change from darkroom mode to lighttable mode so that we can then call darktable.register_lib. --- contrib/rename-tags.lua | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/contrib/rename-tags.lua b/contrib/rename-tags.lua index a0c70be4..f385a7a6 100644 --- a/contrib/rename-tags.lua +++ b/contrib/rename-tags.lua @@ -35,6 +35,10 @@ local debug = require "darktable.debug" -- check API version du.check_min_api_version("3.0.0", "rename-tags") +local rt = {} +rt.module_installed = false +rt.event_registered = false + -- GUI entries local old_tag = darktable.new_widget("entry") { tooltip = "Enter old tag" } local new_tag = darktable.new_widget("entry") { tooltip = "Enter new tag" } @@ -99,6 +103,13 @@ local function rename_tags() rename_reset() end +local function install_module() + if not rt.module_installed then + darktable.register_lib ("rename_tags", "rename tag", true, true, {[darktable.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 20},}, rt.rename_widget, nil, nil) + rt.module_installed = true + end +end + -- GUI local old_widget = darktable.new_widget ("box") { orientation = "horizontal", @@ -112,7 +123,7 @@ local new_widget = darktable.new_widget ("box") { new_tag } -local rename_widget = darktable.new_widget ("box") { +rt.rename_widget = darktable.new_widget ("box") { orientation = "vertical", reset_callback = rename_reset, old_widget, @@ -120,6 +131,20 @@ local rename_widget = darktable.new_widget ("box") { darktable.new_widget("button") { label = "Go", clicked_callback = rename_tags } } +if darktable.gui.current_view().name == "lighttable" then + install_module() +else + if not rt.event_registered then + darktable.register_event( + "view-changed", + function(event, old_view, new_view) + if new_view.name == "lighttable" and old_view.name == "darkroom" then + install_module() + end + end + ) + rt.event_registered = true + end +end -darktable.register_lib ("rename_tags", "rename tag", true, true, {[darktable.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 20},}, rename_widget, nil, nil) From 432b6b5dd767a5952c9026941c8f44c5a1e84dcd Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sun, 9 Aug 2020 01:21:17 -0400 Subject: [PATCH 093/445] Added check to ensure we are in lighttable view prior to callling darktable.register_lib. If darktable was invoked in single image (darkroom) mode, then an event handler is registered to detect the change from darkroom mode to lighttable mode so that we can then call darktable.register_lib. --- contrib/geoToolbox.lua | 52 +++++++++++++++++++++++++++++++++--------- 1 file changed, 41 insertions(+), 11 deletions(-) diff --git a/contrib/geoToolbox.lua b/contrib/geoToolbox.lua index 19e3c7cd..5a308623 100644 --- a/contrib/geoToolbox.lua +++ b/contrib/geoToolbox.lua @@ -40,6 +40,12 @@ local function _(msgid) return gettext.dgettext("geoToolbox", msgid) end + +local gT = {} +gT.module_installed = false +gT.event_registered = false + + -- local labelDistance = dt.new_widget("label") labelDistance.label = _("Distance:") @@ -572,6 +578,22 @@ local function altitude_profile() end +local function install_module() + if not gT.module_installed then + dt.register_lib( + "geoToolbox", -- Module name + "geo toolbox", -- name + true, -- expandable + false, -- resetable + {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, -- containers + gT.widget, + nil,-- view_enter + nil -- view_leave + ) + gT.module_installed = true + end +end + local separator = dt.new_widget("separator"){} local separator2 = dt.new_widget("separator"){} @@ -579,13 +601,7 @@ local separator3 = dt.new_widget("separator"){} local separator4 = dt.new_widget("separator"){} local separator5 = dt.new_widget("separator"){} -dt.register_lib( - "geoToolbox", -- Module name - "geo toolbox", -- name - true, -- expandable - false, -- resetable - {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, -- containers - dt.new_widget("box") +gT.widget = dt.new_widget("box") { orientation = "vertical", dt.new_widget("button") @@ -664,10 +680,24 @@ dt.register_lib( clicked_callback = altitude_profile }, labelDistance - }, - nil,-- view_enter - nil -- view_leave -) + } + + +if dt.gui.current_view().name == "lighttable" then + install_module() +else + if not gT.event_registered then + dt.register_event( + "view-changed", + function(event, old_view, new_view) + if new_view.name == "lighttable" and old_view.name == "darkroom" then + install_module() + end + end + ) + gT.event_registered = true + end +end -- Preferences dt.preferences.register("geoToolbox", From 880ec7fc587660f18bf7579137ec4b9f6b27e796 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sun, 9 Aug 2020 01:26:45 -0400 Subject: [PATCH 094/445] Added check to ensure we are in lighttable view prior to callling darktable.register_lib. If darktable was invoked in single image (darkroom) mode, then an event handler is registered to detect the change from darkroom mode to lighttable mode so that we can then call darktable.register_lib. --- contrib/gpx_export.lua | 74 +++++++++++++++++++++++++++++------------- 1 file changed, 51 insertions(+), 23 deletions(-) diff --git a/contrib/gpx_export.lua b/contrib/gpx_export.lua index b6fed82e..e36b6238 100644 --- a/contrib/gpx_export.lua +++ b/contrib/gpx_export.lua @@ -36,6 +36,10 @@ local function _(msgid) return gettext.dgettext("gpx_export", msgid) end +local gpx = {} +gpx.module_installed = false +gpx.event_registered = false + local path_entry = dt.new_widget("entry") { text = dt.preferences.read("gpx_exporter", "gpxExportPath", "string"), @@ -127,31 +131,55 @@ local function create_gpx_file() end end -dt.register_lib( - "gpx_exporter", - "gpx export", - true, -- expandable - true, -- resetable - {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, -- containers +local function install_module() + if not gpx.module_installed then + dt.register_lib( + "gpx_exporter", + "gpx export", + true, -- expandable + true, -- resetable + {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, -- containers + gpx.widget, + nil,-- view_enter + nil -- view_leave + ) + gpx.module_installed = true + end +end + +gpx.widget = dt.new_widget("box") +{ + orientation = "vertical", + dt.new_widget("button") + { + label = _("export"), + tooltip = _("export gpx file"), + clicked_callback = create_gpx_file + }, dt.new_widget("box") { - orientation = "vertical", - dt.new_widget("button") + orientation = "horizontal", + dt.new_widget("label") { - label = _("export"), - tooltip = _("export gpx file"), - clicked_callback = create_gpx_file - }, - dt.new_widget("box") - { - orientation = "horizontal", - dt.new_widget("label") - { - label = _("file:"), - }, - path_entry + label = _("file:"), }, + path_entry }, - nil,-- view_enter - nil -- view_leave -) +} + + +if dt.gui.current_view().name == "lighttable" then + install_module() +else + if not gpx.event_registered then + dt.register_event( + "view-changed", + function(event, old_view, new_view) + if new_view.name == "lighttable" and old_view.name == "darkroom" then + install_module() + end + end + ) + gpx.event_registered = true + end +end From d10cf968f19976f4b17f37e52e8f3c6285bad71e Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sun, 9 Aug 2020 01:33:09 -0400 Subject: [PATCH 095/445] Added check to ensure we are in lighttable view prior to callling darktable.register_lib. If darktable was invoked in single image (darkroom) mode, then an event handler is registered to detect the change from darkroom mode to lighttable mode so that we can then call darktable.register_lib. --- contrib/exportLUT.lua | 67 +++++++++++++++++++++++++++++++------------ 1 file changed, 48 insertions(+), 19 deletions(-) diff --git a/contrib/exportLUT.lua b/contrib/exportLUT.lua index aa76b0d3..bd35fb39 100644 --- a/contrib/exportLUT.lua +++ b/contrib/exportLUT.lua @@ -41,6 +41,11 @@ end du.check_min_api_version("5.0.0", "exportLUT") +local eL = {} +eL.module_installed = false +eL.event_registered = false +eL.widgets = {} + -- Thanks Kevin Ertel for this bit local os_path_seperator = '/' if dt.configuration.running_os == 'windows' then os_path_seperator = '\\' end @@ -119,27 +124,51 @@ local function export_luts() end end +local function install_module() + if not eL.module_installed then + dt.register_lib( + _("export haldclut"), + _("export haldclut"), + true, + false, + {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, + dt.new_widget("box") + { + orientation = "vertical", + table.unpack(eL.widgets), + }, + nil, + nil + ) + eL.module_installed = true + end +end + local export_button = dt.new_widget("button"){ label = _("export"), clicked_callback = export_luts } -dt.register_lib( - _("export haldclut"), - _("export haldclut"), - true, - false, - {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, - dt.new_widget("box") - { - orientation = "vertical", - identity_label, - file_chooser_button, - output_label, - export_chooser_button, - warning_label, - export_button - }, - nil, - nil -) +table.insert(eL.widgets, identity_label) +table.insert(eL.widgets, file_chooser_button) +table.insert(eL.widgets, output_label) +table.insert(eL.widgets, export_chooser_button) +table.insert(eL.widgets, warning_label) +table.insert(eL.widgets, export_button) + +if dt.gui.current_view().name == "lighttable" then + install_module() +else + if not eL.event_registered then + dt.register_event( + "view-changed", + function(event, old_view, new_view) + if new_view.name == "lighttable" and old_view.name == "darkroom" then + install_module() + end + end + ) + eL.event_registered = true + end +end + From d4e21b78774075c6e0bc12e52fda88c7d35e8ed0 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sun, 9 Aug 2020 01:43:20 -0400 Subject: [PATCH 096/445] Added check to ensure we are in lighttable view prior to callling darktable.register_lib. If darktable was invoked in single image (darkroom) mode, then an event handler is registered to detect the change from darkroom mode to lighttable mode so that we can then call darktable.register_lib. --- contrib/image_time.lua | 44 ++++++++++++++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 10 deletions(-) diff --git a/contrib/image_time.lua b/contrib/image_time.lua index a13a79aa..676f5af4 100644 --- a/contrib/image_time.lua +++ b/contrib/image_time.lua @@ -110,6 +110,8 @@ local ds = require "lib/dtutils.string" local gettext = dt.gettext local img_time = {} +img_time.module_installed = false +img_time.event_registered = false du.check_min_api_version("3.0.0", "image_time") @@ -390,6 +392,22 @@ local function reset_widgets() img_time.adir.selected = 1 end +local function install_module() + if not img_time.module_installed then + dt.register_lib( + "image_time", -- Module name + _("image time"), -- Visible name + true, -- expandable + true, -- resetable + {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, -- containers + img_time.widget, + nil,-- view_enter + nil -- view_leave + ) + img_time.module_installed = true + end +end + -- widgets img_time.widgets = { @@ -528,13 +546,19 @@ img_time.widget = dt.new_widget("box"){ img_time.stack, } -dt.register_lib( - "image_time", -- Module name - _("image time"), -- Visible name - true, -- expandable - true, -- resetable - {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, -- containers - img_time.widget, - nil,-- view_enter - nil -- view_leave -) +if dt.gui.current_view().name == "lighttable" then + install_module() +else + if not img_time.event_registered then + dt.register_event( + "view-changed", + function(event, old_view, new_view) + if new_view.name == "lighttable" and old_view.name == "darkroom" then + install_module() + end + end + ) + img_time.event_registered = true + end +end + From b8e3ec43023af8d38d68d13b971a09580be310f2 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sun, 9 Aug 2020 01:43:31 -0400 Subject: [PATCH 097/445] Added check to ensure we are in lighttable view prior to callling darktable.register_lib. If darktable was invoked in single image (darkroom) mode, then an event handler is registered to detect the change from darkroom mode to lighttable mode so that we can then call darktable.register_lib. --- contrib/HDRMerge.lua | 47 +++++++++++++++++++++++++++++++++----------- 1 file changed, 36 insertions(+), 11 deletions(-) diff --git a/contrib/HDRMerge.lua b/contrib/HDRMerge.lua index ad7dd3a8..aa13a1c4 100644 --- a/contrib/HDRMerge.lua +++ b/contrib/HDRMerge.lua @@ -94,6 +94,10 @@ local GUI = { --GUI Elements Table } } +HDRM.module_installed = false +HDRM.event_registered = false + + --Detect User Styles-- local styles = dt.styles local styles_count = 1 -- 'none' = 1 @@ -264,6 +268,23 @@ local function main() end +local function install_module() + if not HDRM.module_installed then + dt.register_lib( -- register HDRMerge module + 'HDRMerge_Lib', -- Module name + _('HDRMerge'), -- name + true, -- expandable + true, -- resetable + {[dt.gui.views.lighttable] = {'DT_UI_CONTAINER_PANEL_RIGHT_CENTER', 99}}, -- containers + dt.new_widget('box'){ + orientation = 'vertical', + GUI.stack + } + ) + HDRM.module_installed = true + end +end + -- GUI Elements -- local lbl_hdr = dt.new_widget('section_label'){ label = _('HDRMerge options') @@ -411,14 +432,18 @@ else GUI.stack.active = 2 end -dt.register_lib( -- register HDRMerge module - 'HDRMerge_Lib', -- Module name - _('HDRMerge'), -- name - true, -- expandable - true, -- resetable - {[dt.gui.views.lighttable] = {'DT_UI_CONTAINER_PANEL_RIGHT_CENTER', 99}}, -- containers - dt.new_widget('box'){ - orientation = 'vertical', - GUI.stack - } -) +if dt.gui.current_view().name == "lighttable" then + install_module() +else + if not HDRM.event_registered then + dt.register_event( + "view-changed", + function(event, old_view, new_view) + if new_view.name == "lighttable" and old_view.name == "darkroom" then + install_module() + end + end + ) + HDRM.event_registered = true + end +end From dfb8d4e7c6b7f2219f2a8c1068d167e86c0dbb2e Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sun, 9 Aug 2020 01:48:36 -0400 Subject: [PATCH 098/445] Added check to ensure we are in lighttable view prior to callling darktable.register_lib. If darktable was invoked in single image (darkroom) mode, then an event handler is registered to detect the change from darkroom mode to lighttable mode so that we can then call darktable.register_lib. --- contrib/LabelsToTags.lua | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/contrib/LabelsToTags.lua b/contrib/LabelsToTags.lua index 044e9203..29f9322e 100644 --- a/contrib/LabelsToTags.lua +++ b/contrib/LabelsToTags.lua @@ -55,6 +55,10 @@ du.check_min_api_version("3.0.0", "LabelsToTags") -- Lua 5.3 no longer has "unpack" but "table.unpack" unpack = unpack or table.unpack +local ltt = {} +ltt.module_installed = false +ltt.event_registered = false + local LIB_ID = "LabelsToTags" -- Helper functions: BEGIN @@ -184,7 +188,7 @@ local function doTagging(selfC) job.valid = false end -local my_widget = darktable.new_widget("box") { +ltt.my_widget = darktable.new_widget("box") { orientation = "vertical", mappingComboBox, darktable.new_widget("button") { @@ -217,6 +221,15 @@ darktable.register_tag_mapping = function(name, mapping) mappingComboBox.reset_callback(mappingComboBox) end +local function install_module() + if not ltt.module_installed then + darktable.register_lib(LIB_ID,"labels to tags",true,true,{ + [darktable.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER",20}, + },ltt.my_widget,nil,nil) + ltt.module_installed = true + end +end + --[[ darktable.register_tag_mapping("Example", { ["+----*"] = { "Red", "Only red" }, @@ -229,6 +242,19 @@ darktable.register_tag_mapping("Example", ["*****R"] = { "Rejected" } }) ]] -darktable.register_lib(LIB_ID,"labels to tags",true,true,{ - [darktable.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER",20}, - },my_widget,nil,nil) +if darktable.gui.current_view().name == "lighttable" then + install_module() +else + if not ltt.event_registered then + darktable.register_event( + "view-changed", + function(event, old_view, new_view) + if new_view.name == "lighttable" and old_view.name == "darkroom" then + install_module() + end + end + ) + ltt.event_registered = true + end +end + From b613cc266a232baf469ceea1660a61d72867e20f Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sun, 9 Aug 2020 01:56:38 -0400 Subject: [PATCH 099/445] Added check to ensure we are in lighttable view prior to callling darktable.register_lib. If darktable was invoked in single image (darkroom) mode, then an event handler is registered to detect the change from darkroom mode to lighttable mode so that we can then call darktable.register_lib. --- contrib/face_recognition.lua | 43 +++++++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/contrib/face_recognition.lua b/contrib/face_recognition.lua index 26caff60..96bc4a26 100644 --- a/contrib/face_recognition.lua +++ b/contrib/face_recognition.lua @@ -55,6 +55,8 @@ local OUTPUT = dt.configuration.tmp_dir .. PS .. "facerecognition.txt" -- namespace local fc = {} +fc.module_installed = false +fc.event_registered = false -- ensure we meet the minimum api du.check_min_api_version("5.0.0", "face_recognition") @@ -337,6 +339,22 @@ local function face_recognition () end end +local function install_module() + if not fc.module_installed then + dt.register_lib( + "face_recognition", -- Module name + _("face recognition"), -- Visible name + true, -- expandable + true, -- resetable + {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 300}}, -- containers + fc.widget, + nil,-- view_enter + nil -- view_leave + ) + fc.module_installed = true + end +end + -- build the interface fc.unknown_tag = dt.new_widget("entry"){ @@ -466,16 +484,21 @@ fc.widget = dt.new_widget("box"){ table.unpack(widgets), } -dt.register_lib( - "face_recognition", -- Module name - _("face recognition"), -- Visible name - true, -- expandable - true, -- resetable - {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 300}}, -- containers - fc.widget, - nil,-- view_enter - nil -- view_leave -) +if dt.gui.current_view().name == "lighttable" then + install_module() +else + if not fc.event_registered then + dt.register_event( + "view-changed", + function(event, old_view, new_view) + if new_view.name == "lighttable" and old_view.name == "darkroom" then + install_module() + end + end + ) + fc.event_registered = true + end +end fc.tolerance.value = dt.preferences.read(MODULE, "tolerance", "float") From 912ae93d1036b78578c2568e98bf691720193818 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sun, 9 Aug 2020 01:56:48 -0400 Subject: [PATCH 100/445] Added check to ensure we are in lighttable view prior to callling darktable.register_lib. If darktable was invoked in single image (darkroom) mode, then an event handler is registered to detect the change from darkroom mode to lighttable mode so that we can then call darktable.register_lib. --- tools/executable_manager.lua | 57 ++++++++++++++++++++++++------------ 1 file changed, 39 insertions(+), 18 deletions(-) diff --git a/tools/executable_manager.lua b/tools/executable_manager.lua index f45ecb61..2bbe3927 100644 --- a/tools/executable_manager.lua +++ b/tools/executable_manager.lua @@ -40,6 +40,10 @@ local gettext = dt.gettext gettext.bindtextdomain("executable_manager",dt.configuration.config_dir.."/lua/locale/") +local exec_man = {} -- our own namespace +exec_man.module_installed = false +exec_man.event_registered = false + -- - - - - - - - - - - - - - - - - - - - - - - - - - - - -- F U N C T I O N S -- - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -86,12 +90,30 @@ local function update_combobox_choices(combobox, choice_table, selected) combobox.value = selected end +local function install_module() + if not exec_man.module_installed then + dt.register_lib( + "executable_manager", -- Module name + "executable manager", -- Visible name + true, -- expandable + false, -- resetable + {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_LEFT_BOTTOM", 100}}, -- containers + dt.new_widget("box") -- widget + { + orientation = "vertical", + exec_man.selector, + exec_man.stack, + }, + nil,-- view_enter + nil -- view_leave + ) + exec_man.module_installed = true + end +end -- - - - - - - - - - - - - - - - - - - - - - - - - - - - -- M A I N P R O G R A M -- - - - - - - - - - - - - - - - - - - - - - - - - - - - -local exec_man = {} -- our own namespace - local DARKTABLERC = dt.configuration.config_dir .. PS .. "darktablerc" @@ -187,19 +209,18 @@ update_combobox_choices(exec_man.selector, exec_table, 1) -- register the lib -dt.register_lib( - "executable_manager", -- Module name - "executable manager", -- Visible name - true, -- expandable - false, -- resetable - {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_LEFT_BOTTOM", 100}}, -- containers - dt.new_widget("box") -- widget - { - orientation = "vertical", - exec_man.selector, - exec_man.stack, - }, - nil,-- view_enter - nil -- view_leave -) - +if dt.gui.current_view().name == "lighttable" then + install_module() +else + if not exec_man.event_registered then + dt.register_event( + "view-changed", + function(event, old_view, new_view) + if new_view.name == "lighttable" and old_view.name == "darkroom" then + install_module() + end + end + ) + exec_man.event_registered = true + end +end From 7d9b8dbddafa95ed55368c1a0502ba45d16ca470 Mon Sep 17 00:00:00 2001 From: supertobi Date: Mon, 10 Aug 2020 15:21:25 +0200 Subject: [PATCH 101/445] Update video_ffmpeg.lua added more framerate options --- contrib/video_ffmpeg.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/video_ffmpeg.lua b/contrib/video_ffmpeg.lua index 6755e5c9..1d59935f 100644 --- a/contrib/video_ffmpeg.lua +++ b/contrib/video_ffmpeg.lua @@ -96,7 +96,7 @@ local resolutions = { } } -local framerates = {"15", "16", "23.98", "24", "25", "29,97", "30", "48", "50", "59.94", "60"} +local framerates = {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "15", "16", "23.98", "24", "25", "29,97", "30", "48", "50", "59.94", "60", "120", "240", "300"} local formats = { ["AVI"] = { From 509c7da3848fc32f8899007ec5f57f6fe6c68621 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sun, 16 Aug 2020 13:18:27 -0400 Subject: [PATCH 102/445] changed darktable.current_view().name to darktable.current_view().id for view check because name is translated and id is not. --- contrib/AutoGrouper.lua | 2 +- contrib/HDRMerge.lua | 2 +- contrib/LabelsToTags.lua | 2 +- contrib/copy_attach_detach_tags.lua | 2 +- contrib/exportLUT.lua | 2 +- contrib/ext_editor.lua | 2 +- contrib/face_recognition.lua | 2 +- contrib/geoToolbox.lua | 2 +- contrib/gpx_export.lua | 2 +- contrib/image_time.lua | 2 +- contrib/photils.lua | 2 +- contrib/quicktag.lua | 2 +- contrib/rename-tags.lua | 2 +- contrib/transfer_hierarchy.lua | 2 +- examples/moduleExample.lua | 2 +- official/enfuse.lua | 2 +- official/image_path_in_ui.lua | 2 +- tools/executable_manager.lua | 2 +- tools/script_manager.lua | 2 +- 19 files changed, 19 insertions(+), 19 deletions(-) diff --git a/contrib/AutoGrouper.lua b/contrib/AutoGrouper.lua index 18ff103d..4198952d 100644 --- a/contrib/AutoGrouper.lua +++ b/contrib/AutoGrouper.lua @@ -169,7 +169,7 @@ GUI.collection = dt.new_widget("button"){ clicked_callback = function() main(true) end } -if dt.gui.current_view().name == "lighttable" then +if dt.gui.current_view().id == "lighttable" then install_module() else if not Ag.event_registered then diff --git a/contrib/HDRMerge.lua b/contrib/HDRMerge.lua index aa13a1c4..e9e5d035 100644 --- a/contrib/HDRMerge.lua +++ b/contrib/HDRMerge.lua @@ -432,7 +432,7 @@ else GUI.stack.active = 2 end -if dt.gui.current_view().name == "lighttable" then +if dt.gui.current_view().id == "lighttable" then install_module() else if not HDRM.event_registered then diff --git a/contrib/LabelsToTags.lua b/contrib/LabelsToTags.lua index 29f9322e..8c5e5a5e 100644 --- a/contrib/LabelsToTags.lua +++ b/contrib/LabelsToTags.lua @@ -242,7 +242,7 @@ darktable.register_tag_mapping("Example", ["*****R"] = { "Rejected" } }) ]] -if darktable.gui.current_view().name == "lighttable" then +if darktable.gui.current_view().id == "lighttable" then install_module() else if not ltt.event_registered then diff --git a/contrib/copy_attach_detach_tags.lua b/contrib/copy_attach_detach_tags.lua index 9b43c470..43b40e23 100644 --- a/contrib/copy_attach_detach_tags.lua +++ b/contrib/copy_attach_detach_tags.lua @@ -225,7 +225,7 @@ cadt.widget_table[#cadt.widget_table+1] = taglist_label -- create modul -if dt.gui.current_view().name == "lighttable" then +if dt.gui.current_view().id == "lighttable" then install_module() else if not cadt.event_registered then diff --git a/contrib/exportLUT.lua b/contrib/exportLUT.lua index bd35fb39..9c7a1848 100644 --- a/contrib/exportLUT.lua +++ b/contrib/exportLUT.lua @@ -156,7 +156,7 @@ table.insert(eL.widgets, export_chooser_button) table.insert(eL.widgets, warning_label) table.insert(eL.widgets, export_button) -if dt.gui.current_view().name == "lighttable" then +if dt.gui.current_view().id == "lighttable" then install_module() else if not eL.event_registered then diff --git a/contrib/ext_editor.lua b/contrib/ext_editor.lua index 6999c05e..ea957b58 100644 --- a/contrib/ext_editor.lua +++ b/contrib/ext_editor.lua @@ -411,7 +411,7 @@ table.insert(ee.widgets, combobox) table.insert(ee.widgets, box1) -- register new module "external editors" in lighttable ------------------------ -if dt.gui.current_view().name == "lighttable" then +if dt.gui.current_view().id == "lighttable" then install_module() else if not ee.event_registered then diff --git a/contrib/face_recognition.lua b/contrib/face_recognition.lua index 96bc4a26..6d9b0c0e 100644 --- a/contrib/face_recognition.lua +++ b/contrib/face_recognition.lua @@ -484,7 +484,7 @@ fc.widget = dt.new_widget("box"){ table.unpack(widgets), } -if dt.gui.current_view().name == "lighttable" then +if dt.gui.current_view().id == "lighttable" then install_module() else if not fc.event_registered then diff --git a/contrib/geoToolbox.lua b/contrib/geoToolbox.lua index 5a308623..1bce5f31 100644 --- a/contrib/geoToolbox.lua +++ b/contrib/geoToolbox.lua @@ -683,7 +683,7 @@ gT.widget = dt.new_widget("box") } -if dt.gui.current_view().name == "lighttable" then +if dt.gui.current_view().id == "lighttable" then install_module() else if not gT.event_registered then diff --git a/contrib/gpx_export.lua b/contrib/gpx_export.lua index e36b6238..cb76174c 100644 --- a/contrib/gpx_export.lua +++ b/contrib/gpx_export.lua @@ -168,7 +168,7 @@ gpx.widget = dt.new_widget("box") } -if dt.gui.current_view().name == "lighttable" then +if dt.gui.current_view().id == "lighttable" then install_module() else if not gpx.event_registered then diff --git a/contrib/image_time.lua b/contrib/image_time.lua index 676f5af4..b285c61e 100644 --- a/contrib/image_time.lua +++ b/contrib/image_time.lua @@ -546,7 +546,7 @@ img_time.widget = dt.new_widget("box"){ img_time.stack, } -if dt.gui.current_view().name == "lighttable" then +if dt.gui.current_view().id == "lighttable" then install_module() else if not img_time.event_registered then diff --git a/contrib/photils.lua b/contrib/photils.lua index cc41b34c..361ba868 100644 --- a/contrib/photils.lua +++ b/contrib/photils.lua @@ -435,7 +435,7 @@ dt.preferences.register(MODULE_NAME, dt.register_event("mouse-over-image-changed",PHOTILS.image_changed) -if dt.gui.current_view().name == "lighttable" then +if dt.gui.current_view().id == "lighttable" then install_module() else if not PHOTILS.event_registered then diff --git a/contrib/quicktag.lua b/contrib/quicktag.lua index 104c4fe0..09f0be9d 100644 --- a/contrib/quicktag.lua +++ b/contrib/quicktag.lua @@ -251,7 +251,7 @@ qt.widget_table[#qt.widget_table + 1] = new_qt_widget --create module -if dt.gui.current_view().name == "lighttable" then +if dt.gui.current_view().id == "lighttable" then install_module() else if not qt.event_registered then diff --git a/contrib/rename-tags.lua b/contrib/rename-tags.lua index f385a7a6..5ccba2b9 100644 --- a/contrib/rename-tags.lua +++ b/contrib/rename-tags.lua @@ -131,7 +131,7 @@ rt.rename_widget = darktable.new_widget ("box") { darktable.new_widget("button") { label = "Go", clicked_callback = rename_tags } } -if darktable.gui.current_view().name == "lighttable" then +if darktable.gui.current_view().id == "lighttable" then install_module() else if not rt.event_registered then diff --git a/contrib/transfer_hierarchy.lua b/contrib/transfer_hierarchy.lua index 70bb598d..727595cf 100755 --- a/contrib/transfer_hierarchy.lua +++ b/contrib/transfer_hierarchy.lua @@ -361,7 +361,7 @@ darktable.preferences.register( -- Preferences: END -if darktable.gui.current_view().name == "lighttable" then +if darktable.gui.current_view().id == "lighttable" then install_module() else if not th.event_registered then diff --git a/examples/moduleExample.lua b/examples/moduleExample.lua index 12de6828..76a992e0 100644 --- a/examples/moduleExample.lua +++ b/examples/moduleExample.lua @@ -141,7 +141,7 @@ table.insert(mE.widgets, slider) -- ... and tell dt about it all -if dt.gui.current_view().name == "lighttable" then -- make sure we are in lighttable view +if dt.gui.current_view().id == "lighttable" then -- make sure we are in lighttable view install_module() -- register the lib else if not mE.event_registered then -- if we are not in lighttable view then register an event to signal when we might be diff --git a/official/enfuse.lua b/official/enfuse.lua index 4213b480..a2ac3ec2 100644 --- a/official/enfuse.lua +++ b/official/enfuse.lua @@ -263,7 +263,7 @@ if enfuse_installed then -- ... and tell dt about it all - if dt.gui.current_view().name == "lighttable" then + if dt.gui.current_view().id == "lighttable" then install_module() else if not enf.event_registered then diff --git a/official/image_path_in_ui.lua b/official/image_path_in_ui.lua index 60bcce69..7459c520 100644 --- a/official/image_path_in_ui.lua +++ b/official/image_path_in_ui.lua @@ -68,7 +68,7 @@ end main_label.reset_callback = reset_widget -if dt.gui.current_view().name == "lighttable" then +if dt.gui.current_view().id == "lighttable" then install_module() else if not ipiu.event_registered then diff --git a/tools/executable_manager.lua b/tools/executable_manager.lua index 2bbe3927..db65dfa5 100644 --- a/tools/executable_manager.lua +++ b/tools/executable_manager.lua @@ -209,7 +209,7 @@ update_combobox_choices(exec_man.selector, exec_table, 1) -- register the lib -if dt.gui.current_view().name == "lighttable" then +if dt.gui.current_view().id == "lighttable" then install_module() else if not exec_man.event_registered then diff --git a/tools/script_manager.lua b/tools/script_manager.lua index 9592a7ef..b0532e72 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -764,7 +764,7 @@ sm.main_box = dt.new_widget("box"){ -- D A R K T A B L E I N T E G R A T I O N -- - - - - - - - - - - - - - - - - - - - - - - - -if dt.gui.current_view().name == "lighttable" then +if dt.gui.current_view().id == "lighttable" then install_module() else if not sm.event_registered then From a0a8a61d56c6cd35ccc4cbee2ab280ff3ac1666a Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sun, 16 Aug 2020 15:52:57 -0400 Subject: [PATCH 103/445] Enabled latest dev changes in lua API so that script_manager responds better to panel resizing --- tools/script_manager.lua | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/tools/script_manager.lua b/tools/script_manager.lua index b0532e72..5c121a7b 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -65,6 +65,7 @@ local CS = dt.configuration.running_os == "windows" and "&" or ";" local LUA_DIR = dt.configuration.config_dir .. PS .. "lua" local LUA_SCRIPT_REPO = "https://github.com/darktable-org/lua-scripts.git" +local CURR_API_VERSION = dt.configuration.api_version_string dt.print_log("LUA_DIR is " .. LUA_DIR) @@ -284,7 +285,7 @@ local function deactivate(script, scriptname) end local function create_enable_disable_button(btext, sname, req) - return dt.new_widget("button") + button = dt.new_widget("button") { label = btext .. sname, tooltip = get_script_doc(req), @@ -310,6 +311,10 @@ local function create_enable_disable_button(btext, sname, req) end end } + if CURR_API_VERSION >= "6.0.1" then + button.ellipsize = "middle" + end + return button end local function load_script_stack() @@ -733,6 +738,12 @@ sm.main_stack = dt.new_widget("stack"){ table.unpack(sm.main_stack_items), } +if CURR_API_VERSION >= "6.0.1" then + sm.main_stack.h_size_fixed = false + sm.main_stack.v_size_fixed = false +end + + -- make a combobox for the selector sm.main_menu = dt.new_widget("combobox"){ From 650325257ba9b9b3ba9fc69b842c92dd1bba77ad Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sun, 16 Aug 2020 15:57:41 -0400 Subject: [PATCH 104/445] made button a local variable --- tools/script_manager.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/script_manager.lua b/tools/script_manager.lua index 5c121a7b..ecb4999d 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -285,7 +285,7 @@ local function deactivate(script, scriptname) end local function create_enable_disable_button(btext, sname, req) - button = dt.new_widget("button") + local button = dt.new_widget("button") { label = btext .. sname, tooltip = get_script_doc(req), From f76fa01240348883f83088ad5c117b70487178b6 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Tue, 18 Aug 2020 12:08:23 -0400 Subject: [PATCH 105/445] Updated install instructions adding flatpak information and updating preferred way to enable and disable scripts. --- README.md | 44 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 438f5087..11794067 100644 --- a/README.md +++ b/README.md @@ -126,7 +126,17 @@ Ensure git is installed on your system. If it isn't, use the package manager to cd ~/snap/darktable/current git clone https://github.com/darktable-org/lua-scripts.git lua -### flatpak and appimage packages +### flatpak packages + +Flatpak packages now use the internal lua interpreter. + + +Ensure git is installed on your system. If it isn't, use the package manager to install it. Then open a terminal and: + + cd ~/.var/app/org.darktable.Darktable/config/darktable + git clone https://github.com/darktable-org/lua-scripts.git lua + +### appimage packages These packages run in their own environment and don't have access to a lua interpreter, therefore the scripts can't run. The packagers could enable the internal interpreter, or allow the package to link the interpreter from the operating system, or bundle a copy of lua with the package. If you use one of these packages and wish to use the lua scripts, please contact the package maintainer and suggest the above fixes. @@ -150,24 +160,34 @@ If you don't have %LOCALAPPDATA%\darktable you have to start dartable at least o When darktable starts it looks for a file name `~/.config/darktable/luarc` (`%LOCALAPPDATA%\darktable\luarc` for windows) and reads it to see which scripts to include. The file is a plain text file with entries of the form `require "/"` where directory is the directory containing the scripts, from the above list, and name is the name from the above list. To include GIMP the line would be `require "contrib/gimp"`. +The recommended way to enable and disable specific scripts is using the script manager module. To use script manager do the following: + +### Linux or MacOS + + echo 'require "tools/script_manager"' > ~/.config/darktable/luarc + +### Windows + + echo "require 'tools/script_manager'" > %LOCALAPPDATA%\darktable\luarc + +### Snap + + echo 'require "tools/script_manager"' > ~/snap/darktable/current/luarc + +### Flatpak + + echo require "tools/script_manager"' > ~/.var/app/org.darktable.Darktable/config/darktable/luarc + You can also create or add lines to the luarc file from the command line: `echo 'require "contrib/gimp"' > ~/.config/darktable/luarc` to create the file with a gimp entry\ or `echo 'require "contrib/hugin"' >> ~/.config/darktable/luarc` to add an entry for hugin. -Alteratively you can use script_manager.lua as your luarc file. script_manager.lua provides a point and click interface for managing the lua scripts. To use it: - - ln -s $HOME/.config/darktable/lua/tools/script_manager.lua $HOME/.config/darktable/luarc - On windows from a command prompt: `echo require "contrib/gimp" > %LOCALAPPDATA%\darktable\luarc` to create the file with a gimp entry\ or `echo require "contrib/hugin" >> %LOCALAPPDATA%\darktable\luarc` to add an entry for hugin. -Alteratively you can use script_manager.lua as your luarc file. script_manager.lua provides a point and click interface for managing the lua scripts. To use it: - - copy %LOCALAPPDATA%\darktable\lua\tools\script_manager.lua %LOCALAPPDATA%\darktable\luarc - ## Disabling To disable a script open the luarc file in your text editor and insert `--` at the start of the line containing the script you wish to disable, then save the file. @@ -181,6 +201,12 @@ To update the script repository, open a terminal or command prompt and do the fo cd ~/snap/darktable/current/lua git pull + +### Flatpak + + cd ~/.var/app/org.darktable.Darktable/config/darktable/lua + git pull + ### Linux and MacOS cd ~/.config/darktable/lua/ From d9c284b54d7e5a89af4111fbd4dadb81ceb84010 Mon Sep 17 00:00:00 2001 From: supertobi Date: Sun, 6 Sep 2020 20:01:34 +0200 Subject: [PATCH 106/445] Update README.md README - suggested update #286 --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 11794067..8ca96db0 100644 --- a/README.md +++ b/README.md @@ -237,10 +237,14 @@ Running darktable with Lua debugging enabled provides more information about wha Open a terminal and start darktable with the command `snap run darktable -d lua`. This provides debugging information to give you insight into what is happening. -### Linux and MacOS +### Linux Open a terminal and start darktable with the command `darktable -d lua`. This provides debugging information to give you insight into what is happening. +### MacOS + +Open a terminal and start darktable with the command `/Applications/darktable.app/Contents/MacOS/darktable -d lua`. This provides debugging information to give you insight into what is happening. + ### Windows Open a command prompt. Start darktable with the command "C:\Program Files\darktable\bin\darktable" -d lua > log.txt. This provides debugging information to give you insight into what is happening. From 394cbdb4544a4d1d40f040eef0d987b9bb5beb7f Mon Sep 17 00:00:00 2001 From: homer3018 <36423314+homer3018@users.noreply.github.com> Date: Fri, 11 Sep 2020 00:05:22 +0200 Subject: [PATCH 107/445] Typo --- contrib/enfuseAdvanced.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/enfuseAdvanced.lua b/contrib/enfuseAdvanced.lua index 932a6cdd..016bdce1 100644 --- a/contrib/enfuseAdvanced.lua +++ b/contrib/enfuseAdvanced.lua @@ -939,7 +939,7 @@ GUI.Presets.current_preset = dt.new_widget('combobox'){ end } GUI.Presets.load = dt.new_widget('button'){ - label = _('laod fusion preset'), + label = _('load fusion preset'), tooltip = _('load current fusion parameters from selected preset'), clicked_callback = function() LoadFromPreference(GUI.Presets.current_preset.value) end } From 85c218b350065c69cb3cb9f652061426545d3f73 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Mon, 14 Sep 2020 20:47:29 -0400 Subject: [PATCH 108/445] [contrib/enfuseAdvanced] fixed translations in for loops by changing the unused variable _ to x so that the translation function _() doesn't get replaced with the value of _. --- contrib/enfuseAdvanced.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contrib/enfuseAdvanced.lua b/contrib/enfuseAdvanced.lua index 932a6cdd..e5a3733c 100644 --- a/contrib/enfuseAdvanced.lua +++ b/contrib/enfuseAdvanced.lua @@ -240,7 +240,7 @@ end local function ExeUpdate(prog_tbl) --updates executable paths and verifies them dt.preferences.write(mod, 'bin_exists', 'bool', true) - for _,prog in pairs(prog_tbl) do + for x,prog in pairs(prog_tbl) do dt.preferences.write('executable_paths', prog.name, 'string', GUI.exes[prog.name].value) prog.bin = df.check_if_bin_exists(prog.name) if not prog.bin then @@ -455,7 +455,7 @@ local function main(storage, image_table, extra_data) local image_num = 0 local job = dt.gui.create_job('blending '..#variants..' image(s)', true) --create a GUI job bar to display enfuse progress UpdateActivePreference() --load current GUI values into active preference (only applies to elements without a clicked/changed callback) - for _,prefix in pairs(variants) do --for each image to be created load in the preference values, build arguments string, output image, and run command then execute. + for x,prefix in pairs(variants) do --for each image to be created load in the preference values, build arguments string, output image, and run command then execute. job.percent = image_num /(#variants) image_num = image_num+1 ENF.images_string, final_image, source_raw = UpdateENFargs(image_table, prefix) From 8808306a5f6165a210849df977784e3fe2e6eedd Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Wed, 16 Sep 2020 00:05:53 -0400 Subject: [PATCH 109/445] [contrib/enfusedAdvanced.lua] _ was declared globally in a subroutine, thus negating translation once the subroutine was called. --- contrib/enfuseAdvanced.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/enfuseAdvanced.lua b/contrib/enfuseAdvanced.lua index bf6ef3ed..a40be53b 100644 --- a/contrib/enfuseAdvanced.lua +++ b/contrib/enfuseAdvanced.lua @@ -311,7 +311,7 @@ local function UpdateENFargs(image_table, prefix) --updates the Enfuse arguments local largest_id = 0 local first_raw = {} for raw, temp_image in pairs(image_table) do - _, source_name, source_id = GetFileName(raw.filename) + local _, source_name, source_id = GetFileName(raw.filename) source_id = tonumber(source_id) if source_id < smallest_id then smallest_id = source_id From b5b49245fa25090fa4e6930dffc4f624d291d447 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Tue, 17 Nov 2020 18:53:54 -0500 Subject: [PATCH 110/445] Needlessly creating the executable path preference for the ufraw-batch executable on linux caused the value to be saved as the startup directory, which in turn caused a crash when trying to extract the embedded jpg. --- examples/multi_os.lua | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/examples/multi_os.lua b/examples/multi_os.lua index 96b60c2b..04acf56c 100644 --- a/examples/multi_os.lua +++ b/examples/multi_os.lua @@ -204,24 +204,26 @@ end to see if the executable is there. ]] -local executable = "ufraw-batch" -local ufraw_batch_path_widget = dt.new_widget("file_chooser_button"){ - title = _("Select ufraw-batch[.exe] executable"), - value = df.get_executable_path_preference(executable), - is_directory = false, - changed_callback = function(self) - if df.check_if_bin_exists(self.value) then - df.set_executable_path_preference(executable, self.value) +if dt.configuration.running_os ~= "linux" then + local executable = "ufraw-batch" + local ufraw_batch_path_widget = dt.new_widget("file_chooser_button"){ + title = _("Select ufraw-batch[.exe] executable"), + value = df.get_executable_path_preference(executable), + is_directory = false, + changed_callback = function(self) + if df.check_if_bin_exists(self.value) then + df.set_executable_path_preference(executable, self.value) + end end - end -} -dt.preferences.register("executable_paths", "ufraw-batch", -- name - "file", -- type - _('multi_os: ufraw-batch location'), -- label - _('Installed location of ufraw-batch. Requires restart to take effect.'), -- tooltip - "ufraw-batch", -- default - ufraw_batch_path_widget -) + } + dt.preferences.register("executable_paths", "ufraw-batch", -- name + "file", -- type + _('multi_os: ufraw-batch location'), -- label + _('Installed location of ufraw-batch. Requires restart to take effect.'), -- tooltip + "ufraw-batch", -- default + ufraw_batch_path_widget + ) +end --[[ Add a button to the selected images module in lighttable From 536b9726b22940c3e06f7f6df1db61eede7f8446 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Thu, 19 Nov 2020 00:35:17 -0500 Subject: [PATCH 111/445] [enfuseAdvanced] Added check for comma decimal separator. Replace with period if found. --- contrib/enfuseAdvanced.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/contrib/enfuseAdvanced.lua b/contrib/enfuseAdvanced.lua index a40be53b..8e822a1f 100644 --- a/contrib/enfuseAdvanced.lua +++ b/contrib/enfuseAdvanced.lua @@ -470,6 +470,8 @@ local function main(storage, image_table, extra_data) --copy exif data from original file run_cmd = EXF.bin..' -TagsFromFile '..df.sanitize_filename(source_raw.path..os_path_seperator..source_raw.filename)..' -exif:all --subifd:all -overwrite_original '..df.sanitize_filename(final_image) + -- replace comma decimal separator with period + run_cmd = string.gsub(run_cmd, '(%d),(%d)', "%1.%2") resp = dsys.external_command(run_cmd) From 4ab20d808849df4d8ef87ba12aa6a245ae785dcf Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sat, 21 Nov 2020 18:33:26 -0500 Subject: [PATCH 112/445] Removed official/yield.lua since it was only required for lua API 3.x and less (darktable 2.0 and before). Removed require from scripts that had included it. --- contrib/geoJSON_export.lua | 1 - contrib/geoToolbox.lua | 1 - contrib/hugin.lua | 3 +-- contrib/pdf_slideshow.lua | 1 - contrib/slideshowMusic.lua | 1 - lib/dtutils/system.lua | 1 - official/generate_image_txt.lua | 1 - official/selection_to_pdf.lua | 1 - official/yield.lua | 42 --------------------------------- tools/script_manager.lua | 2 +- 10 files changed, 2 insertions(+), 52 deletions(-) delete mode 100644 official/yield.lua diff --git a/contrib/geoJSON_export.lua b/contrib/geoJSON_export.lua index 4834bb01..4815e071 100644 --- a/contrib/geoJSON_export.lua +++ b/contrib/geoJSON_export.lua @@ -35,7 +35,6 @@ USAGE local dt = require "darktable" local du = require "lib/dtutils" local df = require "lib/dtutils.file" -require "official/yield" local gettext = dt.gettext du.check_min_api_version("3.0.0", "geoJSON_export") diff --git a/contrib/geoToolbox.lua b/contrib/geoToolbox.lua index 1bce5f31..86dd533b 100644 --- a/contrib/geoToolbox.lua +++ b/contrib/geoToolbox.lua @@ -28,7 +28,6 @@ require "geoToolbox" local dt = require "darktable" local du = require "lib/dtutils" local df = require "lib/dtutils.file" -require "official/yield" local gettext = dt.gettext du.check_min_api_version("3.0.0", "geoToolbox") diff --git a/contrib/hugin.lua b/contrib/hugin.lua index 83ec3be4..1de8f04a 100644 --- a/contrib/hugin.lua +++ b/contrib/hugin.lua @@ -40,7 +40,6 @@ local du = require "lib/dtutils" local df = require "lib/dtutils.file" local log = require "lib/dtutils.log" local dtsys = require "lib/dtutils.system" -require "official/yield" local gettext = dt.gettext local namespace = 'module_hugin' @@ -227,4 +226,4 @@ dt.register_storage(namespace, _("hugin panorama"), show_status, create_panorama -- --- vim: shiftwidth=2 expandtab tabstop=2 cindent syntax=lua \ No newline at end of file +-- vim: shiftwidth=2 expandtab tabstop=2 cindent syntax=lua diff --git a/contrib/pdf_slideshow.lua b/contrib/pdf_slideshow.lua index f01b014b..10e84db9 100644 --- a/contrib/pdf_slideshow.lua +++ b/contrib/pdf_slideshow.lua @@ -41,7 +41,6 @@ format (all fields can be the empty string): local dt = require "darktable" local du = require "lib/dtutils" local df = require "lib/dtutils.file" -require "official/yield" local gettext = dt.gettext diff --git a/contrib/slideshowMusic.lua b/contrib/slideshowMusic.lua index 90d6bc34..921c6ffd 100644 --- a/contrib/slideshowMusic.lua +++ b/contrib/slideshowMusic.lua @@ -27,7 +27,6 @@ USAGE local dt = require "darktable" local du = require "lib/dtutils" local df = require "lib/dtutils.file" -require "official/yield" local gettext = dt.gettext du.check_min_api_version("2.0.2", "slideshowMusic") diff --git a/lib/dtutils/system.lua b/lib/dtutils/system.lua index f202d6d4..f41f821c 100644 --- a/lib/dtutils/system.lua +++ b/lib/dtutils/system.lua @@ -1,7 +1,6 @@ local dtutils_system = {} local dt = require "darktable" -require "official/yield" -- necessary for dt.control.execute() dtutils_system.libdoc = { Name = [[dtutils.system]], diff --git a/official/generate_image_txt.lua b/official/generate_image_txt.lua index a214a2ae..0d343301 100644 --- a/official/generate_image_txt.lua +++ b/official/generate_image_txt.lua @@ -37,7 +37,6 @@ USAGE local dt = require "darktable" local du = require "lib/dtutils" require "darktable.debug" -require "official/yield" du.check_min_api_version("2.1.0", "generate_image_txt") diff --git a/official/selection_to_pdf.lua b/official/selection_to_pdf.lua index f6fbfe85..9d548da4 100644 --- a/official/selection_to_pdf.lua +++ b/official/selection_to_pdf.lua @@ -35,7 +35,6 @@ Plugin allows you to choose how many thumbnails you need per row ]] local dt = require "darktable" local du = require "lib/dtutils" -require "official/yield" du.check_min_api_version("2.0.0", "selection_to_pdf") diff --git a/official/yield.lua b/official/yield.lua deleted file mode 100644 index 3e5cb9b9..00000000 --- a/official/yield.lua +++ /dev/null @@ -1,42 +0,0 @@ ---[[ - This file is part of darktable, - Copyright 2016 by Tobias Jakobs. - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -]] ---[[ -darktable yield compatibility script - -USAGE -* require this script from your main Lua file in the first line - -]] -local dt = require "darktable" -local yield_orig = coroutine.yield - -if (dt.configuration.api_version_major < 4) then - dt.control = {} - dt.control.execute = function(command) - yield_orig("RUN_COMMAND", command) - end - dt.control.read = function(command) - yield_orig("FILE_READABLE", command) - end - dt.control.sleep = function(command) - yield_orig("WAIT_MS", command) - end -end - --- vim: shiftwidth=2 expandtab tabstop=2 cindent syntax=lua --- kate: hl Lua; diff --git a/tools/script_manager.lua b/tools/script_manager.lua index ecb4999d..684d488b 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -226,7 +226,7 @@ local function scan_scripts() if not string.match(script_file, "yield") then -- special case, because everything needs this add_script_data(script_file) else - prequire(script_file) -- load yield.lua + -- prequire(script_file) -- load yield.lua end end end From 43315bb9ccb2e662fcb0d6bc7692d8fca450240f Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Wed, 25 Nov 2020 19:39:49 -0500 Subject: [PATCH 113/445] [enfuseAdvanced] added a sanitize_decimals function to sanitize the command lines. --- contrib/enfuseAdvanced.lua | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/contrib/enfuseAdvanced.lua b/contrib/enfuseAdvanced.lua index 8e822a1f..a9f6ea0b 100644 --- a/contrib/enfuseAdvanced.lua +++ b/contrib/enfuseAdvanced.lua @@ -180,6 +180,11 @@ for _,i in pairs(dt.styles) do end -- FUNCTION -- + +local function sanitize_decimals(cmd) -- make sure decimal separator is a '.' + return string.gsub(cmd, '(%d),(%d)', "%1.%2") +end + local function InRange(test, low, high) -- tests if test value is within range of low and high (inclusive) if test >= low and test <= high then return true @@ -435,6 +440,9 @@ local function main(storage, image_table, extra_data) local job = dt.gui.create_job('aligning images') image_table, images_to_remove, AIS.images_string = UpdateAISargs(image_table, images_to_remove) local run_cmd = BuildExecuteCmd(AIS) + dt.print_log("AIS run command is " .. run_cmd) + run_cmd = sanitize_decimals(run_cmd) + dt.print_log("AIS decimaal sanitized command is " .. run_cmd) local resp = dsys.external_command(run_cmd) job.valid = false if resp ~= 0 then @@ -460,6 +468,9 @@ local function main(storage, image_table, extra_data) image_num = image_num+1 ENF.images_string, final_image, source_raw = UpdateENFargs(image_table, prefix) local run_cmd = BuildExecuteCmd(ENF) + dt.print_log("ENF run command is " .. run_cmd) + run_cmd = sanitize_decimals(run_cmd) + dt.print_log("ENF decimaal sanitized command is " .. run_cmd) local resp = dsys.external_command(run_cmd) if resp ~= 0 then remove_temp_files(images_to_remove) @@ -471,12 +482,15 @@ local function main(storage, image_table, extra_data) --copy exif data from original file run_cmd = EXF.bin..' -TagsFromFile '..df.sanitize_filename(source_raw.path..os_path_seperator..source_raw.filename)..' -exif:all --subifd:all -overwrite_original '..df.sanitize_filename(final_image) -- replace comma decimal separator with period - run_cmd = string.gsub(run_cmd, '(%d),(%d)', "%1.%2") + dt.print_log("EXF run command is " .. run_cmd) + run_cmd = sanitize_decimals(run_cmd) + dt.print_log("EXF decimaal sanitized command is " .. run_cmd) resp = dsys.external_command(run_cmd) if GUI.Target.auto_import.value then --import image into dt if specified local imported = dt.database.import(final_image) + dt.print_log("image imported") if GUI.Target.apply_style.selected > 1 then --apply specified style to imported image local set_style = styles[GUI.Target.apply_style.selected - 1] dt.styles.apply(set_style , imported) From da0574839373e6c57e879f41d2b74cd19b54380c Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sun, 29 Nov 2020 18:00:47 -0500 Subject: [PATCH 114/445] [file.lua] combined the is_ functions into file_test() which allows testing to see if a path exists, is a dir, is a file, or is executable. Added case insensitive search to the windows search for bin. --- lib/dtutils/file.lua | 283 +++++++++++++++++++++++++------------------ 1 file changed, 167 insertions(+), 116 deletions(-) diff --git a/lib/dtutils/file.lua b/lib/dtutils/file.lua index 05f229f1..3fb4fa50 100644 --- a/lib/dtutils/file.lua +++ b/lib/dtutils/file.lua @@ -35,86 +35,55 @@ local function _(msgid) return gettext.dgettext("dtutils.file", msgid) end -dtutils_file.libdoc.functions["is_dir"] = { - Name = [[is_dir]], - Synopsis = [[check if a path is a directory]], - Usage = [[local df = require "lib/dtutils.file" +--[[ + local function to run a test command on windows and return a true if it succeeds + instead of returning true if it runs +]] - local result = df.is_dir(path) - path - string - the path to check]], - Description = [[is_dir checks a path to see if it is a directory]], - Return_Value = [[result - boolean - true if path is a directory, nil if not]], - Limitations = [[]], - Example = [[]], - See_Also = [[]], - Reference = [[]], - License = [[]], - Copyright = [[]], -} - -function dtutils_file.is_dir(path) - local cmd = nil - - if dt.configuration.running_os == "windows" then - cmd = "if exist " .. ds.sanitize(path .. "\\*") +local function _win_os_execute(cmd) + local result = nil + local p = io.popen(cmd) + local output = p:read("*a") + p:close() + if string.match(output, "true") then + result = true else - cmd = "test -d " .. ds.sanitize(path) + result = false end - - return os.execute(cmd) + return result end -dtutils_file.libdoc.functions["is_file"] = { - Name = [[is_file]], - Synopsis = [[check if a path is a file]], - Usage = [[local df = require "lib/dtutils.file" +--[[ + local function to determine if a path name is a windows executable +]] - local result = df.is_file(path) - path - string - the path to check]], - Description = [[is_file checks a path to see if it is a file]], - Return_Value = [[result - boolean - true if path is a file, nil if not]], - Limitations = [[]], - Example = [[]], - See_Also = [[]], - Reference = [[]], - License = [[]], - Copyright = [[]], -} - -function dtutils_file.is_file(path) - local cmd = nil +local function _is_windows_executable(path) local result = false - - if dt.configuration.running_os == "windows" then - if not dtutils_file.is_dir(path) then - cmd = "if exist " .. ds.sanitize(path) .. " echo true" - local p = io.popen(cmd) - output = p:read("*a") - p:close() - if string.match(output, "true") then + if dtutils_file.test_file(path, "f") then + if string.match(path, ".exe$") or string.match(path, ".EXE$") or + string.match(path, ".com$") or string.match(path, ".COM$") or + string.match(path, ".bat$") or string.match(path, ".BAT$") or + string.match(path, ".cmd$") or string.match(path, ".CMD$") then result = true - else - result = false - end - else - return false end - else - result = os.execute("test -f " .. ds.sanitize(path)) end - return result end -dtutils_file.libdoc.functions["is_executable"] = { - Name = [[is_executable]], - Synopsis = [[check if a path is a executable]], +dtutils_file.libdoc.functions["test_file"] = { + Name = [[test_file]], + Synopsis = [[test a file to see what it is]], Usage = [[local df = require "lib/dtutils.file" - local result = df.is_executable(path) - path - string - the path to check]], - Description = [[is_executable checks a path to see if it is an executable]], - Return_Value = [[result - boolean - true if path is an executable, nil if not]], + local result = df.test_file(path, test) + path - string - the path to check + test - one of d, e, f, x where + d - directory + e - exists + f - file + x - executable]], + Description = [[test_file checks a path to see if it is a directory]], + Return_Value = [[result - boolean - true if path is a directory, nil if not]], Limitations = [[]], Example = [[]], See_Also = [[]], @@ -123,54 +92,61 @@ dtutils_file.libdoc.functions["is_executable"] = { Copyright = [[]], } -local function _is_windows_executable(path) - local result = nil - dt.print_log("checking " .. path) +function dtutils_file.test_file(path, test) + local cmd = "test -" + local engine = os.execute + local cmdstring = "" - if string.match(path, ".exe$") or string.match(path, ".EXE$") or - string.match(path, ".com$") or string.match(path, ".COM$") or - string.match(path, ".bat$") or string.match(path, ".BAT$") or - string.match(path, ".cmd$") or string.match(path, ".CMD$") then - result = true + if dt.configuration.running_os == "windows" then + cmd = "if exist " + engine = _win_os_execute end - return result -end - -function dtutils_file.is_executable(path) - local result = nil - - if dt.configuration.running_os == "windows" then - if _is_windows_executable(path) then - result = true + if test == "d" then + -- test if directory + if dt.configuration.running_os == "windows" then + cmdstring = cmd .. dtutils_file.sanitize_filename(path .. "\\*") .. " echo true" + else + cmdstring = cmd .. test .. " " .. dtutils_file.sanitize_filename(path) + end + elseif test == "e" then + -- test exists + if dt.configuration.running_os == "windows" then + cmdstring = cmd .. dtutils_file.sanitize_filename(path) .. " echo true" + else + cmdstring = cmd .. test .. " " .. dtutils_file.sanitize_filename(path) + end + elseif test == "f" then + -- test if file + if dt.configuration.running_os == "windows" then + if not dtutils_file.test_file(path, "d") then -- make sure it's not a directory + cmdstring = cmd .. dtutils_file.sanitize_filename(path) .. " echo true" + else + return false + end + else + cmdstring = cmd .. test .. " " .. dtutils_file.sanitize_filename(path) + end + elseif test == "x" then + -- test executable + if dt.configuration.running_os == "windows" then + return _is_windows_executable(path) + else + cmdstring = cmd .. test .. " " .. dtutils_file.sanitize_filename(path) end else - result = os.execute("test -x " .. ds.sanitize(path)) + dt.print_error("[test_file] unknown test " .. test) + return false end - return result -end -dtutils_file.libdoc.functions["check_if_bin_exists"] = { - Name = [[check_if_bin_exists]], - Synopsis = [[check if an executable exists]], - Usage = [[local df = require "lib/dtutils.file" + return engine(cmdstring) +end - local result = df.check_if_bin_exists(bin) - bin - string - the binary to check for]], - Description = [[check_if_bin_exists checks to see if the specified binary exists. - check_if_bin_exists first checks to see if a preference for the binary has been - registered and uses that if found. The presence of the file is verified, then - quoted and returned. If no preference is specified and the operating system is - linux then the which command is used to check for a binary in the path. If found - that path is returned. If no binary is found, false is returned.]], - Return_Value = [[result - string - the sanitized path of the binary, false if not found]], - Limitations = [[]], - Example = [[]], - See_Also = [[]], - Reference = [[]], - License = [[]], - Copyright = [[]], -} +local function _case_insensitive_pattern(pattern) + return pattern:gsub("(.)", function(letter) + return string.format("[%s$s]", letter:lower(), letter:upper()) + end) +end local function _search_for_bin_windows(bin) local result = false @@ -185,9 +161,11 @@ local function _search_for_bin_windows(bin) local output = p:read("*a") p:close() local lines = du.split(output, "\n") + local cibin = _case_insensitive_pattern(bin) for _,line in ipairs(lines) do - if string.match(line, bin) then - if dtutils_file.is_file(line) and dtutils_file.is_executable(line) then + if string.match(line, cibin) then + dt.print_log("found win search match " .. line) + if dtutils_file.test_file(line, "f") and dtutils_file.test_file(line, "x") then dtutils_file.set_executable_path_preference(bin, line) -- save it so we don't have to search again return line end @@ -204,7 +182,7 @@ local function _search_for_bin_nix(bin) p:close() if string.len(output) > 0 then local spath = dtutils_file.sanitize_filename(output:sub(1,-2)) - if dtutils_file.is_file(spath) and dtutils_file.is_executable(spath) then + if dtutils_file.test_file(spath, "f") and dtutils_file.test_file(spath, "x") then result = spath end end @@ -230,7 +208,7 @@ local function _search_for_bin_macos(bin) for _,line in ipairs(lines) do local spath = dtutils_file.sanitize_filename(line:sub(1, -2)) - if dtutils_file.is_executable(spath) then + if dtutils_file.test_file(spath, "x") then dtutils_file.set_executable_path_preference(bin, spath) result = spath end @@ -245,6 +223,9 @@ local function _search_for_bin(bin) if dt.configuration.running_os == "windows" then result = _search_for_bin_windows(bin) + if result then + result = dtutils_file.sanitize_filename(result) + end elseif dt.configuration.running_os == "macos" then result = _search_for_bin_macos(bin) else @@ -279,13 +260,13 @@ local function _check_path_for_bin(bin) else path = dtutils_file.get_executable_path_preference(bin) -- reset path preference is the returned preference is a directory - if dtutils_file.is_dir(path) then + if dtutils_file.test_file(path, "d") then dtutils_file.set_executable_path_preference(bin, "") path = nil end end - if path and dtutils_file.is_dir(path) then + if path and dtutils_file.test_file(path, "d") then path = nil end @@ -294,7 +275,7 @@ local function _check_path_for_bin(bin) end if path and not result then - if dtutils_file.is_executable(path) then + if dtutils_file.test_file(path, "x") then result = dtutils_file.sanitize_filename(path) end end @@ -302,15 +283,69 @@ local function _check_path_for_bin(bin) return result end +local function _old_check_if_bin_exists(bin) -- only run on windows if preference checked + local result = false + local path = nil + + if string.match(bin, "\\") then + path = bin + else + path = dtutils_file.get_executable_path_preference(bin) + end + + if string.len(path) > 0 then + if dtutils_file.check_if_file_exists(path) then + if (string.match(path, ".exe$") or string.match(path, ".EXE$")) then + result = dtutils_file.sanitize_filename(path) + end + end + end + return result +end + +dtutils_file.libdoc.functions["check_if_bin_exists"] = { + Name = [[check_if_bin_exists]], + Synopsis = [[check if an executable exists]], + Usage = [[local df = require "lib/dtutils.file" + + local result = df.check_if_bin_exists(bin) + bin - string - the binary to check for]], + Description = [[check_if_bin_exists checks to see if the specified binary exists. + check_if_bin_exists first checks to see if a preference for the binary has been + registered and uses that if found, after it's verified to be an executable and + exist. If no preference exissts, the user's path is checked for the executable. + If the executable is not found in the users path, then a search of the operating + system is conducted to see if the executable can be found. + + If an executalble is found, it's verified to exist and be an executable. Once + the executable is verified, the path is saved as a preference to speed up + subsequent checks. The executable path is sanitized and returned. + + If no executable is found, false is returned.]], + Return_Value = [[result - string - the sanitized path of the binary, false if not found]], + Limitations = [[If more than one executable that satisfies the search results is found, the + wrong one may be returned. If the wrong value is returned, the user can still specify the + correct execuable using tools/executable_manager.]], + Example = [[]], + See_Also = [[executable_manager]], + Reference = [[]], + License = [[]], + Copyright = [[]], +} + function dtutils_file.check_if_bin_exists(bin) local result = false - result = _check_path_for_bin(bin) + if dt.configuration.running_os == "windows" and dt.preferences.read("dtutils.file", "use_old_check_if_bin_exists", "bool") then + result = _old_check_if_bin_exists(bin) + else + + result = _check_path_for_bin(bin) - if not result then - result = _search_for_bin(bin) + if not result then + result = _search_for_bin(bin) + end end - return result end @@ -856,5 +891,21 @@ function dtutils_file.rmdir(path) return dsys.external_command(rm_cmd.." "..path) end +--[[ + The new check_if_bin_exists() does multiple calls to the operating system to check + if the file exists and is an executable. On windows, each call to the operating system + causes a window to open in order to run the command, then the window closes when the + command exits. If the user gets annoyed by the "flickering windows", then they can + enable this preference to use the old check_if_bin_exists() that relys on the + executable path preferences and doesn't do as many checks. +]] + +if dt.configuration.running_os == "windows" then + dt.preferences.register("dtutils.file", "use_old_check_if_bin_exists", "bool", + "lua scripts use old check_if_bin_exists()", + "lessen flickering windows effect when scripts run", + false) +end + return dtutils_file From ddcf3ed3f4dd8cf35c54ef3d6af8360d858682a0 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sun, 29 Nov 2020 18:41:32 -0500 Subject: [PATCH 115/445] [file.lua] fixed line trimming in macos search for bin --- lib/dtutils/file.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/dtutils/file.lua b/lib/dtutils/file.lua index 3fb4fa50..5f785742 100644 --- a/lib/dtutils/file.lua +++ b/lib/dtutils/file.lua @@ -207,9 +207,9 @@ local function _search_for_bin_macos(bin) local lines = du.split(output, "\n") for _,line in ipairs(lines) do - local spath = dtutils_file.sanitize_filename(line:sub(1, -2)) + local spath = dtutils_file.sanitize_filename(line:sub(1, -1)) if dtutils_file.test_file(spath, "x") then - dtutils_file.set_executable_path_preference(bin, spath) + dtutils_file.set_executable_path_preference(bin, spath) -- save it so we don't have to search again result = spath end end From b89338335337072591d792a0879fb306719b64b4 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Mon, 30 Nov 2020 21:06:57 -0500 Subject: [PATCH 116/445] [file.lua] Added comments for local functions. Added more API documentation for check_if_bin_exists. Added save executable path preference to _search_for_nix_bin() so that we can save a little time on subsequent runs once an executable is found. --- lib/dtutils/file.lua | 52 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 3 deletions(-) diff --git a/lib/dtutils/file.lua b/lib/dtutils/file.lua index 5f785742..77d310c8 100644 --- a/lib/dtutils/file.lua +++ b/lib/dtutils/file.lua @@ -59,6 +59,7 @@ end local function _is_windows_executable(path) local result = false +dt.print_log("in -is_windows_executable") if dtutils_file.test_file(path, "f") then if string.match(path, ".exe$") or string.match(path, ".EXE$") or string.match(path, ".com$") or string.match(path, ".COM$") or @@ -142,12 +143,22 @@ function dtutils_file.test_file(path, test) return engine(cmdstring) end +--[[ + local function to return a case insensitive pattern for matching + i.e. gimp becomes [Gg][Ii][Mm][Pp] which should match any capitalization + of gimp. +]] + local function _case_insensitive_pattern(pattern) return pattern:gsub("(.)", function(letter) return string.format("[%s$s]", letter:lower(), letter:upper()) end) end +--[[ + local function to search windows for an executable +]] + local function _search_for_bin_windows(bin) local result = false -- use where on path @@ -175,24 +186,33 @@ local function _search_for_bin_windows(bin) return result end +--[[ + local function to search *nix systems for an executable +]] + local function _search_for_bin_nix(bin) local result = false local p = io.popen("which " .. bin) local output = p:read("*a") p:close() if string.len(output) > 0 then - local spath = dtutils_file.sanitize_filename(output:sub(1,-2)) + local spath = dtutils_file.sanitize_filename(output:sub(1, -2)) if dtutils_file.test_file(spath, "f") and dtutils_file.test_file(spath, "x") then + dtutils_file.set_executable_path_preference(bin, spath) result = spath end end return result end +--[[ + local function to search macos systems for an executable +]] + local function _search_for_bin_macos(bin) local result = false - result = _search_for_bin_nix(bin) + result = _search_for_bin_nix(bin) -- see if it's in the path if not result then local search_start = "/Applications" @@ -218,6 +238,11 @@ local function _search_for_bin_macos(bin) return result end +--[[ + local function to provide a generic search call that can be + split into operating system specific calls +]] + local function _search_for_bin(bin) local result = false @@ -235,6 +260,11 @@ local function _search_for_bin(bin) return result end +--[[ + local function to check if an executable path is + a windows executable on linux or macos, thus requiring wine to run +]] + local function _check_path_for_wine_bin(path) local result = false @@ -249,6 +279,12 @@ local function _check_path_for_wine_bin(path) return result end +--[[ + local function to check if an executable path is + a valid executable. Some generic checks are done before + system specific checks are done. +]] + local function _check_path_for_bin(bin) local result = false local path = nil @@ -283,6 +319,12 @@ local function _check_path_for_bin(bin) return result end +--[[ + local function to the old check_if_bin_exists functionality + on windows in order to decrease the amount of windows being + created and destroyed by system calls. +]] + local function _old_check_if_bin_exists(bin) -- only run on windows if preference checked local result = false local path = nil @@ -325,7 +367,10 @@ dtutils_file.libdoc.functions["check_if_bin_exists"] = { Return_Value = [[result - string - the sanitized path of the binary, false if not found]], Limitations = [[If more than one executable that satisfies the search results is found, the wrong one may be returned. If the wrong value is returned, the user can still specify the - correct execuable using tools/executable_manager.]], + correct execuable using tools/executable_manager. Most packages are well behaved with the + notiable exception being GIMP on windows. Depending on the packager there are multiple + gimp executables, often with version numbers. In this case, the user needs to specify + the location of the correct executable using executable_manager.]], Example = [[]], See_Also = [[executable_manager]], Reference = [[]], @@ -334,6 +379,7 @@ dtutils_file.libdoc.functions["check_if_bin_exists"] = { } function dtutils_file.check_if_bin_exists(bin) +dt.print_log("in check_if_bin_exists") local result = false if dt.configuration.running_os == "windows" and dt.preferences.read("dtutils.file", "use_old_check_if_bin_exists", "bool") then From b41b2a1566dd54d933f16cb87fb452e3ce2fa90b Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Mon, 30 Nov 2020 21:51:55 -0500 Subject: [PATCH 117/445] [file.lua] Added create_tmp_file() back in. --- lib/dtutils/file.lua | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/lib/dtutils/file.lua b/lib/dtutils/file.lua index 77d310c8..f9f14557 100644 --- a/lib/dtutils/file.lua +++ b/lib/dtutils/file.lua @@ -937,6 +937,38 @@ function dtutils_file.rmdir(path) return dsys.external_command(rm_cmd.." "..path) end +dtutils_file.libdoc.functions["create_tmp_file"] = { + Name = [[create_tmp_file]], + Synopsis = [[creates a temporary file]], + Usage = [[local df = require "lib/dtutils.file + + local result = df.create_tmp_file()]], + Description = [[create_tmp_file can be used to create temporary files]], + Return_Value = [[result - string - path to the created temporary file.]], + Limitations = [[]], + Example = [[]], + See_Also = [[]], + Reference = [[]], + License = [[]], + Copyright = [[]], +} + +function dtutils_file.create_tmp_file() + local tmp_file = os.tmpname() + if dt.configuration.running_os == "windows" then + tmp_file = dt.configuration.tmp_dir .. tmp_file -- windows os.tmpname() defaults to root directory + end + + local f = io.open(tmp_file, "w") + if not f then + log.msg(log.error, string.format("Error writing to `%s`", tmp_file)) + os.remove(tmp_file) + return nil + end + + return tmp_file +end + --[[ The new check_if_bin_exists() does multiple calls to the operating system to check if the file exists and is an executable. On windows, each call to the operating system From b26ec58f9f516e932f3350402282fea54a19ceed Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Sun, 13 Dec 2020 22:00:39 -0300 Subject: [PATCH 118/445] Sanitize filename in fujifilm_ratings.lua to handle spaces. --- contrib/fujifilm_ratings.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/fujifilm_ratings.lua b/contrib/fujifilm_ratings.lua index 6cf92c97..29ec406e 100644 --- a/contrib/fujifilm_ratings.lua +++ b/contrib/fujifilm_ratings.lua @@ -41,7 +41,7 @@ local function detect_rating(event, image) dt.print_error(_("exiftool not found")) return end - local RAF_filename = tostring(image) + local RAF_filename = df.sanitize_filename(tostring(image)) local JPEG_filename = string.gsub(RAF_filename, "%.RAF$", ".JPG") local command = "exiftool -Rating " .. JPEG_filename dt.print_error(command) From e86a3a323605afc32255a613184db5769a5cd73b Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Fri, 18 Dec 2020 11:08:12 -0500 Subject: [PATCH 119/445] [file.lua] removed debugging statement --- lib/dtutils/file.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/dtutils/file.lua b/lib/dtutils/file.lua index f9f14557..aa15e8cc 100644 --- a/lib/dtutils/file.lua +++ b/lib/dtutils/file.lua @@ -379,7 +379,6 @@ dtutils_file.libdoc.functions["check_if_bin_exists"] = { } function dtutils_file.check_if_bin_exists(bin) -dt.print_log("in check_if_bin_exists") local result = false if dt.configuration.running_os == "windows" and dt.preferences.read("dtutils.file", "use_old_check_if_bin_exists", "bool") then From 96ba075e868284be920e3d5a3c73192ee10da042 Mon Sep 17 00:00:00 2001 From: wpferguson Date: Tue, 22 Dec 2020 22:00:41 -0500 Subject: [PATCH 120/445] Removed debugging statement --- lib/dtutils/file.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/dtutils/file.lua b/lib/dtutils/file.lua index aa15e8cc..2bb0a7a3 100644 --- a/lib/dtutils/file.lua +++ b/lib/dtutils/file.lua @@ -59,7 +59,6 @@ end local function _is_windows_executable(path) local result = false -dt.print_log("in -is_windows_executable") if dtutils_file.test_file(path, "f") then if string.match(path, ".exe$") or string.match(path, ".EXE$") or string.match(path, ".com$") or string.match(path, ".COM$") or From 37b523f989c8f786bea90031bba6261547f110bb Mon Sep 17 00:00:00 2001 From: wpferguson Date: Wed, 23 Dec 2020 19:54:16 -0500 Subject: [PATCH 121/445] [script_manager] rewrite of script_manager for a better fit with darktable 3.4 and the new scripts_installer. Changed interface to paged instead of scrolled so that less screen space is required. Added capability to install/update external repositories and seamlessly integrate with script_manager. --- tools/script_manager.lua | 1164 ++++++++++++++++++++------------------ 1 file changed, 625 insertions(+), 539 deletions(-) diff --git a/tools/script_manager.lua b/tools/script_manager.lua index 684d488b..0d49f3cd 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -1,6 +1,6 @@ --[[ This file is part of darktable, - copyright (c) 2018 Bill Ferguson + copyright (c) 2018, 2020 Bill Ferguson darktable is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -18,29 +18,42 @@ --[[ script_manager.lua - a tool for managing the darktable lua scripts - script_manager is designed to run as a standalone script so that it - may be used as a drop in luarc file in the user's $HOME/.config/darktable - ($HOME/AppData/Local/darktable on windows) directory. It may also be - required from a luarc file. + script_manager is designed to be called from the users luarc file and used to + manage the lua scripts. - On startup script_manager checks to see if there is an existing scripts directory. - If there is an existing lua scripts directory then it is read to see what scripts are present. - Scripts are sorted by "category" based on what subdirectory they are found in, thus with a lua - scripts directory that matched the current repository the categories would be contrib, examples, - offical, and tools. Each script has an Enable/Disable button to enable or disable the script. + On startup script_manager scans the lua scripts directory to see what scripts are present. + Scripts are sorted by 'category' based on what sub-directory they are in. With no + additional script repositories iinstalled, the categories are contrib, examples, official + and tools. When a category is selected the buttons show the script name and whether the + script is started or stopped. The button is a toggle, so if the script is stopped click + the button to start it and vice versa. - A link is created to the user's Downloads directory on linux, unix and MacOS. Windows users must create the - link manually using mklink.exe. Additional "un-official" scripts may be downloaded - from other sources and placed in the users Downloads directory. These scripts all fall in a downloads category. - They also each have an Enable/Disable button. + Features + + * the number of script buttons shown can be changed to any number between 5 and 20. The + default is 10 buttons. This can be changed in the configuration action. + + * additional repositories of scripts may be installed using from the install/update action. + + * installed scripts can be updated from the install/update action. This includes extra + repositories that have been installed. + + * the scripts can be disabled if desired from the install/update action. This can only + be reversed manually. To enable the "Disable Scripts" button, check the checkbox to + endable it. This is to prevent accidentally disabling the scripts. Click the + "Disable Scripts" button and the luarc file is renamed to luarc.disable. If at + a later time you want to enable the scripts again, simply rename the luarc.disabled + file to luarc and the scripts will run. ]] + local dt = require "darktable" local du = require "lib/dtutils" local df = require "lib/dtutils.file" local ds = require "lib/dtutils.string" local dtsys = require "lib/dtutils.system" +local log = require "lib/dtutils.log" local gettext = dt.gettext @@ -52,22 +65,41 @@ local function _(msgid) return gettext.dgettext("script_manager", msgid) end -collectgarbage("stop") +-- api check + +du.check_min_api_version("5.0.0", "script_manager") + -- - - - - - - - - - - - - - - - - - - - - - - - -- C O N S T A N T S -- - - - - - - - - - - - - - - - - - - - - - - - + -- path separator local PS = dt.configuration.running_os == "windows" and "\\" or "/" -- command separator local CS = dt.configuration.running_os == "windows" and "&" or ";" +local MODULE = "script_manager" + +local MIN_BUTTONS_PER_PAGE = 5 +local MAX_BUTTONS_PER_PAGE = 20 +local DEFAULT_BUTTONS_PER_PAGE = 10 + +local DEFAULT_LOG_LEVEL = log.error + local LUA_DIR = dt.configuration.config_dir .. PS .. "lua" local LUA_SCRIPT_REPO = "https://github.com/darktable-org/lua-scripts.git" -local CURR_API_VERSION = dt.configuration.api_version_string -dt.print_log("LUA_DIR is " .. LUA_DIR) +local CURR_API_STRING = dt.configuration.api_version_string + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- L O G L E V E L +-- - - - - - - - - - - - - - - - - - - - - - - - + +local old_log_level = log.log_level() + +log.log_level(DEFAULT_LOG_LEVEL) -- - - - - - - - - - - - - - - - - - - - - - - - -- N A M E S P A C E @@ -76,20 +108,47 @@ dt.print_log("LUA_DIR is " .. LUA_DIR) local script_manager = {} local sm = script_manager +sm.executables = {} +sm.executables.git = df.check_if_bin_exists("git") + +sm.module_installed = false +sm.event_registered = false + +-- set up tables to contain all the widgets and choices + +sm.widgets = {} +sm.categories = {} +sm.scripts = {} +sm.page_status = {} +sm.page_status.num_buttons = DEFAULT_BUTTONS_PER_PAGE +sm.page_status.buttons_created = 0 +sm.page_status.current_page = 0 +sm.page_status.category = "" + +-- installed script repositories +sm.installed_repositories = { + {name = "lua-scripts", directory = LUA_DIR}, +} + + +-- don't let it run until everything is in place +sm.run = false + -- - - - - - - - - - - - - - - - - - - - - - - - -- F U N C T I O N S -- - - - - - - - - - - - - - - - - - - - - - - - -local function prequire(script) - dt.print_log("Loading " .. script) - local status, lib = pcall(require, script) - if status then - dt.print_log("Loaded " .. script) - else - dt.print_error("Error loading " .. script) - dt.print_error(lib) +local function pref_read(name, pref_type) + log.msg(log.debug, "name is " .. name .. " and type is " .. pref_type) + local val = dt.preferences.read(MODULE, name, pref_type) + if not string.match(pref_type, "bool") then + log.msg(log.debug, "read value " .. tostring(val)) end - return status, lib + return val +end + +local function pref_write(name, pref_type, value) + dt.preferences.write(MODULE, name, pref_type, value) end local function update_combobox_choices(combobox, choice_table, selected) @@ -103,70 +162,84 @@ local function update_combobox_choices(combobox, choice_table, selected) combobox[j] = nil end end + if not selected then + selected = 1 + end + combobox.value = selected end -local function install_scripts() - local result = false - - if df.check_if_file_exists(LUA_DIR) then - if df.check_if_file_exists(LUA_DIR .. ".orig") then - if dt.configuration.running_os == "windows" then - os.execute("rmdir /s " .. LUA_DIR .. ".orig") - else - os.execute("rm -rf " .. LUA_DIR .. ".orig") - end - end - os.rename(LUA_DIR, LUA_DIR .. ".orig") +local function add_script_category(category) + if #sm.categories == 0 or not string.match(du.join(sm.categories, " "), ds.sanitize_lua(category)) then + table.insert(sm.categories, category) + sm.scripts[category] = {} + log.msg(log.debug, "created category " .. category) end +end - local git = df.check_if_bin_exists("git") - - if not git then - dt.print("ERROR: git not found. Install or specify the location of the git executable.") - return +local function get_script_doc(script) + local description = nil + f = io.open(LUA_DIR .. PS .. script .. ".lua") + if f then + -- slurp the file + local content = f:read("*all") + f:close() + -- assume that the second block comment is the documentation + description = string.match(content, "%-%-%[%[.-%]%].-%-%-%[%[(.-)%]%]") + else + log.msg(log.error, _("Cant read from " .. script)) end - - local git_command = git .. " clone " .. sm.lua_repository .. " " .. LUA_DIR - dt.print_log("install git command is " .. git_command) - - result = os.execute(git_command) - - if not df.check_if_file_exists(LUA_DIR .. PS .. "downloads") then - os.execute("mkdir " .. LUA_DIR .. PS .. "downloads") + if description then + return description + else + return "No documentation available" end - - return result end -local function update_scripts() - local result = false - - local git = df.check_if_bin_exists("git") - - if not git then - dt.print("ERROR: git not found. Install or specify the location of the git executable.") - return +local function activate(script) + log.msg(log.info, "activating " .. script.name) + local status, err = du.prequire(script.path) + if status then + pref_write(script.script_name, "bool", true) + log.msg(log.screen, _("Loaded ") .. script.script_name) + script.running = true + else + log.msg(log.screen, script.script_name .. _(" failed to load")) + log.msg(log.error, "Error loading " .. script.script_name) + log.msg(log.error, "Error message: " .. err) end + return status +end - local git_command = "cd " .. LUA_DIR .. " " .. CS .. " " .. git .. " pull" - dt.print_log("update git command is " .. git_command) +local function deactivate(script) + -- presently the lua api doesn't support unloading gui elements therefore + -- we just mark then inactive for the next time darktable starts - if dt.configuration.running_os == "windows" then - result = dtsys.windows_command(git_command) - else - result = os.execute(git_command) - end + -- deactivate it.... - if dt.preferences.read("script_manager", "use_lua_scripts_version", "bool") and - dt.configuration.running_os == "windows" then - use_lua_scripts_version() - end + pref_write(script.script_name, "bool", false) + script.running = false + log.msg(log.info, "setting " .. script.script_name .. " to not start") + log.msg(log.screen, script.name .. _(" will not start when darktable is restarted")) +end - return result +local function add_script_name(name, path, category) + log.msg(log.debug, "category is " .. category) + log.msg(log.debug, "name is " .. name) + local script = { + name = name, + path = category .. "/" .. path .. name, + running = false, + doc = get_script_doc(category .. "/" .. path .. name), + script_name = category .. "/" .. name + } + table.insert(sm.scripts[category], script) + if pref_read(script.script_name, "bool") then + activate(script) + end end -local function add_script_data(script_file) +local function process_script_data(script_file) -- the script file supplied is category/filename.filetype -- the following pattern splits the string into category, path, name, fileename, and filetype @@ -185,274 +258,382 @@ local function add_script_data(script_file) pattern = "(.-)\\(.-)(([^\\]-)%.?([^%.\\]*))$" end - dt.print_log("processing " .. script_file) + log.msg(log.info, "processing " .. script_file) -- add the script data local category,path,name,filename,filetype = string.match(script_file, pattern) - dt.print_log("category is " .. category) - dt.print_log("name is " .. name) + log.msg(log.debug, "category is " .. category) + log.msg(log.debug, "name is " .. name) + + add_script_category(category) - if #sm.script_categories == 0 or not string.match(du.join(sm.script_categories, " "), category) then - sm.script_categories[#sm.script_categories + 1] = category - sm.script_names[category] = {} - end if name then - dt.print_log("category is " .. category) - dt.print_log("name is " .. name) - if not string.match(du.join(sm.script_names[category], " "), name) then - sm.script_names[category][#sm.script_names[category] + 1] = name - sm.script_paths[category .. "/" .. name] = category .. "/" .. path .. name - if category == "downloads" then - sm.have_downloads = true - end - end + add_script_name(name, path, category) end end -local function scan_scripts() - local find_cmd = "find -L " .. LUA_DIR .. " -name \\*.lua -print | sort" +local function scan_scripts(script_dir) + local script_count = 0 + local find_cmd = "find -L " .. script_dir .. " -name \\*.lua -print | sort" if dt.configuration.running_os == "windows" then - find_cmd = "dir /b/s " .. LUA_DIR .. "\\*.lua | sort" + find_cmd = "dir /b/s " .. script_dir .. "\\*.lua | sort" end + log.msg(log.debug, _("find command is ") .. find_cmd) -- scan the scripts local output = io.popen(find_cmd) for line in output:lines() do - local l = string.gsub(line, ds.sanitize_lua(LUA_DIR) .. PS, "") -- strip the lua dir off - local script_file = l:sub(1,-5) - if not string.match(script_file, "script_manager") then -- let's not include ourself - if not string.match(script_file, "plugins") then -- skip plugins - if not string.match(script_file, "lib" .. PS) then -- let's not try and run libraries - if not string.match(script_file, "include_all") then -- skip include_all.lua - if not string.match(script_file, "yield") then -- special case, because everything needs this - add_script_data(script_file) - else - -- prequire(script_file) -- load yield.lua - end + local l = string.gsub(line, ds.sanitize_lua(LUA_DIR) .. PS, "") -- strip the lua dir off + local script_file = l:sub(1,-5) -- strip off .lua\n + if not string.match(script_file, "script_manager") then -- let's not include ourself + if not string.match(script_file, "plugins") then -- skip plugins + if not string.match(script_file, "lib" .. PS) then -- let's not try and run libraries + if not string.match(script_file, "%.git") then -- don't match files in the .git directory + process_script_data(script_file) + script_count = script_count + 1 end end end end end - -- work around because we can't dynamically add a new stack child. We create an empty child that will be - -- populated with downloads as they occur. If there are already downloads then this is just ignored - - add_script_data("downloads" .. PS) + return script_count end --- get the script documentation, with some assumptions -local function get_script_doc(script) - local description = nil - f = io.open(LUA_DIR .. PS .. script .. ".lua") - if f then - -- slurp the file - local content = f:read("*all") - f:close() - -- assume that the second block comment is the documentation - description = string.match(content, "%-%-%[%[.-%]%].-%-%-%[%[(.-)%]%]") - else - dt.print_error("Cant read from " .. script) - end - if description then - return description - else - return "No documentation available" +local function update_scripts() + local result = false + + local git = sm.executables.git + + if not git then + dt.print("ERROR: git not found. Install or specify the location of the git executable.") + return end -end -local function activate(script, scriptname) - dt.print_log("activating " .. scriptname) - local status, err = prequire(sm.script_paths[script]) - if status then - dt.preferences.write("script_manager", script, "bool", true) - dt.print("Loaded " .. scriptname) + local git_command = "cd " .. LUA_DIR .. " " .. CS .. " " .. git .. " pull" + log.msg(log.debug, "update git command is " .. git_command) + + if dt.configuration.running_os == "windows" then + result = dtsys.windows_command(git_command) else - dt.print(scriptname .. " failed to load") - dt.print_error("Error loading " .. scriptname) - dt.print_error("Error message: " .. err) + result = os.execute(git_command) end - return status -end -local function deactivate(script, scriptname) - -- presently the lua api doesn't support unloading gui elements therefore - -- we just mark then inactive for the next time darktable starts + if result == 0 then + dt.print(_("lua scripts successfully updated")) + end - -- deactivate it.... + return result +end - dt.preferences.write("script_manager", script, "bool", false) - dt.print_log("setting " .. scriptname .. " to not start") - dt.print(scriptname .. " will not be active when darktable is restarted") +local function update_script_update_choices() + local installs = {} + local pref_string = "" + for i, repo in ipairs(sm.installed_repositories) do + table.insert(installs, repo.name) + pref_string = pref_string .. i .. "," .. repo.name .. "," .. repo.directory .. "," + end + update_combobox_choices(sm.widgets.update_script_choices, installs, 1) + log.msg(log.debug, "repo pref string is " .. pref_string) + pref_write("installed_repos", "string", pref_string) end -local function create_enable_disable_button(btext, sname, req) - local button = dt.new_widget("button") - { - label = btext .. sname, - tooltip = get_script_doc(req), - clicked_callback = function (self) - -- split the label into action and target - local action, target = string.match(self.label, "(.+) (.+)") - -- load the script if it's not loaded - dt.print_log("Looking for target " .. target) - local scat = sm.category_selector.value - -- check, and fix, the filename for a - since it is a lua magic character in string match - dt.print_log("checking category " .. scat .. " for target " .. target) - local starget = du.join({scat, target}, "/") - dt.print_log("starget to activate is " .. starget) - dt.print_log("target to activate is " .. target) - if action == "Enable" then - local status = activate(starget, target) - if status then - self.label = "Disable " .. target +local function scan_repositories() + local script_count = 0 + local find_cmd = "find -L " .. LUA_DIR .. " -name \\*.git -print | sort" + if dt.configuration.running_os == "windows" then + find_cmd = "dir /b/s /a:d " .. LUA_DIR .. PS .. "*.git | sort" + end + log.msg(log.debug, _("find command is ") .. find_cmd) + local output = io.popen(find_cmd) + for line in output:lines() do + local l = string.gsub(line, ds.sanitize_lua(LUA_DIR) .. PS, "") -- strip the lua dir off + local category = string.match(l, "(.-)" .. PS) -- get everything to teh first / + if category then -- if we have a category (.git doesn't) + log.msg(log.debug, "found category " .. category) + if not string.match(category, "plugins") and not string.match(category, "%.git") then -- skip plugins + if #sm.installed_repositories == 1 then + log.msg(log.debug, "only 1 repo, adding " .. category) + table.insert(sm.installed_repositories, {name = category, directory = LUA_DIR .. PS .. category}) + else + log.msg(log.debug, "more than 1 repo, we have to search the repos to make sure it's not there") + local found = nil + for _, repo in ipairs(sm.installed_repositories) do + if string.match(repo.name, ds.sanitize_lua(category)) then + log.msg(log.debug, "matched " .. repo.name) + found = true + break + end + end + if not found then + table.insert(sm.installed_repositories, {name = category, directory = LUA_DIR .. PS .. category}) + end end - else - deactivate(starget, target) - self.label = "Enable " .. target end end - } - if CURR_API_VERSION >= "6.0.1" then - button.ellipsize = "middle" end - return button + update_script_update_choices() end -local function load_script_stack() - -- load the scripts - table.sort(sm.script_categories) - for _,cat in ipairs(sm.script_categories) do - local tmp = {} - table.sort(sm.script_names[cat]) - if not sm.script_widgets[cat] then - for _,sname in ipairs(sm.script_names[cat]) do - local req = du.join({cat, sname}, "/") - local btext = "Enable " - if dt.preferences.read("script_manager", req, "bool") then - local status, err = prequire(sm.script_paths[req]) - if status then - btext = "Disable " - else - dt.print_error("Error loading " .. sname) - dt.print_error("Error message: " .. err) - end - else - dt.preferences.write("script_manager", req, "bool", false) - end - tmp[#tmp + 1] = create_enable_disable_button(btext, sname, req) - end +local function install_scripts() + local url = sm.widgets.script_url.text + local category = sm.widgets.new_category.text + + if string.match(du.join(sm.categories, " "), ds.sanitize_lua(category)) then + log.msg(log.screen, _("category ") .. category .. _(" is already in use. Please specify a different category name.")) + log.msg(log.error, "category " .. category .. " already exists, returning...") + return + end + + local result = false + + local git = sm.executables.git - sm.script_widgets[cat] = dt.new_widget("box") - { - orientation = "vertical", - table.unpack(tmp), - } - elseif #sm.script_widgets[cat] ~= #sm.script_names[cat] then - for index,sname in ipairs(sm.script_names[cat]) do - local req = du.join({cat, sname}, "/") - dt.print_error("script is " .. sname .. " and index is " .. index) - if sm.script_widgets[cat][index] then - sm.script_widgets[cat][index] = nil + if not git then + dt.print("ERROR: git not found. Install or specify the location of the git executable.") + return + end + + local git_command = "cd " .. LUA_DIR .. " " .. CS .. " " .. git .. " clone " .. url .. " " .. category + log.msg(log.debug, "update git command is " .. git_command) + + if dt.configuration.running_os == "windows" then + result = dtsys.windows_command(git_command) + else + result = dtsys.external_command(git_command) + end + + log.msg(log.info, "result from import is " .. result) + + if result == 0 then + local count = scan_scripts(LUA_DIR .. PS .. category) + if count > 0 then + update_combobox_choices(sm.widgets.category_selector, sm.categories, sm.widgets.category_selector.selected) + dt.print(_("scripts successfully installed into category ") .. category) + table.insert(sm.installed_repositories, {name = category, directory = LUA_DIR .. PS .. category}) + update_script_update_choices() + for i = 1, #sm.widgets.category_selector do + if string.match(sm.widgets.category_selector[i], ds.sanitize_lua(category)) then + log.msg(log.debug, "setting category selector to " .. i) + sm.widgets.category_selector.selected = i + break end - sm.script_widgets[cat][index] = create_enable_disable_button("Enable ", sname, req) + i = i + 1 end + log.msg(log.debug, "clearing text fields") + sm.widgets.script_url.text = "" + sm.widgets.new_category.text = "" + sm.widgets.main_menu.selected = 3 + else + dt.print(_("No scripts found to install")) + log.msg(log.error, "scan_scripts returned " .. count .. " scripts found. Not adding to category_selector") end + else + dt.print(_("failed to download scripts")) end - if not sm.script_stack then - sm.script_stack = dt.new_widget("stack"){} - for i,cat in ipairs(sm.script_categories) do - sm.script_stack[i] = sm.script_widgets[cat] - end - sm.script_stack.active = 1 - end + + return result end -local function update_stack_choices(combobox, choice_table) - sm.have_downloads = true - local items = #combobox - local choices = #choice_table - if #sm.script_widgets["downloads"] == 0 then - choices = choices - 1 - sm.have_downloads = false - end - cnt = 1 - for i, name in ipairs(choice_table) do - if (name == "downloads" and sm.have_downloads) or name ~= "downloads" then - combobox[cnt] = name - cnt = cnt + 1 - end - end - if choices < items then - for j = items, choices + 1, -1 do - combobox[j] = nil +local function clear_button(number) + local button = sm.widgets.buttons[number] + button.label = "" + button.sensitive = false +end + +local function find_script(category, name) + for _, script in ipairs(sm.scripts[category]) do + if string.match(script.name, "^" .. ds.sanitize_lua(name) .. "$") then + return script end end - combobox.value = 1 + return nil end -local function build_scripts_block() - -- build the whole script block - scan_scripts() - - -- set up the stack for the choices - load_script_stack() - - if not sm.category_selector then - -- set up the combobox for the categories - - sm.category_selector = dt.new_widget("combobox"){ - label = "Category", - tooltip = "Select the script category", - value = 1, "placeholder", - changed_callback = function(self) - local cnt = 1 - for i,cat in ipairs(sm.script_categories) do - if cat == self.value then - sm.script_stack.active = i +local function populate_buttons(category, first, last) + log.msg(log.debug, "category is " .. category .. " and first is " .. first .. " and last is " .. last) + local button_num = 1 + for i = first, last do + script = sm.scripts[category][i] + button = sm.widgets.buttons[button_num] + if script.running then + button.label = script.name .. " started" + else + button.label = script.name .. " stopped" + end + if CURR_API_STRING >= "6.0.1" then + button.ellipsize = "middle" + end + button.sensitive = true + button.tooltip = script.doc + button.clicked_callback = function (this) + local script_name, state = string.match(this.label, "(.-) (.+)") + local script = find_script(sm.widgets.category_selector.value, script_name) + if script then + log.msg(log.debug, "found script " .. script.name .. " with path " .. script.path) + if string.match(state, "started") then + log.msg(log.debug, "deactivating " .. script.name .. " on " .. script.path .. " for button " .. this.label) + deactivate(script) + this.label = script.name .. " stopped" + else + log.msg(log.debug, "activating " .. script.name .. " on " .. script.path .. " for button " .. this.label) + local result = activate(script) + if result then + this.label = script.name .. " started" end end + else + log.msg(log.error, "script " .. script_name .. " not found") end - } + end + button_num = button_num + 1 end + if button_num <= sm.page_status.num_buttons then + for i = button_num, sm.page_status.num_buttons do + clear_button(i) + end + end +end - update_stack_choices(sm.category_selector, sm.script_categories) +local function paginate(direction) + local category = sm.page_status.category + log.msg(log.debug, "category is " .. category) + local num_scripts = #sm.scripts[category] + log.msg(log.debug, "num_scripts is " .. num_scripts) + local max_pages = math.ceil(num_scripts / sm.page_status.num_buttons) + local cur_page = sm.page_status.current_page + log.msg(log.debug, "max pages is " .. max_pages) + + local buttons_needed = nil + local first = nil + local last = nil + + if direction == 0 then + cur_page = cur_page - 1 + if cur_page < 1 then + cur_page = 1 + end + elseif direction == 1 then + cur_page = cur_page + 1 + if cur_page > max_pages then + cur_page = max_pages + end + else + log.msg(log.debug, "took path 2") + cur_page = 1 + end + log.msg(log.debug, "cur_page is " .. cur_page .. " and max_pages is " .. max_pages) + if cur_page == max_pages and cur_page == 1 then + sm.widgets.page_forward.sensitive = false + sm.widgets.page_back.sensitive = false + elseif cur_page == max_pages then + sm.widgets.page_forward.sensitive = false + sm.widgets.page_back.sensitive = true + elseif cur_page == 1 then + sm.widgets.page_forward.sensitive = true + sm.widgets.page_back.sensitive = false + else + sm.widgets.page_forward.sensitive = true + sm.widgets.page_back.sensitive = true + end - if not sm.scripts then - sm.scripts = dt.new_widget("box"){ - orientation = "vertical", - dt.new_widget("label"){ label = "Scripts" }, - sm.category_selector, - sm.script_stack, - } + sm.page_status.current_page = cur_page + first = (cur_page * sm.page_status.num_buttons) - (sm.page_status.num_buttons - 1) + if first + sm.page_status.num_buttons > num_scripts then + last = num_scripts + else + last = first + sm.page_status.num_buttons - 1 end -end + sm.widgets.page_status.label = _("Page ") .. cur_page .. _(" of ") .. max_pages -local function insert_scripts_block() - table.insert(sm.main_menu_choices, "Enable/Disable Scripts") - update_combobox_choices(sm.main_menu, sm.main_menu_choices, 1) - sm.main_stack[#sm.main_stack + 1] = sm.scripts + populate_buttons(category, first, last) end -local function use_lua_scripts_version() - if dt.configuration.running_os == "windows" then - -- copy tools\script_manger.lua to luarc - df.file_copy(LUA_DIR .. PS .. "tools\\script_manager.lua", dt.configuration.config_dir .. PS .. "luarc") +local function change_category(category) + if not category then + log.msg(log.debug "setting category to selector value " .. sm.widgets.category_selector.value) + sm.page_status.category = sm.widgets.category_selector.value else - -- create a symbolic link from luarc to tools/script_manager.lua - if df.check_if_file_exists(dt.configuration.config_dir .. "/luarc") then - os.remove(dt.configuration.config_dir .. "/luarc") - end - os.execute("ln -s " .. LUA_DIR .. "/tools/script_manager.lua " .. dt.configuration.config_dir .. "/luarc") + log.msg(log.debug, "setting catgory to argument " .. category) + sm.page_status.category = category end + + paginate(2) end -local function link_downloads_directory() - if not df.check_if_file_exists("$HOME/Downloads") then - os.execute("mkdir $HOME/Downloads") +local function change_num_buttons() + cur_buttons = sm.page_status.num_buttons + new_buttons = sm.widgets.num_buttons.value + pref_write("num_buttons", "integer", new_buttons) + if new_buttons < cur_buttons then + for i = 1, cur_buttons - new_buttons do + table.remove(sm.widgets.scripts) + end + log.msg(log.debug, "finished removing widgets, now there are " .. #sm.widgets.buttons) + elseif new_buttons > cur_buttons then + if new_buttons > sm.page_status.buttons_created then + for i = sm.page_status.buttons_created + 1, new_buttons do + table.insert(sm.widgets.buttons, dt.new_widget("button"){}) + sm.page_status.buttons_created = sm.page_status.buttons_created + 1 + end + end + log.msg(log.debug, "cur_buttons is " .. cur_buttons .. " and new_buttons is " .. new_buttons) + log.msg(log.debug, #sm.widgets.buttons .. " buttons are available") + for i = cur_buttons + 1, new_buttons do + log.msg(log.debug, "inserting button " .. i .. " into scripts widget") + table.insert(sm.widgets.scripts, sm.widgets.buttons[i]) + end + log.msg(log.debug, "finished adding widgets, now there are " .. #sm.widgets.buttons) + else -- no change + log.msg(log.debug, "no change, just returning") + return end - if df.check_if_file_exists(LUA_DIR .. "/downloads") then - os.remove(LUA_DIR .. "/downloads") + sm.page_status.num_buttons = new_buttons + log.msg(log.debug, "num_buttons set to " .. sm.page_status.num_buttons) + paginate(2) -- force the buttons to repopulate + sm.widgets.main_menu.selected = 3 -- jump back to start/stop scripts +end + +local function load_preferences() + -- load the prefs and update settings + -- update_script_choices + local pref_string = pref_read("installed_repos", "string") + local entries = du.split(pref_string, ",") + while #entries > 2 do + local num = table.remove(entries, 1) + local name = table.remove(entries, 1) + local directory = table.remove(entries, 1) + if not string.match(sm.installed_repositories[1].name, "^" .. ds.sanitize_lua(name) .. "$") then + table.insert(sm.installed_repositories, {name = name, directory = directory}) + end end - os.execute("ln -s " .. "$HOME/Downloads " .. LUA_DIR .. "/downloads") + update_script_update_choices() + log.msg(log.debug, "updated installed scripts") + -- category selector + local val = pref_read("category_selector", "integer") + if val == 0 then + val = 1 + end + sm.widgets.category_selector.selected = val + sm.page_status.category = sm.widgets.category_selector.value + log.msg(log.debug, "updated category selector and set it to " .. sm.widgets.category_selector.value) + -- num_buttons + local val = pref_read("num_buttons", "integer") + if val == 0 then + val = DEFAULT_BUTTONS_PER_PAGE + end + sm.widgets.num_buttons.value = val + log.msg(log.debug, "set page buttons to " .. val) + change_num_buttons() + log.msg(log.debug, "paginated") + -- main menu + local val = pref_read("main_menu_action", "integer") + log.msg(log.debug, "read " .. val .. " for main menu") + if val == 0 then + val = 3 + end + sm.widgets.main_menu.selected = val + log.msg(log.debug, "set main menu to val " .. val .. " which is " .. sm.widgets.main_menu.value) + + log.msg(log.debug, "set main menu to " .. sm.widgets.main_menu.value) end local function install_module() @@ -462,312 +643,232 @@ local function install_module() "script manager", -- Visible name true, -- expandable false, -- resetable - {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_LEFT_CENTER", 0}}, -- containers - dt.new_widget("box") -- widget - { - orientation = "vertical", - sm.main_box, - }, + {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_LEFT_BOTTOM", 600}}, -- containers + sm.widgets.main_box, nil,-- view_enter nil -- view_leave ) sm.module_installed = true end + sm.run = true + log.msg(log.debug, "set run to true, loading preferences") + load_preferences() + scan_repositories() end -- - - - - - - - - - - - - - - - - - - - - - - - -- M A I N P R O G R A M -- - - - - - - - - - - - - - - - - - - - - - - - +scan_scripts(LUA_DIR) +log.msg(log.debug, "finished processing scripts") --- api check - -du.check_min_api_version("5.0.0") - --- set up tables to contain all the widgets and choices - -sm.script_widgets = {} -sm.script_categories = {} -sm.script_names = {} -sm.script_paths = {} -sm.main_menu_choices = {} -sm.main_stack_items = {} -sm.event_registered = false -sm.module_installed = false - --- see if we've run this before - -sm.initialized = dt.preferences.read("script_manager", "initialized", "bool") - -if not sm.initialized then - -- write out preferences - dt.preferences.write("script_manager", "lua_repository", "string", LUA_SCRIPT_REPO) - dt.preferences.write("script_manager", "use_distro_version", "bool", false) - dt.preferences.write("script_manager", "link_downloads_directory", "bool", false) - dt.preferences.write("script_manager", "initialized", "bool", true) -end - -sm.have_scripts = df.check_if_file_exists(LUA_DIR) - -sm.git_managed = df.check_if_file_exists(LUA_DIR .. PS .. ".git") +-- - - - - - - - - - - - - - - - - - - - - - - - +-- U S E R I N T E R F A C E +-- - - - - - - - - - - - - - - - - - - - - - - - -if sm.have_scripts then - dt.print_log("found lua scripts directory") -else - dt.print_log("lua scripts directory not found") -end +sm.widgets = {} -if sm.git_managed then - dt.print_log("scripts managed by git") -else - dt.print_log("scripts not managed") -end - -local git = df.check_if_bin_exists("git") +-- update the scripts -if git then - dt.print_log("git found at " .. git) - sm.need_git = false -else - dt.print_log("git not found") - sm.need_git = true -end +sm.widgets.update_script_choices = dt.new_widget("combobox"){ + label = _("scripts to update"), + tooltip = _("select the scripts installation to update"), + selected = 1, + changed_callback = function(this) + pref_write("update_script_choices", "integer", this.selected) + end, + "placeholder", +} -sm.repository = dt.new_widget("entry") -{ - text = dt.preferences.read("script_manager", "lua_repository", "string"), - editable = true, +sm.widgets.update = dt.new_widget("button"){ + label = _("update scripts"), + tooltip = _("update the lua scripts from the repository"), + clicked_callback = function(this) + update_scripts() + end } -sm.need_install = false +-- add additional scripts -local install_update_text = _("install") -if sm.have_scripts and sm.git_managed then - install_update_text = _("update") -else - sm.need_install = true -end +sm.widgets.script_url = dt.new_widget("entry"){ + text = "", + placeholder = "https://", + tooltip = _("enter the URL of the git repository containing the scripts you wish to add") +} -sm.install_update_button = dt.new_widget("button"){ - label = install_update_text .. _(" scripts"), - clicked_callback = function(self) - sm.lua_repository = sm.repository.text - dt.preferences.write("script_manager", "lua_repository", "string", sm.repository.text) - if sm.need_install then - local result = install_scripts() - if result then - build_scripts_block() - insert_scripts_block() - sm.have_scripts = true - sm.git_managed = true - sm.need_install = false - self.label = _("update scripts") - dt.print(_("installed scripts from " .. sm.repository.text)) - else - dt.print(_("Error installing scripts from " .. sm.repository.text)) - end - else - local result = update_scripts() - if result then - --build_scripts_block() - dt.print(_("updated scripts from " .. sm.repository.text)) - else - dt.print(_("Error updating scripts from " .. sm.repository.text)) - end - end - end +sm.widgets.new_category = dt.new_widget("entry"){ + text = "", + placeholder = _("name of new category"), + tooltip = _("enter a category name for the additional scripts") } -if not sm.need_install then - sm.reinstall_button = dt.new_widget("button"){ - label = "reinstall scripts", - clicked_callback = function(self) - sm.lua_repository = sm.repository.text - dt.preferences.write("script_manager", "lua_repository", "string", sm.repository.text) - local result = install_scripts() - if result then - build_scripts_block() - insert_scripts_block() - sm.have_scripts = true - sm.git_managed = true - sm.need_install = false - sm.install_update_button.label = "update scripts" - dt.print(_("reinstalled scripts from " .. sm.repository.text)) - dt.print_log(_("scripts reinstalled")) - else - dt.print(_("ERROR: script reinstallation failed")) - dt.print_error(_("script reinstall failed")) - end +sm.widgets.add_scripts = dt.new_widget("box"){ + orientation = vertical, + dt.new_widget("label"){label = _("URL to download additional scripts from")}, + sm.widgets.script_url, + dt.new_widget("label"){label = _("new category to place scripts in")}, + sm.widgets.new_category, + dt.new_widget("button"){ + label = _("install additional scripts"), + clicked_callback = function(this) + install_scripts() end } - - sm.install_update_widgets = { - sm.install_update_button, - sm.reinstall_button, - } -else - sm.install_update_widgets = { - sm.install_update_button, - } -end - -sm.install_update_box = dt.new_widget("box"){ - orientation = "vertical", - dt.new_widget("label"){ label = "Install/Update scripts" }, - table.unpack(sm.install_update_widgets), } -table.insert(sm.main_menu_choices, "Install/Update Scripts") -table.insert(sm.main_stack_items, sm.install_update_box) - --- configuration items - -sm.repository_update = dt.new_widget("button"){ - label = "update", - clicked_callback = function() - dt.preferences.write("script_manager", "lua_repository", "string", sm.repository.text) - sm.install_update_button.label = "install" - sm.install_update_button.sensitive = true - sm.reinstall_button.sensitive = false - sm.need_install = true - end +sm.widgets.allow_disable = dt.new_widget("check_button"){ + label = _('Enable "Dsiable Scripts" button'), + value = false, + clicked_callback = function(this) + if this.value == true then + sm.widgets.disable_scripts.sensitive = true + end + end, } -sm.repository_reset = dt.new_widget("button"){ - label = "reset", - clicked_callback = function() - sm.repository.text = LUA_SCRIPT_REPO - dt.preferences.write("script_manager", "lua_repository", "string", LUA_SCRIPT_REPO) - sm.install_update_button.label = "install" - sm.install_update_button.sensitive = true - sm.reinstall_button.sensitive = false - sm.need_install = true +sm.widgets.disable_scripts = dt.new_widget("button"){ + label = _("Disable Scripts"), + sensitive = false, + clicked_callback = function(this) + local LUARC = dt.configuration.config_dir .. PS .. "luarc" + df.file_move(LUARC, LUARC .. ".disabled") + log.msg(log.info, "lua scripts disabled") + dt.print(_("lua scripts will not run the next time darktable is started")) end } -sm.update_reset = dt.new_widget("box"){ - orientation = "horizontal", - sm.repository_update, - sm.repository_reset, +sm.widgets.install_update = dt.new_widget("box"){ + orientation = "vertical", + dt.new_widget("section_label"){label = _("update scripts")}, + sm.widgets.update_script_choices, + sm.widgets.update, + dt.new_widget("section_label"){label = _("add more scripts")}, + sm.widgets.add_scripts, + dt.new_widget("section_label"){label = _("disable scripts")}, + sm.widgets.allow_disable, + sm.widgets.disable_scripts } --- replace standalone version of script_manager with distributed version, i.e. tools/script_manager.lua - -- link on linux/MacOS, copy on windows - -- this option won't be active until the repository version of this script is accepted - -sm.use_lua_scripts_version = dt.new_widget("check_button"){ - label = "Use lua scripts distributed version", - tooltip = "Use the standalone version (false) or the distributed version (true)", - value = dt.preferences.read("script_manager", "use_distro_version", "bool"), - clicked_callback = function(self) - if dt.preferences.read("script_manager", "use_distro_version", "bool") == self.value then - -- do nothing - else - sm.apply_configuration.sensitive = true +-- manage the scripts + +sm.widgets.category_selector = dt.new_widget("combobox"){ + label = _("category"), + tooltip = _( "select the script category"), + selected = 1, + changed_callback = function(self) + if sm.run then + pref_write("category_selector", "integer", self.selected) + change_category(self.value) end - end + end, + table.unpack(sm.categories), } --- link downloads to $HOME/downloads on linux and MacOS +sm.widgets.buttons ={} +for i =1, DEFAULT_BUTTONS_PER_PAGE do + table.insert(sm.widgets.buttons, dt.new_widget("button"){}) + sm.page_status.buttons_create = sm.page_status.buttons_created + 1 +end -sm.link_downloads_directory = dt.new_widget("check_button"){ - label = "Link lua/downloads to $HOME/Downloads", - tooltip = "Linking the directories enables dropping a script in $HOME/downloads\nand having it recognized the next time darktable starts", - value = dt.preferences.read("script_manager", "link_downloads_directory", "bool"), - clicked_callback = function(self) - if dt.preferences.read("script_manager", "link_downloads_directory", "bool") == self.value then - -- do nothing - else - sm.apply_configuration.sensitive = true +local page_back = "<" +local page_forward = ">" +if CURR_API_STRING < "6.1.0" then + page_back = " < " + page_forward = " > " +end + +sm.widgets.page_status = dt.new_widget("label"){label = _("Page:")} +sm.widgets.page_back = dt.new_widget("button"){ + label = page_back, + clicked_callback = function(this) + if sm.run then + paginate(0) end end } -sm.apply_configuration = dt.new_widget("button"){ - label = "Apply", - sensitive = false, - clicked_callback = function(self) - dt.preferences.write("script_manager", "use_distro_version", "bool", sm.use_lua_scripts_version.value) - if sm.use_lua_scripts_version.value then - use_lua_scripts_version() - end - if dt.configuration.running_os ~= "windows" then - dt.preferences.write("script_manager", "link_downloads_directory", "bool", sm.link_downloads_directory.value) - if sm.link_downloads_directory.value then - link_downloads_directory() - end +sm.widgets.page_forward = dt.new_widget("button"){ + label = page_forward, + clicked_callback = function(this) + if sm.run then + paginate(1) end end } --- get git location on windows - -sm.git_location = df.executable_path_widget({"git"}) +sm.widgets.page_control = dt.new_widget("box"){ + orientation = "horizontal", + sm.widgets.page_back, + sm.widgets.page_status, + sm.widgets.page_forward, +} -sm.configuration_widgets = { - sm.repository, - sm.update_reset, - dt.new_widget("separator"){}, - dt.new_widget("separator"){}, +sm.widgets.scripts = dt.new_widget("box"){ + orientation = vertical, + dt.new_widget("label"){label = _("Scripts")}, + sm.widgets.category_selector, + sm.widgets.page_control, + table.unpack(sm.widgets.buttons) } -if dt.configuration.running_os == "windows" or sm.need_git then - sm.configuration_widgets[#sm.configuration_widgets + 1] = sm.git_location -end +-- configure options + +sm.widgets.num_buttons = dt.new_widget("slider"){ + label = _("scripts per page"), + tooltip = _("select number of start/stop buttons to display"), + soft_min = MIN_BUTTONS_PER_PAGE, + hard_min = MIN_BUTTONS_PER_PAGE, + soft_max = MAX_BUTTONS_PER_PAGE, + hard_max = MAX_BUTTONS_PER_PAGE, + step = 1, + digits = 0, + value = 10 +} -if dt.configuration.running_os ~= "windows" then - sm.configuration_widgets[#sm.configuration_widgets + 1] = sm.use_lua_scripts_version - sm.configuration_widgets[#sm.configuration_widgets + 1] = sm.link_downloads_directory -end -sm.configuration_widgets[#sm.configuration_widgets + 1] = sm.apply_configuration +sm.widgets.change_buttons = dt.new_widget("button"){ + label = _("change number of buttons"), + clicked_callback = function(this) + change_num_buttons() + end +} -sm.config_box = dt.new_widget("box"){ +sm.widgets.configure = dt.new_widget("box"){ orientation = "vertical", - dt.new_widget("label") { label = "Configuration" }, - table.unpack(sm.configuration_widgets), + dt.new_widget("label"){label = _("Configuration")}, + sm.widgets.num_buttons, + sm.widgets.change_buttons, } +-- stack for the options -table.insert(sm.main_menu_choices, "Configure") -table.insert(sm.main_stack_items, sm.config_box) - --- set up the outside stack for config, install/update, and download - - -- make a stack for the choices - -sm.main_stack = dt.new_widget("stack"){ - table.unpack(sm.main_stack_items), +sm.widgets.main_stack = dt.new_widget("stack"){ + sm.widgets.install_update, + sm.widgets.configure, + sm.widgets.scripts, } -if CURR_API_VERSION >= "6.0.1" then - sm.main_stack.h_size_fixed = false - sm.main_stack.v_size_fixed = false +if CURR_API_STRING >= "6.0.1" then + sm.widgets.main_stack.h_size_fixed = false + sm.widgets.main_stack.v_size_fixed = false end +-- main menu - -- make a combobox for the selector - -sm.main_menu = dt.new_widget("combobox"){ - label = "Action", - tooltip = "Select the action you want to perform", - value = 1, "No actions available", +sm.widgets.main_menu = dt.new_widget("combobox"){ + label = _("action"), changed_callback = function(self) - for pos,str in ipairs(sm.main_menu_choices) do - if self.value == str then - sm.main_stack.active = pos - dt.preferences.write("script_manager", "sm_main_menu_value", "integer", pos) - end - end - end + sm.widgets.main_stack.active = self.selected + pref_write("main_menu_action", "integer", self.selected) + log.msg(log.debug, "saved " .. self.selected .. " for main menu") + end, + _("install/update scripts"), _("configure"), _("start/stop scripts") } -if #sm.main_menu_choices > 0 then - update_combobox_choices(sm.main_menu, sm.main_menu_choices, 1) -end +-- widget for module -sm.main_box = dt.new_widget("box"){ - orientation = "vertical", - sm.main_menu, - sm.main_stack, +sm.widgets.main_box = dt.new_widget("box"){ + sm.widgets.main_menu, + sm.widgets.main_stack } @@ -791,18 +892,3 @@ else end end --- set up the scripts block if we have them otherwise we'll wait until we download them - -if sm.have_scripts then - - -- scan for scripts and populate the categories - build_scripts_block() - - -- add the widgets to the lib - insert_scripts_block() - - sm.main_menu.selected = 3 - -end - -collectgarbage("restart") From 9af60063d8b16f9bf7906a634e9b7d6d225e58e7 Mon Sep 17 00:00:00 2001 From: wpferguson Date: Wed, 23 Dec 2020 22:52:46 -0500 Subject: [PATCH 122/445] [dtutils.log] changed the amount of trace information based on log level. script, caller, line number, msg were printed for all log levels, but changed to return less info except in log.debug log.error, and log.critical messages. All messages print the script name except for log.screen. --- lib/dtutils/log.lua | 38 ++++++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/lib/dtutils/log.lua b/lib/dtutils/log.lua index a90fc7c0..22a4b443 100644 --- a/lib/dtutils/log.lua +++ b/lib/dtutils/log.lua @@ -51,54 +51,63 @@ local dt_print_error = dt.print_error local dt_print_log = dt.print_log local dt_print = dt.print + -- set the default log levels dtutils_log.debug = { - label = "DEBUG:", + label = "DEBUG: ", enabled = false, engine = dt_print_log, + caller_info = 3, level = 1, } dtutils_log.info = { - label = "INFO:", + label = "INFO: ", enable = false, engine = dt_print_log, + caller_info = 1, level = 2, } dtutils_log.warn = { - label = "WARN:", + label = "WARN: ", enabled = false, engine = dt_print_log, + caller_info = 2, level = 3, } dtutils_log.error = { - label = "ERROR:", + label = "ERROR: ", enabled = true, - engine = dt_print_error, + engine = dt_print_log, + caller_info = 3, level = 4, } dtutils_log.success = { - label = "SUCCESS:", + label = "SUCCESS: ", enabled = true, engine = dt_print_log, + caller_info = 2, level = 5, } dtutils_log.screen = { label = "", enabled = true, engine = dt_print, + caller_info = 0, level = 9, } dtutils_log.always = { label = "", enabled = true, engine = dt_print_log, + caller_info = 3, level = 9, } dtutils_log.critical = { - label = "CRITICAL:", + label = "CRITICAL: ", enabled = true, engine = print, + caller_info = 3, level = 9, } @@ -120,7 +129,7 @@ result = log.caller(level) Copyright = [[]], } -function dtutils_log.caller(level) +function dtutils_log.caller(level, info) local name = debug.getinfo(level).name local lineno = nil local source = nil @@ -131,7 +140,16 @@ function dtutils_log.caller(level) -- we just need the filename, so grab it from the string -- Thanks, Tobias Jakobs :-) source = string.match(source, "@.-([^\\/]-%.?[^%.\\/]*)$") - return name .. ": " .. source .. ": " .. lineno .. ":" + + if info == 0 then + return "" + elseif info == 1 then + return source .. ": " + elseif info == 2 then + return source .. ": " .. name .. ": " + else + return source .. ": " .. name .. ": " .. lineno .. ":" + end else return "callback:" end @@ -182,7 +200,7 @@ function dtutils_log.msg(level, ...) end local log_msg = level.label if level.engine ~= dt_screen and call_level ~= 0 then - log_msg = log_msg .. dtutils_log.caller(call_level) .. " " + log_msg = log_msg .. dtutils_log.caller(call_level, level.caller_info) .. " " elseif log_msg:len() > 2 then log_msg = log_msg .. " " end From a0fd22be195abf3e35de90104e47e8f10df08864 Mon Sep 17 00:00:00 2001 From: chrisaga <31566103+chrisaga@users.noreply.github.com> Date: Sat, 26 Dec 2020 12:08:38 +0100 Subject: [PATCH 123/445] Update clear_GPS.lua Changed first line of header which was referring to another plugin (gimp.lua) --- contrib/clear_GPS.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/clear_GPS.lua b/contrib/clear_GPS.lua index 31724952..bf54b89b 100644 --- a/contrib/clear_GPS.lua +++ b/contrib/clear_GPS.lua @@ -1,6 +1,6 @@ --[[ - clear_GPS.lua - export and edit with GIMP + clear_GPS.lua - plugin for Darktable Copyright (C) 2016 Bill Ferguson . From dfd714540e428c253d11bb15169ff7130f13937f Mon Sep 17 00:00:00 2001 From: chrisaga <31566103+chrisaga@users.noreply.github.com> Date: Sat, 26 Dec 2020 13:21:00 +0100 Subject: [PATCH 124/445] fr po-file for copy_paste_metadata --- .../fr_FR/LC_MESSAGES/copy_paste_metadata.po | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 locale/fr_FR/LC_MESSAGES/copy_paste_metadata.po diff --git a/locale/fr_FR/LC_MESSAGES/copy_paste_metadata.po b/locale/fr_FR/LC_MESSAGES/copy_paste_metadata.po new file mode 100644 index 00000000..aa6dc112 --- /dev/null +++ b/locale/fr_FR/LC_MESSAGES/copy_paste_metadata.po @@ -0,0 +1,35 @@ +# French messages for copy_paste_metadata.lua +# Christophe Agathon , 2020 +msgid "" +msgstr "" +"Project-Id-Version: copy_paste_metadata\n" +"POT-Creation-Date: 2020-12-26 12:49+0100\n" +"PO-Revision-Date: 2020-12-26 12:52+0100\n" +"Last-Translator: Christophe Agathon \n" +"Language-Team: \n" +"Language: fr_FR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 2.3\n" +"X-Poedit-Basepath: ../../../official\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Poedit-SourceCharset: UTF-8\n" +"X-Poedit-KeywordsList: _\n" +"X-Poedit-SearchPath-0: copy_paste_metadata.lua\n" + +#: copy_paste_metadata.lua:115 +msgid "copy metadata" +msgstr "copier les métadonnées" + +#: copy_paste_metadata.lua:117 +msgid "copy metadata of the first selected image" +msgstr "copier les métadonnées de la première image sélectionnée" + +#: copy_paste_metadata.lua:121 +msgid "paste metadata" +msgstr "coller les métadonnées" + +#: copy_paste_metadata.lua:123 +msgid "paste metadata to the selected images" +msgstr "coller les métadonnées vers les images sélectionnées" From e5271d79a0a9346157ef403d063c146cb1d81975 Mon Sep 17 00:00:00 2001 From: chrisaga <31566103+chrisaga@users.noreply.github.com> Date: Sat, 26 Dec 2020 13:27:53 +0100 Subject: [PATCH 125/445] Localize copy_paste_metadata.lua --- official/copy_paste_metadata.lua | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/official/copy_paste_metadata.lua b/official/copy_paste_metadata.lua index ca7ccae4..00496119 100644 --- a/official/copy_paste_metadata.lua +++ b/official/copy_paste_metadata.lua @@ -27,6 +27,7 @@ USAGE local dt = require "darktable" local du = require "lib/dtutils" +local gettext = dt.gettext du.check_min_api_version("3.0.0", "copy_paste_metadata") @@ -48,6 +49,13 @@ local publisher = "" local rights = "" local tags = {} +-- Tell gettext where to find the .mo file translating messages for a particular domain +gettext.bindtextdomain("copy_paste_metadata",dt.configuration.config_dir.."/lua/locale/") + +local function _(msgid) + return gettext.dgettext("copy_paste_metadata", msgid) +end + local function copy(image) if not image then have_data = false @@ -105,15 +113,15 @@ local function paste(images) end dt.gui.libs.image.register_action( - "copy metadata", + _("copy metadata"), function(event, images) copy(images[1]) end, - "copy metadata of the first selected image" + _("copy metadata of the first selected image") ) dt.gui.libs.image.register_action( - "paste metadata", + _("paste metadata"), function(event, images) paste(images) end, - "paste metadata to the selected images" + _("paste metadata to the selected images") ) dt.register_event( From 132668d04c8c5bdd92343ac30270f83ed5581d37 Mon Sep 17 00:00:00 2001 From: chrisaga Date: Sun, 27 Dec 2020 18:22:19 +0100 Subject: [PATCH 126/445] More clear_GPS.lua localization --- contrib/clear_GPS.lua | 4 ++-- locale/fr_FR/LC_MESSAGES/clear_GPS.po | 26 +++++++++++++++++--------- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/contrib/clear_GPS.lua b/contrib/clear_GPS.lua index 31724952..5cdb4257 100644 --- a/contrib/clear_GPS.lua +++ b/contrib/clear_GPS.lua @@ -66,11 +66,11 @@ end dt.gui.libs.image.register_action( _("clear GPS data"), function(event, images) clear_GPS(images) end, - "clear GPS data" + _("Clear GPS data from selected images") ) dt.register_event( "shortcut", function(event, shortcut) clear_GPS(dt.gui.action_images) end, - "clear GPS data" + _("Clear GPS data") ) diff --git a/locale/fr_FR/LC_MESSAGES/clear_GPS.po b/locale/fr_FR/LC_MESSAGES/clear_GPS.po index 9b345c67..a61be082 100644 --- a/locale/fr_FR/LC_MESSAGES/clear_GPS.po +++ b/locale/fr_FR/LC_MESSAGES/clear_GPS.po @@ -7,21 +7,29 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2016-09-07 22:25-0400\n" -"PO-Revision-Date: 2016-10-03 14:55+0200\n" -"Last-Translator: Pascal Obry \n" +"POT-Creation-Date: 2020-12-27 17:55+0100\n" +"PO-Revision-Date: 2020-12-27 17:55+0100\n" +"Last-Translator: Christophe Agathon \n" +"Language-Team: \n" "Language: fr_FR\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: Poedit 1.8.9\n" -"Language: fr_FR\n" +"X-Generator: Poedit 2.3\n" "X-Poedit-SourceCharset: UTF-8\n" -"X-Poedit-KeywordsList: gettext;dgettext:2;dcgettext:2ngettext:1,2;" +"X-Poedit-KeywordsList: _;gettext;dgettext:2;dcgettext:2ngettext:1,2;" "dngettext:2,3\n" -"X-Poedit-Basepath: .\n" -"Language-Team: \n" +"X-Poedit-Basepath: ../../../contrib\n" +"X-Poedit-SearchPath-0: clear_GPS.lua\n" -#: clear_GPS.lua:62 +#: clear_GPS.lua:67 msgid "clear GPS data" msgstr "effacer données GPS" + +#: clear_GPS.lua:69 +msgid "Clear GPS data from selected images" +msgstr "Effacer les données GPS des images sélectionnées" + +#: clear_GPS.lua:75 +msgid "Clear GPS data" +msgstr "Effacer les données GPS" From 2be12e5b3711c14730019f6e73c0247d528f657c Mon Sep 17 00:00:00 2001 From: chrisaga Date: Mon, 28 Dec 2020 10:42:15 +0100 Subject: [PATCH 127/445] script_manager.lua localization proposal (including minor changes in the script) --- locale/fr_FR/LC_MESSAGES/script_manager.po | 188 +++++++++++++++++++++ tools/script_manager.lua | 8 +- 2 files changed, 192 insertions(+), 4 deletions(-) create mode 100644 locale/fr_FR/LC_MESSAGES/script_manager.po diff --git a/locale/fr_FR/LC_MESSAGES/script_manager.po b/locale/fr_FR/LC_MESSAGES/script_manager.po new file mode 100644 index 00000000..fbfc1064 --- /dev/null +++ b/locale/fr_FR/LC_MESSAGES/script_manager.po @@ -0,0 +1,188 @@ +# French messages for script_manager.lua +# Christophe Agathon , 2020 +msgid "" +msgstr "" +"Project-Id-Version: \n" +"POT-Creation-Date: 2020-12-28 10:22+0100\n" +"PO-Revision-Date: 2020-12-28 10:24+0100\n" +"Last-Translator: Christophe Agathon \n" +"Language-Team: \n" +"Language: fr_FR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 2.3\n" +"X-Poedit-Basepath: ../../../tools\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Poedit-KeywordsList: _\n" +"X-Poedit-SearchPath-0: script_manager.lua\n" + +#: script_manager.lua:190 +msgid "Cant read from " +msgstr "Ne peut pas lire " + +#: script_manager.lua:204 +msgid "Loaded " +msgstr "Script chargé : " + +#: script_manager.lua:207 +msgid " failed to load" +msgstr " non chargé" + +#: script_manager.lua:223 +msgid " will not start when darktable is restarted" +msgstr " ne démarrera pas lorsque darktable sera redémarré" + +#: script_manager.lua:281 script_manager.lua:345 +msgid "find command is " +msgstr "la commande find est " + +#: script_manager.lua:321 +msgid "lua scripts successfully updated" +msgstr "mise à jour des scripts lua réussie" + +#: script_manager.lua:381 +msgid "category " +msgstr "la catégorie " + +#: script_manager.lua:381 +msgid " is already in use. Please specify a different category name." +msgstr " est déjà utilisée. Indiquez un autre nom de catégorie SVP." + +#: script_manager.lua:410 +msgid "scripts successfully installed into category " +msgstr "les scripts ont été installés dans la catégorie " + +#: script_manager.lua:426 +msgid "No scripts found to install" +msgstr "Nous n'avons pas trouvé de script à installer" + +#: script_manager.lua:430 +msgid "failed to download scripts" +msgstr "impossible de télécharger les scripts" + +# Peut-être que « activé » serait mieux, mais ce n'est pas la traduction de « started » +#: script_manager.lua:458 +msgid " started" +msgstr " démarré" + +# Peut-être que « désactivé » serait mieux, mais ce n'est pas la traduction de « stopped » +#: script_manager.lua:460 +msgid " stopped" +msgstr " arrêté" + +#: script_manager.lua:545 +msgid "Page " +msgstr "Page " + +#: script_manager.lua:545 +msgid " of " +msgstr " sur " + +#: script_manager.lua:674 +msgid "scripts to update" +msgstr "scripts à mettre à jour" + +#: script_manager.lua:675 +msgid "select the scripts installation to update" +msgstr "sélectionnez les scripts à mettre à jour" + +#: script_manager.lua:684 script_manager.lua:742 +msgid "update scripts" +msgstr "mettre à jour les scripts" + +#: script_manager.lua:685 +msgid "update the lua scripts from the repository" +msgstr "metre à jour les scripts depuis le dépôt" + +#: script_manager.lua:696 +msgid "enter the URL of the git repository containing the scripts you wish to add" +msgstr "indiquez l'URL du dépôt git contenant les scripts que vous souhaitez ajouter" + +#: script_manager.lua:701 +msgid "name of new category" +msgstr "nom de la nouvelle catégorie" + +#: script_manager.lua:702 +msgid "enter a category name for the additional scripts" +msgstr "indiquez un nom de catégorie pour les scripts supplémentaires" + +#: script_manager.lua:707 +msgid "URL to download additional scripts from" +msgstr "URL d'où seront téléchargés les scripts" + +#: script_manager.lua:709 +msgid "new category to place scripts in" +msgstr "nouvelle catégorie où seront placés les scripts" + +#: script_manager.lua:712 +msgid "install additional scripts" +msgstr "installer les scripts supplémentaires" + +#: script_manager.lua:720 +msgid "Enable \"Disable Scripts\" button" +msgstr "Activer le bouton « Désactiver les Scripts »" + +#: script_manager.lua:730 +msgid "Disable Scripts" +msgstr "Désactiver les scripts" + +#: script_manager.lua:736 +msgid "lua scripts will not run the next time darktable is started" +msgstr "les scripts lua ne seront pas lancés au prochain démarrage de darktable" + +#: script_manager.lua:745 +msgid "add more scripts" +msgstr "ajouter des scripts" + +#: script_manager.lua:747 +msgid "disable scripts" +msgstr "désactiver les scripts" + +#: script_manager.lua:755 +msgid "category" +msgstr "catégorie" + +#: script_manager.lua:756 +msgid "select the script category" +msgstr "sélectionner la catégorie" + +#: script_manager.lua:780 +msgid "Page:" +msgstr "Page :" + +#: script_manager.lua:808 +msgid "Scripts" +msgstr "Scripts" + +#: script_manager.lua:817 +msgid "scripts per page" +msgstr "scripts par page" + +#: script_manager.lua:818 +msgid "select number of start/stop buttons to display" +msgstr "sélectionner le nombre de boutons marche/arrêt à afficher" + +#: script_manager.lua:829 +msgid "change number of buttons" +msgstr "changer le nombre de boutons" + +#: script_manager.lua:837 +msgid "Configuration" +msgstr "Configuration" + +#: script_manager.lua:858 +msgid "action" +msgstr "action" + +#: script_manager.lua:864 +msgid "install/update scripts" +msgstr "installer/mettre à jour des scripts" + +#: script_manager.lua:864 +msgid "configure" +msgstr "configurer" + +#: script_manager.lua:864 +msgid "start/stop scripts" +msgstr "démarrer/arrêter des scripts" diff --git a/tools/script_manager.lua b/tools/script_manager.lua index 0d49f3cd..8ce16c8d 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -378,7 +378,7 @@ local function install_scripts() local category = sm.widgets.new_category.text if string.match(du.join(sm.categories, " "), ds.sanitize_lua(category)) then - log.msg(log.screen, _("category ") .. category .. _(" is already in use. Please specify a different category name.")) + log.msg(log.screen, _("category ") .. category .. _(" is already in use. Please specify a different category name.")) log.msg(log.error, "category " .. category .. " already exists, returning...") return end @@ -455,9 +455,9 @@ local function populate_buttons(category, first, last) script = sm.scripts[category][i] button = sm.widgets.buttons[button_num] if script.running then - button.label = script.name .. " started" + button.label = script.name .. _(" started") else - button.label = script.name .. " stopped" + button.label = script.name .. _(" stopped") end if CURR_API_STRING >= "6.0.1" then button.ellipsize = "middle" @@ -717,7 +717,7 @@ sm.widgets.add_scripts = dt.new_widget("box"){ } sm.widgets.allow_disable = dt.new_widget("check_button"){ - label = _('Enable "Dsiable Scripts" button'), + label = _('Enable "Disable Scripts" button'), value = false, clicked_callback = function(this) if this.value == true then From dfe589e843e118d4ed51f3fad86c214931f4a905 Mon Sep 17 00:00:00 2001 From: chrisaga Date: Mon, 28 Dec 2020 19:18:35 +0100 Subject: [PATCH 128/445] script_manager.lua function clear_button must reset tooltip too --- tools/script_manager.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/script_manager.lua b/tools/script_manager.lua index 8ce16c8d..157f47bf 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -436,6 +436,7 @@ end local function clear_button(number) local button = sm.widgets.buttons[number] button.label = "" + button.tooltip = "" button.sensitive = false end From 367631af99c46670d35f47b15291f0ce7c9dceaa Mon Sep 17 00:00:00 2001 From: chrisaga Date: Sun, 3 Jan 2021 20:55:45 +0100 Subject: [PATCH 129/445] copy_attach_detachtags.lua localization --- contrib/copy_attach_detach_tags.lua | 24 ++++--- .../LC_MESSAGES/copy_attach_detach_tags.po | 72 +++++++++++++++++++ 2 files changed, 86 insertions(+), 10 deletions(-) create mode 100644 locale/fr_FR/LC_MESSAGES/copy_attach_detach_tags.po diff --git a/contrib/copy_attach_detach_tags.lua b/contrib/copy_attach_detach_tags.lua index 43b40e23..85436471 100644 --- a/contrib/copy_attach_detach_tags.lua +++ b/contrib/copy_attach_detach_tags.lua @@ -112,7 +112,7 @@ local function mcopy_tags() local function attach_tags() if next(image_tags) == nil then - dt.print(_('No tags to attached, please copy tags first.')) + dt.print(_('No tag to attach, please copy tags first.')) return true end @@ -163,7 +163,7 @@ end local function install_module() if not cadt.module_installed then - dt.register_lib("tagging_addon","Tagging addon",true,true,{ + dt.register_lib("tagging_addon","tagging addon",true,true,{ [dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER",500} }, dt.new_widget("box") { @@ -194,22 +194,26 @@ local taglabel = dt.new_widget("label") { local box1 = dt.new_widget("box"){ orientation = "horizontal", dt.new_widget("button") { - label = _('multi copy tags'), - clicked_callback = mcopy_tags}, + label = _('multi copy tags'), + tooltip = _('copy tags from selected image(s)'), + clicked_callback = mcopy_tags}, dt.new_widget("button") { - label = _('paste tags'), - clicked_callback = attach_tags} + tooltip = _('paste tags to selected image(s)'), + label = _('paste tags'), + clicked_callback = attach_tags} } local box2 = dt.new_widget("box"){ orientation = "horizontal", dt.new_widget("button") { - label = _('replace tags'), - clicked_callback = replace_tags}, + label = _('replace tags'), + tooltip = _('replace tags from selected image(s)'), + clicked_callback = replace_tags}, dt.new_widget("button") { - label = _('remove all tags'), - clicked_callback = detach_tags} + label = _('remove all tags'), + tooltip = _('remove tags from selected image(s)'), + clicked_callback = detach_tags} } local sep = dt.new_widget("separator"){} diff --git a/locale/fr_FR/LC_MESSAGES/copy_attach_detach_tags.po b/locale/fr_FR/LC_MESSAGES/copy_attach_detach_tags.po new file mode 100644 index 00000000..1cdae089 --- /dev/null +++ b/locale/fr_FR/LC_MESSAGES/copy_attach_detach_tags.po @@ -0,0 +1,72 @@ +msgid "" +msgstr "" +"Project-Id-Version: \n" +"POT-Creation-Date: 2021-01-03 20:18+0100\n" +"PO-Revision-Date: 2021-01-03 20:46+0100\n" +"Last-Translator: Christophe Agathon \n" +"Language-Team: \n" +"Language: fr_FR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 2.3\n" +"X-Poedit-Basepath: ../../../contrib\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Poedit-KeywordsList: _\n" +"X-Poedit-SearchPath-0: copy_attach_detach_tags.lua\n" + +#: copy_attach_detach_tags.lua:93 +msgid "Image tags copied ..." +msgstr "Mots-clés de l'image copiés ..." + +#: copy_attach_detach_tags.lua:115 +msgid "No tag to attach, please copy tags first." +msgstr "Pas de mot-clé à attacher, veuillez d'abord copier les mots-clés." + +#: copy_attach_detach_tags.lua:139 +msgid "Tags attached ..." +msgstr "Mots-clés attachés ..." + +#: copy_attach_detach_tags.lua:155 +msgid "Tags removed from image(s)." +msgstr "Mots-clés supprimés des images." + +#: copy_attach_detach_tags.lua:161 +msgid "Tags replaced" +msgstr "Mots-clés remplacés" + +#: copy_attach_detach_tags.lua:189 +msgid "tag clipboard" +msgstr "presse-papier des mots-clés" + +#: copy_attach_detach_tags.lua:197 +msgid "multi copy tags" +msgstr "copier mots-clés" + +#: copy_attach_detach_tags.lua:200 +msgid "paste tags" +msgstr "coller mots-clés" + +#: copy_attach_detach_tags.lua:208 +msgid "replace tags" +msgstr "remplacer mots-clés" + +#: copy_attach_detach_tags.lua:211 +msgid "remove all tags" +msgstr "supprimer tous mots-clés" + +#: copy_attach_detach_tags.lua:248 +msgid "copy tags from selected image(s)" +msgstr "copier les mots-clés des images sélectionnnées" + +#: copy_attach_detach_tags.lua:253 +msgid "paste tags to selected image(s)" +msgstr "coller les mots clés dans les images sélectionnées" + +#: copy_attach_detach_tags.lua:258 +msgid "remove tags from selected image(s)" +msgstr "supprimer les mots-clés des images sélectionnées" + +#: copy_attach_detach_tags.lua:263 +msgid "replace tags from selected image(s)" +msgstr "remplacer les mots-clés des images sélectionnées" From a71889021f0fdec82cbd0822f339f29b35b808ec Mon Sep 17 00:00:00 2001 From: chrisaga Date: Sun, 3 Jan 2021 21:02:25 +0100 Subject: [PATCH 130/445] add copy_attach_detachtags.po header --- locale/fr_FR/LC_MESSAGES/copy_attach_detach_tags.po | 2 ++ 1 file changed, 2 insertions(+) diff --git a/locale/fr_FR/LC_MESSAGES/copy_attach_detach_tags.po b/locale/fr_FR/LC_MESSAGES/copy_attach_detach_tags.po index 1cdae089..ba6d8971 100644 --- a/locale/fr_FR/LC_MESSAGES/copy_attach_detach_tags.po +++ b/locale/fr_FR/LC_MESSAGES/copy_attach_detach_tags.po @@ -1,3 +1,5 @@ +# French messages for copy_attach_detach_tags.lua +# Christophe Agathon , 2021 msgid "" msgstr "" "Project-Id-Version: \n" From b08d7f27d2e8b2359b5096b167be0d865b58f150 Mon Sep 17 00:00:00 2001 From: Dan Torop Date: Tue, 5 Jan 2021 22:14:40 -0500 Subject: [PATCH 131/445] fujifilm_dynamic_range : first draft Read RawExposureBias and adjust "EXIF Exposure Bias" based upon this. --- contrib/fujifilm_dynamic_range.lua | 73 ++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 contrib/fujifilm_dynamic_range.lua diff --git a/contrib/fujifilm_dynamic_range.lua b/contrib/fujifilm_dynamic_range.lua new file mode 100644 index 00000000..5ce8fc0c --- /dev/null +++ b/contrib/fujifilm_dynamic_range.lua @@ -0,0 +1,73 @@ +--[[ fujifilm_dynamic_range-0.1 + +Compensate for Fujifilm raw files made using "dynamic range". + +Copyright (C) 2020 Dan Torop + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +]] + +--[[About this Plugin +Support for adjusting darktable exposure by Fujifilm raw exposure +bias. This corrects for a DR100/DR200/DR400 "dynamic range" setting. + +Dependencies: +- exiftool (https://www.sno.phy.queensu.ca/~phil/exiftool/) + +Based upon fujifilm_ratings by Ben Mendis + +--]] + +local dt = require "darktable" +local du = require "lib/dtutils" +local df = require "lib/dtutils.file" +local gettext = dt.gettext + +du.check_min_api_version("4.0.0", "fujifilm_dynamic_range") + +gettext.bindtextdomain("fujifilm_dynamic_range", dt.configuration.config_dir.."/lua/locale/") + +local function _(msgid) + return gettext.dgettext("fujifilm_dynamic_range", msgid) +end + +local function detect_dynamic_range(event, image) + -- exiftool knows about the RawExposureBias tag, unlike exiv2, but it is also 10x slower + if not df.check_if_bin_exists("exiftool") then + dt.print_error(_("exiftool not found")) + return + end + local RAF_filename = df.sanitize_filename(tostring(image)) + local command = "exiftool -RawExposureBias " .. RAF_filename + dt.print_error(command) + output = io.popen(command) + local raf_result = output:read("*all") + output:close() + if string.len(raf_result) > 0 then + raf_result = string.gsub(raf_result, "^Raw Exposure Bias.-([%d%.%-]+)", "%1") + if image.exif_exposure_bias ~= image.exif_exposure_bias then + -- is NAN (this is unlikely as RAFs should have ExposureBiasValue set) + image.exif_exposure_bias = 0 + end + -- this should be auto-applied if plugins/darkroom/workflow is scene-referred + -- FIXME: scene-referred workflow pushes exposure up 0.5 EV, but DR100 pushes up 0.7 EV -- should reduce this by 0.5 EV? + image.exif_exposure_bias = image.exif_exposure_bias + tonumber(raf_result) + dt.print_error(_("Using RAF exposure bias: ") .. tostring(raf_result)) + end +end + +dt.register_event("post-import-image", detect_dynamic_range) + +print(_("fujifilm_dynamic_range loaded.")) From 952b8b2eb23476c3d12133600ae14ab9fd7c67ab Mon Sep 17 00:00:00 2001 From: Dan Torop Date: Wed, 6 Jan 2021 10:11:59 -0500 Subject: [PATCH 132/445] fujifilm-dynamic-range: better exiftool parsing & comments Get tab-delimited output from exiftool without rounding. Add comments to explain the choice of tags being read and tool to read them. --- contrib/fujifilm_dynamic_range.lua | 35 ++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/contrib/fujifilm_dynamic_range.lua b/contrib/fujifilm_dynamic_range.lua index 5ce8fc0c..d5dee9b9 100644 --- a/contrib/fujifilm_dynamic_range.lua +++ b/contrib/fujifilm_dynamic_range.lua @@ -28,6 +28,33 @@ Dependencies: Based upon fujifilm_ratings by Ben Mendis +The relevant tag is RawExposureBias (0x9650). This appears to +represent the shift in EV for the chosen DR setting (whether manual or +automatic). Note that even at 100DR ("standard") there is an EV shift: + +100 DR -> -0.72 EV +200 DR -> -1.72 EV +400 DR -> -2.72 EV + +The ideal would be to use exiv2 to read this tag, as this is the same +code which darktable import uses. Unfortunately, exiv2 as of v0.27.3 +can't read this tag. As it is encoded as a 4-byte ratio of two signed +shorts -- a novel data type -- it will require some attention to fix +this. + +There is an exiv2-readable DevelopmentDynamicRange tag which maps to +RawExposureBias as above. DevelopmentDynamicRange is only present +when tag DynamicRangeSetting (0x1402) is Manual/Raw (0x0001). When it +is Auto (0x0000), the equivalent data is tag AutoDynamicRange +(0x140b). But exiv2 currently can't read that tag either. + +Hence for now this code uses exiftool to read RawExposureBias, as a +more general solution. As exiftool is approx. 10x slower than exiv2 +(Perl vs. C++), this may slow large imports. + +These tags have been checked on a Fujifilm X100S and X100V. Other +cameras may behave in other ways. + --]] local dt = require "darktable" @@ -44,25 +71,25 @@ local function _(msgid) end local function detect_dynamic_range(event, image) - -- exiftool knows about the RawExposureBias tag, unlike exiv2, but it is also 10x slower if not df.check_if_bin_exists("exiftool") then dt.print_error(_("exiftool not found")) return end local RAF_filename = df.sanitize_filename(tostring(image)) - local command = "exiftool -RawExposureBias " .. RAF_filename + -- without -n flag, exiftool will round to the nearest tenth + local command = "exiftool -RawExposureBias -n -t " .. RAF_filename dt.print_error(command) output = io.popen(command) local raf_result = output:read("*all") output:close() if string.len(raf_result) > 0 then - raf_result = string.gsub(raf_result, "^Raw Exposure Bias.-([%d%.%-]+)", "%1") + raf_result = string.match(raf_result, "\t(.*)") if image.exif_exposure_bias ~= image.exif_exposure_bias then -- is NAN (this is unlikely as RAFs should have ExposureBiasValue set) image.exif_exposure_bias = 0 end -- this should be auto-applied if plugins/darkroom/workflow is scene-referred - -- FIXME: scene-referred workflow pushes exposure up 0.5 EV, but DR100 pushes up 0.7 EV -- should reduce this by 0.5 EV? + -- note that scene-referred workflow exposure preset also pushes exposure up by 0.5 EV image.exif_exposure_bias = image.exif_exposure_bias + tonumber(raf_result) dt.print_error(_("Using RAF exposure bias: ") .. tostring(raf_result)) end From 6341a0a45939f8bd770e410ebd97408aa6026615 Mon Sep 17 00:00:00 2001 From: Dan Torop Date: Wed, 6 Jan 2021 10:25:18 -0500 Subject: [PATCH 133/445] fujifilm-dynamic-range: better logging and error handling Use dt.print_log() for log messages. Print error output if no results or results not parseable from exiftool. Also update the date, it's 2021. --- contrib/fujifilm_dynamic_range.lua | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/contrib/fujifilm_dynamic_range.lua b/contrib/fujifilm_dynamic_range.lua index d5dee9b9..0f61cd56 100644 --- a/contrib/fujifilm_dynamic_range.lua +++ b/contrib/fujifilm_dynamic_range.lua @@ -2,7 +2,7 @@ Compensate for Fujifilm raw files made using "dynamic range". -Copyright (C) 2020 Dan Torop +Copyright (C) 2021 Dan Torop This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -78,23 +78,29 @@ local function detect_dynamic_range(event, image) local RAF_filename = df.sanitize_filename(tostring(image)) -- without -n flag, exiftool will round to the nearest tenth local command = "exiftool -RawExposureBias -n -t " .. RAF_filename - dt.print_error(command) + dt.print_log(command) output = io.popen(command) local raf_result = output:read("*all") output:close() if string.len(raf_result) > 0 then raf_result = string.match(raf_result, "\t(.*)") - if image.exif_exposure_bias ~= image.exif_exposure_bias then - -- is NAN (this is unlikely as RAFs should have ExposureBiasValue set) - image.exif_exposure_bias = 0 + if raf_result then + if image.exif_exposure_bias ~= image.exif_exposure_bias then + -- is NAN (this is unlikely as RAFs should have ExposureBiasValue set) + image.exif_exposure_bias = 0 + end + -- this should be auto-applied if plugins/darkroom/workflow is scene-referred + -- note that scene-referred workflow exposure preset also pushes exposure up by 0.5 EV + image.exif_exposure_bias = image.exif_exposure_bias + tonumber(raf_result) + dt.print_log(_("Using RAF exposure bias: ") .. tostring(raf_result)) + else + dt.print_error(_("Could not parse exiftool output.")) end - -- this should be auto-applied if plugins/darkroom/workflow is scene-referred - -- note that scene-referred workflow exposure preset also pushes exposure up by 0.5 EV - image.exif_exposure_bias = image.exif_exposure_bias + tonumber(raf_result) - dt.print_error(_("Using RAF exposure bias: ") .. tostring(raf_result)) + else + dt.print_error(_("No output returned by exiftool.")) end end dt.register_event("post-import-image", detect_dynamic_range) -print(_("fujifilm_dynamic_range loaded.")) +dt.print_log(_("fujifilm_dynamic_range loaded.")) From a9fd0718b072d646011aee6216c605c4085f4ffe Mon Sep 17 00:00:00 2001 From: Dan Torop Date: Wed, 6 Jan 2021 11:21:05 -0500 Subject: [PATCH 134/445] fujifilm-dynamic-range: skip non-Fuji non-raws and clean-ups Don't bother to pull EXIF data unless the imported image is a Fujifilm raw. Cleanup conditionals for error handling by immediately returning on failure, avoiding deep nested conditionals. Cleanup log/error output with clearer messages. --- contrib/fujifilm_dynamic_range.lua | 45 ++++++++++++++++++------------ 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/contrib/fujifilm_dynamic_range.lua b/contrib/fujifilm_dynamic_range.lua index 0f61cd56..8c080d56 100644 --- a/contrib/fujifilm_dynamic_range.lua +++ b/contrib/fujifilm_dynamic_range.lua @@ -71,8 +71,17 @@ local function _(msgid) end local function detect_dynamic_range(event, image) + if image.exif_maker ~= "FUJIFILM" then + dt.print_log(_("[fujifilm_dynamic_range] ignoring non-Fujifilm image")) + return + end + -- it would be nice to check image.is_raw but this appears to not yet be set + if not string.match(image.filename, "%.RAF$") then + dt.print_log(_("[fujifilm_dynamic_range] ignoring non-raw image")) + return + end if not df.check_if_bin_exists("exiftool") then - dt.print_error(_("exiftool not found")) + dt.print_error(_("[fujifilm_dynamic_range] exiftool not found")) return end local RAF_filename = df.sanitize_filename(tostring(image)) @@ -82,25 +91,25 @@ local function detect_dynamic_range(event, image) output = io.popen(command) local raf_result = output:read("*all") output:close() - if string.len(raf_result) > 0 then - raf_result = string.match(raf_result, "\t(.*)") - if raf_result then - if image.exif_exposure_bias ~= image.exif_exposure_bias then - -- is NAN (this is unlikely as RAFs should have ExposureBiasValue set) - image.exif_exposure_bias = 0 - end - -- this should be auto-applied if plugins/darkroom/workflow is scene-referred - -- note that scene-referred workflow exposure preset also pushes exposure up by 0.5 EV - image.exif_exposure_bias = image.exif_exposure_bias + tonumber(raf_result) - dt.print_log(_("Using RAF exposure bias: ") .. tostring(raf_result)) - else - dt.print_error(_("Could not parse exiftool output.")) - end - else - dt.print_error(_("No output returned by exiftool.")) + if #raf_result == 0 then + dt.print_error(_("[fujifilm_dynamic_range] no output returned by exiftool")) + return + end + raf_result = string.match(raf_result, "\t(.*)") + if not raf_result then + dt.print_error(_("[fujifilm_dynamic_range] could not parse exiftool output")) + return + end + if image.exif_exposure_bias ~= image.exif_exposure_bias then + -- is NAN (this is unlikely as RAFs should have ExposureBiasValue set) + image.exif_exposure_bias = 0 end + -- this should be auto-applied if plugins/darkroom/workflow is scene-referred + -- note that scene-referred workflow exposure preset also pushes exposure up by 0.5 EV + image.exif_exposure_bias = image.exif_exposure_bias + tonumber(raf_result) + dt.print_log(_("[fujifilm_dynamic_range] raw exposure bias ") .. tostring(raf_result)) end dt.register_event("post-import-image", detect_dynamic_range) -dt.print_log(_("fujifilm_dynamic_range loaded.")) +dt.print_log(_("[fujifilm_dynamic_range] loaded")) From 1d1eb6a7688bf6bc0d9c18ea3239797785f4a306 Mon Sep 17 00:00:00 2001 From: Dan Torop Date: Thu, 7 Jan 2021 22:55:55 -0500 Subject: [PATCH 135/445] fujifilm-dynamic-range: remove translations, use full exiftool path Suggestions as per @wpferguson: "We came to a decision a while ago to not translate debug messages(i.e. print_log() and print_error()) because the author might not be able to read the output if it was a language they weren't familiar with. So the only thing we translate are labels, tooltips, and dt.print() messages." "df.check_if_bin_exists() returns the full path to the executable. Using the returned value would let the script run on windows and macos too." --- contrib/fujifilm_dynamic_range.lua | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/contrib/fujifilm_dynamic_range.lua b/contrib/fujifilm_dynamic_range.lua index 8c080d56..fb773fa8 100644 --- a/contrib/fujifilm_dynamic_range.lua +++ b/contrib/fujifilm_dynamic_range.lua @@ -60,44 +60,38 @@ cameras may behave in other ways. local dt = require "darktable" local du = require "lib/dtutils" local df = require "lib/dtutils.file" -local gettext = dt.gettext du.check_min_api_version("4.0.0", "fujifilm_dynamic_range") -gettext.bindtextdomain("fujifilm_dynamic_range", dt.configuration.config_dir.."/lua/locale/") - -local function _(msgid) - return gettext.dgettext("fujifilm_dynamic_range", msgid) -end - local function detect_dynamic_range(event, image) if image.exif_maker ~= "FUJIFILM" then - dt.print_log(_("[fujifilm_dynamic_range] ignoring non-Fujifilm image")) + dt.print_log("[fujifilm_dynamic_range] ignoring non-Fujifilm image") return end -- it would be nice to check image.is_raw but this appears to not yet be set if not string.match(image.filename, "%.RAF$") then - dt.print_log(_("[fujifilm_dynamic_range] ignoring non-raw image")) + dt.print_log("[fujifilm_dynamic_range] ignoring non-raw image") return end - if not df.check_if_bin_exists("exiftool") then - dt.print_error(_("[fujifilm_dynamic_range] exiftool not found")) + local command = df.check_if_bin_exists("exiftool") + if not command then + dt.print_error("[fujifilm_dynamic_range] exiftool not found") return end local RAF_filename = df.sanitize_filename(tostring(image)) -- without -n flag, exiftool will round to the nearest tenth - local command = "exiftool -RawExposureBias -n -t " .. RAF_filename + command = command .. " -RawExposureBias -n -t " .. RAF_filename dt.print_log(command) output = io.popen(command) local raf_result = output:read("*all") output:close() if #raf_result == 0 then - dt.print_error(_("[fujifilm_dynamic_range] no output returned by exiftool")) + dt.print_error("[fujifilm_dynamic_range] no output returned by exiftool") return end raf_result = string.match(raf_result, "\t(.*)") if not raf_result then - dt.print_error(_("[fujifilm_dynamic_range] could not parse exiftool output")) + dt.print_error("[fujifilm_dynamic_range] could not parse exiftool output") return end if image.exif_exposure_bias ~= image.exif_exposure_bias then @@ -107,9 +101,9 @@ local function detect_dynamic_range(event, image) -- this should be auto-applied if plugins/darkroom/workflow is scene-referred -- note that scene-referred workflow exposure preset also pushes exposure up by 0.5 EV image.exif_exposure_bias = image.exif_exposure_bias + tonumber(raf_result) - dt.print_log(_("[fujifilm_dynamic_range] raw exposure bias ") .. tostring(raf_result)) + dt.print_log("[fujifilm_dynamic_range] raw exposure bias " .. tostring(raf_result)) end dt.register_event("post-import-image", detect_dynamic_range) -dt.print_log(_("[fujifilm_dynamic_range] loaded")) +dt.print_log("[fujifilm_dynamic_range] loaded") From 359a1fa3a919f1fabe0ee676f00219c537664a1d Mon Sep 17 00:00:00 2001 From: chrisaga Date: Sun, 10 Jan 2021 19:54:10 +0100 Subject: [PATCH 136/445] As discussed, localize module name in GUI --- contrib/copy_attach_detach_tags.lua | 3 +- .../LC_MESSAGES/copy_attach_detach_tags.po | 40 ++++++++++--------- 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/contrib/copy_attach_detach_tags.lua b/contrib/copy_attach_detach_tags.lua index 85436471..d4ab57d9 100644 --- a/contrib/copy_attach_detach_tags.lua +++ b/contrib/copy_attach_detach_tags.lua @@ -163,7 +163,7 @@ end local function install_module() if not cadt.module_installed then - dt.register_lib("tagging_addon","tagging addon",true,true,{ + dt.register_lib("tagging_addon",_('tagging addon'),true,true,{ [dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER",500} }, dt.new_widget("box") { @@ -201,7 +201,6 @@ local box1 = dt.new_widget("box"){ tooltip = _('paste tags to selected image(s)'), label = _('paste tags'), clicked_callback = attach_tags} - } local box2 = dt.new_widget("box"){ diff --git a/locale/fr_FR/LC_MESSAGES/copy_attach_detach_tags.po b/locale/fr_FR/LC_MESSAGES/copy_attach_detach_tags.po index ba6d8971..f7ee47e7 100644 --- a/locale/fr_FR/LC_MESSAGES/copy_attach_detach_tags.po +++ b/locale/fr_FR/LC_MESSAGES/copy_attach_detach_tags.po @@ -3,8 +3,8 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"POT-Creation-Date: 2021-01-03 20:18+0100\n" -"PO-Revision-Date: 2021-01-03 20:46+0100\n" +"POT-Creation-Date: 2021-01-10 19:39+0100\n" +"PO-Revision-Date: 2021-01-10 19:43+0100\n" "Last-Translator: Christophe Agathon \n" "Language-Team: \n" "Language: fr_FR\n" @@ -37,6 +37,10 @@ msgstr "Mots-clés supprimés des images." msgid "Tags replaced" msgstr "Mots-clés remplacés" +#: copy_attach_detach_tags.lua:166 +msgid "tagging addon" +msgstr "mots-clés extra" + #: copy_attach_detach_tags.lua:189 msgid "tag clipboard" msgstr "presse-papier des mots-clés" @@ -45,30 +49,30 @@ msgstr "presse-papier des mots-clés" msgid "multi copy tags" msgstr "copier mots-clés" -#: copy_attach_detach_tags.lua:200 +#: copy_attach_detach_tags.lua:198 copy_attach_detach_tags.lua:252 +msgid "copy tags from selected image(s)" +msgstr "copier les mots-clés des images sélectionnnées" + +#: copy_attach_detach_tags.lua:201 copy_attach_detach_tags.lua:257 +msgid "paste tags to selected image(s)" +msgstr "coller les mots clés dans les images sélectionnées" + +#: copy_attach_detach_tags.lua:202 msgid "paste tags" msgstr "coller mots-clés" -#: copy_attach_detach_tags.lua:208 +#: copy_attach_detach_tags.lua:210 msgid "replace tags" msgstr "remplacer mots-clés" -#: copy_attach_detach_tags.lua:211 +#: copy_attach_detach_tags.lua:211 copy_attach_detach_tags.lua:267 +msgid "replace tags from selected image(s)" +msgstr "remplacer les mots-clés des images sélectionnées" + +#: copy_attach_detach_tags.lua:214 msgid "remove all tags" msgstr "supprimer tous mots-clés" -#: copy_attach_detach_tags.lua:248 -msgid "copy tags from selected image(s)" -msgstr "copier les mots-clés des images sélectionnnées" - -#: copy_attach_detach_tags.lua:253 -msgid "paste tags to selected image(s)" -msgstr "coller les mots clés dans les images sélectionnées" - -#: copy_attach_detach_tags.lua:258 +#: copy_attach_detach_tags.lua:215 copy_attach_detach_tags.lua:262 msgid "remove tags from selected image(s)" msgstr "supprimer les mots-clés des images sélectionnées" - -#: copy_attach_detach_tags.lua:263 -msgid "replace tags from selected image(s)" -msgstr "remplacer les mots-clés des images sélectionnées" From daee82aa6a6b2667073df50109982e00dbf8c877 Mon Sep 17 00:00:00 2001 From: August Schwerdfeger Date: Tue, 19 Jan 2021 01:05:50 -0600 Subject: [PATCH 137/445] Added a new utility function to look up an image in the database by ID. --- lib/dtutils.lua | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/lib/dtutils.lua b/lib/dtutils.lua index e1d403e7..019645c5 100644 --- a/lib/dtutils.lua +++ b/lib/dtutils.lua @@ -283,4 +283,47 @@ function dtutils.check_os(operating_systems) return false end +dtutils.libdoc.functions["find_image_by_id"] = { + Name = [[find_image_by_id]], + Synopsis = [[look up an image by ID in the database]], + Usage = [[local db = require "lib/dtutils.db" + local img = db.find_image_by_id(imgid) + id - int - the ID to look up + ]], + Description = [[find_image_by_id looks up an image by ID in the database.]], + Return_Value = [[result - dt_lua_image_t - image with the given ID if found, nil if not]], + Limitations = [[]], + Example = [[]], + See_Also = [[]], + Reference = [[]], + License = [[]], + Copyright = [[]], +} + +function dtutils.find_image_by_id(imgid) + if #dt.database == 0 or imgid > dt.database[#dt.database].id then + return nil + end + local min = 1 + local max = #dt.database + while (max-min)//2 > 0 do + local mid = min + (max-min)//2 + local midID = dt.database[mid].id + if imgid == midID then + return dt.database[mid] + elseif imgid < midID then + max = mid-1 + else + min = mid+1 + end + end + if dt.database[min].id == imgid then + return dt.database[min] + elseif dt.database[max].id == imgid then + return dt.database[max] + else + return nil + end +end + return dtutils From 8e0bf9e9910fed1660de796b534d2cb4e3f977a9 Mon Sep 17 00:00:00 2001 From: August Schwerdfeger Date: Tue, 19 Jan 2021 01:34:36 -0600 Subject: [PATCH 138/445] Corrected names in documentation of 'find_image_by_id'. --- lib/dtutils.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/dtutils.lua b/lib/dtutils.lua index 019645c5..48b51633 100644 --- a/lib/dtutils.lua +++ b/lib/dtutils.lua @@ -286,8 +286,8 @@ end dtutils.libdoc.functions["find_image_by_id"] = { Name = [[find_image_by_id]], Synopsis = [[look up an image by ID in the database]], - Usage = [[local db = require "lib/dtutils.db" - local img = db.find_image_by_id(imgid) + Usage = [[local du = require "lib/dtutils" + local img = du.find_image_by_id(imgid) id - int - the ID to look up ]], Description = [[find_image_by_id looks up an image by ID in the database.]], From 778ad2ce209397eb94d91498f9febfc5bc071851 Mon Sep 17 00:00:00 2001 From: wpferguson Date: Thu, 21 Jan 2021 21:20:17 -0500 Subject: [PATCH 139/445] [dtutils] added database.get_image() to find_image_by_id() for users with lua API 6.2.0 or greater --- lib/dtutils.lua | 42 +++++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/lib/dtutils.lua b/lib/dtutils.lua index 48b51633..60403be7 100644 --- a/lib/dtutils.lua +++ b/lib/dtutils.lua @@ -304,26 +304,30 @@ function dtutils.find_image_by_id(imgid) if #dt.database == 0 or imgid > dt.database[#dt.database].id then return nil end - local min = 1 - local max = #dt.database - while (max-min)//2 > 0 do - local mid = min + (max-min)//2 - local midID = dt.database[mid].id - if imgid == midID then - return dt.database[mid] - elseif imgid < midID then - max = mid-1 - else - min = mid+1 - end - end - if dt.database[min].id == imgid then - return dt.database[min] - elseif dt.database[max].id == imgid then - return dt.database[max] + if dt.configuration.api_version_string >= "6.3.0" then + return dt.database.get_image(imgid) else - return nil - end + local min = 1 + local max = #dt.database + while (max-min)//2 > 0 do + local mid = min + (max-min)//2 + local midID = dt.database[mid].id + if imgid == midID then + return dt.database[mid] + elseif imgid < midID then + max = mid-1 + else + min = mid+1 + end + end + if dt.database[min].id == imgid then + return dt.database[min] + elseif dt.database[max].id == imgid then + return dt.database[max] + else + return nil + end + end end return dtutils From c17e8325728d7efdb7cff49210f2b3a21b6532cc Mon Sep 17 00:00:00 2001 From: wpferguson Date: Thu, 21 Jan 2021 21:34:43 -0500 Subject: [PATCH 140/445] [dtutils] fixed api version check --- lib/dtutils.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/dtutils.lua b/lib/dtutils.lua index 60403be7..1b06a153 100644 --- a/lib/dtutils.lua +++ b/lib/dtutils.lua @@ -304,7 +304,7 @@ function dtutils.find_image_by_id(imgid) if #dt.database == 0 or imgid > dt.database[#dt.database].id then return nil end - if dt.configuration.api_version_string >= "6.3.0" then + if dt.configuration.api_version_string >= "6.2.0" then return dt.database.get_image(imgid) else local min = 1 From ade7008127f1a4ca860d6838f708a19e5856c906 Mon Sep 17 00:00:00 2001 From: wpferguson Date: Mon, 1 Feb 2021 18:27:20 -0500 Subject: [PATCH 141/445] Added compatibility for lua events API change 6.2.1. --- contrib/AutoGrouper.lua | 3 ++- contrib/HDRMerge.lua | 3 ++- contrib/LabelsToTags.lua | 3 ++- contrib/OpenInExplorer.lua | 3 ++- contrib/autostyle.lua | 6 ++++-- contrib/clear_GPS.lua | 3 ++- contrib/copy_attach_detach_tags.lua | 11 ++++++----- contrib/cr2hdr.lua | 10 +++++++--- contrib/exportLUT.lua | 3 ++- contrib/ext_editor.lua | 6 ++++-- contrib/face_recognition.lua | 3 ++- contrib/fujifilm_dynamic_range.lua | 4 +++- contrib/fujifilm_ratings.lua | 4 +++- contrib/geoToolbox.lua | 17 +++++++++++------ contrib/gpx_export.lua | 3 ++- contrib/image_time.lua | 3 ++- contrib/photils.lua | 6 ++++-- contrib/quicktag.lua | 5 +++-- contrib/rate_group.lua | 22 +++++++++++++++------- contrib/rename-tags.lua | 3 ++- contrib/slideshowMusic.lua | 5 ++++- contrib/transfer_hierarchy.lua | 3 ++- examples/moduleExample.lua | 3 ++- examples/multi_os.lua | 3 ++- official/copy_paste_metadata.lua | 5 +++-- official/enfuse.lua | 3 ++- official/generate_image_txt.lua | 4 +++- official/image_path_in_ui.lua | 5 +++-- official/import_filter_manager.lua | 3 ++- official/save_selection.lua | 7 ++++--- tools/executable_manager.lua | 3 ++- tools/script_manager.lua | 2 +- 32 files changed, 110 insertions(+), 57 deletions(-) diff --git a/contrib/AutoGrouper.lua b/contrib/AutoGrouper.lua index 4198952d..0f69e5d2 100644 --- a/contrib/AutoGrouper.lua +++ b/contrib/AutoGrouper.lua @@ -40,6 +40,7 @@ local dt = require "darktable" local MOD = 'autogrouper' local gettext = dt.gettext -- Tell gettext where to find the .mo file translating messages for a particular domain +local CURR_API_STRING = dt.configuration_api_version_string gettext.bindtextdomain("AutoGrouper",dt.configuration.config_dir.."/lua/locale/") local function _(msgid) return gettext.dgettext("AutoGrouper", msgid) @@ -174,7 +175,7 @@ if dt.gui.current_view().id == "lighttable" then else if not Ag.event_registered then dt.register_event( - "view-changed", + CURR_API_STRING >= "6.2.1" and "AutoGrouper", "view-changed" or "view-changed" , function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() diff --git a/contrib/HDRMerge.lua b/contrib/HDRMerge.lua index e9e5d035..b35ea1c4 100644 --- a/contrib/HDRMerge.lua +++ b/contrib/HDRMerge.lua @@ -50,6 +50,7 @@ local dsys = require 'lib/dtutils.system' local mod = 'module_HDRMerge' local os_path_seperator = '/' if dt.configuration.running_os == 'windows' then os_path_seperator = '\\' end +local CURR_API_STRING = dt.configuration.api_version_string -- Tell gettext where to find the .mo file translating messages for a particular domain local gettext = dt.gettext @@ -437,7 +438,7 @@ if dt.gui.current_view().id == "lighttable" then else if not HDRM.event_registered then dt.register_event( - "view-changed", + CURR_API_STRING >= "6.2.1" and "HDRmerge", "view-changed" or "view-changed" , function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() diff --git a/contrib/LabelsToTags.lua b/contrib/LabelsToTags.lua index 8c5e5a5e..5ab23959 100644 --- a/contrib/LabelsToTags.lua +++ b/contrib/LabelsToTags.lua @@ -60,6 +60,7 @@ ltt.module_installed = false ltt.event_registered = false local LIB_ID = "LabelsToTags" +local CURR_API_STRING = darktable.configuration.api_version_string -- Helper functions: BEGIN @@ -247,7 +248,7 @@ if darktable.gui.current_view().id == "lighttable" then else if not ltt.event_registered then darktable.register_event( - "view-changed", + CURR_API_STRING >= "6.2.1" and LIB_ID, "view-changed" or "view-changed" , function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() diff --git a/contrib/OpenInExplorer.lua b/contrib/OpenInExplorer.lua index f1430cf5..cfc7d573 100644 --- a/contrib/OpenInExplorer.lua +++ b/contrib/OpenInExplorer.lua @@ -65,6 +65,7 @@ end local act_os = dt.configuration.running_os local PS = act_os == "windows" and "\\" or "/" +local CURR_API_STRING = dt.configuration.api_version_string --Detect OS and quit if it is not supported. if act_os ~= "macos" and act_os ~= "windows" and act_os ~= "linux" then @@ -208,7 +209,7 @@ if act_os ~= "windows" then end dt.register_event( - "shortcut", + CURR_API_STRING >= "6.2.1" and "OpenInExplorer", "shortcut" or "shortcut", function(event, shortcut) open_in_fmanager() end, "OpenInExplorer" ) diff --git a/contrib/autostyle.lua b/contrib/autostyle.lua index 0b3891ff..a134b72b 100644 --- a/contrib/autostyle.lua +++ b/contrib/autostyle.lua @@ -42,6 +42,7 @@ local filelib = require "lib/dtutils.file" -- Forward declare the functions local autostyle_apply_one_image,autostyle_apply_one_image_event,autostyle_apply,exiftool_attribute,capture +local CURR_API_STRING = darktable.configuration.api_version_string -- Tested it with darktable 1.6.1 and darktable git from 2014-01-25 du.check_min_api_version("2.0.2", "autostyle") @@ -151,11 +152,12 @@ function get_stdout(cmd) end -- Registering events -darktable.register_event("shortcut",autostyle_apply, +darktable.register_event(CURR_API_STRING >= "6.2.1" and "autostyle", "shortcut" or "shortcut" ,autostyle_apply, "Apply your chosen style from exiftool tags") darktable.preferences.register("autostyle","exif_tag","string","Autostyle: EXIF_tag=value=>style","apply a style automatically if an EXIF_tag matches value. Find the tag with exiftool","") -darktable.register_event("post-import-image",autostyle_apply_one_image_event) +darktable.register_event(CURR_API_STRING >= "6.2.1" and "autostyle", "post-import-image" or "post-import-image" , + autostyle_apply_one_image_event) diff --git a/contrib/clear_GPS.lua b/contrib/clear_GPS.lua index 7570c8eb..08ed7f50 100644 --- a/contrib/clear_GPS.lua +++ b/contrib/clear_GPS.lua @@ -44,6 +44,7 @@ local gettext = dt.gettext local NaN = 0/0 du.check_min_api_version("3.0.0", "clear_GPS") +local CURR_API_STRING = dt.configuration.api_version_string -- Tell gettext where to find the .mo file translating messages for a particular domain @@ -70,7 +71,7 @@ dt.gui.libs.image.register_action( ) dt.register_event( - "shortcut", + CURR_API_STRING >= "6.2.1" and "clearGPS", "shortcut" or "shortcut" , function(event, shortcut) clear_GPS(dt.gui.action_images) end, _("Clear GPS data") ) diff --git a/contrib/copy_attach_detach_tags.lua b/contrib/copy_attach_detach_tags.lua index d4ab57d9..3af07d0b 100644 --- a/contrib/copy_attach_detach_tags.lua +++ b/contrib/copy_attach_detach_tags.lua @@ -43,6 +43,7 @@ local debug = require "darktable.debug" local gettext = dt.gettext du.check_min_api_version("3.0.0", "copy_attach_detach_tags") +local CURR_API_STRING = dt.configuration.api_version_string -- Tell gettext where to find the .mo file translating messages for a particular domain gettext.bindtextdomain("copy_attach_detach_tags",dt.configuration.config_dir.."/lua/locale/") @@ -233,7 +234,7 @@ if dt.gui.current_view().id == "lighttable" then else if not cadt.event_registered then dt.register_event( - "view-changed", + CURR_API_STRING >= "6.2.1" and "cadt", "view-changed" or "view-changed" , function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() @@ -246,22 +247,22 @@ end -- shortcut for copy -dt.register_event("shortcut", +dt.register_event(CURR_API_STRING >= "6.2.1" and "cadt_ct", "shortcut" or "shortcut" , mcopy_tags, _('copy tags from selected image(s)')) -- shortcut for attach -dt.register_event("shortcut", +dt.register_event(CURR_API_STRING >= "6.2.1" and "cadt_at", "shortcut" or "shortcut" , attach_tags, _('paste tags to selected image(s)')) -- shortcut for detaching tags -dt.register_event("shortcut", +dt.register_event(CURR_API_STRING >= "6.2.1" and "cadt_dt", "shortcut" or "shortcut" , detach_tags, _('remove tags from selected image(s)')) -- shortcut for replace tags -dt.register_event("shortcut", +dt.register_event(CURR_API_STRING >= "6.2.1" and "cadt_rt", "shortcut" or "shortcut" , replace_tags, _('replace tags from selected image(s)')) diff --git a/contrib/cr2hdr.lua b/contrib/cr2hdr.lua index 7f7a5bca..f7a5bcfd 100644 --- a/contrib/cr2hdr.lua +++ b/contrib/cr2hdr.lua @@ -37,6 +37,7 @@ local du = require "lib/dtutils" -- Tested with darktable 2.0.1 du.check_min_api_version("2.0.0", "cr2hdr") +local CURR_API_STRING = darktable.configuration.api_version_string local queue = {} local processed_files = {} @@ -107,8 +108,11 @@ local function convert_action_images(shortcut) convert_images() end -darktable.register_event("shortcut", convert_action_images, "Run cr2hdr (Magic Lantern DualISO converter) on selected images") -darktable.register_event("post-import-image", file_imported) -darktable.register_event("post-import-film", film_imported) +darktable.register_event(CURR_API_STRING >= "6.2.1" and "cr2hdr", "shortcut" or "shortcut" , + convert_action_images, "Run cr2hdr (Magic Lantern DualISO converter) on selected images") +darktable.register_event(CURR_API_STRING >= "6.2.1" and "cr2hdr", "post-import-image" or "post-import-image" , + file_imported) +darktable.register_event(CURR_API_STRING >= "6.2.1" and "cr2hdr", "post-import-film" or "post-import-film" , + film_imported) darktable.preferences.register("cr2hdr", "onimport", "bool", "Invoke on import", "If true then cr2hdr will try to proccess every file during importing. Warning: cr2hdr is quite slow even in figuring out on whether the file is Dual ISO or not.", false) diff --git a/contrib/exportLUT.lua b/contrib/exportLUT.lua index 9c7a1848..ca9288e7 100644 --- a/contrib/exportLUT.lua +++ b/contrib/exportLUT.lua @@ -34,6 +34,7 @@ local ds = require("lib/dtutils.system") local gettext = dt.gettext gettext.bindtextdomain("exportLUT",dt.configuration.config_dir.."/lua/locale/") +local CURR_API_STRING = dt.configuration.api_version_string local function _(msgid) return gettext.dgettext("exportLUT", msgid) @@ -161,7 +162,7 @@ if dt.gui.current_view().id == "lighttable" then else if not eL.event_registered then dt.register_event( - "view-changed", + CURR_API_STRING >= "6.2.1" and "exportLUT", "view-changed" or "view-changed" , function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() diff --git a/contrib/ext_editor.lua b/contrib/ext_editor.lua index ea957b58..7e90362b 100644 --- a/contrib/ext_editor.lua +++ b/contrib/ext_editor.lua @@ -75,6 +75,7 @@ local dtsys = require "lib/dtutils.system" -- module name local MODULE_NAME = "ext_editor" +local CURR_API_STRING = dt.configuration.api_version_string -- check API version @@ -416,7 +417,7 @@ if dt.gui.current_view().id == "lighttable" then else if not ee.event_registered then dt.register_event( - "view-changed", + CURR_API_STRING >= "6.2.1" and MODULE_NAME, "view-changed" or "view-changed" , function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() @@ -451,7 +452,8 @@ for i = MAX_EDITORS, 1, -1 do -- register the new shortcuts ------------------------------------------------- for i = 1, MAX_EDITORS do - dt.register_event("shortcut", program_shortcut, _("edit with program ")..string.format("%02d", i)) + dt.register_event(CURR_API_STRING >= "6.2.1" and MODULE_NAME .. i, "shortcut" or "shortcut" , + program_shortcut, _("edit with program ")..string.format("%02d", i)) end diff --git a/contrib/face_recognition.lua b/contrib/face_recognition.lua index 6d9b0c0e..d520453b 100644 --- a/contrib/face_recognition.lua +++ b/contrib/face_recognition.lua @@ -51,6 +51,7 @@ local gettext = dt.gettext local MODULE = "face_recognition" local PS = dt.configuration.running_os == "windows" and '\\' or '/' local OUTPUT = dt.configuration.tmp_dir .. PS .. "facerecognition.txt" +local CURR_API_STRING = dt.configuration.api_version_string -- namespace @@ -489,7 +490,7 @@ if dt.gui.current_view().id == "lighttable" then else if not fc.event_registered then dt.register_event( - "view-changed", + CURR_API_STRING >= "6.2.1" and MODULE, "view-changed" or "view-changed" , function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() diff --git a/contrib/fujifilm_dynamic_range.lua b/contrib/fujifilm_dynamic_range.lua index fb773fa8..7f541952 100644 --- a/contrib/fujifilm_dynamic_range.lua +++ b/contrib/fujifilm_dynamic_range.lua @@ -62,6 +62,7 @@ local du = require "lib/dtutils" local df = require "lib/dtutils.file" du.check_min_api_version("4.0.0", "fujifilm_dynamic_range") +local CURR_API_STRING = dt.configuration.api_version_string local function detect_dynamic_range(event, image) if image.exif_maker ~= "FUJIFILM" then @@ -104,6 +105,7 @@ local function detect_dynamic_range(event, image) dt.print_log("[fujifilm_dynamic_range] raw exposure bias " .. tostring(raf_result)) end -dt.register_event("post-import-image", detect_dynamic_range) +dt.register_event(CURR_API_STRING >= "6.2.1" and "fujifilm_dr", "post-import-image" or "post-import-image" , + detect_dynamic_range) dt.print_log("[fujifilm_dynamic_range] loaded") diff --git a/contrib/fujifilm_ratings.lua b/contrib/fujifilm_ratings.lua index 29ec406e..45da92df 100644 --- a/contrib/fujifilm_ratings.lua +++ b/contrib/fujifilm_ratings.lua @@ -29,6 +29,7 @@ local df = require "lib/dtutils.file" local gettext = dt.gettext du.check_min_api_version("4.0.0", "fujifilm_ratings") +local CURR_API_STRING = dt.configuration.api_version_string gettext.bindtextdomain("fujifilm_ratings", dt.configuration.config_dir.."/lua/locale/") @@ -66,6 +67,7 @@ local function detect_rating(event, image) end end -dt.register_event("post-import-image", detect_rating) +dt.register_event(CURR_API_STRING >= "6.2.1" and "fujifilm_rat", "post-import-image" or "post-import-image" , + detect_rating) print(_("fujifilm_ratings loaded.")) diff --git a/contrib/geoToolbox.lua b/contrib/geoToolbox.lua index 86dd533b..9edad19f 100644 --- a/contrib/geoToolbox.lua +++ b/contrib/geoToolbox.lua @@ -31,6 +31,7 @@ local df = require "lib/dtutils.file" local gettext = dt.gettext du.check_min_api_version("3.0.0", "geoToolbox") +local CURR_API_STRING = dt.configuration.api_version_string -- Tell gettext where to find the .mo file translating messages for a particular domain gettext.bindtextdomain("geoToolbox",dt.configuration.config_dir.."/lua/locale/") @@ -687,7 +688,7 @@ if dt.gui.current_view().id == "lighttable" then else if not gT.event_registered then dt.register_event( - "view-changed", + CURR_API_STRING >= "6.2.1" and "geoToolbox", "view-changed" or "view-chagned", function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() @@ -707,11 +708,15 @@ dt.preferences.register("geoToolbox", '' ) -- Register -dt.register_event("shortcut", print_calc_distance, _("Calculate the distance from latitude and longitude in km")) -dt.register_event("mouse-over-image-changed", toolbox_calc_distance) - -dt.register_event("shortcut", select_with_gps, _("Select all images with GPS information")) -dt.register_event("shortcut", select_without_gps, _("Select all images without GPS information")) +dt.register_event(CURR_API_STRING >= "6.2.1" and "geoToolbox_cd", "shortcut" or "shortcut" , + print_calc_distance, _("Calculate the distance from latitude and longitude in km")) +dt.register_event(CURR_API_STRING >= "6.2.1" and "geoToolbox", "mouse-over-image-changed" or "mouse-over-image-changed" , + toolbox_calc_distance) + +dt.register_event(CURR_API_STRING >= "6.2.1" and "geoToolbox_wg", "shortcut" or "shortcut" , + select_with_gps, _("Select all images with GPS information")) +dt.register_event(CURR_API_STRING >= "6.2.1" and "geoToolbox_ng", "shortcut" or "shortcut" , + select_without_gps, _("Select all images without GPS information")) -- vim: shiftwidth=2 expandtab tabstop=2 cindent syntax=lua -- kate: hl Lua; diff --git a/contrib/gpx_export.lua b/contrib/gpx_export.lua index cb76174c..45111ce0 100644 --- a/contrib/gpx_export.lua +++ b/contrib/gpx_export.lua @@ -28,6 +28,7 @@ local dl = require "lib/dtutils" local gettext = dt.gettext dl.check_min_api_version("3.0.0", "gpx-export") +local CURR_API_STRING = dt.configuration.api_version_string -- Tell gettext where to find the .mo file translating messages for a particular domain gettext.bindtextdomain("gpx_export",dt.configuration.config_dir.."/lua/locale/") @@ -173,7 +174,7 @@ if dt.gui.current_view().id == "lighttable" then else if not gpx.event_registered then dt.register_event( - "view-changed", + CURR_API_STRING >= "6.2.1" and "gpx_export", "view-changed" or "view-changed" , function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() diff --git a/contrib/image_time.lua b/contrib/image_time.lua index b285c61e..1af6f2d7 100644 --- a/contrib/image_time.lua +++ b/contrib/image_time.lua @@ -114,6 +114,7 @@ img_time.module_installed = false img_time.event_registered = false du.check_min_api_version("3.0.0", "image_time") +local CURR_API_STRING = dt.configuration.api_version_string -- Tell gettext where to find the .mo file translating messages for a particular domain @@ -551,7 +552,7 @@ if dt.gui.current_view().id == "lighttable" then else if not img_time.event_registered then dt.register_event( - "view-changed", + CURR_API_STRING >= "6.2.1" and "image_time", "view-changed" or "view-changed" , function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() diff --git a/contrib/photils.lua b/contrib/photils.lua index 361ba868..d303a7bd 100644 --- a/contrib/photils.lua +++ b/contrib/photils.lua @@ -44,6 +44,7 @@ local dtsys = require "lib/dtutils.system" local MODULE_NAME = "photils" du.check_min_api_version("5.0.0", MODULE_NAME) +local CURR_API_STRING = dt.configuration.api_version_string local PS = dt.configuration.running_os == "windows" and "\\" or "/" local gettext = dt.gettext gettext.bindtextdomain(MODULE_NAME, @@ -433,14 +434,15 @@ dt.preferences.register(MODULE_NAME, _("if enabled, the confidence value for each tag is displayed"), true) -dt.register_event("mouse-over-image-changed",PHOTILS.image_changed) +dt.register_event(CURR_API_STRING >= "6.2.1" and "photils", "mouse-over-image-changed" or "mouse-over-image-changed" , + PHOTILS.image_changed) if dt.gui.current_view().id == "lighttable" then install_module() else if not PHOTILS.event_registered then dt.register_event( - "view-changed", + CURR_API_STRING >= "6.2.1" and "photils", "view-changed" or "view-changed", function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() diff --git a/contrib/quicktag.lua b/contrib/quicktag.lua index 09f0be9d..8834b6e1 100644 --- a/contrib/quicktag.lua +++ b/contrib/quicktag.lua @@ -57,6 +57,7 @@ qt.widget_table = {} local gettext = dt.gettext du.check_min_api_version("3.0.0", "quicktag") +local CURR_API_STRING = dt.configuration.api_version_string -- Tell gettext where to find the .mo file translating messages for a particular domain gettext.bindtextdomain("quicktag",dt.configuration.config_dir.."/lua/locale/") @@ -256,7 +257,7 @@ if dt.gui.current_view().id == "lighttable" then else if not qt.event_registered then dt.register_event( - "view-changed", + CURR_API_STRING >= "6.2.1" and "quicktag", "view-changed" or "view-changed" , function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() @@ -269,7 +270,7 @@ end -- create shortcuts for i=1,qnr do - dt.register_event("shortcut", + dt.register_event(CURR_API_STRING >= "6.2.1" and "quicktag", "shortcut" or "shortcut" , function(event, shortcut) tagattach(tostring(quicktag_table[i])) end, string.format(_("quicktag %i"),i)) end diff --git a/contrib/rate_group.lua b/contrib/rate_group.lua index d820d94a..0f9dcc12 100644 --- a/contrib/rate_group.lua +++ b/contrib/rate_group.lua @@ -43,6 +43,7 @@ local du = require "lib/dtutils" -- added version check du.check_min_api_version("3.0.0", "rate_group") +local CURR_API_STRING = dt.configuration.api_version_string local function apply_rating(rating) local images = dt.gui.action_images @@ -59,30 +60,37 @@ local function apply_rating(rating) end end -dt.register_event("shortcut",function(event, shortcut) +dt.register_event(CURR_API_STRING >= "6.2.1" and "rg_reject", "shortcut" or "shortcut" , + function(event, shortcut) apply_rating(-1) end, "Reject group") -dt.register_event("shortcut",function(event, shortcut) +dt.register_event(CURR_API_STRING >= "6.2.1" and "rg0", "shortcut" or "shortcut", + function(event, shortcut) apply_rating(0) end, "Rate group 0") -dt.register_event("shortcut",function(event, shortcut) +dt.register_event(CURR_API_STRING >= "6.2.1" and "rg1", "shortcut" or "shortcut", + function(event, shortcut) apply_rating(1) end, "Rate group 1") -dt.register_event("shortcut",function(event, shortcut) +dt.register_event(CURR_API_STRING >= "6.2.1" and "rg2", "shortcut" or "shortcut", + function(event, shortcut) apply_rating(2) end, "Rate group 2") -dt.register_event("shortcut",function(event, shortcut) +dt.register_event(CURR_API_STRING >= "6.2.1" and "rg3", "shortcut" or "shortcut", + function(event, shortcut) apply_rating(3) end, "Rate group 3") -dt.register_event("shortcut",function(event, shortcut) +dt.register_event(CURR_API_STRING >= "6.2.1" and "rg4", "shortcut" or "shortcut", + function(event, shortcut) apply_rating(4) end, "Rate group 4") -dt.register_event("shortcut",function(event, shortcut) +dt.register_event(CURR_API_STRING >= "6.2.1" and "rg5", "shortcut" or "shortcut", + function(event, shortcut) apply_rating(5) end, "Rate group 5") diff --git a/contrib/rename-tags.lua b/contrib/rename-tags.lua index 5ccba2b9..23510dc1 100644 --- a/contrib/rename-tags.lua +++ b/contrib/rename-tags.lua @@ -34,6 +34,7 @@ local debug = require "darktable.debug" -- check API version du.check_min_api_version("3.0.0", "rename-tags") +local CURR_API_STRING = darktable.configuration.api_version_string local rt = {} rt.module_installed = false @@ -136,7 +137,7 @@ if darktable.gui.current_view().id == "lighttable" then else if not rt.event_registered then darktable.register_event( - "view-changed", + CURR_API_STRING >= "6.2.1" and "rename_tags", "view-changed" or "view-changed" , function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() diff --git a/contrib/slideshowMusic.lua b/contrib/slideshowMusic.lua index 921c6ffd..74e1acd8 100644 --- a/contrib/slideshowMusic.lua +++ b/contrib/slideshowMusic.lua @@ -31,6 +31,8 @@ local gettext = dt.gettext du.check_min_api_version("2.0.2", "slideshowMusic") +local CURR_API_STRING = dt.configuration.api_version_string + -- Tell gettext where to find the .mo file translating messages for a particular domain gettext.bindtextdomain("slideshowMusic",dt.configuration.config_dir.."/lua/locale/") @@ -76,4 +78,5 @@ dt.preferences.register("slideshowMusic", _("Plays music with rhythmbox if a slideshow starts"), true) -- Register -dt.register_event("view-changed",playSlideshowMusic) +dt.register_event(CURR_API_STRING >= "6.2.1" and "slideshow_music", "view-changed" or "view-changed" , + playSlideshowMusic) diff --git a/contrib/transfer_hierarchy.lua b/contrib/transfer_hierarchy.lua index 727595cf..b7f7bd4c 100755 --- a/contrib/transfer_hierarchy.lua +++ b/contrib/transfer_hierarchy.lua @@ -83,6 +83,7 @@ dtutils.check_min_api_version("5.0.0", LIB_ID) local MKDIR_COMMAND = darktable.configuration.running_os == "windows" and "mkdir " or "mkdir -p " local PATH_SEPARATOR = darktable.configuration.running_os == "windows" and "\\\\" or "/" local PATH_SEGMENT_REGEX = "(" .. PATH_SEPARATOR .. "?)([^" .. PATH_SEPARATOR .. "]+)" +local CURR_API_STRING = darktable.configuration.api_version_string unpack = unpack or table.unpack gmatch = string.gfind or string.gmatch @@ -366,7 +367,7 @@ if darktable.gui.current_view().id == "lighttable" then else if not th.event_registered then darktable.register_event( - "view-changed", + CURR_API_STRING >= "6.2.1" and LIB_ID, "view-changed" or "view-changed" , function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() diff --git a/examples/moduleExample.lua b/examples/moduleExample.lua index 76a992e0..0ef2cd64 100644 --- a/examples/moduleExample.lua +++ b/examples/moduleExample.lua @@ -34,6 +34,7 @@ local dt = require "darktable" local du = require "lib/dtutils" du.check_min_api_version("3.0.0", "moduleExample") +local CURR_API_STRING = dt.configuration.api_version_string -- translation @@ -147,7 +148,7 @@ else if not mE.event_registered then -- if we are not in lighttable view then register an event to signal when we might be -- https://www.darktable.org/lua-api/index.html#darktable_register_event dt.register_event( - "view-changed", -- we want to be informed when the view changes + CURR_API_STRING >= "6.2.1" and "mdouleExample", "view-changed" or "view-chagned" , -- we want to be informed when the view changes function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then -- if the view changes from darkroom to lighttable install_module() -- register the lib diff --git a/examples/multi_os.lua b/examples/multi_os.lua index 04acf56c..cbca5f69 100644 --- a/examples/multi_os.lua +++ b/examples/multi_os.lua @@ -62,6 +62,7 @@ local dt = require "darktable" local du = require "lib/dtutils" -- utilities local df = require "lib/dtutils.file" -- file utilities local dtsys = require "lib/dtutils.system" -- system utilities +local CURR_API_STRING = dt.configuration.api_version_string --[[ darktable is an international program, and it's user interface has been translated into @@ -240,7 +241,7 @@ dt.gui.libs.image.register_action( ]] dt.register_event( - "shortcut", + CURR_API_STRING >= "6.2.1" and "multi_os", "shortcut" or "shortcut" , function(event, shortcut) extract_embedded_jpeg(dt.gui.action_images) end, "extract embedded jpeg" ) diff --git a/official/copy_paste_metadata.lua b/official/copy_paste_metadata.lua index 00496119..bce3c2b3 100644 --- a/official/copy_paste_metadata.lua +++ b/official/copy_paste_metadata.lua @@ -30,6 +30,7 @@ local du = require "lib/dtutils" local gettext = dt.gettext du.check_min_api_version("3.0.0", "copy_paste_metadata") +local CURR_API_STRING = dt.configuration.api_version_string -- set this to "false" if you don't want to overwrite metadata fields -- (title, description, creator, publisher and rights) that are already set @@ -125,13 +126,13 @@ dt.gui.libs.image.register_action( ) dt.register_event( - "shortcut", + CURR_API_STRING >= "6.2.1" and "capmd1", "shortcut" or "shortcut" , function(event, shortcut) copy(dt.gui.action_images[1]) end, "copy metadata" ) dt.register_event( - "shortcut", + CURR_API_STRING >= "6.2.1" and "capmd2", "shortcut" or "shortcut" , function(event, shortcut) paste(dt.gui.action_images) end, "paste metadata" ) diff --git a/official/enfuse.lua b/official/enfuse.lua index a2ac3ec2..f8ce5aeb 100644 --- a/official/enfuse.lua +++ b/official/enfuse.lua @@ -38,6 +38,7 @@ local df = require "lib/dtutils.file" local dtsys = require "lib/dtutils.system" local PS = dt.configuration.running_os == "windows" and "\\" or "/" +local CURR_API_STRING = dt.configuration.api_version_string local gettext = dt.gettext @@ -268,7 +269,7 @@ if enfuse_installed then else if not enf.event_registered then dt.register_event( - "view-changed", + CURR_API_STRING >= "6.2.1" and "enfuse", "view-changed" or "view-chagned" , function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() diff --git a/official/generate_image_txt.lua b/official/generate_image_txt.lua index 0d343301..20b9d476 100644 --- a/official/generate_image_txt.lua +++ b/official/generate_image_txt.lua @@ -39,6 +39,7 @@ local du = require "lib/dtutils" require "darktable.debug" du.check_min_api_version("2.1.0", "generate_image_txt") +local CURR_API_STRING = dt.configuration.api_version_string dt.preferences.register("generate_image_txt", "enabled", @@ -65,7 +66,8 @@ end local command_setting = dt.preferences.read("generate_image_txt", "command", "string") check_command(command_setting) -dt.register_event("mouse-over-image-changed", function(event, img) +dt.register_event(CURR_API_STRING >= "6.2.1" and "gen_img_txt", "mouse-over-image-changed" or "mouse-over-image-chagned" , + function(event, img) -- no need to waste processing time if the image has a txt file already if not img or img.has_txt or not dt.preferences.read("generate_image_txt", "enabled", "bool") then return diff --git a/official/image_path_in_ui.lua b/official/image_path_in_ui.lua index 7459c520..130ea138 100644 --- a/official/image_path_in_ui.lua +++ b/official/image_path_in_ui.lua @@ -32,6 +32,7 @@ local dt = require "darktable" local du = require "lib/dtutils" du.check_min_api_version("2.0.0", "image_path_in_ui") +local CURR_API_STRING = dt.configuration.api_version_string local ipiu = {} ipiu.module_installed = false @@ -73,7 +74,7 @@ if dt.gui.current_view().id == "lighttable" then else if not ipiu.event_registered then dt.register_event( - "view-changed", + CURR_API_STRING >= "6.2.1" and "ipiu", "view-changed" or "view-changed" , function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() @@ -84,7 +85,7 @@ else end end -dt.register_event("mouse-over-image-changed",reset_widget); +dt.register_event(CURR_API_STRING >= "6.2.1" and "ipiu", "mouse-over-image-changed" or "mouse-over-image-changed" , reset_widget); -- -- vim: shiftwidth=2 expandtab tabstop=2 cindent syntax=lua diff --git a/official/import_filter_manager.lua b/official/import_filter_manager.lua index fafb2fe4..682593e5 100644 --- a/official/import_filter_manager.lua +++ b/official/import_filter_manager.lua @@ -34,6 +34,7 @@ local dt = require "darktable" local import_filter_list = {} local n_import_filters = 1 +local CURR_API_STRING = dt.configuration.api_version_string -- allow changing the filter from the preferences dt.preferences.register("import_filter_manager", "active_filter", "string", @@ -56,7 +57,7 @@ dt.gui.libs.import.register_widget(filter_dropdown) -- this is just a wrapper which calls the active import filter -dt.register_event("pre-import", function(event, images) +dt.register_event(CURR_API_STRING >= "6.2.1" and "ifm", "pre-import" or "pre-import" , function(event, images) local active_filter = dt.preferences.read("import_filter_manager", "active_filter", "string") if active_filter == "" then return end local callback = import_filter_list[active_filter] diff --git a/official/save_selection.lua b/official/save_selection.lua index 1d71ea97..b1abd4a6 100644 --- a/official/save_selection.lua +++ b/official/save_selection.lua @@ -37,21 +37,22 @@ local dt = require "darktable" local du = require "lib/dtutils" du.check_min_api_version("2.0.0", "save_selection") +local CURR_API_STRING = dt.configuration.api_version_string local buffer_count = 5 for i=1,buffer_count do local saved_selection - dt.register_event("shortcut",function() + dt.register_event(CURR_API_STRING >= "6.2.1" and "save_selection", "shortcut" or "shortcut" ,function() saved_selection = dt.gui.selection() end,"save to buffer "..i) - dt.register_event("shortcut",function() + dt.register_event(CURR_API_STRING >= "6.2.1" and "save_selection1", "shortcut" or "shortcut" ,function() dt.gui.selection(saved_selection) end,"restore from buffer "..i) end local bounce_buffer = {} -dt.register_event("shortcut",function() +dt.register_event(CURR_API_STRING >= "6.2.1" and "save_selection2", "shortcut" or "shortcut" ,function() bounce_buffer = dt.gui.selection(bounce_buffer) end,"switch selection with temporary buffer") diff --git a/tools/executable_manager.lua b/tools/executable_manager.lua index db65dfa5..dd672284 100644 --- a/tools/executable_manager.lua +++ b/tools/executable_manager.lua @@ -37,6 +37,7 @@ du.check_min_api_version("5.0.0", "executable_manager") local PS = dt.configuration.running_os == "windows" and "\\" or "/" local gettext = dt.gettext +local CURR_API_STRING = dt.configuration.api_version_string gettext.bindtextdomain("executable_manager",dt.configuration.config_dir.."/lua/locale/") @@ -214,7 +215,7 @@ if dt.gui.current_view().id == "lighttable" then else if not exec_man.event_registered then dt.register_event( - "view-changed", + CURR_API_STRING >= "6.2.1" and "executable_manager", "view-changed" or "view-changed" , function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() diff --git a/tools/script_manager.lua b/tools/script_manager.lua index 157f47bf..845bf75c 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -882,7 +882,7 @@ if dt.gui.current_view().id == "lighttable" then else if not sm.event_registered then dt.register_event( - "view-changed", + CURR_API_STRING >= "6.2.1" and "script_manager", "view-changed" or "view-changed" , function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() From 1460396d4ffcfd214352689e6b0c95df6d9fdb15 Mon Sep 17 00:00:00 2001 From: wpferguson Date: Thu, 4 Feb 2021 23:04:21 -0500 Subject: [PATCH 142/445] [contrib/select_untagged] Added check for API 6.2.2 and added name field to register_selection if it is --- contrib/select_untagged.lua | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/contrib/select_untagged.lua b/contrib/select_untagged.lua index 2db6dae6..2582b55a 100644 --- a/contrib/select_untagged.lua +++ b/contrib/select_untagged.lua @@ -26,6 +26,7 @@ du.check_min_api_version("3.0.0", "select_untagged") -- Tell gettext where to find the .mo file translating messages for a particular domain gettext.bindtextdomain("select_untagged",dt.configuration.config_dir.."/lua/locale/") +local CURR_API_STRING = dt.configuration.api_version_string local function _(msgid) return gettext.dgettext("select_untagged", msgid) @@ -62,4 +63,7 @@ local function select_untagged_images() dt.gui.selection(selection) end -dt.gui.libs.select.register_selection(_("select untagged"),select_untagged_images,_("select all images containing no tags or only tags added by darktable")) +dt.gui.libs.select.register_selection( + CURR_API_STRING >= "6.2.2" and "select_untagged", _("select untagged") or _("select untagged") , + select_untagged_images, + _("select all images containing no tags or only tags added by darktable")) From dc4938c377d10bed3a67f3771be7d7b73da8744f Mon Sep 17 00:00:00 2001 From: wpferguson Date: Tue, 9 Feb 2021 23:36:54 -0500 Subject: [PATCH 143/445] inline if didn't work. Replaced with full if/else --- contrib/select_untagged.lua | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/contrib/select_untagged.lua b/contrib/select_untagged.lua index 2582b55a..238c1ac2 100644 --- a/contrib/select_untagged.lua +++ b/contrib/select_untagged.lua @@ -63,7 +63,14 @@ local function select_untagged_images() dt.gui.selection(selection) end -dt.gui.libs.select.register_selection( - CURR_API_STRING >= "6.2.2" and "select_untagged", _("select untagged") or _("select untagged") , - select_untagged_images, - _("select all images containing no tags or only tags added by darktable")) +if CURR_API_STRING >= "6.2.2" then + dt.gui.libs.select.register_selection( + "select_untagged", _("select untagged"), + select_untagged_images, + _("select all images containing no tags or only tags added by darktable")) +else + dt.gui.libs.select.register_selection( + _("select untagged"), + select_untagged_images, + _("select all images containing no tags or only tags added by darktable")) +end \ No newline at end of file From b1498aa664a550e274cdc797e30ed56456379e4e Mon Sep 17 00:00:00 2001 From: wpferguson Date: Wed, 10 Feb 2021 00:18:48 -0500 Subject: [PATCH 144/445] inline if didn't work. Added intermediate register_event function in transition library --- contrib/AutoGrouper.lua | 3 +- contrib/HDRMerge.lua | 3 +- contrib/LabelsToTags.lua | 3 +- contrib/OpenInExplorer.lua | 3 +- contrib/autostyle.lua | 5 +-- contrib/clear_GPS.lua | 3 +- contrib/copy_attach_detach_tags.lua | 11 ++++--- contrib/cr2hdr.lua | 7 ++-- contrib/exportLUT.lua | 3 +- contrib/ext_editor.lua | 5 +-- contrib/face_recognition.lua | 3 +- contrib/fujifilm_dynamic_range.lua | 3 +- contrib/fujifilm_ratings.lua | 3 +- contrib/geoToolbox.lua | 11 ++++--- contrib/gpx_export.lua | 3 +- contrib/image_time.lua | 3 +- contrib/photils.lua | 5 +-- contrib/quicktag.lua | 5 +-- contrib/rate_group.lua | 15 +++++---- contrib/rename-tags.lua | 3 +- contrib/slideshowMusic.lua | 3 +- contrib/transfer_hierarchy.lua | 3 +- examples/moduleExample.lua | 3 +- examples/multi_os.lua | 3 +- lib/darktable_transition.lua | 51 +++++++++++++++++++++++++++++ official/copy_paste_metadata.lua | 5 +-- official/enfuse.lua | 3 +- official/generate_image_txt.lua | 3 +- official/image_path_in_ui.lua | 5 +-- official/import_filter_manager.lua | 3 +- official/save_selection.lua | 8 ++--- tools/executable_manager.lua | 3 +- tools/script_manager.lua | 3 +- 33 files changed, 139 insertions(+), 57 deletions(-) create mode 100644 lib/darktable_transition.lua diff --git a/contrib/AutoGrouper.lua b/contrib/AutoGrouper.lua index 0f69e5d2..849b8818 100644 --- a/contrib/AutoGrouper.lua +++ b/contrib/AutoGrouper.lua @@ -37,6 +37,7 @@ selected images, the other button performs grouping on the entire active collect ]] local dt = require "darktable" + require "lib/darktable_transition" local MOD = 'autogrouper' local gettext = dt.gettext -- Tell gettext where to find the .mo file translating messages for a particular domain @@ -175,7 +176,7 @@ if dt.gui.current_view().id == "lighttable" then else if not Ag.event_registered then dt.register_event( - CURR_API_STRING >= "6.2.1" and "AutoGrouper", "view-changed" or "view-changed" , + "AutoGrouper", "view-changed", function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() diff --git a/contrib/HDRMerge.lua b/contrib/HDRMerge.lua index b35ea1c4..5c1635ab 100644 --- a/contrib/HDRMerge.lua +++ b/contrib/HDRMerge.lua @@ -46,6 +46,7 @@ Select a style, whether you want tags to be copied from the original, and any ad local dt = require 'darktable' local df = require 'lib/dtutils.file' + require "lib/darktable_transition" local dsys = require 'lib/dtutils.system' local mod = 'module_HDRMerge' local os_path_seperator = '/' @@ -438,7 +439,7 @@ if dt.gui.current_view().id == "lighttable" then else if not HDRM.event_registered then dt.register_event( - CURR_API_STRING >= "6.2.1" and "HDRmerge", "view-changed" or "view-changed" , + "HDRmerge", "view-changed", function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() diff --git a/contrib/LabelsToTags.lua b/contrib/LabelsToTags.lua index 5ab23959..e2dc5c42 100644 --- a/contrib/LabelsToTags.lua +++ b/contrib/LabelsToTags.lua @@ -49,6 +49,7 @@ local darktable = require("darktable") local du = require "lib/dtutils" + require "lib/darktable_transition" du.check_min_api_version("3.0.0", "LabelsToTags") @@ -248,7 +249,7 @@ if darktable.gui.current_view().id == "lighttable" then else if not ltt.event_registered then darktable.register_event( - CURR_API_STRING >= "6.2.1" and LIB_ID, "view-changed" or "view-changed" , + LIB_ID, "view-changed", function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() diff --git a/contrib/OpenInExplorer.lua b/contrib/OpenInExplorer.lua index cfc7d573..72ec15dc 100644 --- a/contrib/OpenInExplorer.lua +++ b/contrib/OpenInExplorer.lua @@ -50,6 +50,7 @@ As an alternative option you can choose to show the image file names as symbolic local dt = require "darktable" local du = require "lib/dtutils" local df = require "lib/dtutils.file" + require "lib/darktable_transition" local dsys = require "lib/dtutils.system" local gettext = dt.gettext @@ -209,7 +210,7 @@ if act_os ~= "windows" then end dt.register_event( - CURR_API_STRING >= "6.2.1" and "OpenInExplorer", "shortcut" or "shortcut", + "OpenInExplorer", "shortcut", function(event, shortcut) open_in_fmanager() end, "OpenInExplorer" ) diff --git a/contrib/autostyle.lua b/contrib/autostyle.lua index a134b72b..fc726a62 100644 --- a/contrib/autostyle.lua +++ b/contrib/autostyle.lua @@ -38,6 +38,7 @@ GPLv2 local darktable = require "darktable" local du = require "lib/dtutils" + require "lib/darktable_transition" local filelib = require "lib/dtutils.file" -- Forward declare the functions @@ -152,12 +153,12 @@ function get_stdout(cmd) end -- Registering events -darktable.register_event(CURR_API_STRING >= "6.2.1" and "autostyle", "shortcut" or "shortcut" ,autostyle_apply, +darktable.register_event("autostyle", "shortcut", autostyle_apply, "Apply your chosen style from exiftool tags") darktable.preferences.register("autostyle","exif_tag","string","Autostyle: EXIF_tag=value=>style","apply a style automatically if an EXIF_tag matches value. Find the tag with exiftool","") -darktable.register_event(CURR_API_STRING >= "6.2.1" and "autostyle", "post-import-image" or "post-import-image" , +darktable.register_event("autostyle", "post-import-image", autostyle_apply_one_image_event) diff --git a/contrib/clear_GPS.lua b/contrib/clear_GPS.lua index 08ed7f50..58404f9b 100644 --- a/contrib/clear_GPS.lua +++ b/contrib/clear_GPS.lua @@ -38,6 +38,7 @@ local dt = require "darktable" local du = require "lib/dtutils" + require "lib/darktable_transition" local gettext = dt.gettext -- not a number @@ -71,7 +72,7 @@ dt.gui.libs.image.register_action( ) dt.register_event( - CURR_API_STRING >= "6.2.1" and "clearGPS", "shortcut" or "shortcut" , + "clearGPS", "shortcut", function(event, shortcut) clear_GPS(dt.gui.action_images) end, _("Clear GPS data") ) diff --git a/contrib/copy_attach_detach_tags.lua b/contrib/copy_attach_detach_tags.lua index 3af07d0b..6f2b9364 100644 --- a/contrib/copy_attach_detach_tags.lua +++ b/contrib/copy_attach_detach_tags.lua @@ -39,6 +39,7 @@ USAGE local dt = require "darktable" local du = require "lib/dtutils" local debug = require "darktable.debug" + require "lib/darktable_transition" local gettext = dt.gettext @@ -234,7 +235,7 @@ if dt.gui.current_view().id == "lighttable" then else if not cadt.event_registered then dt.register_event( - CURR_API_STRING >= "6.2.1" and "cadt", "view-changed" or "view-changed" , + "cadt", "view-changed", function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() @@ -247,22 +248,22 @@ end -- shortcut for copy -dt.register_event(CURR_API_STRING >= "6.2.1" and "cadt_ct", "shortcut" or "shortcut" , +dt.register_event("cadt_ct", "shortcut", mcopy_tags, _('copy tags from selected image(s)')) -- shortcut for attach -dt.register_event(CURR_API_STRING >= "6.2.1" and "cadt_at", "shortcut" or "shortcut" , +dt.register_event("cadt_at", "shortcut", attach_tags, _('paste tags to selected image(s)')) -- shortcut for detaching tags -dt.register_event(CURR_API_STRING >= "6.2.1" and "cadt_dt", "shortcut" or "shortcut" , +dt.register_event("cadt_dt", "shortcut", detach_tags, _('remove tags from selected image(s)')) -- shortcut for replace tags -dt.register_event(CURR_API_STRING >= "6.2.1" and "cadt_rt", "shortcut" or "shortcut" , +dt.register_event("cadt_rt", "shortcut", replace_tags, _('replace tags from selected image(s)')) diff --git a/contrib/cr2hdr.lua b/contrib/cr2hdr.lua index f7a5bcfd..c27082e6 100644 --- a/contrib/cr2hdr.lua +++ b/contrib/cr2hdr.lua @@ -34,6 +34,7 @@ USAGE local darktable = require "darktable" local du = require "lib/dtutils" + require "lib/darktable_transition" -- Tested with darktable 2.0.1 du.check_min_api_version("2.0.0", "cr2hdr") @@ -108,11 +109,11 @@ local function convert_action_images(shortcut) convert_images() end -darktable.register_event(CURR_API_STRING >= "6.2.1" and "cr2hdr", "shortcut" or "shortcut" , +darktable.register_event("cr2hdr", "shortcut", convert_action_images, "Run cr2hdr (Magic Lantern DualISO converter) on selected images") -darktable.register_event(CURR_API_STRING >= "6.2.1" and "cr2hdr", "post-import-image" or "post-import-image" , +darktable.register_event("cr2hdr", "post-import-image", file_imported) -darktable.register_event(CURR_API_STRING >= "6.2.1" and "cr2hdr", "post-import-film" or "post-import-film" , +darktable.register_event("cr2hdr", "post-import-film", film_imported) darktable.preferences.register("cr2hdr", "onimport", "bool", "Invoke on import", "If true then cr2hdr will try to proccess every file during importing. Warning: cr2hdr is quite slow even in figuring out on whether the file is Dual ISO or not.", false) diff --git a/contrib/exportLUT.lua b/contrib/exportLUT.lua index ca9288e7..4b039a87 100644 --- a/contrib/exportLUT.lua +++ b/contrib/exportLUT.lua @@ -30,6 +30,7 @@ local dt = require "darktable" local du = require "lib/dtutils" local df = require("lib/dtutils.file") local ds = require("lib/dtutils.system") + require "lib/darktable_transition" local gettext = dt.gettext @@ -162,7 +163,7 @@ if dt.gui.current_view().id == "lighttable" then else if not eL.event_registered then dt.register_event( - CURR_API_STRING >= "6.2.1" and "exportLUT", "view-changed" or "view-changed" , + "exportLUT", "view-changed", function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() diff --git a/contrib/ext_editor.lua b/contrib/ext_editor.lua index 7e90362b..2df2237e 100644 --- a/contrib/ext_editor.lua +++ b/contrib/ext_editor.lua @@ -70,6 +70,7 @@ local dt = require "darktable" local du = require "lib/dtutils" local df = require "lib/dtutils.file" + require "lib/darktable_transition" local dtsys = require "lib/dtutils.system" @@ -417,7 +418,7 @@ if dt.gui.current_view().id == "lighttable" then else if not ee.event_registered then dt.register_event( - CURR_API_STRING >= "6.2.1" and MODULE_NAME, "view-changed" or "view-changed" , + MODULE_NAME, "view-changed", function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() @@ -452,7 +453,7 @@ for i = MAX_EDITORS, 1, -1 do -- register the new shortcuts ------------------------------------------------- for i = 1, MAX_EDITORS do - dt.register_event(CURR_API_STRING >= "6.2.1" and MODULE_NAME .. i, "shortcut" or "shortcut" , + dt.register_event(MODULE_NAME .. i, "shortcut", program_shortcut, _("edit with program ")..string.format("%02d", i)) end diff --git a/contrib/face_recognition.lua b/contrib/face_recognition.lua index d520453b..77cd2abb 100644 --- a/contrib/face_recognition.lua +++ b/contrib/face_recognition.lua @@ -44,6 +44,7 @@ local dt = require "darktable" local du = require "lib/dtutils" local df = require "lib/dtutils.file" local dtsys = require "lib/dtutils.system" + require "lib/darktable_transition" local gettext = dt.gettext -- constants @@ -490,7 +491,7 @@ if dt.gui.current_view().id == "lighttable" then else if not fc.event_registered then dt.register_event( - CURR_API_STRING >= "6.2.1" and MODULE, "view-changed" or "view-changed" , + MODULE, "view-changed", function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() diff --git a/contrib/fujifilm_dynamic_range.lua b/contrib/fujifilm_dynamic_range.lua index 7f541952..49866755 100644 --- a/contrib/fujifilm_dynamic_range.lua +++ b/contrib/fujifilm_dynamic_range.lua @@ -60,6 +60,7 @@ cameras may behave in other ways. local dt = require "darktable" local du = require "lib/dtutils" local df = require "lib/dtutils.file" + require "lib/darktable_transition" du.check_min_api_version("4.0.0", "fujifilm_dynamic_range") local CURR_API_STRING = dt.configuration.api_version_string @@ -105,7 +106,7 @@ local function detect_dynamic_range(event, image) dt.print_log("[fujifilm_dynamic_range] raw exposure bias " .. tostring(raf_result)) end -dt.register_event(CURR_API_STRING >= "6.2.1" and "fujifilm_dr", "post-import-image" or "post-import-image" , +dt.register_event("fujifilm_dr", "post-import-image", detect_dynamic_range) dt.print_log("[fujifilm_dynamic_range] loaded") diff --git a/contrib/fujifilm_ratings.lua b/contrib/fujifilm_ratings.lua index 45da92df..05319d4c 100644 --- a/contrib/fujifilm_ratings.lua +++ b/contrib/fujifilm_ratings.lua @@ -26,6 +26,7 @@ Dependencies: local dt = require "darktable" local du = require "lib/dtutils" local df = require "lib/dtutils.file" + require "lib/darktable_transition" local gettext = dt.gettext du.check_min_api_version("4.0.0", "fujifilm_ratings") @@ -67,7 +68,7 @@ local function detect_rating(event, image) end end -dt.register_event(CURR_API_STRING >= "6.2.1" and "fujifilm_rat", "post-import-image" or "post-import-image" , +dt.register_event("fujifilm_rat", "post-import-image", detect_rating) print(_("fujifilm_ratings loaded.")) diff --git a/contrib/geoToolbox.lua b/contrib/geoToolbox.lua index 9edad19f..cdbc1c0a 100644 --- a/contrib/geoToolbox.lua +++ b/contrib/geoToolbox.lua @@ -28,6 +28,7 @@ require "geoToolbox" local dt = require "darktable" local du = require "lib/dtutils" local df = require "lib/dtutils.file" + require "lib/darktable_transition" local gettext = dt.gettext du.check_min_api_version("3.0.0", "geoToolbox") @@ -688,7 +689,7 @@ if dt.gui.current_view().id == "lighttable" then else if not gT.event_registered then dt.register_event( - CURR_API_STRING >= "6.2.1" and "geoToolbox", "view-changed" or "view-chagned", + "geoToolbox", "view-changed", function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() @@ -708,14 +709,14 @@ dt.preferences.register("geoToolbox", '' ) -- Register -dt.register_event(CURR_API_STRING >= "6.2.1" and "geoToolbox_cd", "shortcut" or "shortcut" , +dt.register_event("geoToolbox_cd", "shortcut", print_calc_distance, _("Calculate the distance from latitude and longitude in km")) -dt.register_event(CURR_API_STRING >= "6.2.1" and "geoToolbox", "mouse-over-image-changed" or "mouse-over-image-changed" , +dt.register_event("geoToolbox", "mouse-over-image-changed", toolbox_calc_distance) -dt.register_event(CURR_API_STRING >= "6.2.1" and "geoToolbox_wg", "shortcut" or "shortcut" , +dt.register_event("geoToolbox_wg", "shortcut", select_with_gps, _("Select all images with GPS information")) -dt.register_event(CURR_API_STRING >= "6.2.1" and "geoToolbox_ng", "shortcut" or "shortcut" , +dt.register_event("geoToolbox_ng", "shortcut", select_without_gps, _("Select all images without GPS information")) -- vim: shiftwidth=2 expandtab tabstop=2 cindent syntax=lua diff --git a/contrib/gpx_export.lua b/contrib/gpx_export.lua index 45111ce0..58e4147a 100644 --- a/contrib/gpx_export.lua +++ b/contrib/gpx_export.lua @@ -25,6 +25,7 @@ For each source folder, a separate is generated in the gpx file. local dt = require "darktable" local df = require "lib/dtutils.file" local dl = require "lib/dtutils" + require "lib/darktable_transition" local gettext = dt.gettext dl.check_min_api_version("3.0.0", "gpx-export") @@ -174,7 +175,7 @@ if dt.gui.current_view().id == "lighttable" then else if not gpx.event_registered then dt.register_event( - CURR_API_STRING >= "6.2.1" and "gpx_export", "view-changed" or "view-changed" , + "gpx_export", "view-changed", function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() diff --git a/contrib/image_time.lua b/contrib/image_time.lua index 1af6f2d7..0f09c2d0 100644 --- a/contrib/image_time.lua +++ b/contrib/image_time.lua @@ -107,6 +107,7 @@ local dt = require "darktable" local du = require "lib/dtutils" local df = require "lib/dtutils.file" local ds = require "lib/dtutils.string" + require "lib/darktable_transition" local gettext = dt.gettext local img_time = {} @@ -552,7 +553,7 @@ if dt.gui.current_view().id == "lighttable" then else if not img_time.event_registered then dt.register_event( - CURR_API_STRING >= "6.2.1" and "image_time", "view-changed" or "view-changed" , + "image_time", "view-changed", function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() diff --git a/contrib/photils.lua b/contrib/photils.lua index d303a7bd..69829be7 100644 --- a/contrib/photils.lua +++ b/contrib/photils.lua @@ -39,6 +39,7 @@ local dt = require "darktable" local du = require "lib/dtutils" local df = require "lib/dtutils.file" + require "lib/darktable_transition" local dtsys = require "lib/dtutils.system" local MODULE_NAME = "photils" @@ -434,7 +435,7 @@ dt.preferences.register(MODULE_NAME, _("if enabled, the confidence value for each tag is displayed"), true) -dt.register_event(CURR_API_STRING >= "6.2.1" and "photils", "mouse-over-image-changed" or "mouse-over-image-changed" , +dt.register_event("photils", "mouse-over-image-changed", PHOTILS.image_changed) if dt.gui.current_view().id == "lighttable" then @@ -442,7 +443,7 @@ if dt.gui.current_view().id == "lighttable" then else if not PHOTILS.event_registered then dt.register_event( - CURR_API_STRING >= "6.2.1" and "photils", "view-changed" or "view-changed", + "photils", "view-changed", function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() diff --git a/contrib/quicktag.lua b/contrib/quicktag.lua index 8834b6e1..34053c96 100644 --- a/contrib/quicktag.lua +++ b/contrib/quicktag.lua @@ -45,6 +45,7 @@ USAGE local dt = require "darktable" local du = require "lib/dtutils" + require "lib/darktable_transition" local debug = require "darktable.debug" local qt = {} @@ -257,7 +258,7 @@ if dt.gui.current_view().id == "lighttable" then else if not qt.event_registered then dt.register_event( - CURR_API_STRING >= "6.2.1" and "quicktag", "view-changed" or "view-changed" , + "quicktag", "view-changed", function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() @@ -270,7 +271,7 @@ end -- create shortcuts for i=1,qnr do - dt.register_event(CURR_API_STRING >= "6.2.1" and "quicktag", "shortcut" or "shortcut" , + dt.register_event("quicktag", "shortcut", function(event, shortcut) tagattach(tostring(quicktag_table[i])) end, string.format(_("quicktag %i"),i)) end diff --git a/contrib/rate_group.lua b/contrib/rate_group.lua index 0f9dcc12..80fb4a62 100644 --- a/contrib/rate_group.lua +++ b/contrib/rate_group.lua @@ -40,6 +40,7 @@ local dt = require "darktable" local du = require "lib/dtutils" + require "lib/darktable_transition" -- added version check du.check_min_api_version("3.0.0", "rate_group") @@ -60,37 +61,37 @@ local function apply_rating(rating) end end -dt.register_event(CURR_API_STRING >= "6.2.1" and "rg_reject", "shortcut" or "shortcut" , +dt.register_event("rg_reject", "shortcut", function(event, shortcut) apply_rating(-1) end, "Reject group") -dt.register_event(CURR_API_STRING >= "6.2.1" and "rg0", "shortcut" or "shortcut", +dt.register_event("rg0", "shortcut", function(event, shortcut) apply_rating(0) end, "Rate group 0") -dt.register_event(CURR_API_STRING >= "6.2.1" and "rg1", "shortcut" or "shortcut", +dt.register_event("rg1", "shortcut", function(event, shortcut) apply_rating(1) end, "Rate group 1") -dt.register_event(CURR_API_STRING >= "6.2.1" and "rg2", "shortcut" or "shortcut", +dt.register_event("rg2", "shortcut", function(event, shortcut) apply_rating(2) end, "Rate group 2") -dt.register_event(CURR_API_STRING >= "6.2.1" and "rg3", "shortcut" or "shortcut", +dt.register_event("rg3", "shortcut", function(event, shortcut) apply_rating(3) end, "Rate group 3") -dt.register_event(CURR_API_STRING >= "6.2.1" and "rg4", "shortcut" or "shortcut", +dt.register_event("rg4", "shortcut", function(event, shortcut) apply_rating(4) end, "Rate group 4") -dt.register_event(CURR_API_STRING >= "6.2.1" and "rg5", "shortcut" or "shortcut", +dt.register_event("rg5", "shortcut", function(event, shortcut) apply_rating(5) end, "Rate group 5") diff --git a/contrib/rename-tags.lua b/contrib/rename-tags.lua index 23510dc1..e8a5c9e3 100644 --- a/contrib/rename-tags.lua +++ b/contrib/rename-tags.lua @@ -30,6 +30,7 @@ Changes local darktable = require "darktable" local du = require "lib/dtutils" + require "lib/darktable_transition" local debug = require "darktable.debug" -- check API version @@ -137,7 +138,7 @@ if darktable.gui.current_view().id == "lighttable" then else if not rt.event_registered then darktable.register_event( - CURR_API_STRING >= "6.2.1" and "rename_tags", "view-changed" or "view-changed" , + "rename_tags", "view-changed", function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() diff --git a/contrib/slideshowMusic.lua b/contrib/slideshowMusic.lua index 74e1acd8..ff216af8 100644 --- a/contrib/slideshowMusic.lua +++ b/contrib/slideshowMusic.lua @@ -27,6 +27,7 @@ USAGE local dt = require "darktable" local du = require "lib/dtutils" local df = require "lib/dtutils.file" + require "lib/darktable_transition" local gettext = dt.gettext du.check_min_api_version("2.0.2", "slideshowMusic") @@ -78,5 +79,5 @@ dt.preferences.register("slideshowMusic", _("Plays music with rhythmbox if a slideshow starts"), true) -- Register -dt.register_event(CURR_API_STRING >= "6.2.1" and "slideshow_music", "view-changed" or "view-changed" , +dt.register_event("slideshow_music", "view-changed", playSlideshowMusic) diff --git a/contrib/transfer_hierarchy.lua b/contrib/transfer_hierarchy.lua index b7f7bd4c..03c1523f 100755 --- a/contrib/transfer_hierarchy.lua +++ b/contrib/transfer_hierarchy.lua @@ -76,6 +76,7 @@ local darktable = require("darktable") local dtutils = require("lib/dtutils") local dtutils_file = require("lib/dtutils.file") local dtutils_system = require("lib/dtutils.system") + require "lib/darktable_transition" local LIB_ID = "transfer_hierarchy" dtutils.check_min_api_version("5.0.0", LIB_ID) @@ -367,7 +368,7 @@ if darktable.gui.current_view().id == "lighttable" then else if not th.event_registered then darktable.register_event( - CURR_API_STRING >= "6.2.1" and LIB_ID, "view-changed" or "view-changed" , + LIB_ID, "view-changed", function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() diff --git a/examples/moduleExample.lua b/examples/moduleExample.lua index 0ef2cd64..b778dca2 100644 --- a/examples/moduleExample.lua +++ b/examples/moduleExample.lua @@ -32,6 +32,7 @@ https://www.darktable.org/lua-api/index.html.php#darktable_new_widget local dt = require "darktable" local du = require "lib/dtutils" + require "lib/darktable_transition" du.check_min_api_version("3.0.0", "moduleExample") local CURR_API_STRING = dt.configuration.api_version_string @@ -148,7 +149,7 @@ else if not mE.event_registered then -- if we are not in lighttable view then register an event to signal when we might be -- https://www.darktable.org/lua-api/index.html#darktable_register_event dt.register_event( - CURR_API_STRING >= "6.2.1" and "mdouleExample", "view-changed" or "view-chagned" , -- we want to be informed when the view changes + "mdouleExample", "view-changed", -- we want to be informed when the view changes function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then -- if the view changes from darkroom to lighttable install_module() -- register the lib diff --git a/examples/multi_os.lua b/examples/multi_os.lua index cbca5f69..6ab356bf 100644 --- a/examples/multi_os.lua +++ b/examples/multi_os.lua @@ -52,6 +52,7 @@ ]] local dt = require "darktable" + require "lib/darktable_transition" --[[ require "lib/..." provides access to functions that have been pulled from various @@ -241,7 +242,7 @@ dt.gui.libs.image.register_action( ]] dt.register_event( - CURR_API_STRING >= "6.2.1" and "multi_os", "shortcut" or "shortcut" , + "multi_os", "shortcut", function(event, shortcut) extract_embedded_jpeg(dt.gui.action_images) end, "extract embedded jpeg" ) diff --git a/lib/darktable_transition.lua b/lib/darktable_transition.lua new file mode 100644 index 00000000..da5a4211 --- /dev/null +++ b/lib/darktable_transition.lua @@ -0,0 +1,51 @@ +--[[ + + darktable_transition.lua - temporary library to help with API transition + + Copyright (C) 2016 Bill Ferguson . + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +]] +--[[ + darktable_transition - routines to maintain compatibility with new and previous API versions + +]] + +local dt +for k,v in pairs(package.loaded) do + if string.match(k, "darktable") then + dt = v + break + end +end + +if dt then + dt.orig_register_event = dt.register_event + + function dt.register_event(name, event, callback, tooltip) + if dt.configuration.api_version_string >= "6.2.1" then + if tooltip then + dt.orig_register_event(name, event, callback, tooltip) + else + dt.orig_register_event(name, event, callback) + end + else + if tooltip then + dt.orig_register_event(event, callback, tooltip) + else + dt.orig_register_event(event, callback) + end + end + end +end diff --git a/official/copy_paste_metadata.lua b/official/copy_paste_metadata.lua index bce3c2b3..1db3d622 100644 --- a/official/copy_paste_metadata.lua +++ b/official/copy_paste_metadata.lua @@ -27,6 +27,7 @@ USAGE local dt = require "darktable" local du = require "lib/dtutils" + require "lib/darktable_transition" local gettext = dt.gettext du.check_min_api_version("3.0.0", "copy_paste_metadata") @@ -126,13 +127,13 @@ dt.gui.libs.image.register_action( ) dt.register_event( - CURR_API_STRING >= "6.2.1" and "capmd1", "shortcut" or "shortcut" , + "capmd1", "shortcut", function(event, shortcut) copy(dt.gui.action_images[1]) end, "copy metadata" ) dt.register_event( - CURR_API_STRING >= "6.2.1" and "capmd2", "shortcut" or "shortcut" , + "capmd2", "shortcut", function(event, shortcut) paste(dt.gui.action_images) end, "paste metadata" ) diff --git a/official/enfuse.lua b/official/enfuse.lua index f8ce5aeb..1f494d90 100644 --- a/official/enfuse.lua +++ b/official/enfuse.lua @@ -36,6 +36,7 @@ local dt = require "darktable" local du = require "lib/dtutils" local df = require "lib/dtutils.file" local dtsys = require "lib/dtutils.system" + require "lib/darktable_transition" local PS = dt.configuration.running_os == "windows" and "\\" or "/" local CURR_API_STRING = dt.configuration.api_version_string @@ -269,7 +270,7 @@ if enfuse_installed then else if not enf.event_registered then dt.register_event( - CURR_API_STRING >= "6.2.1" and "enfuse", "view-changed" or "view-chagned" , + "enfuse", "view-changed", function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() diff --git a/official/generate_image_txt.lua b/official/generate_image_txt.lua index 20b9d476..b4ea4756 100644 --- a/official/generate_image_txt.lua +++ b/official/generate_image_txt.lua @@ -36,6 +36,7 @@ USAGE local dt = require "darktable" local du = require "lib/dtutils" + require "lib/darktable_transition" require "darktable.debug" du.check_min_api_version("2.1.0", "generate_image_txt") @@ -66,7 +67,7 @@ end local command_setting = dt.preferences.read("generate_image_txt", "command", "string") check_command(command_setting) -dt.register_event(CURR_API_STRING >= "6.2.1" and "gen_img_txt", "mouse-over-image-changed" or "mouse-over-image-chagned" , +dt.register_event("gen_img_txt", "mouse-over-image-changed", function(event, img) -- no need to waste processing time if the image has a txt file already if not img or img.has_txt or not dt.preferences.read("generate_image_txt", "enabled", "bool") then diff --git a/official/image_path_in_ui.lua b/official/image_path_in_ui.lua index 130ea138..d98e5710 100644 --- a/official/image_path_in_ui.lua +++ b/official/image_path_in_ui.lua @@ -30,6 +30,7 @@ This plugin will add a widget at the bottom of the left column in lighttable mod ]] local dt = require "darktable" local du = require "lib/dtutils" + require "lib/darktable_transition" du.check_min_api_version("2.0.0", "image_path_in_ui") local CURR_API_STRING = dt.configuration.api_version_string @@ -74,7 +75,7 @@ if dt.gui.current_view().id == "lighttable" then else if not ipiu.event_registered then dt.register_event( - CURR_API_STRING >= "6.2.1" and "ipiu", "view-changed" or "view-changed" , + "ipiu", "view-changed", function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() @@ -85,7 +86,7 @@ else end end -dt.register_event(CURR_API_STRING >= "6.2.1" and "ipiu", "mouse-over-image-changed" or "mouse-over-image-changed" , reset_widget); +dt.register_event("ipiu", "mouse-over-image-changed", reset_widget); -- -- vim: shiftwidth=2 expandtab tabstop=2 cindent syntax=lua diff --git a/official/import_filter_manager.lua b/official/import_filter_manager.lua index 682593e5..74b50276 100644 --- a/official/import_filter_manager.lua +++ b/official/import_filter_manager.lua @@ -31,6 +31,7 @@ USAGE ]] local dt = require "darktable" + require "lib/darktable_transition" local import_filter_list = {} local n_import_filters = 1 @@ -57,7 +58,7 @@ dt.gui.libs.import.register_widget(filter_dropdown) -- this is just a wrapper which calls the active import filter -dt.register_event(CURR_API_STRING >= "6.2.1" and "ifm", "pre-import" or "pre-import" , function(event, images) +dt.register_event("ifm", "pre-import", function(event, images) local active_filter = dt.preferences.read("import_filter_manager", "active_filter", "string") if active_filter == "" then return end local callback = import_filter_list[active_filter] diff --git a/official/save_selection.lua b/official/save_selection.lua index b1abd4a6..ba229f27 100644 --- a/official/save_selection.lua +++ b/official/save_selection.lua @@ -35,7 +35,7 @@ increase it if you need more temporary selection buffers ]] local dt = require "darktable" local du = require "lib/dtutils" - + require "lib/darktable_transition" du.check_min_api_version("2.0.0", "save_selection") local CURR_API_STRING = dt.configuration.api_version_string @@ -43,16 +43,16 @@ local buffer_count = 5 for i=1,buffer_count do local saved_selection - dt.register_event(CURR_API_STRING >= "6.2.1" and "save_selection", "shortcut" or "shortcut" ,function() + dt.register_event("save_selection", "shortcut", function() saved_selection = dt.gui.selection() end,"save to buffer "..i) - dt.register_event(CURR_API_STRING >= "6.2.1" and "save_selection1", "shortcut" or "shortcut" ,function() + dt.register_event("save_selection1", "shortcut", function() dt.gui.selection(saved_selection) end,"restore from buffer "..i) end local bounce_buffer = {} -dt.register_event(CURR_API_STRING >= "6.2.1" and "save_selection2", "shortcut" or "shortcut" ,function() +dt.register_event("save_selection2", "shortcut", function() bounce_buffer = dt.gui.selection(bounce_buffer) end,"switch selection with temporary buffer") diff --git a/tools/executable_manager.lua b/tools/executable_manager.lua index dd672284..c2afcece 100644 --- a/tools/executable_manager.lua +++ b/tools/executable_manager.lua @@ -31,6 +31,7 @@ local dt = require "darktable" local du = require "lib/dtutils" local df = require "lib/dtutils.file" + require "lib/darktable_transition" du.check_min_api_version("5.0.0", "executable_manager") @@ -215,7 +216,7 @@ if dt.gui.current_view().id == "lighttable" then else if not exec_man.event_registered then dt.register_event( - CURR_API_STRING >= "6.2.1" and "executable_manager", "view-changed" or "view-changed" , + "executable_manager", "view-changed", function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() diff --git a/tools/script_manager.lua b/tools/script_manager.lua index 845bf75c..39812a7f 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -54,6 +54,7 @@ local df = require "lib/dtutils.file" local ds = require "lib/dtutils.string" local dtsys = require "lib/dtutils.system" local log = require "lib/dtutils.log" + require "lib/darktable_transition" local gettext = dt.gettext @@ -882,7 +883,7 @@ if dt.gui.current_view().id == "lighttable" then else if not sm.event_registered then dt.register_event( - CURR_API_STRING >= "6.2.1" and "script_manager", "view-changed" or "view-changed" , + "script_manager", "view-changed", function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() From 6d9c4c90ba4ce1b80b873c58cea0d8c073fc384a Mon Sep 17 00:00:00 2001 From: wpferguson Date: Wed, 10 Feb 2021 14:52:03 -0500 Subject: [PATCH 145/445] Used image table returned to callback, and returned selection table to caller so that it could do the selection. --- contrib/select_untagged.lua | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/contrib/select_untagged.lua b/contrib/select_untagged.lua index 238c1ac2..7173f5a3 100644 --- a/contrib/select_untagged.lua +++ b/contrib/select_untagged.lua @@ -36,23 +36,23 @@ local function stop_job(job) job.valid = false end -local function select_untagged_images() +local function select_untagged_images(event, images) job = dt.gui.create_job(_("select untagged images"), true, stop_job) local selection = {} - for key,image in ipairs(dt.collection) do + for key,image in ipairs(images) do if(job.valid) then - job.percent = (key-1)/#dt.collection + job.percent = (key - 1)/#images local tags = dt.tags.get_tags(image) local hasTags = false for _,tag in ipairs(tags) do - if not string.match(tag.name,"darktable|") then + if not string.match(tag.name, "darktable|") then hasTags = true end end if hasTags == false then - table.insert(selection,image) + table.insert(selection, image) end else break @@ -60,7 +60,8 @@ local function select_untagged_images() end job.valid = false - dt.gui.selection(selection) + -- return table of images to set the selection to + return selection end if CURR_API_STRING >= "6.2.2" then From 4053ceb9e5dc265ca1cbd020e995ed805ae00ded Mon Sep 17 00:00:00 2001 From: wpferguson Date: Wed, 17 Feb 2021 22:24:02 -0500 Subject: [PATCH 146/445] [API 6.2.3] Added changes for API 6.2.3 compatibility --- contrib/CollectHelper.lua | 72 +++++++++++++++++++++++--------- contrib/OpenInExplorer.lua | 20 ++++++--- contrib/clear_GPS.lua | 19 ++++++--- examples/multi_os.lua | 20 ++++++--- official/copy_paste_metadata.lua | 40 +++++++++++++----- 5 files changed, 127 insertions(+), 44 deletions(-) diff --git a/contrib/CollectHelper.lua b/contrib/CollectHelper.lua index 5996592d..4247b8b6 100644 --- a/contrib/CollectHelper.lua +++ b/contrib/CollectHelper.lua @@ -53,6 +53,8 @@ local all_active = false -- Tell gettext where to find the .mo file translating messages for a particular domain gettext.bindtextdomain("CollectHelper",dt.configuration.config_dir.."/lua/locale/") +local CURR_API_STRING = dt.configuration.api_version_string + local function _(msgid) return gettext.dgettext("CollectHelper", msgid) end @@ -173,31 +175,63 @@ local function CollectOnAll_AND() end -- GUI -- -dt.gui.libs.image.register_action( - _("collect: previous"), - function() PreviousCollection() end, - _("Sets the Collect parameters to be the previously active parameters") -) -if dt.preferences.read('module_CollectHelper','folder','bool') then +if CURR_API_STRING < "6.2.3" then dt.gui.libs.image.register_action( - _("collect: folder"), - function() CollectOnFolder(_ , false) end, - _("Sets the Collect parameters to be the selected images's folder") + _("collect: previous"), + function() PreviousCollection() end, + _("Sets the Collect parameters to be the previously active parameters") ) -end -if dt.preferences.read('module_CollectHelper','colors','bool') then +else dt.gui.libs.image.register_action( - _("collect: color label(s)"), - function() CollectOnColors(_ , false) end, - _("Sets the Collect parameters to be the selected images's color label(s)") + "CollectHelper_prev", _("collect: previous"), + function() PreviousCollection() end, + _("Sets the Collect parameters to be the previously active parameters") ) end +if dt.preferences.read('module_CollectHelper','folder','bool') then + if CURR_API_STRING < "6.2.3" then + dt.gui.libs.image.register_action( + _("collect: folder"), + function() CollectOnFolder(_ , false) end, + _("Sets the Collect parameters to be the selected images's folder") + ) + else + dt.gui.libs.image.register_action( + "CollectHelper_folder", _("collect: folder"), + function() CollectOnFolder(_ , false) end, + _("Sets the Collect parameters to be the selected images's folder") + ) + end +end +if dt.preferences.read('module_CollectHelper','colors','bool') then + if CURR_API_STRING < "6.2.3" then + dt.gui.libs.image.register_action( + _("collect: color label(s)"), + function() CollectOnColors(_ , false) end, + _("Sets the Collect parameters to be the selected images's color label(s)") + ) + else + dt.gui.libs.image.register_action( + "CollectHelper_labels", _("collect: color label(s)"), + function() CollectOnColors(_ , false) end, + _("Sets the Collect parameters to be the selected images's color label(s)") + ) + end +end if dt.preferences.read('module_CollectHelper','all_and','bool') then - dt.gui.libs.image.register_action( - _("collect: all (AND)"), - function() CollectOnAll_AND() end, - _("Sets the Collect parameters based on all activated CollectHelper options") - ) + if CURR_API_STRING < "6.2.3" then + dt.gui.libs.image.register_action( + _("collect: all (AND)"), + function() CollectOnAll_AND() end, + _("Sets the Collect parameters based on all activated CollectHelper options") + ) + else + dt.gui.libs.image.register_action( + "CollectHelper_and", _("collect: all (AND)"), + function() CollectOnAll_AND() end, + _("Sets the Collect parameters based on all activated CollectHelper options") + ) + end end -- PREFERENCES -- diff --git a/contrib/OpenInExplorer.lua b/contrib/OpenInExplorer.lua index 72ec15dc..d9fe4a6b 100644 --- a/contrib/OpenInExplorer.lua +++ b/contrib/OpenInExplorer.lua @@ -184,11 +184,21 @@ end -- GUI -- -dt.gui.libs.image.register_action( - _("show in file explorer"), - function() open_in_fmanager() end, - _("Open the file manager at the selected image's location") -) +if CURR_API_STRING < "6.2.3" then + dt.gui.libs.image.register_action( + _("show in file explorer"), + function() open_in_fmanager() end, + _("Open the file manager at the selected image's location") + ) +else + dt.gui.libs.image.register_action( + "OpenInExplorer", _("show in file explorer"), + function() open_in_fmanager() end, + _("Open the file manager at the selected image's location") + ) +end + + if act_os ~= "windows" then dt.preferences.register("OpenInExplorer", "linked_image_files_dir", -- name "directory", -- type diff --git a/contrib/clear_GPS.lua b/contrib/clear_GPS.lua index 58404f9b..a67fc1a4 100644 --- a/contrib/clear_GPS.lua +++ b/contrib/clear_GPS.lua @@ -64,12 +64,21 @@ local function clear_GPS(images) end end +if CURR_API_STRING < "6.2.3" then + dt.gui.libs.image.register_action( + _("clear GPS data"), + function(event, images) clear_GPS(images) end, + _("Clear GPS data from selected images") + ) +else + dt.gui.libs.image.register_action( + _"clear_GPS", ("clear GPS data"), + function(event, images) clear_GPS(images) end, + _("Clear GPS data from selected images") + ) +end + -dt.gui.libs.image.register_action( - _("clear GPS data"), - function(event, images) clear_GPS(images) end, - _("Clear GPS data from selected images") -) dt.register_event( "clearGPS", "shortcut", diff --git a/examples/multi_os.lua b/examples/multi_os.lua index 6ab356bf..d71f0d47 100644 --- a/examples/multi_os.lua +++ b/examples/multi_os.lua @@ -231,11 +231,21 @@ end Add a button to the selected images module in lighttable ]] -dt.gui.libs.image.register_action( - _("extract embedded jpeg"), - function(event, images) extract_embedded_jpeg(images) end, - "extract embedded jpeg" -) +if CURR_API_STRING < "6.2.3" then + dt.gui.libs.image.register_action( + _("extract embedded jpeg"), + function(event, images) extract_embedded_jpeg(images) end, + "extract embedded jpeg" + ) +else + dt.gui.libs.image.register_action( + "multi_os", _("extract embedded jpeg"), + function(event, images) extract_embedded_jpeg(images) end, + "extract embedded jpeg" + ) +end + + --[[ Add a shortcut diff --git a/official/copy_paste_metadata.lua b/official/copy_paste_metadata.lua index 1db3d622..2c100291 100644 --- a/official/copy_paste_metadata.lua +++ b/official/copy_paste_metadata.lua @@ -114,17 +114,37 @@ local function paste(images) end end -dt.gui.libs.image.register_action( - _("copy metadata"), - function(event, images) copy(images[1]) end, - _("copy metadata of the first selected image") -) +if CURR_API_STRING < "6.2.3" then + dt.gui.libs.image.register_action( + _("copy metadata"), + function(event, images) copy(images[1]) end, + _("copy metadata of the first selected image") + ) +else + dt.gui.libs.image.register_action( + "metadata_copy", _("copy metadata"), + function(event, images) copy(images[1]) end, + _("copy metadata of the first selected image") + ) +end + + + +if CURR_API_STRING < "6.2.3" then + dt.gui.libs.image.register_action( + _("paste metadata"), + function(event, images) paste(images) end, + _("paste metadata to the selected images") + ) +else + dt.gui.libs.image.register_action( + "metadata_paste", _("paste metadata"), + function(event, images) paste(images) end, + _("paste metadata to the selected images") + ) +end + -dt.gui.libs.image.register_action( - _("paste metadata"), - function(event, images) paste(images) end, - _("paste metadata to the selected images") -) dt.register_event( "capmd1", "shortcut", From 4e9c45c162a910e269cd2aea970c19b879e48e37 Mon Sep 17 00:00:00 2001 From: wpferguson Date: Fri, 19 Feb 2021 17:17:53 -0500 Subject: [PATCH 147/445] Updated README.md with links to the lua documentation. Added fujifilm_dynamic_range script to contrib. Added ChangeLog.md to keep track of recent changes. --- ChangeLog.md | 49 ++++++++++++++++++ README.md | 137 +++++++++++++++++++++++++++------------------------ 2 files changed, 121 insertions(+), 65 deletions(-) create mode 100644 ChangeLog.md diff --git a/ChangeLog.md b/ChangeLog.md new file mode 100644 index 00000000..c3aeffdf --- /dev/null +++ b/ChangeLog.md @@ -0,0 +1,49 @@ +## Changes from most recent to oldest + +**17 Feb 2021 - wpferguson - API 6.2.3 register_action changes** + +* Added check for API version and supplied a name argument if the +API version was greater than or equal to 6.2.3 + +**10 Feb 2021 - wpferguson - bugfix select_untagged** + +* Fixed callback to return a list of images as expected instead of +doing the selection in the callback + +**10 Feb 2021 - wpferguson - bugfix API 6.2.1 compatibility** + +* The inline check for API version didn't handle argument return +correctly so added a transition library with a register_event function +override to check the API version and process the arguments correctly. + +**9 Feb 2021 - wpferguson - bugfix API 6.2.2 compatibility** + +* The inline check for API version didn't handle argument return +correctly so changed it to a full if/else block + +**4 Reb 2021 - wpferguson - API 6.2.2 compatibililty** + +* Added check for API version and supplied a name argument to register_selection +if the API version was greater than or eqal to 6.2.2 + +**1 Feb 2021 - wpferguson - API 6.2.1 compatibility** + +* Added check for API version and supplied a name argument to register_event +if the API version was greater than or eqal to 6.2.1 + +**21 Jan 2021 - wpferguson - Modified dtutils function find_image_by_id** + +* For users with API 6.2.0 or greater - Enabled use of new API function +darktable.database_get_image() in find_image_by_id(). + +**19 Jan 2021 - schwerdf - Added dtutils library function find_image_by_id()** + +* Added new library function to retrieve an image from the library based on it's ID instead +of it's row number in the database + +**10 Jan 2021 - chrisaga - copy_attach_detach_tags localization** + +**7 Jan 2021 - dtorop - add contrib/fujifilm_dynamic_range** + +* add a new contrib script, fujifilm_dynamic_range to adjust exposure +based on the exposure bias camera setting \ No newline at end of file diff --git a/README.md b/README.md index 8ca96db0..19a2c952 100644 --- a/README.md +++ b/README.md @@ -7,23 +7,25 @@ efforts of the darktable developers, maintainers, contributors and community. Th contained in the repository, whether they can be run by themselves (Standalone - Yes) or depend on other scripts (Standalone - No), what operating systems they are known to work on (L - Linux, M - MacOS, W - Windows), and their purpose. +For the latest changes, see the [ChangeLog](ChangeLog.md) + ### Official Scripts These scripts are written primarily by the darktable developers and maintained by the authors and/or repository maintainers. They are located in the official/ directory. Name|Standalone|OS |Purpose ----|:--------:|:---:|------- -check_for_updates|Yes|LMW|Check for updates to darktable -copy_paste_metadata|Yes|LMW|Copy and paste metadata, tags, ratings, and color labels between images -delete_long_tags|Yes|LMW|Delete all tags longer than a specified length -delete_unused_tags|Yes|LMW|Delete tags that have no associated images -enfuse|No|L|Exposure blend several images (HDR) -generate_image_txt|No|L|Generate txt sidecar files to be overlaid on zoomed images -image_path_in_ui|Yes|LMW|Plugin to display selected image path -import_filter_manager|Yes|LMW|Manager for import filters -import_filters|No|LMW|Two import filters for use with import_filter_manager -save_selection|Yes|LMW|Provide save and restore from multiple selection buffers -selection_to_pdf|No|L|Generate a PDF file from the selected images +[check_for_updates](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/official/check_for_updates)|Yes|LMW|Check for updates to darktable +[copy_paste_metadata](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/official/copy_paste_metadata)|Yes|LMW|Copy and paste metadata, tags, ratings, and color labels between images +[delete_long_tags](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/official/delete_long_tags)|Yes|LMW|Delete all tags longer than a specified length +[delete_unused_tags](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/official/delete_unused_tags)|Yes|LMW|Delete tags that have no associated images +[enfuse](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/official/enfuse)|No|L|Exposure blend several images (HDR) +[generate_image_txt](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/official/generate_image_txt)|No|L|Generate txt sidecar files to be overlaid on zoomed images +[image_path_in_ui](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/official/image_path_in_ui)|Yes|LMW|Plugin to display selected image path +[import_filter_manager](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/official/import_filter_manager)|Yes|LMW|Manager for import filters +[import_filters](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/official/import_filters)|No|LMW|Two import filters for use with import_filter_manager +[save_selection](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/official/save_selection)|Yes|LMW|Provide save and restore from multiple selection buffers +[selection_to_pdf](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/official/selection_to_pdf)|No|L|Generate a PDF file from the selected images ### Contributed Scripts @@ -32,39 +34,40 @@ These scripts are contributed by users. They are meant to have an "owner", i.e. Name|Standalone|OS |Purpose ----|:--------:|:---:|------- -AutoGrouper|Yes|LMW|Group images together by time -autostyle|Yes|LMW|Automatically apply styles on import -clear_GPS|Yes|LMW|Reset GPS information for selected images -CollectHelper|Yes|LMW|Add buttons to selected images module to manipulate the collection -copy_attach_detach_tags|Yes|LMW|Copy and paste tags from/to images -cr2hdr|Yes|L|Process image created with Magic Lantern Dual ISO -enfuseAdvanced|No|LMW|Merge multiple images into Dynamic Range Increase (DRI) or Depth From Focus (DFF) images -exportLUT|Yes|LMW|Create a LUT from a style and export it -ext_editor|No|LW|Export pictures to collection and edit them with up to nine user-defined external editors -face_recognition|No|LM|Identify and tag images using facial recognition -fujifilm_ratings|No|LM|Support importing Fujifilm ratings -geoJSON_export|No|L|Create a geo JSON script with thumbnails for use in ... -geoToolbox|No|LMW|A toolbox of geo functions -gimp|No|LMW|Open an image in GIMP for editing and return the result -gpx_export|No|LMW|Export a GPX track file from selected images GPS data -HDRMerge|No|LMW|Combine the selected images into an HDR DNG and return the result -hugin|No|LMW|Combine selected images into a panorama and return the result -image_stack|No|LMW|Combine a stack of images to remove noise or transient objects -image_time|Yes|LMW|Adjust the EXIF image time -kml_export|No|L|Export photos with a KML file for usage in Google Earth -LabelsToTags|Yes|LMW|Apply tags based on color labels and ratings -OpenInExplorer|No|LMW|Open the selected images in the system file manager -passport_guide|Yes|LMW|Add passport cropping guide to darkroom crop tool -pdf_slideshow|No|LM|Export images to a PDF slideshow -[photils](https://github.com/scheckmedia/photils-dt)|No|LM|Automatic tag suggestions for your images -quicktag|Yes|LMW|Create shortcuts for quickly applying tags -rate_group|Yes|LMW|Apply or remove a star rating from grouped images -rename-tags|Yes|LMW|Change a tag name -RL_out_sharp|No|LW|Output sharpening using GMic (Richardson-Lucy algorithm) -select_untagged|Yes|LMW|Enable selection of untagged images -slideshowMusic|No|L|Play music during a slideshow -transfer_hierarchy|Yes|LMW|Image move/copy preserving directory hierarchy -video_ffmpeg|No|LMW|Export video from darktable +[AutoGrouper](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/AutoGrouper)|Yes|LMW|Group images together by time +[autostyle](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/autostyle)|Yes|LMW|Automatically apply styles on import +[clear_GPS](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/clear_GPS)|Yes|LMW|Reset GPS information for selected images +[CollectHelper](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/CollectHelper)|Yes|LMW|Add buttons to selected images module to manipulate the collection +[copy_attach_detach_tags](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/copy_attach_detach_tags)|Yes|LMW|Copy and paste tags from/to images +[cr2hdr](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/cr2hdr)|Yes|L|Process image created with Magic Lantern Dual ISO +[enfuseAdvanced](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/enfuseAdvanced)|No|LMW|Merge multiple images into Dynamic Range Increase (DRI) or Depth From Focus (DFF) images +[exportLUT](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/exportLUT)|Yes|LMW|Create a LUT from a style and export it +[ext_editor](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/ext_editor)|No|LW|Export pictures to collection and edit them with up to nine user-defined external editors +[face_recognition](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/face_recognition)|No|LM|Identify and tag images using facial recognition +[fujifilm_dynamic_range](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/fujifilm_dynamic_range)|No|LMW|Correct fujifilm exposure based on exposure bias camera setting +[fujifilm_ratings](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/fujifilm_ratings)|No|LM|Support importing Fujifilm ratings +[geoJSON_export](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/geoJSON_export)|No|L|Create a geo JSON script with thumbnails for use in ... +[geoToolbox](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/geoToolbox)|No|LMW|A toolbox of geo functions +[gimp](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/gimp)|No|LMW|Open an image in GIMP for editing and return the result +[gpx_export](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/gpx_export)|No|LMW|Export a GPX track file from selected images GPS data +[HDRMerge](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/HDRMerge)|No|LMW|Combine the selected images into an HDR DNG and return the result +[hugin](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/hugin)|No|LMW|Combine selected images into a panorama and return the result +[image_stack](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/image_stack)|No|LMW|Combine a stack of images to remove noise or transient objects +[image_time](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/image_time)|Yes|LMW|Adjust the EXIF image time +[kml_export](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/kml_export)|No|L|Export photos with a KML file for usage in Google Earth +[LabelsToTags](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/LabelsToTags)|Yes|LMW|Apply tags based on color labels and ratings +[OpenInExplorer](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/OpenInExplorer)|No|LMW|Open the selected images in the system file manager +[passport_guide](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/passport_guide)|Yes|LMW|Add passport cropping guide to darkroom crop tool +[pdf_slideshow](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/pdf_slideshow)|No|LM|Export images to a PDF slideshow +[photils](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/photils)|No|LM|Automatic tag suggestions for your images +[quicktag](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/quicktag)|Yes|LMW|Create shortcuts for quickly applying tags +[rate_group](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/rate_group)|Yes|LMW|Apply or remove a star rating from grouped images +[rename-tags](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/rename-tags)|Yes|LMW|Change a tag name +[RL_out_sharp](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/RL_out_sharp)|No|LW|Output sharpening using GMic (Richardson-Lucy algorithm) +[select_untagged](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/select_untagged)|Yes|LMW|Enable selection of untagged images +[slideshowMusic](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/slideshowMusic)|No|L|Play music during a slideshow +[transfer_hierarchy](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/transfer_hierarchy)|Yes|LMW|Image move/copy preserving directory hierarchy +[video_ffmpeg](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/video_ffmpeg)|No|LMW|Export video from darktable ### Example Scripts @@ -72,17 +75,17 @@ These scripts provide examples of how to use specific portions of the API. They Name|Standalone|OS |Purpose ----|:--------:|:---:|------- -api_version|Yes|LMW|Print the current API version -darkroom_demo|Yes|LMW|Demonstrate changing images in darkoom -gettextExample|Yes|LM|How to use translation -hello_world|Yes|LMW|Prints hello world when darktable starts -lighttable_demo|Yes|LMW|Demonstrate controlling lighttable mode, zoom, sorting and filtering -moduleExample|Yes|LMW|How to create a lighttable module -multi_os|No|LMW|How to create a cross platform script that calls an external executable -panels_demo|Yes|LMW|Demonstrate hiding and showing darktable panels -preferenceExamples|Yes|LMW|How to use preferences in a script -printExamples|Yes|LMW|How to use various print functions from a script -running_os|Yes|LMW|Print out the running operating system +[api_version](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/api_version)|Yes|LMW|Print the current API version +[darkroom_demo](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/darkroom_demo)|Yes|LMW|Demonstrate changing images in darkoom +[gettextExample](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/gettextExample)|Yes|LM|How to use translation +[hello_world](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/hello_world)|Yes|LMW|Prints hello world when darktable starts +[lighttable_demo](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/lighttable_demo)|Yes|LMW|Demonstrate controlling lighttable mode, zoom, sorting and filtering +[moduleExample](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/moduleExample)|Yes|LMW|How to create a lighttable module +[multi_os](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/multi_os)|No|LMW|How to create a cross platform script that calls an external executable +[panels_demo](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/panels_demo)|Yes|LMW|Demonstrate hiding and showing darktable panels +[preferenceExamples](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/preferenceExamples)|Yes|LMW|How to use preferences in a script +[printExamples](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/printExamples)|Yes|LMW|How to use various print functions from a script +[running_os](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/running_os)|Yes|LMW|Print out the running operating system ### Tools @@ -90,11 +93,11 @@ Tool scripts perform functions relating to the repository, such as generating do Name|Standalone|OS |Purpose ----|:--------:|:---:|------- -executable_manager|Yes|LMW|Manage the external executables used by the lua scripts -gen_i18n_mo|No|LMW|Generate compiled translation files (.mo) from source files (.po) -get_lib_manpages|No|LM|Retrieve the library documentation and output it in man page and PDF format -get_libdoc|No|LMW|Retrieve the library documentation and output it as text -script_manager|No|LMW|Manage (install, update, enable, disable) the lua scripts +[executable_manager](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/tools/executable_manager)|Yes|LMW|Manage the external executables used by the lua scripts +[gen_i18n_mo](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/tools/gen_i18n_mo)|No|LMW|Generate compiled translation files (.mo) from source files (.po) +[get_lib_manpages](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/tools/get_lib_manpages)|No|LM|Retrieve the library documentation and output it in man page and PDF format +[get_libdoc](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/tools/get_libdoc)|No|LMW|Retrieve the library documentation and output it as text +[script_manager](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/tools/script_manager)|No|LMW|Manage (install, update, enable, disable) the lua scripts ### Related third-party projects @@ -219,15 +222,19 @@ To update the script repository, open a terminal or command prompt and do the fo ## Documentation -Each script includes its own documentation and usage in its header, please refer to them. +The [Lua Scripts Manual](https://darktable-org.github.io/luadocs/lua.scripts.manual/) provides documentation +for the scripts transcribed from the header comments. Each script also contains comments and usage instructions +in the header comments. -Lua-script libraries documentation may be generated using the tools in the tools/ directory. +The [Lua Scripts Library API Manual](https://darktable-org.github.io/luadocs/lua.scripts.api.manual/) provides +documentation of the libraries and functions. Lua-script libraries documentation may also be generated using +the tools in the tools/ directory. More information about the scripting with Lua can be found in the darktable user manual: -https://www.darktable.org/usermanual/en/lua_chapter.html +[Scripting with Lua](https://darktable-org.github.io/dtdocs/lua/) -The darktable Lua API documentation is here: -https://www.darktable.org/lua-api/ +The [Lua API Manual](https://darktable-org.github.io/luadocs/lua.api.manual/) provides docuemntation of the +darktable Lua API. ## Troubleshooting From 73cd301ff443410ed88c3ff35fcda4e8a9d7a6a3 Mon Sep 17 00:00:00 2001 From: "U-DESKTOP-HQME86J\\marco" Date: Sun, 21 Feb 2021 20:55:23 +0100 Subject: [PATCH 148/445] ext_editor visible in darkroom --- contrib/ext_editor.lua | 68 ++++++++++++++++-------------------------- 1 file changed, 25 insertions(+), 43 deletions(-) diff --git a/contrib/ext_editor.lua b/contrib/ext_editor.lua index 2df2237e..b5461842 100644 --- a/contrib/ext_editor.lua +++ b/contrib/ext_editor.lua @@ -20,8 +20,8 @@ This script provides helpers to edit image files with programs external to darktable. It adds: - a new target storage "collection". Image exported will be reimported to collection for further edit with external programs - - a new lighttable module "external editors", to select a program from a list of up to - - 9 external editors and run it on a selected image (adjust this limit by changing MAX_EDITORS) + - a new module "external editors", visible in lightable and darkroom, to select a program from a list + - of up to 9 external editors and run it on a selected image (adjust this limit by changing MAX_EDITORS) - a set of lua preferences in order to configure name and path of up to 9 external editors - a set of lua shortcuts in order to quick launch the external editors @@ -32,7 +32,7 @@ * in "preferences/lua options" configure name and path/command of external programs * note that if a program name is left empty, that and all following entries will be ignored * in "preferences/shortcuts/lua" configure shortcuts for external programs (optional) - * whenever programs preferences are changed, in lighttable/external editors, press "update list" + * whenever programs preferences are changed, in external editors GUI, press "update list" -- use -- * in the export dialog choose "collection" and select the format and bit depth for the @@ -40,21 +40,19 @@ * press "export" * the exported image will be imported into collection and grouped with the original image - * select an image for editing with en external program, and: - * in lighttable/external editors, select program and press "edit" + * in lighttable, select an image for editing with en external program + * (or in darkroom for the image being edited): + * in external editors GUI, select program and press "edit" * edit the image with the external editor, overwite the file, quit the external program * the selected image will be updated or - * in lighttable/external editors, select program and press "edit a copy" + * in external editors GUI, select program and press "edit a copy" * edit the image with the external editor, overwite the file, quit the external program * a copy of the selected image will be created and updated or - * in lighttable select target storage "collection" - * enter in darkroom - * to create an export or a copy press CRTL+E * use the shortcut to edit the current image with the corresponding external editor * overwite the file, quit the external program - * the darkroom view will be updated + * the image will be updated * warning: mouseover on lighttable/filmstrip will prevail on current image * this is the default DT behavior, not a bug of this script @@ -101,7 +99,7 @@ local function _(msgid) end -- maximum number of external programs, can be increased to necessity -local MAX_EDITORS = 9 +local MAX_EDITORS = 12 -- number of valid entries in the list of external programs local n_entries @@ -280,13 +278,9 @@ local function OpenWith(images, choice, copy) new_image = dt.database.import(name) new_image:group_with(image_leader) end - -- refresh darkroom view - if dt.gui.current_view() == dt.gui.views.darkroom then - dt.gui.views.darkroom.display_image(new_image) - end end - -- restore image tags, rating and color, must be put after refresh darkroom view + -- restore image tags, rating and color for i, tag in ipairs(tags) do dt.tags.attach(tag, new_image) end new_image.rating = rating new_image.red = red @@ -298,8 +292,12 @@ local function OpenWith(images, choice, copy) -- select the new image local selection = {} table.insert(selection, new_image) - dt.gui.selection (selection) + dt.gui.selection(selection) + -- refresh darkroom view + if dt.gui.current_view().id == "darkroom" then + dt.gui.views.darkroom.display_image(new_image) + end end @@ -334,19 +332,21 @@ local function export2collection(storage, image_table, extra_data) new_image:group_with(image.group_leader) end - dt.print (_("finished exporting")) + dt.print(_("finished exporting")) end --- install the module in the UI + +-- install the module in the UI ----------------------------------------------- local function install_module() if not ee.module_installed then - -- register new module "external editors" in lighttable ------------------------ + -- register new module "external editors" in lighttable and darkroom ------ dt.register_lib( MODULE_NAME, _("external editors"), true, -- expandable false, -- resetable - {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, + {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}, + [dt.gui.views.darkroom] = {"DT_UI_CONTAINER_PANEL_LEFT_CENTER", 100}}, dt.new_widget("box") { orientation = "vertical", table.unpack(ee.widgets), @@ -358,6 +358,7 @@ local function install_module() end end + -- combobox, with variable number of entries ---------------------------------- local combobox = dt.new_widget("combobox") { label = _("choose program"), @@ -409,30 +410,11 @@ local box1 = dt.new_widget("box") { button_update_list } + +-- install module in lighttable and darkroom ---------------------------------- table.insert(ee.widgets, combobox) table.insert(ee.widgets, box1) - --- register new module "external editors" in lighttable ------------------------ -if dt.gui.current_view().id == "lighttable" then - install_module() -else - if not ee.event_registered then - dt.register_event( - MODULE_NAME, "view-changed", - function(event, old_view, new_view) - if new_view.name == "lighttable" and old_view.name == "darkroom" then - install_module() - end - end - ) - ee.event_registered = true - end -end - - - --- initialize list of programs and widgets ------------------------------------ -UpdateProgramList(combobox, button_edit, button_edit_copy, false) +install_module() -- register new storage ------------------------------------------------------- From c9fa13b97b480ef61cafb96b6e72ac87a2aee610 Mon Sep 17 00:00:00 2001 From: "U-DESKTOP-HQME86J\\marco" Date: Sun, 21 Feb 2021 20:59:30 +0100 Subject: [PATCH 149/445] revert MAX_EDITORS to 9 --- contrib/ext_editor.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/ext_editor.lua b/contrib/ext_editor.lua index b5461842..b5a16846 100644 --- a/contrib/ext_editor.lua +++ b/contrib/ext_editor.lua @@ -99,7 +99,7 @@ local function _(msgid) end -- maximum number of external programs, can be increased to necessity -local MAX_EDITORS = 12 +local MAX_EDITORS = 9 -- number of valid entries in the list of external programs local n_entries From 8112472df5d9af97b721a8b43796c3eed6163941 Mon Sep 17 00:00:00 2001 From: "U-DESKTOP-HQME86J\\marco" Date: Mon, 22 Feb 2021 08:17:46 +0100 Subject: [PATCH 150/445] restore initialization line deleted by mistake --- contrib/ext_editor.lua | 3 +++ 1 file changed, 3 insertions(+) diff --git a/contrib/ext_editor.lua b/contrib/ext_editor.lua index b5a16846..0ac6258f 100644 --- a/contrib/ext_editor.lua +++ b/contrib/ext_editor.lua @@ -416,6 +416,9 @@ table.insert(ee.widgets, combobox) table.insert(ee.widgets, box1) install_module() +-- initialize list of programs and widgets ------------------------------------ +UpdateProgramList(combobox, button_edit, button_edit_copy, false) + -- register new storage ------------------------------------------------------- dt.register_storage("exp2coll", _("collection"), nil, export2collection) From aee1f82d04c220dcf522cb84420e0196e118d237 Mon Sep 17 00:00:00 2001 From: "U-DESKTOP-HQME86J\\marco" Date: Tue, 23 Feb 2021 07:40:30 +0100 Subject: [PATCH 151/445] restore current module registration --- contrib/ext_editor.lua | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/contrib/ext_editor.lua b/contrib/ext_editor.lua index 0ac6258f..d16c6af6 100644 --- a/contrib/ext_editor.lua +++ b/contrib/ext_editor.lua @@ -411,10 +411,28 @@ local box1 = dt.new_widget("box") { } --- install module in lighttable and darkroom ---------------------------------- +-- table with all the widgets -------------------------------------------------- table.insert(ee.widgets, combobox) table.insert(ee.widgets, box1) -install_module() + + +-- register new module, but only when in lighttable ---------------------------- +if dt.gui.current_view().id == "lighttable" then + install_module() +else + if not ee.event_registered then + dt.register_event( + MODULE_NAME, "view-changed", + function(event, old_view, new_view) + if new_view.name == "lighttable" and old_view.name == "darkroom" then + install_module() + end + end + ) + ee.event_registered = true + end +end + -- initialize list of programs and widgets ------------------------------------ UpdateProgramList(combobox, button_edit, button_edit_copy, false) From abd8bf4a608dc108e9f4049f724712fc9b699218 Mon Sep 17 00:00:00 2001 From: "U-DESKTOP-HQME86J\\marco" Date: Wed, 24 Feb 2021 14:14:38 +0100 Subject: [PATCH 152/445] option to display module in darkroom --- contrib/ext_editor.lua | 57 +++++++++++++++++++++++++++++------------- 1 file changed, 39 insertions(+), 18 deletions(-) diff --git a/contrib/ext_editor.lua b/contrib/ext_editor.lua index d16c6af6..3a94f981 100644 --- a/contrib/ext_editor.lua +++ b/contrib/ext_editor.lua @@ -337,23 +337,40 @@ local function export2collection(storage, image_table, extra_data) -- install the module in the UI ----------------------------------------------- -local function install_module() +local function install_module(dr) if not ee.module_installed then - -- register new module "external editors" in lighttable and darkroom ------ - dt.register_lib( - MODULE_NAME, - _("external editors"), - true, -- expandable - false, -- resetable - {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}, - [dt.gui.views.darkroom] = {"DT_UI_CONTAINER_PANEL_LEFT_CENTER", 100}}, - dt.new_widget("box") { - orientation = "vertical", - table.unpack(ee.widgets), - }, - nil, -- view_enter - nil -- view_leave - ) + if dr then + -- register new module "external editors" in lighttable and darkroom ---- + dt.register_lib( + MODULE_NAME, + _("external editors"), + true, -- expandable + false, -- resetable + {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}, + [dt.gui.views.darkroom] = {"DT_UI_CONTAINER_PANEL_LEFT_CENTER", 100}}, + dt.new_widget("box") { + orientation = "vertical", + table.unpack(ee.widgets), + }, + nil, -- view_enter + nil -- view_leave + ) + else + -- register new module "external editors" in lighttable only ------------ + dt.register_lib( + MODULE_NAME, + _("external editors"), + true, -- expandable + false, -- resetable + {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, + dt.new_widget("box") { + orientation = "vertical", + table.unpack(ee.widgets), + }, + nil, -- view_enter + nil -- view_leave + ) + end ee.module_installed = true end end @@ -417,15 +434,16 @@ table.insert(ee.widgets, box1) -- register new module, but only when in lighttable ---------------------------- +local show_dr = dt.preferences.read(MODULE_NAME, "show_in_darkrooom", "bool") if dt.gui.current_view().id == "lighttable" then - install_module() + install_module(show_dr) else if not ee.event_registered then dt.register_event( MODULE_NAME, "view-changed", function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then - install_module() + install_module(show_dr) end end ) @@ -452,6 +470,9 @@ for i = MAX_EDITORS, 1, -1 do _("name of external editor ")..i, _("friendly name of external editor"), "") end +dt.preferences.register(MODULE_NAME, "show_in_darkrooom", "bool", + _("show external editors in darkroom"), + _("check to show external editors module also in darkroom (requires restart)"), false) -- register the new shortcuts ------------------------------------------------- From 931e448ebde9f503fa1ca90aea213eb6612e5fc1 Mon Sep 17 00:00:00 2001 From: "U-DESKTOP-HQME86J\\marco" Date: Wed, 24 Feb 2021 19:21:32 +0100 Subject: [PATCH 153/445] more compact code --- contrib/ext_editor.lua | 53 +++++++++++++++++------------------------- 1 file changed, 21 insertions(+), 32 deletions(-) diff --git a/contrib/ext_editor.lua b/contrib/ext_editor.lua index 3a94f981..7e1460c8 100644 --- a/contrib/ext_editor.lua +++ b/contrib/ext_editor.lua @@ -338,39 +338,28 @@ local function export2collection(storage, image_table, extra_data) -- install the module in the UI ----------------------------------------------- local function install_module(dr) + + local views = {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}} + if dr then + views = {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}, + [dt.gui.views.darkroom] = {"DT_UI_CONTAINER_PANEL_LEFT_CENTER", 100}} + end + if not ee.module_installed then - if dr then - -- register new module "external editors" in lighttable and darkroom ---- - dt.register_lib( - MODULE_NAME, - _("external editors"), - true, -- expandable - false, -- resetable - {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}, - [dt.gui.views.darkroom] = {"DT_UI_CONTAINER_PANEL_LEFT_CENTER", 100}}, - dt.new_widget("box") { - orientation = "vertical", - table.unpack(ee.widgets), - }, - nil, -- view_enter - nil -- view_leave - ) - else - -- register new module "external editors" in lighttable only ------------ - dt.register_lib( - MODULE_NAME, - _("external editors"), - true, -- expandable - false, -- resetable - {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, - dt.new_widget("box") { - orientation = "vertical", - table.unpack(ee.widgets), - }, - nil, -- view_enter - nil -- view_leave - ) - end + -- register new module "external editors" in lighttable and darkroom ---- + dt.register_lib( + MODULE_NAME, + _("external editors"), + true, -- expandable + false, -- resetable + views, + dt.new_widget("box") { + orientation = "vertical", + table.unpack(ee.widgets), + }, + nil, -- view_enter + nil -- view_leave + ) ee.module_installed = true end end From db47dd5110308a59d89dace0c534f0a3671c6326 Mon Sep 17 00:00:00 2001 From: wpferguson Date: Wed, 24 Feb 2021 20:11:30 -0500 Subject: [PATCH 154/445] Update for Mark64/ext_editor_darkroom --- ChangeLog.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ChangeLog.md b/ChangeLog.md index c3aeffdf..35fbbc84 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,5 +1,7 @@ ## Changes from most recent to oldest +**24 Feb 2021 - Mark64 - make ext_editor lib visible in darkroom view** + **17 Feb 2021 - wpferguson - API 6.2.3 register_action changes** * Added check for API version and supplied a name argument if the From 752e27d97f32984942c97a86685fc2b045296e64 Mon Sep 17 00:00:00 2001 From: wpferguson Date: Thu, 25 Feb 2021 21:04:59 -0500 Subject: [PATCH 155/445] Added detached mode to Edit with GIMP so that GIMP can keep running and accepting new images --- ChangeLog.md | 6 ++++ contrib/gimp.lua | 81 ++++++++++++++++++++++++++++++------------------ 2 files changed, 57 insertions(+), 30 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 35fbbc84..fd361091 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,5 +1,11 @@ ## Changes from most recent to oldest +** 25 Feb 2021 - wpferguson - added detached mode to contrib/gimp.lua** + +* Added run_detached checkbox to the exporter GUI. Selecting run_detached +let's GIMP keep running and accepting additional images. It does not return +the edited images to darktable. + **24 Feb 2021 - Mark64 - make ext_editor lib visible in darkroom view** **17 Feb 2021 - wpferguson - API 6.2.3 register_action changes** diff --git a/contrib/gimp.lua b/contrib/gimp.lua index d7528d1b..0a8bd8d8 100644 --- a/contrib/gimp.lua +++ b/contrib/gimp.lua @@ -41,7 +41,9 @@ * require this script from your main lua file * select an image or images for editing with GIMP * in the export dialog select "Edit with GIMP" and select the format and bit depth for the - exported image + exported image. Check the "run_detached" button to run GIMP in detached mode. Images + will not be returned to darktable in this mode, but additional images can be sent to + GIMP without stopping it. * Press "export" * Edit the image with GIMP then save the changes with File->Overwrite.... * Exit GIMP @@ -103,6 +105,8 @@ end local function gimp_edit(storage, image_table, extra_data) --finalize + local run_detached = dt.preferences.read("gimp", "run_detached", "bool") + local gimp_executable = df.check_if_bin_exists("gimp") if not gimp_executable then @@ -111,7 +115,11 @@ local function gimp_edit(storage, image_table, extra_data) --finalize end if dt.configuration.running_os == "macos" then - gimp_executable = "open -W -a " .. gimp_executable + if run_detached then + gimp_executable = "open -a " .. gimp_executable + else + gimp_executable = "open -W -a " .. gimp_executable + end end -- list of exported images @@ -130,54 +138,67 @@ local function gimp_edit(storage, image_table, extra_data) --finalize local gimpStartCommand gimpStartCommand = gimp_executable .. " " .. img_list + if run_detached then + if dt.configuration.running_os == "windows" then + gimpStartCommand = "start /b \"\" " .. gimpStartCommand + else + gimpStartCommand = gimpStartCommand .. " &" + end + end + dt.print_log(gimpStartCommand) dtsys.external_command(gimpStartCommand) - -- for each of the image, exported image pairs - -- move the exported image into the directory with the original - -- then import the image into the database which will group it with the original - -- and then copy over any tags other than darktable tags + if not run_detached then + + -- for each of the image, exported image pairs + -- move the exported image into the directory with the original + -- then import the image into the database which will group it with the original + -- and then copy over any tags other than darktable tags - for image,exported_image in pairs(image_table) do + for image,exported_image in pairs(image_table) do - local myimage_name = image.path .. "/" .. df.get_filename(exported_image) + local myimage_name = image.path .. "/" .. df.get_filename(exported_image) - while df.check_if_file_exists(myimage_name) do - myimage_name = df.filename_increment(myimage_name) - -- limit to 99 more exports of the original export - if string.match(df.get_basename(myimage_name), "_(d-)$") == "99" then - break + while df.check_if_file_exists(myimage_name) do + myimage_name = df.filename_increment(myimage_name) + -- limit to 99 more exports of the original export + if string.match(df.get_basename(myimage_name), "_(d-)$") == "99" then + break + end end - end - dt.print_log("moving " .. exported_image .. " to " .. myimage_name) - local result = df.file_move(exported_image, myimage_name) + dt.print_log("moving " .. exported_image .. " to " .. myimage_name) + local result = df.file_move(exported_image, myimage_name) - if result then - dt.print_log("importing file") - local myimage = dt.database.import(myimage_name) + if result then + dt.print_log("importing file") + local myimage = dt.database.import(myimage_name) - group_if_not_member(image, myimage) + group_if_not_member(image, myimage) - for _,tag in pairs(dt.tags.get_tags(image)) do - if not (string.sub(tag.name,1,9) == "darktable") then - dt.print_log("attaching tag") - dt.tags.attach(tag,myimage) + for _,tag in pairs(dt.tags.get_tags(image)) do + if not (string.sub(tag.name,1,9) == "darktable") then + dt.print_log("attaching tag") + dt.tags.attach(tag,myimage) + end end end end end - end -- Register -local executables = {"gimp"} - -if dt.configuration.running_os ~= "linux" then - gimp_widget = df.executable_path_widget(executables) -end +gimp_widget = dt.new_widget("check_button"){ + label = _("run detached"), + tooltip = _("don't import resulting image back into darktable"), + value = dt.preferences.read("gimp", "run_detached", "bool"), + clicked_callback = function(this) + dt.preferences.write("gimp", "run_detached", "bool", this.value) + end +} dt.register_storage("module_gimp", _("Edit with GIMP"), show_status, gimp_edit, nil, nil, gimp_widget) From 9900f46be4d8327b2666d93b3f839e24c458fe7e Mon Sep 17 00:00:00 2001 From: Tobias Scheck Date: Mon, 15 Mar 2021 11:36:37 +0100 Subject: [PATCH 156/445] add option to apply selected tags from a single image to multiple images (close #3); add setting parameter to enable/disable the export of an image before tag suggestion (close #5) --- contrib/photils.lua | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/contrib/photils.lua b/contrib/photils.lua index 69829be7..32931e7d 100644 --- a/contrib/photils.lua +++ b/contrib/photils.lua @@ -143,7 +143,7 @@ local GUI = { attach_button = dt.new_widget("button") { label = "", sensitive = false, - clicked_callback = function() PHOTILS.attach_tags() end + clicked_callback = function(self) PHOTILS.attach_tags() end }, confidence_slider = dt.new_widget("slider") { step = 1, @@ -226,16 +226,25 @@ function PHOTILS.paginate() end function PHOTILS.attach_tags() - local image = dt.gui.selection()[1] - for tag, _ in pairs(PHOTILS.selected_tags) do - local dt_tag = dt.tags.create(tag) - dt.tags.attach(dt_tag, image) + local num_selected = #dt.gui.selection() + local job = dt.gui.create_job(_("Apply tag to image"), true) + + for i = 1, num_selected, 1 do + local image = dt.gui.selection()[i] + for tag, _ in pairs(PHOTILS.selected_tags) do + local dt_tag = dt.tags.create(tag) + dt.tags.attach(dt_tag, image) + end + + job.percent = i / num_selected + dt.print(_("Tags successfully attached to image")) end - dt.print(_("Tags successfully attached to image")) + job.valid = false end function PHOTILS.get_tags(image, with_export) + local tmp_file = df.create_tmp_file() local in_arg = df.sanitize_filename(tostring(image)) local out_arg = df.sanitize_filename(tmp_file) @@ -305,7 +314,8 @@ function PHOTILS.on_tags_clicked() dt.control.sleep(2000) end - if not PHOTILS.get_tags(images[1], true) then + with_export = dt.preferences.read(MODULE_NAME, "export_image_before_for_tags", "bool") + if not PHOTILS.get_tags(images[1], with_export) then local msg = string.format(_("%s failed, see terminal output for details"), MODULE_NAME) GUI.warning_label.label = msg GUI.stack.active = GUI.error_view @@ -435,6 +445,15 @@ dt.preferences.register(MODULE_NAME, _("if enabled, the confidence value for each tag is displayed"), true) +dt.preferences.register(MODULE_NAME, + "export_image_before_for_tags", + "bool", + _("photils: use exported image for tag request"), + _("If enabled, the image passed to photils for tag suggestion is based on the exported, already edited image. " .. + "Otherwise, the embedded thumbnail of the RAW file will be used for tag suggestion." .. + "The embedded thumbnail could speedup the tag suggestion but can fail if the RAW file is not supported."), + true) + dt.register_event("photils", "mouse-over-image-changed", PHOTILS.image_changed) From 1d10d5234fb2e33cc7322556ce30436c9a7411b3 Mon Sep 17 00:00:00 2001 From: Tobias Scheck Date: Mon, 15 Mar 2021 11:41:52 +0100 Subject: [PATCH 157/445] refactore print method --- contrib/photils.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/photils.lua b/contrib/photils.lua index 32931e7d..e3e0e4b9 100644 --- a/contrib/photils.lua +++ b/contrib/photils.lua @@ -237,9 +237,9 @@ function PHOTILS.attach_tags() end job.percent = i / num_selected - dt.print(_("Tags successfully attached to image")) end + dt.print(_("Tags successfully attached to image")) job.valid = false end From beafb6c21b620cc9fdcdeacd37aaaec817dd31b4 Mon Sep 17 00:00:00 2001 From: wpferguson Date: Fri, 19 Mar 2021 23:52:28 -0400 Subject: [PATCH 158/445] [HDRmerge] fixed crash resulting users renaming images from camera default. Minor code cleanup --- contrib/HDRMerge.lua | 538 +++++++++++++++++++++---------------------- 1 file changed, 269 insertions(+), 269 deletions(-) diff --git a/contrib/HDRMerge.lua b/contrib/HDRMerge.lua index 5c1635ab..aafff83f 100644 --- a/contrib/HDRMerge.lua +++ b/contrib/HDRMerge.lua @@ -55,45 +55,45 @@ local CURR_API_STRING = dt.configuration.api_version_string -- Tell gettext where to find the .mo file translating messages for a particular domain local gettext = dt.gettext -gettext.bindtextdomain('HDRMerge',dt.configuration.config_dir..'/lua/locale/') +gettext.bindtextdomain('HDRMerge', dt.configuration.config_dir..'/lua/locale/') local function _(msgid) return gettext.dgettext('HDRMerge', msgid) end local temp local HDRM = { --HDRMerge Program Table - name = 'HDRMerge', - bin = '', - first_run = true, - install_error = false, - arg_string = '', - images_string = '', - args = { - bps ={text = '-b ', style = 'integer'}, - size ={text = '-p ', style = 'string'}, - batch ={text = '-B ', style = 'bool'}, - gap ={text = '-g ', style = 'integer'} - } + name = 'HDRMerge', + bin = '', + first_run = true, + install_error = false, + arg_string = '', + images_string = '', + args = { + bps = {text = '-b ', style = 'integer'}, + size = {text = '-p ', style = 'string'}, + batch = {text = '-B ', style = 'bool'}, + gap = {text = '-g ', style = 'integer'} + } } local GUI = { --GUI Elements Table - HDR = { - bps ={}, - size ={}, - batch ={}, - gap ={} - }, - Target = { - style ={}, - copy_tags ={}, - add_tags ={} - }, - run = {}, - stack = {}, - options = {}, - exes = { - HDRMerge = {}, - update = {}, - } + HDR = { + bps ={}, + size ={}, + batch ={}, + gap ={} + }, + Target = { + style ={}, + copy_tags ={}, + add_tags ={} + }, + run = {}, + stack = {}, + options = {}, + exes = { + HDRMerge = {}, + update = {}, + } } HDRM.module_installed = false @@ -104,184 +104,184 @@ HDRM.event_registered = false local styles = dt.styles local styles_count = 1 -- 'none' = 1 for _,i in pairs(dt.styles) do - if type(i) == 'userdata' then styles_count = styles_count + 1 end + if type(i) == 'userdata' then styles_count = styles_count + 1 end end local function InRange(test, low, high) --tests if test value is within range of low and high (inclusive) - if test >= low and test <= high then - return true - else - return false - end + if test >= low and test <= high then + return true + else + return false + end end local function GetFileName(full_path) --Parses a full path (path/filename_identifier.extension) into individual parts --[[Input: Folder1/Folder2/Folder3/Img_0001.CR2 - Returns: - path: Folder1/Folder2/Folder3/ - filename: Img_0001 - identifier: 0001 - extension: .CR2 - - EX: - path_1, file_1, id_1, ext_1 = GetFileName(full_path_1) - ]] - local path = string.match(full_path, '.*[\\/]') - local filename = string.gsub(string.match(full_path, '[%w-_]*%.') , '%.' , '' ) - local identifier = string.match(filename, '%d*$') - local extension = string.match(full_path, '%.%w*') - return path, filename, identifier, extension + Returns: + path: Folder1/Folder2/Folder3/ + filename: Img_0001 + identifier: 0001 + extension: .CR2 + + EX: + path_1, file_1, id_1, ext_1 = GetFileName(full_path_1) + ]] + local path = string.match(full_path, '.*[\\/]') + local filename = string.gsub(string.match(full_path, '[%w-_]*%.') , '%.' , '' ) + local identifier = string.match(filename, '%d*$') + local extension = string.match(full_path, '%.%w*') + return path, filename, identifier, extension end local function CleanSpaces(text) --removes spaces from the front and back of passed in text - text = string.gsub(text,'^%s*','') - text = string.gsub(text,'%s*$','') - return text + text = string.gsub(text,'^%s*','') + text = string.gsub(text,'%s*$','') + return text end local function BuildExecuteCmd(prog_table) --creates a program command using elements of the passed in program table - local result = CleanSpaces(prog_table.bin)..' '..CleanSpaces(prog_table.arg_string)..' '..CleanSpaces(prog_table.images_string) - return result + local result = CleanSpaces(prog_table.bin)..' '..CleanSpaces(prog_table.arg_string)..' '..CleanSpaces(prog_table.images_string) + return result end local function PreCall(prog_tbl) --looks to see if this is the first call, if so checks to see if program is installed properly - for _,prog in pairs(prog_tbl) do - if prog.first_run then - prog.bin = df.check_if_bin_exists(prog.name) - if not prog.bin then - prog.install_error = true - dt.preferences.write(mod, 'bin_exists', 'bool', false) - else - prog.bin = CleanSpaces(prog.bin) - end - prog.first_run = false - end - end - if not dt.preferences.read(mod, 'bin_exists', 'bool') then - GUI.stack.active = 2 - dt.print(_('please update you binary locatoin')) + for _,prog in pairs(prog_tbl) do + if prog.first_run then + prog.bin = df.check_if_bin_exists(prog.name) + if not prog.bin then + prog.install_error = true + dt.preferences.write(mod, 'bin_exists', 'bool', false) + else + prog.bin = CleanSpaces(prog.bin) + end + prog.first_run = false end + end + if not dt.preferences.read(mod, 'bin_exists', 'bool') then + GUI.stack.active = 2 + dt.print(_('please update you binary location')) + end end local function ExeUpdate(prog_tbl) - dt.preferences.write(mod, 'bin_exists', 'bool', true) - for _,prog in pairs(prog_tbl) do - dt.preferences.write('executable_paths', prog.name, 'string', GUI.exes[prog.name].value) - prog.bin = df.check_if_bin_exists(prog.name) - if not prog.bin then - prog.install_error = true - dt.preferences.write(mod, 'bin_exists', 'bool', false) - else - prog.bin = CleanSpaces(prog.bin) - end - prog.first_run = false - end - if dt.preferences.read(mod, 'bin_exists', 'bool') then - GUI.stack.active = 1 - dt.print(_('update successful')) + dt.preferences.write(mod, 'bin_exists', 'bool', true) + for _,prog in pairs(prog_tbl) do + dt.preferences.write('executable_paths', prog.name, 'string', GUI.exes[prog.name].value) + prog.bin = df.check_if_bin_exists(prog.name) + if not prog.bin then + prog.install_error = true + dt.preferences.write(mod, 'bin_exists', 'bool', false) else - dt.print(_('update unsuccessful, please try again')) + prog.bin = CleanSpaces(prog.bin) end + prog.first_run = false + end + if dt.preferences.read(mod, 'bin_exists', 'bool') then + GUI.stack.active = 1 + dt.print(_('update successful')) + else + dt.print(_('update unsuccessful, please try again')) + end end local function UpdateActivePreference() --sliders & entry boxes do not have a click/changed callback, so their values must be saved to the active preference - temp = GUI.HDR.gap.value - dt.preferences.write(mod, 'active_gap', 'integer', temp) - temp = GUI.Target.add_tags.text - dt.preferences.write(mod, 'active_add_tags', 'string', temp) + temp = GUI.HDR.gap.value + dt.preferences.write(mod, 'active_gap', 'integer', temp) + temp = GUI.Target.add_tags.text + dt.preferences.write(mod, 'active_add_tags', 'string', temp) end local function main() - PreCall({HDRM}) --check if furst run then check if install OK - if HDRM.install_error then - dt.print_error(_('HDRMerge install issue')) - dt.print(_('HDRMerge install issue, please ensure the binary path is proper')) - return - end - images = dt.gui.selection() --get selected images - if #images < 2 then --ensure enough images selected - dt.print(_('not enough images selected, select at least 2 images to merge')) - return + PreCall({HDRM}) --check if furst run then check if install OK + if HDRM.install_error then + dt.print_error(_('HDRMerge install issue')) + dt.print(_('HDRMerge install issue, please ensure the binary path is proper')) + return + end + images = dt.gui.selection() --get selected images + if #images < 2 then --ensure enough images selected + dt.print(_('not enough images selected, select at least 2 images to merge')) + return + end + + UpdateActivePreference() --save current gui elements to active preference so those values will be pre-loaded at next startup + + --create image string and output path + HDRM.images_string = '' + local out_path = '' + local smallest_id = math.huge + local smallest_name = '' + local largest_id = 0 + local source_raw = {} + for _,image in pairs(images) do --loop to concat the images string, also track the image indexes for use in creating the final image name (eg; IMG_1034-1037.dng) + local curr_image = image.path..os_path_seperator..image.filename + HDRM.images_string = HDRM.images_string..df.sanitize_filename(curr_image)..' ' + out_path = image.path + _unused, source_name, source_id = GetFileName(image.filename) + source_id = tonumber(source_id) or 0 + if source_id < smallest_id then + smallest_id = source_id + smallest_name = source_name + source_raw = image end - - UpdateActivePreference() --save current gui elements to active preference so those values will be pre-loaded at next startup - - --create image string and output path - HDRM.images_string = '' - local out_path = '' - local smallest_id = math.huge - local smallest_name = '' - local largest_id = 0 - local source_raw = {} - for _,image in pairs(images) do --loop to concat the images string, also track the image indexes for use in creating the final image name (eg; IMG_1034-1037.dng) - local curr_image = image.path..os_path_seperator..image.filename - HDRM.images_string = HDRM.images_string..df.sanitize_filename(curr_image)..' ' - out_path = image.path - _, source_name, source_id = GetFileName(image.filename) - source_id = tonumber(source_id) - if source_id < smallest_id then - smallest_id = source_id - smallest_name = source_name - source_raw = image - end - if source_id > largest_id then largest_id = source_id end + if source_id > largest_id then largest_id = source_id end + end + out_path = out_path..os_path_seperator..smallest_name..'-'..largest_id..'.dng' + out_path = df.create_unique_filename(out_path) + + --create argument string + HDRM.arg_string = HDRM.args.bps.text..GUI.HDR.bps.value..' '..HDRM.args.size.text..GUI.HDR.size.value..' ' + if GUI.HDR.batch.value then + HDRM.arg_string = HDRM.arg_string..HDRM.args.batch.text..HDRM.args.gap.text..math.floor(GUI.HDR.gap.value)..' -a' + else + HDRM.arg_string = HDRM.arg_string..'-o '..df.sanitize_filename(out_path) + end + + -- create run command and execute + local run_cmd = BuildExecuteCmd(HDRM) + resp = dsys.external_command(run_cmd) + + if resp == 0 and not GUI.HDR.batch.value then + local imported = dt.database.import(out_path) -- import the new file + if GUI.Target.style.selected > 1 then -- apply selected style + local set_style = styles[GUI.Target.style.selected - 1] + dt.styles.apply(set_style , imported) end - out_path = out_path..os_path_seperator..smallest_name..'-'..largest_id..'.dng' - out_path = df.create_unique_filename(out_path) - - --create argument string - HDRM.arg_string = HDRM.args.bps.text..GUI.HDR.bps.value..' '..HDRM.args.size.text..GUI.HDR.size.value..' ' - if GUI.HDR.batch.value then - HDRM.arg_string = HDRM.arg_string..HDRM.args.batch.text..HDRM.args.gap.text..math.floor(GUI.HDR.gap.value)..' -a' - else - HDRM.arg_string = HDRM.arg_string..'-o '..df.sanitize_filename(out_path) + if GUI.Target.copy_tags.value then -- copy tags from the original file (ignore 'darktable' generated tags) + local all_tags = dt.tags.get_tags(source_raw) + for _,tag in pairs(all_tags) do + if string.match(tag.name, 'darktable|') == nil then dt.tags.attach(tag, imported) end + end end - - -- create run command and execute - local run_cmd = BuildExecuteCmd(HDRM) - resp = dsys.external_command(run_cmd) - - if resp == 0 and not GUI.HDR.batch.value then - local imported = dt.database.import(out_path) -- import the new file - if GUI.Target.style.selected > 1 then -- apply selected style - local set_style = styles[GUI.Target.style.selected - 1] - dt.styles.apply(set_style , imported) - end - if GUI.Target.copy_tags.value then -- copy tags from the original file (ignore 'darktable' generated tags) - local all_tags = dt.tags.get_tags(source_raw) - for _,tag in pairs(all_tags) do - if string.match(tag.name, 'darktable|') == nil then dt.tags.attach(tag, imported) end - end - end - local set_tag = GUI.Target.add_tags.text - if set_tag ~= nil then -- add additional user-specified tags - for tag in string.gmatch(set_tag, '[^,]+') do - tag = CleanSpaces(tag) - tag = dt.tags.create(tag) - dt.tags.attach(tag, imported) - end - end - dt.print(_('HDRMerge completed successfully')) - else - dt.print_error(_('HDRMerge failed')) - dt.print(_('HDRMerge failed')) + local set_tag = GUI.Target.add_tags.text + if set_tag ~= nil then -- add additional user-specified tags + for tag in string.gmatch(set_tag, '[^,]+') do + tag = CleanSpaces(tag) + tag = dt.tags.create(tag) + dt.tags.attach(tag, imported) + end end + dt.print(_('HDRMerge completed successfully')) + else + dt.print_error(_('HDRMerge failed')) + dt.print(_('HDRMerge failed')) + end end local function install_module() if not HDRM.module_installed then dt.register_lib( -- register HDRMerge module - 'HDRMerge_Lib', -- Module name - _('HDRMerge'), -- name - true, -- expandable - true, -- resetable - {[dt.gui.views.lighttable] = {'DT_UI_CONTAINER_PANEL_RIGHT_CENTER', 99}}, -- containers - dt.new_widget('box'){ - orientation = 'vertical', - GUI.stack - } + 'HDRMerge_Lib', -- Module name + _('HDRMerge'), -- name + true, -- expandable + true, -- resetable + {[dt.gui.views.lighttable] = {'DT_UI_CONTAINER_PANEL_RIGHT_CENTER', 99}}, -- containers + dt.new_widget('box'){ + orientation = 'vertical', + GUI.stack + } ) HDRM.module_installed = true end @@ -289,149 +289,149 @@ end -- GUI Elements -- local lbl_hdr = dt.new_widget('section_label'){ - label = _('HDRMerge options') + label = _('HDRMerge options') } temp = dt.preferences.read(mod, 'active_bps_ind', 'integer') if not InRange(temp, 1, 3) then temp = 3 end GUI.HDR.bps = dt.new_widget('combobox'){ - label = _('bits per sample'), - tooltip =_('number of bits per sample in the output image'), - selected = temp, - '16','24','32', - changed_callback = function(self) - dt.preferences.write(mod, 'active_bps', 'integer', self.value) - dt.preferences.write(mod, 'active_bps_ind', 'integer', self.selected) - end, - reset_callback = function(self) - self.selected = 3 - dt.preferences.write(mod, 'active_bps', 'integer', self.value) - dt.preferences.write(mod, 'active_bps_ind', 'integer', self.selected) - end + label = _('bits per sample'), + tooltip =_('number of bits per sample in the output image'), + selected = temp, + '16','24','32', + changed_callback = function(self) + dt.preferences.write(mod, 'active_bps', 'integer', self.value) + dt.preferences.write(mod, 'active_bps_ind', 'integer', self.selected) + end, + reset_callback = function(self) + self.selected = 3 + dt.preferences.write(mod, 'active_bps', 'integer', self.value) + dt.preferences.write(mod, 'active_bps_ind', 'integer', self.selected) + end } temp = dt.preferences.read(mod, 'active_size_ind', 'integer') if not InRange(temp, 1, 3) then temp = 2 end GUI.HDR.size = dt.new_widget('combobox'){ - label = _('embedded preview size'), - tooltip =_('size of the embedded preview in output image'), - selected = temp, - _('none'),_('half'),_('full'), - changed_callback = function(self) - dt.preferences.write(mod, 'active_size', 'string', self.value) - dt.preferences.write(mod, 'active_size_ind', 'integer', self.selected) - end, - reset_callback = function(self) - self.selected = 2 - dt.preferences.write(mod, 'active_size', 'string', self.value) - dt.preferences.write(mod, 'active_size_ind', 'integer', self.selected) - end + label = _('embedded preview size'), + tooltip =_('size of the embedded preview in output image'), + selected = temp, + _('none'),_('half'),_('full'), + changed_callback = function(self) + dt.preferences.write(mod, 'active_size', 'string', self.value) + dt.preferences.write(mod, 'active_size_ind', 'integer', self.selected) + end, + reset_callback = function(self) + self.selected = 2 + dt.preferences.write(mod, 'active_size', 'string', self.value) + dt.preferences.write(mod, 'active_size_ind', 'integer', self.selected) + end } GUI.HDR.batch = dt.new_widget('check_button'){ - label = _('batch mode'), - value = dt.preferences.read(mod, 'active_batch', 'bool'), - tooltip = _('enable batch mode operation \nNOTE: resultant files will NOT be auto-imported'), - clicked_callback = function(self) - dt.preferences.write(mod, 'active_batch', 'bool', self.value) - GUI.HDR.gap.sensitive = self.value - end, - reset_callback = function(self) self.value = false end + label = _('batch mode'), + value = dt.preferences.read(mod, 'active_batch', 'bool'), + tooltip = _('enable batch mode operation \nNOTE: resultant files will NOT be auto-imported'), + clicked_callback = function(self) + dt.preferences.write(mod, 'active_batch', 'bool', self.value) + GUI.HDR.gap.sensitive = self.value + end, + reset_callback = function(self) self.value = false end } temp = dt.preferences.read(mod, 'active_gap', 'integer') if not InRange(temp, 1, 3600) then temp = 3 end GUI.HDR.gap = dt.new_widget('slider'){ - label = _('batch gap [sec.]'), - tooltip = _('gap, in seconds, between batch mode groups'), - soft_min = 1, - soft_max = 30, - hard_min = 1, - hard_max = 3600, - step = 1, - digits = 0, - value = temp, - sensitive = GUI.HDR.batch.value, - reset_callback = function(self) - self.value = 3 - end + label = _('batch gap [sec.]'), + tooltip = _('gap, in seconds, between batch mode groups'), + soft_min = 1, + soft_max = 30, + hard_min = 1, + hard_max = 3600, + step = 1, + digits = 0, + value = temp, + sensitive = GUI.HDR.batch.value, + reset_callback = function(self) + self.value = 3 + end } local lbl_import = dt.new_widget('section_label'){ - label = _('import options') + label = _('import options') } GUI.Target.style = dt.new_widget('combobox'){ - label = _('apply style on import'), - tooltip = _('Apply selected style on auto-import to newly created image'), - selected = 1, - _('none'), - changed_callback = function(self) - dt.preferences.write(mod, 'active_style', 'string', self.value) - dt.preferences.write(mod, 'active_style_ind', 'integer', self.selected) - end, - reset_callback = function(self) - self.selected = 1 - dt.preferences.write(mod, 'active_style', 'string', self.value) - dt.preferences.write(mod, 'active_style_ind', 'integer', self.selected) - end + label = _('apply style on import'), + tooltip = _('Apply selected style on auto-import to newly created image'), + selected = 1, + _('none'), + changed_callback = function(self) + dt.preferences.write(mod, 'active_style', 'string', self.value) + dt.preferences.write(mod, 'active_style_ind', 'integer', self.selected) + end, + reset_callback = function(self) + self.selected = 1 + dt.preferences.write(mod, 'active_style', 'string', self.value) + dt.preferences.write(mod, 'active_style_ind', 'integer', self.selected) + end } for k=1, (styles_count-1) do - GUI.Target.style[k+1] = styles[k].name + GUI.Target.style[k+1] = styles[k].name end temp = dt.preferences.read(mod, 'active_style_ind', 'integer') if not InRange(temp, 1, styles_count) then temp = 1 end GUI.Target.style.selected = temp GUI.Target.copy_tags = dt.new_widget('check_button'){ - label = _('copy tags'), - value = dt.preferences.read(mod, 'active_copy_tags', 'bool'), - tooltip = _('copy tags from first source image'), - clicked_callback = function(self) dt.preferences.write(mod, 'active_copy_tags', 'bool', self.value) end, - reset_callback = function(self) self.value = true end + label = _('copy tags'), + value = dt.preferences.read(mod, 'active_copy_tags', 'bool'), + tooltip = _('copy tags from first source image'), + clicked_callback = function(self) dt.preferences.write(mod, 'active_copy_tags', 'bool', self.value) end, + reset_callback = function(self) self.value = true end } temp = dt.preferences.read(mod, 'active_add_tags', 'string') if temp == '' then temp = nil end GUI.Target.add_tags = dt.new_widget('entry'){ - tooltip = _('Additional tags to be added on import. Seperate with commas, all spaces will be removed'), - text = temp, - placeholder = _('Enter tags, seperated by commas'), - editable = true + tooltip = _('Additional tags to be added on import. Seperate with commas, all spaces will be removed'), + text = temp, + placeholder = _('Enter tags, seperated by commas'), + editable = true } GUI.run = dt.new_widget('button'){ - label = _('merge'), - tooltip =_('run HDRMerge with the above specified settings'), - clicked_callback = function() main() end + label = _('merge'), + tooltip =_('run HDRMerge with the above specified settings'), + clicked_callback = function() main() end } GUI.exes.HDRMerge = dt.new_widget('file_chooser_button'){ - title = _('Select HDRmerge executable'), - value = df.get_executable_path_preference(HDRM.name), - is_directory = false + title = _('Select HDRmerge executable'), + value = df.get_executable_path_preference(HDRM.name), + is_directory = false } GUI.exes.update = dt.new_widget('button'){ - label = _('update'), - tooltip =_('update the binary path with current value'), - clicked_callback = function() ExeUpdate({HDRM}) end + label = _('update'), + tooltip =_('update the binary path with current value'), + clicked_callback = function() ExeUpdate({HDRM}) end } GUI.options = dt.new_widget('box'){ - orientation = 'vertical', - lbl_hdr, - GUI.HDR.bps, - GUI.HDR.size, - GUI.HDR.batch, - GUI.HDR.gap, - lbl_import, - GUI.Target.style, - GUI.Target.copy_tags, - GUI.Target.add_tags, - GUI.run + orientation = 'vertical', + lbl_hdr, + GUI.HDR.bps, + GUI.HDR.size, + GUI.HDR.batch, + GUI.HDR.gap, + lbl_import, + GUI.Target.style, + GUI.Target.copy_tags, + GUI.Target.add_tags, + GUI.run } local exes_box = dt.new_widget('box'){ - orientation = 'vertical', - GUI.exes.HDRMerge, - GUI.exes.update + orientation = 'vertical', + GUI.exes.HDRMerge, + GUI.exes.update } GUI.stack = dt.new_widget('stack'){ - GUI.options, - exes_box + GUI.options, + exes_box } if dt.preferences.read(mod, 'bin_exists', 'bool') then - GUI.stack.active = 1 + GUI.stack.active = 1 else - GUI.stack.active = 2 + GUI.stack.active = 2 end if dt.gui.current_view().id == "lighttable" then From ed0adfbae18b64658355eb7f18cfe52051f7336f Mon Sep 17 00:00:00 2001 From: wpferguson Date: Sat, 20 Mar 2021 00:01:25 -0400 Subject: [PATCH 159/445] [Changelog] Added latest changes --- ChangeLog.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ChangeLog.md b/ChangeLog.md index fd361091..f1df9174 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,5 +1,9 @@ ## Changes from most recent to oldest +** 19 Mar 2021 - wpferguson - fixed crash in contrib/HDRmerge.lua** +* Made generated filename routine gracefully handle names that +are not in the exported format. + ** 25 Feb 2021 - wpferguson - added detached mode to contrib/gimp.lua** * Added run_detached checkbox to the exporter GUI. Selecting run_detached @@ -54,4 +58,4 @@ of it's row number in the database **7 Jan 2021 - dtorop - add contrib/fujifilm_dynamic_range** * add a new contrib script, fujifilm_dynamic_range to adjust exposure -based on the exposure bias camera setting \ No newline at end of file +based on the exposure bias camera setting From 9885e34f8256b18a99c6e3bf8cd47beb09e99029 Mon Sep 17 00:00:00 2001 From: wpferguson Date: Sat, 20 Mar 2021 00:01:44 -0400 Subject: [PATCH 160/445] [Changelog] Added latest changes --- ChangeLog.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ChangeLog.md b/ChangeLog.md index f1df9174..5b1a09e0 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -2,7 +2,12 @@ ** 19 Mar 2021 - wpferguson - fixed crash in contrib/HDRmerge.lua** * Made generated filename routine gracefully handle names that -are not in the exported format. +are not in the expected format. + +** 15 Mar 2021 - scheckmedia - updated contrib/photils.lua** +* refactor print method +* add option to apply selected tags from a single image to multiple images +* add setting parameter to enable/disable the export of an image before tag suggestion ** 25 Feb 2021 - wpferguson - added detached mode to contrib/gimp.lua** From 15de64dcf5b3a8cbb7c0722216c8a502c6dfd76c Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Wed, 2 Jun 2021 23:41:02 -0400 Subject: [PATCH 161/445] [contrib/quicktag] changed new entry field is_password setting to false so that the user can see what they are typing. --- ChangeLog.md | 4 ++++ contrib/quicktag.lua | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/ChangeLog.md b/ChangeLog.md index 5b1a09e0..19b2ed36 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,5 +1,9 @@ ## Changes from most recent to oldest +** 02 Jun 2021 - wpferguson - fix contrib/quicktag** +* set new entry field is_password to false so entry +is visible to user while typing. + ** 19 Mar 2021 - wpferguson - fixed crash in contrib/HDRmerge.lua** * Made generated filename routine gracefully handle names that are not in the expected format. diff --git a/contrib/quicktag.lua b/contrib/quicktag.lua index 34053c96..ef1987ec 100644 --- a/contrib/quicktag.lua +++ b/contrib/quicktag.lua @@ -211,7 +211,7 @@ update_quicktag_list() local new_quicktag = dt.new_widget("entry"){ text = "", placeholder = _("new tag"), - is_password = true, + is_password = false, editable = true, tooltip = _("enter your tag here") } From 9d5947904958f8e75afa65313fe5f47eace697f8 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Fri, 11 Jun 2021 19:47:43 -0400 Subject: [PATCH 162/445] Revert changes to accomadate API changes greater than 6.1 --- contrib/CollectHelper.lua | 70 +++++++++----------------------- contrib/OpenInExplorer.lua | 19 +++------ contrib/clear_GPS.lua | 20 +++------ contrib/select_untagged.lua | 15 ++----- examples/multi_os.lua | 19 +++------ lib/darktable_transition.lua | 51 ----------------------- official/copy_paste_metadata.lua | 40 +++++------------- tools/script_manager.lua | 20 +++------ 8 files changed, 54 insertions(+), 200 deletions(-) delete mode 100644 lib/darktable_transition.lua diff --git a/contrib/CollectHelper.lua b/contrib/CollectHelper.lua index 4247b8b6..8dff8ec4 100644 --- a/contrib/CollectHelper.lua +++ b/contrib/CollectHelper.lua @@ -175,63 +175,31 @@ local function CollectOnAll_AND() end -- GUI -- -if CURR_API_STRING < "6.2.3" then - dt.gui.libs.image.register_action( - _("collect: previous"), - function() PreviousCollection() end, - _("Sets the Collect parameters to be the previously active parameters") - ) -else +dt.gui.libs.image.register_action( + _("collect: previous"), + function() PreviousCollection() end, + _("Sets the Collect parameters to be the previously active parameters") +) +if dt.preferences.read('module_CollectHelper','folder','bool') then dt.gui.libs.image.register_action( - "CollectHelper_prev", _("collect: previous"), - function() PreviousCollection() end, - _("Sets the Collect parameters to be the previously active parameters") + _("collect: folder"), + function() CollectOnFolder(_ , false) end, + _("Sets the Collect parameters to be the selected images's folder") ) end -if dt.preferences.read('module_CollectHelper','folder','bool') then - if CURR_API_STRING < "6.2.3" then - dt.gui.libs.image.register_action( - _("collect: folder"), - function() CollectOnFolder(_ , false) end, - _("Sets the Collect parameters to be the selected images's folder") - ) - else - dt.gui.libs.image.register_action( - "CollectHelper_folder", _("collect: folder"), - function() CollectOnFolder(_ , false) end, - _("Sets the Collect parameters to be the selected images's folder") - ) - end -end if dt.preferences.read('module_CollectHelper','colors','bool') then - if CURR_API_STRING < "6.2.3" then - dt.gui.libs.image.register_action( - _("collect: color label(s)"), - function() CollectOnColors(_ , false) end, - _("Sets the Collect parameters to be the selected images's color label(s)") - ) - else - dt.gui.libs.image.register_action( - "CollectHelper_labels", _("collect: color label(s)"), - function() CollectOnColors(_ , false) end, - _("Sets the Collect parameters to be the selected images's color label(s)") - ) - end + dt.gui.libs.image.register_action( + _("collect: color label(s)"), + function() CollectOnColors(_ , false) end, + _("Sets the Collect parameters to be the selected images's color label(s)") + ) end if dt.preferences.read('module_CollectHelper','all_and','bool') then - if CURR_API_STRING < "6.2.3" then - dt.gui.libs.image.register_action( - _("collect: all (AND)"), - function() CollectOnAll_AND() end, - _("Sets the Collect parameters based on all activated CollectHelper options") - ) - else - dt.gui.libs.image.register_action( - "CollectHelper_and", _("collect: all (AND)"), - function() CollectOnAll_AND() end, - _("Sets the Collect parameters based on all activated CollectHelper options") - ) - end + dt.gui.libs.image.register_action( + _("collect: all (AND)"), + function() CollectOnAll_AND() end, + _("Sets the Collect parameters based on all activated CollectHelper options") + ) end -- PREFERENCES -- diff --git a/contrib/OpenInExplorer.lua b/contrib/OpenInExplorer.lua index d9fe4a6b..4f0c5d59 100644 --- a/contrib/OpenInExplorer.lua +++ b/contrib/OpenInExplorer.lua @@ -184,20 +184,11 @@ end -- GUI -- -if CURR_API_STRING < "6.2.3" then - dt.gui.libs.image.register_action( - _("show in file explorer"), - function() open_in_fmanager() end, - _("Open the file manager at the selected image's location") - ) -else - dt.gui.libs.image.register_action( - "OpenInExplorer", _("show in file explorer"), - function() open_in_fmanager() end, - _("Open the file manager at the selected image's location") - ) -end - +dt.gui.libs.image.register_action( + _("show in file explorer"), + function() open_in_fmanager() end, + _("Open the file manager at the selected image's location") +) if act_os ~= "windows" then dt.preferences.register("OpenInExplorer", "linked_image_files_dir", -- name diff --git a/contrib/clear_GPS.lua b/contrib/clear_GPS.lua index a67fc1a4..d919ccaf 100644 --- a/contrib/clear_GPS.lua +++ b/contrib/clear_GPS.lua @@ -64,21 +64,11 @@ local function clear_GPS(images) end end -if CURR_API_STRING < "6.2.3" then - dt.gui.libs.image.register_action( - _("clear GPS data"), - function(event, images) clear_GPS(images) end, - _("Clear GPS data from selected images") - ) -else - dt.gui.libs.image.register_action( - _"clear_GPS", ("clear GPS data"), - function(event, images) clear_GPS(images) end, - _("Clear GPS data from selected images") - ) -end - - +dt.gui.libs.image.register_action( + _("clear GPS data"), + function(event, images) clear_GPS(images) end, + _("Clear GPS data from selected images") +) dt.register_event( "clearGPS", "shortcut", diff --git a/contrib/select_untagged.lua b/contrib/select_untagged.lua index 7173f5a3..0c8e9698 100644 --- a/contrib/select_untagged.lua +++ b/contrib/select_untagged.lua @@ -64,14 +64,7 @@ local function select_untagged_images(event, images) return selection end -if CURR_API_STRING >= "6.2.2" then - dt.gui.libs.select.register_selection( - "select_untagged", _("select untagged"), - select_untagged_images, - _("select all images containing no tags or only tags added by darktable")) -else - dt.gui.libs.select.register_selection( - _("select untagged"), - select_untagged_images, - _("select all images containing no tags or only tags added by darktable")) -end \ No newline at end of file +dt.gui.libs.select.register_selection( + _("select untagged"), + select_untagged_images, + _("select all images containing no tags or only tags added by darktable")) diff --git a/examples/multi_os.lua b/examples/multi_os.lua index d71f0d47..c7afdf3b 100644 --- a/examples/multi_os.lua +++ b/examples/multi_os.lua @@ -231,22 +231,13 @@ end Add a button to the selected images module in lighttable ]] -if CURR_API_STRING < "6.2.3" then - dt.gui.libs.image.register_action( - _("extract embedded jpeg"), - function(event, images) extract_embedded_jpeg(images) end, - "extract embedded jpeg" - ) -else - dt.gui.libs.image.register_action( - "multi_os", _("extract embedded jpeg"), - function(event, images) extract_embedded_jpeg(images) end, - "extract embedded jpeg" - ) -end +dt.gui.libs.image.register_action( + _("extract embedded jpeg"), + function(event, images) extract_embedded_jpeg(images) end, + "extract embedded jpeg" +) - --[[ Add a shortcut ]] diff --git a/lib/darktable_transition.lua b/lib/darktable_transition.lua deleted file mode 100644 index da5a4211..00000000 --- a/lib/darktable_transition.lua +++ /dev/null @@ -1,51 +0,0 @@ ---[[ - - darktable_transition.lua - temporary library to help with API transition - - Copyright (C) 2016 Bill Ferguson . - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -]] ---[[ - darktable_transition - routines to maintain compatibility with new and previous API versions - -]] - -local dt -for k,v in pairs(package.loaded) do - if string.match(k, "darktable") then - dt = v - break - end -end - -if dt then - dt.orig_register_event = dt.register_event - - function dt.register_event(name, event, callback, tooltip) - if dt.configuration.api_version_string >= "6.2.1" then - if tooltip then - dt.orig_register_event(name, event, callback, tooltip) - else - dt.orig_register_event(name, event, callback) - end - else - if tooltip then - dt.orig_register_event(event, callback, tooltip) - else - dt.orig_register_event(event, callback) - end - end - end -end diff --git a/official/copy_paste_metadata.lua b/official/copy_paste_metadata.lua index 2c100291..1db3d622 100644 --- a/official/copy_paste_metadata.lua +++ b/official/copy_paste_metadata.lua @@ -114,37 +114,17 @@ local function paste(images) end end -if CURR_API_STRING < "6.2.3" then - dt.gui.libs.image.register_action( - _("copy metadata"), - function(event, images) copy(images[1]) end, - _("copy metadata of the first selected image") - ) -else - dt.gui.libs.image.register_action( - "metadata_copy", _("copy metadata"), - function(event, images) copy(images[1]) end, - _("copy metadata of the first selected image") - ) -end - - - -if CURR_API_STRING < "6.2.3" then - dt.gui.libs.image.register_action( - _("paste metadata"), - function(event, images) paste(images) end, - _("paste metadata to the selected images") - ) -else - dt.gui.libs.image.register_action( - "metadata_paste", _("paste metadata"), - function(event, images) paste(images) end, - _("paste metadata to the selected images") - ) -end - +dt.gui.libs.image.register_action( + _("copy metadata"), + function(event, images) copy(images[1]) end, + _("copy metadata of the first selected image") +) +dt.gui.libs.image.register_action( + _("paste metadata"), + function(event, images) paste(images) end, + _("paste metadata to the selected images") +) dt.register_event( "capmd1", "shortcut", diff --git a/tools/script_manager.lua b/tools/script_manager.lua index 39812a7f..531cd4e3 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -68,7 +68,7 @@ end -- api check -du.check_min_api_version("5.0.0", "script_manager") +du.check_min_api_version("6.1.0", "script_manager") -- - - - - - - - - - - - - - - - - - - - - - - - @@ -461,9 +461,7 @@ local function populate_buttons(category, first, last) else button.label = script.name .. _(" stopped") end - if CURR_API_STRING >= "6.0.1" then - button.ellipsize = "middle" - end + button.ellipsize = "middle" button.sensitive = true button.tooltip = script.doc button.clicked_callback = function (this) @@ -772,12 +770,8 @@ for i =1, DEFAULT_BUTTONS_PER_PAGE do sm.page_status.buttons_create = sm.page_status.buttons_created + 1 end -local page_back = "<" -local page_forward = ">" -if CURR_API_STRING < "6.1.0" then - page_back = " < " - page_forward = " > " -end +local page_back = " < " +local page_forward = " > " sm.widgets.page_status = dt.new_widget("label"){label = _("Page:")} sm.widgets.page_back = dt.new_widget("button"){ @@ -849,10 +843,8 @@ sm.widgets.main_stack = dt.new_widget("stack"){ sm.widgets.scripts, } -if CURR_API_STRING >= "6.0.1" then - sm.widgets.main_stack.h_size_fixed = false - sm.widgets.main_stack.v_size_fixed = false -end +sm.widgets.main_stack.h_size_fixed = false +sm.widgets.main_stack.v_size_fixed = false -- main menu From 4b63240ab9bef15589dcd15eb2a494b7ece37cd4 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Fri, 11 Jun 2021 21:44:38 -0400 Subject: [PATCH 163/445] Reverted register_event calls back to API 6.1.0 --- contrib/AutoGrouper.lua | 4 ++-- contrib/HDRMerge.lua | 4 ++-- contrib/LabelsToTags.lua | 3 +-- contrib/OpenInExplorer.lua | 3 +-- contrib/autostyle.lua | 5 ++--- contrib/clear_GPS.lua | 4 ++-- contrib/copy_attach_detach_tags.lua | 11 +++++------ contrib/cr2hdr.lua | 7 +++---- contrib/exportLUT.lua | 3 +-- contrib/ext_editor.lua | 5 ++--- contrib/face_recognition.lua | 4 ++-- contrib/fujifilm_dynamic_range.lua | 3 +-- contrib/fujifilm_ratings.lua | 4 ++-- contrib/geoToolbox.lua | 12 ++++++------ contrib/gpx_export.lua | 4 ++-- contrib/image_time.lua | 4 ++-- contrib/photils.lua | 6 +++--- contrib/quicktag.lua | 5 ++--- contrib/rate_group.lua | 15 +++++++-------- contrib/rename-tags.lua | 3 +-- contrib/slideshowMusic.lua | 4 ++-- contrib/transfer_hierarchy.lua | 3 +-- examples/moduleExample.lua | 3 +-- examples/multi_os.lua | 5 ++--- official/copy_paste_metadata.lua | 5 ++--- official/enfuse.lua | 3 +-- official/generate_image_txt.lua | 3 +-- official/image_path_in_ui.lua | 3 +-- official/import_filter_manager.lua | 3 +-- official/save_selection.lua | 8 ++++---- tools/executable_manager.lua | 3 +-- tools/script_manager.lua | 3 +-- 32 files changed, 67 insertions(+), 88 deletions(-) diff --git a/contrib/AutoGrouper.lua b/contrib/AutoGrouper.lua index 849b8818..fd7bbac9 100644 --- a/contrib/AutoGrouper.lua +++ b/contrib/AutoGrouper.lua @@ -37,7 +37,7 @@ selected images, the other button performs grouping on the entire active collect ]] local dt = require "darktable" - require "lib/darktable_transition" + local MOD = 'autogrouper' local gettext = dt.gettext -- Tell gettext where to find the .mo file translating messages for a particular domain @@ -176,7 +176,7 @@ if dt.gui.current_view().id == "lighttable" then else if not Ag.event_registered then dt.register_event( - "AutoGrouper", "view-changed", + "view-changed", function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() diff --git a/contrib/HDRMerge.lua b/contrib/HDRMerge.lua index aafff83f..476e1c6b 100644 --- a/contrib/HDRMerge.lua +++ b/contrib/HDRMerge.lua @@ -46,7 +46,7 @@ Select a style, whether you want tags to be copied from the original, and any ad local dt = require 'darktable' local df = require 'lib/dtutils.file' - require "lib/darktable_transition" + local dsys = require 'lib/dtutils.system' local mod = 'module_HDRMerge' local os_path_seperator = '/' @@ -439,7 +439,7 @@ if dt.gui.current_view().id == "lighttable" then else if not HDRM.event_registered then dt.register_event( - "HDRmerge", "view-changed", + "view-changed", function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() diff --git a/contrib/LabelsToTags.lua b/contrib/LabelsToTags.lua index e2dc5c42..50e1359f 100644 --- a/contrib/LabelsToTags.lua +++ b/contrib/LabelsToTags.lua @@ -49,7 +49,6 @@ local darktable = require("darktable") local du = require "lib/dtutils" - require "lib/darktable_transition" du.check_min_api_version("3.0.0", "LabelsToTags") @@ -249,7 +248,7 @@ if darktable.gui.current_view().id == "lighttable" then else if not ltt.event_registered then darktable.register_event( - LIB_ID, "view-changed", + "view-changed", function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() diff --git a/contrib/OpenInExplorer.lua b/contrib/OpenInExplorer.lua index 4f0c5d59..53a8e0bb 100644 --- a/contrib/OpenInExplorer.lua +++ b/contrib/OpenInExplorer.lua @@ -50,7 +50,6 @@ As an alternative option you can choose to show the image file names as symbolic local dt = require "darktable" local du = require "lib/dtutils" local df = require "lib/dtutils.file" - require "lib/darktable_transition" local dsys = require "lib/dtutils.system" local gettext = dt.gettext @@ -211,7 +210,7 @@ if act_os ~= "windows" then end dt.register_event( - "OpenInExplorer", "shortcut", + "shortcut", function(event, shortcut) open_in_fmanager() end, "OpenInExplorer" ) diff --git a/contrib/autostyle.lua b/contrib/autostyle.lua index fc726a62..cd144b09 100644 --- a/contrib/autostyle.lua +++ b/contrib/autostyle.lua @@ -38,7 +38,6 @@ GPLv2 local darktable = require "darktable" local du = require "lib/dtutils" - require "lib/darktable_transition" local filelib = require "lib/dtutils.file" -- Forward declare the functions @@ -153,12 +152,12 @@ function get_stdout(cmd) end -- Registering events -darktable.register_event("autostyle", "shortcut", autostyle_apply, +darktable.register_event("shortcut", autostyle_apply, "Apply your chosen style from exiftool tags") darktable.preferences.register("autostyle","exif_tag","string","Autostyle: EXIF_tag=value=>style","apply a style automatically if an EXIF_tag matches value. Find the tag with exiftool","") -darktable.register_event("autostyle", "post-import-image", +darktable.register_event("post-import-image", autostyle_apply_one_image_event) diff --git a/contrib/clear_GPS.lua b/contrib/clear_GPS.lua index d919ccaf..5495abf3 100644 --- a/contrib/clear_GPS.lua +++ b/contrib/clear_GPS.lua @@ -38,7 +38,7 @@ local dt = require "darktable" local du = require "lib/dtutils" - require "lib/darktable_transition" + local gettext = dt.gettext -- not a number @@ -71,7 +71,7 @@ dt.gui.libs.image.register_action( ) dt.register_event( - "clearGPS", "shortcut", + "shortcut", function(event, shortcut) clear_GPS(dt.gui.action_images) end, _("Clear GPS data") ) diff --git a/contrib/copy_attach_detach_tags.lua b/contrib/copy_attach_detach_tags.lua index 6f2b9364..45f2c036 100644 --- a/contrib/copy_attach_detach_tags.lua +++ b/contrib/copy_attach_detach_tags.lua @@ -39,7 +39,6 @@ USAGE local dt = require "darktable" local du = require "lib/dtutils" local debug = require "darktable.debug" - require "lib/darktable_transition" local gettext = dt.gettext @@ -235,7 +234,7 @@ if dt.gui.current_view().id == "lighttable" then else if not cadt.event_registered then dt.register_event( - "cadt", "view-changed", + "view-changed", function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() @@ -248,22 +247,22 @@ end -- shortcut for copy -dt.register_event("cadt_ct", "shortcut", +dt.register_event("shortcut", mcopy_tags, _('copy tags from selected image(s)')) -- shortcut for attach -dt.register_event("cadt_at", "shortcut", +dt.register_event("shortcut", attach_tags, _('paste tags to selected image(s)')) -- shortcut for detaching tags -dt.register_event("cadt_dt", "shortcut", +dt.register_event("shortcut", detach_tags, _('remove tags from selected image(s)')) -- shortcut for replace tags -dt.register_event("cadt_rt", "shortcut", +dt.register_event("shortcut", replace_tags, _('replace tags from selected image(s)')) diff --git a/contrib/cr2hdr.lua b/contrib/cr2hdr.lua index c27082e6..15b348a3 100644 --- a/contrib/cr2hdr.lua +++ b/contrib/cr2hdr.lua @@ -34,7 +34,6 @@ USAGE local darktable = require "darktable" local du = require "lib/dtutils" - require "lib/darktable_transition" -- Tested with darktable 2.0.1 du.check_min_api_version("2.0.0", "cr2hdr") @@ -109,11 +108,11 @@ local function convert_action_images(shortcut) convert_images() end -darktable.register_event("cr2hdr", "shortcut", +darktable.register_event("shortcut", convert_action_images, "Run cr2hdr (Magic Lantern DualISO converter) on selected images") -darktable.register_event("cr2hdr", "post-import-image", +darktable.register_event("post-import-image", file_imported) -darktable.register_event("cr2hdr", "post-import-film", +darktable.register_event("post-import-film", film_imported) darktable.preferences.register("cr2hdr", "onimport", "bool", "Invoke on import", "If true then cr2hdr will try to proccess every file during importing. Warning: cr2hdr is quite slow even in figuring out on whether the file is Dual ISO or not.", false) diff --git a/contrib/exportLUT.lua b/contrib/exportLUT.lua index 4b039a87..a0858d6a 100644 --- a/contrib/exportLUT.lua +++ b/contrib/exportLUT.lua @@ -30,7 +30,6 @@ local dt = require "darktable" local du = require "lib/dtutils" local df = require("lib/dtutils.file") local ds = require("lib/dtutils.system") - require "lib/darktable_transition" local gettext = dt.gettext @@ -163,7 +162,7 @@ if dt.gui.current_view().id == "lighttable" then else if not eL.event_registered then dt.register_event( - "exportLUT", "view-changed", + "view-changed", function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() diff --git a/contrib/ext_editor.lua b/contrib/ext_editor.lua index 7e1460c8..3aa622a1 100644 --- a/contrib/ext_editor.lua +++ b/contrib/ext_editor.lua @@ -68,7 +68,6 @@ local dt = require "darktable" local du = require "lib/dtutils" local df = require "lib/dtutils.file" - require "lib/darktable_transition" local dtsys = require "lib/dtutils.system" @@ -429,7 +428,7 @@ if dt.gui.current_view().id == "lighttable" then else if not ee.event_registered then dt.register_event( - MODULE_NAME, "view-changed", + "view-changed", function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module(show_dr) @@ -466,7 +465,7 @@ dt.preferences.register(MODULE_NAME, "show_in_darkrooom", "bool", -- register the new shortcuts ------------------------------------------------- for i = 1, MAX_EDITORS do - dt.register_event(MODULE_NAME .. i, "shortcut", + dt.register_event("shortcut", program_shortcut, _("edit with program ")..string.format("%02d", i)) end diff --git a/contrib/face_recognition.lua b/contrib/face_recognition.lua index 77cd2abb..980c0d71 100644 --- a/contrib/face_recognition.lua +++ b/contrib/face_recognition.lua @@ -44,7 +44,7 @@ local dt = require "darktable" local du = require "lib/dtutils" local df = require "lib/dtutils.file" local dtsys = require "lib/dtutils.system" - require "lib/darktable_transition" + local gettext = dt.gettext -- constants @@ -491,7 +491,7 @@ if dt.gui.current_view().id == "lighttable" then else if not fc.event_registered then dt.register_event( - MODULE, "view-changed", + "view-changed", function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() diff --git a/contrib/fujifilm_dynamic_range.lua b/contrib/fujifilm_dynamic_range.lua index 49866755..66bfd1fa 100644 --- a/contrib/fujifilm_dynamic_range.lua +++ b/contrib/fujifilm_dynamic_range.lua @@ -60,7 +60,6 @@ cameras may behave in other ways. local dt = require "darktable" local du = require "lib/dtutils" local df = require "lib/dtutils.file" - require "lib/darktable_transition" du.check_min_api_version("4.0.0", "fujifilm_dynamic_range") local CURR_API_STRING = dt.configuration.api_version_string @@ -106,7 +105,7 @@ local function detect_dynamic_range(event, image) dt.print_log("[fujifilm_dynamic_range] raw exposure bias " .. tostring(raf_result)) end -dt.register_event("fujifilm_dr", "post-import-image", +dt.register_event("post-import-image", detect_dynamic_range) dt.print_log("[fujifilm_dynamic_range] loaded") diff --git a/contrib/fujifilm_ratings.lua b/contrib/fujifilm_ratings.lua index 05319d4c..524d1bd2 100644 --- a/contrib/fujifilm_ratings.lua +++ b/contrib/fujifilm_ratings.lua @@ -26,7 +26,7 @@ Dependencies: local dt = require "darktable" local du = require "lib/dtutils" local df = require "lib/dtutils.file" - require "lib/darktable_transition" + local gettext = dt.gettext du.check_min_api_version("4.0.0", "fujifilm_ratings") @@ -68,7 +68,7 @@ local function detect_rating(event, image) end end -dt.register_event("fujifilm_rat", "post-import-image", +dt.register_event("post-import-image", detect_rating) print(_("fujifilm_ratings loaded.")) diff --git a/contrib/geoToolbox.lua b/contrib/geoToolbox.lua index cdbc1c0a..09b0513f 100644 --- a/contrib/geoToolbox.lua +++ b/contrib/geoToolbox.lua @@ -28,7 +28,7 @@ require "geoToolbox" local dt = require "darktable" local du = require "lib/dtutils" local df = require "lib/dtutils.file" - require "lib/darktable_transition" + local gettext = dt.gettext du.check_min_api_version("3.0.0", "geoToolbox") @@ -689,7 +689,7 @@ if dt.gui.current_view().id == "lighttable" then else if not gT.event_registered then dt.register_event( - "geoToolbox", "view-changed", + "view-changed", function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() @@ -709,14 +709,14 @@ dt.preferences.register("geoToolbox", '' ) -- Register -dt.register_event("geoToolbox_cd", "shortcut", +dt.register_event("shortcut", print_calc_distance, _("Calculate the distance from latitude and longitude in km")) -dt.register_event("geoToolbox", "mouse-over-image-changed", +dt.register_event("mouse-over-image-changed", toolbox_calc_distance) -dt.register_event("geoToolbox_wg", "shortcut", +dt.register_event("shortcut", select_with_gps, _("Select all images with GPS information")) -dt.register_event("geoToolbox_ng", "shortcut", +dt.register_event("shortcut", select_without_gps, _("Select all images without GPS information")) -- vim: shiftwidth=2 expandtab tabstop=2 cindent syntax=lua diff --git a/contrib/gpx_export.lua b/contrib/gpx_export.lua index 58e4147a..0995ba98 100644 --- a/contrib/gpx_export.lua +++ b/contrib/gpx_export.lua @@ -25,7 +25,7 @@ For each source folder, a separate is generated in the gpx file. local dt = require "darktable" local df = require "lib/dtutils.file" local dl = require "lib/dtutils" - require "lib/darktable_transition" + local gettext = dt.gettext dl.check_min_api_version("3.0.0", "gpx-export") @@ -175,7 +175,7 @@ if dt.gui.current_view().id == "lighttable" then else if not gpx.event_registered then dt.register_event( - "gpx_export", "view-changed", + "view-changed", function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() diff --git a/contrib/image_time.lua b/contrib/image_time.lua index 0f09c2d0..ed60a5a9 100644 --- a/contrib/image_time.lua +++ b/contrib/image_time.lua @@ -107,7 +107,7 @@ local dt = require "darktable" local du = require "lib/dtutils" local df = require "lib/dtutils.file" local ds = require "lib/dtutils.string" - require "lib/darktable_transition" + local gettext = dt.gettext local img_time = {} @@ -553,7 +553,7 @@ if dt.gui.current_view().id == "lighttable" then else if not img_time.event_registered then dt.register_event( - "image_time", "view-changed", + "view-changed", function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() diff --git a/contrib/photils.lua b/contrib/photils.lua index e3e0e4b9..c2858f2a 100644 --- a/contrib/photils.lua +++ b/contrib/photils.lua @@ -39,7 +39,7 @@ local dt = require "darktable" local du = require "lib/dtutils" local df = require "lib/dtutils.file" - require "lib/darktable_transition" + local dtsys = require "lib/dtutils.system" local MODULE_NAME = "photils" @@ -454,7 +454,7 @@ dt.preferences.register(MODULE_NAME, "The embedded thumbnail could speedup the tag suggestion but can fail if the RAW file is not supported."), true) -dt.register_event("photils", "mouse-over-image-changed", +dt.register_event("mouse-over-image-changed", PHOTILS.image_changed) if dt.gui.current_view().id == "lighttable" then @@ -462,7 +462,7 @@ if dt.gui.current_view().id == "lighttable" then else if not PHOTILS.event_registered then dt.register_event( - "photils", "view-changed", + "view-changed", function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() diff --git a/contrib/quicktag.lua b/contrib/quicktag.lua index ef1987ec..51bf57d9 100644 --- a/contrib/quicktag.lua +++ b/contrib/quicktag.lua @@ -45,7 +45,6 @@ USAGE local dt = require "darktable" local du = require "lib/dtutils" - require "lib/darktable_transition" local debug = require "darktable.debug" local qt = {} @@ -258,7 +257,7 @@ if dt.gui.current_view().id == "lighttable" then else if not qt.event_registered then dt.register_event( - "quicktag", "view-changed", + "view-changed", function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() @@ -271,7 +270,7 @@ end -- create shortcuts for i=1,qnr do - dt.register_event("quicktag", "shortcut", + dt.register_event("shortcut", function(event, shortcut) tagattach(tostring(quicktag_table[i])) end, string.format(_("quicktag %i"),i)) end diff --git a/contrib/rate_group.lua b/contrib/rate_group.lua index 80fb4a62..88bbf555 100644 --- a/contrib/rate_group.lua +++ b/contrib/rate_group.lua @@ -40,7 +40,6 @@ local dt = require "darktable" local du = require "lib/dtutils" - require "lib/darktable_transition" -- added version check du.check_min_api_version("3.0.0", "rate_group") @@ -61,37 +60,37 @@ local function apply_rating(rating) end end -dt.register_event("rg_reject", "shortcut", +dt.register_event("shortcut", function(event, shortcut) apply_rating(-1) end, "Reject group") -dt.register_event("rg0", "shortcut", +dt.register_event("shortcut", function(event, shortcut) apply_rating(0) end, "Rate group 0") -dt.register_event("rg1", "shortcut", +dt.register_event("shortcut", function(event, shortcut) apply_rating(1) end, "Rate group 1") -dt.register_event("rg2", "shortcut", +dt.register_event("shortcut", function(event, shortcut) apply_rating(2) end, "Rate group 2") -dt.register_event("rg3", "shortcut", +dt.register_event("shortcut", function(event, shortcut) apply_rating(3) end, "Rate group 3") -dt.register_event("rg4", "shortcut", +dt.register_event("shortcut", function(event, shortcut) apply_rating(4) end, "Rate group 4") -dt.register_event("rg5", "shortcut", +dt.register_event("shortcut", function(event, shortcut) apply_rating(5) end, "Rate group 5") diff --git a/contrib/rename-tags.lua b/contrib/rename-tags.lua index e8a5c9e3..6f1eea90 100644 --- a/contrib/rename-tags.lua +++ b/contrib/rename-tags.lua @@ -30,7 +30,6 @@ Changes local darktable = require "darktable" local du = require "lib/dtutils" - require "lib/darktable_transition" local debug = require "darktable.debug" -- check API version @@ -138,7 +137,7 @@ if darktable.gui.current_view().id == "lighttable" then else if not rt.event_registered then darktable.register_event( - "rename_tags", "view-changed", + "view-changed", function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() diff --git a/contrib/slideshowMusic.lua b/contrib/slideshowMusic.lua index ff216af8..0e66f4d4 100644 --- a/contrib/slideshowMusic.lua +++ b/contrib/slideshowMusic.lua @@ -27,7 +27,7 @@ USAGE local dt = require "darktable" local du = require "lib/dtutils" local df = require "lib/dtutils.file" - require "lib/darktable_transition" + local gettext = dt.gettext du.check_min_api_version("2.0.2", "slideshowMusic") @@ -79,5 +79,5 @@ dt.preferences.register("slideshowMusic", _("Plays music with rhythmbox if a slideshow starts"), true) -- Register -dt.register_event("slideshow_music", "view-changed", +dt.register_event("view-changed", playSlideshowMusic) diff --git a/contrib/transfer_hierarchy.lua b/contrib/transfer_hierarchy.lua index 03c1523f..291950da 100755 --- a/contrib/transfer_hierarchy.lua +++ b/contrib/transfer_hierarchy.lua @@ -76,7 +76,6 @@ local darktable = require("darktable") local dtutils = require("lib/dtutils") local dtutils_file = require("lib/dtutils.file") local dtutils_system = require("lib/dtutils.system") - require "lib/darktable_transition" local LIB_ID = "transfer_hierarchy" dtutils.check_min_api_version("5.0.0", LIB_ID) @@ -368,7 +367,7 @@ if darktable.gui.current_view().id == "lighttable" then else if not th.event_registered then darktable.register_event( - LIB_ID, "view-changed", + "view-changed", function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() diff --git a/examples/moduleExample.lua b/examples/moduleExample.lua index b778dca2..93c182df 100644 --- a/examples/moduleExample.lua +++ b/examples/moduleExample.lua @@ -32,7 +32,6 @@ https://www.darktable.org/lua-api/index.html.php#darktable_new_widget local dt = require "darktable" local du = require "lib/dtutils" - require "lib/darktable_transition" du.check_min_api_version("3.0.0", "moduleExample") local CURR_API_STRING = dt.configuration.api_version_string @@ -149,7 +148,7 @@ else if not mE.event_registered then -- if we are not in lighttable view then register an event to signal when we might be -- https://www.darktable.org/lua-api/index.html#darktable_register_event dt.register_event( - "mdouleExample", "view-changed", -- we want to be informed when the view changes + "view-changed", -- we want to be informed when the view changes function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then -- if the view changes from darkroom to lighttable install_module() -- register the lib diff --git a/examples/multi_os.lua b/examples/multi_os.lua index c7afdf3b..1227e5ea 100644 --- a/examples/multi_os.lua +++ b/examples/multi_os.lua @@ -52,8 +52,7 @@ ]] local dt = require "darktable" - require "lib/darktable_transition" - + --[[ require "lib/..." provides access to functions that have been pulled from various scripts and consolidated into libraries. Using the libraries eliminates having to @@ -243,7 +242,7 @@ dt.gui.libs.image.register_action( ]] dt.register_event( - "multi_os", "shortcut", + "shortcut", function(event, shortcut) extract_embedded_jpeg(dt.gui.action_images) end, "extract embedded jpeg" ) diff --git a/official/copy_paste_metadata.lua b/official/copy_paste_metadata.lua index 1db3d622..05808169 100644 --- a/official/copy_paste_metadata.lua +++ b/official/copy_paste_metadata.lua @@ -27,7 +27,6 @@ USAGE local dt = require "darktable" local du = require "lib/dtutils" - require "lib/darktable_transition" local gettext = dt.gettext du.check_min_api_version("3.0.0", "copy_paste_metadata") @@ -127,13 +126,13 @@ dt.gui.libs.image.register_action( ) dt.register_event( - "capmd1", "shortcut", + "shortcut", function(event, shortcut) copy(dt.gui.action_images[1]) end, "copy metadata" ) dt.register_event( - "capmd2", "shortcut", + "shortcut", function(event, shortcut) paste(dt.gui.action_images) end, "paste metadata" ) diff --git a/official/enfuse.lua b/official/enfuse.lua index 1f494d90..ecb2b8e1 100644 --- a/official/enfuse.lua +++ b/official/enfuse.lua @@ -36,7 +36,6 @@ local dt = require "darktable" local du = require "lib/dtutils" local df = require "lib/dtutils.file" local dtsys = require "lib/dtutils.system" - require "lib/darktable_transition" local PS = dt.configuration.running_os == "windows" and "\\" or "/" local CURR_API_STRING = dt.configuration.api_version_string @@ -270,7 +269,7 @@ if enfuse_installed then else if not enf.event_registered then dt.register_event( - "enfuse", "view-changed", + "view-changed", function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() diff --git a/official/generate_image_txt.lua b/official/generate_image_txt.lua index b4ea4756..3d9906d1 100644 --- a/official/generate_image_txt.lua +++ b/official/generate_image_txt.lua @@ -36,7 +36,6 @@ USAGE local dt = require "darktable" local du = require "lib/dtutils" - require "lib/darktable_transition" require "darktable.debug" du.check_min_api_version("2.1.0", "generate_image_txt") @@ -67,7 +66,7 @@ end local command_setting = dt.preferences.read("generate_image_txt", "command", "string") check_command(command_setting) -dt.register_event("gen_img_txt", "mouse-over-image-changed", +dt.register_event("mouse-over-image-changed", function(event, img) -- no need to waste processing time if the image has a txt file already if not img or img.has_txt or not dt.preferences.read("generate_image_txt", "enabled", "bool") then diff --git a/official/image_path_in_ui.lua b/official/image_path_in_ui.lua index d98e5710..23ff89a0 100644 --- a/official/image_path_in_ui.lua +++ b/official/image_path_in_ui.lua @@ -30,7 +30,6 @@ This plugin will add a widget at the bottom of the left column in lighttable mod ]] local dt = require "darktable" local du = require "lib/dtutils" - require "lib/darktable_transition" du.check_min_api_version("2.0.0", "image_path_in_ui") local CURR_API_STRING = dt.configuration.api_version_string @@ -86,7 +85,7 @@ else end end -dt.register_event("ipiu", "mouse-over-image-changed", reset_widget); +dt.register_event("mouse-over-image-changed", reset_widget); -- -- vim: shiftwidth=2 expandtab tabstop=2 cindent syntax=lua diff --git a/official/import_filter_manager.lua b/official/import_filter_manager.lua index 74b50276..63466c59 100644 --- a/official/import_filter_manager.lua +++ b/official/import_filter_manager.lua @@ -31,7 +31,6 @@ USAGE ]] local dt = require "darktable" - require "lib/darktable_transition" local import_filter_list = {} local n_import_filters = 1 @@ -58,7 +57,7 @@ dt.gui.libs.import.register_widget(filter_dropdown) -- this is just a wrapper which calls the active import filter -dt.register_event("ifm", "pre-import", function(event, images) +dt.register_event("pre-import", function(event, images) local active_filter = dt.preferences.read("import_filter_manager", "active_filter", "string") if active_filter == "" then return end local callback = import_filter_list[active_filter] diff --git a/official/save_selection.lua b/official/save_selection.lua index ba229f27..6861b5f0 100644 --- a/official/save_selection.lua +++ b/official/save_selection.lua @@ -35,7 +35,7 @@ increase it if you need more temporary selection buffers ]] local dt = require "darktable" local du = require "lib/dtutils" - require "lib/darktable_transition" + du.check_min_api_version("2.0.0", "save_selection") local CURR_API_STRING = dt.configuration.api_version_string @@ -43,16 +43,16 @@ local buffer_count = 5 for i=1,buffer_count do local saved_selection - dt.register_event("save_selection", "shortcut", function() + dt.register_event("shortcut", function() saved_selection = dt.gui.selection() end,"save to buffer "..i) - dt.register_event("save_selection1", "shortcut", function() + dt.register_event("shortcut", function() dt.gui.selection(saved_selection) end,"restore from buffer "..i) end local bounce_buffer = {} -dt.register_event("save_selection2", "shortcut", function() +dt.register_event("shortcut", function() bounce_buffer = dt.gui.selection(bounce_buffer) end,"switch selection with temporary buffer") diff --git a/tools/executable_manager.lua b/tools/executable_manager.lua index c2afcece..14c4d7b3 100644 --- a/tools/executable_manager.lua +++ b/tools/executable_manager.lua @@ -31,7 +31,6 @@ local dt = require "darktable" local du = require "lib/dtutils" local df = require "lib/dtutils.file" - require "lib/darktable_transition" du.check_min_api_version("5.0.0", "executable_manager") @@ -216,7 +215,7 @@ if dt.gui.current_view().id == "lighttable" then else if not exec_man.event_registered then dt.register_event( - "executable_manager", "view-changed", + "view-changed", function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() diff --git a/tools/script_manager.lua b/tools/script_manager.lua index 531cd4e3..3ab0b547 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -54,7 +54,6 @@ local df = require "lib/dtutils.file" local ds = require "lib/dtutils.string" local dtsys = require "lib/dtutils.system" local log = require "lib/dtutils.log" - require "lib/darktable_transition" local gettext = dt.gettext @@ -875,7 +874,7 @@ if dt.gui.current_view().id == "lighttable" then else if not sm.event_registered then dt.register_event( - "script_manager", "view-changed", + "view-changed", function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() From 2041fb34c95fb7f494fa207ce6e27cc2c63b0a93 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sat, 19 Jun 2021 13:57:39 -0400 Subject: [PATCH 164/445] [image_path_in_ui] changed case of module title to respect darktable UI. --- ChangeLog.md | 2 ++ official/image_path_in_ui.lua | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 19b2ed36..346b4fa8 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,5 +1,7 @@ ## Changes from most recent to oldest +** 19 Jun 2021 - wpferguson - fix issue 312, image_path_in_ui** + ** 02 Jun 2021 - wpferguson - fix contrib/quicktag** * set new entry field is_password to false so entry is visible to user while typing. diff --git a/official/image_path_in_ui.lua b/official/image_path_in_ui.lua index d98e5710..5968ccfd 100644 --- a/official/image_path_in_ui.lua +++ b/official/image_path_in_ui.lua @@ -43,8 +43,8 @@ local main_label = dt.new_widget("label"){selectable = true, ellipsize = "middle local function install_module() if not ipiu.module_installed then - dt.register_lib("image_path_no_ui","Selected Images path",true,false,{ - [dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_LEFT_CENTER",300} + dt.register_lib("image_path_no_ui", "selected images path", true, false,{ + [dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_LEFT_CENTER", 300} }, main_label ) ipiu.module_installed = true From 5da64a7da034be86d268ca6e76d8bb665486bd4f Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sat, 19 Jun 2021 23:34:14 -0400 Subject: [PATCH 165/445] [API 7.0.0 compatibility] Made changes to take advantage of the latest API changes including the ability to start and stop most scripts. --- contrib/AutoGrouper.lua | 214 ++++++++++++++++------------ contrib/CollectHelper.lua | 48 +++++-- contrib/HDRMerge.lua | 31 +++- contrib/LabelsToTags.lua | 65 ++++++--- contrib/OpenInExplorer.lua | 30 +++- contrib/RL_out_sharp.lua | 22 ++- contrib/autostyle.lua | 130 +++++++++-------- contrib/clear_GPS.lua | 25 +++- contrib/copy_attach_detach_tags.lua | 62 +++++++- contrib/cr2hdr.lua | 28 +++- contrib/enfuseAdvanced.lua | 18 ++- contrib/exportLUT.lua | 29 +++- contrib/ext_editor.lua | 137 +++++++++++------- contrib/face_recognition.lua | 33 ++++- contrib/fujifilm_dynamic_range.lua | 21 ++- contrib/fujifilm_ratings.lua | 21 ++- contrib/geoJSON_export.lua | 18 ++- contrib/geoToolbox.lua | 55 +++++-- contrib/gimp.lua | 17 ++- contrib/gpx_export.lua | 28 +++- contrib/hugin.lua | 16 ++- contrib/image_stack.lua | 17 ++- contrib/image_time.lua | 28 +++- contrib/kml_export.lua | 18 ++- contrib/pdf_slideshow.lua | 17 ++- contrib/photils.lua | 39 ++++- contrib/quicktag.lua | 53 +++++-- contrib/rate_group.lua | 39 +++-- contrib/rename-tags.lua | 28 +++- contrib/select_untagged.lua | 21 ++- contrib/slideshowMusic.lua | 23 ++- contrib/transfer_hierarchy.lua | 28 +++- contrib/video_ffmpeg.lua | 21 ++- examples/api_version.lua | 14 ++ examples/darkroom_demo.lua | 23 +++ examples/gettextExample.lua | 14 ++ examples/hello_world.lua | 13 ++ examples/lighttable_demo.lua | 22 +++ examples/moduleExample.lua | 32 ++++- examples/multi_os.lua | 30 +++- examples/panels_demo.lua | 16 ++- examples/preferenceExamples.lua | 13 +- examples/printExamples.lua | 13 ++ examples/running_os.lua | 14 ++ official/check_for_updates.lua | 15 ++ official/copy_paste_metadata.lua | 34 ++++- official/delete_long_tags.lua | 16 +++ official/delete_unused_tags.lua | 17 +++ official/enfuse.lua | 28 +++- official/generate_image_txt.lua | 20 ++- official/image_path_in_ui.lua | 37 ++++- official/import_filter_manager.lua | 3 +- official/save_selection.lua | 36 +++-- official/selection_to_pdf.lua | 19 ++- tools/executable_manager.lua | 29 +++- tools/gen_i18n_mo.lua | 9 ++ tools/get_lib_manpages.lua | 8 ++ tools/get_libdoc.lua | 8 ++ tools/script_manager.lua | 193 +++++++++++++++++++++---- 59 files changed, 1641 insertions(+), 415 deletions(-) diff --git a/contrib/AutoGrouper.lua b/contrib/AutoGrouper.lua index fd7bbac9..a1d449d2 100644 --- a/contrib/AutoGrouper.lua +++ b/contrib/AutoGrouper.lua @@ -37,14 +37,29 @@ selected images, the other button performs grouping on the entire active collect ]] local dt = require "darktable" +local du = require "lib/dtutils" +du.check_min_api_version("7.0.0", "AutoGrouper") + +dt.print_log("hiding styles") +dt.gui.libs["styles"].visible = false + local MOD = 'autogrouper' + +-- return data structure for script_manager + +local script_data = {} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again + local gettext = dt.gettext -- Tell gettext where to find the .mo file translating messages for a particular domain -local CURR_API_STRING = dt.configuration_api_version_string gettext.bindtextdomain("AutoGrouper",dt.configuration.config_dir.."/lua/locale/") + local function _(msgid) - return gettext.dgettext("AutoGrouper", msgid) + return gettext.dgettext("AutoGrouper", msgid) end local Ag = {} @@ -52,123 +67,134 @@ Ag.module_installed = false Ag.event_registered = false local GUI = { - gap = {}, - selected = {}, - collection = {} + gap = {}, + selected = {}, + collection = {} } local function InRange(test, low, high) --tests if test value is within range of low and high (inclusive) - if test >= low and test <= high then - return true - else - return false - end + if test >= low and test <= high then + return true + else + return false + end end local function CompTime(first, second) --compares the timestamps and returns true if first was taken before second - first_time = first.exif_datetime_taken - if string.match(first_time, '[0-9]') == nil then first_time = '9999:99:99 99:99:99' end - first_time = tonumber(string.gsub(first_time, '[^0-9]*','')) - second_time = second.exif_datetime_taken - if string.match(second_time, '[0-9]') == nil then second_time = '9999:99:99 99:99:99' end - second_time = tonumber(string.gsub(second_time, '[^0-9]*','')) - return first_time < second_time + first_time = first.exif_datetime_taken + if string.match(first_time, '[0-9]') == nil then first_time = '9999:99:99 99:99:99' end + first_time = tonumber(string.gsub(first_time, '[^0-9]*','')) + second_time = second.exif_datetime_taken + if string.match(second_time, '[0-9]') == nil then second_time = '9999:99:99 99:99:99' end + second_time = tonumber(string.gsub(second_time, '[^0-9]*','')) + return first_time < second_time end local function SeperateTime(str) --seperates the timestamp into individual components for used with OS.time operations - local cleaned = string.gsub(str, '[^%d]',':') - cleaned = string.gsub(cleaned, '::*',':') --YYYY:MM:DD:hh:mm:ss - local year = string.sub(cleaned,1,4) - local month = string.sub(cleaned,6,7) - local day = string.sub(cleaned,9,10) - local hour = string.sub(cleaned,12,13) - local min = string.sub(cleaned,15,16) - local sec = string.sub(cleaned,18,19) - return {year = year, month = month, day = day, hour = hour, min = min, sec = sec} + local cleaned = string.gsub(str, '[^%d]',':') + cleaned = string.gsub(cleaned, '::*',':') --YYYY:MM:DD:hh:mm:ss + local year = string.sub(cleaned,1,4) + local month = string.sub(cleaned,6,7) + local day = string.sub(cleaned,9,10) + local hour = string.sub(cleaned,12,13) + local min = string.sub(cleaned,15,16) + local sec = string.sub(cleaned,18,19) + return {year = year, month = month, day = day, hour = hour, min = min, sec = sec} end local function GetTimeDiff(curr_image, prev_image) --returns the time difference (in sec.) from current image and the previous image - local curr_time = SeperateTime(curr_image.exif_datetime_taken) - local prev_time = SeperateTime(prev_image.exif_datetime_taken) - return os.time(curr_time)-os.time(prev_time) + local curr_time = SeperateTime(curr_image.exif_datetime_taken) + local prev_time = SeperateTime(prev_image.exif_datetime_taken) + return os.time(curr_time)-os.time(prev_time) end local function main(on_collection) - local images = {} - if on_collection then - local col_images = dt.collection - for i,image in ipairs(col_images) do --copy images to a standard table, table.sort barfs on type dt_lua_singleton_image_collection - table.insert(images,i,image) - end - else - images = dt.gui.selection() - end - dt.preferences.write(MOD, 'active_gap', 'integer', GUI.gap.value) - if #images < 2 then - dt.print('please select at least 2 images') - return + local images = {} + if on_collection then + local col_images = dt.collection + for i,image in ipairs(col_images) do --copy images to a standard table, table.sort barfs on type dt_lua_singleton_image_collection + table.insert(images,i,image) end - table.sort(images, function(first, second) return CompTime(first,second) end) --sort images by timestamp - - for i, image in ipairs(images) do - if i == 1 then - prev_image = image - elseif string.match(image.exif_datetime_taken, '[%d]') ~= nil then --make sure current image has a timestamp, if so check if it is within the user specified gap value and add to group - local curr_image = image - if GetTimeDiff(curr_image, prev_image) <= GUI.gap.value then - images[i]:group_with(images[i-1]) - end - prev_image = curr_image - end + else + images = dt.gui.selection() + end + dt.preferences.write(MOD, 'active_gap', 'integer', GUI.gap.value) + if #images < 2 then + dt.print('please select at least 2 images') + return + end + table.sort(images, function(first, second) return CompTime(first,second) end) --sort images by timestamp + + for i, image in ipairs(images) do + if i == 1 then + prev_image = image + elseif string.match(image.exif_datetime_taken, '[%d]') ~= nil then --make sure current image has a timestamp, if so check if it is within the user specified gap value and add to group + local curr_image = image + if GetTimeDiff(curr_image, prev_image) <= GUI.gap.value then + images[i]:group_with(images[i-1]) + end + prev_image = curr_image end + end end local function install_module() if not Ag.module_installed then + dt.print_log("installing module") dt.register_lib( - 'AutoGroup_Lib', -- Module name - _('auto group'), -- name - true, -- expandable - true, -- resetable - {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 99}}, -- containers - dt.new_widget("box"){ - orientation = "vertical", - GUI.gap, - GUI.selected, - GUI.collection - } + MOD, -- Module name + _('auto group'), -- name + true, -- expandable + true, -- resetable + {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 99}}, -- containers + dt.new_widget("box"){ + orientation = "vertical", + GUI.gap, + GUI.selected, + GUI.collection + } ) Ag.module_installed = true + dt.print_log("module installed") + dt.print_log("styles module visibility is " .. tostring(dt.gui.libs["styles"].visible)) end end +local function destroy() + dt.gui.libs[MOD].visible = false +end + +local function restart() + dt.gui.libs[MOD].visible = true +end + -- GUI -- temp = dt.preferences.read(MOD, 'active_gap', 'integer') if not InRange(temp, 1, 86400) then temp = 3 end GUI.gap = dt.new_widget('slider'){ - label = _('group gap [sec.]'), - tooltip = _('minimum gap, in seconds, between groups'), - soft_min = 1, - soft_max = 60, - hard_min = 1, - hard_max = 86400, - step = 1, - digits = 0, - value = temp, - reset_callback = function(self) - self.value = 3 - end + label = _('group gap [sec.]'), + tooltip = _('minimum gap, in seconds, between groups'), + soft_min = 1, + soft_max = 60, + hard_min = 1, + hard_max = 86400, + step = 1, + digits = 0, + value = temp, + reset_callback = function(self) + self.value = 3 + end } GUI.selected = dt.new_widget("button"){ - label = _('auto group: selected'), - tooltip =_('auto group selected images'), - clicked_callback = function() main(false) end + label = _('auto group: selected'), + tooltip =_('auto group selected images'), + clicked_callback = function() main(false) end } GUI.collection = dt.new_widget("button"){ - label = _('auto group: collection'), - tooltip =_('auto group the entire collection'), - clicked_callback = function() main(true) end + label = _('auto group: collection'), + tooltip =_('auto group the entire collection'), + clicked_callback = function() main(true) end } if dt.gui.current_view().id == "lighttable" then @@ -176,14 +202,20 @@ if dt.gui.current_view().id == "lighttable" then else if not Ag.event_registered then dt.register_event( - "view-changed", - function(event, old_view, new_view) - if new_view.name == "lighttable" and old_view.name == "darkroom" then - install_module() - end - end - ) - Ag.event_registered = true + "AutoGrouper", "view-changed", + function(event, old_view, new_view) + if new_view.name == "lighttable" and old_view.name == "darkroom" then + install_module() + end + end + ) + Ag.event_registered = true end end +script_data.destroy = destroy +script_data.destroy_method = "hide" +script_data.restart = restart +script_data.show = restart + +return script_data \ No newline at end of file diff --git a/contrib/CollectHelper.lua b/contrib/CollectHelper.lua index 8dff8ec4..94c5f77a 100644 --- a/contrib/CollectHelper.lua +++ b/contrib/CollectHelper.lua @@ -46,6 +46,7 @@ In the "Selected Images" module click on "Collect on this Image" ]] local dt = require "darktable" +local du = require "lib/dtutils" local gettext = dt.gettext local previous = nil local all_active = false @@ -53,7 +54,15 @@ local all_active = false -- Tell gettext where to find the .mo file translating messages for a particular domain gettext.bindtextdomain("CollectHelper",dt.configuration.config_dir.."/lua/locale/") -local CURR_API_STRING = dt.configuration.api_version_string +du.check_min_api_version("7.0.0", "CollectHelper") + +-- return data structure for script_manager + +local script_data = {} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again local function _(msgid) return gettext.dgettext("CollectHelper", msgid) @@ -67,6 +76,7 @@ local function CheckSingleImage(selection) end return false end + local function CheckHasColorLabel(selection) local ret = false for _,image in pairs(selection) do @@ -83,6 +93,7 @@ local function PreviousCollection() previous = dt.gui.libs.collect.filter(previous) end end + local function CollectOnFolder(all_rules, all_active) local images = dt.gui.selection() if CheckSingleImage(images) then @@ -103,6 +114,7 @@ local function CollectOnFolder(all_rules, all_active) previous = dt.gui.libs.collect.filter(rules) end end + local function CollectOnColors(all_rules, all_active) local images = dt.gui.selection() if CheckSingleImage(images) then @@ -159,6 +171,7 @@ local function CollectOnColors(all_rules, all_active) end end end + local function CollectOnAll_AND() local images = dt.gui.selection() if CheckSingleImage(images) then @@ -174,29 +187,42 @@ local function CollectOnAll_AND() previous = dt.gui.libs.collect.filter(rules) end +local function destroy() + dt.gui.libs.image.destroy_action("CollectHelper_prev") + if dt.preferences.read('module_CollectHelper','folder','bool') then + dt.gui.libs.image.destroy_action("CollectHelper_folder") + end + if dt.preferences.read('module_CollectHelper','colors','bool') then + dt.gui.libs.image.destroy_action("CollectHelper_labels") + end + if dt.preferences.read('module_CollectHelper','all_and','bool') then + dt.gui.libs.image.destroy_action("CollectHelper_and") + end +end + -- GUI -- dt.gui.libs.image.register_action( - _("collect: previous"), + "CollectHelper_prev", _("collect: previous"), function() PreviousCollection() end, _("Sets the Collect parameters to be the previously active parameters") ) if dt.preferences.read('module_CollectHelper','folder','bool') then - dt.gui.libs.image.register_action( - _("collect: folder"), + dt.gui.libs.image.register_action( + "CollectHelper_folder", _("collect: folder"), function() CollectOnFolder(_ , false) end, _("Sets the Collect parameters to be the selected images's folder") ) end if dt.preferences.read('module_CollectHelper','colors','bool') then - dt.gui.libs.image.register_action( - _("collect: color label(s)"), + dt.gui.libs.image.register_action( + "CollectHelper_labels", _("collect: color label(s)"), function() CollectOnColors(_ , false) end, _("Sets the Collect parameters to be the selected images's color label(s)") ) end if dt.preferences.read('module_CollectHelper','all_and','bool') then - dt.gui.libs.image.register_action( - _("collect: all (AND)"), + dt.gui.libs.image.register_action( + "CollectHelper_and", _("collect: all (AND)"), function() CollectOnAll_AND() end, _("Sets the Collect parameters based on all activated CollectHelper options") ) @@ -206,7 +232,7 @@ end dt.preferences.register("module_CollectHelper", "all_and", -- name "bool", -- type _('CollectHelper: All'), -- label - _('Will create a collect parameter set that utelizes all enabled CollectHelper types (AND)'), -- tooltip + _('Will create a collect parameter set that utilizes all enabled CollectHelper types (AND)'), -- tooltip true -- default ) dt.preferences.register("module_CollectHelper", "colors", -- name @@ -221,3 +247,7 @@ dt.preferences.register("module_CollectHelper", "folder", -- name _('Enable the button that allows you to swap to a collection based on selected image\'s FOLDER location'), -- tooltip true -- default ) + +script_data.destroy = destroy + +return script_data diff --git a/contrib/HDRMerge.lua b/contrib/HDRMerge.lua index 476e1c6b..bf922989 100644 --- a/contrib/HDRMerge.lua +++ b/contrib/HDRMerge.lua @@ -45,9 +45,21 @@ Select a style, whether you want tags to be copied from the original, and any ad ]] local dt = require 'darktable' +local du = require "lib/dtutils" local df = require 'lib/dtutils.file' - local dsys = require 'lib/dtutils.system' + +du.check_min_api_version("7.0.0", "HDRmerge") + +-- return data structure for script_manager + +local script_data = {} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again + + local mod = 'module_HDRMerge' local os_path_seperator = '/' if dt.configuration.running_os == 'windows' then os_path_seperator = '\\' end @@ -287,6 +299,14 @@ local function install_module() end end +local function destroy() + dt.gui.libs["HDRMerge_Lib"].visible = false +end + +local function restart() + dt.gui.libs["HDRMerge_Lib"].visible = true +end + -- GUI Elements -- local lbl_hdr = dt.new_widget('section_label'){ label = _('HDRMerge options') @@ -439,7 +459,7 @@ if dt.gui.current_view().id == "lighttable" then else if not HDRM.event_registered then dt.register_event( - "view-changed", + "HDRmerge", "view-changed", function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() @@ -449,3 +469,10 @@ else HDRM.event_registered = true end end + +script_data.destroy = destroy +script_data.restart = restart +script_data.destroy_method = "hide" +script_data.show = restart + +return script_data \ No newline at end of file diff --git a/contrib/LabelsToTags.lua b/contrib/LabelsToTags.lua index 50e1359f..f5d87ba2 100644 --- a/contrib/LabelsToTags.lua +++ b/contrib/LabelsToTags.lua @@ -50,7 +50,15 @@ local darktable = require("darktable") local du = require "lib/dtutils" -du.check_min_api_version("3.0.0", "LabelsToTags") +du.check_min_api_version("7.0.0", "LabelsToTags") + +-- return data structure for script_manager + +local script_data = {} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again -- Lua 5.3 no longer has "unpack" but "table.unpack" unpack = unpack or table.unpack @@ -60,7 +68,6 @@ ltt.module_installed = false ltt.event_registered = false local LIB_ID = "LabelsToTags" -local CURR_API_STRING = darktable.configuration.api_version_string -- Helper functions: BEGIN @@ -144,16 +151,16 @@ local mappingComboBox = darktable.new_widget("combobox"){ tooltip = getComboboxTooltip(), reset_callback = function(selfC) if selfC == nil then - return + return end i = 1 for _,m in pairs(keySet(getAvailableMappings())) do - selfC[i] = m - i = i+1 + selfC[i] = m + i = i+1 end n = #selfC for j = i,n do - selfC[i] = nil + selfC[i] = nil end selfC.value = 1 selfC.tooltip = getComboboxTooltip() @@ -172,17 +179,17 @@ local function doTagging(selfC) local tagsToApply = {} local hash = generateLabelHash(img) for k,v in pairs(availableMappings[mappingComboBox.value]) do - if hashMatch(hash,k) then - for _,tag in ipairs(v) do - tagsToApply[tag] = true - end - end + if hashMatch(hash,k) then + for _,tag in ipairs(v) do + tagsToApply[tag] = true + end + end end for k,_ in pairs(tagsToApply) do - if memoizedTags[k] == nil then - memoizedTags[k] = darktable.tags.create(k) - end - darktable.tags.attach(memoizedTags[k],img) + if memoizedTags[k] == nil then + memoizedTags[k] = darktable.tags.create(k) + end + darktable.tags.attach(memoizedTags[k],img) end job.percent = job.percent + pctIncrement end @@ -208,14 +215,14 @@ darktable.register_tag_mapping = function(name, mapping) end for pattern,tags in pairs(mapping) do if string.match(pattern,PATTERN_PATTERN) == nil then - darktable.print_error("In tag mapping '" .. name .. "': Pattern '" .. pattern .. "' invalid") - return + darktable.print_error("In tag mapping '" .. name .. "': Pattern '" .. pattern .. "' invalid") + return end for _,tag in ipairs(tags) do - if type(tag) ~= "string" then - darktable.print_error("In tag mapping '" .. name .. "': All tag mappings must be lists of strings") - return - end + if type(tag) ~= "string" then + darktable.print_error("In tag mapping '" .. name .. "': All tag mappings must be lists of strings") + return + end end end availableMappings[name] = mapping @@ -231,6 +238,14 @@ local function install_module() end end +local function destroy() + darktable.gui.libs[LIB_ID].visible = false +end + +local function restart() + darktable.gui.libs[LIB_ID].visible = true +end + --[[ darktable.register_tag_mapping("Example", { ["+----*"] = { "Red", "Only red" }, @@ -248,7 +263,7 @@ if darktable.gui.current_view().id == "lighttable" then else if not ltt.event_registered then darktable.register_event( - "view-changed", + LIB_ID, "view-changed", function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() @@ -259,3 +274,9 @@ else end end +script_data.destroy = destroy +script_data.restart = restart +script_data.destroy_method = "hide" +script_data.show = restart + +return script_data diff --git a/contrib/OpenInExplorer.lua b/contrib/OpenInExplorer.lua index 53a8e0bb..a7761989 100644 --- a/contrib/OpenInExplorer.lua +++ b/contrib/OpenInExplorer.lua @@ -54,7 +54,15 @@ local dsys = require "lib/dtutils.system" local gettext = dt.gettext --Check API version -du.check_min_api_version("5.0.0", "OpenInExplorer") +du.check_min_api_version("7.0.0", "OpenInExplorer") + +-- return data structure for script_manager + +local script_data = {} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again -- Tell gettext where to find the .mo file translating messages for a particular domain gettext.bindtextdomain("OpenInExplorer",dt.configuration.config_dir.."/lua/locale/") @@ -65,7 +73,6 @@ end local act_os = dt.configuration.running_os local PS = act_os == "windows" and "\\" or "/" -local CURR_API_STRING = dt.configuration.api_version_string --Detect OS and quit if it is not supported. if act_os ~= "macos" and act_os ~= "windows" and act_os ~= "linux" then @@ -181,13 +188,23 @@ local function open_in_fmanager() end end +local function destroy() + dt.gui.libs.image.destroy_action("OpenInExplorer") + dt.destroy_event("OpenInExplorer", "shortcut") + if act_os ~= "windows" then + dt.preferences.destroy("OpenInExplorer", "linked_image_files_dir") + end + dt.preferences.destroy("OpenInExplorer", "use_links") +end + -- GUI -- dt.gui.libs.image.register_action( - _("show in file explorer"), + "OpenInExplorer", _("show in file explorer"), function() open_in_fmanager() end, _("Open the file manager at the selected image's location") -) +) + if act_os ~= "windows" then dt.preferences.register("OpenInExplorer", "linked_image_files_dir", -- name @@ -210,8 +227,11 @@ if act_os ~= "windows" then end dt.register_event( - "shortcut", + "OpenInExplorer", "shortcut", function(event, shortcut) open_in_fmanager() end, "OpenInExplorer" ) +script_data.destroy = destroy + +return script_data diff --git a/contrib/RL_out_sharp.lua b/contrib/RL_out_sharp.lua index 75446d12..40cfb204 100644 --- a/contrib/RL_out_sharp.lua +++ b/contrib/RL_out_sharp.lua @@ -63,7 +63,15 @@ local dtsys = require "lib/dtutils.system" local MODULE_NAME = "RL_out_sharp" -- check API version -du.check_min_api_version("5.0.0", MODULE_NAME) +du.check_min_api_version("7.0.0", MODULE_NAME) + +-- return data structure for script_manager + +local script_data = {} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again -- OS compatibility local PS = dt.configuration.running_os == "windows" and "\\" or "/" @@ -155,6 +163,12 @@ local function export2RL(storage, image_table, extra_data) dt.print(_("finished exporting")) end + -- script_manager integration + + local function destroy() + dt.destroy_storage("exp2RL") + end + -- new widgets ---------------------------------------------------------------- output_folder_selector = dt.new_widget("file_chooser_button"){ @@ -224,6 +238,12 @@ sigma_slider.value = dt.preferences.read(MODULE_NAME, "sigma", "float") iterations_slider.value = dt.preferences.read(MODULE_NAME, "iterations", "float") jpg_quality_slider.value = dt.preferences.read(MODULE_NAME, "jpg_quality", "float") +-- script_manager integration + +script_data.destroy = destroy + +return script_data + -- end of script -------------------------------------------------------------- -- vim: shiftwidth=2 expandtab tabstop=2 cindent syntax=lua diff --git a/contrib/autostyle.lua b/contrib/autostyle.lua index cd144b09..64de2a80 100644 --- a/contrib/autostyle.lua +++ b/contrib/autostyle.lua @@ -40,124 +40,136 @@ local darktable = require "darktable" local du = require "lib/dtutils" local filelib = require "lib/dtutils.file" --- Forward declare the functions -local autostyle_apply_one_image,autostyle_apply_one_image_event,autostyle_apply,exiftool_attribute,capture -local CURR_API_STRING = darktable.configuration.api_version_string +du.check_min_api_version("7.0.0", "autostyle") --- Tested it with darktable 1.6.1 and darktable git from 2014-01-25 -du.check_min_api_version("2.0.2", "autostyle") +-- return data structure for script_manager --- Receive the event triggered -function autostyle_apply_one_image_event(event,image) - autostyle_apply_one_image(image) +local script_data = {} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again + +-- run command and retrieve stdout +local function get_stdout(cmd) + -- Open the command, for reading + local fd = assert(io.popen(cmd, 'r')) + darktable.control.read(fd) + -- slurp the whole file + local data = assert(fd:read('*a')) + + fd:close() + -- Replace carriage returns and linefeeds with spaces + data = string.gsub(data, '[\n\r]+', ' ') + -- Remove spaces at the beginning + data = string.gsub(data, '^%s+', '') + -- Remove spaces at the end + data = string.gsub(data, '%s+$', '') + return data +end + +-- Retrieve the attribute through exiftool +local function exiftool_attribute(path, attr) + local cmd = "exiftool -" .. attr .. " '" .. path .. "'"; + local exifresult = get_stdout(cmd) + local attribute = string.match(exifresult, ": (.*)") + if (attribute == nil) then + darktable.print_error( "Could not find the attribute " .. attr .. " using the command: <" .. cmd .. ">") + -- Raise an error to the caller + error( "Could not find the attribute " .. attr .. " using the command: <" .. cmd .. ">"); + end + -- darktable.print_error("Returning attribute: " .. attribute) + return attribute end -- Apply the style to an image, if it matches the tag condition -function autostyle_apply_one_image (image) +local function autostyle_apply_one_image (image) + + local pref = darktable.preferences.read("autostyle", "exif_tag", "string") -- We need the tag, the value and the style_name provided from the configuration string - local tag,value,style_name=string.match(darktable.preferences.read("autostyle","exif_tag","string"),"(%g+)%s*=%s*(%g+)%s*=>%s*(%g+)") + local tag, value, style_name = string.match(pref, "(%g+)%s*=%s*(%g+)%s*=>%s*(%g+)") -- check they all exist (correct syntax) if (not tag) then - darktable.print("EXIF TAG not found in " .. darktable.preferences.read("autostyle","exif_tag","string")) + darktable.print("EXIF TAG not found in " .. pref) return 0 end if (not value) then - darktable.print("value to match not found in " .. darktable.preferences.read("autostyle","exif_tag","string")) + darktable.print("value to match not found in " .. pref) return 0 end if (not style_name) then - darktable.print("style name not found in " .. darktable.preferences.read("autostyle","exif_tag","string")) + darktable.print("style name not found in " .. pref) return 0 end if not filelib.check_if_bin_exists("exiftool") then darktable.print("Can't find exiftool") - return 0 + return 0 end -- First find the style (we have its name) - local styles= darktable.styles + local styles = darktable.styles local style - for _,s in ipairs(styles) do + for _, s in ipairs(styles) do if s.name == style_name then - style=s + style = s end end if (not style) then darktable.print("style not found for autostyle: " .. style_name) - return 0 + return 0 end -- Apply the style to image, if it is tagged - local ok,auto_dr_attr= pcall(exiftool_attribute,image.path .. '/' .. image.filename,tag) + local ok, auto_dr_attr = pcall(exiftool_attribute, image.path .. '/' .. image.filename,tag) --darktable.print_error("dr_attr:" .. auto_dr_attr) -- If the lookup fails, stop here if (not ok) then darktable.print("Couldn't get attribute " .. auto_dr_attr .. " from exiftool's output") return 0 end - if auto_dr_attr==value then - darktable.print_log("Image " .. image.filename .. ": autostyle automatically applied " .. darktable.preferences.read("autostyle","exif_tag","string") ) + if auto_dr_attr == value then + darktable.print_log("Image " .. image.filename .. ": autostyle automatically applied " .. pref) darktable.styles.apply(style,image) return 1 else - darktable.print_log("Image " .. image.filename .. ": autostyle not applied, exif tag " .. darktable.preferences.read("autostyle","exif_tag","string") .. " not matched: " .. auto_dr_attr) + darktable.print_log("Image " .. image.filename .. ": autostyle not applied, exif tag " .. pref .. " not matched: " .. auto_dr_attr) return 0 end end -function autostyle_apply( shortcut) +-- Receive the event triggered +local function autostyle_apply_one_image_event(event,image) + autostyle_apply_one_image(image) +end + +local function autostyle_apply(shortcut) local images = darktable.gui.action_images - local images_processed =0 - local images_submitted =0 + local images_processed = 0 + local images_submitted = 0 for _,image in pairs(images) do - images_submitted = images_submitted +1 + images_submitted = images_submitted + 1 images_processed = images_processed + autostyle_apply_one_image(image) end darktable.print("Applied auto style to " .. images_processed .. " out of " .. images_submitted .. " image(s)") end --- Retrieve the attribute through exiftool -function exiftool_attribute(path,attr) - local cmd="exiftool -" .. attr .. " '" .. path .. "'"; - local exifresult=get_stdout(cmd) - local attribute=string.match(exifresult,": (.*)") - if (attribute == nil) then - darktable.print_error( "Could not find the attribute " .. attr .. " using the command: <" .. cmd .. ">") - -- Raise an error to the caller - error( "Could not find the attribute " .. attr .. " using the command: <" .. cmd .. ">"); - end --- darktable.print_error("Returning attribute: " .. attribute) - return attribute -end - --- run command and retrieve stdout -function get_stdout(cmd) - -- Open the command, for reading - local fd = assert(io.popen(cmd, 'r')) - darktable.control.read(fd) - -- slurp the whole file - local data = assert(fd:read('*a')) - - fd:close() - -- Replace carriage returns and linefeeds with spaces - data = string.gsub(data, '[\n\r]+', ' ') - -- Remove spaces at the beginning - data = string.gsub(data, '^%s+', '') - -- Remove spaces at the end - data = string.gsub(data, '%s+$', '') - return data +local function destroy() + darktable.destroy_event("autostyle", "shortcut") + darktable.destroy_event("autostyle", "post-import-image") end -- Registering events -darktable.register_event("shortcut", autostyle_apply, +darktable.register_event("autostyle", "shortcut", autostyle_apply, "Apply your chosen style from exiftool tags") -darktable.preferences.register("autostyle","exif_tag","string","Autostyle: EXIF_tag=value=>style","apply a style automatically if an EXIF_tag matches value. Find the tag with exiftool","") +darktable.preferences.register("autostyle", "exif_tag", "string", "Autostyle: EXIF_tag=value=>style", "apply a style automatically if an EXIF_tag matches value. Find the tag with exiftool", "") -darktable.register_event("post-import-image", +darktable.register_event("autostyle", "post-import-image", autostyle_apply_one_image_event) +script_data.destroy = destroy +return script_data \ No newline at end of file diff --git a/contrib/clear_GPS.lua b/contrib/clear_GPS.lua index 5495abf3..518e0372 100644 --- a/contrib/clear_GPS.lua +++ b/contrib/clear_GPS.lua @@ -39,14 +39,20 @@ local dt = require "darktable" local du = require "lib/dtutils" +-- return data structure for script_manager + +local script_data = {} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again + local gettext = dt.gettext -- not a number local NaN = 0/0 -du.check_min_api_version("3.0.0", "clear_GPS") -local CURR_API_STRING = dt.configuration.api_version_string - +du.check_min_api_version("7.0.0", "clear_GPS") -- Tell gettext where to find the .mo file translating messages for a particular domain gettext.bindtextdomain("clear_GPS",dt.configuration.config_dir.."/lua/locale/") @@ -64,14 +70,23 @@ local function clear_GPS(images) end end +local function destroy() + dt.destroy_event("clear_GPS", "shortcut") + dt.gui.libs.image.destroy_action("clear_GPS") +end + +script_data.destroy = destroy + dt.gui.libs.image.register_action( - _("clear GPS data"), + "clear_GPS", _("clear GPS data"), function(event, images) clear_GPS(images) end, _("Clear GPS data from selected images") ) dt.register_event( - "shortcut", + "clear_GPS", "shortcut", function(event, shortcut) clear_GPS(dt.gui.action_images) end, _("Clear GPS data") ) + +return script_data diff --git a/contrib/copy_attach_detach_tags.lua b/contrib/copy_attach_detach_tags.lua index 45f2c036..dda92aed 100644 --- a/contrib/copy_attach_detach_tags.lua +++ b/contrib/copy_attach_detach_tags.lua @@ -42,8 +42,15 @@ local debug = require "darktable.debug" local gettext = dt.gettext -du.check_min_api_version("3.0.0", "copy_attach_detach_tags") -local CURR_API_STRING = dt.configuration.api_version_string +du.check_min_api_version("7.0.0", "copy_attach_detach_tags") + +-- return data structure for script_manager + +local script_data = {} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again -- Tell gettext where to find the .mo file translating messages for a particular domain gettext.bindtextdomain("copy_attach_detach_tags",dt.configuration.config_dir.."/lua/locale/") @@ -182,6 +189,41 @@ local function install_module() end end +local function destroy() + dt.destroy_event("cadt_ct", "shortcut") + dt.destroy_event("cadt_at", "shortcut") + dt.destroy_event("cadt_dt", "shortcut") + dt.destroy_event("cadt_rt", "shortcut") + dt.gui.libs["tagging_addon"].visible = false +end + +local function restart() + -- shortcut for copy + dt.register_event("cadt_ct", "shortcut", + mcopy_tags, + _('copy tags from selected image(s)')) + + -- shortcut for attach + dt.register_event("cadt_at", "shortcut", + attach_tags, + _('paste tags to selected image(s)')) + + -- shortcut for detaching tags + dt.register_event("cadt_dt", "shortcut", + detach_tags, + _('remove tags from selected image(s)')) + + -- shortcut for replace tags + dt.register_event("cadt_rt", "shortcut", + replace_tags, + _('replace tags from selected image(s)')) + dt.gui.libs["tagging_addon"].visible = true +end + +local function show() + dt.gui.libs["tagging_addon"].visible = true +end + -- create modul Tagging addons taglist_label.reset_callback = mcopy_tags @@ -234,7 +276,7 @@ if dt.gui.current_view().id == "lighttable" then else if not cadt.event_registered then dt.register_event( - "view-changed", + "cadt", "view-changed", function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() @@ -247,24 +289,30 @@ end -- shortcut for copy -dt.register_event("shortcut", +dt.register_event("cadt_ct", "shortcut", mcopy_tags, _('copy tags from selected image(s)')) -- shortcut for attach -dt.register_event("shortcut", +dt.register_event("cadt_at", "shortcut", attach_tags, _('paste tags to selected image(s)')) -- shortcut for detaching tags -dt.register_event("shortcut", +dt.register_event("cadt_dt", "shortcut", detach_tags, _('remove tags from selected image(s)')) -- shortcut for replace tags -dt.register_event("shortcut", +dt.register_event("cadt_rt", "shortcut", replace_tags, _('replace tags from selected image(s)')) +script_data.destroy = destroy +script_data.restart = restart +script_data.destroy_method = "hide" +script_data.show = show + +return script_data -- vim: shiftwidth=2 expandtab tabstop=2 cindent syntax=lua -- kate: tab-indents: off; indent-width 2; replace-tabs on; remove-trailing-space on; diff --git a/contrib/cr2hdr.lua b/contrib/cr2hdr.lua index 15b348a3..25d07a2f 100644 --- a/contrib/cr2hdr.lua +++ b/contrib/cr2hdr.lua @@ -35,9 +35,15 @@ USAGE local darktable = require "darktable" local du = require "lib/dtutils" --- Tested with darktable 2.0.1 -du.check_min_api_version("2.0.0", "cr2hdr") -local CURR_API_STRING = darktable.configuration.api_version_string +du.check_min_api_version("7.0.0", "cr2hdr") + +-- return data structure for script_manager + +local script_data = {} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again local queue = {} local processed_files = {} @@ -108,11 +114,21 @@ local function convert_action_images(shortcut) convert_images() end -darktable.register_event("shortcut", +local function destroy() + darktable.destroy_event("cr2hdr", "shortcut") + darktable.destroy_event("cr2hdr", "post-import-image") + darktable.destroy_event("cr2hdr", "post-import-film") +end + +darktable.register_event("cr2hdr", "shortcut", convert_action_images, "Run cr2hdr (Magic Lantern DualISO converter) on selected images") -darktable.register_event("post-import-image", +darktable.register_event("cr2hdr", "post-import-image", file_imported) -darktable.register_event("post-import-film", +darktable.register_event("cr2hdr", "post-import-film", film_imported) darktable.preferences.register("cr2hdr", "onimport", "bool", "Invoke on import", "If true then cr2hdr will try to proccess every file during importing. Warning: cr2hdr is quite slow even in figuring out on whether the file is Dual ISO or not.", false) + +script_data.destroy = destroy + +return script_data diff --git a/contrib/enfuseAdvanced.lua b/contrib/enfuseAdvanced.lua index a9f6ea0b..3103821c 100644 --- a/contrib/enfuseAdvanced.lua +++ b/contrib/enfuseAdvanced.lua @@ -65,7 +65,15 @@ local mod = 'module_enfuseAdvanced' local os_path_seperator = '/' if dt.configuration.running_os == 'windows' then os_path_seperator = '\\' end -du.check_min_api_version('5.0.0', 'enfuseAdvanced') +du.check_min_api_version("7.0.0", "enfuseAdvanced") + +-- return data structure for script_manager + +local script_data = {} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again -- Tell gettext where to find the .mo file translating messages for a particular domain local gettext = dt.gettext @@ -516,6 +524,10 @@ local function main(storage, image_table, extra_data) dt.print('image fusion process complete') end +local function destroy() + dt.destroy_storage('module_enfuseAdvanced') +end + --GUI-- stack_compression = dt.new_widget('stack'){} local label_AIS_options= dt.new_widget('section_label'){ @@ -1142,3 +1154,7 @@ else GUI.options_contain.active = 4 GUI.show_options.sensitive = false end + +script_data.destroy = destroy + +return script_data \ No newline at end of file diff --git a/contrib/exportLUT.lua b/contrib/exportLUT.lua index a0858d6a..3d023901 100644 --- a/contrib/exportLUT.lua +++ b/contrib/exportLUT.lua @@ -31,10 +31,19 @@ local du = require "lib/dtutils" local df = require("lib/dtutils.file") local ds = require("lib/dtutils.system") +du.check_min_api_version("7.0.0", "exportLUT") + +-- return data structure for script_manager + +local script_data = {} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again + local gettext = dt.gettext gettext.bindtextdomain("exportLUT",dt.configuration.config_dir.."/lua/locale/") -local CURR_API_STRING = dt.configuration.api_version_string local function _(msgid) return gettext.dgettext("exportLUT", msgid) @@ -128,7 +137,7 @@ end local function install_module() if not eL.module_installed then dt.register_lib( - _("export haldclut"), + "export haldclut", _("export haldclut"), true, false, @@ -145,6 +154,14 @@ local function install_module() end end +local function destroy() + dt.gui.libs["export haldclut"].visible = false +end + +local function restart() + dt.gui.libs["export haldclut"].visible = true +end + local export_button = dt.new_widget("button"){ label = _("export"), clicked_callback = export_luts @@ -162,7 +179,7 @@ if dt.gui.current_view().id == "lighttable" then else if not eL.event_registered then dt.register_event( - "view-changed", + "exportLUT", "view-changed", function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() @@ -173,3 +190,9 @@ else end end +script_data.destroy = destroy +script_data.restart = restart +script_data.destroy_method = "hide" +script_data.show = restart + +return script_data diff --git a/contrib/ext_editor.lua b/contrib/ext_editor.lua index 3aa622a1..10d1ca6c 100644 --- a/contrib/ext_editor.lua +++ b/contrib/ext_editor.lua @@ -73,12 +73,15 @@ local dtsys = require "lib/dtutils.system" -- module name local MODULE_NAME = "ext_editor" -local CURR_API_STRING = dt.configuration.api_version_string +du.check_min_api_version("7.0.0", MODULE_NAME) +-- return data structure for script_manager --- check API version -du.check_min_api_version("5.0.2", MODULE_NAME) -- darktable 3.x +local script_data = {} +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again -- OS compatibility local PS = dt.configuration.running_os == "windows" and "\\" or "/" @@ -95,7 +98,7 @@ local gettext = dt.gettext gettext.bindtextdomain(MODULE_NAME, dt.configuration.config_dir..PS.."lua"..PS.."locale"..PS) local function _(msgid) return gettext.dgettext(MODULE_NAME, msgid) - end +end -- maximum number of external programs, can be increased to necessity local MAX_EDITORS = 9 @@ -112,7 +115,7 @@ local allowed_file_types = {"JPG", "jpg", "JPEG", "jpeg", "TIF", "tif", "TIFF", if not dt.preferences.read(MODULE_NAME, "initialized", "bool") then dt.preferences.write(MODULE_NAME, "lastchoice", "integer", 0) dt.preferences.write(MODULE_NAME, "initialized", "bool", true) - end +end local lastchoice = 0 @@ -137,23 +140,23 @@ local function UpdateProgramList(combobox, button_edit, button_edit_copy, update program_names[i] = name program_paths[i] = df.sanitize_filename(dt.preferences.read(MODULE_NAME, "program_path_"..i, "string")) n_entries = i - end - end + end + end - lastchoice = dt.preferences.read(MODULE_NAME, "lastchoice", "integer") - if lastchoice == 0 and n_entries > 0 then lastchoice = 1 end - if lastchoice > n_entries then lastchoice = n_entries end - dt.preferences.write(MODULE_NAME, "lastchoice", "integer", lastchoice) + lastchoice = dt.preferences.read(MODULE_NAME, "lastchoice", "integer") + if lastchoice == 0 and n_entries > 0 then lastchoice = 1 end + if lastchoice > n_entries then lastchoice = n_entries end + dt.preferences.write(MODULE_NAME, "lastchoice", "integer", lastchoice) - -- widgets enabled if there is at least one program configured - combobox.selected = lastchoice - local active = n_entries > 0 - combobox.sensitive = active - button_edit.sensitive = active - button_edit_copy.sensitive = active + -- widgets enabled if there is at least one program configured + combobox.selected = lastchoice + local active = n_entries > 0 + combobox.sensitive = active + button_edit.sensitive = active + button_edit_copy.sensitive = active - if update_button_pressed then dt.print(n_entries.._(" editors configured")) end - end + if update_button_pressed then dt.print(n_entries.._(" editors configured")) end +end -- callback for buttons "edit" and "edit a copy" ------------------------------ @@ -163,13 +166,13 @@ local function OpenWith(images, choice, copy) if choice > n_entries then dt.print(_("not a valid choice")) return - end + end -- check if one image is selected, return if not if #images ~= 1 then dt.print(_("please select one image")) return - end + end local bin = program_paths[choice] local friendly_name = program_names[choice] @@ -188,18 +191,18 @@ local function OpenWith(images, choice, copy) if v == file_ext then allowed = true break - end - end + end + end if not allowed then dt.print(_("file type not allowed")) return - end + end -- save image tags, rating and color local tags = {} - for i, tag in ipairs(dt.tags.get_tags(image)) do + for i, tag in ipairs(dt.tags.get_tags(image)) do if not (string.sub(tag.name, 1, 9) == "darktable") then table.insert(tags, tag) end - end + end local rating = image.rating local red = image.red local blue = image.blue @@ -221,8 +224,8 @@ local function OpenWith(images, choice, copy) if not copy_success then dt.print(_("error copying file ")..name) return - end - end + end + end -- launch the external editor, check result, return if error local run_cmd = bin.." "..df.sanitize_filename(new_name) @@ -231,7 +234,7 @@ local function OpenWith(images, choice, copy) if result ~= 0 then dt.print(_("error launching ")..friendly_name) return - end + end if copy then -- import in database and group @@ -256,7 +259,7 @@ local function OpenWith(images, choice, copy) while not found do index, new_leader = next(group_members, index) if new_leader ~= image_leader then found = true end - end + end new_leader:make_group_leader() image:delete() if image.local_copy then image:drop_cache() end -- to fix fail to allocate cache error @@ -269,15 +272,15 @@ local function OpenWith(images, choice, copy) if image.local_copy then image:drop_cache() end -- to fix fail to allocate cache error new_image = dt.database.import(name) new_image:group_with() - end + end else -- case 3: image is in a group but is not leader image:delete() if image.local_copy then image:drop_cache() end -- to fix fail to allocate cache error new_image = dt.database.import(name) new_image:group_with(image_leader) - end - end + end + end -- restore image tags, rating and color for i, tag in ipairs(tags) do dt.tags.attach(tag, new_image) end @@ -296,14 +299,14 @@ local function OpenWith(images, choice, copy) -- refresh darkroom view if dt.gui.current_view().id == "darkroom" then dt.gui.views.darkroom.display_image(new_image) - end end +end -- callback function for shortcuts -------------------------------------------- local function program_shortcut(event, shortcut) OpenWith(dt.gui.action_images, tonumber(string.sub(shortcut, -2)), false) - end +end -- export images and reimport in collection ----------------------------------- @@ -324,23 +327,23 @@ local function export2collection(storage, image_table, extra_data) if not move_success then dt.print(_("error moving file ")..temp_name) return - end + end -- import in database and group new_image = dt.database.import(new_name) new_image:group_with(image.group_leader) - end + end dt.print(_("finished exporting")) - end +end -- install the module in the UI ----------------------------------------------- local function install_module(dr) - local views = {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}} + local views = {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 90}} if dr then - views = {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}, + views = {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 90}, [dt.gui.views.darkroom] = {"DT_UI_CONTAINER_PANEL_LEFT_CENTER", 100}} end @@ -363,6 +366,27 @@ local function install_module(dr) end end +local function destroy() + for i = 1, MAX_EDITORS do + dt.destroy_event(MODULE_NAME .. i, "shortcut") + end + dt.destroy_storage("exp2coll") + dt.gui.libs[MODULE_NAME].visible = false +end + +local function restart() + for i = 1, MAX_EDITORS do + dt.register_event(MODULE_NAME .. i, "shortcut", + program_shortcut, _("edit with program ")..string.format("%02d", i)) + end + dt.register_storage("exp2coll", _("collection"), nil, export2collection) + dt.gui.libs[MODULE_NAME].visible = true +end + +local function show() + dt.gui.libs[MODULE_NAME].visible = true +end + -- combobox, with variable number of entries ---------------------------------- local combobox = dt.new_widget("combobox") { @@ -372,7 +396,7 @@ local combobox = dt.new_widget("combobox") { dt.preferences.write(MODULE_NAME, "lastchoice", "integer", self.selected) end, "" - } +} -- button edit ---------------------------------------------------------------- @@ -382,8 +406,8 @@ local button_edit = dt.new_widget("button") { --sensitive = false, clicked_callback = function() OpenWith(dt.gui.action_images, combobox.selected, false) - end - } + end +} -- button edit a copy --------------------------------------------------------- @@ -392,8 +416,8 @@ local button_edit_copy = dt.new_widget("button") { tooltip = _("create a copy of the selected image and open it in external editor"), clicked_callback = function() OpenWith(dt.gui.action_images, combobox.selected, true) - end - } + end +} -- button update list --------------------------------------------------------- @@ -402,18 +426,18 @@ local button_update_list = dt.new_widget("button") { tooltip = _("update list of programs if lua preferences are changed"), clicked_callback = function() UpdateProgramList(combobox, button_edit, button_edit_copy, true) - end - } + end +} -- box for the buttons -------------------------------------------------------- -- it doesn't seem there is a way to make the buttons equal in size local box1 = dt.new_widget("box") { - orientation = "horizontal", + orientation = "horizontal", button_edit, button_edit_copy, button_update_list - } +} -- table with all the widgets -------------------------------------------------- @@ -428,7 +452,7 @@ if dt.gui.current_view().id == "lighttable" then else if not ee.event_registered then dt.register_event( - "view-changed", + MODULE_NAME, "view-changed", function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module(show_dr) @@ -457,7 +481,7 @@ for i = MAX_EDITORS, 1, -1 do dt.preferences.register(MODULE_NAME, "program_name_"..i, "string", _("name of external editor ")..i, _("friendly name of external editor"), "") - end +end dt.preferences.register(MODULE_NAME, "show_in_darkrooom", "bool", _("show external editors in darkroom"), _("check to show external editors module also in darkroom (requires restart)"), false) @@ -465,10 +489,17 @@ dt.preferences.register(MODULE_NAME, "show_in_darkrooom", "bool", -- register the new shortcuts ------------------------------------------------- for i = 1, MAX_EDITORS do - dt.register_event("shortcut", + dt.register_event(MODULE_NAME .. i, "shortcut", program_shortcut, _("edit with program ")..string.format("%02d", i)) - end +end + + +script_data.destroy = destroy +script_data.restart = restart +script_data.destroy_method = "hide" +script_data.show = show +return script_data -- end of script -------------------------------------------------------------- diff --git a/contrib/face_recognition.lua b/contrib/face_recognition.lua index 980c0d71..68a497cc 100644 --- a/contrib/face_recognition.lua +++ b/contrib/face_recognition.lua @@ -44,7 +44,6 @@ local dt = require "darktable" local du = require "lib/dtutils" local df = require "lib/dtutils.file" local dtsys = require "lib/dtutils.system" - local gettext = dt.gettext -- constants @@ -52,7 +51,16 @@ local gettext = dt.gettext local MODULE = "face_recognition" local PS = dt.configuration.running_os == "windows" and '\\' or '/' local OUTPUT = dt.configuration.tmp_dir .. PS .. "facerecognition.txt" -local CURR_API_STRING = dt.configuration.api_version_string + +du.check_min_api_version("7.0.0", MODULE) + +-- return data structure for script_manager + +local script_data = {} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again -- namespace @@ -60,9 +68,6 @@ local fc = {} fc.module_installed = false fc.event_registered = false --- ensure we meet the minimum api -du.check_min_api_version("5.0.0", "face_recognition") - -- Tell gettext where to find the .mo file translating messages for a particular domain gettext.bindtextdomain("face_recognition", dt.configuration.config_dir.."/lua/locale/") @@ -344,7 +349,7 @@ end local function install_module() if not fc.module_installed then dt.register_lib( - "face_recognition", -- Module name + MODULE, -- Module name _("face recognition"), -- Visible name true, -- expandable true, -- resetable @@ -357,6 +362,14 @@ local function install_module() end end +local function destroy() + dt.gui.libs[MODULE].visible = false +end + +local function restart() + dt.gui.libs[MODULE].visible = true +end + -- build the interface fc.unknown_tag = dt.new_widget("entry"){ @@ -491,7 +504,7 @@ if dt.gui.current_view().id == "lighttable" then else if not fc.event_registered then dt.register_event( - "view-changed", + MODULE, "view-changed", function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() @@ -512,5 +525,11 @@ if not dt.preferences.read(MODULE, "initialized", "bool") then dt.preferences.write(MODULE, "initialized", "bool", true) end +script_data.destroy = destroy +script_data.restart = restart +script_data.destroy_method = "hide" +script_data.show = restart + +return script_data -- -- vim: shiftwidth=2 expandtab tabstop=2 cindent syntax=lua diff --git a/contrib/fujifilm_dynamic_range.lua b/contrib/fujifilm_dynamic_range.lua index 66bfd1fa..c48d7146 100644 --- a/contrib/fujifilm_dynamic_range.lua +++ b/contrib/fujifilm_dynamic_range.lua @@ -61,8 +61,15 @@ local dt = require "darktable" local du = require "lib/dtutils" local df = require "lib/dtutils.file" -du.check_min_api_version("4.0.0", "fujifilm_dynamic_range") -local CURR_API_STRING = dt.configuration.api_version_string +du.check_min_api_version("7.0.0", "fujifilm_dynamic_range") + +-- return data structure for script_manager + +local script_data = {} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again local function detect_dynamic_range(event, image) if image.exif_maker ~= "FUJIFILM" then @@ -105,7 +112,15 @@ local function detect_dynamic_range(event, image) dt.print_log("[fujifilm_dynamic_range] raw exposure bias " .. tostring(raf_result)) end -dt.register_event("post-import-image", +local function destroy() + dt.destroy_event("fujifilm_dr", "post-import-image") +end + +dt.register_event("fujifilm_dr", "post-import-image", detect_dynamic_range) dt.print_log("[fujifilm_dynamic_range] loaded") + +script_data.destroy = destroy + +return script_data diff --git a/contrib/fujifilm_ratings.lua b/contrib/fujifilm_ratings.lua index 524d1bd2..18dba2bc 100644 --- a/contrib/fujifilm_ratings.lua +++ b/contrib/fujifilm_ratings.lua @@ -26,11 +26,17 @@ Dependencies: local dt = require "darktable" local du = require "lib/dtutils" local df = require "lib/dtutils.file" - local gettext = dt.gettext -du.check_min_api_version("4.0.0", "fujifilm_ratings") -local CURR_API_STRING = dt.configuration.api_version_string +du.check_min_api_version("7.0.0", "fujifilm_ratings") + +-- return data structure for script_manager + +local script_data = {} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again gettext.bindtextdomain("fujifilm_ratings", dt.configuration.config_dir.."/lua/locale/") @@ -68,7 +74,12 @@ local function detect_rating(event, image) end end -dt.register_event("post-import-image", +local function destroy() + dt.destroy_event("fujifilm_rat", "post-import-image") +end + +dt.register_event("fujifilm_rat", "post-import-image", detect_rating) -print(_("fujifilm_ratings loaded.")) +script_data.destroy = destroy +return script_data diff --git a/contrib/geoJSON_export.lua b/contrib/geoJSON_export.lua index 4815e071..cc3d9560 100644 --- a/contrib/geoJSON_export.lua +++ b/contrib/geoJSON_export.lua @@ -37,7 +37,15 @@ local du = require "lib/dtutils" local df = require "lib/dtutils.file" local gettext = dt.gettext -du.check_min_api_version("3.0.0", "geoJSON_export") +du.check_min_api_version("7.0.0", "geoJSON_export") + +-- return data structure for script_manager + +local script_data = {} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again -- Tell gettext where to find the .mo file translating messages for a particular domain gettext.bindtextdomain("geoJSON_export",dt.configuration.config_dir.."/lua/locale/") @@ -291,6 +299,10 @@ local function create_geoJSON_file(storage, image_table, extra_data) end +local function destroy() + dt.destroy_storage("geoJSON_export") +end + -- Preferences dt.preferences.register("geoJSON_export", "CreateMapBoxHTMLFile", @@ -326,3 +338,7 @@ dt.preferences.register("geoJSON_export", -- Register dt.register_storage("geoJSON_export", "geoJSON Export", nil, create_geoJSON_file) + +script_data.destroy = destroy + +return script_data diff --git a/contrib/geoToolbox.lua b/contrib/geoToolbox.lua index 09b0513f..c43d313e 100644 --- a/contrib/geoToolbox.lua +++ b/contrib/geoToolbox.lua @@ -28,11 +28,17 @@ require "geoToolbox" local dt = require "darktable" local du = require "lib/dtutils" local df = require "lib/dtutils.file" - local gettext = dt.gettext -du.check_min_api_version("3.0.0", "geoToolbox") -local CURR_API_STRING = dt.configuration.api_version_string +du.check_min_api_version("7.0.0", "geoToolbox") + +-- return data structure for script_manager + +local script_data = {} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again -- Tell gettext where to find the .mo file translating messages for a particular domain gettext.bindtextdomain("geoToolbox",dt.configuration.config_dir.."/lua/locale/") @@ -595,6 +601,33 @@ local function install_module() end end +local function destroy() + dt.gui.libs["geoToolbox"].visible = false + dt.destroy_event("geoToolbox_cd", "shortcut") + dt.destroy_event("geoToolbox", "mouse-over-image-changed") + dt.destroy_event("geoToolbox_wg", "shortcut") + dt.destroy_event("geoToolbox_ng", "shortcut") +end + +local function restart() + dt.register_event("geoToolbox_cd", "shortcut", + print_calc_distance, _("Calculate the distance from latitude and longitude in km")) + dt.register_event("geoToolbox", "mouse-over-image-changed", + toolbox_calc_distance) + + dt.register_event("geoToolbox_wg", "shortcut", + select_with_gps, _("Select all images with GPS information")) + dt.register_event("geoToolbox_ng", "shortcut", + select_without_gps, _("Select all images without GPS information")) + + dt.gui.libs["geoToolbox"].visible = true +end + +local function show() + dt.gui.libs["geoToolbox"].visible = true +end + + local separator = dt.new_widget("separator"){} local separator2 = dt.new_widget("separator"){} @@ -689,7 +722,7 @@ if dt.gui.current_view().id == "lighttable" then else if not gT.event_registered then dt.register_event( - "view-changed", + "geoToolbox", "view-changed", function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() @@ -709,15 +742,21 @@ dt.preferences.register("geoToolbox", '' ) -- Register -dt.register_event("shortcut", +dt.register_event("geoToolbox_cd", "shortcut", print_calc_distance, _("Calculate the distance from latitude and longitude in km")) -dt.register_event("mouse-over-image-changed", +dt.register_event("geoToolbox", "mouse-over-image-changed", toolbox_calc_distance) -dt.register_event("shortcut", +dt.register_event("geoToolbox_wg", "shortcut", select_with_gps, _("Select all images with GPS information")) -dt.register_event("shortcut", +dt.register_event("geoToolbox_ng", "shortcut", select_without_gps, _("Select all images without GPS information")) +script_data.destroy = destroy +script_data.restart = restart +script_data.destroy_method = "hide" +script_data.show = show + +return script_data -- vim: shiftwidth=2 expandtab tabstop=2 cindent syntax=lua -- kate: hl Lua; diff --git a/contrib/gimp.lua b/contrib/gimp.lua index 0a8bd8d8..d2809222 100644 --- a/contrib/gimp.lua +++ b/contrib/gimp.lua @@ -72,7 +72,15 @@ local dtsys = require "lib/dtutils.system" local gettext = dt.gettext local gimp_widget = nil -du.check_min_api_version("5.0.0", "gimp") +du.check_min_api_version("7.0.0", "gimp") + +-- return data structure for script_manager + +local script_data = {} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again -- Tell gettext where to find the .mo file translating messages for a particular domain gettext.bindtextdomain("gimp",dt.configuration.config_dir.."/lua/locale/") @@ -189,6 +197,10 @@ local function gimp_edit(storage, image_table, extra_data) --finalize end end +local function destroy() + dt.destroy_storage("module_gimp") +end + -- Register gimp_widget = dt.new_widget("check_button"){ @@ -203,3 +215,6 @@ gimp_widget = dt.new_widget("check_button"){ dt.register_storage("module_gimp", _("Edit with GIMP"), show_status, gimp_edit, nil, nil, gimp_widget) -- +script_data.destroy = destroy + +return script_data diff --git a/contrib/gpx_export.lua b/contrib/gpx_export.lua index 0995ba98..152d3e60 100644 --- a/contrib/gpx_export.lua +++ b/contrib/gpx_export.lua @@ -25,11 +25,17 @@ For each source folder, a separate is generated in the gpx file. local dt = require "darktable" local df = require "lib/dtutils.file" local dl = require "lib/dtutils" - local gettext = dt.gettext -dl.check_min_api_version("3.0.0", "gpx-export") -local CURR_API_STRING = dt.configuration.api_version_string +dl.check_min_api_version("7.0.0", "gpx_export") + +-- return data structure for script_manager + +local script_data = {} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again -- Tell gettext where to find the .mo file translating messages for a particular domain gettext.bindtextdomain("gpx_export",dt.configuration.config_dir.."/lua/locale/") @@ -149,6 +155,14 @@ local function install_module() end end +local function destroy() + dt.gui.libs["gpx_exporter"].visible = false +end + +local function restart() + dt.gui.libs["gpx_exporter"].visible = true +end + gpx.widget = dt.new_widget("box") { orientation = "vertical", @@ -175,7 +189,7 @@ if dt.gui.current_view().id == "lighttable" then else if not gpx.event_registered then dt.register_event( - "view-changed", + "gpx_export", "view-changed", function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() @@ -185,3 +199,9 @@ else gpx.event_registered = true end end + +script_data.destroy = destroy +script_data.restart = restart +script_data.destroy_method = "hide" + +return script_data diff --git a/contrib/hugin.lua b/contrib/hugin.lua index 1de8f04a..ed040f1e 100644 --- a/contrib/hugin.lua +++ b/contrib/hugin.lua @@ -54,7 +54,15 @@ local executable_table = {"hugin", "hugin_executor", "pto_gen"} local PQ = dt.configuration.running_os == "windows" and '"' or "'" -- works with darktable API version from 5.0.0 on -du.check_min_api_version("5.0.0", "hugin") +du.check_min_api_version("7.0.0", "hugin") + +-- return data structure for script_manager + +local script_data = {} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again -- Tell gettext where to find the .mo file translating messages for a particular domain gettext.bindtextdomain("hugin",dt.configuration.config_dir.."/lua/locale/") @@ -205,6 +213,10 @@ local function create_panorama(storage, image_table, extra_data) --finalize end end +local function destroy() + dt.destroy_storage(namespace) +end + -- Register if dt.configuration.running_os ~= "linux" then exec_widget = df.executable_path_widget(executable_table) @@ -224,6 +236,8 @@ hugin_widget = dt.new_widget("box") { dt.register_storage(namespace, _("hugin panorama"), show_status, create_panorama, nil, nil, hugin_widget) +script_data.destroy = destroy +return script_data -- -- vim: shiftwidth=2 expandtab tabstop=2 cindent syntax=lua diff --git a/contrib/image_stack.lua b/contrib/image_stack.lua index de3e0c04..8560c131 100644 --- a/contrib/image_stack.lua +++ b/contrib/image_stack.lua @@ -71,7 +71,15 @@ local job = nil local PS = dt.configuration.running_os == "windows" and "\\" or "/" -- works with LUA API version 5.0.0 -du.check_min_api_version("5.0.0", "image_stack") +du.check_min_api_version("7.0.0", "image_stack") + +-- return data structure for script_manager + +local script_data = {} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again -- Tell gettext where to find the .mo file translating messages for a particular domain gettext.bindtextdomain("image_stack",dt.configuration.config_dir.."/lua/locale/") @@ -452,6 +460,10 @@ local function stop_job() job.valid = false end +local function destroy() + dt.destroy_storage("module_image_stack") +end + -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -- main program -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -585,3 +597,6 @@ dt.preferences.register("align_image_stack", "align_use_gpu", -- name dt.register_storage("module_image_stack", _("image stack"), show_status, image_stack, nil, nil, image_stack_widget) +script_data.destroy = destroy + +return script_data diff --git a/contrib/image_time.lua b/contrib/image_time.lua index ed60a5a9..78b6f42e 100644 --- a/contrib/image_time.lua +++ b/contrib/image_time.lua @@ -107,15 +107,21 @@ local dt = require "darktable" local du = require "lib/dtutils" local df = require "lib/dtutils.file" local ds = require "lib/dtutils.string" - local gettext = dt.gettext local img_time = {} img_time.module_installed = false img_time.event_registered = false -du.check_min_api_version("3.0.0", "image_time") -local CURR_API_STRING = dt.configuration.api_version_string +du.check_min_api_version("7.0.0", "image_time") + +-- return data structure for script_manager + +local script_data = {} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again -- Tell gettext where to find the .mo file translating messages for a particular domain @@ -410,6 +416,14 @@ local function install_module() end end +local function destroy() + dt.gui.libs["image_time"].visible = false +end + +local function restart() + dt.gui.libs["image_time"].visible = true +end + -- widgets img_time.widgets = { @@ -553,7 +567,7 @@ if dt.gui.current_view().id == "lighttable" then else if not img_time.event_registered then dt.register_event( - "view-changed", + "image_time", "view-changed", function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() @@ -564,3 +578,9 @@ else end end +script_data.destroy = destroy +script_data.restart = restart +script_data.destroy_method = "hide" +script_data.show = restart + +return script_data diff --git a/contrib/kml_export.lua b/contrib/kml_export.lua index 279ad769..f2722be2 100644 --- a/contrib/kml_export.lua +++ b/contrib/kml_export.lua @@ -43,7 +43,15 @@ local gettext = dt.gettext local PS = dt.configuration.running_os == "windows" and "\\" or "/" -du.check_min_api_version("5.0.0", kml_export) +du.check_min_api_version("7.0.0", "kml_export") + +-- return data structure for script_manager + +local script_data = {} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again -- Tell gettext where to find the .mo file translating messages for a particular domain gettext.bindtextdomain("kml_export",dt.configuration.config_dir.."/lua/locale/") @@ -301,6 +309,10 @@ local function create_kml_file(storage, image_table, extra_data) end +local function destroy() + dt.destroy_storage("kml_export") +end + -- Preferences if dt.configuration.running_os == "windows" then dt.preferences.register("kml_export", @@ -369,5 +381,9 @@ else dt.register_storage("kml_export", _("KML/KMZ Export"), nil, create_kml_file) end +script_data.destroy = destroy + +return script_data + -- vim: shiftwidth=2 expandtab tabstop=2 cindent syntax=lua -- kate: hl Lua; diff --git a/contrib/pdf_slideshow.lua b/contrib/pdf_slideshow.lua index 10e84db9..f1824856 100644 --- a/contrib/pdf_slideshow.lua +++ b/contrib/pdf_slideshow.lua @@ -56,7 +56,15 @@ if not df.check_if_bin_exists("pdflatex") then return end -du.check_min_api_version("4.0.0", "pdf_slideshow") +du.check_min_api_version("7.0.0", "pdf_slideshow") + +-- return data structure for script_manager + +local script_data = {} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again dt.preferences.register ("pdf_slideshow","open with","string", @@ -164,6 +172,10 @@ local function slide(latexfile,i,image,file) my_write(latexfile,"\\end{figure}\n") end +local function destroy() + dt.destroy_storage("pdf_slideshow") +end + dt.register_storage("pdf_slideshow",_("pdf slideshow"), nil, function(storage,image_table) @@ -243,5 +255,8 @@ dt.register_storage("pdf_slideshow",_("pdf slideshow"), nil, widget) +script_data.destroy = destroy + +return script_data -- -- vim: shiftwidth=2 expandtab tabstop=2 cindent syntax=lua diff --git a/contrib/photils.lua b/contrib/photils.lua index c2858f2a..3be939e2 100644 --- a/contrib/photils.lua +++ b/contrib/photils.lua @@ -39,13 +39,20 @@ local dt = require "darktable" local du = require "lib/dtutils" local df = require "lib/dtutils.file" - local dtsys = require "lib/dtutils.system" local MODULE_NAME = "photils" -du.check_min_api_version("5.0.0", MODULE_NAME) +du.check_min_api_version("7.0.0", MODULE_NAME) + +-- return data structure for script_manager + +local script_data = {} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again + -local CURR_API_STRING = dt.configuration.api_version_string local PS = dt.configuration.running_os == "windows" and "\\" or "/" local gettext = dt.gettext gettext.bindtextdomain(MODULE_NAME, @@ -391,6 +398,22 @@ local function install_module() end end +local function destroy() + dt.gui.libs[MODULE_NAME].visible = false + dt.destroy_event("photils", "mouse-over-image-changed") +end + +local function restart() + dt.gui.libs[MODULE_NAME].visible = true + dt.register_event("photils", "mouse-over-image-changed", + PHOTILS.image_changed) +end + +local function show() + dt.gui.libs[MODULE_NAME].visible = true +end + + -- add a fix number of buttons for _ = 1, PHOTILS.per_page, 1 do local btn_tag = dt.new_widget("check_button") { @@ -454,7 +477,7 @@ dt.preferences.register(MODULE_NAME, "The embedded thumbnail could speedup the tag suggestion but can fail if the RAW file is not supported."), true) -dt.register_event("mouse-over-image-changed", +dt.register_event("photils", "mouse-over-image-changed", PHOTILS.image_changed) if dt.gui.current_view().id == "lighttable" then @@ -462,7 +485,7 @@ if dt.gui.current_view().id == "lighttable" then else if not PHOTILS.event_registered then dt.register_event( - "view-changed", + "photils", "view-changed", function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() @@ -473,3 +496,9 @@ else end end +script_data.destroy = destroy +script_data.restart = restart +script_data.destroy_method = "hide" +script_data.show = show + +return script_data diff --git a/contrib/quicktag.lua b/contrib/quicktag.lua index 51bf57d9..db451e19 100644 --- a/contrib/quicktag.lua +++ b/contrib/quicktag.lua @@ -47,18 +47,23 @@ local dt = require "darktable" local du = require "lib/dtutils" local debug = require "darktable.debug" +du.check_min_api_version("7.0.0", "quicktag") + +-- return data structure for script_manager + +local script_data = {} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again + local qt = {} qt.module_installed = false qt.event_registered = false qt.widget_table = {} - - local gettext = dt.gettext -du.check_min_api_version("3.0.0", "quicktag") -local CURR_API_STRING = dt.configuration.api_version_string - -- Tell gettext where to find the .mo file translating messages for a particular domain gettext.bindtextdomain("quicktag",dt.configuration.config_dir.."/lua/locale/") @@ -163,7 +168,7 @@ abbrevate_tags(quicktag_table) local button = {} -- function to create buttons with tags as labels -for j=1,qnr do +for j = 1, qnr do button[#button+1] = dt.new_widget("button") { label = j..": "..quicktag_table[j], clicked_callback = function() tagattach(tostring(quicktag_table[j]),j) end} @@ -205,12 +210,35 @@ local function install_module() end end +local function destroy() + dt.gui.libs["quicktag"].visible = false + for i=1,qnr do + dt.destroy_event("quicktag " .. tostring(i), "shortcut") + end +end + +local function restart() + dt.gui.libs["quicktag"].visible = true + for i = 1 ,qnr do + dt.register_event("quicktag", "shortcut", + function(event, shortcut) tagattach(tostring(quicktag_table[i])) end, + string.format(_("quicktag %i"),i)) + end +end + +local function show() + dt.gui.libs["quicktag"].visible = true +end + + + + update_quicktag_list() local new_quicktag = dt.new_widget("entry"){ text = "", placeholder = _("new tag"), - is_password = false, + is_password = true, editable = true, tooltip = _("enter your tag here") } @@ -257,7 +285,7 @@ if dt.gui.current_view().id == "lighttable" then else if not qt.event_registered then dt.register_event( - "view-changed", + "quicktag", "view-changed", function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() @@ -270,10 +298,17 @@ end -- create shortcuts for i=1,qnr do - dt.register_event("shortcut", + dt.register_event("quicktag " .. tostring(i), "shortcut", function(event, shortcut) tagattach(tostring(quicktag_table[i])) end, string.format(_("quicktag %i"),i)) end +script_data.destroy = destroy +script_data.restart = restart +script_data.destroy_method = "hide" +script_data.show = show + +return script_data + -- vim: shiftwidth=2 expandtab tabstop=2 cindent syntax=lua -- kate: tab-indents: off; indent-width 2; replace-tabs on; remove-trailing-space on; diff --git a/contrib/rate_group.lua b/contrib/rate_group.lua index 88bbf555..4f2fa608 100644 --- a/contrib/rate_group.lua +++ b/contrib/rate_group.lua @@ -42,8 +42,15 @@ local dt = require "darktable" local du = require "lib/dtutils" -- added version check -du.check_min_api_version("3.0.0", "rate_group") -local CURR_API_STRING = dt.configuration.api_version_string +du.check_min_api_version("7.0.0", "rate_group") + +-- return data structure for script_manager + +local script_data = {} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again local function apply_rating(rating) local images = dt.gui.action_images @@ -60,37 +67,51 @@ local function apply_rating(rating) end end -dt.register_event("shortcut", +local function destroy() + dt.destroy_event("rg_reject", "shortcut") + dt.destroy_event("rg0", "shortcut") + dt.destroy_event("rg1", "shortcut") + dt.destroy_event("rg2", "shortcut") + dt.destroy_event("rg3", "shortcut") + dt.destroy_event("rg4", "shortcut") + dt.destroy_event("rg5", "shortcut") +end + +dt.register_event("rg_reject", "shortcut", function(event, shortcut) apply_rating(-1) end, "Reject group") -dt.register_event("shortcut", +dt.register_event("rg0", "shortcut", function(event, shortcut) apply_rating(0) end, "Rate group 0") -dt.register_event("shortcut", +dt.register_event("rg1", "shortcut", function(event, shortcut) apply_rating(1) end, "Rate group 1") -dt.register_event("shortcut", +dt.register_event("rg2", "shortcut", function(event, shortcut) apply_rating(2) end, "Rate group 2") -dt.register_event("shortcut", +dt.register_event("rg3", "shortcut", function(event, shortcut) apply_rating(3) end, "Rate group 3") -dt.register_event("shortcut", +dt.register_event("rg4", "shortcut", function(event, shortcut) apply_rating(4) end, "Rate group 4") -dt.register_event("shortcut", +dt.register_event("rg5", "shortcut", function(event, shortcut) apply_rating(5) end, "Rate group 5") + +script_data.destroy = destroy + +return script_data diff --git a/contrib/rename-tags.lua b/contrib/rename-tags.lua index 6f1eea90..d440c5f9 100644 --- a/contrib/rename-tags.lua +++ b/contrib/rename-tags.lua @@ -33,8 +33,15 @@ local du = require "lib/dtutils" local debug = require "darktable.debug" -- check API version -du.check_min_api_version("3.0.0", "rename-tags") -local CURR_API_STRING = darktable.configuration.api_version_string +du.check_min_api_version("7.0.0", "rename-tags") + +-- return data structure for script_manager + +local script_data = {} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again local rt = {} rt.module_installed = false @@ -111,6 +118,14 @@ local function install_module() end end +local function destroy() + darktable.gui.libs["rename_tags"].visible = false +end + +local function restart() + darktable.gui.libs["rename_tags"].visible = true +end + -- GUI local old_widget = darktable.new_widget ("box") { orientation = "horizontal", @@ -137,7 +152,7 @@ if darktable.gui.current_view().id == "lighttable" then else if not rt.event_registered then darktable.register_event( - "view-changed", + "rename_tags", "view-changed", function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() @@ -148,4 +163,11 @@ else end end +script_data.destroy = destroy +script_data.restart = restart +script_data.destroy_method = "hide" +script_data.show = restart + +return script_data + diff --git a/contrib/select_untagged.lua b/contrib/select_untagged.lua index 0c8e9698..8740ee2f 100644 --- a/contrib/select_untagged.lua +++ b/contrib/select_untagged.lua @@ -22,11 +22,18 @@ local dt = require "darktable" local du = require "lib/dtutils" local gettext = dt.gettext -du.check_min_api_version("3.0.0", "select_untagged") +du.check_min_api_version("7.0.0", "select_untagged") + +-- return data structure for script_manager + +local script_data = {} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again -- Tell gettext where to find the .mo file translating messages for a particular domain gettext.bindtextdomain("select_untagged",dt.configuration.config_dir.."/lua/locale/") -local CURR_API_STRING = dt.configuration.api_version_string local function _(msgid) return gettext.dgettext("select_untagged", msgid) @@ -64,7 +71,15 @@ local function select_untagged_images(event, images) return selection end +local function destroy() + dt.gui.libs.select.destroy_selection("select_untagged") +end + dt.gui.libs.select.register_selection( - _("select untagged"), + "select_untagged", _("select untagged"), select_untagged_images, _("select all images containing no tags or only tags added by darktable")) + +script_data.destroy = destroy + +return script_data diff --git a/contrib/slideshowMusic.lua b/contrib/slideshowMusic.lua index 0e66f4d4..67c17363 100644 --- a/contrib/slideshowMusic.lua +++ b/contrib/slideshowMusic.lua @@ -27,12 +27,17 @@ USAGE local dt = require "darktable" local du = require "lib/dtutils" local df = require "lib/dtutils.file" - local gettext = dt.gettext -du.check_min_api_version("2.0.2", "slideshowMusic") +du.check_min_api_version("7.0.0", "slideshowMusic") + +-- return data structure for script_manager -local CURR_API_STRING = dt.configuration.api_version_string +local script_data = {} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again -- Tell gettext where to find the .mo file translating messages for a particular domain gettext.bindtextdomain("slideshowMusic",dt.configuration.config_dir.."/lua/locale/") @@ -70,6 +75,12 @@ local function playSlideshowMusic(_, old_view, new_view) end end +function destroy() + dt.destroy_event("slideshow_music", "view-changed") + dt.preferences.destroy("slideshowMusic", "SlideshowMusic") + dt.preferences.destroy("slideshowMusic", "PlaySlideshowMusic") +end + -- Preferences dt.preferences.register("slideshowMusic", "SlideshowMusic", "file", _("Slideshow background music file"), "", "") dt.preferences.register("slideshowMusic", @@ -79,5 +90,9 @@ dt.preferences.register("slideshowMusic", _("Plays music with rhythmbox if a slideshow starts"), true) -- Register -dt.register_event("view-changed", +dt.register_event("slideshow_music", "view-changed", playSlideshowMusic) + +script_data.destroy = destroy + +return script_data diff --git a/contrib/transfer_hierarchy.lua b/contrib/transfer_hierarchy.lua index 291950da..840deeca 100755 --- a/contrib/transfer_hierarchy.lua +++ b/contrib/transfer_hierarchy.lua @@ -78,12 +78,19 @@ local dtutils_file = require("lib/dtutils.file") local dtutils_system = require("lib/dtutils.system") local LIB_ID = "transfer_hierarchy" -dtutils.check_min_api_version("5.0.0", LIB_ID) +dtutils.check_min_api_version("7.0.0", LIB_ID) + +-- return data structure for script_manager + +local script_data = {} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again local MKDIR_COMMAND = darktable.configuration.running_os == "windows" and "mkdir " or "mkdir -p " local PATH_SEPARATOR = darktable.configuration.running_os == "windows" and "\\\\" or "/" local PATH_SEGMENT_REGEX = "(" .. PATH_SEPARATOR .. "?)([^" .. PATH_SEPARATOR .. "]+)" -local CURR_API_STRING = darktable.configuration.api_version_string unpack = unpack or table.unpack gmatch = string.gfind or string.gmatch @@ -302,6 +309,13 @@ local function doCopy() doTransfer(darktable.database.copy_image) end +local function destroy() + darktable.gui.libs[LIB_ID].visible = false +end + +local function restart() + darktable.gui.libs[LIB_ID].visible = true +end @@ -367,7 +381,7 @@ if darktable.gui.current_view().id == "lighttable" then else if not th.event_registered then darktable.register_event( - "view-changed", + LIB_ID, "view-changed", function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() @@ -377,3 +391,11 @@ else th.event_registered = true end end + + +script_data.destroy = destroy +script_data.restart = restart +script_data.destroy_method = "hide" +script_data.show = restart + +return script_data \ No newline at end of file diff --git a/contrib/video_ffmpeg.lua b/contrib/video_ffmpeg.lua index 1d59935f..43a79d9e 100644 --- a/contrib/video_ffmpeg.lua +++ b/contrib/video_ffmpeg.lua @@ -39,7 +39,15 @@ local df = require "lib/dtutils.file" local dsys = require "lib/dtutils.system" local gettext = dt.gettext -du.check_min_api_version("5.0.0") +du.check_min_api_version("7.0.0", "video_ffmpeg") + +-- return data structure for script_manager + +local script_data = {} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again local MODULE_NAME = "video_ffmpeg" @@ -448,6 +456,12 @@ local function finalize_export(storage, images_table, extra_data) df.rmdir(df.sanitize_filename(tmp_dir)) end +-- script_manager integration + +local function destroy() + dt.destroy_storage("module_video_ffmpeg") +end + dt.register_storage( "module_video_ffmpeg", _(MODULE_NAME), @@ -458,3 +472,8 @@ dt.register_storage( module_widget ) +-- script_manager integration + +script_data.destroy = destroy + +return script_data diff --git a/examples/api_version.lua b/examples/api_version.lua index 971f14c0..f2aaff72 100644 --- a/examples/api_version.lua +++ b/examples/api_version.lua @@ -23,5 +23,19 @@ USAGE ]] local dt = require "darktable" +-- script_manager integration to allow a script to be removed +-- without restarting darktable +local function destroy() + -- nothing to destroy +end + local result = dt.configuration.api_version_string dt.print_error("API Version: "..result) + +-- set the destroy routine so that script_manager can call it when +-- it's time to destroy the script and then return the data to +-- script_manager +local script_data = {} +script_data.destroy = destroy + +return script_data diff --git a/examples/darkroom_demo.lua b/examples/darkroom_demo.lua index e0e40526..b4edcc56 100644 --- a/examples/darkroom_demo.lua +++ b/examples/darkroom_demo.lua @@ -42,6 +42,12 @@ local du = require "lib/dtutils" du.check_min_api_version("5.0.2", "darkroom_mode") -- darktable 3.0 +-- script_manager integration to allow a script to be removed +-- without restarting darktable +local function destroy() + -- nothing to destroy +end + -- - - - - - - - - - - - - - - - - - - - - - - - -- C O N S T A N T S -- - - - - - - - - - - - - - - - - - - - - - - - @@ -70,6 +76,16 @@ local sleep = dt.control.sleep local current_view = dt.gui.current_view() +-- check that there is an image selected, otherwise we can't activate darkroom viewe + +local images = dt.gui.action_images +dt.print_log(#images .. " images selected") +if not images or #images == 0 then + dt.print_log("no images selected, creating selection") + dt.print_log("using image " .. dt.collection[1].filename) + dt.gui.selection({dt.collection[1]}) +end + -- enter darkroom view dt.gui.current_view(dt.gui.views.darkroom) @@ -96,3 +112,10 @@ dt.print(_("Restoring view")) sleep(1500) dt.gui.current_view(current_view) +-- set the destroy routine so that script_manager can call it when +-- it's time to destroy the script and then return the data to +-- script_manager +local script_data = {} +script_data.destroy = destroy + +return script_data diff --git a/examples/gettextExample.lua b/examples/gettextExample.lua index c6eda49e..59a676c1 100644 --- a/examples/gettextExample.lua +++ b/examples/gettextExample.lua @@ -58,6 +58,12 @@ local du = require "lib/dtutils" --check API version du.check_min_api_version("3.0.0", "gettextExample") +-- script_manager integration to allow a script to be removed +-- without restarting darktable +local function destroy() + -- nothing to destroy +end + -- Not translated Text dt.print_error("Hello World!") @@ -77,3 +83,11 @@ local function _(msgid) return gettext.dgettext("gettextExample", msgid) end dt.print_error(_('Hello World!')) + +-- set the destroy routine so that script_manager can call it when +-- it's time to destroy the script and then return the data to +-- script_manager +local script_data = {} +script_data.destroy = destroy + +return script_data diff --git a/examples/hello_world.lua b/examples/hello_world.lua index 11a287e2..f8fba8d4 100644 --- a/examples/hello_world.lua +++ b/examples/hello_world.lua @@ -31,7 +31,20 @@ local du = require "lib/dtutils" du.check_min_api_version("2.0.0", "hello_world") +-- script_manager integration to allow a script to be removed +-- without restarting darktable +local function destroy() + -- nothing to destroy +end + dt.print("hello, world") +-- set the destroy routine so that script_manager can call it when +-- it's time to destroy the script and then return the data to +-- script_manager +local script_data = {} +script_data.destroy = destroy + +return script_data -- -- vim: shiftwidth=2 expandtab tabstop=2 cindent syntax=lua diff --git a/examples/lighttable_demo.lua b/examples/lighttable_demo.lua index c3629bad..fc071325 100644 --- a/examples/lighttable_demo.lua +++ b/examples/lighttable_demo.lua @@ -50,6 +50,12 @@ du.check_min_api_version("5.0.2", "lighttable_demo") -- darktable 3.0 local MODULE_NAME = "lighttable" local PS = dt.configuration.running_os == "windows" and "\\" or "/" +-- script_manager integration to allow a script to be removed +-- without restarting darktable +local function destroy() + -- nothing to destroy +end + -- - - - - - - - - - - - - - - - - - - - - - - - -- T R A N S L A T I O N S -- - - - - - - - - - - - - - - - - - - - - - - - @@ -75,6 +81,7 @@ local layouts = { "DT_LIGHTTABLE_LAYOUT_ZOOMABLE", "DT_LIGHTTABLE_LAYOUT_FILEMANAGER", "DT_LIGHTTABLE_LAYOUT_CULLING", + "DT_LIGHTTABLE_LAYOUT_CULLING_DYNAMIC", } local sorts = { @@ -139,6 +146,7 @@ sleep(2000) for n, layout in ipairs(layouts) do dt.gui.libs.lighttable_mode.layout(layout) dt.print(_("set lighttable layout to " .. layout)) + dt.print_log(_("set lighttable layout to " .. layout)) sleep(1500) for i = 1, 10 do dt.gui.libs.lighttable_mode.zoom_level(i) @@ -152,11 +160,17 @@ for n, layout in ipairs(layouts) do end end +dt.print_log("finished layout and zoom level testing") +dt.print_log("starting sort demonstration") -- cycle through sorts dt.print(_("lighttable sorting demonstration")) +dt.print_log("setting lighttable to filemanager mode") dt.gui.libs.lighttable_mode.layout("DT_LIGHTTABLE_LAYOUT_FILEMANAGER") +sleep(500) +dt.print_log("setting lighttable to zoom level 5") dt.gui.libs.lighttable_mode.zoom_level(5) +dt.print_log("starting sorts") for n, sort in ipairs(sorts) do dt.gui.libs.filter.sort(sort) @@ -196,3 +210,11 @@ current_rating = dt.gui.libs.filter.rating(current_rating) current_rating_comparator = dt.gui.libs.filter.rating_comparator(current_rating_comparator) current_sort =dt.gui.libs.filter.sort(current_sort) current_sort_order = dt.gui.libs.filter.sort_order(current_sort_order) + +-- set the destroy routine so that script_manager can call it when +-- it's time to destroy the script and then return the data to +-- script_manager +local script_data = {} +script_data.destroy = destroy + +return script_data diff --git a/examples/moduleExample.lua b/examples/moduleExample.lua index 93c182df..b68161e8 100644 --- a/examples/moduleExample.lua +++ b/examples/moduleExample.lua @@ -33,8 +33,15 @@ https://www.darktable.org/lua-api/index.html.php#darktable_new_widget local dt = require "darktable" local du = require "lib/dtutils" -du.check_min_api_version("3.0.0", "moduleExample") -local CURR_API_STRING = dt.configuration.api_version_string +du.check_min_api_version("7.0.0", "moduleExample") + +-- return data structure for script_manager + +local script_data = {} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again -- translation @@ -86,6 +93,16 @@ local function install_module() end end +-- script_manager integration to allow a script to be removed +-- without restarting darktable +local function destroy() + dt.gui.libs["exampleModule"].visible = false -- we haven't figured out how to destroy it yet, so we hide it for now +end + +local function restart() + dt.gui.libs["exampleModule"].visible = true -- the user wants to use it again, so we just make it visible and it shows up in the UI +end + -- https://www.darktable.org/lua-api/types_lua_check_button.html local check_button = dt.new_widget("check_button"){label = _("MyCheck_button"), value = true} @@ -148,7 +165,7 @@ else if not mE.event_registered then -- if we are not in lighttable view then register an event to signal when we might be -- https://www.darktable.org/lua-api/index.html#darktable_register_event dt.register_event( - "view-changed", -- we want to be informed when the view changes + "mdouleExample", "view-changed", -- we want to be informed when the view changes function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then -- if the view changes from darkroom to lighttable install_module() -- register the lib @@ -159,5 +176,14 @@ else end end +-- set the destroy routine so that script_manager can call it when +-- it's time to destroy the script and then return the data to +-- script_manager +script_data.destroy = destroy +script_data.restart = restart -- only required for lib modules until we figure out how to destroy them +script_data.destroy_method = "hide" -- tell script_manager that we are hiding the lib so it knows to use the restart function +script_data.show = restart -- if the script was "off" when darktable exited, the module is hidden, so force it to show on start + +return script_data -- vim: shiftwidth=2 expandtab tabstop=2 cindent syntax=lua -- kate: hl Lua; diff --git a/examples/multi_os.lua b/examples/multi_os.lua index 1227e5ea..4ab650ff 100644 --- a/examples/multi_os.lua +++ b/examples/multi_os.lua @@ -52,7 +52,7 @@ ]] local dt = require "darktable" - + --[[ require "lib/..." provides access to functions that have been pulled from various scripts and consolidated into libraries. Using the libraries eliminates having to @@ -62,7 +62,6 @@ local dt = require "darktable" local du = require "lib/dtutils" -- utilities local df = require "lib/dtutils.file" -- file utilities local dtsys = require "lib/dtutils.system" -- system utilities -local CURR_API_STRING = dt.configuration.api_version_string --[[ darktable is an international program, and it's user interface has been translated into @@ -87,7 +86,7 @@ end screen stating that you couldn't load because the minimum api version wasn't met. ]] -du.check_min_api_version("5.0.0", "multi_os") +du.check_min_api_version("7.0.0", "multi_os") --[[ copy_image_attributes is a local subroutine to copy image attributes in the database from the raw image @@ -197,6 +196,15 @@ local function extract_embedded_jpeg(images) end end +--[[ + script_manager integration to allow a script to be removed + without restarting darktable +]] + +local function destroy() + dt.destroy_event("multi_os", "shortcut") -- destroy the event since the callback will no longer be present + dt.gui.libs.image.destroy_action("multi_os") -- remove the button from the selected images module +end --[[ Windows and MacOS don't place executables in the user's path so their location needs to be specified so that the script can find them. An exception to this is packages installed on MacOS with homebrew. Those @@ -231,18 +239,28 @@ end ]] dt.gui.libs.image.register_action( - _("extract embedded jpeg"), + "multi_os", _("extract embedded jpeg"), function(event, images) extract_embedded_jpeg(images) end, "extract embedded jpeg" ) - --[[ Add a shortcut ]] dt.register_event( - "shortcut", + "multi_os", "shortcut", function(event, shortcut) extract_embedded_jpeg(dt.gui.action_images) end, "extract embedded jpeg" ) + +--[[ + set the destroy routine so that script_manager can call it when + it's time to destroy the script and then return the data to + script_manager +]] + +local script_data = {} +script_data.destroy = destroy + +return script_data diff --git a/examples/panels_demo.lua b/examples/panels_demo.lua index edab6ae5..1f74d718 100644 --- a/examples/panels_demo.lua +++ b/examples/panels_demo.lua @@ -41,7 +41,13 @@ local du = require "lib/dtutils" -- V E R S I O N C H E C K -- - - - - - - - - - - - - - - - - - - - - - - - -du.check_min_api_version("5.0.2", "panels_demo") -- darktable 3.0 +du.check_min_api_version("7.0.0", "panels_demo") + +-- script_manager integration to allow a script to be removed +-- without restarting darktable +local function destroy() + -- nothing to destroy +end -- - - - - - - - - - - - - - - - - - - - - - - - -- C O N S T A N T S @@ -134,3 +140,11 @@ for i = 1, #panels do dt.gui.panel_hide(panels[i]) end end + +-- set the destroy routine so that script_manager can call it when +-- it's time to destroy the script and then return the data to +-- script_manager +local script_data = {} +script_data.destroy = destroy + +return script_data diff --git a/examples/preferenceExamples.lua b/examples/preferenceExamples.lua index 9710b95b..99f85188 100644 --- a/examples/preferenceExamples.lua +++ b/examples/preferenceExamples.lua @@ -26,6 +26,7 @@ local du = require "lib/dtutils" du.check_min_api_version("2.0.1", "preferenceExamples") + dt.preferences.register("preferenceExamples", -- script: This is a string used to avoid name collision in preferences (i.e namespace). Set it to something unique, usually the name of the script handling the preference. "preferenceExamplesString", -- name "string", -- type @@ -34,14 +35,14 @@ dt.preferences.register("preferenceExamples", -- script: This is a string "String") -- default dt.preferences.register("preferenceExamples", -- script: This is a string used to avoid name collision in preferences (i.e namespace). Set it to something unique, usually the name of the script handling the preference. - "preferenceExamplesString", -- name + "preferenceExamplesBool", -- name "bool", -- type "Example Boolean", -- label "Example Boolean Tooltip", -- tooltip true) -- default dt.preferences.register("preferenceExamples", -- script: This is a string used to avoid name collision in preferences (i.e namespace). Set it to something unique, usually the name of the script handling the preference. - "preferenceExamplesString", -- name + "preferenceExamplesInteger", -- name "integer", -- type "Example Integer", -- label "Example Integer Tooltip", -- tooltip @@ -50,7 +51,7 @@ dt.preferences.register("preferenceExamples", -- script: This is a string 99) -- max dt.preferences.register("preferenceExamples", -- script: This is a string used to avoid name collision in preferences (i.e namespace). Set it to something unique, usually the name of the script handling the preference. - "preferenceExamplesString", -- name + "preferenceExamplesFloat", -- name "float", -- type "Example Float", -- label "Example Float Tooltip", -- tooltip @@ -60,21 +61,21 @@ dt.preferences.register("preferenceExamples", -- script: This is a string 0.5) -- step dt.preferences.register("preferenceExamples", -- script: This is a string used to avoid name collision in preferences (i.e namespace). Set it to something unique, usually the name of the script handling the preference. - "preferenceExamplesString", -- name + "preferenceExamplesFile", -- name "file", -- type "Example File", -- label "Example File Tooltip", -- tooltip "") -- default dt.preferences.register("preferenceExamples", -- script: This is a string used to avoid name collision in preferences (i.e namespace). Set it to something unique, usually the name of the script handling the preference. - "preferenceExamplesString", -- name + "preferenceExamplesDirectory", -- name "directory", -- type "Example Directory", -- label "Example Directory Tooltip", -- tooltip "") -- default dt.preferences.register("preferenceExamples", -- script: This is a string used to avoid name collision in preferences (i.e namespace). Set it to something unique, usually the name of the script handling the preference. - "preferenceExamplesString", -- name + "preferenceExamplesEnum", -- name "enum", -- type "Example Enum", -- label "Example Enum Tooltip", -- tooltip diff --git a/examples/printExamples.lua b/examples/printExamples.lua index 074a5db1..b220b7a0 100644 --- a/examples/printExamples.lua +++ b/examples/printExamples.lua @@ -24,6 +24,12 @@ local du = require "lib/dtutils" du.check_min_api_version("5.0.0", "printExamples") +-- script_manager integration to allow a script to be removed +-- without restarting darktable +local function destroy() + -- nothing to destroy +end + -- Will print a string to the darktable control log (the long -- overlayed window that appears over the main panel). dt.print("print") @@ -38,5 +44,12 @@ dt.print_error("print error") -- to enable the Lua logdomain. dt.print_log("print log") +-- set the destroy routine so that script_manager can call it when +-- it's time to destroy the script and then return the data to +-- script_manager +local script_data = {} +script_data.destroy = destroy + +return script_data -- -- vim: shiftwidth=2 expandtab tabstop=2 cindent syntax=lua diff --git a/examples/running_os.lua b/examples/running_os.lua index 632c033a..d214b2a9 100644 --- a/examples/running_os.lua +++ b/examples/running_os.lua @@ -30,7 +30,21 @@ local du = require "lib/dtutils" du.check_min_api_version("5.0.0", "running_os") +-- script_manager integration to allow a script to be removed +-- without restarting darktable +local function destroy() + -- nothing to destroy +end + dt.print("You are running: "..dt.configuration.running_os) +-- set the destroy routine so that script_manager can call it when +-- it's time to destroy the script and then return the data to +-- script_manager +local script_data = {} +script_data.destroy = destroy + +return script_data + -- -- vim: shiftwidth=2 expandtab tabstop=2 cindent syntax=lua diff --git a/official/check_for_updates.lua b/official/check_for_updates.lua index 712daab1..5f1b4848 100644 --- a/official/check_for_updates.lua +++ b/official/check_for_updates.lua @@ -34,6 +34,14 @@ local cjson = require "cjson" du.check_min_api_version("2.0.0", "check_for_updates") +-- return data structure for script_manager + +local script_data = {} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again + -- compare two version strings of the form "major.minor.patch" -- returns -1, 0, 1 if the first version is smaller, equal, greater than the second version, -- or nil if one or both are of the wrong format @@ -80,6 +88,10 @@ local function compare_versions(a, b) end end +local function destroy() + -- nothing to destroy +end + -- local function test(a, b, r) -- local cmp = compare_versions(a, b) @@ -134,3 +146,6 @@ if now > (back_then + 60 * 60 * 24 * 7) then end end + +script_data.destroy = destroy +return script_data diff --git a/official/copy_paste_metadata.lua b/official/copy_paste_metadata.lua index 05808169..ec4e7c85 100644 --- a/official/copy_paste_metadata.lua +++ b/official/copy_paste_metadata.lua @@ -29,8 +29,15 @@ local dt = require "darktable" local du = require "lib/dtutils" local gettext = dt.gettext -du.check_min_api_version("3.0.0", "copy_paste_metadata") -local CURR_API_STRING = dt.configuration.api_version_string +du.check_min_api_version("7.0.0", "copy_paste_metadata") + +-- return data structure for script_manager + +local script_data = {} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again -- set this to "false" if you don't want to overwrite metadata fields -- (title, description, creator, publisher and rights) that are already set @@ -113,26 +120,41 @@ local function paste(images) end end +local function destroy() + dt.gui.libs.image.destroy_action("metadata_copy") + dt.gui.libs.image.destroy_action("metadata_paste") + dt.destroy_event("capmd1", "shortcut") + dt.destroy_event("capmd2", "shortcut") +end + dt.gui.libs.image.register_action( - _("copy metadata"), + "metadata_copy", _("copy metadata"), function(event, images) copy(images[1]) end, _("copy metadata of the first selected image") ) + + dt.gui.libs.image.register_action( - _("paste metadata"), + "metadata_paste", _("paste metadata"), function(event, images) paste(images) end, _("paste metadata to the selected images") ) + + dt.register_event( - "shortcut", + "capmd1", "shortcut", function(event, shortcut) copy(dt.gui.action_images[1]) end, "copy metadata" ) dt.register_event( - "shortcut", + "capmd2", "shortcut", function(event, shortcut) paste(dt.gui.action_images) end, "paste metadata" ) + +script_data.destroy = destroy + +return script_data diff --git a/official/delete_long_tags.lua b/official/delete_long_tags.lua index 9ab1a289..a5f54553 100644 --- a/official/delete_long_tags.lua +++ b/official/delete_long_tags.lua @@ -33,11 +33,23 @@ local du = require "lib/dtutils" du.check_min_api_version("2.0.0", "delete_long_tags") +-- return data structure for script_manager + +local script_data = {} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again + dt.preferences.register("delete_long_tags", "length", "integer", "maximum length of tags to keep", "tags longer than this get deleted on start", 666, 0, 65536) +local function destroy() + -- noting to destroy +end + local max_length = dt.preferences.read("delete_long_tags", "length", "integer") -- deleting while iterating the tags list seems to break the iterator! @@ -55,3 +67,7 @@ for _,name in pairs(long_tags) do tag = dt.tags.find(name) tag:delete() end + +script_data.destroy = destroy + +return script_data diff --git a/official/delete_unused_tags.lua b/official/delete_unused_tags.lua index 4c114230..fcaf03d6 100644 --- a/official/delete_unused_tags.lua +++ b/official/delete_unused_tags.lua @@ -31,6 +31,20 @@ local du = require "lib/dtutils" du.check_min_api_version("5.0.0", "delete_unused_tags") +local script_data = {} + +local function destroy() + -- noting to destroy +end + +-- return data structure for script_manager + +local script_data = {} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again + -- deleting while iterating the tags list seems to break the iterator! local unused_tags = {} @@ -45,3 +59,6 @@ for _,name in pairs(unused_tags) do tag = dt.tags.find(name) tag:delete() end + +script_data.destroy = destroy +return script_data \ No newline at end of file diff --git a/official/enfuse.lua b/official/enfuse.lua index ecb2b8e1..212f0e3f 100644 --- a/official/enfuse.lua +++ b/official/enfuse.lua @@ -38,11 +38,18 @@ local df = require "lib/dtutils.file" local dtsys = require "lib/dtutils.system" local PS = dt.configuration.running_os == "windows" and "\\" or "/" -local CURR_API_STRING = dt.configuration.api_version_string local gettext = dt.gettext -du.check_min_api_version("3.0.0", "enfuse") +du.check_min_api_version("7.0.0", "enfuse") + +-- return data structure for script_manager + +local script_data = {} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again -- Tell gettext where to find the .mo file translating messages for a particular domain gettext.bindtextdomain("enfuse",dt.configuration.config_dir..PS .. "lua" .. PS .. "locale" .. PS) @@ -76,6 +83,15 @@ local function install_module() enf.module_installed = true end end + +local function destroy() + dt.gui.libs["enfuse"].visible = false +end + +local function restart() + dt.gui.libs["enfuse"].visible = true +end + -- add a new lib -- is enfuse installed? local enfuse_installed = df.check_if_bin_exists("enfuse") @@ -269,7 +285,7 @@ if enfuse_installed then else if not enf.event_registered then dt.register_event( - "view-changed", + "enfuse", "view-changed", function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() @@ -285,5 +301,11 @@ else dt.print(_("Could not find enfuse executable. Not loading enfuse exporter...")) end +script_data.destroy = destroy +script_data.restart = restart +script_data.destroy_method = "hide" +script_data.show = restart + +return script_data -- vim: shiftwidth=2 expandtab tabstop=2 cindent syntax=lua -- kate: hl Lua; diff --git a/official/generate_image_txt.lua b/official/generate_image_txt.lua index 3d9906d1..11eceb0b 100644 --- a/official/generate_image_txt.lua +++ b/official/generate_image_txt.lua @@ -38,8 +38,15 @@ local dt = require "darktable" local du = require "lib/dtutils" require "darktable.debug" -du.check_min_api_version("2.1.0", "generate_image_txt") -local CURR_API_STRING = dt.configuration.api_version_string +du.check_min_api_version("7.0.0", "generate_image_txt") + +-- return data structure for script_manager + +local script_data = {} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again dt.preferences.register("generate_image_txt", "enabled", @@ -62,11 +69,15 @@ local check_command = function(command) end end +local function destroy() + dt.destroy_event("gen_img_txt", "mouse-over-image-changed") +end + local command_setting = dt.preferences.read("generate_image_txt", "command", "string") check_command(command_setting) -dt.register_event("mouse-over-image-changed", +dt.register_event("gen_img_txt", "mouse-over-image-changed", function(event, img) -- no need to waste processing time if the image has a txt file already if not img or img.has_txt or not dt.preferences.read("generate_image_txt", "enabled", "bool") then @@ -105,6 +116,9 @@ dt.register_event("mouse-over-image-changed", end ) +script_data.destroy = destroy + +return script_data -- vim: shiftwidth=2 expandtab tabstop=2 cindent -- kate: tab-indents: off; indent-width 2; replace-tabs on; remove-trailing-space on; diff --git a/official/image_path_in_ui.lua b/official/image_path_in_ui.lua index 7cf63c7b..e256cf41 100644 --- a/official/image_path_in_ui.lua +++ b/official/image_path_in_ui.lua @@ -31,8 +31,15 @@ This plugin will add a widget at the bottom of the left column in lighttable mod local dt = require "darktable" local du = require "lib/dtutils" -du.check_min_api_version("2.0.0", "image_path_in_ui") -local CURR_API_STRING = dt.configuration.api_version_string +du.check_min_api_version("7.0.0", "image_path_in_ui") + +-- return data structure for script_manager + +local script_data = {} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again local ipiu = {} ipiu.module_installed = false @@ -42,8 +49,8 @@ local main_label = dt.new_widget("label"){selectable = true, ellipsize = "middle local function install_module() if not ipiu.module_installed then - dt.register_lib("image_path_no_ui", "selected images path", true, false,{ - [dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_LEFT_CENTER", 300} + dt.register_lib("image_path_no_ui","selected images path",true,false,{ + [dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_LEFT_CENTER",300} }, main_label ) ipiu.module_installed = true @@ -67,6 +74,20 @@ local function reset_widget() main_label.label = result end +local function destroy() + dt.gui.libs["image_path_no_ui"].visible = false + dt.destroy_event("ipiu", "mouse-over-image-changed") +end + +local function restart() + dt.register_event("ipiu", "mouse-over-image-changed", reset_widget); + dt.gui.libs["image_path_no_ui"].visible = true +end + +local function show() + dt.gui.libs["image_path_no_ui"].visible = true +end + main_label.reset_callback = reset_widget if dt.gui.current_view().id == "lighttable" then @@ -85,7 +106,13 @@ else end end -dt.register_event("mouse-over-image-changed", reset_widget); +dt.register_event("ipiu", "mouse-over-image-changed", reset_widget); + +script_data.destroy = destroy +script_data.restart = restart +script_data.destroy_method = "hide" +script_data.show = show +return script_data -- -- vim: shiftwidth=2 expandtab tabstop=2 cindent syntax=lua diff --git a/official/import_filter_manager.lua b/official/import_filter_manager.lua index 63466c59..e27a1f7f 100644 --- a/official/import_filter_manager.lua +++ b/official/import_filter_manager.lua @@ -34,7 +34,6 @@ local dt = require "darktable" local import_filter_list = {} local n_import_filters = 1 -local CURR_API_STRING = dt.configuration.api_version_string -- allow changing the filter from the preferences dt.preferences.register("import_filter_manager", "active_filter", "string", @@ -57,7 +56,7 @@ dt.gui.libs.import.register_widget(filter_dropdown) -- this is just a wrapper which calls the active import filter -dt.register_event("pre-import", function(event, images) +dt.register_event("ifm", "pre-import", function(event, images) local active_filter = dt.preferences.read("import_filter_manager", "active_filter", "string") if active_filter == "" then return end local callback = import_filter_list[active_filter] diff --git a/official/save_selection.lua b/official/save_selection.lua index 6861b5f0..d05a760a 100644 --- a/official/save_selection.lua +++ b/official/save_selection.lua @@ -36,25 +36,43 @@ increase it if you need more temporary selection buffers local dt = require "darktable" local du = require "lib/dtutils" -du.check_min_api_version("2.0.0", "save_selection") -local CURR_API_STRING = dt.configuration.api_version_string +du.check_min_api_version("7.0.0", "save_selection") + +-- return data structure for script_manager + +local script_data = {} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again local buffer_count = 5 -for i=1,buffer_count do +local function destroy() + for i = 1, buffer_count do + dt.destroy_event("save_selection save " .. i, "shortcut") + dt.destroy_event("save_selection restore " .. i, "shortcut") + end + dt.destroy_event("save_selection switch", "shortcut") +end + +for i = 1, buffer_count do local saved_selection - dt.register_event("shortcut", function() + dt.register_event("save_selection save " .. i, "shortcut", function() saved_selection = dt.gui.selection() - end,"save to buffer "..i) - dt.register_event("shortcut", function() + end, "save to buffer " .. i) + dt.register_event("save_selection restore " .. i, "shortcut", function() dt.gui.selection(saved_selection) - end,"restore from buffer "..i) + end, "restore from buffer " .. i) end local bounce_buffer = {} -dt.register_event("shortcut", function() +dt.register_event("save_selection switch", "shortcut", function() bounce_buffer = dt.gui.selection(bounce_buffer) -end,"switch selection with temporary buffer") +end, "switch selection with temporary buffer") + +script_data.destroy = destroy +return script_data -- -- vim: shiftwidth=2 expandtab tabstop=2 cindent syntax=lua diff --git a/official/selection_to_pdf.lua b/official/selection_to_pdf.lua index 9d548da4..b2b688e5 100644 --- a/official/selection_to_pdf.lua +++ b/official/selection_to_pdf.lua @@ -36,7 +36,15 @@ Plugin allows you to choose how many thumbnails you need per row local dt = require "darktable" local du = require "lib/dtutils" -du.check_min_api_version("2.0.0", "selection_to_pdf") +du.check_min_api_version("7.0.0", "selection_to_pdf") + +-- return data structure for script_manager + +local script_data = {} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again dt.preferences.register ("selection_to_pdf","Open with","string", @@ -101,6 +109,12 @@ local function thumbnail(latexfile,i,image,file) my_write(latexfile,"\\end{minipage}\\quad\n") end +local function destroy() + dt.print_log("destroying storage") + dt.destroy_storage("export_pdf") + dt.print_log("done destroying") +end + dt.register_storage("export_pdf","Export thumbnails to pdf", nil, function(storage,image_table) @@ -168,5 +182,8 @@ dt.register_storage("export_pdf","Export thumbnails to pdf", end end,nil,nil,widget) +script_data.destroy = destroy + +return script_data -- -- vim: shiftwidth=2 expandtab tabstop=2 cindent syntax=lua diff --git a/tools/executable_manager.lua b/tools/executable_manager.lua index 14c4d7b3..396e44c1 100644 --- a/tools/executable_manager.lua +++ b/tools/executable_manager.lua @@ -32,12 +32,19 @@ local dt = require "darktable" local du = require "lib/dtutils" local df = require "lib/dtutils.file" -du.check_min_api_version("5.0.0", "executable_manager") +du.check_min_api_version("7.0.0", "executable_manager") + +-- return data structure for script_manager + +local script_data = {} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again local PS = dt.configuration.running_os == "windows" and "\\" or "/" local gettext = dt.gettext -local CURR_API_STRING = dt.configuration.api_version_string gettext.bindtextdomain("executable_manager",dt.configuration.config_dir.."/lua/locale/") @@ -111,6 +118,15 @@ local function install_module() exec_man.module_installed = true end end + +local function destroy() + dt.gui.libs["executable_manager"].visible = false +end + +local function restart() + dt.gui.libs["executable_manager"].visible = true +end + -- - - - - - - - - - - - - - - - - - - - - - - - - - - - -- M A I N P R O G R A M -- - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -215,7 +231,7 @@ if dt.gui.current_view().id == "lighttable" then else if not exec_man.event_registered then dt.register_event( - "view-changed", + "executable_manager", "view-changed", function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() @@ -225,3 +241,10 @@ else exec_man.event_registered = true end end + +script_data.destroy = destroy +script_data.restart = restart +script_data.destroy_method = "hide" +script_data.show = restart + +return script_data diff --git a/tools/gen_i18n_mo.lua b/tools/gen_i18n_mo.lua index d032484b..6aa453c2 100644 --- a/tools/gen_i18n_mo.lua +++ b/tools/gen_i18n_mo.lua @@ -32,6 +32,10 @@ local dtsys = require "lib/dtutils.system" du.check_min_api_version("5.0.0", "gen_I18n_mo") +local function destroy() + -- nothing to destroy +end + -- figure out the path separator local PS = dt.configuration.running_os == "windows" and "\\" or "/" @@ -97,3 +101,8 @@ dt.preferences.register("executable_paths", "msgfmt", -- name is_directory = false, } ) + +local script_data = {} +script_data.destroy = destroy + +return script_data diff --git a/tools/get_lib_manpages.lua b/tools/get_lib_manpages.lua index 9ea2f699..2e599181 100644 --- a/tools/get_lib_manpages.lua +++ b/tools/get_lib_manpages.lua @@ -12,6 +12,10 @@ local libname = nil du.check_min_api_version("3.0.0", "get_lib_manpages") +local function destroy() + -- nothing to destroy +end + local keys = {"Name", "Synopsis", "Usage", "Description", "Return_Value", "Limitations", "Example", "See_Also", "Reference", "License", "Copyright"} @@ -74,3 +78,7 @@ for line in output:lines() do libname = nil end +local script_data = {} +script_data.destroy = destroy + +return script_data diff --git a/tools/get_libdoc.lua b/tools/get_libdoc.lua index ed0813ac..d22516fc 100644 --- a/tools/get_libdoc.lua +++ b/tools/get_libdoc.lua @@ -9,6 +9,10 @@ local du = require "lib/dtutils" du.check_min_api_version("3.0.0", "get_libdoc") +local function destroy() + -- nothing to destroy +end + local keys = {"Name", "Synopsis", "Usage", "Description", "Return_Value", "Limitations", "Example", "See_Also", "Reference", "License", "Copyright"} @@ -48,3 +52,7 @@ for line in output:lines() do end end +local script_data = {} +script_data.destroy = destroy + +return script_data diff --git a/tools/script_manager.lua b/tools/script_manager.lua index 3ab0b547..6c6518c4 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -54,6 +54,7 @@ local df = require "lib/dtutils.file" local ds = require "lib/dtutils.string" local dtsys = require "lib/dtutils.system" local log = require "lib/dtutils.log" +local debug = require "darktable.debug" local gettext = dt.gettext @@ -67,7 +68,7 @@ end -- api check -du.check_min_api_version("6.1.0", "script_manager") +du.check_min_api_version("5.0.0", "script_manager") -- - - - - - - - - - - - - - - - - - - - - - - - @@ -91,7 +92,6 @@ local DEFAULT_LOG_LEVEL = log.error local LUA_DIR = dt.configuration.config_dir .. PS .. "lua" local LUA_SCRIPT_REPO = "https://github.com/darktable-org/lua-scripts.git" -local CURR_API_STRING = dt.configuration.api_version_string -- - - - - - - - - - - - - - - - - - - - - - - - -- L O G L E V E L @@ -99,7 +99,7 @@ local CURR_API_STRING = dt.configuration.api_version_string local old_log_level = log.log_level() -log.log_level(DEFAULT_LOG_LEVEL) +log.log_level(log.debug) -- - - - - - - - - - - - - - - - - - - - - - - - -- N A M E S P A C E @@ -118,6 +118,44 @@ sm.event_registered = false sm.widgets = {} sm.categories = {} + +--[[ + + sm.scripts is a table of tables for containing the scripts + It is organized as into category (folder) subtables containing + each script definition, which is a table + + sm.scripts- + | + - category------------| + | - script + - category----| | + - script| + | - script + - script| + + and a script table looks like + + name the name of the script file without the lua extension + path category (folder), path separator, path, name without the lua extension + doc the header comments from the script to be used as a tooltip + script_name the folder, path separator, and name without the lua extension + running true if running, false if not, hidden if running but the + lib/storage/action for the script is hidden + has_lib true if it creates a module + lib_name name of the created lib + has_storage true if it creates a storage (exporter) + storage_name name of the exporter (in the exporter storage menu) + has_action true if it creates an action + action_name name on the button + has_event true if it creates an event handler + event_type type of event, shortcut, post-xxx, pre-xxx + callback name of the callback routine + initialized all of the above data has been retreived and set. If the + script is unloaded and reloaded we don't have to reparse the file + +]] + sm.scripts = {} sm.page_status = {} sm.page_status.num_buttons = DEFAULT_BUTTONS_PER_PAGE @@ -125,6 +163,9 @@ sm.page_status.buttons_created = 0 sm.page_status.current_page = 0 sm.page_status.category = "" +-- use color in the interface? +sm.use_color = false + -- installed script repositories sm.installed_repositories = { {name = "lua-scripts", directory = LUA_DIR}, @@ -169,6 +210,16 @@ local function update_combobox_choices(combobox, choice_table, selected) combobox.value = selected end +local function string_trim(str) + local result = string.gsub(str, "^%s+", "") + result = string.gsub(result, "%s+$", "") + return result +end + +local function string_dequote(str) + return string.gsub(str, "['\"]", "") +end + local function add_script_category(category) if #sm.categories == 0 or not string.match(du.join(sm.categories, " "), ds.sanitize_lua(category)) then table.insert(sm.categories, category) @@ -197,30 +248,67 @@ local function get_script_doc(script) end local function activate(script) + local status = nil -- status of start function + local err = nil -- error message returned if module doesn't start log.msg(log.info, "activating " .. script.name) - local status, err = du.prequire(script.path) - if status then - pref_write(script.script_name, "bool", true) - log.msg(log.screen, _("Loaded ") .. script.script_name) + if script.running == false then + status, err = du.prequire(script.path) + log.msg(log.debug, "prequire returned " .. tostring(status) .. " and for err " .. tostring(err)) + if status then + pref_write(script.script_name, "bool", true) + log.msg(log.screen, _("Loaded ") .. script.script_name) + script.running = true + if err ~= true then + log.msg(log.debug, "got lib data") + script.data = err + if script.data.destroy_method and script.data.destroy_method == "hide" then + script.data.show() + end + else + script.data = nil + end + else + log.msg(log.screen, script.script_name .. _(" failed to load")) + log.msg(log.error, "Error loading " .. script.script_name) + log.msg(log.error, "Error message: " .. err) + end + else -- script is a lib and loaded but hidden and the user wants to reload + script.data.restart() script.running = true - else - log.msg(log.screen, script.script_name .. _(" failed to load")) - log.msg(log.error, "Error loading " .. script.script_name) - log.msg(log.error, "Error message: " .. err) + status = true + pref_write(script.script_name, "bool", true) end return status end local function deactivate(script) - -- presently the lua api doesn't support unloading gui elements therefore - -- we just mark then inactive for the next time darktable starts + -- presently the lua api doesn't support unloading gui elements however, we + -- can hide libs, so we just mark those as hidden and hide the gui + -- can delete storage + --therefore we just mark then inactive for the next time darktable starts -- deactivate it.... - pref_write(script.script_name, "bool", false) - script.running = false - log.msg(log.info, "setting " .. script.script_name .. " to not start") - log.msg(log.screen, script.name .. _(" will not start when darktable is restarted")) + if script.data then + script.data.destroy() + if script.data.destroy_method then + if string.match(script.data.destroy_method, "hide") then + script.running = "hidden" + else + package.loaded[script.script_name] = nil + script.running = false + end + else + package.loaded[script.script_name] = nil + script.running = false + end + log.msg(log.info, "turned off " .. script.script_name) + log.msg(log.screen, script.name .. _(" stopped")) + else + script.running = false + log.msg(log.info, "setting " .. script.script_name .. " to not start") + log.msg(log.screen, script.name .. _(" will not start when darktable is restarted")) + end end local function add_script_name(name, path, category) @@ -231,7 +319,8 @@ local function add_script_name(name, path, category) path = category .. "/" .. path .. name, running = false, doc = get_script_doc(category .. "/" .. path .. name), - script_name = category .. "/" .. name + script_name = category .. "/" .. name, + data = nil } table.insert(sm.scripts[category], script) if pref_read(script.script_name, "bool") then @@ -438,9 +527,11 @@ local function clear_button(number) button.label = "" button.tooltip = "" button.sensitive = false +--button.name = "" end local function find_script(category, name) + log.msg(log.debug, "looking for script " .. name .. " in category " .. category) for _, script in ipairs(sm.scripts[category]) do if string.match(script.name, "^" .. ds.sanitize_lua(name) .. "$") then return script @@ -455,28 +546,52 @@ local function populate_buttons(category, first, last) for i = first, last do script = sm.scripts[category][i] button = sm.widgets.buttons[button_num] - if script.running then - button.label = script.name .. _(" started") + if script.running == true then + if sm.use_color then + button.label = script.name + button.name = "sm_started" + else + button.label = script.name .. _(" started") + end else - button.label = script.name .. _(" stopped") + if sm.use_color then + button.label = script.name + button.name = "sm_stopped" + else + button.label = script.name .. _(" stopped") + end end button.ellipsize = "middle" button.sensitive = true button.tooltip = script.doc button.clicked_callback = function (this) - local script_name, state = string.match(this.label, "(.-) (.+)") + local script_name = nil + local state = nil + if sm.use_color then + script_name = string.match(this.label, "(.+)") + else + script_name, state = string.match(this.label, "(.-) (.+)") + end local script = find_script(sm.widgets.category_selector.value, script_name) if script then log.msg(log.debug, "found script " .. script.name .. " with path " .. script.path) - if string.match(state, "started") then + if script.running == true then log.msg(log.debug, "deactivating " .. script.name .. " on " .. script.path .. " for button " .. this.label) deactivate(script) - this.label = script.name .. " stopped" + if sm.use_color then + this.name = "sm_stopped" + else + this.label = script.name .. _(" stopped") + end else log.msg(log.debug, "activating " .. script.name .. " on " .. script.path .. " for button " .. this.label) local result = activate(script) if result then - this.label = script.name .. " started" + if sm.use_color then + this.name = "sm_started" + else + this.label = script.name .. " started" + end end end else @@ -650,9 +765,21 @@ local function install_module() sm.module_installed = true end sm.run = true + sm.use_color = pref_read("use_color", "bool") log.msg(log.debug, "set run to true, loading preferences") load_preferences() scan_repositories() + --[[dt.print_log("\n\nsetting sm visible false\n\n") + dt.gui.libs["script_manager"].visible = false + dt.control.sleep(5000) + dt.print_log("setting sm visible true") + dt.gui.libs["script_manager"].visible = true + --[[dt.control.sleep(5000) + dt.print_log("setting sm expanded false") + dt.gui.libs["script_manager"].expanded = false + dt.control.sleep(5000) + dt.print_log("setting sm expanded true") + dt.gui.libs["script_manager"].expanded = true]] end -- - - - - - - - - - - - - - - - - - - - - - - - @@ -665,8 +792,6 @@ log.msg(log.debug, "finished processing scripts") -- U S E R I N T E R F A C E -- - - - - - - - - - - - - - - - - - - - - - - - -sm.widgets = {} - -- update the scripts sm.widgets.update_script_choices = dt.new_widget("combobox"){ @@ -769,8 +894,8 @@ for i =1, DEFAULT_BUTTONS_PER_PAGE do sm.page_status.buttons_create = sm.page_status.buttons_created + 1 end -local page_back = " < " -local page_forward = " > " +local page_back = "<" +local page_forward = ">" sm.widgets.page_status = dt.new_widget("label"){label = _("Page:")} sm.widgets.page_back = dt.new_widget("button"){ @@ -834,6 +959,16 @@ sm.widgets.configure = dt.new_widget("box"){ sm.widgets.change_buttons, } +sm.widgets.color = dt.new_widget("check_button"){ + label = _("use color interface?"), + value = pref_read("use_color", "bool"), + clicked_callback = function(this) + pref_write("use_color", "bool", this.value) + sm.use_color = this.value + end +} +table.insert(sm.widgets.configure, sm.widgets.color) + -- stack for the options sm.widgets.main_stack = dt.new_widget("stack"){ From 56ec258cc7db60b58294bf19d8c72dafbb24a347 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Thu, 1 Jul 2021 21:45:38 -0400 Subject: [PATCH 166/445] [script_manager] Added API awareness so that the correct version of scripts that match the API version of darktable are used. [Changelog.md] Updated the change log with the latest changes. --- ChangeLog.md | 34 ++++++++--- tools/script_manager.lua | 121 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 147 insertions(+), 8 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 346b4fa8..aef3eab4 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,21 +1,41 @@ ## Changes from most recent to oldest - -** 19 Jun 2021 - wpferguson - fix issue 312, image_path_in_ui** - -** 02 Jun 2021 - wpferguson - fix contrib/quicktag** +**02 Jul 2021 - wpferguson - merged API-7.0.0-dev branch to master +* API-7.0.0 is darktable 3.6 +* breaking changes + * register_event argments changed + * register_action arguments changed + * register_selection arguments changed + * register_event arguments changed +* scripts updated to API-7.0.0 compatibility +* script_manger updated to be API aware and check out the proper branch + based on darktable API version + +**01 Jul 2021 - wpferguson - created branch for API-6.1.0 - darktable 3.4 + +**20 Jun 2021 - wpferguson - created branches for older API versions +* API-6.0.0 - darktable 3.2.1 +* API-5.0.2 - darktable 3.0 +* API-5.0.1 - darktable 2.6.1 +* API-5.0.0 - darktable 2.4 +* API-4.0.0 - darktable 2.2 +* API-3.0.0 - darktable 2.0 + +**19 Jun 2021 - wpferguson - fix issue 312, image_path_in_ui** + +**02 Jun 2021 - wpferguson - fix contrib/quicktag** * set new entry field is_password to false so entry is visible to user while typing. -** 19 Mar 2021 - wpferguson - fixed crash in contrib/HDRmerge.lua** +**19 Mar 2021 - wpferguson - fixed crash in contrib/HDRmerge.lua** * Made generated filename routine gracefully handle names that are not in the expected format. -** 15 Mar 2021 - scheckmedia - updated contrib/photils.lua** +**15 Mar 2021 - scheckmedia - updated contrib/photils.lua** * refactor print method * add option to apply selected tags from a single image to multiple images * add setting parameter to enable/disable the export of an image before tag suggestion -** 25 Feb 2021 - wpferguson - added detached mode to contrib/gimp.lua** +**25 Feb 2021 - wpferguson - added detached mode to contrib/gimp.lua** * Added run_detached checkbox to the exporter GUI. Selecting run_detached let's GIMP keep running and accepting additional images. It does not return diff --git a/tools/script_manager.lua b/tools/script_manager.lua index 6c6518c4..d1f600d1 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -92,6 +92,8 @@ local DEFAULT_LOG_LEVEL = log.error local LUA_DIR = dt.configuration.config_dir .. PS .. "lua" local LUA_SCRIPT_REPO = "https://github.com/darktable-org/lua-scripts.git" +local LUA_API_VER = "API-" .. dt.configuration.api_version_string + -- - - - - - - - - - - - - - - - - - - - - - - - -- L O G L E V E L @@ -99,7 +101,7 @@ local LUA_SCRIPT_REPO = "https://github.com/darktable-org/lua-scripts.git" local old_log_level = log.log_level() -log.log_level(log.debug) +log.log_level(DEFAULT_LOG_LEVEL) -- - - - - - - - - - - - - - - - - - - - - - - - -- N A M E S P A C E @@ -192,6 +194,62 @@ local function pref_write(name, pref_type, value) dt.preferences.write(MODULE, name, pref_type, value) end +-- git interface + +local function get_repo_status(repo) + local p = io.popen("cd " .. repo .. CS .. "git status") + if p then + local data = p:read("*a") + p:close() + return data + end + dt.print_error("unable to get status of " .. repo) + return nil +end + +local function get_current_repo_branch(repo_data) + local branch = nil + branch = string.match(repo_data, "On branch (.-)\n") + dt.print_log("\ncurrent rep branch is " .. branch) + return branch +end + +local function get_repo_branches(repo) + local branches = {} + local p = io.popen("cd " .. repo .. CS .. "git pull --all" .. CS .. "git branch --all") + if p then + local data = p:read("*a") + p:close() + dt.print_log("data is \n" .. data) + local branch_data = du.split(data, "\n") + for _, line in ipairs(branch_data) do + dt.print_log("line is " .. line) + local branch = string.gsub(line, "%s+remotes/%a+/", "") + if string.match(branch, "API") then + dt.print_log("found branch - " .. branch) + table.insert(branches, branch) + end + end + end + return branches +end + + +local function is_repo_clean(repo_data) + if string.match(repo_data, "working tree clean") then + dt.print_log("repo is clean") + return true + else + dt.print_log("repo is dirty") + return false + end +end + +local function checkout_repo_branch(repo, branch) + dt.print_log("checkout out branch " .. branch .. " from repository " .. repo) + os.execute("cd " .. repo .. CS .. "git checkout " .. branch) +end + local function update_combobox_choices(combobox, choice_table, selected) local items = #combobox local choices = #choice_table @@ -785,9 +843,70 @@ end -- - - - - - - - - - - - - - - - - - - - - - - - -- M A I N P R O G R A M -- - - - - - - - - - - - - - - - - - - - - - - - +local repo_data = get_repo_status(LUA_DIR) +local current_branch = get_current_repo_branch(repo_data) +local clean = is_repo_clean(repo_data) +local repo = LUA_DIR + +if sm.executables.git and clean and + (current_branch == "master" or string.match(current_branch, "^API%-")) then -- only make changes to clean branches + local branches = get_repo_branches(LUA_DIR) + if current_branch ~= LUA_API_VER and current_branch ~= "master" then + -- probably upgraded from an earlier api version so get back to master + -- to use the latest version of script_manager to get the proper API + checkout_repo_branch(repo, "master") + log.msg(log.screen, "lua API version reset, please restart darktable") + elseif LUA_API_VER == current_branch then + -- do nothing, we are fine + log.msg(log.debug, "took equal branch, doing nothing") + elseif string.match(LUA_API_VER, "dev") then + -- we are on a dev API version, so checkout the dev + -- api version or checkout/stay on master + log.msg(log.debug, "took the dev branch") + local match = false + for _, branch in ipairs(branches) do + log.msg(log.debug, "checking branch " .. branch .. " against API " .. LUA_API_VER) + if LUA_API_VER == branch then + match = true + log.msg(log.info, "checking out repo development branch " .. branch) + checkout_repo_branch(repo, branch) + end + end + if not match then + if current_branch == "master" then + log.msg(log.info, "staying on master, no dev branch yet") + else + log.msg(log.info, "no dev branch available, checking out master") + checkout_repo_branch(repo, "master") + end + end + elseif LUA_API_VER > branches[#branches] then + log.msg(log.info, "no newer branches, staying on master") + -- stay on master + else + -- checkout the appropriate branch for API version if it exists + log.msg(log.info, "checking out the appropriate API branch") + local match = false + for _, branch in ipairs(branches) do + log.msg(log.debug, "checking branch " .. branch .. " against API " .. LUA_API_VER) + if LUA_API_VER == branch then + match = true + log.msg(log.info, "checking out repo branch " .. branch) + checkout_repo_branch(repo, branch) + log.msg(log.screen, "you must restart darktable to use the correct version of the lua") + end + end + if not match then + log.msg(log.warn, "no matching branch found for " .. LUA_API_VER) + end + end +end + scan_scripts(LUA_DIR) log.msg(log.debug, "finished processing scripts") + + -- - - - - - - - - - - - - - - - - - - - - - - - -- U S E R I N T E R F A C E -- - - - - - - - - - - - - - - - - - - - - - - - From c196f98bc6c75d41634405fe98e11473a820ac6a Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Thu, 1 Jul 2021 21:51:26 -0400 Subject: [PATCH 167/445] [ChangeLog.md] fixed formatting --- ChangeLog.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index aef3eab4..34d4d960 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,5 +1,5 @@ ## Changes from most recent to oldest -**02 Jul 2021 - wpferguson - merged API-7.0.0-dev branch to master +**02 Jul 2021 - wpferguson - merged API-7.0.0-dev branch to master** * API-7.0.0 is darktable 3.6 * breaking changes * register_event argments changed @@ -10,9 +10,9 @@ * script_manger updated to be API aware and check out the proper branch based on darktable API version -**01 Jul 2021 - wpferguson - created branch for API-6.1.0 - darktable 3.4 +**01 Jul 2021 - wpferguson - created branch for API-6.1.0 - darktable 3.4** -**20 Jun 2021 - wpferguson - created branches for older API versions +**20 Jun 2021 - wpferguson - created branches for older API versions** * API-6.0.0 - darktable 3.2.1 * API-5.0.2 - darktable 3.0 * API-5.0.1 - darktable 2.6.1 From 19cd118f8fb91ad6555bd201bea671e885f799fe Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Fri, 2 Jul 2021 20:28:48 -0400 Subject: [PATCH 168/445] [script_manager] converted dt.print_log statements to log.msg with the appropriate level --- tools/script_manager.lua | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tools/script_manager.lua b/tools/script_manager.lua index d1f600d1..2c561c71 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -203,14 +203,14 @@ local function get_repo_status(repo) p:close() return data end - dt.print_error("unable to get status of " .. repo) + log.msg(log.error, "unable to get status of " .. repo) return nil end local function get_current_repo_branch(repo_data) local branch = nil branch = string.match(repo_data, "On branch (.-)\n") - dt.print_log("\ncurrent rep branch is " .. branch) + log.msg(log.info, "\ncurrent rep0 branch is " .. branch) return branch end @@ -220,13 +220,13 @@ local function get_repo_branches(repo) if p then local data = p:read("*a") p:close() - dt.print_log("data is \n" .. data) + log.msg(log.debug, "data is \n" .. data) local branch_data = du.split(data, "\n") for _, line in ipairs(branch_data) do - dt.print_log("line is " .. line) + log.msg(log.debug, "line is " .. line) local branch = string.gsub(line, "%s+remotes/%a+/", "") if string.match(branch, "API") then - dt.print_log("found branch - " .. branch) + log.msg(log.info, "found branch - " .. branch) table.insert(branches, branch) end end @@ -237,16 +237,16 @@ end local function is_repo_clean(repo_data) if string.match(repo_data, "working tree clean") then - dt.print_log("repo is clean") + log.msg(log.info, "repo is clean") return true else - dt.print_log("repo is dirty") + log.msg(log.info, "repo is dirty") return false end end local function checkout_repo_branch(repo, branch) - dt.print_log("checkout out branch " .. branch .. " from repository " .. repo) + log.msg(log.info, "checkout out branch " .. branch .. " from repository " .. repo) os.execute("cd " .. repo .. CS .. "git checkout " .. branch) end @@ -451,7 +451,7 @@ local function update_scripts() local git = sm.executables.git if not git then - dt.print("ERROR: git not found. Install or specify the location of the git executable.") + dt.print(_("ERROR: git not found. Install or specify the location of the git executable.")) return end @@ -535,7 +535,7 @@ local function install_scripts() local git = sm.executables.git if not git then - dt.print("ERROR: git not found. Install or specify the location of the git executable.") + dt.print(_("ERROR: git not found. Install or specify the location of the git executable.")) return end From 8f314059e4b3712228ef24c435af3601b66edc27 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Fri, 2 Jul 2021 21:13:33 -0400 Subject: [PATCH 169/445] [script_manager] handle the case where no branches are detected --- tools/script_manager.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/script_manager.lua b/tools/script_manager.lua index 2c561c71..8f26f757 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -880,7 +880,7 @@ if sm.executables.git and clean and checkout_repo_branch(repo, "master") end end - elseif LUA_API_VER > branches[#branches] then + elseif #branches and LUA_API_VER > branches[#branches] then log.msg(log.info, "no newer branches, staying on master") -- stay on master else From f8ec85ddae20736d33fb6542e20973ce75c1ec80 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Fri, 2 Jul 2021 21:22:43 -0400 Subject: [PATCH 170/445] bug --- tools/script_manager.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/script_manager.lua b/tools/script_manager.lua index 8f26f757..a70ec9ce 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -87,7 +87,7 @@ local MIN_BUTTONS_PER_PAGE = 5 local MAX_BUTTONS_PER_PAGE = 20 local DEFAULT_BUTTONS_PER_PAGE = 10 -local DEFAULT_LOG_LEVEL = log.error +local DEFAULT_LOG_LEVEL = log.debug local LUA_DIR = dt.configuration.config_dir .. PS .. "lua" local LUA_SCRIPT_REPO = "https://github.com/darktable-org/lua-scripts.git" From 93cc0adb398c0950c805f9db9e5878e61e4044c8 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Fri, 2 Jul 2021 21:25:36 -0400 Subject: [PATCH 171/445] bug --- tools/script_manager.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/script_manager.lua b/tools/script_manager.lua index a70ec9ce..9c7e3884 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -880,7 +880,7 @@ if sm.executables.git and clean and checkout_repo_branch(repo, "master") end end - elseif #branches and LUA_API_VER > branches[#branches] then + elseif branches ~= nil and LUA_API_VER > branches[#branches] then log.msg(log.info, "no newer branches, staying on master") -- stay on master else From 440dfcadfd4f7b990228f2f6df6a177a7b0bfb41 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Fri, 2 Jul 2021 21:26:45 -0400 Subject: [PATCH 172/445] bug --- tools/script_manager.lua | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tools/script_manager.lua b/tools/script_manager.lua index 9c7e3884..1cee7654 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -880,9 +880,11 @@ if sm.executables.git and clean and checkout_repo_branch(repo, "master") end end - elseif branches ~= nil and LUA_API_VER > branches[#branches] then - log.msg(log.info, "no newer branches, staying on master") - -- stay on master + elseif branches then + if LUA_API_VER > branches[#branches] then + log.msg(log.info, "no newer branches, staying on master") + -- stay on master + end else -- checkout the appropriate branch for API version if it exists log.msg(log.info, "checking out the appropriate API branch") From e32c0c70a838e24cd8f6b942bb86b6fed269cec8 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Fri, 2 Jul 2021 21:28:26 -0400 Subject: [PATCH 173/445] bug --- tools/script_manager.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/script_manager.lua b/tools/script_manager.lua index 1cee7654..1df213f2 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -881,6 +881,7 @@ if sm.executables.git and clean and end end elseif branches then + dt.print_log("branches has " .. #branches .. " branches") if LUA_API_VER > branches[#branches] then log.msg(log.info, "no newer branches, staying on master") -- stay on master From 887bc03f3240168c04199d575b973f2e69d66b6b Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Fri, 2 Jul 2021 21:29:36 -0400 Subject: [PATCH 174/445] bug --- tools/script_manager.lua | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/tools/script_manager.lua b/tools/script_manager.lua index 1df213f2..acba4a64 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -880,12 +880,9 @@ if sm.executables.git and clean and checkout_repo_branch(repo, "master") end end - elseif branches then - dt.print_log("branches has " .. #branches .. " branches") - if LUA_API_VER > branches[#branches] then - log.msg(log.info, "no newer branches, staying on master") - -- stay on master - end + elseif #branches >0 and LUA_API_VER > branches[#branches] then + log.msg(log.info, "no newer branches, staying on master") + -- stay on master else -- checkout the appropriate branch for API version if it exists log.msg(log.info, "checking out the appropriate API branch") From 422fdbe2cf9a6c9b04c2294958a29969f0f2a9e4 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Fri, 2 Jul 2021 21:33:50 -0400 Subject: [PATCH 175/445] [script_manager] make sure we have branches before comparing --- tools/script_manager.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/script_manager.lua b/tools/script_manager.lua index acba4a64..cf764147 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -87,7 +87,7 @@ local MIN_BUTTONS_PER_PAGE = 5 local MAX_BUTTONS_PER_PAGE = 20 local DEFAULT_BUTTONS_PER_PAGE = 10 -local DEFAULT_LOG_LEVEL = log.debug +local DEFAULT_LOG_LEVEL = log.error local LUA_DIR = dt.configuration.config_dir .. PS .. "lua" local LUA_SCRIPT_REPO = "https://github.com/darktable-org/lua-scripts.git" @@ -210,7 +210,7 @@ end local function get_current_repo_branch(repo_data) local branch = nil branch = string.match(repo_data, "On branch (.-)\n") - log.msg(log.info, "\ncurrent rep0 branch is " .. branch) + log.msg(log.info, "\ncurrent repo branch is " .. branch) return branch end @@ -880,7 +880,7 @@ if sm.executables.git and clean and checkout_repo_branch(repo, "master") end end - elseif #branches >0 and LUA_API_VER > branches[#branches] then + elseif #branches > 0 and LUA_API_VER > branches[#branches] then log.msg(log.info, "no newer branches, staying on master") -- stay on master else From 53f15ba8b8664e3e8077f2713f34af5b54924317 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Fri, 2 Jul 2021 21:51:20 -0400 Subject: [PATCH 176/445] [color_profile_manager] created color_profile_manager to manage the darktable input and output color profiles --- contrib/color_profile_manager.lua | 372 ++++++++++++++++++++++++++++++ 1 file changed, 372 insertions(+) create mode 100644 contrib/color_profile_manager.lua diff --git a/contrib/color_profile_manager.lua b/contrib/color_profile_manager.lua new file mode 100644 index 00000000..bd097558 --- /dev/null +++ b/contrib/color_profile_manager.lua @@ -0,0 +1,372 @@ +--[[ + + color_profile_manager.lua - manage external darktable color profiles + + Copyright (C) 2021 Bill Ferguson . + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +]] +--[[ + color_profile_manager - manage external darktable color profiles + + This script provides a tool to manage input and output external color + profiles used by darktable. Color profiles can be added or removed + to/from the correct directories so that darktable can find and use + them. + + ADDITIONAL SOFTWARE NEEDED FOR THIS SCRIPT + * None + + USAGE + * require this script from your main lua file + * select the input or output set of color profiles + * a list of profiles is displayed. Click the check box beside the + profile name to select it for removal. Click the "remove profile" + button to remove the profile. + * use the file selector to select a color profile to add to the currently + selected set (input or output) + * click the "add profile" button to add the profile to the selected set + + BUGS, COMMENTS, SUGGESTIONS + * Send to Bill Ferguson, wpferguson@gmail.com or raise an issue on + https://github.com/dakrtable-org/lua-scripts +]] +local dt = require "darktable" +local du = require "lib/dtutils" +local df = require "lib/dtutils.file" + +du.check_min_api_version("7.0.0", "color_profile_manager") + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- L O C A L I Z A T I O N +-- - - - - - - - - - - - - - - - - - - - - - - - + +local gettext = dt.gettext + +-- Tell gettext where to find the .mo file translating messages for a particular domain +gettext.bindtextdomain("color_profile_manager", dt.configuration.config_dir .. "/lua/locale/") + +local function _(msgid) + return gettext.dgettext("color_profile_manager", msgid) +end + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- C O N S T A N T S +-- - - - - - - - - - - - - - - - - - - - - - - - + +local MODULE_NAME = "color_profile_manager" +local PS = dt.configuration.running_os == "windows" and "\\" or "/" +local CS = dt.configuration.running_os == "windows" and "&" or ";" +local DIR_CMD = dt.configuration.running_os == "windows" and "dir /b" or "ls" +local COLOR_IN_DIR = dt.configuration.config_dir .. PS .. "color" .. PS .. "in" +local COLOR_OUT_DIR = dt.configuration.config_dir .. PS .. "color" .. PS .. "out" + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- N A M E S P A C E +-- - - - - - - - - - - - - - - - - - - - - - - - + +local cpm = {} +cpm.widgets = {} +cpm.widgets.profile_box = dt.new_widget("box"){ + orientation = "vertical", +} +cpm.module_installed = false +cpm.event_registered = false +-- - - - - - - - - - - - - - - - - - - - - - - - +-- F U N C T I O N S +-- - - - - - - - - - - - - - - - - - - - - - - - + +local function check_for_directories() + if not df.test_file(COLOR_IN_DIR, "d") then + dt.print_log("didn't find " .. COLOR_IN_DIR) + return false + elseif not df.test_file(COLOR_OUT_DIR, "d") then + dt.print_log("didn't find " .. COLOR_OUT_DIR) + return false + else + dt.print_log("both directories exist") + return true + end +end + +local function add_directories() + df.mkdir(COLOR_IN_DIR) + df.mkdir(COLOR_OUT_DIR) +end + +local function list_profiles(dir) + local files = {} + local p = io.popen(DIR_CMD .. " " .. dir) + if p then + for line in p:lines() do + table.insert(files, line) + end + end + p:close() + return files +end + +local function add_profile(file, dir) + df.file_copy(file, dir) + dt.print(_("added color profile " .. file .. " to " .. dir)) + dt.print_log("color profile " .. file .. " added to " .. dir) +end + +local function remove_profile(file, dir) + os.remove(dir .. PS .. file) + dt.print(_("removed color profile " .. file .. " from " .. dir)) + dt.print_log("color profile " .. file .. " removed from " .. dir) +end + +local function clear_profile_box() + for i = #cpm.widgets.profile_box, 1, -1 do + cpm.widgets.profile_box[i] = nil + end +end + +local function add_profile_callback() + local profile_dir = COLOR_IN_DIR + if cpm.widgets.profile_set.selected == 2 then + profile_dir = COLOR_OUT_DIR + end + + local new_profile = cpm.widgets.profile_selector.value + if string.lower(df.get_filetype(new_profile)) ~= "icm" and string.lower(df.get_filetype(new_profile)) ~= "icc" then + dt.print(_("ERROR: color profile must be an icc or icm file")) + dt.print_error(new_profile .. " selected and isn't an icc or icm file") + return + end + + -- set selector value to directory that new profile came from + -- in case there are more + cpm.widgets.profile_selector.value = df.get_path(cpm.widgets.profile_selector.value) + add_profile(new_profile, profile_dir) + local files = list_profiles(profile_dir) + local widgets = {} + + local profile_ptr = 1 + for i, file in ipairs(files) do + if #cpm.widgets.profile_box == 0 or cpm.widgets.profile_box[profile_ptr].label ~= file then + table.insert(widgets, dt.new_widget("check_button"){value = false, label = file}) + else + table.insert(widgets, cpm.widgets.profile_box[profile_ptr]) + profile_ptr = profile_ptr + 1 + if profile_ptr > #cpm.widgets.profile_box then + profile_ptr = #cpm.widgets.profile_box + end + end + end + clear_profile_box() + for _, widget in ipairs(widgets) do + table.insert(cpm.widgets.profile_box, widget) + end + if not cpm.widgets.remove_box.visible then + cpm.widgets.remove_box.visible = true + end +end + +local function remove_profile_callback() + local widgets_to_keep = {} + local profile_dir = COLOR_IN_DIR + if cpm.widgets.profile_set.selected == 2 then + profile_dir = COLOR_OUT_DIR + end + + for _, widget in ipairs(cpm.widgets.profile_box) do + if widget.value == true then + remove_profile(widget.label, profile_dir) + else + table.insert(widgets_to_keep, widget) + end + end + clear_profile_box() + for _, widget in ipairs(widgets_to_keep) do + table.insert(cpm.widgets.profile_box, widget) + end + if #cpm.widgets.profile_box == 0 then + cpm.widgets.remove_box.visible = false + else + cpm.widgets.remove_box.visible = true + end +end + +local function list_profile_callback(choice) + local list_dir = COLOR_IN_DIR + if choice == 2 then + list_dir = COLOR_OUT_DIR + end + + local files = list_profiles(list_dir) + + if #files == 0 then + cpm.widgets.remove_box.visible = false + else + cpm.widgets.remove_box.visible = true + end + + clear_profile_box() + + for i, file in ipairs(files) do + cpm.widgets.profile_box[i] = dt.new_widget("check_button"){value = false, label = file} + end +end + +local function install_module() + if not cpm.module_installed then + dt.register_lib( + MODULE_NAME, -- Module name + _("color profile manager"), -- Visible name + true, -- expandable + false, -- resetable + {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_LEFT_CENTER", 0}}, -- containers + cpm.widgets.main_widget, + nil,-- view_enter + nil -- view_leave + ) + cpm.module_installed = true + dt.control.sleep(500) + if not cpm.initialized then + cpm.widgets.profile_set.visible = false + cpm.widgets.add_box.visible = false + cpm.widgets.remove_box.visible = false + else + cpm.widgets.profile_set.selected = 1 + end + end +end + +local function destroy() + dt.gui.libs[MODULE_NAME].visible = false + return +end + +local function restart() + dt.gui.libs[MODULE_NAME].visible = true + return +end +-- - - - - - - - - - - - - - - - - - - - - - - - +-- W I D G E T S +-- - - - - - - - - - - - - - - - - - - - - - - - + +cpm.initialized = check_for_directories() +dt.print_log("cpm.initialized is " .. tostring(cpm.initialized)) + +if not cpm.initialized then + dt.print_log("creating init_box") + cpm.widgets.init_box = dt.new_widget("box"){ + orientation = "vertical", + dt.new_widget("button"){ + label = _("initialize color profiles"), + tooltip = _("create the directory structure to contain the color profiles"), + clicked_callback = function(this) + add_directories() + cpm.initialized = true + cpm.widgets.profile_set.visible = true + cpm.widgets.add_box.visible = true + cpm.widgets.remove_box.visible = false + cpm.widgets.init_box.visible = false + cpm.widgets.profile_set.selected = 1 + end + } + } +end + +cpm.widgets.profile_set = dt.new_widget("combobox"){ + label = _("select profile set"), + tooltip = _("select input or output profiles"), + visible = cpm.initialized and false or true, + changed_callback = function(this) + if cpm.initialized then + list_profile_callback(this.selected) + end + end, + _("input"), _("output"), +} + +cpm.widgets.profile_selector = dt.new_widget("file_chooser_button"){ + title = _("select color profile to add"), + tooltip = _("select the .icc or .icm file to add"), + is_directory = false +} + +cpm.widgets.add_box = dt.new_widget("box"){ + orientation = "vertical", + visible = cpm.initialized and true or false, + dt.new_widget("section_label"){label = _("add profile")}, + cpm.widgets.profile_selector, + dt.new_widget("button"){ + label = _("add selected color profile"), + tooltip = _("add selected file to profiles"), + clicked_callback = function(this) + add_profile_callback() + end + } +} + +cpm.widgets.remove_box = dt.new_widget("box"){ + orientation = "vertical", + visible = cpm.initialized and true or false, + dt.new_widget("section_label"){label = _("remove profile")}, + cpm.widgets.profile_box, + dt.new_widget("button"){ + label = _("remove selected profile(s)"), + tooltip = _("remove the checked profile(s)"), + clicked_callback = function(this) + remove_profile_callback() + end + } +} + +local main_widgets = {} + +if not cpm.initialized then + table.insert(main_widgets, cpm.widgets.init_box) +end +table.insert(main_widgets, cpm.widgets.profile_set) +table.insert(main_widgets, cpm.widgets.remove_box) +table.insert(main_widgets, cpm.widgets.add_box) + +cpm.widgets.main_widget = dt.new_widget("box"){ + orientation = "vertical", + table.unpack(main_widgets) +} + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- M A I N +-- - - - - - - - - - - - - - - - - - - - - - - - + +if dt.gui.current_view().id == "lighttable" then + install_module() +else + if not cpm.event_registered then + dt.register_event( + MODULE_NAME, "view-changed", + function(event, old_view, new_view) + if new_view.name == "lighttable" and old_view.name == "darkroom" then + install_module() + end + end + ) + cpm.event_registered = true + end +end + +local script_data = {} + +script_data.destroy = destroy +script_data.restart = restart +script_data.destroy_method = "hide" +script_data.show = restart + +return script_data \ No newline at end of file From 9a3eb7bc3ec1cd2fa141e91f56c0d1b46294f17f Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Mon, 5 Jul 2021 15:13:56 -0400 Subject: [PATCH 177/445] [script_manager] added check for nil current branch and dumped repo_data --- tools/script_manager.lua | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tools/script_manager.lua b/tools/script_manager.lua index cf764147..d2e23675 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -210,7 +210,11 @@ end local function get_current_repo_branch(repo_data) local branch = nil branch = string.match(repo_data, "On branch (.-)\n") - log.msg(log.info, "\ncurrent repo branch is " .. branch) + if not branch then + log.msg(log.error, "no branch detected in repo_data\nrepo_data:\n" .. repo_data) + else + log.msg(log.info, "\ncurrent repo branch is " .. branch) + end return branch end From 53d9a42a1a59ab6d55b1b5b7c95c6b15e08288f7 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Mon, 5 Jul 2021 22:49:39 -0400 Subject: [PATCH 178/445] [script_manager] modified git interface to not rely on locale --- tools/script_manager.lua | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/tools/script_manager.lua b/tools/script_manager.lua index d2e23675..98f5bb84 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -87,7 +87,7 @@ local MIN_BUTTONS_PER_PAGE = 5 local MAX_BUTTONS_PER_PAGE = 20 local DEFAULT_BUTTONS_PER_PAGE = 10 -local DEFAULT_LOG_LEVEL = log.error +local DEFAULT_LOG_LEVEL = log.debug local LUA_DIR = dt.configuration.config_dir .. PS .. "lua" local LUA_SCRIPT_REPO = "https://github.com/darktable-org/lua-scripts.git" @@ -207,11 +207,16 @@ local function get_repo_status(repo) return nil end -local function get_current_repo_branch(repo_data) +local function get_current_repo_branch(repo) local branch = nil - branch = string.match(repo_data, "On branch (.-)\n") + local p = io.popen("cd " .. repo .. CS .. "git branch") + if p then + local data = p:read("*a") + p:close() + branch = string.match(data, "\n%* (.-)\n") + end if not branch then - log.msg(log.error, "no branch detected in repo_data\nrepo_data:\n" .. repo_data) + log.msg(log.error, "no current branch detected in repo_data") else log.msg(log.info, "\ncurrent repo branch is " .. branch) end @@ -240,12 +245,12 @@ end local function is_repo_clean(repo_data) - if string.match(repo_data, "working tree clean") then - log.msg(log.info, "repo is clean") - return true - else + if string.match(repo_data, "\n%s-%a.-%a:%s-%g-\n") then log.msg(log.info, "repo is dirty") return false + else + log.msg(log.info, "repo is clean") + return true end end @@ -848,7 +853,7 @@ end -- M A I N P R O G R A M -- - - - - - - - - - - - - - - - - - - - - - - - local repo_data = get_repo_status(LUA_DIR) -local current_branch = get_current_repo_branch(repo_data) +local current_branch = get_current_repo_branch(LUA_DIR) local clean = is_repo_clean(repo_data) local repo = LUA_DIR From 97f4c911edf27d01ed079c47fb879eb9c804170d Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Mon, 5 Jul 2021 22:55:30 -0400 Subject: [PATCH 179/445] [script_manager] modified dirty repo test --- tools/script_manager.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/script_manager.lua b/tools/script_manager.lua index 98f5bb84..ba2d72c6 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -245,7 +245,7 @@ end local function is_repo_clean(repo_data) - if string.match(repo_data, "\n%s-%a.-%a:%s-%g-\n") then + if string.match(repo_data, "\n%s-%a.-%a:%s-%a%g-\n") then log.msg(log.info, "repo is dirty") return false else From 2bc23a14468694df252ccc39e71bc8a784217060 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Mon, 5 Jul 2021 23:01:30 -0400 Subject: [PATCH 180/445] [script_manager] fixed log message and reset log level for production --- tools/script_manager.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/script_manager.lua b/tools/script_manager.lua index ba2d72c6..ee53aa31 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -87,7 +87,7 @@ local MIN_BUTTONS_PER_PAGE = 5 local MAX_BUTTONS_PER_PAGE = 20 local DEFAULT_BUTTONS_PER_PAGE = 10 -local DEFAULT_LOG_LEVEL = log.debug +local DEFAULT_LOG_LEVEL = log.error local LUA_DIR = dt.configuration.config_dir .. PS .. "lua" local LUA_SCRIPT_REPO = "https://github.com/darktable-org/lua-scripts.git" @@ -218,7 +218,7 @@ local function get_current_repo_branch(repo) if not branch then log.msg(log.error, "no current branch detected in repo_data") else - log.msg(log.info, "\ncurrent repo branch is " .. branch) + log.msg(log.info, "current repo branch is " .. branch) end return branch end From c1fbfd80d4c1dd83ba43a10bbae07982bfb7f610 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Mon, 5 Jul 2021 23:24:19 -0400 Subject: [PATCH 181/445] [script_manager] fix current branch not detected --- tools/script_manager.lua | 98 ++++++++++++++++++++-------------------- 1 file changed, 50 insertions(+), 48 deletions(-) diff --git a/tools/script_manager.lua b/tools/script_manager.lua index ee53aa31..ab87b830 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -209,7 +209,7 @@ end local function get_current_repo_branch(repo) local branch = nil - local p = io.popen("cd " .. repo .. CS .. "git branch") + local p = io.popen("cd " .. repo .. CS .. "git branch --all") if p then local data = p:read("*a") p:close() @@ -857,56 +857,58 @@ local current_branch = get_current_repo_branch(LUA_DIR) local clean = is_repo_clean(repo_data) local repo = LUA_DIR -if sm.executables.git and clean and - (current_branch == "master" or string.match(current_branch, "^API%-")) then -- only make changes to clean branches - local branches = get_repo_branches(LUA_DIR) - if current_branch ~= LUA_API_VER and current_branch ~= "master" then - -- probably upgraded from an earlier api version so get back to master - -- to use the latest version of script_manager to get the proper API - checkout_repo_branch(repo, "master") - log.msg(log.screen, "lua API version reset, please restart darktable") - elseif LUA_API_VER == current_branch then - -- do nothing, we are fine - log.msg(log.debug, "took equal branch, doing nothing") - elseif string.match(LUA_API_VER, "dev") then - -- we are on a dev API version, so checkout the dev - -- api version or checkout/stay on master - log.msg(log.debug, "took the dev branch") - local match = false - for _, branch in ipairs(branches) do - log.msg(log.debug, "checking branch " .. branch .. " against API " .. LUA_API_VER) - if LUA_API_VER == branch then - match = true - log.msg(log.info, "checking out repo development branch " .. branch) - checkout_repo_branch(repo, branch) +if current_branch then + if sm.executables.git and clean and + (current_branch == "master" or string.match(current_branch, "^API%-")) then -- only make changes to clean branches + local branches = get_repo_branches(LUA_DIR) + if current_branch ~= LUA_API_VER and current_branch ~= "master" then + -- probably upgraded from an earlier api version so get back to master + -- to use the latest version of script_manager to get the proper API + checkout_repo_branch(repo, "master") + log.msg(log.screen, "lua API version reset, please restart darktable") + elseif LUA_API_VER == current_branch then + -- do nothing, we are fine + log.msg(log.debug, "took equal branch, doing nothing") + elseif string.match(LUA_API_VER, "dev") then + -- we are on a dev API version, so checkout the dev + -- api version or checkout/stay on master + log.msg(log.debug, "took the dev branch") + local match = false + for _, branch in ipairs(branches) do + log.msg(log.debug, "checking branch " .. branch .. " against API " .. LUA_API_VER) + if LUA_API_VER == branch then + match = true + log.msg(log.info, "checking out repo development branch " .. branch) + checkout_repo_branch(repo, branch) + end end - end - if not match then - if current_branch == "master" then - log.msg(log.info, "staying on master, no dev branch yet") - else - log.msg(log.info, "no dev branch available, checking out master") - checkout_repo_branch(repo, "master") + if not match then + if current_branch == "master" then + log.msg(log.info, "staying on master, no dev branch yet") + else + log.msg(log.info, "no dev branch available, checking out master") + checkout_repo_branch(repo, "master") + end end - end - elseif #branches > 0 and LUA_API_VER > branches[#branches] then - log.msg(log.info, "no newer branches, staying on master") - -- stay on master - else - -- checkout the appropriate branch for API version if it exists - log.msg(log.info, "checking out the appropriate API branch") - local match = false - for _, branch in ipairs(branches) do - log.msg(log.debug, "checking branch " .. branch .. " against API " .. LUA_API_VER) - if LUA_API_VER == branch then - match = true - log.msg(log.info, "checking out repo branch " .. branch) - checkout_repo_branch(repo, branch) - log.msg(log.screen, "you must restart darktable to use the correct version of the lua") + elseif #branches > 0 and LUA_API_VER > branches[#branches] then + log.msg(log.info, "no newer branches, staying on master") + -- stay on master + else + -- checkout the appropriate branch for API version if it exists + log.msg(log.info, "checking out the appropriate API branch") + local match = false + for _, branch in ipairs(branches) do + log.msg(log.debug, "checking branch " .. branch .. " against API " .. LUA_API_VER) + if LUA_API_VER == branch then + match = true + log.msg(log.info, "checking out repo branch " .. branch) + checkout_repo_branch(repo, branch) + log.msg(log.screen, "you must restart darktable to use the correct version of the lua") + end + end + if not match then + log.msg(log.warn, "no matching branch found for " .. LUA_API_VER) end - end - if not match then - log.msg(log.warn, "no matching branch found for " .. LUA_API_VER) end end end From 6af180a313897c96cecd2f25d18854c754b78452 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Tue, 6 Jul 2021 00:42:55 -0400 Subject: [PATCH 182/445] [script_manager] after numerous attempts to solve this with just pattern matching I realized the lack of conditionals made it impossible to solve in that manner, so I resorted to splitting the output into lines and testing each line. --- tools/script_manager.lua | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/tools/script_manager.lua b/tools/script_manager.lua index ee53aa31..eb94a802 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -87,7 +87,7 @@ local MIN_BUTTONS_PER_PAGE = 5 local MAX_BUTTONS_PER_PAGE = 20 local DEFAULT_BUTTONS_PER_PAGE = 10 -local DEFAULT_LOG_LEVEL = log.error +local DEFAULT_LOG_LEVEL = log.debug local LUA_DIR = dt.configuration.config_dir .. PS .. "lua" local LUA_SCRIPT_REPO = "https://github.com/darktable-org/lua-scripts.git" @@ -213,14 +213,20 @@ local function get_current_repo_branch(repo) if p then local data = p:read("*a") p:close() - branch = string.match(data, "\n%* (.-)\n") + local branches = du.split(data, "\n") + for _, b in ipairs(branches) do + log.msg(log.debug, "branch for testing is " .. b) + branch = string.match(b, "^%* (.-)$") + if branch then + log.msg(log.info, "current repo branch is " .. branch) + return branch + end + end end if not branch then log.msg(log.error, "no current branch detected in repo_data") - else - log.msg(log.info, "current repo branch is " .. branch) end - return branch + return nil end local function get_repo_branches(repo) From a6d5001e84583110c8415b14d42ce1457d993e15 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Tue, 6 Jul 2021 00:46:21 -0400 Subject: [PATCH 183/445] [script_manager] set logging to error --- tools/script_manager.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/script_manager.lua b/tools/script_manager.lua index eb94a802..979ecba0 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -87,7 +87,7 @@ local MIN_BUTTONS_PER_PAGE = 5 local MAX_BUTTONS_PER_PAGE = 20 local DEFAULT_BUTTONS_PER_PAGE = 10 -local DEFAULT_LOG_LEVEL = log.debug +local DEFAULT_LOG_LEVEL = log.error local LUA_DIR = dt.configuration.config_dir .. PS .. "lua" local LUA_SCRIPT_REPO = "https://github.com/darktable-org/lua-scripts.git" From 4cbb7724f20776be6704d7b86dc7347804229381 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Wed, 14 Jul 2021 11:44:27 -0400 Subject: [PATCH 184/445] [script_manager] updated register_event syntax to API 7.0.0 --- tools/script_manager.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/script_manager.lua b/tools/script_manager.lua index 41181ca1..eb2db044 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -1145,7 +1145,7 @@ if dt.gui.current_view().id == "lighttable" then else if not sm.event_registered then dt.register_event( - "view-changed", + "script_manager", "view-changed", function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() From 3cf0fea092e7aa63aaa8350d0829ffa488e445aa Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Wed, 28 Jul 2021 01:18:51 -0400 Subject: [PATCH 185/445] [contrib/rename] Rename files including moving them into new or other film rolls. --- contrib/rename.lua | 315 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 315 insertions(+) create mode 100644 contrib/rename.lua diff --git a/contrib/rename.lua b/contrib/rename.lua new file mode 100644 index 00000000..bc83d7b1 --- /dev/null +++ b/contrib/rename.lua @@ -0,0 +1,315 @@ +--[[ + + rename.lua - rename image file(s) + + Copyright (C) 2020, 2021 Bill Ferguson . + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +]] +--[[ + rename - rename an image file or files + + This shortcut resets the GPS information to that contained within + the image file. If no GPS info is in the image file, the GPS data + is cleared. + + USAGE + * require this script from your luarc file or start it from script_manager + * select an image or images + * enter a renaming pattern + * click the button to rename the files + + BUGS, COMMENTS, SUGGESTIONS + * Send to Bill Ferguson, wpferguson@gmail.com + + CHANGES + + TODO + * Add pattern builder + * Add new name preview +]] + +local dt = require "darktable" +local du = require "lib/dtutils" +local df = require "lib/dtutils.file" + +du.check_min_api_version("7.0.0", "rename") + +local gettext = dt.gettext + +-- Tell gettext where to find the .mo file translating messages for a particular domain +gettext.bindtextdomain("rename",dt.configuration.config_dir.."/lua/locale/") + +local function _(msgid) + return gettext.dgettext("rename", msgid) +end + +-- namespace variable +local rename = { + presets = {}, + substitutes = {}, + placeholders = {"ROLL_NAME","FILE_FOLDER","FILE_NAME","FILE_EXTENSION","ID","VERSION","SEQUENCE","YEAR","MONTH","DAY", + "HOUR","MINUTE","SECOND","EXIF_YEAR","EXIF_MONTH","EXIF_DAY","EXIF_HOUR","EXIF_MINUTE","EXIF_SECOND", + "STARS","LABELS","MAKER","MODEL","TITLE","CREATOR","PUBLISHER","RIGHTS","USERNAME","PICTURES_FOLDER", + "HOME","DESKTOP","EXIF_ISO","EXIF_EXPOSURE","EXIF_EXPOSURE_BIAS","EXIF_APERTURE","EXIF_FOCUS_DISTANCE", + "EXIF_FOCAL_LENGTH","LONGITUDE","LATITUDE","ELEVATION","LENS","DESCRIPTION","EXIF_CROP"}, + widgets = {}, +} +rename.module_installed = false +rename.event_registered = false + +-- script_manager integration +local script_data = {} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again + + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- C O N S T A N T S +-- - - - - - - - - - - - - - - - - - - - - - - - + +local MODULE_NAME = "rename" +local PS = dt.configuration.running_os == "windows" and "\\" or "/" +local USER = os.getenv("USERNAME") +local HOME = os.getenv(dt.configuration.running_os == "windows" and "HOMEPATH" or "HOME") +local PICTURES = HOME .. PS .. dt.configuration.running_os == "windows" and "My Pictures" or "Pictures" +local DESKTOP = HOME .. PS .. "Desktop" + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- F U N C T I O N S +-- - - - - - - - - - - - - - - - - - - - - - - - + +local function build_substitution_list(image, sequence, datetime, username, pic_folder, home, desktop) + -- build the argument substitution list from each image + -- local datetime = os.date("*t") + local colorlabels = {} + if image.red then table.insert(colorlabels, "red") end + if image.yellow then table.insert(colorlabels, "yellow") end + if image.green then table.insert(colorlabels, "green") end + if image.blue then table.insert(colorlabels, "blue") end + if image.purple then table.insert(colorlabels, "purple") end + local labels = #colorlabels == 1 and colorlabels[1] or du.join(colorlabels, ",") + local eyear,emon,eday,ehour,emin,esec = string.match(image.exif_datetime_taken, "(%d-):(%d-):(%d-) (%d-):(%d-):(%d-)$") + local replacements = {image.film,image.path,df.get_filename(image.filename),string.upper(df.get_filetype(image.filename)),image.id,image.duplicate_index, + sequence,datetime.year,string.format("%02d", datetime.month),string.format("%02d", datetime.day),string.format("%02d", datetime.hour), + string.format("%02d", datetime.min),string.format("%02d", datetime.sec),eyear,emon,eday,ehour,emin,esec,image.rating,labels, + image.exif_maker,image.exif_model,image.title,image.creator,image.publisher,image.rights,username,pic_folder,home,desktop, + image.exif_iso,image.exif_exposure,image.exif_exposure_bias,image.exif_aperture,image.exif_focus_distance,image.exif_focal_length, + image.longitude,image.latitude,image.elevation,image.exif_lens,image.description,image.exif_crop} + + for i=1,#rename.placeholders,1 do rename.substitutes[rename.placeholders[i]] = replacements[i] end +end + +local function substitute_list(str) + -- replace the substitution variables in a string + for match in string.gmatch(str, "%$%(.-%)") do + local var = string.match(match, "%$%((.-)%)") + if rename.substitutes[var] then + str = string.gsub(str, "%$%("..var.."%)", rename.substitutes[var]) + else + dt.print_error(_("unrecognized variable " .. var)) + dt.print(_("unknown variable " .. var .. ", aborting...")) + return -1 + end + end + return str +end + +local function clear_substitute_list() + for i=1,#rename.placeholders,1 do rename.substitutes[rename.placeholders[i]] = nil end +end + +local function stop_job(job) + job.valid = false +end + +local function install_module() + if not rename.module_installed then + dt.register_lib( + _("rename"), + ("rename"), + true, + true, + {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER",700}}, + dt.new_widget("box"){ + orientation = "vertical", + rename.widgets.pattern, + rename.widgets.button, + }, + nil, + nil + ) + rename.module_installed = true + end +end + +local function destroy() + dt.gui.libs["rename"].visible = false +end + +local function restart() + dt.gui.libs["rename"].visible = true +end + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- M A I N +-- - - - - - - - - - - - - - - - - - - - - - - - + +local function do_rename(images) + if #images > 0 then + local pattern = rename.widgets.pattern.text + dt.preferences.write(MODULE_NAME, "pattern", "string", pattern) + dt.print_log(_("pattern is " .. pattern)) + if string.len(pattern) > 0 then + local datetime = os.date("*t") + + local job = dt.gui.create_job(_("renaming images"), true, stop_job) + for i, image in ipairs(images) do + if job.valid then + job.percent = i / #images + build_substitution_list(image, i, datetime, USER, PICTURES, HOME, DESKTOP) + local new_name = substitute_list(pattern) + if new_name == -1 then + dt.print(_("unable to do variable substitution, exiting...")) + stop_job(job) + return + end + clear_substitute_list() + local args = {} + local path = string.sub(df.get_path(new_name), 1, -2) + if string.len(path) == 0 then + path = image.path + end + local filename = df.get_filename(new_name) + local filmname = image.path + if path ~= image.path then + if not df.check_if_file_exists(df.sanitize_filename(path)) then + df.mkdir(df.sanitize_filename(path)) + end + filmname = path + end + args[1] = dt.films.new(filmname) + args[2] = image + if filename ~= image.filename then + args[3] = filename + end + dt.database.move_image(table.unpack(args)) + end + end + stop_job(job) + local collect_rules = dt.gui.libs.collect.filter() + dt.gui.libs.collect.filter(collect_rules) + dt.print(_("renamed " .. #images .. " images")) + else -- pattern length + dt.print_error("no pattern supplied, returning...") + dt.print(_("please enter the new name or pattern")) + end + else -- image count + dt.print_error("no images selected, returning...") + dt.print(_("please select some images and try again")) + end +end + +local function reset_callback() + rename.widgets.pattern.text = "" +end + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- W I D G E T S +-- - - - - - - - - - - - - - - - - - - - - - - - + +rename.widgets.pattern = dt.new_widget("entry"){ + tooltip = _("$(ROLL_NAME) - film roll name\n") .. + _("$(FILE_FOLDER) - image file folder\n") .. + _("$(FILE_NAME) - image file name\n") .. + _("$(FILE_EXTENSION) - image file extension\n") .. + _("$(ID) - image id\n") .. + _("$(VERSION) - version number\n") .. + _("$(SEQUENCE) - sequence number of selection\n") .. + _("$(YEAR) - current year\n") .. + _("$(MONTH) - current month\n") .. + _("$(DAY) - current day\n") .. + _("$(HOUR) - current hour\n") .. + _("$(MINUTE) - current minute\n") .. + _("$(SECOND) - current second\n") .. + _("$(EXIF_YEAR) - EXIF year\n") .. + _("$(EXIF_MONTH) - EXIF month\n") .. + _("$(EXIF_DAY) - EXIF day\n") .. + _("$(EXIF_HOUR) - EXIF hour\n") .. + _("$(EXIF_MINUTE) - EXIF minute\n") .. + _("$(EXIF_SECOND) - EXIF seconds\n") .. + _("$(EXIF_ISO) - EXIF ISO\n") .. + _("$(EXIF_EXPOSURE) - EXIF exposure\n") .. + _("$(EXIF_EXPOSURE_BIAS) - EXIF exposure bias\n") .. + _("$(EXIF_APERTURE) - EXIF aperture\n") .. + _("$(EXIF_FOCAL_LENGTH) - EXIF focal length\n") .. + _("$(EXIF_FOCUS_DISTANCE) - EXIF focus distance\n") .. + _("$(EXIF_CROP) - EXIF crop\n") .. + _("$(LONGITUDE) - longitude\n") .. + _("$(LATITUDE) - latitude\n") .. + _("$(ELEVATION) - elevation\n") .. + _("$(STARS) - star rating\n") .. + _("$(LABELS) - color labels\n") .. + _("$(MAKER) - camera maker\n") .. + _("$(MODEL) - camera model\n") .. + _("$(LENS) - lens\n") .. + _("$(TITLE) - title from metadata\n") .. + _("$(DESCRIPTION) - description from metadata\n") .. + _("$(CREATOR) - creator from metadata\n") .. + _("$(PUBLISHER) - publisher from metadata\n") .. + _("$(RIGHTS) - rights from metadata\n") .. + _("$(USERNAME) - username\n") .. + _("$(PICTURES_FOLDER) - pictures folder\n") .. + _("$(HOME) - user's home directory\n") .. + _("$(DESKTOP) - desktop directory"), + placeholder = _("enter pattern $(FILE_FOLDER)/$(FILE_NAME)"), + text = "" +} + +local pattern_pref = dt.preferences.read(MODULE_NAME, "pattern", "string") +if pattern_pref then + rename.widgets.pattern.text = pattern_pref +end + +rename.widgets.button = dt.new_widget("button"){ + label = _("rename"), + clicked_callback = function(this) + do_rename(dt.gui.action_images) + end +} + +if dt.gui.current_view().id == "lighttable" then + install_module() +else + if not rename.event_registered then + dt.register_event( + "rename", "view-changed", + function(event, old_view, new_view) + if new_view.name == "lighttable" and old_view.name == "darkroom" then + install_module() + end + end + ) + rename.event_registered = true + end +end + +script_data.destroy = destroy +script_data.restart = restart +script_data.destroy_method = "hide" +script_data.show = restart + +return script_data From 4bdaaaf1ce160b27491e81868e025486fa14515a Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Mon, 2 Aug 2021 23:26:22 -0400 Subject: [PATCH 186/445] renamed rename to rename_images to better reflect the purpose --- contrib/{rename.lua => rename_images.lua} | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) rename contrib/{rename.lua => rename_images.lua} (97%) diff --git a/contrib/rename.lua b/contrib/rename_images.lua similarity index 97% rename from contrib/rename.lua rename to contrib/rename_images.lua index bc83d7b1..1e11c6d9 100644 --- a/contrib/rename.lua +++ b/contrib/rename_images.lua @@ -44,7 +44,7 @@ local dt = require "darktable" local du = require "lib/dtutils" local df = require "lib/dtutils.file" -du.check_min_api_version("7.0.0", "rename") +du.check_min_api_version("7.0.0", "rename_images") local gettext = dt.gettext @@ -52,7 +52,7 @@ local gettext = dt.gettext gettext.bindtextdomain("rename",dt.configuration.config_dir.."/lua/locale/") local function _(msgid) - return gettext.dgettext("rename", msgid) + return gettext.dgettext("rename_images", msgid) end -- namespace variable @@ -81,7 +81,7 @@ script_data.restart = nil -- how to restart the (lib) script after it's been hid -- C O N S T A N T S -- - - - - - - - - - - - - - - - - - - - - - - - -local MODULE_NAME = "rename" +local MODULE_NAME = "rename_images" local PS = dt.configuration.running_os == "windows" and "\\" or "/" local USER = os.getenv("USERNAME") local HOME = os.getenv(dt.configuration.running_os == "windows" and "HOMEPATH" or "HOME") @@ -139,8 +139,8 @@ end local function install_module() if not rename.module_installed then dt.register_lib( - _("rename"), - ("rename"), + _("rename images"), + ("rename_images"), true, true, {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER",700}}, @@ -157,11 +157,11 @@ local function install_module() end local function destroy() - dt.gui.libs["rename"].visible = false + dt.gui.libs["rename_images"].visible = false end local function restart() - dt.gui.libs["rename"].visible = true + dt.gui.libs["rename_images"].visible = true end -- - - - - - - - - - - - - - - - - - - - - - - - @@ -296,7 +296,7 @@ if dt.gui.current_view().id == "lighttable" then else if not rename.event_registered then dt.register_event( - "rename", "view-changed", + "rename_images", "view-changed", function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() From b4ee97a768abfe3a92f400160457d9d4dbc50608 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Mon, 2 Aug 2021 23:44:05 -0400 Subject: [PATCH 187/445] got register_lib arguments in the correct order --- contrib/rename_images.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/contrib/rename_images.lua b/contrib/rename_images.lua index 1e11c6d9..4ddf78f9 100644 --- a/contrib/rename_images.lua +++ b/contrib/rename_images.lua @@ -49,7 +49,7 @@ du.check_min_api_version("7.0.0", "rename_images") local gettext = dt.gettext -- Tell gettext where to find the .mo file translating messages for a particular domain -gettext.bindtextdomain("rename",dt.configuration.config_dir.."/lua/locale/") +gettext.bindtextdomain("rename_images",dt.configuration.config_dir.."/lua/locale/") local function _(msgid) return gettext.dgettext("rename_images", msgid) @@ -139,8 +139,8 @@ end local function install_module() if not rename.module_installed then dt.register_lib( + MODULE_NAME, _("rename images"), - ("rename_images"), true, true, {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER",700}}, @@ -157,11 +157,11 @@ local function install_module() end local function destroy() - dt.gui.libs["rename_images"].visible = false + dt.gui.libs[MODULE_NAME].visible = false end local function restart() - dt.gui.libs["rename_images"].visible = true + dt.gui.libs[MODULE_NAME].visible = true end -- - - - - - - - - - - - - - - - - - - - - - - - From a0cbe8efd5d3d196d0e2102cbdc89c3748bd2938 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Wed, 4 Aug 2021 11:28:12 -0400 Subject: [PATCH 188/445] [contrib/quicktag] changed is_password to false on entry so user can see what they typed. --- contrib/quicktag.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/quicktag.lua b/contrib/quicktag.lua index db451e19..15f1d8db 100644 --- a/contrib/quicktag.lua +++ b/contrib/quicktag.lua @@ -238,7 +238,7 @@ update_quicktag_list() local new_quicktag = dt.new_widget("entry"){ text = "", placeholder = _("new tag"), - is_password = true, + is_password = false, editable = true, tooltip = _("enter your tag here") } From c4df81bdef8089a10a441007c8b09ee3f35d3909 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Thu, 5 Aug 2021 18:53:05 -0400 Subject: [PATCH 189/445] [contrib/geoToolbox] changed atan2 call to atan for lua 5.4 compatibility --- contrib/geoToolbox.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/geoToolbox.lua b/contrib/geoToolbox.lua index c43d313e..db99d26f 100644 --- a/contrib/geoToolbox.lua +++ b/contrib/geoToolbox.lua @@ -430,7 +430,7 @@ local function get_distance(lat1, lon1, ele1, lat2, lon2, ele2) math.cos(math.rad(lat1)) * math.cos(math.rad(lat2)) * math.sin(dLon/2) * math.sin(dLon/2) ; - local angle = 2 * math.atan2(math.sqrt(a), math.sqrt(1-a)); + local angle = 2 * math.atan(math.sqrt(a), math.sqrt(1-a)); local distance = earthRadius * angle; -- Distance in km -- Add the elevation to the calculation From 5209b9899d644d822d346b0eb254bb5b203a65cd Mon Sep 17 00:00:00 2001 From: chrisaga Date: Fri, 13 Aug 2021 10:06:58 +0200 Subject: [PATCH 190/445] Add french translation for photils --- locale/fr_FR/LC_MESSAGES/photils.po | 115 ++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 locale/fr_FR/LC_MESSAGES/photils.po diff --git a/locale/fr_FR/LC_MESSAGES/photils.po b/locale/fr_FR/LC_MESSAGES/photils.po new file mode 100644 index 00000000..e90295c5 --- /dev/null +++ b/locale/fr_FR/LC_MESSAGES/photils.po @@ -0,0 +1,115 @@ +msgid "" +msgstr "" +"Project-Id-Version: \n" +"POT-Creation-Date: 2021-08-13 09:04+0200\n" +"PO-Revision-Date: 2021-08-13 09:49+0200\n" +"Last-Translator: Christophe Agathon \n" +"Language-Team: \n" +"Language: fr_FR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 2.4.1\n" +"X-Poedit-Basepath: ../../../contrib\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Poedit-SearchPath-0: photils.lua\n" + +#: photils.lua:117 +msgid "get tags" +msgstr "trouver des mots-clés" + +#: photils.lua:148 +msgid "requires a restart to be applied" +msgstr "nécessite un redémarrage pour être pris en compte" + +#: photils.lua:163 +msgid "min confidence value" +msgstr "niveau de confiance minimum" + +#: photils.lua:180 +msgid "" +"The suggested tags were not generated\n" +" for the currently selected image!" +msgstr "" +"La proposition de mots-clés n'a pas été générée\n" +" pour l'image sélectionnée actuellement !" + +#: photils.lua:186 +#, lua-format +msgid " page %s of %s " +msgstr " page %s de %s " + +#: photils.lua:237 +msgid "Apply tag to image" +msgstr "Appliquer les mots-clés à l'image" + +#: photils.lua:249 +msgid "Tags successfully attached to image" +msgstr "Les mots-clés ont bien été ajoutés à l'image" + +#: photils.lua:299 +#, lua-format +msgid "%s found %d tags for your image" +msgstr "%s a trouvé %d mots-clés pour votre image" + +#: photils.lua:315 +msgid "No image selected." +msgstr "Pas d'image sélectionnée." + +#: photils.lua:319 +msgid "This plugin can only handle a single image." +msgstr "Ce plugin ne peut gérer qu'une seule image." + +#: photils.lua:326 +#, lua-format +msgid "%s failed, see terminal output for details" +msgstr "" +"%s a échoué, consultez les messages sur le terminal pour plus de détails" + +#: photils.lua:334 +#, lua-format +msgid "no tags where found" +msgstr "aucun mot-clé n'a été trouvé" + +#: photils.lua:365 +#, lua-format +msgid "attach %d tags" +msgstr "ajouter %d mots-clés" + +#: photils.lua:429 photils.lua:430 +msgid "photils-cli not found" +msgstr "photils-cli non trouvé" + +#: photils.lua:432 +msgid "" +"Select an image, click \"get tags\" and get \n" +"suggestions for tags." +msgstr "" +"Sélectionnez une image, cliquez sur « trouver des mots-clés » \n" +"pour obtenir une proposition de mots-clés." + +#: photils.lua:467 +msgid "photils: show confidence value" +msgstr "photils: afficher le niveau de confiance" + +# Original message should begin with capital I +#: photils.lua:468 +msgid "if enabled, the confidence value for each tag is displayed" +msgstr "Si activé, le niveau de confiance de chaque mot-clé est affiché" + +#: photils.lua:474 +msgid "photils: use exported image for tag request" +msgstr "photils: utiliser l'image exportée pour la recherche de mots-clés" + +#: photils.lua:475 +msgid "" +"If enabled, the image passed to photils for tag suggestion is based on the " +"exported, already edited image. Otherwise, the embedded thumbnail of the RAW " +"file will be used for tag suggestion.The embedded thumbnail could speedup " +"the tag suggestion but can fail if the RAW file is not supported." +msgstr "" +"Si activé, l'image passée à photils pour la proposition de mots-clés est " +"basée sur l'export de l'image déjà éditée. Sinon, c'est la vignette " +"encapsulée dans le fichier RAW qui sera utilisée. La vignette encapsulée " +"pourra accélérer la proposition des mots-clés mais la recherche échouera si " +"le fichier RAW n'est pas supporté." From 27d3ea253d92215643365e26f47c411a6f51030d Mon Sep 17 00:00:00 2001 From: chrisaga Date: Fri, 13 Aug 2021 10:15:38 +0200 Subject: [PATCH 191/445] Add simple file header --- locale/fr_FR/LC_MESSAGES/photils.po | 2 ++ 1 file changed, 2 insertions(+) diff --git a/locale/fr_FR/LC_MESSAGES/photils.po b/locale/fr_FR/LC_MESSAGES/photils.po index e90295c5..ceafc472 100644 --- a/locale/fr_FR/LC_MESSAGES/photils.po +++ b/locale/fr_FR/LC_MESSAGES/photils.po @@ -1,3 +1,5 @@ +# French messages for photils.lua +# Christophe Agathon , 2021 msgid "" msgstr "" "Project-Id-Version: \n" From 7f140828bbc87ed573d3329fb42d8e5218af8c52 Mon Sep 17 00:00:00 2001 From: Hubert Kowalski Date: Sat, 14 Aug 2021 13:01:00 +0200 Subject: [PATCH 192/445] add harmonic armature guide --- contrib/harmonic_armature_guide.lua | 84 +++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 contrib/harmonic_armature_guide.lua diff --git a/contrib/harmonic_armature_guide.lua b/contrib/harmonic_armature_guide.lua new file mode 100644 index 00000000..7376e005 --- /dev/null +++ b/contrib/harmonic_armature_guide.lua @@ -0,0 +1,84 @@ +--[[ + harmonic artmature guide for darktable + + copyright (c) 2021 Hubert Kowalski + + darktable is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + darktable is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with darktable. If not, see . +]] + +--[[ +HARMONIC ARMATURE GUIDE +Harmonic Armature (also known as 14 line armature) + +INSTALLATION +* copy this file in $CONFIGDIR/lua/ where CONFIGDIR is your darktable configuration directory +* add the following line in the file $CONFIGDIR/luarc + require "harmonic_armature_guide" + +USAGE +* when using guides, select "harmonic armature" as guide +]] + +local dt = require "darktable" +local du = require "lib/dtutils" +local gettext = dt.gettext + +du.check_min_api_version("2.0.0", "harmonic_armature_guide") + +-- Tell gettext where to find the .mo file translating messages for a particular domain +gettext.bindtextdomain("harmonic_armature_guide",dt.configuration.config_dir.."/lua/locale/") + +local function _(msgid) + return gettext.dgettext("harmonic_armature_guide", msgid) +end + +dt.guides.register_guide("harmonic armature", +-- draw +function(cairo, x, y, width, height, zoom_scale) + cairo:save() + + cairo:translate(x, y) + cairo:scale(width, height) + + cairo:move_to(0,0) + cairo:line_to(1, 0.5) + cairo:line_to(0.5, 1) + cairo:line_to(0,0) + cairo:line_to(1, 1) + cairo:line_to(0.5, 0) + cairo:line_to(0, 0.5) + cairo:line_to(1, 1) + + cairo:move_to(1, 0) + cairo:line_to(0, 0.5) + cairo:line_to(0.5, 1) + cairo:line_to(1, 0) + cairo:line_to(0, 1) + cairo:line_to(0.5, 0) + cairo:line_to(1, 0.5) + cairo:line_to(0, 1) + + -- middle lines - not needed for harmonic armature + -- cairo:move_to(0,0.5) + -- cairo:line_to(1,0.5) + -- cairo:move_to(0.5,0) + -- cairo:line_to(0.5,1) + + cairo:restore() +end, +-- gui +function() + return dt.new_widget("label"){label = _("harmonic armature"), halign = "start"} +end +) \ No newline at end of file From d14215105599c804e34a0a62512fd4e081078ffd Mon Sep 17 00:00:00 2001 From: Hubert Kowalski Date: Sun, 15 Aug 2021 22:43:13 +0200 Subject: [PATCH 193/445] fix lines and contrib require --- contrib/harmonic_armature_guide.lua | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/contrib/harmonic_armature_guide.lua b/contrib/harmonic_armature_guide.lua index 7376e005..e5c23f27 100644 --- a/contrib/harmonic_armature_guide.lua +++ b/contrib/harmonic_armature_guide.lua @@ -22,9 +22,9 @@ HARMONIC ARMATURE GUIDE Harmonic Armature (also known as 14 line armature) INSTALLATION -* copy this file in $CONFIGDIR/lua/ where CONFIGDIR is your darktable configuration directory +* copy this file in $CONFIGDIR/lua/contrib where CONFIGDIR is your darktable configuration directory * add the following line in the file $CONFIGDIR/luarc - require "harmonic_armature_guide" + require "contrib/harmonic_armature_guide" USAGE * when using guides, select "harmonic armature" as guide @@ -69,12 +69,6 @@ function(cairo, x, y, width, height, zoom_scale) cairo:line_to(1, 0.5) cairo:line_to(0, 1) - -- middle lines - not needed for harmonic armature - -- cairo:move_to(0,0.5) - -- cairo:line_to(1,0.5) - -- cairo:move_to(0.5,0) - -- cairo:line_to(0.5,1) - cairo:restore() end, -- gui From 1ca6b18f5e17313edc3def90b6da842a14024ee6 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Tue, 31 Aug 2021 12:31:04 -0400 Subject: [PATCH 194/445] Remove styles hiding from AutoGrouper.lua --- ChangeLog.md | 1 + contrib/AutoGrouper.lua | 5 +---- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 34d4d960..c84cc31d 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,4 +1,5 @@ ## Changes from most recent to oldest +**31 Aug 2021 - wpferguson - remove styles hiding from AutoGrouper.lua** **02 Jul 2021 - wpferguson - merged API-7.0.0-dev branch to master** * API-7.0.0 is darktable 3.6 * breaking changes diff --git a/contrib/AutoGrouper.lua b/contrib/AutoGrouper.lua index a1d449d2..58a8c1b8 100644 --- a/contrib/AutoGrouper.lua +++ b/contrib/AutoGrouper.lua @@ -41,9 +41,6 @@ local du = require "lib/dtutils" du.check_min_api_version("7.0.0", "AutoGrouper") -dt.print_log("hiding styles") -dt.gui.libs["styles"].visible = false - local MOD = 'autogrouper' -- return data structure for script_manager @@ -218,4 +215,4 @@ script_data.destroy_method = "hide" script_data.restart = restart script_data.show = restart -return script_data \ No newline at end of file +return script_data From 63763bedc80c34541f211cf5826f84468b0c9ec5 Mon Sep 17 00:00:00 2001 From: chrisaga Date: Thu, 2 Sep 2021 11:23:36 +0200 Subject: [PATCH 195/445] Minor errors in dtutils_log.libdoc.Example : error levels are log.xxxx --- lib/dtutils/log.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/dtutils/log.lua b/lib/dtutils/log.lua index 22a4b443..6910c8eb 100644 --- a/lib/dtutils/log.lua +++ b/lib/dtutils/log.lua @@ -17,11 +17,11 @@ dtutils_log.libdoc = { print out warning, error and success messages as code is running - log.log_level(debug) + log.log_level(log.debug) print out debugging messages too because this isnt working - log.log_level(info) + log.log_level(log.info) I want to make sure this is working ok From 28ae2ea5011e6b9f89cef0fe8b107c23bd0d90f4 Mon Sep 17 00:00:00 2001 From: Diederik ter Rahe Date: Sun, 12 Sep 2021 18:16:09 +0200 Subject: [PATCH 196/445] simple module to call dt_action_process --- examples/gui_action.lua | 105 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 examples/gui_action.lua diff --git a/examples/gui_action.lua b/examples/gui_action.lua new file mode 100644 index 00000000..cbf33a4a --- /dev/null +++ b/examples/gui_action.lua @@ -0,0 +1,105 @@ +local dt = require "darktable" + +local NaN = 0/0 + +local wg = {} + +wg.action = dt.new_widget("entry"){ + text = "lib/filter/view", + placeholder = "action path", + tooltip = "enter the full path of an action, for example 'lib/filter/view'" + } + +wg.instance = dt.new_widget("combobox"){ + label = "instance", + tooltip = "the instance of an image processing module to execute action on", + "0", "+1", "-1", "+2", "-2", "+3", "-3", "+4", "-4", "+5", "-5", "+6", "-6", "+7", "-7", "+8", "-8", "+9", "-9" +} + +wg.element = dt.new_widget("entry"){ + text = "", + placeholder = "action element", + tooltip = "enter the element of an action, for example 'selection', or leave empty for default" +} + +wg.effect = dt.new_widget("entry"){ + text = "next", + placeholder = "action effect", + tooltip = "enter the effect of an action, for example 'next', or leave empty for default" +} + +wg.speed = dt.new_widget("entry"){ + text = "1", + placeholder = "action speed", + tooltip = "enter the speed to use in action execution, or leave empty to only read state" +} + +wg.check = dt.new_widget("check_button"){ + label = 'perform action', + tooltip = 'perform action or only read return', + clicked_callback = function() + wg.speed.sensitive = wg.check.value + end, + value = true +} + +wg.return_value = dt.new_widget("entry"){ + text = "", + sensitive = false +} + +dt.register_lib( + "execute_action", -- Module name + "execute gui actions", -- name + true, -- expandable + false, -- resetable + {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_LEFT_CENTER", 100}, + [dt.gui.views.darkroom] = {"DT_UI_CONTAINER_PANEL_LEFT_CENTER", 100}}, + dt.new_widget("box") + { + orientation = "vertical", + + dt.new_widget("box") + { + orientation = "horizontal", + dt.new_widget("label"){label = "action path", halign = "start"}, + wg.action + }, + wg.instance, + dt.new_widget("box") + { + orientation = "horizontal", + dt.new_widget("label"){label = "element", halign = "start"}, + wg.element + }, + dt.new_widget("box") + { + orientation = "horizontal", + dt.new_widget("label"){label = "effect", halign = "start"}, + wg.effect + }, + wg.check, + dt.new_widget("box") + { + orientation = "horizontal", + dt.new_widget("label"){label = "speed", halign = "start"}, + wg.speed + }, + dt.new_widget("button") + { + label = "execute action", + tooltip = "execute the action specified in the fields above", + clicked_callback = function(_) + local sp = nan + if wg.check.value then sp = wg.speed.text end + wg.return_value.text = dt.gui.action(wg.action.text, wg.instance.value, wg.element.text, wg.effect.text, sp) + end + }, + dt.new_widget("box") + { + orientation = "horizontal", + dt.new_widget("label"){label = "return value:", halign = "start"}, + wg.return_value + }, + } + ) \ No newline at end of file From ef6e4d8f0b9bdef52b15a86c7182b52e9cfbbb87 Mon Sep 17 00:00:00 2001 From: Leonardo Brondani Schenkel Date: Mon, 13 Sep 2021 17:23:10 +0200 Subject: [PATCH 197/445] Fix URL of Finnish police document The old URL returns a 404, this is the current replacement. --- contrib/passport_guide.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/passport_guide.lua b/contrib/passport_guide.lua index 72611ebd..0b617286 100644 --- a/contrib/passport_guide.lua +++ b/contrib/passport_guide.lua @@ -20,7 +20,7 @@ --[[ PASSPORT CROPPING GUIDE guides for cropping passport photos based on documents from the Finnish police -(https://www.poliisi.fi/instancedata/prime_product_julkaisu/intermin/embeds/poliisiwwwstructure/38462_Passikuvaohje_EN.pdf) describing passport photo dimensions of 47x36 mm and 500x653 px for digital biometric data stored in passports. They use ISO 19794-5 standard based on ICAO 9303 regulations which should also be compliant for all of Europe. +(https://poliisi.fi/documents/25235045/31329600/Passport-photograph-instructions-by-the-police-2020-EN-fixed.pdf/1eec2f4c-aed7-68e0-c112-0a8f25e0328d/Passport-photograph-instructions-by-the-police-2020-EN-fixed.pdf) describing passport photo dimensions of 47x36 mm and 500x653 px for digital biometric data stored in passports. They use ISO 19794-5 standard based on ICAO 9303 regulations which should also be compliant for all of Europe. INSTALLATION * copy this file in $CONFIGDIR/lua/ where CONFIGDIR is your darktable configuration directory From ea4c6373f92ac42ccf592d7a41181122ecbd9047 Mon Sep 17 00:00:00 2001 From: Marcus Gama Date: Tue, 28 Sep 2021 20:08:30 -0300 Subject: [PATCH 198/445] Initial pt_BR translation --- locale/pt_BR/LC_MESSAGES/AutoGrouper.po | 46 ++++ locale/pt_BR/LC_MESSAGES/CollectHelper.po | 97 +++++++++ locale/pt_BR/LC_MESSAGES/clear_GPS.po | 30 +++ .../LC_MESSAGES/copy_attach_detach_tags.po | 86 ++++++++ .../pt_BR/LC_MESSAGES/copy_paste_metadata.po | 34 +++ locale/pt_BR/LC_MESSAGES/enfuse.po | 61 ++++++ .../pt_BR/LC_MESSAGES/executable_manager.po | 58 +++++ locale/pt_BR/LC_MESSAGES/gpx_export.po | 54 +++++ locale/pt_BR/LC_MESSAGES/script_manager.po | 199 ++++++++++++++++++ locale/pt_BR/LC_MESSAGES/select_untagged.po | 32 +++ locale/pt_BR/LC_MESSAGES/slideshowMusic.po | 34 +++ 11 files changed, 731 insertions(+) create mode 100644 locale/pt_BR/LC_MESSAGES/AutoGrouper.po create mode 100644 locale/pt_BR/LC_MESSAGES/CollectHelper.po create mode 100644 locale/pt_BR/LC_MESSAGES/clear_GPS.po create mode 100644 locale/pt_BR/LC_MESSAGES/copy_attach_detach_tags.po create mode 100644 locale/pt_BR/LC_MESSAGES/copy_paste_metadata.po create mode 100644 locale/pt_BR/LC_MESSAGES/enfuse.po create mode 100644 locale/pt_BR/LC_MESSAGES/executable_manager.po create mode 100644 locale/pt_BR/LC_MESSAGES/gpx_export.po create mode 100644 locale/pt_BR/LC_MESSAGES/script_manager.po create mode 100644 locale/pt_BR/LC_MESSAGES/select_untagged.po create mode 100644 locale/pt_BR/LC_MESSAGES/slideshowMusic.po diff --git a/locale/pt_BR/LC_MESSAGES/AutoGrouper.po b/locale/pt_BR/LC_MESSAGES/AutoGrouper.po new file mode 100644 index 00000000..23681b7f --- /dev/null +++ b/locale/pt_BR/LC_MESSAGES/AutoGrouper.po @@ -0,0 +1,46 @@ +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Marcus Gama , 2021. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-09-28 19:37-0300\n" +"PO-Revision-Date: 2021-09-28 19:54-0300\n" +"Last-Translator: Marcus Gama \n" +"Language-Team: Portuguese \n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Generator: Lokalize 21.08.1\n" + +#: ../contrib/AutoGrouper.lua:144 +msgid "auto group" +msgstr "grupo automático" + +#: ../contrib/AutoGrouper.lua:173 +msgid "group gap [sec.]" +msgstr "intervalo de agrupamento [seg]" + +#: ../contrib/AutoGrouper.lua:174 +msgid "minimum gap, in seconds, between groups" +msgstr "intervalo mínimo, em segundos, entre os grupos" + +#: ../contrib/AutoGrouper.lua:187 +msgid "auto group: selected" +msgstr "grupo automático: selecionado" + +#: ../contrib/AutoGrouper.lua:188 +msgid "auto group selected images" +msgstr "agrupa automaticamente as imagens selecionadas" + +#: ../contrib/AutoGrouper.lua:192 +msgid "auto group: collection" +msgstr "grupo automático: coleção" + +#: ../contrib/AutoGrouper.lua:193 +msgid "auto group the entire collection" +msgstr "agrupa automaticamente toda a coleção" diff --git a/locale/pt_BR/LC_MESSAGES/CollectHelper.po b/locale/pt_BR/LC_MESSAGES/CollectHelper.po new file mode 100644 index 00000000..d9aca975 --- /dev/null +++ b/locale/pt_BR/LC_MESSAGES/CollectHelper.po @@ -0,0 +1,97 @@ +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Marcus Gama , 2021. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-09-28 19:37-0300\n" +"PO-Revision-Date: 2021-09-28 20:02-0300\n" +"Last-Translator: Marcus Gama \n" +"Language-Team: Portuguese \n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Generator: Lokalize 21.08.1\n" + +#: ../contrib/CollectHelper.lua:74 +msgid "Please select a single image" +msgstr "Por favor, selecione uma única imagem" + +#: ../contrib/CollectHelper.lua:124 +msgid "select an image with an active color label" +msgstr "selecione uma imagem com uma etiqueta de cor ativa" + +#: ../contrib/CollectHelper.lua:205 +msgid "collect: previous" +msgstr "colecionar: anterior" + +#: ../contrib/CollectHelper.lua:207 +msgid "Sets the Collect parameters to be the previously active parameters" +msgstr "Define os parâmetros da coleção para os ativos anteriormente" + +#: ../contrib/CollectHelper.lua:211 +msgid "collect: folder" +msgstr "colecionar: pasta" + +#: ../contrib/CollectHelper.lua:213 +msgid "Sets the Collect parameters to be the selected images's folder" +msgstr "Define os parâmetros da coleção para a pasta de imagens selecionada" + +#: ../contrib/CollectHelper.lua:218 +msgid "collect: color label(s)" +msgstr "colecionar: etiqueta(s) de cor" + +#: ../contrib/CollectHelper.lua:220 +msgid "Sets the Collect parameters to be the selected images's color label(s)" +msgstr "" +"Define os parâmetros da coleção para a(s) etiqueta(s) de cor das imagens" +" selecionadas" + +#: ../contrib/CollectHelper.lua:225 +msgid "collect: all (AND)" +msgstr "colecionar: tudo (E)" + +#: ../contrib/CollectHelper.lua:227 +msgid "" +"Sets the Collect parameters based on all activated CollectHelper options" +msgstr "Define os parâmetros da coleção baseado em todas as opções do script" + +#: ../contrib/CollectHelper.lua:234 +msgid "CollectHelper: All" +msgstr "CollectHelper: Tudo" + +#: ../contrib/CollectHelper.lua:235 +msgid "" +"Will create a collect parameter set that utilizes all enabled CollectHelper " +"types (AND)" +msgstr "" +"Criará um conjunto de parâmetros de coleção que utilizará todos os tipos " +"habilitados do CollectHelper (E)" + +#: ../contrib/CollectHelper.lua:240 +msgid "CollectHelper: Color Label(s)" +msgstr "CollectHelper: Etiqueta(s) de Cor" + +#: ../contrib/CollectHelper.lua:241 +msgid "" +"Enable the button that allows you to swap to a collection based on selected " +"image's COLOR LABEL(S)" +msgstr "" +"Habilita o botão que permite que você alterna para uma coleção baseada na " +"ETIQUETA(S) DE COR da imagem selecionada" + +#: ../contrib/CollectHelper.lua:246 +msgid "CollectHelper: Folder" +msgstr "CollectHelper: Pasta" + +#: ../contrib/CollectHelper.lua:247 +msgid "" +"Enable the button that allows you to swap to a collection based on selected " +"image's FOLDER location" +msgstr "" +"Habilita o botão que permite que você alterne para uma coleção baseada na " +"PASTA da imagem selecionada" diff --git a/locale/pt_BR/LC_MESSAGES/clear_GPS.po b/locale/pt_BR/LC_MESSAGES/clear_GPS.po new file mode 100644 index 00000000..d96c0daf --- /dev/null +++ b/locale/pt_BR/LC_MESSAGES/clear_GPS.po @@ -0,0 +1,30 @@ +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Marcus Gama , 2021. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-09-28 19:37-0300\n" +"PO-Revision-Date: 2021-09-28 19:53-0300\n" +"Last-Translator: Marcus Gama \n" +"Language-Team: Portuguese \n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Generator: Lokalize 21.08.1\n" + +#: ../contrib/clear_GPS.lua:81 +msgid "clear GPS data" +msgstr "limpar dados de GPS" + +#: ../contrib/clear_GPS.lua:83 +msgid "Clear GPS data from selected images" +msgstr "Limpa os dados de GPS das imagens selecionadas" + +#: ../contrib/clear_GPS.lua:89 +msgid "Clear GPS data" +msgstr "Limpar dados de GPS" diff --git a/locale/pt_BR/LC_MESSAGES/copy_attach_detach_tags.po b/locale/pt_BR/LC_MESSAGES/copy_attach_detach_tags.po new file mode 100644 index 00000000..f9fcd12e --- /dev/null +++ b/locale/pt_BR/LC_MESSAGES/copy_attach_detach_tags.po @@ -0,0 +1,86 @@ +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Marcus Gama , 2021. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-09-28 19:37-0300\n" +"PO-Revision-Date: 2021-09-28 19:52-0300\n" +"Last-Translator: Marcus Gama \n" +"Language-Team: Portuguese \n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Generator: Lokalize 21.08.1\n" + +#: ../contrib/copy_attach_detach_tags.lua:101 +msgid "Image tags copied ..." +msgstr "Etiquetas de imagem copiadas ..." + +#: ../contrib/copy_attach_detach_tags.lua:123 +msgid "No tag to attach, please copy tags first." +msgstr "Nenhuma etiqueta anexada, por favor copie as etiquetas primeiro." + +#: ../contrib/copy_attach_detach_tags.lua:147 +msgid "Tags attached ..." +msgstr "Etiquetas anexadas ..." + +#: ../contrib/copy_attach_detach_tags.lua:163 +msgid "Tags removed from image(s)." +msgstr "Etiquetas removidas da(s) imagem(ns) " + +#: ../contrib/copy_attach_detach_tags.lua:169 +msgid "Tags replaced" +msgstr "Etiquetas substituídas" + +#: ../contrib/copy_attach_detach_tags.lua:174 +msgid "tagging addon" +msgstr "addon de etiquetas" + +#: ../contrib/copy_attach_detach_tags.lua:204 +#: ../contrib/copy_attach_detach_tags.lua:241 +#: ../contrib/copy_attach_detach_tags.lua:294 +msgid "copy tags from selected image(s)" +msgstr "copiar etiquetas da(s) imagem(ns) selecionada(s)" + +#: ../contrib/copy_attach_detach_tags.lua:209 +#: ../contrib/copy_attach_detach_tags.lua:244 +#: ../contrib/copy_attach_detach_tags.lua:299 +msgid "paste tags to selected image(s)" +msgstr "colar etiquetas para a(s) imagem(ns) selecionada(s)" + +#: ../contrib/copy_attach_detach_tags.lua:214 +#: ../contrib/copy_attach_detach_tags.lua:257 +#: ../contrib/copy_attach_detach_tags.lua:304 +msgid "remove tags from selected image(s)" +msgstr "remover etiquetas da(s) imagem(ns) selecionada(s)" + +#: ../contrib/copy_attach_detach_tags.lua:219 +#: ../contrib/copy_attach_detach_tags.lua:253 +#: ../contrib/copy_attach_detach_tags.lua:309 +msgid "replace tags from selected image(s)" +msgstr "substituir etiquetas a partir da(s) imagem(ns) selecionada(s)" + +#: ../contrib/copy_attach_detach_tags.lua:232 +msgid "tag clipboard" +msgstr "área de transferência de etiqueta" + +#: ../contrib/copy_attach_detach_tags.lua:240 +msgid "multi copy tags" +msgstr "copiar etiquetas múltiplas" + +#: ../contrib/copy_attach_detach_tags.lua:245 +msgid "paste tags" +msgstr "colar etiquetas" + +#: ../contrib/copy_attach_detach_tags.lua:252 +msgid "replace tags" +msgstr "substituir etiquetas" + +#: ../contrib/copy_attach_detach_tags.lua:256 +msgid "remove all tags" +msgstr "remover todas as etiquetas" diff --git a/locale/pt_BR/LC_MESSAGES/copy_paste_metadata.po b/locale/pt_BR/LC_MESSAGES/copy_paste_metadata.po new file mode 100644 index 00000000..572c3774 --- /dev/null +++ b/locale/pt_BR/LC_MESSAGES/copy_paste_metadata.po @@ -0,0 +1,34 @@ +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Marcus Gama , 2021. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-09-28 14:57-0300\n" +"PO-Revision-Date: 2021-09-28 19:38-0300\n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Last-Translator: Marcus Gama \n" +"Language-Team: Portuguese \n" +"X-Generator: Lokalize 21.08.1\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +#: copy_paste_metadata.lua:131 +msgid "copy metadata" +msgstr "copiar metadados" + +#: copy_paste_metadata.lua:133 +msgid "copy metadata of the first selected image" +msgstr "copiar metadados da primeira imagem selecionada" + +#: copy_paste_metadata.lua:139 +msgid "paste metadata" +msgstr "colar metadados" + +#: copy_paste_metadata.lua:141 +msgid "paste metadata to the selected images" +msgstr "colar metadados para as imagens selecionadas" diff --git a/locale/pt_BR/LC_MESSAGES/enfuse.po b/locale/pt_BR/LC_MESSAGES/enfuse.po new file mode 100644 index 00000000..6218f876 --- /dev/null +++ b/locale/pt_BR/LC_MESSAGES/enfuse.po @@ -0,0 +1,61 @@ +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Marcus Gama , 2021. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-09-28 15:19-0300\n" +"PO-Revision-Date: 2021-09-28 19:39-0300\n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Last-Translator: Marcus Gama \n" +"Language-Team: Portuguese \n" +"X-Generator: Lokalize 21.08.1\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +#: enfuse.lua:187 +#, lua-format +msgid "Error writing to `%s`" +msgstr "Erro ao salvar `%s`" + +#: enfuse.lua:210 +#, lua-format +msgid "Converting raw file '%s' to tiff..." +msgstr "Converter arquivo raw `%s` para tiff..." + +#: enfuse.lua:220 +#, lua-format +msgid "Skipping %s..." +msgstr "Pulando %s..." + +#: enfuse.lua:227 +msgid "No suitable images selected, nothing to do for enfuse" +msgstr "Nenhuma imagem adequada selecionado, nada a fazer para o script" + +#: enfuse.lua:233 +#, lua-format +msgid "%d image(s) skipped" +msgstr "%d imagem(ns) pulada(s)" + +#: enfuse.lua:253 +msgid "Enfuse failed, see terminal output for details" +msgstr "Script falhou, veja a saída do terminal para detalhes" + +#: enfuse.lua:265 +msgid "enfuse was successful, resulting image has been imported" +msgstr "script foi bem sucedido, imagem resultante foi importada" + +#: enfuse.lua:267 +#, lua-format +msgid "enfuse: done, resulting image '%s' has been imported with id %d" +msgstr "enfuse: feito, imagem '%s' resultante foi importada com o id %d" + +#: enfuse.lua:301 +msgid "Could not find enfuse executable. Not loading enfuse exporter..." +msgstr "" +"Não foi possível encontrar o executável do enfuse. Exportador do enfuse não" +" carregado..." diff --git a/locale/pt_BR/LC_MESSAGES/executable_manager.po b/locale/pt_BR/LC_MESSAGES/executable_manager.po new file mode 100644 index 00000000..00732548 --- /dev/null +++ b/locale/pt_BR/LC_MESSAGES/executable_manager.po @@ -0,0 +1,58 @@ +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Marcus Gama , 2021. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-09-28 11:50-0300\n" +"PO-Revision-Date: 2021-09-28 19:39-0300\n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Last-Translator: Marcus Gama \n" +"Language-Team: Portuguese \n" +"X-Generator: Lokalize 21.08.1\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +#: executable_manager.lua:144 +msgid "No executable paths found, exiting..." +msgstr "Caminho do executável não encontrado, saindo..." + +#: executable_manager.lua:160 +msgid "select an executable" +msgstr "selecione um executável" + +#: executable_manager.lua:160 +msgid "search path for executable" +msgstr "caminho de pesquisa por executável" + +#: executable_manager.lua:169 +msgid "select " +msgstr "selecionar " + +#: executable_manager.lua:169 +msgid " executable" +msgstr " executável" + +#: executable_manager.lua:190 +msgid "select executable to modify" +msgstr "selecione executável a modificar" + +#: executable_manager.lua:205 +msgid "current" +msgstr "atual" + +#: executable_manager.lua:207 +msgid "select" +msgstr "selecionar" + +#: executable_manager.lua:209 +msgid "reset" +msgstr "reiniciar" + +#: executable_manager.lua:212 +msgid "Clear path for " +msgstr "Limpar caminho para " diff --git a/locale/pt_BR/LC_MESSAGES/gpx_export.po b/locale/pt_BR/LC_MESSAGES/gpx_export.po new file mode 100644 index 00000000..a5d5c78a --- /dev/null +++ b/locale/pt_BR/LC_MESSAGES/gpx_export.po @@ -0,0 +1,54 @@ +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Marcus Gama , 2021. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-09-28 19:37-0300\n" +"PO-Revision-Date: 2021-09-28 19:48-0300\n" +"Last-Translator: Marcus Gama \n" +"Language-Team: Portuguese \n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Generator: Lokalize 21.08.1\n" + +#: ../contrib/gpx_export.lua:59 +msgid "gpx file path" +msgstr "caminho do arquivo gpx" + +#: ../contrib/gpx_export.lua:72 +msgid "exporting gpx file..." +msgstr "exportar arquivo gpx..." + +#: ../contrib/gpx_export.lua:74 +msgid "gpx export" +msgstr "exportar gpx" + +#: ../contrib/gpx_export.lua:93 ../contrib/gpx_export.lua:94 +msgid " does not have date information and won't be processed" +msgstr " não possui informações de data e não será processado" + +#: ../contrib/gpx_export.lua:134 +msgid "invalid path: " +msgstr "caminho inválido: " + +#: ../contrib/gpx_export.lua:138 +msgid "gpx file created: " +msgstr "arquivo gpx criado: " + +#: ../contrib/gpx_export.lua:171 +msgid "export" +msgstr "exportar" + +#: ../contrib/gpx_export.lua:172 +msgid "export gpx file" +msgstr "exportar arquivo gpx" + +#: ../contrib/gpx_export.lua:180 +msgid "file:" +msgstr "arquivo:" diff --git a/locale/pt_BR/LC_MESSAGES/script_manager.po b/locale/pt_BR/LC_MESSAGES/script_manager.po new file mode 100644 index 00000000..626ec843 --- /dev/null +++ b/locale/pt_BR/LC_MESSAGES/script_manager.po @@ -0,0 +1,199 @@ +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Marcus Gama , 2021. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-09-28 11:49-0300\n" +"PO-Revision-Date: 2021-09-28 19:41-0300\n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Last-Translator: Marcus Gama \n" +"Language-Team: Portuguese \n" +"X-Generator: Lokalize 21.08.1\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +#: script_manager.lua:314 +msgid "Cant read from " +msgstr "Não foi possível ler de " + +#: script_manager.lua:332 +msgid "Loaded " +msgstr "Carregado " + +#: script_manager.lua:344 +msgid " failed to load" +msgstr " falhou ao carregar" + +#: script_manager.lua:379 script_manager.lua:634 script_manager.lua:657 +msgid " stopped" +msgstr " parado" + +#: script_manager.lua:383 +msgid " will not start when darktable is restarted" +msgstr " não iniciará quando o darktable for reiniciado" + +#: script_manager.lua:443 script_manager.lua:507 +msgid "find command is " +msgstr "encontrar comando é " + +#: script_manager.lua:469 script_manager.lua:553 +msgid "" +"ERROR: git not found. Install or specify the location of the git executable." +msgstr "" +"ERRO: git não encontrado. Instale ou defina a localização do executável do" +" git." + +#: script_manager.lua:483 +msgid "lua scripts successfully updated" +msgstr "scripts lua atualizados com sucesso" + +#: script_manager.lua:543 +msgid "category " +msgstr "categoria " + +#: script_manager.lua:543 +msgid " is already in use. Please specify a different category name." +msgstr " já está em uso. Por favor, defina um nome de categoria diferente." + +#: script_manager.lua:572 +msgid "scripts successfully installed into category " +msgstr "scripts instalados com sucesso na categoria " + +#: script_manager.lua:588 +msgid "No scripts found to install" +msgstr "Nenhum script para instalação encontrado" + +#: script_manager.lua:592 +msgid "failed to download scripts" +msgstr "falha ao baixar scripts" + +#: script_manager.lua:627 +msgid " started" +msgstr " iniciado" + +#: script_manager.lua:732 +msgid "Page " +msgstr "Página " + +#: script_manager.lua:732 +msgid " of " +msgstr " de " + +#: script_manager.lua:934 +msgid "scripts to update" +msgstr "scripts a atualizar" + +#: script_manager.lua:935 +msgid "select the scripts installation to update" +msgstr "selecione as instalações de scripts a atualizar" + +#: script_manager.lua:944 script_manager.lua:1002 +msgid "update scripts" +msgstr "atualizar scripts" + +#: script_manager.lua:945 +msgid "update the lua scripts from the repository" +msgstr "atualizar os scripts lua a partir do repositório" + +#: script_manager.lua:956 +msgid "" +"enter the URL of the git repository containing the scripts you wish to add" +msgstr "" +"insira a URL do repositório git contendo os scripts que deseja adicionar" + +#: script_manager.lua:961 +msgid "name of new category" +msgstr "nome da nova categoria" + +#: script_manager.lua:962 +msgid "enter a category name for the additional scripts" +msgstr "insira um nome de categoria para os scripts adicionais" + +#: script_manager.lua:967 +msgid "URL to download additional scripts from" +msgstr "URL da qual baixar os scripts adicionais" + +#: script_manager.lua:969 +msgid "new category to place scripts in" +msgstr "nova categoria para colocar os scripts" + +#: script_manager.lua:972 +msgid "install additional scripts" +msgstr "instalar scripts adicionais" + +#: script_manager.lua:980 +msgid "Enable \"Disable Scripts\" button" +msgstr "Ativar botão \"Desabilitar Scripts\"" + +#: script_manager.lua:990 +msgid "Disable Scripts" +msgstr "Desabilitar Scripts" + +#: script_manager.lua:996 +msgid "lua scripts will not run the next time darktable is started" +msgstr "scripts lua não rodarão na próxima vez que o darktable for iniciado" + +#: script_manager.lua:1005 +msgid "add more scripts" +msgstr "adicionar mais scripts" + +#: script_manager.lua:1007 +msgid "disable scripts" +msgstr "desabilitar scripts" + +#: script_manager.lua:1015 +msgid "category" +msgstr "categoria" + +#: script_manager.lua:1016 +msgid "select the script category" +msgstr "selecione a categoria do script" + +#: script_manager.lua:1036 +msgid "Page:" +msgstr "Página:" + +#: script_manager.lua:1064 +msgid "Scripts" +msgstr "Scripts" + +#: script_manager.lua:1073 +msgid "scripts per page" +msgstr "scripts por página" + +#: script_manager.lua:1074 +msgid "select number of start/stop buttons to display" +msgstr "selecione o número de botões de iniciar/parar a exibir" + +#: script_manager.lua:1085 +msgid "change number of buttons" +msgstr "mudar o número de botões" + +#: script_manager.lua:1093 +msgid "Configuration" +msgstr "Configuração" + +#: script_manager.lua:1099 +msgid "use color interface?" +msgstr "usar interface colorida?" + +#: script_manager.lua:1122 +msgid "action" +msgstr "ação" + +#: script_manager.lua:1128 +msgid "install/update scripts" +msgstr "instalar/atualizar scripts" + +#: script_manager.lua:1128 +msgid "configure" +msgstr "configurar" + +#: script_manager.lua:1128 +msgid "start/stop scripts" +msgstr "iniciar/parar scripts" diff --git a/locale/pt_BR/LC_MESSAGES/select_untagged.po b/locale/pt_BR/LC_MESSAGES/select_untagged.po new file mode 100644 index 00000000..5408fafa --- /dev/null +++ b/locale/pt_BR/LC_MESSAGES/select_untagged.po @@ -0,0 +1,32 @@ +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Marcus Gama , 2021. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-09-28 19:37-0300\n" +"PO-Revision-Date: 2021-09-28 19:47-0300\n" +"Last-Translator: Marcus Gama \n" +"Language-Team: Portuguese \n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Generator: Lokalize 21.08.1\n" + +#: ../contrib/select_untagged.lua:47 +msgid "select untagged images" +msgstr "selecionar imagens sem etiqueta" + +#: ../contrib/select_untagged.lua:79 +msgid "select untagged" +msgstr "selecionar sem etiqueta" + +#: ../contrib/select_untagged.lua:81 +msgid "select all images containing no tags or only tags added by darktable" +msgstr "" +"seleciona todas as imagens que não possuam etiqueta ou somente etiquetas" +" adicionadas pelo darktable" diff --git a/locale/pt_BR/LC_MESSAGES/slideshowMusic.po b/locale/pt_BR/LC_MESSAGES/slideshowMusic.po new file mode 100644 index 00000000..c6fe4b5f --- /dev/null +++ b/locale/pt_BR/LC_MESSAGES/slideshowMusic.po @@ -0,0 +1,34 @@ +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Marcus Gama , 2021. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-09-28 19:37-0300\n" +"PO-Revision-Date: 2021-09-28 19:50-0300\n" +"Last-Translator: Marcus Gama \n" +"Language-Team: Portuguese \n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Generator: Lokalize 21.08.1\n" + +#: ../contrib/slideshowMusic.lua:56 +msgid "rhythmbox-client not found" +msgstr "cliente rhythmbox não encontrado" + +#: ../contrib/slideshowMusic.lua:85 +msgid "Slideshow background music file" +msgstr "Arquivo de música de fundo da apresentação" + +#: ../contrib/slideshowMusic.lua:89 +msgid "Play slideshow background music" +msgstr "Exibe uma apresentação com música de fundo" + +#: ../contrib/slideshowMusic.lua:90 +msgid "Plays music with rhythmbox if a slideshow starts" +msgstr "Toca música com o rhytmbox se uma apresentação inicia" From 3dbbb7dfd58b39ec468997c9f55239dd3d9cf8e9 Mon Sep 17 00:00:00 2001 From: Marcus Gama Date: Sat, 2 Oct 2021 05:52:20 -0300 Subject: [PATCH 199/445] Update pt_BR translation --- locale/pt_BR/LC_MESSAGES/HDRMerge.po | 163 +++++ locale/pt_BR/LC_MESSAGES/OpenInExplorer.po | 86 +++ locale/pt_BR/LC_MESSAGES/RL_out_sharp.po | 74 +++ .../LC_MESSAGES/color_profile_manager.po | 90 +++ locale/pt_BR/LC_MESSAGES/enfuseAdvanced.po | 555 ++++++++++++++++++ locale/pt_BR/LC_MESSAGES/exportLUT.po | 62 ++ locale/pt_BR/LC_MESSAGES/ext_editor.po | 129 ++++ locale/pt_BR/LC_MESSAGES/face_recognition.po | 135 +++++ locale/pt_BR/LC_MESSAGES/fujifilm_ratings.po | 30 + locale/pt_BR/LC_MESSAGES/geoJSON_export.po | 77 +++ locale/pt_BR/LC_MESSAGES/geoToolbox.po | 166 ++++++ locale/pt_BR/LC_MESSAGES/gimp.po | 43 ++ .../LC_MESSAGES/harmonic_armature_guide.po | 22 + locale/pt_BR/LC_MESSAGES/hugin.po | 67 +++ locale/pt_BR/LC_MESSAGES/image_stack.po | 273 +++++++++ locale/pt_BR/LC_MESSAGES/image_time.po | 244 ++++++++ locale/pt_BR/LC_MESSAGES/kml_export.po | 90 +++ locale/pt_BR/LC_MESSAGES/passport_guide.po | 22 + locale/pt_BR/LC_MESSAGES/pdf_slideshow.po | 70 +++ locale/pt_BR/LC_MESSAGES/photils.po | 118 ++++ locale/pt_BR/LC_MESSAGES/quicktag.po | 82 +++ locale/pt_BR/LC_MESSAGES/rename_images.po | 234 ++++++++ .../pt_BR/LC_MESSAGES/transfer_hierarchy.po | 75 +++ locale/pt_BR/LC_MESSAGES/video_ffmpeg.po | 135 +++++ 24 files changed, 3042 insertions(+) create mode 100644 locale/pt_BR/LC_MESSAGES/HDRMerge.po create mode 100644 locale/pt_BR/LC_MESSAGES/OpenInExplorer.po create mode 100644 locale/pt_BR/LC_MESSAGES/RL_out_sharp.po create mode 100644 locale/pt_BR/LC_MESSAGES/color_profile_manager.po create mode 100644 locale/pt_BR/LC_MESSAGES/enfuseAdvanced.po create mode 100644 locale/pt_BR/LC_MESSAGES/exportLUT.po create mode 100644 locale/pt_BR/LC_MESSAGES/ext_editor.po create mode 100644 locale/pt_BR/LC_MESSAGES/face_recognition.po create mode 100644 locale/pt_BR/LC_MESSAGES/fujifilm_ratings.po create mode 100644 locale/pt_BR/LC_MESSAGES/geoJSON_export.po create mode 100644 locale/pt_BR/LC_MESSAGES/geoToolbox.po create mode 100644 locale/pt_BR/LC_MESSAGES/gimp.po create mode 100644 locale/pt_BR/LC_MESSAGES/harmonic_armature_guide.po create mode 100644 locale/pt_BR/LC_MESSAGES/hugin.po create mode 100644 locale/pt_BR/LC_MESSAGES/image_stack.po create mode 100644 locale/pt_BR/LC_MESSAGES/image_time.po create mode 100644 locale/pt_BR/LC_MESSAGES/kml_export.po create mode 100644 locale/pt_BR/LC_MESSAGES/passport_guide.po create mode 100644 locale/pt_BR/LC_MESSAGES/pdf_slideshow.po create mode 100644 locale/pt_BR/LC_MESSAGES/photils.po create mode 100644 locale/pt_BR/LC_MESSAGES/quicktag.po create mode 100644 locale/pt_BR/LC_MESSAGES/rename_images.po create mode 100644 locale/pt_BR/LC_MESSAGES/transfer_hierarchy.po create mode 100644 locale/pt_BR/LC_MESSAGES/video_ffmpeg.po diff --git a/locale/pt_BR/LC_MESSAGES/HDRMerge.po b/locale/pt_BR/LC_MESSAGES/HDRMerge.po new file mode 100644 index 00000000..b60cb139 --- /dev/null +++ b/locale/pt_BR/LC_MESSAGES/HDRMerge.po @@ -0,0 +1,163 @@ +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Marcus Gama , 2021. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-09-28 19:37-0300\n" +"PO-Revision-Date: 2021-10-01 19:40-0300\n" +"Last-Translator: Marcus Gama \n" +"Language-Team: Portuguese \n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Generator: Lokalize 21.08.1\n" + +#: ../contrib/HDRMerge.lua:175 +msgid "please update you binary location" +msgstr "por favor, atualize a localização do binário" + +#: ../contrib/HDRMerge.lua:194 +msgid "update successful" +msgstr "atualização bem sucedida" + +#: ../contrib/HDRMerge.lua:196 +msgid "update unsuccessful, please try again" +msgstr "atualização mau sucedida, tente de novo" + +#: ../contrib/HDRMerge.lua:210 +msgid "HDRMerge install issue" +msgstr "problema com a instalação do HDRMerge" + +#: ../contrib/HDRMerge.lua:211 +msgid "HDRMerge install issue, please ensure the binary path is proper" +msgstr "" +"problema com a instalação do HDRMerge, certifique-se de que o caminho do" +" binário esteja correto" + +#: ../contrib/HDRMerge.lua:216 +msgid "not enough images selected, select at least 2 images to merge" +msgstr "" +"imagens selecionadas insuficientes, selecione apenas 2 imagens para mesclar" + +#: ../contrib/HDRMerge.lua:277 +msgid "HDRMerge completed successfully" +msgstr "HDRMerge completado com sucesso" + +#: ../contrib/HDRMerge.lua:279 ../contrib/HDRMerge.lua:280 +msgid "HDRMerge failed" +msgstr "HDRMerge falhou" + +#: ../contrib/HDRMerge.lua:289 +msgid "HDRMerge" +msgstr "HDRMerge" + +#: ../contrib/HDRMerge.lua:312 +msgid "HDRMerge options" +msgstr "opções do HDRMerge" + +#: ../contrib/HDRMerge.lua:317 +msgid "bits per sample" +msgstr "bits por amostra" + +#: ../contrib/HDRMerge.lua:318 +msgid "number of bits per sample in the output image" +msgstr "número de bits por amostra na imagem de saída" + +#: ../contrib/HDRMerge.lua:334 +msgid "embedded preview size" +msgstr "tamanho da pré-visualização embutida" + +#: ../contrib/HDRMerge.lua:335 +msgid "size of the embedded preview in output image" +msgstr "tamanho da pré-visualização embutida na imagem de saída" + +#: ../contrib/HDRMerge.lua:337 ../contrib/HDRMerge.lua:382 +msgid "none" +msgstr "nenhum" + +#: ../contrib/HDRMerge.lua:337 +msgid "half" +msgstr "metade" + +#: ../contrib/HDRMerge.lua:337 +msgid "full" +msgstr "completo" + +#: ../contrib/HDRMerge.lua:349 +msgid "batch mode" +msgstr "modo em lote" + +#: ../contrib/HDRMerge.lua:351 +msgid "" +"enable batch mode operation \n" +"NOTE: resultant files will NOT be auto-imported" +msgstr "" +"ativar a operação em modo em lote\n" +"NOTA: arquivos resultantes NÃO serão importados automaticamente" + +#: ../contrib/HDRMerge.lua:361 +msgid "batch gap [sec.]" +msgstr "intervalo do lote [seg.]" + +#: ../contrib/HDRMerge.lua:362 +msgid "gap, in seconds, between batch mode groups" +msgstr "intervalo, em segundos, entre os grupos do modo em lote" + +#: ../contrib/HDRMerge.lua:376 +msgid "import options" +msgstr "opções de importação" + +#: ../contrib/HDRMerge.lua:379 +msgid "apply style on import" +msgstr "aplicar estilo ao importar" + +#: ../contrib/HDRMerge.lua:380 +msgid "Apply selected style on auto-import to newly created image" +msgstr "" +"Aplica o estilo selecionado ao importar automaticamente para novas imagens" +" criadas" + +#: ../contrib/HDRMerge.lua:400 +msgid "copy tags" +msgstr "copiar etiquetas" + +#: ../contrib/HDRMerge.lua:402 +msgid "copy tags from first source image" +msgstr "copia etiquetas da primeira imagem fonte" + +#: ../contrib/HDRMerge.lua:409 +msgid "" +"Additional tags to be added on import. Seperate with commas, all spaces will " +"be removed" +msgstr "" +"Etiquetas adicionais a serem anexadas ao importar. Separar com vírgulas," +" todos os espaços serão removidos" + +#: ../contrib/HDRMerge.lua:411 +msgid "Enter tags, seperated by commas" +msgstr "Insira as etiquetas, separadas por vírgulas" + +#: ../contrib/HDRMerge.lua:415 +msgid "merge" +msgstr "mesclar" + +#: ../contrib/HDRMerge.lua:416 +msgid "run HDRMerge with the above specified settings" +msgstr "rodar o HDRMerge com as configurações especificadas acima" + +#: ../contrib/HDRMerge.lua:420 +msgid "Select HDRmerge executable" +msgstr "Selecionar o executável do HDRmerge" + +#: ../contrib/HDRMerge.lua:425 +msgid "update" +msgstr "atualizar" + +#: ../contrib/HDRMerge.lua:426 +msgid "update the binary path with current value" +msgstr "atualiza o caminho do binário com o valor atual" diff --git a/locale/pt_BR/LC_MESSAGES/OpenInExplorer.po b/locale/pt_BR/LC_MESSAGES/OpenInExplorer.po new file mode 100644 index 00000000..9779db96 --- /dev/null +++ b/locale/pt_BR/LC_MESSAGES/OpenInExplorer.po @@ -0,0 +1,86 @@ +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Marcus Gama , 2021. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-09-28 19:37-0300\n" +"PO-Revision-Date: 2021-10-01 23:40-0300\n" +"Last-Translator: Marcus Gama \n" +"Language-Team: Portuguese \n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Generator: Lokalize 21.08.1\n" + +#: ../contrib/OpenInExplorer.lua:79 +msgid "" +"OpenInExplorer plug-in only supports Linux, macOS, and Windows at this time" +msgstr "" +"Atualmente, o plugin OpenInExplorer somente suporta Linux, macOS e Windows" + +#: ../contrib/OpenInExplorer.lua:95 +msgid "" +"No links directory selected.\n" +"Please check the dt preferences (lua options)" +msgstr "" +"Nenhum link para pasta selecionado.\n" +"Verifique as preferências do darktable (opções lua)" + +#: ../contrib/OpenInExplorer.lua:99 +#, lua-format +msgid "" +"Links directory '%s' not found.\n" +"Please check the dt preferences (lua options)" +msgstr "" +"Links para pasta '%s' não encontrados.\n" +"Verifique as preferências do darktable (opções lua)" + +#: ../contrib/OpenInExplorer.lua:156 +msgid "Failed to create links. Missing rights?" +msgstr "Falha ao criar links. Possui permissões adequadas?" + +#: ../contrib/OpenInExplorer.lua:172 +msgid "Please select an image" +msgstr "Por favor, selecione uma imagem" + +#: ../contrib/OpenInExplorer.lua:178 +msgid "Please select fewer images (max. 15)" +msgstr "Por favor, selecione menos imagens (máx 15)" + +#: ../contrib/OpenInExplorer.lua:203 +msgid "show in file explorer" +msgstr "mostrar no navegador de arquivos" + +#: ../contrib/OpenInExplorer.lua:205 +msgid "Open the file manager at the selected image's location" +msgstr "Abre o gerenciador de arquivos na localização das imagens selecionadas" + +#: ../contrib/OpenInExplorer.lua:212 +msgid "OpenInExplorer: linked files directory" +msgstr "OpenInExplorer: pasta de arquivos linkada" + +#: ../contrib/OpenInExplorer.lua:213 +msgid "" +"Directory to store the links to the file names. Requires restart to take " +"effect" +msgstr "" +"Pasta para armazenar os links para os nomes de arquivo. Precisa reiniciar" +" para ter efeito" + +#: ../contrib/OpenInExplorer.lua:216 +msgid "Select directory" +msgstr "Selecione a pasta" + +#: ../contrib/OpenInExplorer.lua:222 +msgid "OpenInExplorer: use links" +msgstr "OpenInExplorer: usar links" + +#: ../contrib/OpenInExplorer.lua:223 +msgid "Use links instead of multiple windows. Requires restart to take effect" +msgstr "" +"Usa links ao invés de janelas múltiplas. Precisa reiniciar para ter efeito" diff --git a/locale/pt_BR/LC_MESSAGES/RL_out_sharp.po b/locale/pt_BR/LC_MESSAGES/RL_out_sharp.po new file mode 100644 index 00000000..1b5b3ed6 --- /dev/null +++ b/locale/pt_BR/LC_MESSAGES/RL_out_sharp.po @@ -0,0 +1,74 @@ +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Marcus Gama , 2021. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-09-28 19:37-0300\n" +"PO-Revision-Date: 2021-10-02 05:31-0300\n" +"Last-Translator: Marcus Gama \n" +"Language-Team: Portuguese \n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Generator: Lokalize 21.08.1\n" + +#: ../contrib/RL_out_sharp.lua:119 +msgid "GMic executable not configured" +msgstr "executável GMic não configurado" + +#: ../contrib/RL_out_sharp.lua:139 +msgid "sharpening image " +msgstr "melhorar nitidez da imagem " + +#: ../contrib/RL_out_sharp.lua:154 +msgid "sharpening error" +msgstr "erro ao melhorar nitidez" + +#: ../contrib/RL_out_sharp.lua:163 +msgid "finished exporting" +msgstr "exportação finalizada" + +#: ../contrib/RL_out_sharp.lua:175 ../contrib/RL_out_sharp.lua:176 +msgid "select output folder" +msgstr "selecionar pasta de saída" + +#: ../contrib/RL_out_sharp.lua:185 +msgid "sigma" +msgstr "sigma" + +#: ../contrib/RL_out_sharp.lua:186 +msgid "controls the width of the blur that's applied" +msgstr "controla a largura do desfoque que é aplicada" + +#: ../contrib/RL_out_sharp.lua:197 +msgid "iterations" +msgstr "iterações" + +#: ../contrib/RL_out_sharp.lua:198 +msgid "increase for better sharpening, but slower" +msgstr "aumente para melhor efeito, mas diminui velocidade" + +#: ../contrib/RL_out_sharp.lua:209 +msgid "output jpg quality" +msgstr "qualidade do jpg de saída" + +#: ../contrib/RL_out_sharp.lua:210 +msgid "quality of the output jpg file" +msgstr "qualidade do arquivo jpg de saída" + +#: ../contrib/RL_out_sharp.lua:229 +msgid "RL output sharpen" +msgstr "melhoria de nitidez na saída RL" + +#: ../contrib/RL_out_sharp.lua:233 +msgid "executable for GMic CLI" +msgstr "executável para o GMic CLI" + +#: ../contrib/RL_out_sharp.lua:234 +msgid "select executable for GMic command line version" +msgstr "selecione o executável para a versão de linha de comando do GMic" diff --git a/locale/pt_BR/LC_MESSAGES/color_profile_manager.po b/locale/pt_BR/LC_MESSAGES/color_profile_manager.po new file mode 100644 index 00000000..103ce0b4 --- /dev/null +++ b/locale/pt_BR/LC_MESSAGES/color_profile_manager.po @@ -0,0 +1,90 @@ +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Marcus Gama , 2021. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-09-28 19:37-0300\n" +"PO-Revision-Date: 2021-09-30 19:05-0300\n" +"Last-Translator: Marcus Gama \n" +"Language-Team: Portuguese \n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Generator: Lokalize 21.08.1\n" + +#: ../contrib/color_profile_manager.lua:122 +msgid "added color profile " +msgstr "perfil de cor adicionado " + +#: ../contrib/color_profile_manager.lua:128 +msgid "removed color profile " +msgstr "perfil de cor removido " + +#: ../contrib/color_profile_manager.lua:146 +msgid "ERROR: color profile must be an icc or icm file" +msgstr "ERRO: perfil de cor deve ser um arquivo icm ou icc" + +#: ../contrib/color_profile_manager.lua:229 +msgid "color profile manager" +msgstr "gerenciador de perfil de cor" + +#: ../contrib/color_profile_manager.lua:270 +msgid "initialize color profiles" +msgstr "inicializar perfis de cor" + +#: ../contrib/color_profile_manager.lua:271 +msgid "create the directory structure to contain the color profiles" +msgstr "cria a estrutura de pasta para conter os perfis de cor" + +#: ../contrib/color_profile_manager.lua:286 +msgid "select profile set" +msgstr "selecionar definição de perfil" + +#: ../contrib/color_profile_manager.lua:287 +msgid "select input or output profiles" +msgstr "selecionar perfis de entrada ou saída" + +#: ../contrib/color_profile_manager.lua:294 +msgid "input" +msgstr "entrada" + +#: ../contrib/color_profile_manager.lua:294 +msgid "output" +msgstr "saída" + +#: ../contrib/color_profile_manager.lua:298 +msgid "select color profile to add" +msgstr "selecionar perfil de cor a adicionar" + +#: ../contrib/color_profile_manager.lua:299 +msgid "select the .icc or .icm file to add" +msgstr "selecionar arquivo icc ou icm a adicionar" + +#: ../contrib/color_profile_manager.lua:306 +msgid "add profile" +msgstr "adicionar perfil" + +#: ../contrib/color_profile_manager.lua:309 +msgid "add selected color profile" +msgstr "adicionar perfil de cor selecionado" + +#: ../contrib/color_profile_manager.lua:310 +msgid "add selected file to profiles" +msgstr "adicionar arquivo selecionado aos perfis" + +#: ../contrib/color_profile_manager.lua:320 +msgid "remove profile" +msgstr "remover perfil" + +#: ../contrib/color_profile_manager.lua:323 +msgid "remove selected profile(s)" +msgstr "remover perfil(s) selecionado(s)" + +#: ../contrib/color_profile_manager.lua:324 +msgid "remove the checked profile(s)" +msgstr "remover o(s) perfil(s) marcado(s)" diff --git a/locale/pt_BR/LC_MESSAGES/enfuseAdvanced.po b/locale/pt_BR/LC_MESSAGES/enfuseAdvanced.po new file mode 100644 index 00000000..f1b785c1 --- /dev/null +++ b/locale/pt_BR/LC_MESSAGES/enfuseAdvanced.po @@ -0,0 +1,555 @@ +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Marcus Gama , 2021. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-09-28 19:37-0300\n" +"PO-Revision-Date: 2021-10-01 19:03-0300\n" +"Last-Translator: Marcus Gama \n" +"Language-Team: Portuguese \n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Generator: Lokalize 21.08.1\n" + +#: ../contrib/enfuseAdvanced.lua:250 +msgid "please update your binary locations" +msgstr "por favor, atualiza suas localizações de binários" + +#: ../contrib/enfuseAdvanced.lua:262 +msgid "issue with " +msgstr "problema com " + +#: ../contrib/enfuseAdvanced.lua:262 +msgid " executable" +msgstr " executável" + +#: ../contrib/enfuseAdvanced.lua:271 +msgid "update successful" +msgstr "atualização bem sucedida" + +#: ../contrib/enfuseAdvanced.lua:273 +msgid "update unsuccessful, please try again" +msgstr "atualização mau sucedida, tente novamente" + +#: ../contrib/enfuseAdvanced.lua:379 +msgid "saved to " +msgstr "salvar para " + +#: ../contrib/enfuseAdvanced.lua:395 +msgid "loaded from " +msgstr "carregado de " + +#: ../contrib/enfuseAdvanced.lua:430 +msgid "export for image fusion " +msgstr "exportar para fusão de imagem " + +#: ../contrib/enfuseAdvanced.lua:435 +msgid "too few images selected, please select at least 2 images" +msgstr "muito poucas imagens selecionadas, selecione pelo menos 2 imagens" + +#: ../contrib/enfuseAdvanced.lua:438 +msgid "installation error, please verify binary paths are proper" +msgstr "" +"erro de instalação, verifique se as localizações dos binários estão corretas" + +#: ../contrib/enfuseAdvanced.lua:458 ../contrib/enfuseAdvanced.lua:459 +#: ../contrib/enfuseAdvanced.lua:485 ../contrib/enfuseAdvanced.lua:486 +msgid " failed" +msgstr " falhou" + +#: ../contrib/enfuseAdvanced.lua:534 +msgid "image align options" +msgstr "opções de alinhamento de imagem" + +#: ../contrib/enfuseAdvanced.lua:537 +msgid "align images" +msgstr "alinhar imagens" + +#: ../contrib/enfuseAdvanced.lua:539 +msgid "automatically align images prior to enfuse" +msgstr "alinha automaticamente as imagens antes de fundir" + +#: ../contrib/enfuseAdvanced.lua:549 +msgid "optimize radial distortion" +msgstr "otimizar distorção radial" + +#: ../contrib/enfuseAdvanced.lua:551 +msgid "" +"optimize radial distortion for all images, \n" +"except for first" +msgstr "" +"otimiza a distorção radial para todas as imagens, \n" +"exceto para a primeira" + +#: ../contrib/enfuseAdvanced.lua:556 +msgid "optimize field of view" +msgstr "otimizar o campo de visão" + +#: ../contrib/enfuseAdvanced.lua:558 +msgid "" +"optimize field of view for all images, except for first. \n" +"Useful for aligning focus stacks (DFF) with slightly \n" +"different magnification." +msgstr "" +"otimizar o campo de visão para todas as imagens, exceto para a primeira. \n" +"Útil para alinhar foco empilhado (DFF, sigla em inglês) com ampliação \n" +"ligeiramente diferente." + +#: ../contrib/enfuseAdvanced.lua:563 +msgid "optimize image center shift" +msgstr "otimizar deslocamento do centro da imagem" + +#: ../contrib/enfuseAdvanced.lua:565 +msgid "" +"optimize image center shift for all images, \n" +"except for first." +msgstr "" +"otimiza o deslocamento do centro da imagem para\n" +"todas as imagens, exceto a primeira." + +#: ../contrib/enfuseAdvanced.lua:570 +msgid "auto crop" +msgstr "recorte automático" + +#: ../contrib/enfuseAdvanced.lua:572 +msgid "auto crop the image to the area covered by all images." +msgstr "" +"recorta automaticamente a imagem para a área coberta por todas\n" +"as imagens." + +#: ../contrib/enfuseAdvanced.lua:577 +msgid "load distortion from lens database" +msgstr "carregar distorção a partir da base de dados de lentes" + +#: ../contrib/enfuseAdvanced.lua:579 +msgid "try to load distortion information from lens database" +msgstr "tenta carregar informações de distorção da base de dados de lentes" + +#: ../contrib/enfuseAdvanced.lua:584 +msgid "use gpu" +msgstr "usar gpu" + +#: ../contrib/enfuseAdvanced.lua:586 +msgid "use gpu during alignment" +msgstr "usa a gpu durante o alinhamento" + +#: ../contrib/enfuseAdvanced.lua:593 +msgid "image grid size" +msgstr "tamanho da grade de imagem" + +#: ../contrib/enfuseAdvanced.lua:594 +msgid "" +"break image into a rectangular grid \n" +"and attempt to find num control points in each section.\n" +"default: (5x5)" +msgstr "" +"quebra a imagem em uma grade retangular e \n" +"tenta encontrar um número de pontos de controle\n" +"em cada seção.\n" +"padrão: (5x5)" + +#: ../contrib/enfuseAdvanced.lua:610 +msgid "control points/grid" +msgstr "pontos de controle/grade" + +#: ../contrib/enfuseAdvanced.lua:611 +msgid "" +"number of control points (per grid, see option -g) \n" +"to create between adjacent images \n" +"default: (8)." +msgstr "" +"número de pontos de controle (por grade, veja a opção -g)\n" +"para criar entre imagens adjacentes \n" +"padrão: (8)" + +#: ../contrib/enfuseAdvanced.lua:627 +msgid "remove control points with error" +msgstr "remover pontos de controle com erro" + +#: ../contrib/enfuseAdvanced.lua:628 +msgid "" +"remove all control points with an error higher \n" +"than num pixels \n" +"default: (3)" +msgstr "" +"remove todos os pontos de controle com um erro superior\n" +"que um número de pixels\n" +"padrão: (3)" + +#: ../contrib/enfuseAdvanced.lua:644 +msgid "correlation threshold for control points" +msgstr "limiar de correlação para pontos de controle" + +#: ../contrib/enfuseAdvanced.lua:645 +msgid "" +"correlation threshold for identifying \n" +"control points \n" +"default: (0.9)." +msgstr "" +"limiar de correlação para identificar pontos\n" +"de controle\n" +"padrão: (0,9)" + +#: ../contrib/enfuseAdvanced.lua:659 +msgid "image fusion options" +msgstr "opções de fusão de imagem" + +#: ../contrib/enfuseAdvanced.lua:664 +msgid "exposure weight" +msgstr "peso da exposição" + +#: ../contrib/enfuseAdvanced.lua:665 +msgid "" +"set the relative weight of the well-exposedness criterion \n" +"as defined by the chosen exposure weight function. \n" +"increasing this weight relative to the others will\n" +" make well-exposed pixels contribute more to\n" +" the final output. \n" +"default: (1.0)" +msgstr "" +"configura o peso relativo do critério de boa exposição como\n" +"definido pela função de peso de exposição.\n" +"aumentar este peso relativo para outros fará com que\n" +"os pixels bem expostos contribuam mais para a saída\n" +"final.\n" +"padrão: (1,0)" + +#: ../contrib/enfuseAdvanced.lua:676 +msgid "saturation weight" +msgstr "peso da saturação" + +#: ../contrib/enfuseAdvanced.lua:677 +msgid "" +"set the relative weight of high-saturation pixels. \n" +"increasing this weight makes pixels with high \n" +"saturation contribute more to the final output. \n" +"default: (0.2)" +msgstr "" +"configura o peso relativo dos pixels altamente saturados.\n" +"aumentar este peso fará com que os pixels com alta saturação\n" +"contribuam mais para a saída final. " +"padrão: (0,2)" + +#: ../contrib/enfuseAdvanced.lua:688 +msgid "contrast weight" +msgstr "peso do contraste" + +#: ../contrib/enfuseAdvanced.lua:689 +msgid "" +"sets the relative weight of high local-contrast pixels. \n" +"default: (0.0)." +msgstr "" +"configura o peso relativo dos pixels com alto contraste local.\n" +"padrão: (0,0)" + +#: ../contrib/enfuseAdvanced.lua:700 +msgid "exposure optimum" +msgstr "exposição ótima" + +#: ../contrib/enfuseAdvanced.lua:701 +msgid "" +"determine at what normalized exposure value\n" +" the optimum exposure of the input images\n" +" is. this is, set the position of the maximum\n" +" of the exposure weight curve. use this \n" +"option to fine-tune exposure weighting. \n" +"default: (0.5)" +msgstr "" +"determina qual valor de exposição normalizado\n" +"é a exposição ótima da imagem de entrada.\n" +"isto é, define a posição do máximo de exposição\n" +"da curva de peso. use esta opção para ajustar o\n" +"peso da exposição.\n" +"padrão: (0,5)" + +#: ../contrib/enfuseAdvanced.lua:712 +msgid "exposure width" +msgstr "largura da exposição" + +#: ../contrib/enfuseAdvanced.lua:713 +msgid "" +"set the characteristic width (FWHM) of the exposure \n" +"weight function. low numbers give less weight to \n" +"pixels that are far from the user-defined \n" +"optimum and vice versa. use this option to \n" +"fine-tune exposure weighting. \n" +"default: (0.2)" +msgstr "" +"configura a largura característica (FWHM) da função de peso\n" +"da exposição. números baixos atribuem menos peso para os\n" +"pixels que estão longe do ótimo definido pelo usuário e vice-\n" +"versa. use esta opção para ajustar o peso da exposição.\n" +"padrão: (0,2)" + +#: ../contrib/enfuseAdvanced.lua:722 +msgid "hard mask" +msgstr "máscara dura" + +#: ../contrib/enfuseAdvanced.lua:724 +msgid "" +"force hard blend masks on the finest scale. this avoids \n" +"averaging of fine details (only), at the expense \n" +"of increasing the noise. this improves the \n" +"sharpness of focus stacks considerably.\n" +"default (soft mask)" +msgstr "" +"força máscaras de mesclagem duras na escala mais fina. isto\n" +"previne aproximação dos detalhes mais finos (somente), ao\n" +"custo de aumentar o ruído. isto melhora a nitidez do empilha-\n" +"mento de foco consideravelmente.\n" +"padrão (máscara suave)" + +#: ../contrib/enfuseAdvanced.lua:729 +msgid "save masks" +msgstr "salvar máscaras" + +#: ../contrib/enfuseAdvanced.lua:731 +msgid "" +"Save the generated weight masks to your home directory,\n" +"enblend saves masks as 8 bit grayscale, \n" +"i.e. single channel images. \n" +"for accuracy we recommend to choose a lossless format." +msgstr "" +"Salva as máscaras de peso geradas para sua pasta pessoal,\n" +"mescla máscaras salvas como tons de cinza de 8 bits, isto é,\n" +"imagens de canal simples.\n" +"para maior precisão, nós recomendamos escolher um formato\n" +"sem perdas." + +#: ../contrib/enfuseAdvanced.lua:738 +msgid "contrast window size" +msgstr "tamanho da janela de contraste" + +#: ../contrib/enfuseAdvanced.lua:739 +msgid "" +"set the window size for local contrast analysis. \n" +"the window will be a square of size × size pixels. \n" +"if given an even size, Enfuse will \n" +"automatically use the next odd number.\n" +"for contrast analysis size values larger \n" +"than 5 pixels might result in a \n" +"blurry composite image. values of 3 and \n" +"5 pixels have given good results on \n" +"focus stacks. \n" +"default: (5) pixels" +msgstr "" +"configura o tamanho da janela para a análise de contraste local.\n" +"a janela será um quadrado de tamanho x tamanho em pixels.\n" +"se fornecido um tamanho par, o script usará automaticamente\n" +"o próximo número ímpar.\n" +"valores de tamanho para análise de contraste maiores que\n" +"5 pixels podem resultar em uma imagem composta borrada.\n" +"valores de 3 e 5 pixels produzem bons resultados para empi-\n" +"lhamento de foco.\n" +"padrão: (5) pixels" + +#: ../contrib/enfuseAdvanced.lua:755 +msgid "contrast edge scale" +msgstr "escala de borda de contraste" + +#: ../contrib/enfuseAdvanced.lua:756 +msgid "" +"a non-zero value for EDGE-SCALE switches on the \n" +"Laplacian-of-Gaussian (LoG) edge detection algorithm.\n" +" edage-scale is the radius of the Gaussian used \n" +"in the search for edges. a positive LCE-SCALE \n" +"turns on local contrast enhancement (LCE) \n" +"before the LoG edge detection. \n" +"Default: (0.0) pixels." +msgstr "" +"um valor diferente de zero para a ESCALA DE BORDA alterna\n" +"o algoritmo de detecção de borda Laplaciano-de-Gaussiano (LoG).\n" +"a escala de borda é o raio do Gaussiano usado na busca por bordas.\n" +"uma escala LCE positiva ativa o melhoramento de contraste local (LCE)\n" +"antes da detecção de borda LoG.\n" +"Padrão: (0,0) pixels" + +#: ../contrib/enfuseAdvanced.lua:772 +msgid "contrast min curvature [%]" +msgstr "curvatura mín de contraste [%]" + +#: ../contrib/enfuseAdvanced.lua:773 +msgid "" +"define the minimum curvature for the LoG edge detection. Append a ‘%’ to " +"specify the minimum curvature relative to maximum pixel value in the source " +"image. Default: (0.0%)" +msgstr "" +"configura a curvatura mínima para a detecção de borda LoG. Adicionar um '%'" +" para " +"definir a curvatura mínima em relação ao valor máximo de pixel na imagem" +" fonte. " +"Padrão: (0,0%)" + +#: ../contrib/enfuseAdvanced.lua:787 +msgid "target file" +msgstr "arquivo alvo" + +#: ../contrib/enfuseAdvanced.lua:792 +msgid "tiff compression" +msgstr "compressão tiff" + +#: ../contrib/enfuseAdvanced.lua:793 +msgid "compression method for tiff files" +msgstr "método de compressão para arquivos tiff" + +#: ../contrib/enfuseAdvanced.lua:809 +msgid "jpeg compression" +msgstr "compressão jpeg" + +#: ../contrib/enfuseAdvanced.lua:810 +msgid "jpeg compression level" +msgstr "nível de compressão jpeg" + +#: ../contrib/enfuseAdvanced.lua:832 +msgid "file format" +msgstr "formato de arquivo" + +#: ../contrib/enfuseAdvanced.lua:833 +msgid "file format of the enfused final image" +msgstr "formato de arquivo da imagem final fundida" + +#: ../contrib/enfuseAdvanced.lua:853 +msgid "bit depth" +msgstr "profundidade de bits" + +#: ../contrib/enfuseAdvanced.lua:854 +msgid "bit depth of the enfused file" +msgstr "profundidade de bits do arquivo fundido" + +#: ../contrib/enfuseAdvanced.lua:868 +msgid "directory" +msgstr "pasta" + +#: ../contrib/enfuseAdvanced.lua:877 +msgid "" +"select the target directory for the fused image. \n" +"the filename is created automatically." +msgstr "" +"seleciona a pasta alvo para a imagem fundida.\n" +"o nome do arquivo é criado automaticamente." + +#: ../contrib/enfuseAdvanced.lua:882 +msgid "save to source image location" +msgstr "salvar para a localização da imagem fonte" + +#: ../contrib/enfuseAdvanced.lua:884 +msgid "" +"If checked ignores the location above and saves output image(s) to the same " +"location as the source images." +msgstr "" +"Se selecionado, ignora a localização acima e salva a(s) imagem(ns) de saída" +" na mesma " +"localização das imagens fonte." + +#: ../contrib/enfuseAdvanced.lua:891 +msgid "on conflict" +msgstr "no caso de conflito" + +#: ../contrib/enfuseAdvanced.lua:905 +msgid "auto import" +msgstr "importar automaticamente" + +#: ../contrib/enfuseAdvanced.lua:907 +msgid "import the image into darktable database when enfuse completes" +msgstr "" +"importa a imagem para a base de dados do darktable quando a fusão for" +" completada" + +#: ../contrib/enfuseAdvanced.lua:918 +msgid "Apply Style on Import" +msgstr "Aplicar estilo ao importar" + +#: ../contrib/enfuseAdvanced.lua:919 +msgid "Apply selected style on auto-import to newly created blended image" +msgstr "" +"Aplica o estilo selecionado ao importar automaticamente para a nova imagem" +" fundida criada" + +#: ../contrib/enfuseAdvanced.lua:938 +msgid "copy tags" +msgstr "copiar etiquetas" + +#: ../contrib/enfuseAdvanced.lua:940 +msgid "Copy tags from first image." +msgstr "Copia as etiquetas da primeira imagem." + +#: ../contrib/enfuseAdvanced.lua:947 +msgid "" +"Additional tags to be added on import. Seperate with commas, all spaces will " +"be removed" +msgstr "" +"Etiquetas adicionais a serem adicionadas ao importar. Separe-as com vírgulas," +" todos " +"os espaços serão removidos" + +#: ../contrib/enfuseAdvanced.lua:955 +msgid "active preset" +msgstr "predefinição ativa" + +#: ../contrib/enfuseAdvanced.lua:956 +msgid "preset to be loaded from or saved to" +msgstr "predefinição a ser carregada de ou salvada para" + +#: ../contrib/enfuseAdvanced.lua:970 +msgid "load fusion preset" +msgstr "carregar predefinição de fusão" + +#: ../contrib/enfuseAdvanced.lua:971 +msgid "load current fusion parameters from selected preset" +msgstr "" +"carrega parâmetros de fusão atuais a partir da predefinição selecionada" + +#: ../contrib/enfuseAdvanced.lua:975 +msgid "save to fusion preset" +msgstr "salvar para predefinição de fusão" + +#: ../contrib/enfuseAdvanced.lua:976 +msgid "save current fusion parameters to selected preset" +msgstr "salva os parâmetros de fusão atuais para a predefinição selecionada" + +#: ../contrib/enfuseAdvanced.lua:980 +msgid "create image variants from presets" +msgstr "criar variantes da imagem a partir das predefinições" + +#: ../contrib/enfuseAdvanced.lua:982 +msgid "" +"create multiple image variants based on the three different presets of the " +"specified type" +msgstr "" +"cria múltiplas variantes da imagem baseadas nas três diferentes predefinições" +" do tipo " +"especificado" + +#: ../contrib/enfuseAdvanced.lua:999 +msgid "create variants type" +msgstr "criar tipos de variantes" + +#: ../contrib/enfuseAdvanced.lua:1000 +msgid "preset type to be used when creating image variants" +msgstr "tipo de predefinição a ser usado ao criar variantes de imagens" + +#: ../contrib/enfuseAdvanced.lua:1039 +msgid "update" +msgstr "atualizar" + +#: ../contrib/enfuseAdvanced.lua:1040 +msgid "update the binary paths with current values" +msgstr "atualiza os caminhos dos binários com os valores atuais" + +#: ../contrib/enfuseAdvanced.lua:1120 +msgid "show options" +msgstr "mostrar opções" + +#: ../contrib/enfuseAdvanced.lua:1121 +msgid "show options for specified aspect of output" +msgstr "mostra as opções para o aspecto de saída especificado" + +#: ../contrib/enfuseAdvanced.lua:1142 +msgid "DRI or DFF image" +msgstr "imagem DRI ou DFF" diff --git a/locale/pt_BR/LC_MESSAGES/exportLUT.po b/locale/pt_BR/LC_MESSAGES/exportLUT.po new file mode 100644 index 00000000..3cac47b2 --- /dev/null +++ b/locale/pt_BR/LC_MESSAGES/exportLUT.po @@ -0,0 +1,62 @@ +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Marcus Gama , 2021. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-09-28 19:37-0300\n" +"PO-Revision-Date: 2021-09-30 19:25-0300\n" +"Last-Translator: Marcus Gama \n" +"Language-Team: Portuguese \n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Generator: Lokalize 21.08.1\n" + +#: ../contrib/exportLUT.lua:66 +msgid "Identity_file_chooser" +msgstr "Selecionar_arquiv_identidade" + +#: ../contrib/exportLUT.lua:72 +msgid "Export_location_chooser" +msgstr "Selecionar_localização_exportação" + +#: ../contrib/exportLUT.lua:78 +msgid "choose the identity haldclut file" +msgstr "selecione o arquivo halclut de identidade" + +#: ../contrib/exportLUT.lua:82 +msgid "choose the output location" +msgstr "selecione a localização de saída" + +#: ../contrib/exportLUT.lua:86 +msgid "WARNING: files may be silently overwritten" +msgstr "AVISO: os arquivos podem ser sobrescritos sem confirmação" + +#: ../contrib/exportLUT.lua:108 +msgid "Invalid identity lut file" +msgstr "Arquivo lut de identidade inválido" + +#: ../contrib/exportLUT.lua:110 +msgid "Exporting styles as haldCLUTs" +msgstr "Exportar estilos como haldCLUTs" + +#: ../contrib/exportLUT.lua:129 +msgid "Exported: " +msgstr "Exportado: " + +#: ../contrib/exportLUT.lua:131 +msgid "Done exporting haldCLUTs" +msgstr "Exportação de haldCLUTs feita" + +#: ../contrib/exportLUT.lua:141 +msgid "export haldclut" +msgstr "exportar haldclut" + +#: ../contrib/exportLUT.lua:166 +msgid "export" +msgstr "exportar" diff --git a/locale/pt_BR/LC_MESSAGES/ext_editor.po b/locale/pt_BR/LC_MESSAGES/ext_editor.po new file mode 100644 index 00000000..d863a5dd --- /dev/null +++ b/locale/pt_BR/LC_MESSAGES/ext_editor.po @@ -0,0 +1,129 @@ +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Marcus Gama , 2021. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-09-28 19:37-0300\n" +"PO-Revision-Date: 2021-10-01 19:07-0300\n" +"Last-Translator: Marcus Gama \n" +"Language-Team: Portuguese \n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Generator: Lokalize 21.08.1\n" + +#: ../contrib/ext_editor.lua:158 +msgid " editors configured" +msgstr " editores configurados" + +#: ../contrib/ext_editor.lua:167 +msgid "not a valid choice" +msgstr "não é uma escolha válida" + +#: ../contrib/ext_editor.lua:173 +msgid "please select one image" +msgstr "por favor, selecione uma imagem" + +#: ../contrib/ext_editor.lua:197 +msgid "file type not allowed" +msgstr "tipo de arquivo não permitido" + +#: ../contrib/ext_editor.lua:225 +msgid "error copying file " +msgstr "erro ao copiar arquivo " + +#: ../contrib/ext_editor.lua:232 +msgid "launching " +msgstr "iniciando " + +#: ../contrib/ext_editor.lua:235 +msgid "error launching " +msgstr "erro ao lançar " + +#: ../contrib/ext_editor.lua:328 +msgid "error moving file " +msgstr "erro ao mover arquivo " + +#: ../contrib/ext_editor.lua:337 +msgid "finished exporting" +msgstr "exportação terminada" + +#: ../contrib/ext_editor.lua:354 +msgid "external editors" +msgstr "editores externos" + +#: ../contrib/ext_editor.lua:380 ../contrib/ext_editor.lua:493 +msgid "edit with program " +msgstr "editar com programa " + +#: ../contrib/ext_editor.lua:382 ../contrib/ext_editor.lua:472 +msgid "collection" +msgstr "coleção" + +#: ../contrib/ext_editor.lua:393 +msgid "choose program" +msgstr "selecionar programa" + +#: ../contrib/ext_editor.lua:394 +msgid "select the external editor from the list" +msgstr "selecione o editor externo a partir da lista" + +#: ../contrib/ext_editor.lua:404 +msgid "edit" +msgstr "editar" + +#: ../contrib/ext_editor.lua:405 +msgid "open the selected image in external editor" +msgstr "abre a imagem selecionada no editor externo" + +#: ../contrib/ext_editor.lua:415 +msgid "edit a copy" +msgstr "editar uma cópia" + +#: ../contrib/ext_editor.lua:416 +msgid "create a copy of the selected image and open it in external editor" +msgstr "cria uma cópia da imagem selecionada e abre-a no editor externo" + +#: ../contrib/ext_editor.lua:425 +msgid "update list" +msgstr "atualizar lista" + +#: ../contrib/ext_editor.lua:426 +msgid "update list of programs if lua preferences are changed" +msgstr "atualiza lista de programas se as preferências do lua forem alteradas" + +#: ../contrib/ext_editor.lua:478 +msgid "executable for external editor " +msgstr "executável para o editor externo " + +#: ../contrib/ext_editor.lua:479 +msgid "select executable for external editor" +msgstr "seleciona o executável para o editor externo" + +#: ../contrib/ext_editor.lua:479 +msgid "(None)" +msgstr "(Nenhum)" + +#: ../contrib/ext_editor.lua:482 +msgid "name of external editor " +msgstr "nome do editor externo " + +#: ../contrib/ext_editor.lua:483 +msgid "friendly name of external editor" +msgstr "nome amigável do editor externo" + +#: ../contrib/ext_editor.lua:486 +msgid "show external editors in darkroom" +msgstr "mostrar editores externos na sala escura" + +#: ../contrib/ext_editor.lua:487 +msgid "" +"check to show external editors module also in darkroom (requires restart)" +msgstr "" +"ative para mostrar o módulo de editores externos também na sala escura" +" (precisa reiniciar)" diff --git a/locale/pt_BR/LC_MESSAGES/face_recognition.po b/locale/pt_BR/LC_MESSAGES/face_recognition.po new file mode 100644 index 00000000..242eb2e1 --- /dev/null +++ b/locale/pt_BR/LC_MESSAGES/face_recognition.po @@ -0,0 +1,135 @@ +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Marcus Gama , 2021. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-09-28 19:37-0300\n" +"PO-Revision-Date: 2021-10-01 19:12-0300\n" +"Last-Translator: Marcus Gama \n" +"Language-Team: Portuguese \n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Generator: Lokalize 21.08.1\n" + +#: ../contrib/face_recognition.lua:131 +msgid "export images" +msgstr "exportar imagens" + +#: ../contrib/face_recognition.lua:137 +#, lua-format +msgid "Exporting image %i of %i images" +msgstr "Exportando imagem %i de %i imagens" + +#: ../contrib/face_recognition.lua:207 +msgid "Face recognition not found" +msgstr "Reconhecimento de rosto não encontrado" + +#: ../contrib/face_recognition.lua:259 +msgid "Starting face recognition..." +msgstr "Iniciando reconhecimento de rosto..." + +#: ../contrib/face_recognition.lua:267 +msgid "Face recognition failed" +msgstr "Reconhecimento de rosto falhou" + +#: ../contrib/face_recognition.lua:269 +msgid "Face recognition finished" +msgstr "Reconhecimento de rosto terminado" + +#: ../contrib/face_recognition.lua:274 +msgid "processing results..." +msgstr "processando resultados..." + +#: ../contrib/face_recognition.lua:338 +msgid "face recognition complete" +msgstr "reconhecimento de rosto completo" + +#: ../contrib/face_recognition.lua:340 +msgid "image export failed" +msgstr "exportação da imagem falhou" + +#: ../contrib/face_recognition.lua:344 +msgid "no images selected" +msgstr "nenhuma imagem selecionada" + +#: ../contrib/face_recognition.lua:353 +msgid "face recognition" +msgstr "reconhecimento de rosto" + +#: ../contrib/face_recognition.lua:377 +msgid "tag to be used for unknown person" +msgstr "etiqueta a ser usada para pessoa desconhecida" + +#: ../contrib/face_recognition.lua:383 +msgid "tag to be used when no persons are found" +msgstr "etiqueta a ser usada quando nenhuma pessoa for encontrada" + +#: ../contrib/face_recognition.lua:389 ../contrib/face_recognition.lua:467 +msgid "tags of images to ignore" +msgstr "etiquetas de imagens para ignorar" + +#: ../contrib/face_recognition.lua:395 ../contrib/face_recognition.lua:469 +msgid "tag category" +msgstr "categoria da etiqueta" + +#: ../contrib/face_recognition.lua:400 +msgid "tolerance" +msgstr "tolerância" + +#: ../contrib/face_recognition.lua:412 +msgid "processor cores" +msgstr "núcleos de processador" + +#: ../contrib/face_recognition.lua:413 +msgid "number of processor cores to use, 0 for all" +msgstr "número de núcleos de processador a usar, 0 para todos" + +#: ../contrib/face_recognition.lua:424 +msgid "known image directory" +msgstr "pasta de imagem conhecida" + +#: ../contrib/face_recognition.lua:425 ../contrib/face_recognition.lua:471 +msgid "face data directory" +msgstr "pasta de dados de rosto" + +#: ../contrib/face_recognition.lua:434 +msgid "export image format" +msgstr "formato de exportação da imagem" + +#: ../contrib/face_recognition.lua:435 +msgid "format for exported images" +msgstr "formato para as imagens exportadas" + +#: ../contrib/face_recognition.lua:445 +msgid "maximum exported image width" +msgstr "largura máxima das imagens exportadas" + +#: ../contrib/face_recognition.lua:451 +msgid "maximum exported image height" +msgstr "altura máxima das imagens exportada" + +#: ../contrib/face_recognition.lua:463 +msgid "unknown person tag" +msgstr "etiqueta de pessoa desconhecida" + +#: ../contrib/face_recognition.lua:465 +msgid "no persons found tag" +msgstr "etiqueta de nenhuma pessoa encontrada" + +#: ../contrib/face_recognition.lua:478 +msgid "processing options" +msgstr "opções de processamento" + +#: ../contrib/face_recognition.lua:484 +msgid "width " +msgstr "largura " + +#: ../contrib/face_recognition.lua:489 +msgid "height " +msgstr "altura " diff --git a/locale/pt_BR/LC_MESSAGES/fujifilm_ratings.po b/locale/pt_BR/LC_MESSAGES/fujifilm_ratings.po new file mode 100644 index 00000000..497344d4 --- /dev/null +++ b/locale/pt_BR/LC_MESSAGES/fujifilm_ratings.po @@ -0,0 +1,30 @@ +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Marcus Gama , 2021. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-09-28 19:37-0300\n" +"PO-Revision-Date: 2021-09-30 19:26-0300\n" +"Last-Translator: Marcus Gama \n" +"Language-Team: Portuguese \n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Generator: Lokalize 21.08.1\n" + +#: ../contrib/fujifilm_ratings.lua:49 +msgid "exiftool not found" +msgstr "exiftool não encontrado" + +#: ../contrib/fujifilm_ratings.lua:62 +msgid "Using JPEG Rating: " +msgstr "Usar classificação JPEG: " + +#: ../contrib/fujifilm_ratings.lua:73 +msgid "Using RAF Rating: " +msgstr "Usar classificação RAF: " diff --git a/locale/pt_BR/LC_MESSAGES/geoJSON_export.po b/locale/pt_BR/LC_MESSAGES/geoJSON_export.po new file mode 100644 index 00000000..8ed5afda --- /dev/null +++ b/locale/pt_BR/LC_MESSAGES/geoJSON_export.po @@ -0,0 +1,77 @@ +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Marcus Gama , 2021. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-09-28 19:37-0300\n" +"PO-Revision-Date: 2021-10-01 19:16-0300\n" +"Last-Translator: Marcus Gama \n" +"Language-Team: Portuguese \n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Generator: Lokalize 21.08.1\n" + +#: ../contrib/geoJSON_export.lua:82 +#, lua-format +msgid "Export Image %i/%i" +msgstr "Exportar Imagem %i/%i" + +#: ../contrib/geoJSON_export.lua:87 +msgid "mkdir not found" +msgstr "mkdir não encontrado" + +#: ../contrib/geoJSON_export.lua:91 +msgid "convert not found" +msgstr "convert não encontrado" + +#: ../contrib/geoJSON_export.lua:95 +msgid "xdg-open not found" +msgstr "xdg-open não encontrado" + +#: ../contrib/geoJSON_export.lua:99 +msgid "xdg-user-dir not found" +msgstr "xdg-user-dir não encontrado" + +#: ../contrib/geoJSON_export.lua:310 +msgid "geoJSON export: Create an additional HTML file" +msgstr "exportar geoJSON: Criar um arquivo HTML adicional" + +#: ../contrib/geoJSON_export.lua:311 +msgid "Creates a HTML file, that loads the geoJASON file. (Needs a MapBox key" +msgstr "" +"Cria um arquivo HTML que carrega o arquivo geoJSON. (Precisa de uma chave" +" MapBox)" + +#: ../contrib/geoJSON_export.lua:316 +msgid "geoJSON export: MapBox Key" +msgstr "exportar geoJSON : chave MapBox" + +#: ../contrib/geoJSON_export.lua:317 +msgid "https://www.mapbox.com/studio/account/tokens" +msgstr "https://www.mapbox.com/studio/account/tokens" + +#: ../contrib/geoJSON_export.lua:322 +msgid "geoJSON export: Open geoJSON file after export" +msgstr "exportar geoJSON: Abrir o arquivo geoJSON após exportar" + +#: ../contrib/geoJSON_export.lua:323 +msgid "" +"Opens the geoJSON file after the export with the standard program for " +"geoJSON files" +msgstr "" +"Abre o arquivo geoJSON após a exportação com o programa padrão para arquivos" +" geoJSON" + +#: ../contrib/geoJSON_export.lua:335 +msgid "geoJSON export: Export directory" +msgstr "exportar geoJSON: Pasta de exportação" + +#: ../contrib/geoJSON_export.lua:336 +msgid "A directory that will be used to export the geoJSON files" +msgstr "Uma pasta que será usada para exportar os arquivos geoJSON" diff --git a/locale/pt_BR/LC_MESSAGES/geoToolbox.po b/locale/pt_BR/LC_MESSAGES/geoToolbox.po new file mode 100644 index 00000000..e5b28276 --- /dev/null +++ b/locale/pt_BR/LC_MESSAGES/geoToolbox.po @@ -0,0 +1,166 @@ +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Marcus Gama , 2021. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-09-28 19:37-0300\n" +"PO-Revision-Date: 2021-10-01 19:23-0300\n" +"Last-Translator: Marcus Gama \n" +"Language-Team: Portuguese \n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Generator: Lokalize 21.08.1\n" + +#: ../contrib/geoToolbox.lua:58 +msgid "Distance:" +msgstr "Distância:" + +#: ../contrib/geoToolbox.lua:62 +msgid "latitude:" +msgstr "latitude:" + +#: ../contrib/geoToolbox.lua:67 +msgid "longitude:" +msgstr "longitude:" + +#: ../contrib/geoToolbox.lua:72 +msgid "elevation:" +msgstr "elevação:" + +#: ../contrib/geoToolbox.lua:79 ../contrib/geoToolbox.lua:99 +msgid "GPS selection" +msgstr "seleção do GPS" + +#: ../contrib/geoToolbox.lua:302 +msgid "latitude: " +msgstr "latitude: " + +#: ../contrib/geoToolbox.lua:303 +msgid "longitude: " +msgstr "longitude: " + +#: ../contrib/geoToolbox.lua:304 +msgid "elevation: " +msgstr "elevação: " + +#: ../contrib/geoToolbox.lua:329 +msgid "gnome-maps not found" +msgstr "gnome-maps não encontrado" + +#: ../contrib/geoToolbox.lua:367 +msgid "curl not found" +msgstr "curl não encontrado" + +#: ../contrib/geoToolbox.lua:372 +msgid "jq not found" +msgstr "jq não encontrado" + +#: ../contrib/geoToolbox.lua:490 +msgid "m" +msgstr "m" + +#: ../contrib/geoToolbox.lua:492 +msgid "km" +msgstr "km" + +#: ../contrib/geoToolbox.lua:495 +#, lua-format +msgid "Distance: %.2f %s" +msgstr "Distância: %.2f %s" + +#: ../contrib/geoToolbox.lua:508 +msgid "export altitude CSV" +msgstr "exportar altitude para CSV" + +#: ../contrib/geoToolbox.lua:518 +msgid "Name of the exported file" +msgstr "Nome do arquivo exportado" + +#: ../contrib/geoToolbox.lua:523 +msgid "Start export" +msgstr "Iniciar exportação" + +#: ../contrib/geoToolbox.lua:584 +msgid "File created in " +msgstr "Arquivo criado em " + +#: ../contrib/geoToolbox.lua:614 ../contrib/geoToolbox.lua:746 +msgid "Calculate the distance from latitude and longitude in km" +msgstr "Calcula a distância da latitude e longitude em km" + +#: ../contrib/geoToolbox.lua:619 ../contrib/geoToolbox.lua:644 +#: ../contrib/geoToolbox.lua:751 +msgid "Select all images with GPS information" +msgstr "Selecionar todas as imagens com informação de GPS" + +#: ../contrib/geoToolbox.lua:621 ../contrib/geoToolbox.lua:650 +#: ../contrib/geoToolbox.lua:753 +msgid "Select all images without GPS information" +msgstr "Selecionar todas as imagens sem informação de GPS" + +#: ../contrib/geoToolbox.lua:643 +msgid "select geo images" +msgstr "selecionar imagens geoetiquetadas" + +#: ../contrib/geoToolbox.lua:649 +msgid "select non-geo images" +msgstr "selecionar imagens sem geoetiquetas" + +#: ../contrib/geoToolbox.lua:656 +msgid "copy GPS data" +msgstr "copiar dados do GPS" + +#: ../contrib/geoToolbox.lua:657 +msgid "Copy GPS data" +msgstr "Copiar dados do GPS" + +#: ../contrib/geoToolbox.lua:665 +msgid "paste GPS data" +msgstr "colar dados do GPS" + +#: ../contrib/geoToolbox.lua:666 +msgid "Paste GPS data" +msgstr "Colar dados do GPS" + +#: ../contrib/geoToolbox.lua:695 +msgid "open in Gnome Maps" +msgstr "abrir no Gnome Maps" + +#: ../contrib/geoToolbox.lua:696 +msgid "Open location in Gnome Maps" +msgstr "Abrir localização no Gnome Maps" + +#: ../contrib/geoToolbox.lua:702 +msgid "reverse geocode" +msgstr "geocódigo reverso" + +#: ../contrib/geoToolbox.lua:703 +msgid "This just shows the name of the location, but doesn't add it as tag" +msgstr "" +"Isto apenas mostra o nome da localização, mas não adiciona-a como uma etiqueta" + +#: ../contrib/geoToolbox.lua:707 +msgid "altitude CSV export" +msgstr "exportar altitude em CSV" + +#: ../contrib/geoToolbox.lua:712 +msgid "export altitude CSV file" +msgstr "exporta o arquivo CSV de altitude" + +#: ../contrib/geoToolbox.lua:713 +msgid "Create an altitude profile using the GPS data in the metadata" +msgstr "Cria um perfil de altitude usando os dados GPS nos metadados" + +#: ../contrib/geoToolbox.lua:740 +msgid "geoToolbox export: MapBox Key" +msgstr "exportar geoToolbox: chave MapBox" + +#: ../contrib/geoToolbox.lua:741 +msgid "https://www.mapbox.com/studio/account/tokens" +msgstr "https://www.mapbox.com/studio/account/tokens" diff --git a/locale/pt_BR/LC_MESSAGES/gimp.po b/locale/pt_BR/LC_MESSAGES/gimp.po new file mode 100644 index 00000000..3df96f73 --- /dev/null +++ b/locale/pt_BR/LC_MESSAGES/gimp.po @@ -0,0 +1,43 @@ +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Marcus Gama , 2021. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-09-28 19:37-0300\n" +"PO-Revision-Date: 2021-10-01 19:18-0300\n" +"Last-Translator: Marcus Gama \n" +"Language-Team: Portuguese \n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Generator: Lokalize 21.08.1\n" + +#: ../contrib/gimp.lua:111 +#, lua-format +msgid "Export Image %i/%i" +msgstr "Exportar Imagem %i/%i" + +#: ../contrib/gimp.lua:121 +msgid "GIMP not found" +msgstr "GIMP não encontrado" + +#: ../contrib/gimp.lua:144 +msgid "Launching GIMP..." +msgstr "Iniciando GIMP..." + +#: ../contrib/gimp.lua:207 +msgid "run detached" +msgstr "executar desassociado" + +#: ../contrib/gimp.lua:208 +msgid "don't import resulting image back into darktable" +msgstr "não importar a imagem resultante de volta para o darktable" + +#: ../contrib/gimp.lua:215 +msgid "Edit with GIMP" +msgstr "Editar com o GIMP" diff --git a/locale/pt_BR/LC_MESSAGES/harmonic_armature_guide.po b/locale/pt_BR/LC_MESSAGES/harmonic_armature_guide.po new file mode 100644 index 00000000..c409e880 --- /dev/null +++ b/locale/pt_BR/LC_MESSAGES/harmonic_armature_guide.po @@ -0,0 +1,22 @@ +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Marcus Gama , 2021. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-09-28 19:37-0300\n" +"PO-Revision-Date: 2021-09-30 19:26-0300\n" +"Last-Translator: Marcus Gama \n" +"Language-Team: Portuguese \n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Generator: Lokalize 21.08.1\n" + +#: ../contrib/harmonic_armature_guide.lua:76 +msgid "harmonic armature" +msgstr "armadura harmônica" diff --git a/locale/pt_BR/LC_MESSAGES/hugin.po b/locale/pt_BR/LC_MESSAGES/hugin.po new file mode 100644 index 00000000..3a7c57cb --- /dev/null +++ b/locale/pt_BR/LC_MESSAGES/hugin.po @@ -0,0 +1,67 @@ +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Marcus Gama , 2021. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-09-28 19:37-0300\n" +"PO-Revision-Date: 2021-10-01 19:26-0300\n" +"Last-Translator: Marcus Gama \n" +"Language-Team: Portuguese \n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Generator: Lokalize 21.08.1\n" + +#: ../contrib/hugin.lua:109 +msgid "hugin is not found, did you set the path?" +msgstr "hugin não encontrado, você configurou o caminho?" + +#: ../contrib/hugin.lua:165 +msgid "will try to stitch now" +msgstr "tentará pregar agora" + +#: ../contrib/hugin.lua:170 +msgid "creating pto file" +msgstr "criar arquivo pto" + +#: ../contrib/hugin.lua:174 +msgid "running assistant" +msgstr "rodar assistente" + +#: ../contrib/hugin.lua:182 +msgid "launching hugin" +msgstr "iniciar o hugin" + +#: ../contrib/hugin.lua:184 +msgid "unable to find command line tools, launching hugin" +msgstr "" +"não foi possível encontrar as ferramentas de linha de comando, iniciar o hugin" + +#: ../contrib/hugin.lua:192 +msgid "hugin isn't available." +msgstr "hugin não está disponível." + +#: ../contrib/hugin.lua:197 +msgid "hugin failed ..." +msgstr "hugin falhou..." + +#: ../contrib/hugin.lua:203 +msgid "importing file " +msgstr "importar arquivo " + +#: ../contrib/hugin.lua:229 +msgid " launch hugin gui" +msgstr " iniciar interface gráfica do hugin" + +#: ../contrib/hugin.lua:231 +msgid "launch hugin in gui mode" +msgstr "inicia o hugin no modo de interface gráfica" + +#: ../contrib/hugin.lua:237 +msgid "hugin panorama" +msgstr "hugin panorama" diff --git a/locale/pt_BR/LC_MESSAGES/image_stack.po b/locale/pt_BR/LC_MESSAGES/image_stack.po new file mode 100644 index 00000000..2421070c --- /dev/null +++ b/locale/pt_BR/LC_MESSAGES/image_stack.po @@ -0,0 +1,273 @@ +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Marcus Gama , 2021. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-09-28 19:37-0300\n" +"PO-Revision-Date: 2021-10-01 23:35-0300\n" +"Last-Translator: Marcus Gama \n" +"Language-Team: Portuguese \n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Generator: Lokalize 21.08.1\n" + +#: ../contrib/image_stack.lua:96 +msgid "image align options" +msgstr "opções de alinhamento da imagem" + +#: ../contrib/image_stack.lua:100 +msgid "image stack options" +msgstr "opções de empilhamento da imagem" + +#: ../contrib/image_stack.lua:104 +msgid "executable locations" +msgstr "localizações dos executáveis" + +#: ../contrib/image_stack.lua:129 +msgid "perform image alignment" +msgstr "realizar o alinhamento da imagem" + +#: ../contrib/image_stack.lua:131 +msgid "align the image stack before processing" +msgstr "alinha a pilha de imagem antes de processar" + +#: ../contrib/image_stack.lua:135 +msgid "optimize radial distortion for all images" +msgstr "otimizar a distorção radial para todas as imagens" + +#: ../contrib/image_stack.lua:137 +msgid "" +"optimize radial distortion for all images, \n" +"except for first" +msgstr "" +"otimiza a distorção radial para todas as imagens,\n" +"exceto para a primeira" + +#: ../contrib/image_stack.lua:141 +msgid "optimize field of view for all images" +msgstr "otimizar campo de visão para todas as imagens" + +#: ../contrib/image_stack.lua:143 +msgid "" +"optimize field of view for all images, except for first. \n" +"Useful for aligning focus stacks (DFF) with slightly \n" +"different magnification." +msgstr "" +"otimiza o campo de visão para todas as imagens, exceto para a primeira.\n" +"Útil para alinhar o empilhamento de foco (DFF) com uma ampliação \n" +"levemente diferente." + +#: ../contrib/image_stack.lua:147 +msgid "optimize image center shift for all images" +msgstr "otimizar o deslocamento do centro da imagem para todas as imagens" + +#: ../contrib/image_stack.lua:149 +msgid "" +"optimize image center shift for all images, \n" +"except for first." +msgstr "" +"otimiza o deslocamento do centro da imagem para todas as imagens, \n" +"exceto para a primeira." + +#: ../contrib/image_stack.lua:153 +msgid "auto crop the image" +msgstr "cortar automaticamente a imagem" + +#: ../contrib/image_stack.lua:155 +msgid "auto crop the image to the area covered by all images." +msgstr "" +"corta automaticamente a imagem para a área coberta por todas as imagens." + +#: ../contrib/image_stack.lua:159 +msgid "load distortion from lens database" +msgstr "carregar a distorção a partir da base de dados de lentes" + +#: ../contrib/image_stack.lua:161 +msgid "try to load distortion information from lens database" +msgstr "tenta carregar as informações de distorção da base de dados de lentes" + +#: ../contrib/image_stack.lua:165 +msgid "image grid size" +msgstr "tamanho da grade da imagem" + +#: ../contrib/image_stack.lua:166 +msgid "" +"break image into a rectangular grid \n" +"and attempt to find num control points in each section.\n" +"default: (5x5)" +msgstr "" +"quebra a imagem em uma grade retangular \n" +"e tenta encontrar o número de pontos de controle\n" +"em cada seção.\n" +"padrão: (5x5)" + +#: ../contrib/image_stack.lua:175 +msgid "control points/grid" +msgstr "grade/pontos de controle" + +#: ../contrib/image_stack.lua:176 +msgid "" +"number of control points (per grid, see option -g) \n" +"to create between adjacent images \n" +"default: (8)." +msgstr "" +"número de pontos de controle (por grade, veja a opção -g) \n" +"a criar entre imagens adjacentes\n" +"padrão: (8)" + +#: ../contrib/image_stack.lua:185 +msgid "remove control points with error" +msgstr "remover pontos de controle com erro" + +#: ../contrib/image_stack.lua:186 +msgid "" +"remove all control points with an error higher \n" +"than num pixels \n" +"default: (3)" +msgstr "" +"remove todos os pontos de controle com um erro maior \n" +"que um número de pixels \n" +"padrão: (3)" + +#: ../contrib/image_stack.lua:195 +msgid "correlation threshold for control points" +msgstr "limiar de correlação para pontos de controle" + +#: ../contrib/image_stack.lua:196 +msgid "" +"correlation threshold for identifying \n" +"control points \n" +"default: (0.9)." +msgstr "" +"limiar de correlação para identificar pontos\n" +"de controle\n" +"padrão: (0,9)" + +#: ../contrib/image_stack.lua:205 +msgid "select stack function" +msgstr "função de seleção de pilha" + +#: ../contrib/image_stack.lua:206 +msgid "" +"select function to be \n" +"applied to image stack" +msgstr "" +"função de seleção a ser aplicada\n" +"à pilha de imagens" + +#: ../contrib/image_stack.lua:215 +msgid "select output format" +msgstr "selecionar formato de saída" + +#: ../contrib/image_stack.lua:216 +msgid "choose the format for the resulting image" +msgstr "seleciona o formato para a imagem resultante" + +#: ../contrib/image_stack.lua:224 +msgid "tag source images used?" +msgstr "etiquetas das imagens fonte usadas?" + +#: ../contrib/image_stack.lua:226 +msgid "tag the source images used to create the output file?" +msgstr "etiquetas das imagens fonte usadas para criar o arquivo de saída?" + +#: ../contrib/image_stack.lua:261 +#, lua-format +msgid "Export Image %i/%i" +msgstr "Exportar Imagem %i/%i" + +#: ../contrib/image_stack.lua:454 +msgid "Unrecognized option to copy_image_attributes: " +msgstr "Opção não reconhecida para copy_image_attributes: " + +#: ../contrib/image_stack.lua:497 +msgid "ERROR: at least 2 images required for image stacking, exiting..." +msgstr "" +"ERRO: pelo menos 2 imagens são necessárias para empilhamento de imagens," +" saindo..." + +#: ../contrib/image_stack.lua:498 +msgid " image(s) selected, at least 2 required" +msgstr " imagem(ns) selecionada(s), pelo menos 2 necessárias" + +#: ../contrib/image_stack.lua:512 +msgid "aligning images..." +msgstr "alinhar imagens..." + +#: ../contrib/image_stack.lua:515 +msgid "images aligned" +msgstr "imagens alinhadas" + +#: ../contrib/image_stack.lua:521 +msgid "ERROR: image alignment failed" +msgstr "ERRO: alinhamento de imagem falhou" + +#: ../contrib/image_stack.lua:522 +msgid "image alignment failed" +msgstr "alinhamento de imagem falhou" + +#: ../contrib/image_stack.lua:527 +msgid "ERROR: align_image_stack not found" +msgstr "ERRO: align_image_stack não encontrado" + +#: ../contrib/image_stack.lua:528 +msgid "align_image_stack not found" +msgstr "align_image_stack não encontrado" + +#: ../contrib/image_stack.lua:542 +msgid "convert command is " +msgstr "comando convert é " + +#: ../contrib/image_stack.lua:543 +msgid "processing image stack" +msgstr "processar empilhamento de imagem" + +#: ../contrib/image_stack.lua:546 +msgid "image stack processed" +msgstr "empilhamento de imagem processado" + +#: ../contrib/image_stack.lua:551 +msgid "importing result" +msgstr "importar resultado" + +#: ../contrib/image_stack.lua:556 +msgid "Created with|image_stack" +msgstr "Criado com|image_stack" + +#: ../contrib/image_stack.lua:569 +msgid "tagging source images" +msgstr "etiquetando imagens fonte" + +#: ../contrib/image_stack.lua:570 +msgid "Source file|" +msgstr "Arquivo fonte |" + +#: ../contrib/image_stack.lua:577 +msgid "ERROR: image stack processing failed" +msgstr "ERRO: processamento de empilhamento de imagem falhou" + +#: ../contrib/image_stack.lua:581 +msgid "ERROR: convert executable not found" +msgstr "ERRO: executável do convert não encontrado" + +#: ../contrib/image_stack.lua:582 +msgid "convert executable not found" +msgstr "executável do convert não encontrado" + +#: ../contrib/image_stack.lua:594 +msgid "align image stack: use GPU for remaping" +msgstr "alinhar pilha de imagens: usar GPU para remapear" + +#: ../contrib/image_stack.lua:595 +msgid "set the GPU remapping for image align" +msgstr "definir o remapeamento de GPU para alinhamento de imagem" + +#: ../contrib/image_stack.lua:598 +msgid "image stack" +msgstr "empilhamento de imagem" diff --git a/locale/pt_BR/LC_MESSAGES/image_time.po b/locale/pt_BR/LC_MESSAGES/image_time.po new file mode 100644 index 00000000..d99ffb77 --- /dev/null +++ b/locale/pt_BR/LC_MESSAGES/image_time.po @@ -0,0 +1,244 @@ +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Marcus Gama , 2021. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-09-28 19:37-0300\n" +"PO-Revision-Date: 2021-10-02 05:09-0300\n" +"Last-Translator: Marcus Gama \n" +"Language-Team: Portuguese \n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Generator: Lokalize 21.08.1\n" + +#: ../contrib/image_time.lua:177 +msgid "Error: 2 images must be selected" +msgstr "Erro: 2 imagens devem ser selecionadas" + +#: ../contrib/image_time.lua:230 +msgid "unable to detect exiv2" +msgstr "não foi possível detectar exiv2" + +#: ../contrib/image_time.lua:251 ../contrib/image_time.lua:268 +msgid "unable to get information for " +msgstr "não foi possível obter informações para " + +#: ../contrib/image_time.lua:316 +msgid "reset time: no images selected" +msgstr "reiniciar tempo: nenhuma imagem selecionada" + +#: ../contrib/image_time.lua:317 +msgid "please select the images that need their time reset" +msgstr "" +"por favor, selecione as imagens que precisam que seu tempo seja reiniciado" + +#: ../contrib/image_time.lua:330 ../contrib/image_time.lua:355 +msgid "please select some images and try again" +msgstr "por favor, selecione algumas imagens e tente novamente" + +#: ../contrib/image_time.lua:334 ../contrib/image_time.lua:437 +#: ../contrib/image_time.lua:444 +msgid "subtract" +msgstr "subtrair" + +#: ../contrib/image_time.lua:407 +msgid "image time" +msgstr "tempo da imagem" + +#: ../contrib/image_time.lua:431 +msgid "years" +msgstr "anos" + +#: ../contrib/image_time.lua:431 +msgid "years to adjust by, 0 - ?" +msgstr "anos a ajustar, 0 - ?" + +#: ../contrib/image_time.lua:432 +msgid "months" +msgstr "meses" + +#: ../contrib/image_time.lua:433 +msgid "days" +msgstr "dias" + +#: ../contrib/image_time.lua:434 +msgid "hours" +msgstr "horas" + +#: ../contrib/image_time.lua:434 +msgid "hours to adjust by, 0-23" +msgstr "horas a ajustar, 0-23" + +#: ../contrib/image_time.lua:435 +msgid "minutes" +msgstr "minutos" + +#: ../contrib/image_time.lua:435 +msgid "minutes to adjust by, 0-59" +msgstr "minutos a ajustar, 0-59" + +#: ../contrib/image_time.lua:436 ../contrib/image_time.lua:443 +msgid "seconds" +msgstr "segundos" + +#: ../contrib/image_time.lua:436 +msgid "seconds to adjust by, 0-59" +msgstr "segundos a ajustar, 0-59" + +#: ../contrib/image_time.lua:437 ../contrib/image_time.lua:444 +msgid "add/subtract" +msgstr "adicionar/subtrair" + +#: ../contrib/image_time.lua:437 ../contrib/image_time.lua:444 +msgid "add or subtract time" +msgstr "adicionar ou subtrair tempo" + +#: ../contrib/image_time.lua:437 ../contrib/image_time.lua:444 +msgid "add" +msgstr "adicionar" + +#: ../contrib/image_time.lua:438 +msgid "year" +msgstr "ano" + +#: ../contrib/image_time.lua:438 +msgid "year to set, 1900 - now" +msgstr "ano a definir, 1900 - agora" + +#: ../contrib/image_time.lua:439 +msgid "month" +msgstr "mês" + +#: ../contrib/image_time.lua:439 +msgid "month to set, 1-12" +msgstr "mês a definir, 1-12" + +#: ../contrib/image_time.lua:440 +msgid "day" +msgstr "dia" + +#: ../contrib/image_time.lua:440 +msgid "day to set, 1-31" +msgstr "dia a definir, 1-31" + +#: ../contrib/image_time.lua:441 +msgid "hour" +msgstr "hora" + +#: ../contrib/image_time.lua:441 +msgid "hour to set, 0-23" +msgstr "hora a definir, 0-23" + +#: ../contrib/image_time.lua:442 +msgid "minute" +msgstr "minuto" + +#: ../contrib/image_time.lua:442 +msgid "minutes to set, 0-59" +msgstr "minuto a definir, 0-59" + +#: ../contrib/image_time.lua:443 +msgid "seconds to set, 0-59" +msgstr "segundos a definir, 0-59" + +#: ../contrib/image_time.lua:459 +msgid "Time difference between images in seconds" +msgstr "Diferença de tempo entre as imagens em segundos" + +#: ../contrib/image_time.lua:460 +msgid "Select 2 images and use the calculate button" +msgstr "Selecione 2 imagens e use o botão para calcular" + +#: ../contrib/image_time.lua:465 +msgid "Calculate" +msgstr "Calcular" + +#: ../contrib/image_time.lua:466 +msgid "calculate time difference between 2 images" +msgstr "calcula a diferença de tempo entre 2 imagens" + +#: ../contrib/image_time.lua:473 +msgid "synchronize image times" +msgstr "sincronizar tempos da imagem" + +#: ../contrib/image_time.lua:474 +msgid "apply the time difference from selected images" +msgstr "aplica a diferença de tempo a partir das imagens selecionadas" + +#: ../contrib/image_time.lua:484 ../contrib/image_time.lua:550 +msgid "adjust time" +msgstr "ajustar tempo" + +#: ../contrib/image_time.lua:485 +msgid "days, months, years" +msgstr "dias, meses, anos" + +#: ../contrib/image_time.lua:489 +msgid "hours, minutes, seconds" +msgstr "horas, minutos, segundos" + +#: ../contrib/image_time.lua:493 +msgid "adjustment direction" +msgstr "direção de ajuste" + +#: ../contrib/image_time.lua:496 +msgid "adjust" +msgstr "ajustar" + +#: ../contrib/image_time.lua:504 ../contrib/image_time.lua:551 +msgid "set time" +msgstr "definir tempo" + +#: ../contrib/image_time.lua:505 +msgid "date: " +msgstr "data: " + +#: ../contrib/image_time.lua:509 +msgid "time:" +msgstr "tempo: " + +#: ../contrib/image_time.lua:514 +msgid "set" +msgstr "definir" + +#: ../contrib/image_time.lua:522 +msgid "synchronize image time" +msgstr "sincronizar tempo da imagem" + +#: ../contrib/image_time.lua:523 +msgid "calculate difference between images" +msgstr "calcular a diferença entre imagens" + +#: ../contrib/image_time.lua:526 +msgid "apply difference" +msgstr "aplicar diferença" + +#: ../contrib/image_time.lua:532 +msgid "reset to original time" +msgstr "reiniciar para o tempo original" + +#: ../contrib/image_time.lua:535 +msgid "reset" +msgstr "reiniciar" + +#: ../contrib/image_time.lua:544 +msgid "mode" +msgstr "modo" + +#: ../contrib/image_time.lua:545 +msgid "select mode" +msgstr "selecionar modo" + +#: ../contrib/image_time.lua:552 +msgid "synchronize time" +msgstr "sincronizar tempo" + +#: ../contrib/image_time.lua:553 +msgid "reset time" +msgstr "reiniciar tempo" diff --git a/locale/pt_BR/LC_MESSAGES/kml_export.po b/locale/pt_BR/LC_MESSAGES/kml_export.po new file mode 100644 index 00000000..2ff81383 --- /dev/null +++ b/locale/pt_BR/LC_MESSAGES/kml_export.po @@ -0,0 +1,90 @@ +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Marcus Gama , 2021. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-09-28 19:37-0300\n" +"PO-Revision-Date: 2021-10-02 05:14-0300\n" +"Last-Translator: Marcus Gama \n" +"Language-Team: Portuguese \n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Generator: Lokalize 21.08.1\n" + +#: ../contrib/kml_export.lua:64 +#, lua-format +msgid "Export Image %i/%i" +msgstr "Exportar Imagem %i/%i" + +#: ../contrib/kml_export.lua:91 +msgid "magick not found" +msgstr "magick não encontrado" + +#: ../contrib/kml_export.lua:96 +msgid "xdg-user-dir not found" +msgstr "xdg-user-dir não encontrado" + +#: ../contrib/kml_export.lua:106 +msgid "zip not found" +msgstr "zip não encontrado" + +#: ../contrib/kml_export.lua:321 +msgid "KML export: Open KML file after export" +msgstr "exportar KML: Abrir arquivo Open KML após a exportação" + +#: ../contrib/kml_export.lua:322 ../contrib/kml_export.lua:329 +msgid "" +"Opens the KML file after the export with the standard program for KML files" +msgstr "" +"Abre o arquivo KML após a exportação com o programa padrão para arquivos KML" + +#: ../contrib/kml_export.lua:328 +msgid "KML export: Open KML/KMZ file after export" +msgstr "exportar KML: Abre arquivo KML/KMZ após a exportação" + +#: ../contrib/kml_export.lua:348 +msgid "KML export: Export directory" +msgstr "exportar KML: Pasta de exportação" + +#: ../contrib/kml_export.lua:349 +msgid "A directory that will be used to export the KML/KMZ files" +msgstr "Uma pasta que será usada para exportar os arquivos KML/KMZ" + +#: ../contrib/kml_export.lua:356 +msgid "KML export: ImageMagick binary Location" +msgstr "exportar KML: Localização do binário do ImageMagick" + +#: ../contrib/kml_export.lua:357 +msgid "Install location of magick[.exe]. Requires restart to take effect." +msgstr "" +"Localização de instalação do magick[.exe]. Precisa reiniciar para ter efeito." + +#: ../contrib/kml_export.lua:364 +msgid "KML export: Connect images with path" +msgstr "exportar KML: Conectar imagens com caminho" + +#: ../contrib/kml_export.lua:365 +msgid "connect all images with a path" +msgstr "conecta todas as imagens com um caminho" + +#: ../contrib/kml_export.lua:372 +msgid "KML export: Create KMZ file" +msgstr "exportar KML: Criar arquivo KMZ" + +#: ../contrib/kml_export.lua:373 +msgid "Compress all imeges to one KMZ file" +msgstr "Comprime todas as imagens para um arquivo KMZ" + +#: ../contrib/kml_export.lua:379 +msgid "KML Export" +msgstr "Exportar KML" + +#: ../contrib/kml_export.lua:381 +msgid "KML/KMZ Export" +msgstr "Exportar KML/KMZ" diff --git a/locale/pt_BR/LC_MESSAGES/passport_guide.po b/locale/pt_BR/LC_MESSAGES/passport_guide.po new file mode 100644 index 00000000..a69e95a0 --- /dev/null +++ b/locale/pt_BR/LC_MESSAGES/passport_guide.po @@ -0,0 +1,22 @@ +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Marcus Gama , 2021. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-09-28 19:37-0300\n" +"PO-Revision-Date: 2021-10-01 19:26-0300\n" +"Last-Translator: Marcus Gama \n" +"Language-Team: Portuguese \n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Generator: Lokalize 21.08.1\n" + +#: ../contrib/passport_guide.lua:90 +msgid "ISO 19794-5/ICAO 9309 passport" +msgstr "passaporte ISO 19794-5/ICAO 9309" diff --git a/locale/pt_BR/LC_MESSAGES/pdf_slideshow.po b/locale/pt_BR/LC_MESSAGES/pdf_slideshow.po new file mode 100644 index 00000000..0dab56fa --- /dev/null +++ b/locale/pt_BR/LC_MESSAGES/pdf_slideshow.po @@ -0,0 +1,70 @@ +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Marcus Gama , 2021. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-09-28 19:37-0300\n" +"PO-Revision-Date: 2021-10-02 05:16-0300\n" +"Last-Translator: Marcus Gama \n" +"Language-Team: Portuguese \n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Generator: Lokalize 21.08.1\n" + +#: ../contrib/pdf_slideshow.lua:55 +msgid "pdflatex not found" +msgstr "pdflatex não encontrado" + +#: ../contrib/pdf_slideshow.lua:71 +msgid "a pdf viewer" +msgstr "um visualizador de pdf" + +#: ../contrib/pdf_slideshow.lua:72 +msgid "can be an absolute pathname or the tool may be in the PATH" +msgstr "pode ser um caminho absoluto ou a ferramenta pode estar no PATH" + +#: ../contrib/pdf_slideshow.lua:76 ../contrib/pdf_slideshow.lua:103 +msgid "slideshow title" +msgstr "título da apresentação" + +#: ../contrib/pdf_slideshow.lua:80 +msgid "transition delay (s)" +msgstr "atraso da transição (s)" + +#: ../contrib/pdf_slideshow.lua:91 +msgid "include image title" +msgstr "incluir título da imagem" + +#: ../contrib/pdf_slideshow.lua:93 +msgid "whether to include the image title (if defined) into the slide" +msgstr "se deve ser incluído o título da imagem (se definido) no slide" + +#: ../contrib/pdf_slideshow.lua:97 +msgid "include image author" +msgstr "incluir autor da imagem" + +#: ../contrib/pdf_slideshow.lua:99 +msgid "whether to include the image author (if defined) into the slide" +msgstr "se deve ser incluído o autor da imagem (se definido) no slide" + +#: ../contrib/pdf_slideshow.lua:179 +msgid "pdf slideshow" +msgstr "apresentação do pdf" + +#: ../contrib/pdf_slideshow.lua:232 +msgid "problem running pdflatex" +msgstr "problema ao executar o pdflatex" + +#: ../contrib/pdf_slideshow.lua:233 ../contrib/pdf_slideshow.lua:243 +msgid "problem running " +msgstr "problema ao executar " + +#: ../contrib/pdf_slideshow.lua:242 +msgid "problem running pdf viewer" +msgstr "problema ao executar o visualizador de pdf" diff --git a/locale/pt_BR/LC_MESSAGES/photils.po b/locale/pt_BR/LC_MESSAGES/photils.po new file mode 100644 index 00000000..01b0e520 --- /dev/null +++ b/locale/pt_BR/LC_MESSAGES/photils.po @@ -0,0 +1,118 @@ +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Marcus Gama , 2021. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-09-28 19:37-0300\n" +"PO-Revision-Date: 2021-10-02 05:22-0300\n" +"Last-Translator: Marcus Gama \n" +"Language-Team: Portuguese \n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Generator: Lokalize 21.08.1\n" + +#: ../contrib/photils.lua:117 +msgid "get tags" +msgstr "obter etiquetas" + +#: ../contrib/photils.lua:148 +msgid "requires a restart to be applied" +msgstr "precisa reiniciar para ser aplicado" + +#: ../contrib/photils.lua:163 +msgid "min confidence value" +msgstr "valor mín de confiança" + +#: ../contrib/photils.lua:180 +msgid "" +"The suggested tags were not generated\n" +" for the currently selected image!" +msgstr "" +"As etiquetas sugeridas não serão geradas\n" +"para a imagem atualmente selecionada!" + +#: ../contrib/photils.lua:186 +#, lua-format +msgid " page %s of %s " +msgstr " página %s de %s " + +#: ../contrib/photils.lua:237 +msgid "Apply tag to image" +msgstr "Aplicar etiqueta à imagem" + +#: ../contrib/photils.lua:249 +msgid "Tags successfully attached to image" +msgstr "Etiquetas anexadas com sucesso à imagem" + +#: ../contrib/photils.lua:299 +#, lua-format +msgid "%s found %d tags for your image" +msgstr "%s encontrado %d etiquetas para sua imagem" + +#: ../contrib/photils.lua:315 +msgid "No image selected." +msgstr "Nenhuma imagem selecionada." + +#: ../contrib/photils.lua:319 +msgid "This plugin can only handle a single image." +msgstr "Este plugin pode manipular somente uma imagem por vez." + +#: ../contrib/photils.lua:326 +#, lua-format +msgid "%s failed, see terminal output for details" +msgstr "%s falhou, veja a saída do terminal para detalhes" + +#: ../contrib/photils.lua:334 +#, lua-format +msgid "no tags where found" +msgstr "nenhuma etiqueta encontrada" + +#: ../contrib/photils.lua:365 +#, lua-format +msgid "attach %d tags" +msgstr "anexar %d etiquetas" + +#: ../contrib/photils.lua:429 ../contrib/photils.lua:430 +msgid "photils-cli not found" +msgstr "photils-cli não encontrado" + +#: ../contrib/photils.lua:432 +msgid "" +"Select an image, click \"get tags\" and get \n" +"suggestions for tags." +msgstr "" +"Selecione uma imagem, clique em \"obter etiquetas\"\n" +"e obtenha sugestões para etiquetas." + +#: ../contrib/photils.lua:467 +msgid "photils: show confidence value" +msgstr "photils: mostrar valor de confiança" + +#: ../contrib/photils.lua:468 +msgid "if enabled, the confidence value for each tag is displayed" +msgstr "se ativo, o valor de confiança para cada etiqueta é exibido" + +#: ../contrib/photils.lua:474 +msgid "photils: use exported image for tag request" +msgstr "photils: usar imagem exportada para pedido de etiqueta" + +#: ../contrib/photils.lua:475 +msgid "" +"If enabled, the image passed to photils for tag suggestion is based on the " +"exported, already edited image. Otherwise, the embedded thumbnail of the RAW " +"file will be used for tag suggestion.The embedded thumbnail could speedup " +"the tag suggestion but can fail if the RAW file is not supported." +msgstr "" +"Se ativo, a imagem passada para o photils para a sugestão de etiquetas é" +" baseada na " +"exportada, a imagem já editada. Caso contrário, a miniatura embutida no" +" arquivo RAW " +"será usada para sugestão de etiquetas. A miniatura embutida pode acelerar a" +" sugestão " +"de etiqueta mas pode falhar se o arquivo RAW não for suportado." diff --git a/locale/pt_BR/LC_MESSAGES/quicktag.po b/locale/pt_BR/LC_MESSAGES/quicktag.po new file mode 100644 index 00000000..ef764259 --- /dev/null +++ b/locale/pt_BR/LC_MESSAGES/quicktag.po @@ -0,0 +1,82 @@ +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Marcus Gama , 2021. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-09-28 19:37-0300\n" +"PO-Revision-Date: 2021-10-02 05:25-0300\n" +"Last-Translator: Marcus Gama \n" +"Language-Team: Portuguese \n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Generator: Lokalize 21.08.1\n" + +#: ../contrib/quicktag.lua:78 +msgid "max. length of button labels" +msgstr "comprimento máximo dos rótulos de botão" + +#: ../contrib/quicktag.lua:79 +msgid "may range from 15 to 60 - needs a restart" +msgstr "pode ir de 16 à 60 - precisa reiniciar" + +#: ../contrib/quicktag.lua:92 +msgid "number of quicktag fields" +msgstr "número de campos de quicktag" + +#: ../contrib/quicktag.lua:93 +msgid "may range from 2 to 20 - needs a restart" +msgstr "pode ir de 2 à 20 - precisa reiniciar" + +#: ../contrib/quicktag.lua:133 +#, lua-format +msgid "quicktag %i is empty, please set a tag" +msgstr "quicktag %i está vazio, por favor defina uma etiqueta" + +#: ../contrib/quicktag.lua:148 +msgid "no images selected" +msgstr "nenhuma imagem selecionada" + +#: ../contrib/quicktag.lua:158 +#, lua-format +msgid "tag \"%s\" attached to %i image(s)" +msgstr "etiqueta \"%s\" anexada a %i imagem(ns)" + +#: ../contrib/quicktag.lua:179 +msgid "old tag" +msgstr "etiqueta antiga" + +#: ../contrib/quicktag.lua:180 +msgid "select the quicktag to replace" +msgstr "selecione a quicktag para substituir" + +#: ../contrib/quicktag.lua:225 ../contrib/quicktag.lua:303 +#, lua-format +msgid "quicktag %i" +msgstr "quicktag %i" + +#: ../contrib/quicktag.lua:240 ../contrib/quicktag.lua:264 +msgid "new tag" +msgstr "nova etiqueta" + +#: ../contrib/quicktag.lua:243 +msgid "enter your tag here" +msgstr "insira sua etiqueta aqui" + +#: ../contrib/quicktag.lua:247 +msgid "set tag" +msgstr "definir etiqueta" + +#: ../contrib/quicktag.lua:251 +msgid "new quicktag is empty!" +msgstr "nova quicktag está vazia!" + +#: ../contrib/quicktag.lua:255 +#, lua-format +msgid "quicktag \"%s\" replaced by \"%s\"" +msgstr "quicktag \"%s\" substituída por \"%s\"" diff --git a/locale/pt_BR/LC_MESSAGES/rename_images.po b/locale/pt_BR/LC_MESSAGES/rename_images.po new file mode 100644 index 00000000..edb543bf --- /dev/null +++ b/locale/pt_BR/LC_MESSAGES/rename_images.po @@ -0,0 +1,234 @@ +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Marcus Gama , 2021. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-09-28 19:37-0300\n" +"PO-Revision-Date: 2021-10-02 05:45-0300\n" +"Last-Translator: Marcus Gama \n" +"Language-Team: Portuguese \n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Generator: Lokalize 21.08.1\n" + +#: ../contrib/rename_images.lua:123 +msgid "unrecognized variable " +msgstr "variável não reconhecida " + +#: ../contrib/rename_images.lua:124 +msgid "unknown variable " +msgstr "variável desconhecida " + +#: ../contrib/rename_images.lua:143 +msgid "rename images" +msgstr "renomear imagens" + +#: ../contrib/rename_images.lua:175 +msgid "pattern is " +msgstr "padrão é " + +#: ../contrib/rename_images.lua:179 +msgid "renaming images" +msgstr "renomeando images" + +#: ../contrib/rename_images.lua:186 +msgid "unable to do variable substitution, exiting..." +msgstr "não foi possível a substituição de variável, saindo..." + +#: ../contrib/rename_images.lua:215 +msgid "renamed " +msgstr "renomeado " + +#: ../contrib/rename_images.lua:218 +msgid "please enter the new name or pattern" +msgstr "por favor, insira o novo nome ou padrão" + +#: ../contrib/rename_images.lua:222 +msgid "please select some images and try again" +msgstr "por favor, selecione algumas imagens e tente novamente" + +#: ../contrib/rename_images.lua:235 +msgid "$(ROLL_NAME) - film roll name\n" +msgstr "$(ROLL_NAME) - nome do rolo de filme\n" + +#: ../contrib/rename_images.lua:236 +msgid "$(FILE_FOLDER) - image file folder\n" +msgstr "$(FILE_FOLDER) - pasta do arquivo de imagem\n" + +#: ../contrib/rename_images.lua:237 +msgid "$(FILE_NAME) - image file name\n" +msgstr "$(FILE_NAME) - nome do arquivo de imagem\n" + +#: ../contrib/rename_images.lua:238 +msgid "$(FILE_EXTENSION) - image file extension\n" +msgstr "$(FILE_EXTENSION) - extensão do arquivo de imagem\n" + +#: ../contrib/rename_images.lua:239 +msgid "$(ID) - image id\n" +msgstr "$(ID) - id da imagem\n" + +#: ../contrib/rename_images.lua:240 +msgid "$(VERSION) - version number\n" +msgstr "$(VERSION) - número de versão\n" + +#: ../contrib/rename_images.lua:241 +msgid "$(SEQUENCE) - sequence number of selection\n" +msgstr "$(SEQUENCE) - número de sequência da seleção\n" + +#: ../contrib/rename_images.lua:242 +msgid "$(YEAR) - current year\n" +msgstr "$(YEAR) - ano atual\n" + +#: ../contrib/rename_images.lua:243 +msgid "$(MONTH) - current month\n" +msgstr "$(MONTH) - mês atual\n" + +#: ../contrib/rename_images.lua:244 +msgid "$(DAY) - current day\n" +msgstr "$(DAY) - dia atual\n" + +#: ../contrib/rename_images.lua:245 +msgid "$(HOUR) - current hour\n" +msgstr "$(HOUR) - hora atual\n" + +#: ../contrib/rename_images.lua:246 +msgid "$(MINUTE) - current minute\n" +msgstr "$(MINUTE) - minuto atual\n" + +#: ../contrib/rename_images.lua:247 +msgid "$(SECOND) - current second\n" +msgstr "$(SECOND) - segundo atual\n" + +#: ../contrib/rename_images.lua:248 +msgid "$(EXIF_YEAR) - EXIF year\n" +msgstr "$(EXIF_YEAR) - ano EXIF\n" + +#: ../contrib/rename_images.lua:249 +msgid "$(EXIF_MONTH) - EXIF month\n" +msgstr "$(EXIF_MONTH) - mês EXIF\n" + +#: ../contrib/rename_images.lua:250 +msgid "$(EXIF_DAY) - EXIF day\n" +msgstr "$(EXIF_DAY) - dia EXIF\n" + +#: ../contrib/rename_images.lua:251 +msgid "$(EXIF_HOUR) - EXIF hour\n" +msgstr "$(EXIF_HOUR) - hora EXIF\n" + +#: ../contrib/rename_images.lua:252 +msgid "$(EXIF_MINUTE) - EXIF minute\n" +msgstr "$(EXIF_MINUTE) - minuto EXIF\n" + +#: ../contrib/rename_images.lua:253 +msgid "$(EXIF_SECOND) - EXIF seconds\n" +msgstr "$(EXIF_SECOND) - segundo EXIF\n" + +#: ../contrib/rename_images.lua:254 +msgid "$(EXIF_ISO) - EXIF ISO\n" +msgstr "$(EXIF_ISO) - ISO EXIF\n" + +#: ../contrib/rename_images.lua:255 +msgid "$(EXIF_EXPOSURE) - EXIF exposure\n" +msgstr "$(EXIF_EXPOSURE) - exposição EXIF\n" + +#: ../contrib/rename_images.lua:256 +msgid "$(EXIF_EXPOSURE_BIAS) - EXIF exposure bias\n" +msgstr "$(EXIF_EXPOSURE_BIAS) - viés de exposição EXIF\n" + +#: ../contrib/rename_images.lua:257 +msgid "$(EXIF_APERTURE) - EXIF aperture\n" +msgstr "$(EXIF_APERTURE) - abertura EXIF\n" + +#: ../contrib/rename_images.lua:258 +msgid "$(EXIF_FOCAL_LENGTH) - EXIF focal length\n" +msgstr "$(EXIF_FOCAL_LENGTH) - distância focal EXIF\n" + +#: ../contrib/rename_images.lua:259 +msgid "$(EXIF_FOCUS_DISTANCE) - EXIF focus distance\n" +msgstr "$(EXIF_FOCUS_DISTANCE) - distância do foco EXIF\n" + +#: ../contrib/rename_images.lua:260 +msgid "$(EXIF_CROP) - EXIF crop\n" +msgstr "$(EXIF_CROP) - corte EXIF\n" + +#: ../contrib/rename_images.lua:261 +msgid "$(LONGITUDE) - longitude\n" +msgstr "$(LONGITUDE) - longitude\n" + +#: ../contrib/rename_images.lua:262 +msgid "$(LATITUDE) - latitude\n" +msgstr "$(LATITUDE) - latitude\n" + +#: ../contrib/rename_images.lua:263 +msgid "$(ELEVATION) - elevation\n" +msgstr "$(ELEVATION) - elevação\n" + +#: ../contrib/rename_images.lua:264 +msgid "$(STARS) - star rating\n" +msgstr "$(STARS) - classificação de estrelas\n" + +#: ../contrib/rename_images.lua:265 +msgid "$(LABELS) - color labels\n" +msgstr "$(LABELS) - etiquetas de cor\n" + +#: ../contrib/rename_images.lua:266 +msgid "$(MAKER) - camera maker\n" +msgstr "$(MAKER) - fabricante da câmera\n" + +#: ../contrib/rename_images.lua:267 +msgid "$(MODEL) - camera model\n" +msgstr "$(MODEL) - modelo da câmera\n" + +#: ../contrib/rename_images.lua:268 +msgid "$(LENS) - lens\n" +msgstr "$(LENS) - lente\n" + +#: ../contrib/rename_images.lua:269 +msgid "$(TITLE) - title from metadata\n" +msgstr "$(TITLE) - título a partir dos metadados\n" + +#: ../contrib/rename_images.lua:270 +msgid "$(DESCRIPTION) - description from metadata\n" +msgstr "$(DESCRIPTION) - descrição a partir dos metadados\n" + +#: ../contrib/rename_images.lua:271 +msgid "$(CREATOR) - creator from metadata\n" +msgstr "$(CREATOR) - autor a partir dos metadados\n" + +#: ../contrib/rename_images.lua:272 +msgid "$(PUBLISHER) - publisher from metadata\n" +msgstr "$(PUBLISHER) - editor a partir dos metadados\n" + +#: ../contrib/rename_images.lua:273 +msgid "$(RIGHTS) - rights from metadata\n" +msgstr "$(RIGHTS) - direitos autorais a partir dos metadados\n" + +#: ../contrib/rename_images.lua:274 +msgid "$(USERNAME) - username\n" +msgstr "$(USERNAME) - nome do usuário\n" + +#: ../contrib/rename_images.lua:275 +msgid "$(PICTURES_FOLDER) - pictures folder\n" +msgstr "$(PICTURES_FOLDER) - pasta de imagens\n" + +#: ../contrib/rename_images.lua:276 +msgid "$(HOME) - user's home directory\n" +msgstr "$(HOME) - pasta pessoal do usuário\n" + +#: ../contrib/rename_images.lua:277 +msgid "$(DESKTOP) - desktop directory" +msgstr "$(DESKTOP) - pasta da área de trabalho" + +#: ../contrib/rename_images.lua:278 +msgid "enter pattern $(FILE_FOLDER)/$(FILE_NAME)" +msgstr "insira o padrão $(FILE_FOLDER)/$(FILE_NAME)" + +#: ../contrib/rename_images.lua:288 +msgid "rename" +msgstr "renomear" diff --git a/locale/pt_BR/LC_MESSAGES/transfer_hierarchy.po b/locale/pt_BR/LC_MESSAGES/transfer_hierarchy.po new file mode 100644 index 00000000..b05fa153 --- /dev/null +++ b/locale/pt_BR/LC_MESSAGES/transfer_hierarchy.po @@ -0,0 +1,75 @@ +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Marcus Gama , 2021. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-09-28 19:37-0300\n" +"PO-Revision-Date: 2021-10-02 05:28-0300\n" +"Last-Translator: Marcus Gama \n" +"Language-Team: Portuguese \n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Generator: Lokalize 21.08.1\n" + +#: ../contrib/transfer_hierarchy.lua:153 +msgid "Lowest directory containing all selected images" +msgstr "Pasta de nível mais baixa contendo todas as imagens selecionadas" + +#: ../contrib/transfer_hierarchy.lua:256 +msgid "" +"transfer hierarchy: ERROR: existing root is out of sync -- click 'calculate' " +"to update" +msgstr "" +"transferir hierarquia: ERRO: raiz existente está fora de sincronia -- clique" +" 'calcular' para atualizar" + +#: ../contrib/transfer_hierarchy.lua:260 +msgid "transfer hierarchy: ERROR: destination not specified" +msgstr "transferir hierarquia: ERRO: destino não especificado" + +#: ../contrib/transfer_hierarchy.lua:270 +msgid "transfer hierarchy: ERROR: could not create directory: " +msgstr "transferir hierarquia: ERRO: não foi possível criar a pasta: " + +#: ../contrib/transfer_hierarchy.lua:275 +msgid "transfer hierarchy: ERROR: not a directory: " +msgstr "transferir hierarquia: ERRO: não é uma pasta: " + +#: ../contrib/transfer_hierarchy.lua:280 +msgid "transfer hierarchy: ERROR: could not create film: " +msgstr "transferir hierarquia: ERRO: não foi possível criar um filme: " + +#: ../contrib/transfer_hierarchy.lua:289 +#, lua-format +msgid "transfer hierarchy" +msgstr "transferir hierarquia" + +#: ../contrib/transfer_hierarchy.lua:327 +msgid "calculate" +msgstr "calcular" + +#: ../contrib/transfer_hierarchy.lua:331 +msgid "existing root" +msgstr "raiz existente" + +#: ../contrib/transfer_hierarchy.lua:336 +msgid "root of destination" +msgstr "raiz do destino" + +#: ../contrib/transfer_hierarchy.lua:341 +msgid "move" +msgstr "mover" + +#: ../contrib/transfer_hierarchy.lua:346 +msgid "copy" +msgstr "copiar" + +#: ../contrib/transfer_hierarchy.lua:347 +msgid "Copy all selected images" +msgstr "Copia todas as imagens selecionadas" diff --git a/locale/pt_BR/LC_MESSAGES/video_ffmpeg.po b/locale/pt_BR/LC_MESSAGES/video_ffmpeg.po new file mode 100644 index 00000000..9abc3cbc --- /dev/null +++ b/locale/pt_BR/LC_MESSAGES/video_ffmpeg.po @@ -0,0 +1,135 @@ +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Marcus Gama , 2021. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-09-28 19:37-0300\n" +"PO-Revision-Date: 2021-10-02 05:38-0300\n" +"Last-Translator: Marcus Gama \n" +"Language-Team: Portuguese \n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Generator: Lokalize 21.08.1\n" + +#: ../contrib/video_ffmpeg.lua:243 +msgid "framerate" +msgstr "taxa de quadros" + +#: ../contrib/video_ffmpeg.lua:244 +msgid "select framerate of output video" +msgstr "seleciona a taxa de quadros da saída de vídeo" + +#: ../contrib/video_ffmpeg.lua:251 +msgid "resolution" +msgstr "resolução" + +#: ../contrib/video_ffmpeg.lua:252 +msgid "select resolution of output video" +msgstr "seleciona a resolução da saída de vídeo" + +#: ../contrib/video_ffmpeg.lua:259 +msgid "codec" +msgstr "codec" + +#: ../contrib/video_ffmpeg.lua:260 +msgid "select codec" +msgstr "seleciona o codec" + +#: ../contrib/video_ffmpeg.lua:267 +msgid "format container" +msgstr "formato" + +#: ../contrib/video_ffmpeg.lua:268 +msgid "select format of output video" +msgstr "seleciona o formato da saída de vídeo" + +#: ../contrib/video_ffmpeg.lua:280 +msgid "output file destination" +msgstr "destino do arquivo de saída" + +#: ../contrib/video_ffmpeg.lua:281 +msgid "settings of output file destination and name" +msgstr "configurações do destino e nome do arquivo de saída" + +#: ../contrib/video_ffmpeg.lua:296 +msgid "Select export path" +msgstr "Selecionar caminho de exportação" + +#: ../contrib/video_ffmpeg.lua:298 +msgid "" +"select the target directory for the timelapse. \n" +"the filename is created automatically." +msgstr "" +"selecione a pasta alvo para o timelapse.\n" +"o nome do arquivo é criado automaticamente." + +#: ../contrib/video_ffmpeg.lua:305 +msgid "" +"if selected, output video will be placed in the same directory as first of " +"selected images" +msgstr "" +"se selecionado, o vídeo de saída será colocado na mesma pasta da primeira das" +" imagens " +"selecionadas" + +#: ../contrib/video_ffmpeg.lua:320 +msgid "override output file on conflict" +msgstr "sobrescrever arquivo de saída em caso de conflito" + +#: ../contrib/video_ffmpeg.lua:321 +msgid "if checked, in case of file name conflict, the file will be overwritten" +msgstr "se ativo, em caso de conflito de nome, o arquivo será sobrescrito" + +#: ../contrib/video_ffmpeg.lua:329 +msgid "" +"enter output file name without extension.\n" +"\n" +"You can use some placeholders:\n" +"- {time} - time in format HH-mm-ss\n" +"- {date} - date in foramt YYYY-mm-dd\n" +"- {first_file} - name of first input file\n" +"- {last_file} - name of last last_file" +msgstr "" +"insira o nome do arquivo de saída sem extensão.\n" +"\n" +"Você pode usar alguns coringas:\n" +"- {time} - tempo no formato HH-mm-ss\n" +"- {date} - data no formato AAAA-mm-dd\n" +"- {first_file} - nome do primeiro arquivo de entrada\n" +"- {last_file} - nome do último last_file" + +#: ../contrib/video_ffmpeg.lua:349 +msgid " open after export" +msgstr " abrir após exportar" + +#: ../contrib/video_ffmpeg.lua:350 +msgid "open video file after successful export" +msgstr "abre o arquivo de vídeo após ser exportado com sucesso" + +#: ../contrib/video_ffmpeg.lua:377 +msgid "export " +msgstr "exportar " + +#: ../contrib/video_ffmpeg.lua:433 +msgid "prepare merge process" +msgstr "preparar o processo de mesclagem" + +#: ../contrib/video_ffmpeg.lua:436 +msgid "ERROR: cannot create temp directory" +msgstr "ERRO: não foi possível criar a pasta temporária" + +#: ../contrib/video_ffmpeg.lua:448 +msgid "ERROR: cannot build image, see console for more info" +msgstr "" +"ERRO: não foi possível construir a imagem, veja o console para mais" +" informações" + +#: ../contrib/video_ffmpeg.lua:450 +msgid "SUCCESS" +msgstr "SUCESSO" From 2e521553bfe335a831af8725bc251c926b47fb23 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Fri, 22 Oct 2021 11:09:01 -0400 Subject: [PATCH 200/445] =?UTF-8?q?[rename=5Fimages]=20Added=20changed=20s?= =?UTF-8?q?uggested=20by=20Volker=20B=C3=B6dker=20to=20make=20sure=20=20?= =?UTF-8?q?=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20sequence=20was=204?= =?UTF-8?q?=20digits=20with=20leading=20zeros.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contrib/rename_images.lua | 49 ++++++++++++++++++++++++++++++++++----- 1 file changed, 43 insertions(+), 6 deletions(-) diff --git a/contrib/rename_images.lua b/contrib/rename_images.lua index 4ddf78f9..584ba31a 100644 --- a/contrib/rename_images.lua +++ b/contrib/rename_images.lua @@ -103,12 +103,49 @@ local function build_substitution_list(image, sequence, datetime, username, pic_ if image.purple then table.insert(colorlabels, "purple") end local labels = #colorlabels == 1 and colorlabels[1] or du.join(colorlabels, ",") local eyear,emon,eday,ehour,emin,esec = string.match(image.exif_datetime_taken, "(%d-):(%d-):(%d-) (%d-):(%d-):(%d-)$") - local replacements = {image.film,image.path,df.get_filename(image.filename),string.upper(df.get_filetype(image.filename)),image.id,image.duplicate_index, - sequence,datetime.year,string.format("%02d", datetime.month),string.format("%02d", datetime.day),string.format("%02d", datetime.hour), - string.format("%02d", datetime.min),string.format("%02d", datetime.sec),eyear,emon,eday,ehour,emin,esec,image.rating,labels, - image.exif_maker,image.exif_model,image.title,image.creator,image.publisher,image.rights,username,pic_folder,home,desktop, - image.exif_iso,image.exif_exposure,image.exif_exposure_bias,image.exif_aperture,image.exif_focus_distance,image.exif_focal_length, - image.longitude,image.latitude,image.elevation,image.exif_lens,image.description,image.exif_crop} + local replacements = {image.film, + image.path, + df.get_filename(image.filename), + string.upper(df.get_filetype(image.filename)), + image.id,image.duplicate_index, + string.format("%04d", sequence), + datetime.year, + string.format("%02d", datetime.month), + string.format("%02d", datetime.day), + string.format("%02d", datetime.hour), + string.format("%02d", datetime.min), + string.format("%02d", datetime.sec), + eyear, + emon, + eday, + ehour, + emin, + esec, + image.rating, + labels, + image.exif_maker, + image.exif_model, + image.title, + image.creator, + image.publisher, + image.rights, + username, + pic_folder, + home, + desktop, + image.exif_iso, + image.exif_exposure, + image.exif_exposure_bias, + image.exif_aperture, + image.exif_focus_distance, + image.exif_focal_length, + image.longitude, + image.latitude, + image.elevation, + image.exif_lens, + image.description, + image.exif_crop + } for i=1,#rename.placeholders,1 do rename.substitutes[rename.placeholders[i]] = replacements[i] end end From 8f414f783a07c62193e3ed000e0ebfb675807cae Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Fri, 22 Oct 2021 11:12:24 -0400 Subject: [PATCH 201/445] [Changelog] Updated with latest changes --- ChangeLog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/ChangeLog.md b/ChangeLog.md index c84cc31d..50468a9e 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,4 +1,5 @@ ## Changes from most recent to oldest +**22 Oct 2021 - wpferguson for Volker Bödker - make sure sequence is 4 digits in rename_images.lua** **31 Aug 2021 - wpferguson - remove styles hiding from AutoGrouper.lua** **02 Jul 2021 - wpferguson - merged API-7.0.0-dev branch to master** * API-7.0.0 is darktable 3.6 From aebd26d03ae2a9fd27c4b01c2b463eb35db620c3 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Mon, 27 Dec 2021 19:36:15 -0500 Subject: [PATCH 202/445] [lib/dtutils.lua] - Added deprecated function to use when deprecating scripts [contrib/rename-tags.lua] - Added deprecation warning --- contrib/rename-tags.lua | 1 + lib/dtutils.lua | 25 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/contrib/rename-tags.lua b/contrib/rename-tags.lua index d440c5f9..74d9bfed 100644 --- a/contrib/rename-tags.lua +++ b/contrib/rename-tags.lua @@ -34,6 +34,7 @@ local debug = require "darktable.debug" -- check API version du.check_min_api_version("7.0.0", "rename-tags") +du.deprecated("contrib/rename-tags.lua","darktable release 4.0") -- return data structure for script_manager diff --git a/lib/dtutils.lua b/lib/dtutils.lua index 1b06a153..0a6d4416 100644 --- a/lib/dtutils.lua +++ b/lib/dtutils.lua @@ -330,4 +330,29 @@ function dtutils.find_image_by_id(imgid) end end +dtutils.libdoc.functions["deprecated"] = { + Name = [[deprecated]], + Synopsis = [[print deprecation warning]], + Usage = [[local du = require "lib/dtutils" + + du.deprecated(script_name, removal_string) + script_name - name of the script being deprecated + removal_strubg - a string explaining when the script will be removed]], + Description = [[deprecated prints an error message saying the script is deprecated and when it will be removed]], + Return_Value = [[]], + Limitations = [[]], + Example = [[local du = require "lib/dtutils" + du.deprecated("contrib/rename-tags.lua", "darktable release 4.0")]], + See_Also = [[]], + Reference = [[]], + License = [[]], + Copyright = [[]], +} + +function dtutils.deprecated(script_name, removal_string) + dt.print_toast("WARNING: " .. script_name .. " is deprecated and will be removed in " .. removal_string) + dt.print_error("WARNING: " .. script_name .. " is deprecated and will be removed in " .. removal_string) +end + + return dtutils From 79678fd82f3ae1171d1b1edcca38a9e2c0b41cb1 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Tue, 28 Dec 2021 20:45:50 -0500 Subject: [PATCH 203/445] [lib/dtutils/file.lua] replaced deprecated "which" call with recommended "command -v" call to check the existence of a program --- lib/dtutils/file.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/dtutils/file.lua b/lib/dtutils/file.lua index 28bb9c4b..c3174c7c 100644 --- a/lib/dtutils/file.lua +++ b/lib/dtutils/file.lua @@ -191,7 +191,7 @@ end local function _search_for_bin_nix(bin) local result = false - local p = io.popen("which " .. bin) + local p = io.popen("command -v " .. bin) local output = p:read("*a") p:close() if string.len(output) > 0 then From 3070ca0bc4220f774fa63fc9925673e9e431fbd1 Mon Sep 17 00:00:00 2001 From: Christian Mandel Date: Sun, 9 Jan 2022 15:46:29 +0100 Subject: [PATCH 204/445] Added tooltip to filter manager to better match new import scheme. --- official/import_filter_manager.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/official/import_filter_manager.lua b/official/import_filter_manager.lua index e27a1f7f..c648c1a4 100644 --- a/official/import_filter_manager.lua +++ b/official/import_filter_manager.lua @@ -45,6 +45,7 @@ local filter_dropdown = dt.new_widget("combobox") { label = "import filter", editable = false, + tooltip = "import filters are applied after completion of the import dialog", changed_callback = function(widget) dt.preferences.write("import_filter_manager", "active_filter", "string", widget.value) From f38c14d6b529a10fb3d73f58142459ae9f13ab7f Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Wed, 12 Jan 2022 14:53:02 -0500 Subject: [PATCH 205/445] Updated documentation --- ChangeLog.md | 5 +++++ README.md | 1 + 2 files changed, 6 insertions(+) diff --git a/ChangeLog.md b/ChangeLog.md index 50468a9e..39624996 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,4 +1,9 @@ ## Changes from most recent to oldest +**12 Jan 2022 - wpferguson - Documented contrib/rename_images.lua** +**28 Dec 2021 - wpferguson - Replaced deprecated _which_ command with _command -v_ in lib/dtutils/file.lua** +**12 Dec 2021 - wpferguson** +* Added deprecated function to library +* Added deprecation warning to contrib/rename-tags.lua **22 Oct 2021 - wpferguson for Volker Bödker - make sure sequence is 4 digits in rename_images.lua** **31 Aug 2021 - wpferguson - remove styles hiding from AutoGrouper.lua** **02 Jul 2021 - wpferguson - merged API-7.0.0-dev branch to master** diff --git a/README.md b/README.md index 19a2c952..266a6ba2 100644 --- a/README.md +++ b/README.md @@ -62,6 +62,7 @@ Name|Standalone|OS |Purpose [photils](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/photils)|No|LM|Automatic tag suggestions for your images [quicktag](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/quicktag)|Yes|LMW|Create shortcuts for quickly applying tags [rate_group](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/rate_group)|Yes|LMW|Apply or remove a star rating from grouped images +[rename_images](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/rename_images)|Yes|LMW|Rename single or multiple images [rename-tags](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/rename-tags)|Yes|LMW|Change a tag name [RL_out_sharp](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/RL_out_sharp)|No|LW|Output sharpening using GMic (Richardson-Lucy algorithm) [select_untagged](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/select_untagged)|Yes|LMW|Enable selection of untagged images From 4fb8b97084d7b36f967568c767072d1494d67409 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Wed, 12 Jan 2022 14:57:57 -0500 Subject: [PATCH 206/445] fix changelog formatting --- ChangeLog.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ChangeLog.md b/ChangeLog.md index 39624996..a38901d8 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,11 +1,17 @@ ## Changes from most recent to oldest + **12 Jan 2022 - wpferguson - Documented contrib/rename_images.lua** + **28 Dec 2021 - wpferguson - Replaced deprecated _which_ command with _command -v_ in lib/dtutils/file.lua** + **12 Dec 2021 - wpferguson** * Added deprecated function to library * Added deprecation warning to contrib/rename-tags.lua + **22 Oct 2021 - wpferguson for Volker Bödker - make sure sequence is 4 digits in rename_images.lua** + **31 Aug 2021 - wpferguson - remove styles hiding from AutoGrouper.lua** + **02 Jul 2021 - wpferguson - merged API-7.0.0-dev branch to master** * API-7.0.0 is darktable 3.6 * breaking changes From 2bc55d00bb7e10b3de5ab16bcd4d3bde42c0af33 Mon Sep 17 00:00:00 2001 From: Dan Torop Date: Sun, 13 Feb 2022 22:14:57 -0500 Subject: [PATCH 207/445] fujifilm_dynamic_range: only load if exiftool present Fail to load if exiftool binary is not present. This may be better than silently (in UI) failing to read dyanmic range data. --- contrib/fujifilm_dynamic_range.lua | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/contrib/fujifilm_dynamic_range.lua b/contrib/fujifilm_dynamic_range.lua index c48d7146..68694ea3 100644 --- a/contrib/fujifilm_dynamic_range.lua +++ b/contrib/fujifilm_dynamic_range.lua @@ -2,7 +2,7 @@ Compensate for Fujifilm raw files made using "dynamic range". -Copyright (C) 2021 Dan Torop +Copyright (C) 2021, 2022 Dan Torop This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -116,6 +116,11 @@ local function destroy() dt.destroy_event("fujifilm_dr", "post-import-image") end +if not df.check_if_bin_exists("exiftool") then + dt.print_log("Please install exiftool to use fujifilm_dynamic_range") + error "[fujifilm_dynamic_range] exiftool not found" +end + dt.register_event("fujifilm_dr", "post-import-image", detect_dynamic_range) From 56b40a80ac2c0b019e9f1495969e0b4d3a68802c Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Wed, 16 Mar 2022 13:10:06 -0400 Subject: [PATCH 208/445] [README.md] fix links to documentation --- README.md | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 266a6ba2..9d58d0e5 100644 --- a/README.md +++ b/README.md @@ -34,29 +34,29 @@ These scripts are contributed by users. They are meant to have an "owner", i.e. Name|Standalone|OS |Purpose ----|:--------:|:---:|------- -[AutoGrouper](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/AutoGrouper)|Yes|LMW|Group images together by time +[AutoGrouper](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/autogrouper)|Yes|LMW|Group images together by time [autostyle](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/autostyle)|Yes|LMW|Automatically apply styles on import -[clear_GPS](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/clear_GPS)|Yes|LMW|Reset GPS information for selected images -[CollectHelper](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/CollectHelper)|Yes|LMW|Add buttons to selected images module to manipulate the collection +[clear_GPS](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/clear_gps)|Yes|LMW|Reset GPS information for selected images +[CollectHelper](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/collecthelper)|Yes|LMW|Add buttons to selected images module to manipulate the collection [copy_attach_detach_tags](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/copy_attach_detach_tags)|Yes|LMW|Copy and paste tags from/to images [cr2hdr](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/cr2hdr)|Yes|L|Process image created with Magic Lantern Dual ISO -[enfuseAdvanced](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/enfuseAdvanced)|No|LMW|Merge multiple images into Dynamic Range Increase (DRI) or Depth From Focus (DFF) images -[exportLUT](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/exportLUT)|Yes|LMW|Create a LUT from a style and export it +[enfuseAdvanced](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/enfuseadvanced)|No|LMW|Merge multiple images into Dynamic Range Increase (DRI) or Depth From Focus (DFF) images +[exportLUT](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/exportlut)|Yes|LMW|Create a LUT from a style and export it [ext_editor](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/ext_editor)|No|LW|Export pictures to collection and edit them with up to nine user-defined external editors [face_recognition](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/face_recognition)|No|LM|Identify and tag images using facial recognition [fujifilm_dynamic_range](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/fujifilm_dynamic_range)|No|LMW|Correct fujifilm exposure based on exposure bias camera setting [fujifilm_ratings](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/fujifilm_ratings)|No|LM|Support importing Fujifilm ratings -[geoJSON_export](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/geoJSON_export)|No|L|Create a geo JSON script with thumbnails for use in ... -[geoToolbox](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/geoToolbox)|No|LMW|A toolbox of geo functions +[geoJSON_export](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/geojson_export)|No|L|Create a geo JSON script with thumbnails for use in ... +[geoToolbox](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/geotoolbox)|No|LMW|A toolbox of geo functions [gimp](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/gimp)|No|LMW|Open an image in GIMP for editing and return the result [gpx_export](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/gpx_export)|No|LMW|Export a GPX track file from selected images GPS data -[HDRMerge](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/HDRMerge)|No|LMW|Combine the selected images into an HDR DNG and return the result +[HDRMerge](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/hdrmerge)|No|LMW|Combine the selected images into an HDR DNG and return the result [hugin](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/hugin)|No|LMW|Combine selected images into a panorama and return the result [image_stack](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/image_stack)|No|LMW|Combine a stack of images to remove noise or transient objects [image_time](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/image_time)|Yes|LMW|Adjust the EXIF image time [kml_export](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/kml_export)|No|L|Export photos with a KML file for usage in Google Earth -[LabelsToTags](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/LabelsToTags)|Yes|LMW|Apply tags based on color labels and ratings -[OpenInExplorer](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/OpenInExplorer)|No|LMW|Open the selected images in the system file manager +[LabelsToTags](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/labelstotags)|Yes|LMW|Apply tags based on color labels and ratings +[OpenInExplorer](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/openinexplorer)|No|LMW|Open the selected images in the system file manager [passport_guide](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/passport_guide)|Yes|LMW|Add passport cropping guide to darkroom crop tool [pdf_slideshow](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/pdf_slideshow)|No|LM|Export images to a PDF slideshow [photils](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/photils)|No|LM|Automatic tag suggestions for your images @@ -64,7 +64,7 @@ Name|Standalone|OS |Purpose [rate_group](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/rate_group)|Yes|LMW|Apply or remove a star rating from grouped images [rename_images](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/rename_images)|Yes|LMW|Rename single or multiple images [rename-tags](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/rename-tags)|Yes|LMW|Change a tag name -[RL_out_sharp](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/RL_out_sharp)|No|LW|Output sharpening using GMic (Richardson-Lucy algorithm) +[RL_out_sharp](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/rl_out_sharp)|No|LW|Output sharpening using GMic (Richardson-Lucy algorithm) [select_untagged](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/select_untagged)|Yes|LMW|Enable selection of untagged images [slideshowMusic](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/slideshowMusic)|No|L|Play music during a slideshow [transfer_hierarchy](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/transfer_hierarchy)|Yes|LMW|Image move/copy preserving directory hierarchy @@ -78,14 +78,14 @@ Name|Standalone|OS |Purpose ----|:--------:|:---:|------- [api_version](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/api_version)|Yes|LMW|Print the current API version [darkroom_demo](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/darkroom_demo)|Yes|LMW|Demonstrate changing images in darkoom -[gettextExample](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/gettextExample)|Yes|LM|How to use translation +[gettextExample](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/gettextexample)|Yes|LM|How to use translation [hello_world](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/hello_world)|Yes|LMW|Prints hello world when darktable starts [lighttable_demo](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/lighttable_demo)|Yes|LMW|Demonstrate controlling lighttable mode, zoom, sorting and filtering -[moduleExample](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/moduleExample)|Yes|LMW|How to create a lighttable module +[moduleExample](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/moduleexample)|Yes|LMW|How to create a lighttable module [multi_os](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/multi_os)|No|LMW|How to create a cross platform script that calls an external executable [panels_demo](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/panels_demo)|Yes|LMW|Demonstrate hiding and showing darktable panels -[preferenceExamples](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/preferenceExamples)|Yes|LMW|How to use preferences in a script -[printExamples](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/printExamples)|Yes|LMW|How to use various print functions from a script +[preferenceExamples](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/preferenceexamples)|Yes|LMW|How to use preferences in a script +[printExamples](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/printexamples)|Yes|LMW|How to use various print functions from a script [running_os](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/running_os)|Yes|LMW|Print out the running operating system ### Tools From b061f27e7af938a5126498839f08e880c139b53a Mon Sep 17 00:00:00 2001 From: manu-p Date: Mon, 27 Jun 2022 17:36:47 +0200 Subject: [PATCH 209/445] OpenInExplorer fr_FR translation --- locale/fr_FR/LC_MESSAGES/OpenInExplorer.po | 85 ++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 locale/fr_FR/LC_MESSAGES/OpenInExplorer.po diff --git a/locale/fr_FR/LC_MESSAGES/OpenInExplorer.po b/locale/fr_FR/LC_MESSAGES/OpenInExplorer.po new file mode 100644 index 00000000..02109e06 --- /dev/null +++ b/locale/fr_FR/LC_MESSAGES/OpenInExplorer.po @@ -0,0 +1,85 @@ +msgid "" +msgstr "" +"Project-Id-Version: \n" +"POT-Creation-Date: 2022-06-27 17:22+0200\n" +"PO-Revision-Date: 2022-06-27 17:36+0200\n" +"Last-Translator: Manuel PINTOR \n" +"Language-Team: \n" +"Language: fr_FR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 2.3\n" +"X-Poedit-Basepath: ../../../contrib\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Poedit-SearchPath-0: OpenInExplorer.lua\n" + +#: OpenInExplorer.lua:79 +msgid "" +"OpenInExplorer plug-in only supports Linux, macOS, and Windows at this time" +msgstr "" +"Le script OpenInExplorer ne fonctionne que sur Linux, macOS et Windows pour " +"le moment" + +#: OpenInExplorer.lua:95 +msgid "" +"No links directory selected.\n" +"Please check the dt preferences (lua options)" +msgstr "" +"Aucun répertoire de liens sélectionné.\n" +"Voir dans les préférences dt > options lua" + +#: OpenInExplorer.lua:99 +#, lua-format +msgid "" +"Links directory '%s' not found.\n" +"Please check the dt preferences (lua options)" +msgstr "" +"Répertoire de liens '%s' inexistant.\n" +"Voir dans les préférences dt > options lua" + +#: OpenInExplorer.lua:156 +msgid "Failed to create links. Missing rights?" +msgstr "Erreur de création de liens. Droits insuffisants ?" + +#: OpenInExplorer.lua:172 +msgid "Please select an image" +msgstr "Sélectionner une image SVP" + +#: OpenInExplorer.lua:178 +msgid "Please select fewer images (max. 15)" +msgstr "Sélectionner moins d'images SVP (max. 15)" + +#: OpenInExplorer.lua:203 +msgid "show in file explorer" +msgstr "afficher dans le gestionnaire de fichiers" + +#: OpenInExplorer.lua:205 +msgid "Open the file manager at the selected image's location" +msgstr "Ouvre le gestionnaire de fichiers à l'endroit de l'image sélectionnée" + +#: OpenInExplorer.lua:212 +msgid "OpenInExplorer: linked files directory" +msgstr "OpenInExplorer : répertoire des fichiers liés" + +#: OpenInExplorer.lua:213 +msgid "" +"Directory to store the links to the file names. Requires restart to take " +"effect" +msgstr "" +"Répertoire dans lequel enregistrer les liens sur les fichiers. Nécessite un " +"redémarrage de dt" + +#: OpenInExplorer.lua:216 +msgid "Select directory" +msgstr "Sélectionner un répertoire" + +#: OpenInExplorer.lua:222 +msgid "OpenInExplorer: use links" +msgstr "OpenInExplorer : utiliser des liens" + +#: OpenInExplorer.lua:223 +msgid "Use links instead of multiple windows. Requires restart to take effect" +msgstr "" +"Utiliser des liens plutôt que de multiples fenêtres. Nécessite un " +"redémarrage de dt" From b11f43e903814c9164fa0cd13777028991029784 Mon Sep 17 00:00:00 2001 From: Maurizio Paglia Date: Thu, 14 Jul 2022 18:43:02 +0200 Subject: [PATCH 210/445] Added Italian translations --- .../it_IT/LC_MESSAGES/executable_manager.po | 62 ++++++ locale/it_IT/LC_MESSAGES/script_manager.po | 190 ++++++++++++++++++ 2 files changed, 252 insertions(+) create mode 100644 locale/it_IT/LC_MESSAGES/executable_manager.po create mode 100644 locale/it_IT/LC_MESSAGES/script_manager.po diff --git a/locale/it_IT/LC_MESSAGES/executable_manager.po b/locale/it_IT/LC_MESSAGES/executable_manager.po new file mode 100644 index 00000000..9e31669d --- /dev/null +++ b/locale/it_IT/LC_MESSAGES/executable_manager.po @@ -0,0 +1,62 @@ +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Maurizio Paglia , 2022. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2022-07-11 22:19+0200\n" +"PO-Revision-Date: 2022-07-11 22:21+0200\n" +"Last-Translator: Maurizio Paglia \n" +"Language-Team: Italian <>\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Lokalize 21.12.3\n" + +#: executable_manager.lua:144 +msgid "No executable paths found, exiting..." +msgstr "Nessun percorso con eseguibili, esco..." + +#: executable_manager.lua:160 +msgid "select an executable" +msgstr "seleziona un eseguibile" + +#: executable_manager.lua:160 +msgid "search path for executable" +msgstr "cerca il percorso dell'eseguibile" + +#: executable_manager.lua:169 +msgid "select " +msgstr "seleziona" + +#: executable_manager.lua:169 +msgid " executable" +msgstr " eseguibile" + +#: executable_manager.lua:190 +msgid "select executable to modify" +msgstr "Seleziona l'eseguibile da modificare" + +#: executable_manager.lua:205 +msgid "current" +msgstr "Attuale" + +#: executable_manager.lua:207 +msgid "select" +msgstr "Seleziona" + +#: executable_manager.lua:209 +msgid "reset" +msgstr "Cancella" + +#: executable_manager.lua:212 +msgid "Clear path for " +msgstr "Cancella il percorso di " + +#: executable_manager.lua:211 +msgid "clear" +msgstr "Pulisci" diff --git a/locale/it_IT/LC_MESSAGES/script_manager.po b/locale/it_IT/LC_MESSAGES/script_manager.po new file mode 100644 index 00000000..d0f1ac59 --- /dev/null +++ b/locale/it_IT/LC_MESSAGES/script_manager.po @@ -0,0 +1,190 @@ +# French messages for script_manager.lua +# Christophe Agathon , 2020. +# Maurizio Paglia , 2021, 2022. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"POT-Creation-Date: 2020-12-28 10:22+0100\n" +"PO-Revision-Date: 2022-07-11 22:03+0200\n" +"Last-Translator: Maurizio Paglia \n" +"Language-Team: Italian <>\n" +"Language: fr_FR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Lokalize 21.12.3\n" +"X-Poedit-Basepath: ../../../tools\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Poedit-KeywordsList: _\n" +"X-Poedit-SearchPath-0: script_manager.lua\n" + +#: script_manager.lua:190 +msgid "Cant read from " +msgstr "Non posso leggere da " + +#: script_manager.lua:204 +msgid "Loaded " +msgstr "Script caricato " + +#: script_manager.lua:207 +msgid " failed to load" +msgstr "Non riesco a caricare lo script" + +#: script_manager.lua:223 +msgid " will not start when darktable is restarted" +msgstr " non verrà avviato al riavvio di darktable" + +#: script_manager.lua:281 script_manager.lua:345 +msgid "find command is " +msgstr "Il comando find è " + +#: script_manager.lua:321 +msgid "lua scripts successfully updated" +msgstr "Gli script lua sono stati correttamente aggiornati" + +#: script_manager.lua:381 +msgid "category " +msgstr "Categoria" + +#: script_manager.lua:381 +msgid " is already in use. Please specify a different category name." +msgstr " è già utilizzato. Prego specificare un nome differente." + +#: script_manager.lua:410 +msgid "scripts successfully installed into category " +msgstr "Gli script sono stati installati correttamente nella categoria " + +#: script_manager.lua:426 +msgid "No scripts found to install" +msgstr "Non trovo script da installare" + +#: script_manager.lua:430 +msgid "failed to download scripts" +msgstr "Non riesco a scaricare gli script" + +# Peut-être que « activé » serait mieux, mais ce n'est pas la traduction de « started » +#: script_manager.lua:458 +msgid " started" +msgstr " avviato" + +# Peut-être que « désactivé » serait mieux, mais ce n'est pas la traduction de « stopped » +#: script_manager.lua:460 +msgid " stopped" +msgstr " bloccato" + +#: script_manager.lua:545 +msgid "Page " +msgstr "Pag." + +#: script_manager.lua:545 +msgid " of " +msgstr " di " + +#: script_manager.lua:674 +msgid "scripts to update" +msgstr "Script da aggiornare" + +#: script_manager.lua:675 +msgid "select the scripts installation to update" +msgstr "Selezionare l'installazione di script da aggiornare" + +#: script_manager.lua:684 script_manager.lua:742 +msgid "update scripts" +msgstr "Aggiornare gli script" + +#: script_manager.lua:685 +msgid "update the lua scripts from the repository" +msgstr "Aggiornare gli script lua del repo" + +#: script_manager.lua:696 +msgid "" +"enter the URL of the git repository containing the scripts you wish to add" +msgstr "Immettere l'URL del repo git che contiene gli script da aggiungere" + +#: script_manager.lua:701 +msgid "name of new category" +msgstr "Nome della nuova categoria" + +#: script_manager.lua:702 +msgid "enter a category name for the additional scripts" +msgstr "Immettere il nome della categoria per altri script" + +#: script_manager.lua:707 +msgid "URL to download additional scripts from" +msgstr "URL dal quale scaricare ulteriori script" + +#: script_manager.lua:709 +msgid "new category to place scripts in" +msgstr "Nuova categoria che dovrà contenere gli script" + +#: script_manager.lua:712 +msgid "install additional scripts" +msgstr "Installare gli script aggiuntivi" + +#: script_manager.lua:720 +msgid "Enable \"Disable Scripts\" button" +msgstr "Abilita il pulsante \"Disabilita Script\"" + +#: script_manager.lua:730 +msgid "Disable Scripts" +msgstr "Disabilita Script" + +#: script_manager.lua:736 +msgid "lua scripts will not run the next time darktable is started" +msgstr "Gli script lua non verranno avviati al prossimo riavvio di darktable" + +#: script_manager.lua:745 +msgid "add more scripts" +msgstr "Aggiungi altri script" + +#: script_manager.lua:747 +msgid "disable scripts" +msgstr "Disabilita script" + +#: script_manager.lua:755 +msgid "category" +msgstr "categoria" + +#: script_manager.lua:756 +msgid "select the script category" +msgstr "Seleziona la categoria" + +#: script_manager.lua:780 +msgid "Page:" +msgstr "Pag.:" + +#: script_manager.lua:808 +msgid "Scripts" +msgstr "Scripts" + +#: script_manager.lua:817 +msgid "scripts per page" +msgstr "Script per pagina" + +#: script_manager.lua:818 +msgid "select number of start/stop buttons to display" +msgstr "Selezionare il numero di pulsanti da visualizzare" + +#: script_manager.lua:829 +msgid "change number of buttons" +msgstr "Modifica la quantità di pulsanti" + +#: script_manager.lua:837 +msgid "Configuration" +msgstr "Configurazione" + +#: script_manager.lua:858 +msgid "action" +msgstr "Azione" + +#: script_manager.lua:864 +msgid "install/update scripts" +msgstr "Installa/aggiorna script" + +#: script_manager.lua:864 +msgid "configure" +msgstr "Configura" + +#: script_manager.lua:864 +msgid "start/stop scripts" +msgstr "Avvia/blocca script" From da6bddcd77568b951e0e30182112238eb4736c2e Mon Sep 17 00:00:00 2001 From: Maurizio Paglia Date: Thu, 14 Jul 2022 18:44:42 +0200 Subject: [PATCH 211/445] Clear button now can be translated --- tools/executable_manager.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/executable_manager.lua b/tools/executable_manager.lua index 396e44c1..68752880 100644 --- a/tools/executable_manager.lua +++ b/tools/executable_manager.lua @@ -208,7 +208,7 @@ for i,exec in ipairs(exec_table) do executable_path_widgets[exec], dt.new_widget("section_label"){label = _("reset")}, dt.new_widget("button"){ - label = "clear", + label = _("clear"), tooltip = _("Clear path for ") .. exec, clicked_callback = function() df.set_executable_path_preference(exec, "") From 4648c2d9af5e83a157a6f1c663963a0cf09b43a8 Mon Sep 17 00:00:00 2001 From: dexterlb Date: Sun, 9 Oct 2022 11:54:02 +0300 Subject: [PATCH 212/445] add change_group_leader script --- contrib/change_group_leader.lua | 130 ++++++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 contrib/change_group_leader.lua diff --git a/contrib/change_group_leader.lua b/contrib/change_group_leader.lua new file mode 100644 index 00000000..a1a842a1 --- /dev/null +++ b/contrib/change_group_leader.lua @@ -0,0 +1,130 @@ +local dt = require "darktable" +local du = require "lib/dtutils" +local debug = require "darktable.debug" + +local MODULE = "change_group_leader" + +du.check_min_api_version("3.0.0", MODULE) + +-- create a namespace to contain persistent data and widgets +chg_grp_ldr = {} + +local cgl = chg_grp_ldr + +cgl.widgets = {} + +cgl.event_registered = false +cgl.module_installed = false + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- F U N C T I O N S +-- - - - - - - - - - - - - - - - - - - - - - - - + +local function install_module() + if not cgl.module_installed then + dt.register_lib( + MODULE, -- Module name + "change_group_leader", -- Visible name + true, -- expandable + false, -- resetable + {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 700}}, -- containers + cgl.widgets.box, + nil,-- view_enter + nil -- view_leave + ) + cgl.module_installed = true + end +end + +local function find_group_leader(images, mode) + for _, img in ipairs(images) do + dt.print_log("checking image " .. img.id .. " named " .. img.filename) + local found = false + if mode == "jpg" then + if string.match(string.lower(img.filename), "jpg$") then + dt.print_log("jpg matched image " .. img.filename) + found = true + end + elseif mode == "raw" then + if img.is_raw and img.duplicate_index == 0 then + dt.print_log("found raw " .. img.filename) + found = true + end + elseif mode == "non-raw" then + if img.is_ldr then + dt.print_log("found ldr " .. img.filename) + found = true + end + else + dt.print_error(MODULE .. ": unrecognized mode " .. mode) + return + end + if found then + dt.print_log("making " .. img.filename .. " group leader") + img:make_group_leader() + return + end + end +end + +local function process_image_groups(images) + if #images < 1 then + dt.print("No images selected.") + dt.print_log(MODULE .. "no images seletected, returning...") + else + local mode = cgl.widgets.mode.value + for _,img in ipairs(images) do + dt.print_log("checking image " .. img.id) + local group_images = img:get_group_members() + if group_images == 1 then + dt.print_log("only one image in group for image " .. image.id) + else + find_group_leader(group_images, mode) + end + end + end +end + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- W I D G E T S +-- - - - - - - - - - - - - - - - - - - - - - - - + +cgl.widgets.mode = dt.new_widget("combobox"){ + label = "select new group leader", + tooltip = "select type of image to be group leader", + selected = 1, + "jpg", "raw", "non-raw", +} + +cgl.widgets.execute = dt.new_widget("button"){ + label = "Execute", + clicked_callback = function() + process_image_groups(dt.gui.action_images) + end +} + +cgl.widgets.box = dt.new_widget("box"){ + orientation = "vertical", + cgl.widgets.mode, + cgl.widgets.execute, +} + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- D A R K T A B L E I N T E G R A T I O N +-- - - - - - - - - - - - - - - - - - - - - - - - + +if dt.gui.current_view().id == "lighttable" then + install_module() +else + if not cgl.event_registered then + dt.register_event( + "view-changed", + function(event, old_view, new_view) + if new_view.name == "lighttable" and old_view.name == "darkroom" then + install_module() + end + end + ) + cgl.event_registered = true + end +end From 803537c63e328b0eb088b04e8754f729dc6f27dc Mon Sep 17 00:00:00 2001 From: dexterlb Date: Sun, 9 Oct 2022 12:00:29 +0300 Subject: [PATCH 213/445] add comments to change_group_leader --- contrib/change_group_leader.lua | 52 ++++++++++++++++++++++++++++----- 1 file changed, 45 insertions(+), 7 deletions(-) diff --git a/contrib/change_group_leader.lua b/contrib/change_group_leader.lua index a1a842a1..1dedd00b 100644 --- a/contrib/change_group_leader.lua +++ b/contrib/change_group_leader.lua @@ -1,3 +1,41 @@ +--[[ + Passport cropping guide for darktable + + copyright (c) 2021 Angel Angelov + + darktable is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + darktable is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with darktable. If not, see . +]] + +--[[ + Original author: github.com/wpferguson +]] + +--[[ +CHANGE GROUP LEADER +automatically change the leader of raw+jpg paired image groups + +INSTALLATION +* copy this file in $CONFIGDIR/lua/ where CONFIGDIR is your darktable configuration directory +* add the following line in the file $CONFIGDIR/luarc + require "change_group_leader" + +USAGE +* in lighttable mode, select the image groups you wish to process, + select whether you want to set the leader to "jpg" or "raw", + and click "Execute" +]] + local dt = require "darktable" local du = require "lib/dtutils" local debug = require "darktable.debug" @@ -16,9 +54,9 @@ cgl.widgets = {} cgl.event_registered = false cgl.module_installed = false --- - - - - - - - - - - - - - - - - - - - - - - - +-- - - - - - - - - - - - - - - - - - - - - - - - -- F U N C T I O N S --- - - - - - - - - - - - - - - - - - - - - - - - +-- - - - - - - - - - - - - - - - - - - - - - - - local function install_module() if not cgl.module_installed then @@ -85,9 +123,9 @@ local function process_image_groups(images) end end --- - - - - - - - - - - - - - - - - - - - - - - - +-- - - - - - - - - - - - - - - - - - - - - - - - -- W I D G E T S --- - - - - - - - - - - - - - - - - - - - - - - - +-- - - - - - - - - - - - - - - - - - - - - - - - cgl.widgets.mode = dt.new_widget("combobox"){ label = "select new group leader", @@ -109,9 +147,9 @@ cgl.widgets.box = dt.new_widget("box"){ cgl.widgets.execute, } --- - - - - - - - - - - - - - - - - - - - - - - - --- D A R K T A B L E I N T E G R A T I O N --- - - - - - - - - - - - - - - - - - - - - - - - +-- - - - - - - - - - - - - - - - - - - - - - - - +-- D A R K T A B L E I N T E G R A T I O N +-- - - - - - - - - - - - - - - - - - - - - - - - if dt.gui.current_view().id == "lighttable" then install_module() From 652606ffb04bf8e63e66aa8d890405b61d9d1879 Mon Sep 17 00:00:00 2001 From: dexterlb Date: Mon, 10 Oct 2022 21:38:30 +0300 Subject: [PATCH 214/445] fix copyright message --- contrib/change_group_leader.lua | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/contrib/change_group_leader.lua b/contrib/change_group_leader.lua index 1dedd00b..9d2012ac 100644 --- a/contrib/change_group_leader.lua +++ b/contrib/change_group_leader.lua @@ -1,7 +1,7 @@ --[[ Passport cropping guide for darktable - copyright (c) 2021 Angel Angelov + copyright (c) 2022 Bill Ferguson darktable is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -17,10 +17,6 @@ along with darktable. If not, see . ]] ---[[ - Original author: github.com/wpferguson -]] - --[[ CHANGE GROUP LEADER automatically change the leader of raw+jpg paired image groups From 572a634d90f8b567c07b15c101c835dece5f3f74 Mon Sep 17 00:00:00 2001 From: dexterlb Date: Mon, 10 Oct 2022 21:39:38 +0300 Subject: [PATCH 215/445] fix title --- contrib/change_group_leader.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/change_group_leader.lua b/contrib/change_group_leader.lua index 9d2012ac..c4eb3f6f 100644 --- a/contrib/change_group_leader.lua +++ b/contrib/change_group_leader.lua @@ -1,5 +1,5 @@ --[[ - Passport cropping guide for darktable + change group leader copyright (c) 2022 Bill Ferguson From 6748a7125e65fd18d5eb465a3c9738cac44a2cac Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sun, 16 Oct 2022 13:58:19 -0400 Subject: [PATCH 216/445] README.md Added change_group_leader to contrib section change_group_leader.lua Updated copyright information Added script_manager integration Added i18n --- README.md | 1 + contrib/change_group_leader.lua | 50 ++++++++++++++++++++++++++++----- 2 files changed, 44 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 9d58d0e5..598b4c2a 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,7 @@ Name|Standalone|OS |Purpose ----|:--------:|:---:|------- [AutoGrouper](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/autogrouper)|Yes|LMW|Group images together by time [autostyle](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/autostyle)|Yes|LMW|Automatically apply styles on import +change_group_leader|Yes|LMW|Change which image leads group [clear_GPS](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/clear_gps)|Yes|LMW|Reset GPS information for selected images [CollectHelper](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/collecthelper)|Yes|LMW|Add buttons to selected images module to manipulate the collection [copy_attach_detach_tags](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/copy_attach_detach_tags)|Yes|LMW|Copy and paste tags from/to images diff --git a/contrib/change_group_leader.lua b/contrib/change_group_leader.lua index c4eb3f6f..07ce8119 100644 --- a/contrib/change_group_leader.lua +++ b/contrib/change_group_leader.lua @@ -1,7 +1,8 @@ --[[ change group leader - copyright (c) 2022 Bill Ferguson + copyright (c) 2020, 2022 Bill Ferguson + copyright (c) 2021 Angel Angelov darktable is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -34,12 +35,28 @@ USAGE local dt = require "darktable" local du = require "lib/dtutils" -local debug = require "darktable.debug" + +local gettext = dt.gettext local MODULE = "change_group_leader" du.check_min_api_version("3.0.0", MODULE) +-- return data structure for script_manager + +local script_data = {} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again + +-- Tell gettext where to find the .mo file translating messages for a particular domain +gettext.bindtextdomain(MODULE, dt.configuration.config_dir.."/lua/locale/") + +local function _(msgid) + return gettext.dgettext(MODULE, msgid) +end + -- create a namespace to contain persistent data and widgets chg_grp_ldr = {} @@ -58,7 +75,7 @@ local function install_module() if not cgl.module_installed then dt.register_lib( MODULE, -- Module name - "change_group_leader", -- Visible name + _("change_group_leader"), -- Visible name true, -- expandable false, -- resetable {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 700}}, -- containers @@ -103,7 +120,7 @@ end local function process_image_groups(images) if #images < 1 then - dt.print("No images selected.") + dt.print(_("No images selected.")) dt.print_log(MODULE .. "no images seletected, returning...") else local mode = cgl.widgets.mode.value @@ -119,19 +136,31 @@ local function process_image_groups(images) end end +-- - - - - - - - - - - - - - - - - - - - - - - - +-- S C R I P T M A N A G E R I N T E G R A T I O N +-- - - - - - - - - - - - - - - - - - - - - - - - + +local function destroy() + dt.gui.libs[MODULE].visible = false +end + +local function restart() + dt.gui.libs[MODULE].visible = true +end + -- - - - - - - - - - - - - - - - - - - - - - - - -- W I D G E T S -- - - - - - - - - - - - - - - - - - - - - - - - cgl.widgets.mode = dt.new_widget("combobox"){ - label = "select new group leader", - tooltip = "select type of image to be group leader", + label = _("select new group leader"), + tooltip = _("select type of image to be group leader"), selected = 1, "jpg", "raw", "non-raw", } cgl.widgets.execute = dt.new_widget("button"){ - label = "Execute", + label = _("Execute"), clicked_callback = function() process_image_groups(dt.gui.action_images) end @@ -162,3 +191,10 @@ else cgl.event_registered = true end end + +script_data.destroy = destroy +script_data.restart = restart +script_data.destroy_method = "hide" +script_data.show = restart + +return script_data \ No newline at end of file From 9b31f18470ee5e6a28db9e94e2de5c34da7f75de Mon Sep 17 00:00:00 2001 From: Romuald du Song Date: Sat, 25 Feb 2023 17:41:45 +0100 Subject: [PATCH 217/445] fix HOME environment variable name --- contrib/kml_export.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/kml_export.lua b/contrib/kml_export.lua index f2722be2..8451d72c 100644 --- a/contrib/kml_export.lua +++ b/contrib/kml_export.lua @@ -334,7 +334,7 @@ local defaultDir = '' if dt.configuration.running_os == "windows" then defaultDir = os.getenv("USERPROFILE") elseif dt.configuration.running_os == "macos" then - defaultDir = os.getenv("home") + defaultDir = os.getenv("HOME") else local handle = io.popen("xdg-user-dir DESKTOP") defaultDir = handle:read() From d556f48168b46989c4de0bba54c0c12f2db9970a Mon Sep 17 00:00:00 2001 From: supertobi Date: Mon, 27 Feb 2023 09:27:25 +0100 Subject: [PATCH 218/445] fix HOME environment variable name for macOS --- contrib/video_ffmpeg.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/video_ffmpeg.lua b/contrib/video_ffmpeg.lua index 43a79d9e..d670a517 100644 --- a/contrib/video_ffmpeg.lua +++ b/contrib/video_ffmpeg.lua @@ -285,7 +285,7 @@ local defaultVideoDir = '' if dt.configuration.running_os == "windows" then defaultVideoDir = os.getenv("USERPROFILE")..PS .."videos" elseif dt.configuration.running_os == "macos" then - defaultVideoDir = os.getenv("home")..PS.."Videos" + defaultVideoDir = os.getenv("HOME")..PS.."Videos" else local handle = io.popen("xdg-user-dir VIDEOS") defaultVideoDir = handle:read() From b883714192ca8cd9df08d91ea2b7a026108b4fae Mon Sep 17 00:00:00 2001 From: supertobi Date: Mon, 27 Feb 2023 09:29:16 +0100 Subject: [PATCH 219/445] fix HOME environment variable name for macOS --- contrib/kml_export.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/kml_export.lua b/contrib/kml_export.lua index f2722be2..8451d72c 100644 --- a/contrib/kml_export.lua +++ b/contrib/kml_export.lua @@ -334,7 +334,7 @@ local defaultDir = '' if dt.configuration.running_os == "windows" then defaultDir = os.getenv("USERPROFILE") elseif dt.configuration.running_os == "macos" then - defaultDir = os.getenv("home") + defaultDir = os.getenv("HOME") else local handle = io.popen("xdg-user-dir DESKTOP") defaultDir = handle:read() From 574f6a976f9e513126ff00d06bd1359b3e7d92fc Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Mon, 6 Mar 2023 22:56:55 -0500 Subject: [PATCH 220/445] script_manager.lua - added a preference allowing the user to disable automatic checking for updated scripts. --- tools/script_manager.lua | 120 +++++++++++++++++++++------------------ 1 file changed, 66 insertions(+), 54 deletions(-) diff --git a/tools/script_manager.lua b/tools/script_manager.lua index eb2db044..24d9714d 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -70,7 +70,6 @@ end du.check_min_api_version("5.0.0", "script_manager") - -- - - - - - - - - - - - - - - - - - - - - - - - -- C O N S T A N T S -- - - - - - - - - - - - - - - - - - - - - - - - @@ -94,6 +93,16 @@ local LUA_SCRIPT_REPO = "https://github.com/darktable-org/lua-scripts.git" local LUA_API_VER = "API-" .. dt.configuration.api_version_string +-- - - - - - - - - - - - - - - - - - - - - - - - +-- P R E F E R E N C E S +-- - - - - - - - - - - - - - - - - - - - - - - - + +dt.preferences.register(MODULE, "check_update", "bool", + "check for updated scripts on start up", + "automatically update scripts to correct version", + true) + +local check_for_updates = dt.preferences.read(MODULE, "check_update", "bool") -- - - - - - - - - - - - - - - - - - - - - - - - -- L O G L E V E L @@ -858,62 +867,65 @@ end -- - - - - - - - - - - - - - - - - - - - - - - - -- M A I N P R O G R A M -- - - - - - - - - - - - - - - - - - - - - - - - -local repo_data = get_repo_status(LUA_DIR) -local current_branch = get_current_repo_branch(LUA_DIR) -local clean = is_repo_clean(repo_data) -local repo = LUA_DIR - -if current_branch then - if sm.executables.git and clean and - (current_branch == "master" or string.match(current_branch, "^API%-")) then -- only make changes to clean branches - local branches = get_repo_branches(LUA_DIR) - if current_branch ~= LUA_API_VER and current_branch ~= "master" then - -- probably upgraded from an earlier api version so get back to master - -- to use the latest version of script_manager to get the proper API - checkout_repo_branch(repo, "master") - log.msg(log.screen, "lua API version reset, please restart darktable") - elseif LUA_API_VER == current_branch then - -- do nothing, we are fine - log.msg(log.debug, "took equal branch, doing nothing") - elseif string.match(LUA_API_VER, "dev") then - -- we are on a dev API version, so checkout the dev - -- api version or checkout/stay on master - log.msg(log.debug, "took the dev branch") - local match = false - for _, branch in ipairs(branches) do - log.msg(log.debug, "checking branch " .. branch .. " against API " .. LUA_API_VER) - if LUA_API_VER == branch then - match = true - log.msg(log.info, "checking out repo development branch " .. branch) - checkout_repo_branch(repo, branch) + +if check_for_updates then + local repo_data = get_repo_status(LUA_DIR) + local current_branch = get_current_repo_branch(LUA_DIR) + local clean = is_repo_clean(repo_data) + local repo = LUA_DIR + + if current_branch then + if sm.executables.git and clean and + (current_branch == "master" or string.match(current_branch, "^API%-")) then -- only make changes to clean branches + local branches = get_repo_branches(LUA_DIR) + if current_branch ~= LUA_API_VER and current_branch ~= "master" then + -- probably upgraded from an earlier api version so get back to master + -- to use the latest version of script_manager to get the proper API + checkout_repo_branch(repo, "master") + log.msg(log.screen, "lua API version reset, please restart darktable") + elseif LUA_API_VER == current_branch then + -- do nothing, we are fine + log.msg(log.debug, "took equal branch, doing nothing") + elseif string.match(LUA_API_VER, "dev") then + -- we are on a dev API version, so checkout the dev + -- api version or checkout/stay on master + log.msg(log.debug, "took the dev branch") + local match = false + for _, branch in ipairs(branches) do + log.msg(log.debug, "checking branch " .. branch .. " against API " .. LUA_API_VER) + if LUA_API_VER == branch then + match = true + log.msg(log.info, "checking out repo development branch " .. branch) + checkout_repo_branch(repo, branch) + end end - end - if not match then - if current_branch == "master" then - log.msg(log.info, "staying on master, no dev branch yet") - else - log.msg(log.info, "no dev branch available, checking out master") - checkout_repo_branch(repo, "master") + if not match then + if current_branch == "master" then + log.msg(log.info, "staying on master, no dev branch yet") + else + log.msg(log.info, "no dev branch available, checking out master") + checkout_repo_branch(repo, "master") + end end - end - elseif #branches > 0 and LUA_API_VER > branches[#branches] then - log.msg(log.info, "no newer branches, staying on master") - -- stay on master - else - -- checkout the appropriate branch for API version if it exists - log.msg(log.info, "checking out the appropriate API branch") - local match = false - for _, branch in ipairs(branches) do - log.msg(log.debug, "checking branch " .. branch .. " against API " .. LUA_API_VER) - if LUA_API_VER == branch then - match = true - log.msg(log.info, "checking out repo branch " .. branch) - checkout_repo_branch(repo, branch) - log.msg(log.screen, "you must restart darktable to use the correct version of the lua") + elseif #branches > 0 and LUA_API_VER > branches[#branches] then + log.msg(log.info, "no newer branches, staying on master") + -- stay on master + else + -- checkout the appropriate branch for API version if it exists + log.msg(log.info, "checking out the appropriate API branch") + local match = false + for _, branch in ipairs(branches) do + log.msg(log.debug, "checking branch " .. branch .. " against API " .. LUA_API_VER) + if LUA_API_VER == branch then + match = true + log.msg(log.info, "checking out repo branch " .. branch) + checkout_repo_branch(repo, branch) + log.msg(log.screen, "you must restart darktable to use the correct version of the lua") + end + end + if not match then + log.msg(log.warn, "no matching branch found for " .. LUA_API_VER) end - end - if not match then - log.msg(log.warn, "no matching branch found for " .. LUA_API_VER) end end end From 3f6a3e25f1040ce0f9155d9a3aed5f2e85aa6cce Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Thu, 16 Mar 2023 20:59:10 -0400 Subject: [PATCH 221/445] added global variable script+_manager_running_script to convey the script name to the darktable shortcut system --- tools/script_manager.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/script_manager.lua b/tools/script_manager.lua index eb2db044..a0a02202 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -325,8 +325,10 @@ local function activate(script) local err = nil -- error message returned if module doesn't start log.msg(log.info, "activating " .. script.name) if script.running == false then + script_manager_running_script = script.name status, err = du.prequire(script.path) log.msg(log.debug, "prequire returned " .. tostring(status) .. " and for err " .. tostring(err)) + script_manager_running_script = nil if status then pref_write(script.script_name, "bool", true) log.msg(log.screen, _("Loaded ") .. script.script_name) From 80147a9ebcb5c8a8a514a40cbae924e4501dc998 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Fri, 24 Mar 2023 13:40:34 -0400 Subject: [PATCH 222/445] lib/dtugiles.file - Moved filename/path/extension string functions to string library. Left the existing function calls in place for backward compatibility. They now call the new functions in the string library lib/dtutils.string - Moved the filename/path/extension string functions to the string library to prevent a circular library depnedency. The file library includes the string library. If the string library needed to manipulate filename related strings then the string library would need to include the file library which would lead to a stack overflow. --- lib/dtutils/file.lua | 115 ++++----------------------------------- lib/dtutils/string.lua | 121 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 132 insertions(+), 104 deletions(-) diff --git a/lib/dtutils/file.lua b/lib/dtutils/file.lua index c3174c7c..cd898e71 100644 --- a/lib/dtutils/file.lua +++ b/lib/dtutils/file.lua @@ -394,125 +394,32 @@ function dtutils_file.check_if_bin_exists(bin) return result end -dtutils_file.libdoc.functions["split_filepath"] = { - Name = [[split_filepath]], - Synopsis = [[split a filepath into parts]], - Usage = [[local df = require "lib/dtutils.file" +-- the following path, filename, etc functions have +-- moved to the string library since they are string +-- manipulation functions, and to prevent circular +-- library inclusiion. - local result = df.split_filepath(filepath) - filepath - string - path and filename]], - Description = [[split_filepath splits a filepath into the path, filename, basename and filetype and puts - that in a table]], - Return_Value = [[result - table - a table containing the path, filename, basename, and filetype]], - Limitations = [[]], - Example = [[]], - See_Also = [[]], - Reference = [[]], - License = [[]], - Copyright = [[]], -} +-- these functions are left here for compatibility +-- with older scripts function dtutils_file.split_filepath(str) - -- strip out single quotes from quoted pathnames - str = string.gsub(str, "'", "") - str = string.gsub(str, '"', '') - local result = {} - -- Thank you Tobias Jakobs for the awesome regular expression, which I tweaked a little - result["path"], result["filename"], result["basename"], result["filetype"] = string.match(str, "(.-)(([^\\/]-)%.?([^%.\\/]*))$") - if result["basename"] == "" and result["filetype"]:len() > 1 then - result["basename"] = result["filetype"] - result["filetype"] = "" - end - return result + return ds.split_filepath(str) end -dtutils_file.libdoc.functions["get_path"] = { - Name = [[get_path]], - Synopsis = [[get the path from a file path]], - Usage = [[local df = require "lib/dtutils.file" - - local result = df.get_path(filepath) - filepath - string - path and filename]], - Description = [[get_path strips the filename and filetype from a path and returns the path]], - Return_Value = [[result - string - the path]], - Limitations = [[]], - Example = [[]], - See_Also = [[]], - Reference = [[]], - License = [[]], - Copyright = [[]], -} - function dtutils_file.get_path(str) - local parts = dtutils_file.split_filepath(str) - return parts["path"] + return ds.get_path(str) end -dtutils_file.libdoc.functions["get_filename"] = { - Name = [[get_filename]], - Synopsis = [[get the filename and extension from a file path]], - Usage = [[local df = require "lib/dtutils.file" - - local result = df.get_filename(filepath) - filepath - string - path and filename]], - Description = [[get_filename strips the path from a filepath and returns the filename]], - Return_Value = [[result - string - the file name and type]], - Limitations = [[]], - Example = [[]], - See_Also = [[]], - Reference = [[]], - License = [[]], - Copyright = [[]], -} - function dtutils_file.get_filename(str) - local parts = dtutils_file.split_filepath(str) - return parts["filename"] + return ds.get_filename(str) end -dtutils_file.libdoc.functions["get_basename"] = { - Name = [[get_basename]], - Synopsis = [[get the filename without the path or extension]], - Usage = [[local df = require "lib/dtutils.file" - - local result = df.get_basename(filepath) - filepath - string - path and filename]], - Description = [[get_basename returns the name of the file without the path or filetype -]], - Return_Value = [[result - string - the basename of the file]], - Limitations = [[]], - Example = [[]], - See_Also = [[]], - Reference = [[]], - License = [[]], - Copyright = [[]], -} - function dtutils_file.get_basename(str) - local parts = dtutils_file.split_filepath(str) - return parts["basename"] + return ds.get_basename(str) end -dtutils_file.libdoc.functions["get_filetype"] = { - Name = [[get_filetype]], - Synopsis = [[get the filetype from a filename]], - Usage = [[local df = require "lib/dtutils.file" - - local result = df.get_filetype(filepath) - filepath - string - path and filename]], - Description = [[get_filetype returns the filetype from the supplied filepath]], - Return_Value = [[result - string - the filetype]], - Limitations = [[]], - Example = [[]], - See_Also = [[]], - Reference = [[]], - License = [[]], - Copyright = [[]], -} - function dtutils_file.get_filetype(str) - local parts = dtutils_file.split_filepath(str) - return parts["filetype"] + return ds.get_filetype(str) end diff --git a/lib/dtutils/string.lua b/lib/dtutils/string.lua index e3cc8170..f7159a2f 100644 --- a/lib/dtutils/string.lua +++ b/lib/dtutils/string.lua @@ -294,6 +294,127 @@ function dtutils_string.sanitize_lua(str) return str end +dtutils_string.libdoc.functions["split_filepath"] = { + Name = [[split_filepath]], + Synopsis = [[split a filepath into parts]], + Usage = [[local ds = require "lib/dtutils.string" + + local result = ds.split_filepath(filepath) + filepath - string - path and filename]], + Description = [[split_filepath splits a filepath into the path, filename, basename and filetype and puts + that in a table]], + Return_Value = [[result - table - a table containing the path, filename, basename, and filetype]], + Limitations = [[]], + Example = [[]], + See_Also = [[]], + Reference = [[]], + License = [[]], + Copyright = [[]], +} + +function dtutils_string.split_filepath(str) + -- strip out single quotes from quoted pathnames + str = string.gsub(str, "'", "") + str = string.gsub(str, '"', '') + local result = {} + -- Thank you Tobias Jakobs for the awesome regular expression, which I tweaked a little + result["path"], result["filename"], result["basename"], result["filetype"] = string.match(str, "(.-)(([^\\/]-)%.?([^%.\\/]*))$") + if result["basename"] == "" and result["filetype"]:len() > 1 then + result["basename"] = result["filetype"] + result["filetype"] = "" + end + return result +end + +dtutils_string.libdoc.functions["get_path"] = { + Name = [[get_path]], + Synopsis = [[get the path from a file path]], + Usage = [[local ds = require "lib/dtutils.string" + + local result = ds.get_path(filepath) + filepath - string - path and filename]], + Description = [[get_path strips the filename and filetype from a path and returns the path]], + Return_Value = [[result - string - the path]], + Limitations = [[]], + Example = [[]], + See_Also = [[]], + Reference = [[]], + License = [[]], + Copyright = [[]], +} + +function dtutils_string.get_path(str) + local parts = dtutils_string.split_filepath(str) + return parts["path"] +end + +dtutils_string.libdoc.functions["get_filename"] = { + Name = [[get_filename]], + Synopsis = [[get the filename and extension from a file path]], + Usage = [[local ds = require "lib/dtutils.string" + + local result = ds.get_filename(filepath) + filepath - string - path and filename]], + Description = [[get_filename strips the path from a filepath and returns the filename]], + Return_Value = [[result - string - the file name and type]], + Limitations = [[]], + Example = [[]], + See_Also = [[]], + Reference = [[]], + License = [[]], + Copyright = [[]], +} + +function dtutils_string.get_filename(str) + local parts = dtutils_string.split_filepath(str) + return parts["filename"] +end + +dtutils_string.libdoc.functions["get_basename"] = { + Name = [[get_basename]], + Synopsis = [[get the filename without the path or extension]], + Usage = [[local ds = require "lib/dtutils.string" + + local result = ds.get_basename(filepath) + filepath - string - path and filename]], + Description = [[get_basename returns the name of the file without the path or filetype +]], + Return_Value = [[result - string - the basename of the file]], + Limitations = [[]], + Example = [[]], + See_Also = [[]], + Reference = [[]], + License = [[]], + Copyright = [[]], +} + +function dtutils_string.get_basename(str) + local parts = dtutils_string.split_filepath(str) + return parts["basename"] +end + +dtutils_string.libdoc.functions["get_filetype"] = { + Name = [[get_filetype]], + Synopsis = [[get the filetype from a filename]], + Usage = [[local ds = require "lib/dtutils.string" + + local result = ds.get_filetype(filepath) + filepath - string - path and filename]], + Description = [[get_filetype returns the filetype from the supplied filepath]], + Return_Value = [[result - string - the filetype]], + Limitations = [[]], + Example = [[]], + See_Also = [[]], + Reference = [[]], + License = [[]], + Copyright = [[]], +} + +function dtutils_string.get_filetype(str) + local parts = dtutils_string.split_filepath(str) + return parts["filetype"] +end + return dtutils_string From 8e412c3eb32990418baf990bd963328d08035017 Mon Sep 17 00:00:00 2001 From: dterrahe Date: Sat, 25 Mar 2023 10:59:19 -0400 Subject: [PATCH 223/445] example slider mimic script for x-touch mini --- examples/x-touch.lua | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 examples/x-touch.lua diff --git a/examples/x-touch.lua b/examples/x-touch.lua new file mode 100644 index 00000000..6adfa4c3 --- /dev/null +++ b/examples/x-touch.lua @@ -0,0 +1,40 @@ +local dt = require "darktable" +local du = require "lib/dtutils" + +du.check_min_api_version("9.1.0", "x-touch") + +function knob(action, element, effect, size) + k = tonumber(action:sub(-1)) + + if dt.gui.action("iop/blend/tools/show and edit mask elements") ~= 0 then + local s = { "opacity", "size", "feather", "hardness","rotation","curvature","compression" } + which = "lib/masks/properties/" .. s[k] + + elseif dt.gui.action("iop/colorzones", "focus") ~= 0 then + local e = { "red", "orange", "yellow", "green", "aqua", "blue", "purple", "magenta" } + element = e[k] + which = "iop/colorzones/graph" + + elseif dt.gui.action("iop/toneequal", "focus") ~= 0 then + which ="iop/toneequal/simple/"..(k-9).." EV" + + elseif k == 4 and dt.gui.action("iop/colorbalancergb", "focus") ~= 0 then + which = "iop/colorbalancergb/contrast" + + else + local s = { "iop/exposure/exposure", + "iop/filmicrgb/white relative exposure", + "iop/filmicrgb/black relative exposure", + "iop/filmicrgb/contrast", + "iop/crop/left", + "iop/crop/right", + "iop/crop/top", + "iop/crop/bottom" } + which = s[k] + end + return dt.gui.action(which, element, effect, size) +end + +for k = 1,8 do + dt.gui.mimic("slider", "knob ".. k, knob) +end From 05d555eae53f35656831306ad81aa316b874ae8a Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sat, 25 Mar 2023 12:46:59 -0400 Subject: [PATCH 224/445] tools/script_manager - let the shortcut system know that script_manager widgets belong to script_manager --- tools/script_manager.lua | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tools/script_manager.lua b/tools/script_manager.lua index a0a02202..4ae6657d 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -865,6 +865,10 @@ local current_branch = get_current_repo_branch(LUA_DIR) local clean = is_repo_clean(repo_data) local repo = LUA_DIR +-- ensure shortcuts module knows widgets belong to script_manager + +script_manager_running_script = "script_manager" + if current_branch then if sm.executables.git and clean and (current_branch == "master" or string.match(current_branch, "^API%-")) then -- only make changes to clean branches @@ -1137,7 +1141,7 @@ sm.widgets.main_box = dt.new_widget("box"){ sm.widgets.main_stack } - +script_manager_running_script = nil -- - - - - - - - - - - - - - - - - - - - - - - - -- D A R K T A B L E I N T E G R A T I O N -- - - - - - - - - - - - - - - - - - - - - - - - From 21d7e72b0c0d81f0fd91c22cea130055d65243c5 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sat, 25 Mar 2023 13:01:40 -0400 Subject: [PATCH 225/445] tools/script_manager - resolved conflicts --- tools/script_manager.lua | 119 ++++++++++++++++++++++----------------- 1 file changed, 66 insertions(+), 53 deletions(-) diff --git a/tools/script_manager.lua b/tools/script_manager.lua index 4ae6657d..3494bd69 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -95,6 +95,17 @@ local LUA_SCRIPT_REPO = "https://github.com/darktable-org/lua-scripts.git" local LUA_API_VER = "API-" .. dt.configuration.api_version_string +-- - - - - - - - - - - - - - - - - - - - - - - - +-- P R E F E R E N C E S +-- - - - - - - - - - - - - - - - - - - - - - - - + +dt.preferences.register(MODULE, "check_update", "bool", + "check for updated scripts on start up", + "automatically update scripts to correct version", + true) + +local check_for_updates = dt.preferences.read(MODULE, "check_update", "bool") + -- - - - - - - - - - - - - - - - - - - - - - - - -- L O G L E V E L -- - - - - - - - - - - - - - - - - - - - - - - - @@ -860,66 +871,69 @@ end -- - - - - - - - - - - - - - - - - - - - - - - - -- M A I N P R O G R A M -- - - - - - - - - - - - - - - - - - - - - - - - -local repo_data = get_repo_status(LUA_DIR) -local current_branch = get_current_repo_branch(LUA_DIR) -local clean = is_repo_clean(repo_data) -local repo = LUA_DIR -- ensure shortcuts module knows widgets belong to script_manager script_manager_running_script = "script_manager" -if current_branch then - if sm.executables.git and clean and - (current_branch == "master" or string.match(current_branch, "^API%-")) then -- only make changes to clean branches - local branches = get_repo_branches(LUA_DIR) - if current_branch ~= LUA_API_VER and current_branch ~= "master" then - -- probably upgraded from an earlier api version so get back to master - -- to use the latest version of script_manager to get the proper API - checkout_repo_branch(repo, "master") - log.msg(log.screen, "lua API version reset, please restart darktable") - elseif LUA_API_VER == current_branch then - -- do nothing, we are fine - log.msg(log.debug, "took equal branch, doing nothing") - elseif string.match(LUA_API_VER, "dev") then - -- we are on a dev API version, so checkout the dev - -- api version or checkout/stay on master - log.msg(log.debug, "took the dev branch") - local match = false - for _, branch in ipairs(branches) do - log.msg(log.debug, "checking branch " .. branch .. " against API " .. LUA_API_VER) - if LUA_API_VER == branch then - match = true - log.msg(log.info, "checking out repo development branch " .. branch) - checkout_repo_branch(repo, branch) +if check_for_updates then + local repo_data = get_repo_status(LUA_DIR) + local current_branch = get_current_repo_branch(LUA_DIR) + local clean = is_repo_clean(repo_data) + local repo = LUA_DIR + + if current_branch then + if sm.executables.git and clean and + (current_branch == "master" or string.match(current_branch, "^API%-")) then -- only make changes to clean branches + local branches = get_repo_branches(LUA_DIR) + if current_branch ~= LUA_API_VER and current_branch ~= "master" then + -- probably upgraded from an earlier api version so get back to master + -- to use the latest version of script_manager to get the proper API + checkout_repo_branch(repo, "master") + log.msg(log.screen, "lua API version reset, please restart darktable") + elseif LUA_API_VER == current_branch then + -- do nothing, we are fine + log.msg(log.debug, "took equal branch, doing nothing") + elseif string.match(LUA_API_VER, "dev") then + -- we are on a dev API version, so checkout the dev + -- api version or checkout/stay on master + log.msg(log.debug, "took the dev branch") + local match = false + for _, branch in ipairs(branches) do + log.msg(log.debug, "checking branch " .. branch .. " against API " .. LUA_API_VER) + if LUA_API_VER == branch then + match = true + log.msg(log.info, "checking out repo development branch " .. branch) + checkout_repo_branch(repo, branch) + end end - end - if not match then - if current_branch == "master" then - log.msg(log.info, "staying on master, no dev branch yet") - else - log.msg(log.info, "no dev branch available, checking out master") - checkout_repo_branch(repo, "master") + if not match then + if current_branch == "master" then + log.msg(log.info, "staying on master, no dev branch yet") + else + log.msg(log.info, "no dev branch available, checking out master") + checkout_repo_branch(repo, "master") + end end - end - elseif #branches > 0 and LUA_API_VER > branches[#branches] then - log.msg(log.info, "no newer branches, staying on master") - -- stay on master - else - -- checkout the appropriate branch for API version if it exists - log.msg(log.info, "checking out the appropriate API branch") - local match = false - for _, branch in ipairs(branches) do - log.msg(log.debug, "checking branch " .. branch .. " against API " .. LUA_API_VER) - if LUA_API_VER == branch then - match = true - log.msg(log.info, "checking out repo branch " .. branch) - checkout_repo_branch(repo, branch) - log.msg(log.screen, "you must restart darktable to use the correct version of the lua") + elseif #branches > 0 and LUA_API_VER > branches[#branches] then + log.msg(log.info, "no newer branches, staying on master") + -- stay on master + else + -- checkout the appropriate branch for API version if it exists + log.msg(log.info, "checking out the appropriate API branch") + local match = false + for _, branch in ipairs(branches) do + log.msg(log.debug, "checking branch " .. branch .. " against API " .. LUA_API_VER) + if LUA_API_VER == branch then + match = true + log.msg(log.info, "checking out repo branch " .. branch) + checkout_repo_branch(repo, branch) + log.msg(log.screen, "you must restart darktable to use the correct version of the lua") + end + end + if not match then + log.msg(log.warn, "no matching branch found for " .. LUA_API_VER) end - end - if not match then - log.msg(log.warn, "no matching branch found for " .. LUA_API_VER) end end end @@ -929,7 +943,6 @@ scan_scripts(LUA_DIR) log.msg(log.debug, "finished processing scripts") - -- - - - - - - - - - - - - - - - - - - - - - - - -- U S E R I N T E R F A C E -- - - - - - - - - - - - - - - - - - - - - - - - From a85364ecff3d2bd9eaab0fc22fd6202265169af3 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sat, 25 Mar 2023 13:24:04 -0400 Subject: [PATCH 226/445] Updated documentation --- ChangeLog.md | 6 ++++++ README.md | 1 + 2 files changed, 7 insertions(+) diff --git a/ChangeLog.md b/ChangeLog.md index a38901d8..d935ab16 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,5 +1,11 @@ ## Changes from most recent to oldest +**25 Mar 2023 - wpferguson** +* Added script_manager darktable shortcut integration +* Moved filename/path/extension string functions to string library + +**06 Mar 2023 - wpferguson - Added option to disable script_manager update check** + **12 Jan 2022 - wpferguson - Documented contrib/rename_images.lua** **28 Dec 2021 - wpferguson - Replaced deprecated _which_ command with _command -v_ in lib/dtutils/file.lua** diff --git a/README.md b/README.md index 598b4c2a..c89804d8 100644 --- a/README.md +++ b/README.md @@ -116,6 +116,7 @@ The following third-party projects are listed for information only. Think of thi * [arru/darktable-scripts](https://github.com/arru/darktable-scripts) * [nbremond77/darktable](https://github.com/nbremond77/darktable/tree/master/scripts) * [s5k6/dtscripts](https://github.com/s5k6/dtscripts) +* [ChristianBirzer/darktable_extra_scripts](https://github.com/ChristianBirzer/darktable_extra_scripts) ## Download and Install From 6bf3706455ba1104fbc3136b34804124491f3764 Mon Sep 17 00:00:00 2001 From: dterrahe Date: Sat, 25 Mar 2023 18:14:19 +0000 Subject: [PATCH 227/445] add x-touch color calibration customisation --- examples/x-touch.lua | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/examples/x-touch.lua b/examples/x-touch.lua index 6adfa4c3..0aa2e6fc 100644 --- a/examples/x-touch.lua +++ b/examples/x-touch.lua @@ -1,7 +1,7 @@ local dt = require "darktable" local du = require "lib/dtutils" -du.check_min_api_version("9.1.0", "x-touch") +du.check_min_api_version("9.1.0", "x-touch") function knob(action, element, effect, size) k = tonumber(action:sub(-1)) @@ -11,16 +11,30 @@ function knob(action, element, effect, size) which = "lib/masks/properties/" .. s[k] elseif dt.gui.action("iop/colorzones", "focus") ~= 0 then + which = "iop/colorzones/graph" local e = { "red", "orange", "yellow", "green", "aqua", "blue", "purple", "magenta" } element = e[k] - which = "iop/colorzones/graph" elseif dt.gui.action("iop/toneequal", "focus") ~= 0 then which ="iop/toneequal/simple/"..(k-9).." EV" - elseif k == 4 and dt.gui.action("iop/colorbalancergb", "focus") ~= 0 then + elseif dt.gui.action("iop/colorbalancergb", "focus") ~= 0 and k == 4 then which = "iop/colorbalancergb/contrast" + elseif dt.gui.action("iop/channelmixerrgb", "focus") ~= 0 and k >= 5 then + if k == 5 then + which = "iop/channelmixerrgb/page" + element = "CAT" + if effect == "up" then effect = "next" + elseif effect == "down" then effect = "previous" + else effect = "activate" + end + else + which = "iop/focus/sliders" + local e = { "1st", "2nd", "3rd" } + element = e[k - 5] + end + else local s = { "iop/exposure/exposure", "iop/filmicrgb/white relative exposure", @@ -32,6 +46,7 @@ function knob(action, element, effect, size) "iop/crop/bottom" } which = s[k] end + return dt.gui.action(which, element, effect, size) end From 3889742e0647fa6d5f550ac53c6f94521f0492e1 Mon Sep 17 00:00:00 2001 From: dterrahe Date: Sat, 25 Mar 2023 18:49:55 +0000 Subject: [PATCH 228/445] add x-touch mini script documentation --- examples/x-touch.lua | 52 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/examples/x-touch.lua b/examples/x-touch.lua index 0aa2e6fc..0cb31c16 100644 --- a/examples/x-touch.lua +++ b/examples/x-touch.lua @@ -1,3 +1,55 @@ +--[[ + This file is part of darktable, + copyright (c) 2023 Diederik ter Rahe + + darktable is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + darktable is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with darktable. If not, see . +]] +--[[ +X-Touch Mini flexible encoder shortcuts + +This script will create virtual sliders that are mapped dynamically to +the most relevant sliders for the currently focused processing module. +Tailored modules are color zones, tone equalizer, color calibration and +mask manager properties. The script can easily be amended for other +devices or personal preferences. Virtual "toggle" buttons can be created +as well, that dynamically change meaning depending on current status. + +USAGE +* require this script from your main lua file +* restart darktable +* create shortcuts for each of the encoders on the x-touch mini + to a virtual slider under lua/x-touch + or import the following shortcutsrc file in the shortcuts dialog/preferences tab: + +None;midi:CC1=lua/x-touch/knob 1 +None;midi:CC2=lua/x-touch/knob 2 +None;midi:CC3=lua/x-touch/knob 3 +None;midi:CC4=lua/x-touch/knob 4 +None;midi:CC5=lua/x-touch/knob 5 +None;midi:CC6=lua/x-touch/knob 6 +None;midi:CC7=lua/x-touch/knob 7 +None;midi:CC8=lua/x-touch/knob 8 +midi:E0=global/modifiers +midi:F0=global/modifiers;ctrl +midi:F#0=global/modifiers;alt +midi:G#-1=iop/blend/tools/show and edit mask elements +midi:A-1=iop/colorzones;focus +midi:A#-1=iop/toneequal;focus +midi:B-1=iop/colorbalancergb;focus +midi:C0=iop/channelmixerrgb;focus +]] + local dt = require "darktable" local du = require "lib/dtutils" From c9943a206519352b156b7312b22a3707d87cb3dc Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sat, 25 Mar 2023 17:02:48 -0400 Subject: [PATCH 229/445] lib/dtutils/string - Added logging capability with the ability to set library logging level from a user script --- lib/dtutils/string.lua | 117 +++++++++++++++++++++++++++++++---------- 1 file changed, 88 insertions(+), 29 deletions(-) diff --git a/lib/dtutils/string.lua b/lib/dtutils/string.lua index f7159a2f..6b716929 100644 --- a/lib/dtutils/string.lua +++ b/lib/dtutils/string.lua @@ -1,6 +1,12 @@ local dtutils_string = {} local dt = require "darktable" +local du = require "lib/dtutils" +local log = require "lib/dtutils.log" + +local DEFAULT_LOG_LEVEL = log.error + +dtutils_string.log_level = DEFAULT_LOG_LEVEL dtutils_string.libdoc = { Name = [[dtutils.string]], @@ -48,6 +54,8 @@ dtutils_string.libdoc.functions["strip_accents"] = { } function dtutils_string.strip_accents( str ) + local old_log_level = log.log_level() + log.log_level(dtutils_string.log_level) local tableAccents = {} tableAccents["à"] = "a" tableAccents["á"] = "a" @@ -111,6 +119,7 @@ function dtutils_string.strip_accents( str ) end end + log.log_level(old_log_level) return normalizedString end @@ -136,6 +145,8 @@ dtutils_string.libdoc.functions["escape_xml_characters"] = { -- Keep & first, otherwise it will double escape other characters function dtutils_string.escape_xml_characters( str ) + local old_log_level = log.log_level() + log.log_level(dtutils_string.log_level) str = string.gsub(str,"&", "&") str = string.gsub(str,"\"", """) @@ -143,6 +154,7 @@ function dtutils_string.escape_xml_characters( str ) str = string.gsub(str,"<", "<") str = string.gsub(str,">", ">") + log.log_level(old_log_level) return str end @@ -165,11 +177,14 @@ dtutils_string.libdoc.functions["urlencode"] = { } function dtutils_string.urlencode(str) + local old_log_level = log.log_level() + log.log_level(dtutils_string.log_level) if (str) then str = string.gsub (str, "\n", "\r\n") str = string.gsub (str, "([^%w ])", function (c) return string.format ("%%%02X", string.byte(c)) end) str = string.gsub (str, " ", "+") end + log.log_level(old_log_level) return str end @@ -192,38 +207,52 @@ dtutils_string.libdoc.functions["is_not_sanitized"] = { } local function _is_not_sanitized_posix(str) - -- A sanitized string must be quoted. - if not string.match(str, "^'.*'$") then - return true + local old_log_level = log.log_level() + log.log_level(dtutils_string.log_level) + -- A sanitized string must be quoted. + if not string.match(str, "^'.*'$") then + log.log_level(old_log_level) + return true -- A quoted string containing no quote characters within is sanitized. - elseif string.match(str, "^'[^']*'$") then - return false - end + elseif string.match(str, "^'[^']*'$") then + log.log_level(old_log_level) + return false + end - -- Any quote characters within a sanitized string must be properly - -- escaped. - local quotesStripped = string.sub(str, 2, -2) - local escapedQuotesRemoved = string.gsub(quotesStripped, "'\\''", "") - if string.find(escapedQuotesRemoved, "'") then - return true - else - return false - end + -- Any quote characters within a sanitized string must be properly + -- escaped. + local quotesStripped = string.sub(str, 2, -2) + local escapedQuotesRemoved = string.gsub(quotesStripped, "'\\''", "") + if string.find(escapedQuotesRemoved, "'") then + log.log_level(old_log_level) + return true + else + log.log_level(old_log_level) + return false + end end local function _is_not_sanitized_windows(str) - if not string.match(str, "^\".*\"$") then - return true - else - return false - end + local old_log_level = log.log_level() + log.log_level(dtutils_string.log_level) + if not string.match(str, "^\".*\"$") then + log.log_level(old_log_level) + return true + else + log.log_level(old_log_level) + return false + end end function dtutils_string.is_not_sanitized(str) + local old_log_level = log.log_level() + log.log_level(dtutils_string.log_level) if dt.configuration.running_os == "windows" then - return _is_not_sanitized_windows(str) + log.log_level(old_log_level) + return _is_not_sanitized_windows(str) else - return _is_not_sanitized_posix(str) + log.log_level(old_log_level) + return _is_not_sanitized_posix(str) end end @@ -246,26 +275,38 @@ dtutils_string.libdoc.functions["sanitize"] = { } local function _sanitize_posix(str) + local old_log_level = log.log_level() + log.log_level(dtutils_string.log_level) if _is_not_sanitized_posix(str) then - return "'" .. string.gsub(str, "'", "'\\''") .. "'" + log.log_level(old_log_level) + return "'" .. string.gsub(str, "'", "'\\''") .. "'" else - return str + log.log_level(old_log_level) + return str end end local function _sanitize_windows(str) + local old_log_level = log.log_level() + log.log_level(dtutils_string.log_level) if _is_not_sanitized_windows(str) then - return "\"" .. string.gsub(str, "\"", "\"^\"\"") .. "\"" + log.log_level(old_log_level) + return "\"" .. string.gsub(str, "\"", "\"^\"\"") .. "\"" else - return str + log.log_level(old_log_level) + return str end end function dtutils_string.sanitize(str) + local old_log_level = log.log_level() + log.log_level(dtutils_string.log_level) if dt.configuration.running_os == "windows" then - return _sanitize_windows(str) + log.log_level(old_log_level) + return _sanitize_windows(str) else - return _sanitize_posix(str) + log.log_level(old_log_level) + return _sanitize_posix(str) end end @@ -288,9 +329,12 @@ dtutils_string.libdoc.functions["sanitize_lua"] = { } function dtutils_string.sanitize_lua(str) + local old_log_level = log.log_level() + log.log_level(dtutils_string.log_level) str = string.gsub(str, "%-", "%%-") str = string.gsub(str, "%(", "%%(") str = string.gsub(str, "%)", "%%)") + log.log_level(old_log_level) return str end @@ -313,7 +357,9 @@ dtutils_string.libdoc.functions["split_filepath"] = { } function dtutils_string.split_filepath(str) - -- strip out single quotes from quoted pathnames + local old_log_level = log.log_level() + log.log_level(dtutils_string.log_level) + -- strip out single quotes from quoted pathnames str = string.gsub(str, "'", "") str = string.gsub(str, '"', '') local result = {} @@ -323,6 +369,7 @@ function dtutils_string.split_filepath(str) result["basename"] = result["filetype"] result["filetype"] = "" end + log.log_level(old_log_level) return result end @@ -344,7 +391,10 @@ dtutils_string.libdoc.functions["get_path"] = { } function dtutils_string.get_path(str) + local old_log_level = log.log_level() + log.log_level(dtutils_string.log_level) local parts = dtutils_string.split_filepath(str) + log.log_level(old_log_level) return parts["path"] end @@ -366,7 +416,10 @@ dtutils_string.libdoc.functions["get_filename"] = { } function dtutils_string.get_filename(str) + local old_log_level = log.log_level() + log.log_level(dtutils_string.log_level) local parts = dtutils_string.split_filepath(str) + log.log_level(old_log_level) return parts["filename"] end @@ -389,7 +442,10 @@ dtutils_string.libdoc.functions["get_basename"] = { } function dtutils_string.get_basename(str) + local old_log_level = log.log_level() + log.log_level(dtutils_string.log_level) local parts = dtutils_string.split_filepath(str) + log.log_level(old_log_level) return parts["basename"] end @@ -411,7 +467,10 @@ dtutils_string.libdoc.functions["get_filetype"] = { } function dtutils_string.get_filetype(str) + local old_log_level = log.log_level() + log.log_level(dtutils_string.log_level) local parts = dtutils_string.split_filepath(str) + log.log_level(old_log_level) return parts["filetype"] end From 5331a38f10fdbbd85894ec6b9cd096e242370aa4 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sat, 25 Mar 2023 17:05:11 -0400 Subject: [PATCH 230/445] lib/dtutils/string - added % and + to sanitize_lua() to prevent pattern matching problems --- lib/dtutils/string.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/dtutils/string.lua b/lib/dtutils/string.lua index 6b716929..b988731e 100644 --- a/lib/dtutils/string.lua +++ b/lib/dtutils/string.lua @@ -331,9 +331,11 @@ dtutils_string.libdoc.functions["sanitize_lua"] = { function dtutils_string.sanitize_lua(str) local old_log_level = log.log_level() log.log_level(dtutils_string.log_level) + str = string.gsub(str, "%%", "%%%%") str = string.gsub(str, "%-", "%%-") str = string.gsub(str, "%(", "%%(") str = string.gsub(str, "%)", "%%)") + str = string.gsub(str, "+", "%%+") log.log_level(old_log_level) return str end From ad10542b3025a2a4e32d87cc3bd1ca61351a0fdb Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sun, 26 Mar 2023 14:55:40 -0400 Subject: [PATCH 231/445] lib/dtutils/string - Added variable substitution functions that are equivalent to the darktable variable substitution functions. --- lib/dtutils/string.lua | 411 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 411 insertions(+) diff --git a/lib/dtutils/string.lua b/lib/dtutils/string.lua index b988731e..e315edaa 100644 --- a/lib/dtutils/string.lua +++ b/lib/dtutils/string.lua @@ -476,6 +476,417 @@ function dtutils_string.get_filetype(str) return parts["filetype"] end +local substitutes = {} + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- C O N S T A N T S +-- - - - - - - - - - - - - - - - - - - - - - - - + +local PLACEHOLDERS = {"ROLL.NAME", + "FILE.FOLDER", + "FILE.NAME", + "FILE.EXTENSION", + "ID", + "VERSION", + "VERSION.IF.MULTI", -- Not Implemented + "VERSION.NAME", + "DARKTABLE.VERSION", + "DARKTABLE.NAME", -- Not Implemented + "SEQUENCE", + "WIDTH.SENSOR", + "HEIGHT.SENSOR", + "WIDTH.RAW", + "HEIGHT.RAW", + "WIDTH.CROP", + "HEIGHT.CROP", + "WIDTH.EXPORT", + "HEIGHT.EXPORT", + "WIDTH.MAX", -- Not Implemented + "HEIGHT.MAX", -- Not Implemented + "YEAR", + "MONTH", + "DAY", + "HOUR", + "MINUTE", + "SECOND", + "MSEC", + "EXIF.YEAR", + "EXIF.MONTH", + "EXIF.DAY", + "EXIF.HOUR", + "EXIF.MINUTE", + "EXIF.SECOND", + "EXIF.MSEC", + "EXIF.DATE.REGIONAL", -- Not Implemented + "EXIF.TIME.REGIONAL", -- Not Implemented + "EXIF.ISO", + "EXIF.EXPOSURE", + "EXIF.EXPOSURE.BIAS", + "EXIF.APERTURE", + "EXIF.FOCAL.LENGTH", + "EXIF.FOCUS.DISTANCE", + "LONGITUDE", + "LATITUDE", + "ALTITUDE", + "STARS", + "RATING.ICONS", -- Not Implemented + "LABELS", + "LABELS.ICONS", -- Not Implemented + "MAKER", + "MODEL", + "TITLE", + "DESCRIPTION", + "CREATOR", + "PUBLISHER", + "RIGHTS", + "TAGS", -- Not Implemented + "CATEGORY", -- Not Implemented + "SIDECAR.TXT", -- Not Implemented + "FOLDER.PICTURES", + "FOLDER.HOME", + "FOLDER.DESKTOP", + "OPENCL.ACTIVATED", -- Not Implemented + "USERNAME", + "NL", + "JOBCODE" -- Not Implemented +} + +local PS = dt.configuration.running_os == "windows" and "\\" or "/" +local USER = os.getenv("USERNAME") +local HOME = dt.configuration.running_os == "windows" and os.getenv("HOMEPATH") or os.getenv("HOME") +local PICTURES = HOME .. PS .. (dt.configuration.running_os == "windows" and "My Pictures" or "Pictures") +local DESKTOP = HOME .. PS .. "Desktop" + +local function get_colorlabels(image) + local old_log_level = log.log_level() + log.log_level(dtutils_string.log_level) + local colorlabels = {} + if image.red then table.insert(colorlabels, "red") end + if image.yellow then table.insert(colorlabels, "yellow") end + if image.green then table.insert(colorlabels, "green") end + if image.blue then table.insert(colorlabels, "blue") end + if image.purple then table.insert(colorlabels, "purple") end + local labels = #colorlabels == 1 and colorlabels[1] or du.join(colorlabels, ",") + log.log_level(old_log_level) + return labels +end + +dtutils_string.libdoc.functions["build_substitution_list"] = { + Name = [[build_substitution_list]], + Synopsis = [[build a list of variable substitutions]], + Usage = [[local ds = require "lib/dtutils.string" + ds.build_substitution_list(image, sequence, [username], [pic_folder], [home], [desktop]) + image - dt_lua_image_t - the image being processed + sequence - integer - the sequence number of the image + [username] - string - optional - user name. Will be determined if not supplied + [pic_folder] - string - optional - pictures folder name. Will be determined if not supplied + [home] - string - optional - home directory. Will be determined if not supplied + [desktop] - string - optional - desktop directory. Will be determined if not supplied]], + Description = [[build_substitution_list populates variables with values from the arguments + and determined from the system and darktable.]], + Return_Value = [[]], + Limitations = [[If the value for a variable can not be determined, or if it is not supported, + then an empty string is used for the value.]], + Example = [[]], + See_Also = [[https://docs.darktable.org/usermanual/4.2/en/special-topics/variables/]], + Reference = [[]], + License = [[]], + Copyright = [[]], +} + +function dtutils_string.build_substition_list(image, sequence, username, pic_folder, home, desktop) + -- build the argument substitution list from each image + + local old_log_level = log.log_level() + log.log_level(dtutils_string.log_level) + + local is_api_9_1 = true + if dt.configuration.api_version_string < "9.1.0" then + is_api_9_1 = false + end + + local datetime = os.date("*t") + local user_name = username or USER + local pictures_folder = pic_folder or PICTURES + local home_folder = home or HOME + log.msg(log.info, "home is " .. tostring(home) .. " and HOME is " .. tostring(HOME) .. " and home_folder is " .. tostring(home_folder)) + local desktop_folder = desktop or DESKTOP + + local labels = get_colorlabels(image) + log.msg(log.info, "image date time taken is " .. image.exif_datetime_taken) + local eyear, emon, eday, ehour, emin, esec, emsec + if dt.preferences.read("darktable", "lighttable/ui/milliseconds", "bool") and is_api_9_1 then + eyear, emon, eday, ehour, emin, esec, emsec = + string.match(image.exif_datetime_taken, "(%d+):(%d+):(%d+) (%d+):(%d+):(%d+)%.(%d+)$") + else + emsec = "0" + eyear, emon, eday, ehour, emin, esec = + string.match(image.exif_datetime_taken, "(%d+):(%d+):(%d+) (%d+):(%d+):(%d+)$") + end + local replacements = {image.film, -- ROLL.NAME + image.path, -- FILE.FOLDER + image.filename, -- FILE.NAME + dtutils_string.get_filetype(image.filename),-- FILE.EXTENSION + image.id, -- ID + image.duplicate_index, -- VERSION + "", -- VERSION.IF_MULTI + image.version_name, -- VERSION.NAME + dt.configuration.version, -- DARKTABLE.VERSION + "", -- DARKTABLE.NAME + sequence, -- SEQUENCE + image.width, -- WIDTH.SENSOR + image.height, -- HEIGHT.SENSOR + is_api_9_1 and image.p_width or "", -- WIDTH.RAW + is_api_9_1 and image.p_height or "", -- HEIGHT.RAW + is_api_9_1 and image.final_width or "", -- WIDTH.CROP + is_api_9_1 and image.final_height or "", -- HEIGHT.CROP + is_api_9_1 and image.final_width or "", -- WIDTH.EXPORT + is_api_9_1 and image.final_height or "", -- HEIGHT.EXPORT + "", -- WIDTH.MAX + "", -- HEIGHT.MAX + string.format("%4d", datetime.year), -- YEAR + string.format("%02d", datetime.month), -- MONTH + string.format("%02d", datetime.day), -- DAY + string.format("%02d", datetime.hour), -- HOUR + string.format("%02d", datetime.min), -- MINUTE + string.format("%02d", datetime.sec), -- SECOND + "", -- MSEC + eyear, -- EXIF.YEAR + emon, -- EXIF.MONTH + eday, -- EXIF.DAY + ehour, -- EXIF.HOUR + emin, -- EXIF.MINUTE + esec, -- EXIF.SECOND + emsec, -- EXIF.MSEC + "", -- EXIF.DATE.REGIONAL + "", -- EXIF.TIME.REGIONAL + string.format("%d", image.exif_iso), -- EXIF.ISO + string.format("1/%.0f", 1./image.exif_exposure), -- EXIF.EXPOSURE + image.exif_exposure_bias, -- EXIF.EXPOSURE.BIAS + string.format("%.01f", image.exif_aperture), -- EXIF.APERTURE + string.format("%.0f", image.exif_focal_length), -- EXIF.FOCAL.LENGTH + image.exif_focus_distance, -- EXIF.FOCUS.DISTANCE + image.longitude or "", -- LONGITUDE + image.latitude or "", -- LATITUDE + image.elevation or "", -- ALTITUDE + image.rating, -- STARS + "", -- RATING.ICONS + labels, -- LABELS + "", -- LABELS.ICONS + image.exif_maker, -- MAKER + image.exif_model, -- MODEL + image.title, -- TITLE + image.description, -- DESCRIPTION + image.creator, -- CREATOR + image.publisher, -- PUBLISHER + image.rights, -- RIGHTS + "", -- TAGS + "", -- CATEGORYn + "", -- SIDECAR.TXT + pictures_folder, -- FOLDER.PICTURES + home_folder, -- FOLDER.HOME + desktop_folder, -- FOLDER.DESKTOP + "", -- OPENCL.ACTIVATED + user_name, -- USERNAME + "\n", -- NL + "" -- JOBCODE + } + + for i = 1, #PLACEHOLDERS, 1 do + substitutes[PLACEHOLDERS[i]] = replacements[i] + log.msg(log.info, "setting " .. PLACEHOLDERS[i] .. " to " .. tostring(replacements[i])) + end + log.log_level(old_log_level) +end + +local function check_legacy_vars(var_name) + local var = var_name + if string.match(var, "_") then + var = string.gsub(var, "_", ".") + end + if string.match(var, "^HOME$") then var = "FOLDER.HOME" end + if string.match(var, "^PICTURES.FOLDER$") then var = "FOLDER.PICTURES" end + if string.match(var, "^DESKTOP$") then var = "FOLDER.DESKTOP" end + return var +end + +local function treat(var_string) + local old_log_level = log.log_level() + log.log_level(dtutils_string.log_level) + local ret_val = "" + -- remove the var from the string + local var = string.match(var_string, "[%a%._]+") + var = check_legacy_vars(var) + log.msg(log.info, "var_string is " .. tostring(var_string) .. " and var is " .. tostring(var)) + ret_val = substitutes[var] + if not ret_val then + log.msg(log.error, "variable " .. var .. " is not an allowed variable, returning empty value") + log.log_level(old_log_level) + return "" + end + local args = string.gsub(var_string, var, "") + log.msg(log.info, "args is " .. tostring(args)) + if string.len(args) > 0 then + if string.match(args, '^%^%^') then + ret_val = string.upper(ret_val) + elseif string.match(args, "^%^") then + ret_val = string.gsub(ret_val, "^%a", string.upper, 1) + elseif string.match(args, "^,,") then + ret_val = string.lower(ret_val) + elseif string.match(args, "^,") then + ret_val = string.gsub(ret_val, "^%a", string.lower, 1) + elseif string.match(args, "^:%-?%d+:%-?%d+") then + local soffset, slen = string.match(args, ":(%-?%d+):(%-?%d+)") + log.msg(log.info, "soffset is " .. soffset .. " and slen is " .. slen) + if tonumber(soffset) >= 0 then + soffset = soffset + 1 + end + log.msg(log.info, "soffset is " .. soffset .. " and slen is " .. slen) + if tonumber(soffset) < 0 and tonumber(slen) < 0 then + local temp = soffset + soffset = slen + slen = temp + end + log.msg(log.info, "soffset is " .. soffset .. " and slen is " .. slen) + ret_val = string.sub(ret_val, soffset, slen) + log.msg(log.info, "ret_val is " .. ret_val) + elseif string.match(args, "^:%-?%d+") then + local soffset= string.match(args, ":(%-?%d+)") + if tonumber(soffset) >= 0 then + soffset = soffset + 1 + end + ret_val = string.sub(ret_val, soffset, -1) + elseif string.match(args, "^-%$%(.-%)") then + local replacement = string.match(args, "-%$%(([%a%._]+)%)") + replacement = check_legacy_vars(replacement) + if string.len(ret_val) == 0 then + ret_val = substitutes[replacement] + end + elseif string.match(args, "^-.+$") then + local replacement = string.match(args, "-(.+)$") + if string.len(ret_val) == 0 then + ret_val = replacement + end + elseif string.match(args, "^+.+") then + local replacement = string.match(args, "+(.+)") + if string.len(ret_val) > 0 then + ret_val = replacement + end + elseif string.match(args, "^#.+") then + local pattern = string.match(args, "#(.+)") + log.msg(log.info, "pattern to remove is " .. tostring(pattern)) + ret_val = string.gsub(ret_val, "^" .. dtutils_string.sanitize_lua(pattern), "") + elseif string.match(args, "^%%.+") then + local pattern = string.match(args, "%%(.+)") + ret_val = string.gsub(ret_val, pattern .. "$", "") + elseif string.match(args, "^//.-/.+") then + local pattern, replacement = string.match(args, "//(.-)/(.+)") + ret_val = string.gsub(ret_val, pattern, replacement) + elseif string.match(args, "^/#.+/.+") then + local pattern, replacement = string.match(args, "/#(.+)/(.+)") + ret_val = string.gsub(ret_val, "^" .. pattern, replacement, 1) + elseif string.match(args, "^/%%.-/.+") then + local pattern, replacement = string.match(args, "/%%(.-)/(.+)") + ret_val = string.gsub(ret_val, pattern .. "$", replacement) + elseif string.match(args, "^/.-/.+") then + log.msg(log.info, "took replacement branch") + local pattern, replacement = string.match(args, "/(.-)/(.+)") + ret_val = string.gsub(ret_val, pattern, replacement, 1) + end + end + log.log_level(old_log_level) + return ret_val +end + +dtutils_string.libdoc.functions["substitute_list"] = { + Name = [[substitute_list]], + Synopsis = [[Replace variables in a string with their computed values]], + Usage = [[local ds = require "lib/dtutils.string" + local result = ds.substitute_list(str) + str - string - the string containing the variables to be substituted for]], + Description = [[substitute_list replaces the variables in the supplied string with + values computed in build_substitution_list().]], + Return_Value = [[result - string - the input string with values substituted for the variables]], + Limitations = [[]], + Example = [[]], + See_Also = [[]], + Reference = [[]], + License = [[]], + Copyright = [[]], +} + +function dtutils_string.substitute_list(str) + local old_log_level = log.log_level() + log.log_level(dtutils_string.log_level) + -- replace the substitution variables in a string + for match in string.gmatch(str, "%$%(.-%)?%)") do + local var = string.match(match, "%$%((.-%)?)%)") + local treated_var = treat(var) + log.msg(log.info, "var is " .. var .. " and treated var is " .. tostring(treated_var)) + str = string.gsub(str, "%$%(".. dtutils_string.sanitize_lua(var) .."%)", tostring(treated_var)) + log.msg(log.info, "str after replacement is " .. str) + end + log.log_level(old_log_level) + return str +end + +dtutils_string.libdoc.functions["clear_substitute_list"] = { + Name = [[clear_substitute_list]], + Synopsis = [[Clear the computed list of variable substitution values]], + Usage = [[local ds = require "lib/dtutils.string" + ds.clear_substitute_list()]], + Description = [[clear_substitute_list resets the list of variable replacement values]], + Return_Value = [[]], + Limitations = [[]], + Example = [[]], + See_Also = [[]], + Reference = [[]], + License = [[]], + Copyright = [[]], +} + +function dtutils_string.clear_substitute_list() + local old_log_level = log.log_level() + log.log_level(dtutils_string.log_level) + for i = 1, #PLACEHOLDERS, 1 do + substitutes[PLACEHOLDERS[i]] = nil + end + log.log_level(old_log_level) +end + +dtutils_string.libdoc.functions["substitute"] = { + Name = [[substitute]], + Synopsis = [[Check if a string has been sanitized]], + Usage = [[local ds = require "lib/dtutils.string" + ds.substitute(image, sequence, [username], [pic_folder], [home], [desktop]) + image - dt_lua_image_t - the image being processed + sequence - integer - the sequence number of the image + [username] - string - optional - user name. Will be determined if not supplied + [pic_folder] - string - optional - pictures folder name. Will be determined if not supplied + [home] - string - optional - home directory. Will be determined if not supplied + [desktop] - string - optional - desktop directory. Will be determined if not supplied]], + Description = [[substitute initializes the substitution list by calling clear_substitute_list(), + then builds the substitutions by calling build_substitution_list() and finally does the + substitution by calling substitute_list(), then returns the result string.]], + Return_Value = [[result - string - the input string with values substituted for the variables]], + Limitations = [[]], + Example = [[]], + See_Also = [[]], + Reference = [[]], + License = [[]], + Copyright = [[]], +} + +function dtutils_string.substitute(image, sequence, variable_string, username, pic_folder, home, desktop) + local old_log_level = log.log_level() + log.log_level(dtutils_string.log_level) + dtutils_string.clear_substitute_list() + dtutils_string.build_substition_list(image, sequence, username, pic_folder, home, desktop) + local str = dtutils_string.substitute_list(variable_string) + log.log_level(old_log_level) + return str +end + return dtutils_string From 7ac37ddc1a2abfc94c9c6d7091e8e5c61b32f76f Mon Sep 17 00:00:00 2001 From: dterrahe Date: Wed, 3 May 2023 23:43:01 +0100 Subject: [PATCH 232/445] Probe individual mask sliders --- examples/x-touch.lua | 138 ++++++++++++++++++++++++++++--------------- 1 file changed, 89 insertions(+), 49 deletions(-) diff --git a/examples/x-touch.lua b/examples/x-touch.lua index 0cb31c16..c1020fa3 100644 --- a/examples/x-touch.lua +++ b/examples/x-touch.lua @@ -18,7 +18,7 @@ --[[ X-Touch Mini flexible encoder shortcuts -This script will create virtual sliders that are mapped dynamically to +This script will create virtual sliders that are mapped dynamically to the most relevant sliders for the currently focused processing module. Tailored modules are color zones, tone equalizer, color calibration and mask manager properties. The script can easily be amended for other @@ -28,8 +28,8 @@ as well, that dynamically change meaning depending on current status. USAGE * require this script from your main lua file * restart darktable -* create shortcuts for each of the encoders on the x-touch mini - to a virtual slider under lua/x-touch +* create shortcuts for each of the encoders on the x-touch mini + to a virtual slider under lua/x-touch or import the following shortcutsrc file in the shortcuts dialog/preferences tab: None;midi:CC1=lua/x-touch/knob 1 @@ -55,53 +55,93 @@ local du = require "lib/dtutils" du.check_min_api_version("9.1.0", "x-touch") -function knob(action, element, effect, size) - k = tonumber(action:sub(-1)) - - if dt.gui.action("iop/blend/tools/show and edit mask elements") ~= 0 then - local s = { "opacity", "size", "feather", "hardness","rotation","curvature","compression" } - which = "lib/masks/properties/" .. s[k] - - elseif dt.gui.action("iop/colorzones", "focus") ~= 0 then - which = "iop/colorzones/graph" - local e = { "red", "orange", "yellow", "green", "aqua", "blue", "purple", "magenta" } - element = e[k] - - elseif dt.gui.action("iop/toneequal", "focus") ~= 0 then - which ="iop/toneequal/simple/"..(k-9).." EV" - - elseif dt.gui.action("iop/colorbalancergb", "focus") ~= 0 and k == 4 then - which = "iop/colorbalancergb/contrast" +-- set up 8 mimic sliders with the same function +for k = 1,8 do + dt.gui.mimic("slider", "knob ".. k, + function(action, element, effect, size) + -- take the number from the mimic name + local k = tonumber(action:sub(-1)) + + -- only operate in darkroom; return NAN otherwise + if dt.gui.current_view() ~= dt.gui.views.darkroom then + return 0/0 + end - elseif dt.gui.action("iop/channelmixerrgb", "focus") ~= 0 and k >= 5 then - if k == 5 then - which = "iop/channelmixerrgb/page" - element = "CAT" - if effect == "up" then effect = "next" - elseif effect == "down" then effect = "previous" - else effect = "activate" + -- first try if the mask slider at that position is active + local s = { "opacity", + "size", + "feather", + "hardness", + "rotation", + "curvature", + "compression" } + local maskval = dt.gui.action("lib/masks/properties/" .. s[k], + element, effect, size) + -- if a value different from NAN is returned, the slider was active + if maskval == maskval then + return maskval + + -- try if colorzones module is focused; if so select element of graph + elseif dt.gui.action("iop/colorzones", "focus") ~= 0 then + which = "iop/colorzones/graph" + local e = { "red", + "orange", + "yellow", + "green", + "aqua", + "blue", + "purple", + "magenta" } + element = e[k] + + -- if the tone equalizer is focused, + -- select one of the sliders in the "simple" tab + elseif dt.gui.action("iop/toneequal", "focus") ~= 0 then + which ="iop/toneequal/simple/"..(k-9).." EV" + + -- if color calibration is focused, + -- the last 4 knobs are sent there + elseif dt.gui.action("iop/channelmixerrgb", "focus") ~= 0 + and k >= 5 then + -- knob 5 selects the active tab; pressing it resets to CAT + if k == 5 then + which = "iop/channelmixerrgb/page" + element = "CAT" + -- since the tab action is not a slider, + -- the effects need to be translated + if effect == "up" then effect = "next" + elseif effect == "down" then effect = "previous" + else effect = "activate" + end + else + -- knobs 6, 7 and 8 are for the three color sliders on each tab + which = "iop/focus/sliders" + local e = { "1st", + "2nd", + "3rd" } + element = e[k - 5] + end + + -- the 4th knob is contrast; + -- either colorbalance if it is focused, or filmic + elseif dt.gui.action("iop/colorbalancergb", "focus") ~= 0 + and k == 4 then + which = "iop/colorbalancergb/contrast" + + -- in all other cases use a default selection + else + local s = { "iop/exposure/exposure", + "iop/filmicrgb/white relative exposure", + "iop/filmicrgb/black relative exposure", + "iop/filmicrgb/contrast", + "iop/crop/left", + "iop/crop/right", + "iop/crop/top", + "iop/crop/bottom" } + which = s[k] end - else - which = "iop/focus/sliders" - local e = { "1st", "2nd", "3rd" } - element = e[k - 5] - end - - else - local s = { "iop/exposure/exposure", - "iop/filmicrgb/white relative exposure", - "iop/filmicrgb/black relative exposure", - "iop/filmicrgb/contrast", - "iop/crop/left", - "iop/crop/right", - "iop/crop/top", - "iop/crop/bottom" } - which = s[k] - end - - return dt.gui.action(which, element, effect, size) -end -for k = 1,8 do - dt.gui.mimic("slider", "knob ".. k, knob) + -- now pass the element/effect/size to the selected slider + return dt.gui.action(which, element, effect, size) + end) end From 4726821e7def774c398579b73c85fe0f02f66c3f Mon Sep 17 00:00:00 2001 From: dterrahe Date: Fri, 5 May 2023 23:19:00 +0100 Subject: [PATCH 233/445] Fix 8th knob --- examples/x-touch.lua | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/examples/x-touch.lua b/examples/x-touch.lua index c1020fa3..7c5b9988 100644 --- a/examples/x-touch.lua +++ b/examples/x-touch.lua @@ -67,16 +67,19 @@ for k = 1,8 do return 0/0 end - -- first try if the mask slider at that position is active - local s = { "opacity", - "size", - "feather", - "hardness", - "rotation", - "curvature", - "compression" } - local maskval = dt.gui.action("lib/masks/properties/" .. s[k], - element, effect, size) + local maskval = 0/0 + if k < 8 then + -- first try if the mask slider at that position is active + local s = { "opacity", + "size", + "feather", + "hardness", + "rotation", + "curvature", + "compression" } + maskval = dt.gui.action("lib/masks/properties/" .. s[k], + element, effect, size) + end -- if a value different from NAN is returned, the slider was active if maskval == maskval then return maskval From 1905be8577689c6e65aed4395fbb83504c60f567 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sat, 6 May 2023 14:31:15 -0400 Subject: [PATCH 234/445] lib/dtutils.lua - added check_max_api_version to handle the case where part of the API is removed as in the case of the darktable.gui.libs.fixter functions. --- lib/dtutils.lua | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/lib/dtutils.lua b/lib/dtutils.lua index 0a6d4416..dcc116a9 100644 --- a/lib/dtutils.lua +++ b/lib/dtutils.lua @@ -69,6 +69,42 @@ function dtutils.check_min_api_version(min_api, script_name) end end +dtutils.libdoc.functions["check_max_api_version"] = { + Name = [[check_max_api_version]], + Synopsis = [[check the maximum required api version against the current api version]], + Usage = [[local du = require "lib/dtutils" + + local result = du.check_max_api_version(max_api, script_name) + max_api - string - the api version that the application was written for (example: "5.0.0") + script_name - string - the name of the script]], + Description = [[check_max_api_version compares the maximum api required for the appllication to + run against the current api version. This function is used when a part of the Lua API that + the script relies on is removed. If the maximum api version is not met, then an + error message is printed saying the script_name failed to load, then an error is thrown causing the + program to stop executing. + + Return_Value = [[result - true if the maximum api version is available, false if not.]], + Limitations = [[When using the default handler on a script being executed from the luarc file, the error thrown + will stop the luarc file from executing any remaining statements. This limitation does not apply to script_manger.]], + Example = [[check_max_api_version("9.0.0") does nothing if the api is less than or equal to 9.0.0 otherwise an + error message is printed and an error is thrown stopping execution of the script.]], + See_Also = [[]], + Reference = [[]], + License = [[]], + Copyright = [[]], +} + +function dtutils.check_max_api_version(max_api, script_name) + local current_api = dt.configuration.api_version_string + if max_api < current_api then + dt.print_error("This application is written for lua api version " .. max_api .. " or earlier.") + dt.print_error("The current lua api version is " .. current_api) + dt.print("ERROR: " .. script_name .. " failed to load. Lua API version " .. max_api .. " or earlier required.") + dt.control.sleep(2000) -- aqllow time for the error to display before script_manager writes it's error message + error("Mzximum API " .. max_api .. " not met for " .. script_name .. ".", 0) + end +end + dtutils.libdoc.functions["split"] = { Name = [[split]], Synopsis = [[split a string on a specified separator]], From e47672b4951f2e6d100bbddb528410d1beafd6a7 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sat, 6 May 2023 14:36:22 -0400 Subject: [PATCH 235/445] lib/dtutils.lua - added delay in check_min_api_version to sllow display of the error message before script_manager displays an error message. --- lib/dtutils.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/dtutils.lua b/lib/dtutils.lua index dcc116a9..ee9f4ee8 100644 --- a/lib/dtutils.lua +++ b/lib/dtutils.lua @@ -65,6 +65,7 @@ function dtutils.check_min_api_version(min_api, script_name) dt.print_error("This application is written for lua api version " .. min_api .. " or later.") dt.print_error("The current lua api version is " .. current_api) dt.print("ERROR: " .. script_name .. " failed to load. Lua API version " .. min_api .. " or later required.") + dt.control.sleep(2000) -- aqllow time for the error to display before script_manager writes it's error message error("Minimum API " .. min_api .. " not met for " .. script_name .. ".", 0) end end From 9e0374d597a7ad17175aa01b556aa5ea6337d672 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sat, 6 May 2023 14:56:58 -0400 Subject: [PATCH 236/445] lib/dtutils.lua - fix typos --- lib/dtutils.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/dtutils.lua b/lib/dtutils.lua index ee9f4ee8..1798163f 100644 --- a/lib/dtutils.lua +++ b/lib/dtutils.lua @@ -65,7 +65,7 @@ function dtutils.check_min_api_version(min_api, script_name) dt.print_error("This application is written for lua api version " .. min_api .. " or later.") dt.print_error("The current lua api version is " .. current_api) dt.print("ERROR: " .. script_name .. " failed to load. Lua API version " .. min_api .. " or later required.") - dt.control.sleep(2000) -- aqllow time for the error to display before script_manager writes it's error message + dt.control.sleep(2000) -- allow time for the error to display before script_manager writes it's error message error("Minimum API " .. min_api .. " not met for " .. script_name .. ".", 0) end end @@ -101,8 +101,8 @@ function dtutils.check_max_api_version(max_api, script_name) dt.print_error("This application is written for lua api version " .. max_api .. " or earlier.") dt.print_error("The current lua api version is " .. current_api) dt.print("ERROR: " .. script_name .. " failed to load. Lua API version " .. max_api .. " or earlier required.") - dt.control.sleep(2000) -- aqllow time for the error to display before script_manager writes it's error message - error("Mzximum API " .. max_api .. " not met for " .. script_name .. ".", 0) + dt.control.sleep(2000) -- allow time for the error to display before script_manager writes it's error message + error("Maximum API " .. max_api .. " not met for " .. script_name .. ".", 0) end end From 3e2d4c956d74e1f388edd93ea9488752bb7ce0ea Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Thu, 22 Jun 2023 16:04:26 -0400 Subject: [PATCH 237/445] tools/script_manager.lua - Documented more fields for the sm.scripts table Removed extra declaration of check_update preference --- tools/script_manager.lua | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/tools/script_manager.lua b/tools/script_manager.lua index 7befa037..b17ec572 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -104,17 +104,6 @@ dt.preferences.register(MODULE, "check_update", "bool", local check_for_updates = dt.preferences.read(MODULE, "check_update", "bool") --- - - - - - - - - - - - - - - - - - - - - - - - --- P R E F E R E N C E S --- - - - - - - - - - - - - - - - - - - - - - - - - -dt.preferences.register(MODULE, "check_update", "bool", - "check for updated scripts on start up", - "automatically update scripts to correct version", - true) - -local check_for_updates = dt.preferences.read(MODULE, "check_update", "bool") - -- - - - - - - - - - - - - - - - - - - - - - - - -- L O G L E V E L -- - - - - - - - - - - - - - - - - - - - - - - - @@ -170,6 +159,8 @@ sm.categories = {} storage_name name of the exporter (in the exporter storage menu) has_action true if it creates an action action_name name on the button + has_select true if it creates a select + select_name name on the button has_event true if it creates an event handler event_type type of event, shortcut, post-xxx, pre-xxx callback name of the callback routine From fad74d6438963a11f3ccf0e7491955e724f57430 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Fri, 23 Jun 2023 19:09:57 -0400 Subject: [PATCH 238/445] tools/script_manager.lua - cleaned up deactivate comments --- tools/script_manager.lua | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tools/script_manager.lua b/tools/script_manager.lua index b17ec572..84e6f0eb 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -368,10 +368,12 @@ local function activate(script) end local function deactivate(script) - -- presently the lua api doesn't support unloading gui elements however, we - -- can hide libs, so we just mark those as hidden and hide the gui - -- can delete storage - --therefore we just mark then inactive for the next time darktable starts + -- presently the lua api doesn't support unloading lib elements however, we + -- can hide libs, so we just mark those as hidden and hide the gui + -- can delete storages + -- can delete actions + -- can delete selects + -- and mark them inactive for the next time darktable starts -- deactivate it.... pref_write(script.script_name, "bool", false) From a4f6af73ec340700ca613a42fcd832487008c646 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sat, 24 Jun 2023 19:56:51 -0400 Subject: [PATCH 239/445] tools/script_manager.lua - enabled log levels in callback routines --- tools/script_manager.lua | 86 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 82 insertions(+), 4 deletions(-) diff --git a/tools/script_manager.lua b/tools/script_manager.lua index 84e6f0eb..1a3b2a27 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -130,6 +130,10 @@ sm.event_registered = false sm.widgets = {} sm.categories = {} +-- set log level for functions + +sm.log_level = DEFAULT_LOG_LEVEL + --[[ sm.scripts is a table of tables for containing the scripts @@ -192,22 +196,42 @@ sm.run = false -- F U N C T I O N S -- - - - - - - - - - - - - - - - - - - - - - - - +------------------- +-- helper functions +------------------- + +local function set_log_level(level) + local old_log_level = log.log_level() + log.log_level(level) + return old_log_level +end + +local function restore_log_level(level) + log.log_level(level) +end + local function pref_read(name, pref_type) + local old_log_level = set_log_level(sm.log_level) log.msg(log.debug, "name is " .. name .. " and type is " .. pref_type) local val = dt.preferences.read(MODULE, name, pref_type) - if not string.match(pref_type, "bool") then - log.msg(log.debug, "read value " .. tostring(val)) - end + log.msg(log.debug, "read value " .. tostring(val)) + restore_log_level(old_log_level) return val end local function pref_write(name, pref_type, value) - dt.preferences.write(MODULE, name, pref_type, value) + local old_log_level = set_log_level(sm.log_level) + log.msg(log.debug, "writing value " .. tostring(value) .. " for name " .. name) + dt.preferences.write(MODULE, name, pref_type, value) + restore_log_level(old_log_level) end +---------------- -- git interface +---------------- local function get_repo_status(repo) + local old_log_level = set_log_level(sm.log_level) local p = io.popen("cd " .. repo .. CS .. "git status") if p then local data = p:read("*a") @@ -215,10 +239,12 @@ local function get_repo_status(repo) return data end log.msg(log.error, "unable to get status of " .. repo) + restore_log_level(old_log_level) return nil end local function get_current_repo_branch(repo) + local old_log_level = set_log_level(sm.log_level) local branch = nil local p = io.popen("cd " .. repo .. CS .. "git branch --all") if p then @@ -237,10 +263,12 @@ local function get_current_repo_branch(repo) if not branch then log.msg(log.error, "no current branch detected in repo_data") end + restore_log_level(old_log_level) return nil end local function get_repo_branches(repo) + local old_log_level = set_log_level(sm.log_level) local branches = {} local p = io.popen("cd " .. repo .. CS .. "git pull --all" .. CS .. "git branch --all") if p then @@ -257,11 +285,13 @@ local function get_repo_branches(repo) end end end + restore_log_level(old_log_level) return branches end local function is_repo_clean(repo_data) + local old_log_level = set_log_level(sm.log_level) if string.match(repo_data, "\n%s-%a.-%a:%s-%a%g-\n") then log.msg(log.info, "repo is dirty") return false @@ -269,14 +299,18 @@ local function is_repo_clean(repo_data) log.msg(log.info, "repo is clean") return true end + restore_log_level(old_log_level) end local function checkout_repo_branch(repo, branch) + local old_log_level = set_log_level(sm.log_level) log.msg(log.info, "checkout out branch " .. branch .. " from repository " .. repo) os.execute("cd " .. repo .. CS .. "git checkout " .. branch) + restore_log_level(old_log_level) end local function update_combobox_choices(combobox, choice_table, selected) + local old_log_level = set_log_level(sm.log_level) local items = #combobox local choices = #choice_table for i, name in ipairs(choice_table) do @@ -292,11 +326,14 @@ local function update_combobox_choices(combobox, choice_table, selected) end combobox.value = selected + restore_log_level(old_log_level) end local function string_trim(str) + local old_log_level = set_log_level(sm.log_level) local result = string.gsub(str, "^%s+", "") result = string.gsub(result, "%s+$", "") + restore_log_level(old_log_level) return result end @@ -305,14 +342,17 @@ local function string_dequote(str) end local function add_script_category(category) + local old_log_level = set_log_level(sm.log_level) if #sm.categories == 0 or not string.match(du.join(sm.categories, " "), ds.sanitize_lua(category)) then table.insert(sm.categories, category) sm.scripts[category] = {} log.msg(log.debug, "created category " .. category) end + restore_log_level(old_log_level) end local function get_script_doc(script) + local old_log_level = set_log_level(sm.log_level) local description = nil f = io.open(LUA_DIR .. PS .. script .. ".lua") if f then @@ -325,13 +365,16 @@ local function get_script_doc(script) log.msg(log.error, _("Cant read from " .. script)) end if description then + restore_log_level(old_log_level) return description else + restore_log_level(old_log_level) return "No documentation available" end end local function activate(script) + local old_log_level = set_log_level(sm.log_level) local status = nil -- status of start function local err = nil -- error message returned if module doesn't start log.msg(log.info, "activating " .. script.name) @@ -364,6 +407,7 @@ local function activate(script) status = true pref_write(script.script_name, "bool", true) end + restore_log_level(old_log_level) return status end @@ -376,6 +420,7 @@ local function deactivate(script) -- and mark them inactive for the next time darktable starts -- deactivate it.... + local old_log_level = set_log_level(sm.log_level) pref_write(script.script_name, "bool", false) if script.data then script.data.destroy() @@ -397,9 +442,11 @@ local function deactivate(script) log.msg(log.info, "setting " .. script.script_name .. " to not start") log.msg(log.screen, script.name .. _(" will not start when darktable is restarted")) end + restore_log_level(old_log_level) end local function add_script_name(name, path, category) + local old_log_level = set_log_level(sm.log_level) log.msg(log.debug, "category is " .. category) log.msg(log.debug, "name is " .. name) local script = { @@ -414,9 +461,11 @@ local function add_script_name(name, path, category) if pref_read(script.script_name, "bool") then activate(script) end + restore_log_level(old_log_level) end local function process_script_data(script_file) + local old_log_level = set_log_level(sm.log_level) -- the script file supplied is category/filename.filetype -- the following pattern splits the string into category, path, name, fileename, and filetype @@ -447,9 +496,11 @@ local function process_script_data(script_file) if name then add_script_name(name, path, category) end + restore_log_level(old_log_level) end local function scan_scripts(script_dir) + local old_log_level = set_log_level(sm.log_level) local script_count = 0 local find_cmd = "find -L " .. script_dir .. " -name \\*.lua -print | sort" if dt.configuration.running_os == "windows" then @@ -472,10 +523,12 @@ local function scan_scripts(script_dir) end end end + restore_log_level(old_log_level) return script_count end local function update_scripts() + local old_log_level = set_log_level(sm.log_level) local result = false local git = sm.executables.git @@ -498,10 +551,12 @@ local function update_scripts() dt.print(_("lua scripts successfully updated")) end + restore_log_level(old_log_level) return result end local function update_script_update_choices() + local old_log_level = set_log_level(sm.log_level) local installs = {} local pref_string = "" for i, repo in ipairs(sm.installed_repositories) do @@ -511,9 +566,11 @@ local function update_script_update_choices() update_combobox_choices(sm.widgets.update_script_choices, installs, 1) log.msg(log.debug, "repo pref string is " .. pref_string) pref_write("installed_repos", "string", pref_string) + restore_log_level(old_log_level) end local function scan_repositories() + local old_log_level = set_log_level(sm.log_level) local script_count = 0 local find_cmd = "find -L " .. LUA_DIR .. " -name \\*.git -print | sort" if dt.configuration.running_os == "windows" then @@ -548,15 +605,18 @@ local function scan_repositories() end end update_script_update_choices() + restore_log_level(old_log_level) end local function install_scripts() + local old_log_level = set_log_level(sm.log_level) local url = sm.widgets.script_url.text local category = sm.widgets.new_category.text if string.match(du.join(sm.categories, " "), ds.sanitize_lua(category)) then log.msg(log.screen, _("category ") .. category .. _(" is already in use. Please specify a different category name.")) log.msg(log.error, "category " .. category .. " already exists, returning...") + restore_log_level(old_log_level) return end @@ -566,6 +626,7 @@ local function install_scripts() if not git then dt.print(_("ERROR: git not found. Install or specify the location of the git executable.")) + restore_log_level(old_log_level) return end @@ -607,28 +668,34 @@ local function install_scripts() dt.print(_("failed to download scripts")) end + restore_log_level(old_log_level) return result end local function clear_button(number) + local old_log_level = set_log_level(sm.log_level) local button = sm.widgets.buttons[number] button.label = "" button.tooltip = "" button.sensitive = false --button.name = "" + restore_log_level(old_log_level) end local function find_script(category, name) + local old_log_level = set_log_level(sm.log_level) log.msg(log.debug, "looking for script " .. name .. " in category " .. category) for _, script in ipairs(sm.scripts[category]) do if string.match(script.name, "^" .. ds.sanitize_lua(name) .. "$") then return script end end + restore_log_level(old_log_level) return nil end local function populate_buttons(category, first, last) + local old_log_level = set_log_level(sm.log_level) log.msg(log.debug, "category is " .. category .. " and first is " .. first .. " and last is " .. last) local button_num = 1 for i = first, last do @@ -693,9 +760,11 @@ local function populate_buttons(category, first, last) clear_button(i) end end + restore_log_level(old_log_level) end local function paginate(direction) + local old_log_level = set_log_level(sm.log_level) local category = sm.page_status.category log.msg(log.debug, "category is " .. category) local num_scripts = #sm.scripts[category] @@ -747,9 +816,11 @@ local function paginate(direction) sm.widgets.page_status.label = _("Page ") .. cur_page .. _(" of ") .. max_pages populate_buttons(category, first, last) + restore_log_level(old_log_level) end local function change_category(category) + local old_log_level = set_log_level(sm.log_level) if not category then log.msg(log.debug "setting category to selector value " .. sm.widgets.category_selector.value) sm.page_status.category = sm.widgets.category_selector.value @@ -759,9 +830,11 @@ local function change_category(category) end paginate(2) + restore_log_level(old_log_level) end local function change_num_buttons() + local old_log_level = set_log_level(sm.log_level) cur_buttons = sm.page_status.num_buttons new_buttons = sm.widgets.num_buttons.value pref_write("num_buttons", "integer", new_buttons) @@ -792,9 +865,11 @@ local function change_num_buttons() log.msg(log.debug, "num_buttons set to " .. sm.page_status.num_buttons) paginate(2) -- force the buttons to repopulate sm.widgets.main_menu.selected = 3 -- jump back to start/stop scripts + restore_log_level(old_log_level) end local function load_preferences() + local old_log_level = set_log_level(sm.log_level) -- load the prefs and update settings -- update_script_choices local pref_string = pref_read("installed_repos", "string") @@ -836,9 +911,11 @@ local function load_preferences() log.msg(log.debug, "set main menu to val " .. val .. " which is " .. sm.widgets.main_menu.value) log.msg(log.debug, "set main menu to " .. sm.widgets.main_menu.value) + restore_log_level(old_log_level) end local function install_module() + local old_log_level = set_log_level(sm.log_level) if not sm.module_installed then dt.register_lib( "script_manager", -- Module name @@ -868,6 +945,7 @@ local function install_module() dt.control.sleep(5000) dt.print_log("setting sm expanded true") dt.gui.libs["script_manager"].expanded = true]] + restore_log_level(old_log_level) end -- - - - - - - - - - - - - - - - - - - - - - - - From 236b25a235e733e108103f3203eaa4bf987ae378 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Mon, 3 Jul 2023 23:42:47 -0400 Subject: [PATCH 240/445] tools/script_manager.lua - clean up formatting and documentation --- tools/script_manager.lua | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/tools/script_manager.lua b/tools/script_manager.lua index 1a3b2a27..0ace7796 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -1,6 +1,6 @@ --[[ This file is part of darktable, - copyright (c) 2018, 2020 Bill Ferguson + copyright (c) 2018, 2020, 2023 Bill Ferguson darktable is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -289,7 +289,6 @@ local function get_repo_branches(repo) return branches end - local function is_repo_clean(repo_data) local old_log_level = set_log_level(sm.log_level) if string.match(repo_data, "\n%s-%a.-%a:%s-%a%g-\n") then @@ -309,6 +308,10 @@ local function checkout_repo_branch(repo, branch) restore_log_level(old_log_level) end +-------------------- +-- utility functions +-------------------- + local function update_combobox_choices(combobox, choice_table, selected) local old_log_level = set_log_level(sm.log_level) local items = #combobox @@ -341,6 +344,10 @@ local function string_dequote(str) return string.gsub(str, "['\"]", "") end +------------------ +-- script handling +------------------ + local function add_script_category(category) local old_log_level = set_log_level(sm.log_level) if #sm.categories == 0 or not string.match(du.join(sm.categories, " "), ds.sanitize_lua(category)) then @@ -555,6 +562,10 @@ local function update_scripts() return result end +-------------- +-- UI handling +-------------- + local function update_script_update_choices() local old_log_level = set_log_level(sm.log_level) local installs = {} @@ -678,7 +689,7 @@ local function clear_button(number) button.label = "" button.tooltip = "" button.sensitive = false ---button.name = "" + --button.name = "" restore_log_level(old_log_level) end @@ -1235,6 +1246,7 @@ sm.widgets.main_box = dt.new_widget("box"){ } script_manager_running_script = nil + -- - - - - - - - - - - - - - - - - - - - - - - - -- D A R K T A B L E I N T E G R A T I O N -- - - - - - - - - - - - - - - - - - - - - - - - From 2fc8ed78e446ced4b352da2bc6281c6567dcce87 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Mon, 3 Jul 2023 23:44:13 -0400 Subject: [PATCH 241/445] tools/script_manager.lua - added check to ensure script_data.show() runction was passed as part of the script_data table before trying to use it. Fixes #418. --- tools/script_manager.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/script_manager.lua b/tools/script_manager.lua index 0ace7796..78909fd9 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -397,7 +397,7 @@ local function activate(script) if err ~= true then log.msg(log.debug, "got lib data") script.data = err - if script.data.destroy_method and script.data.destroy_method == "hide" then + if script.data.destroy_method and script.data.destroy_method == "hide" and script.data.show then script.data.show() end else From b4626f278768f93be4da283e70d96862f1c7c076 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Tue, 4 Jul 2023 15:57:12 -0400 Subject: [PATCH 242/445] lib/dtutils.lua - changed log message to error on fail to load. Added printing of the returned error. --- lib/dtutils.lua | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/dtutils.lua b/lib/dtutils.lua index 0a6d4416..8aae188d 100644 --- a/lib/dtutils.lua +++ b/lib/dtutils.lua @@ -180,11 +180,12 @@ dtutils.libdoc.functions["prequire"] = { } function dtutils.prequire(req_name) - local status, lib = pcall(require, req_name) + local status, lib = pcall(require, san_req_name) if status then log.msg(log.info, "Loaded " .. req_name) else - log.msg(log.info, "Error loading " .. req_name) + log.msg(log.error, "Error loading " .. req_name) + log.msg(log.error, "Error returned is " .. lib) end return status, lib end From 68ae9326bf3fd402b3bbcc5f3cf98a14f944146f Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Wed, 12 Jul 2023 12:37:14 -0400 Subject: [PATCH 243/445] tools/script_manager.lua - added translation to preference setting --- tools/script_manager.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/script_manager.lua b/tools/script_manager.lua index 78909fd9..c4546b65 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -98,8 +98,8 @@ local LUA_API_VER = "API-" .. dt.configuration.api_version_string -- - - - - - - - - - - - - - - - - - - - - - - - dt.preferences.register(MODULE, "check_update", "bool", - "check for updated scripts on start up", - "automatically update scripts to correct version", + _("check for updated scripts on start up"), + _("automatically update scripts to correct version"), true) local check_for_updates = dt.preferences.read(MODULE, "check_update", "bool") From 24b552d61983d51cec6e140ab03f728e6d866e47 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Wed, 12 Jul 2023 13:18:01 -0400 Subject: [PATCH 244/445] lib/dtutils.lua - fix typo from testing --- lib/dtutils.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/dtutils.lua b/lib/dtutils.lua index 8aae188d..5ff6c9f7 100644 --- a/lib/dtutils.lua +++ b/lib/dtutils.lua @@ -180,7 +180,7 @@ dtutils.libdoc.functions["prequire"] = { } function dtutils.prequire(req_name) - local status, lib = pcall(require, san_req_name) + local status, lib = pcall(require, req_name) if status then log.msg(log.info, "Loaded " .. req_name) else From 1792410efe1ffdf2c6300a7c80120fa065783050 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sat, 15 Jul 2023 19:52:39 -0400 Subject: [PATCH 245/445] lib/dtutils.lua - corrected test --- lib/dtutils.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/dtutils.lua b/lib/dtutils.lua index 1798163f..ad8abfa2 100644 --- a/lib/dtutils.lua +++ b/lib/dtutils.lua @@ -97,7 +97,7 @@ dtutils.libdoc.functions["check_max_api_version"] = { function dtutils.check_max_api_version(max_api, script_name) local current_api = dt.configuration.api_version_string - if max_api < current_api then + if current_api > max_api then dt.print_error("This application is written for lua api version " .. max_api .. " or earlier.") dt.print_error("The current lua api version is " .. current_api) dt.print("ERROR: " .. script_name .. " failed to load. Lua API version " .. max_api .. " or earlier required.") From e1b2715ee9c2e0f3ca266a2ca58cf86fd1a14d31 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sun, 16 Jul 2023 12:50:28 -0400 Subject: [PATCH 246/445] contrib/gpx_export - added show function to script_data to fix #418 and #419. --- contrib/gpx_export.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/contrib/gpx_export.lua b/contrib/gpx_export.lua index 152d3e60..12c45323 100644 --- a/contrib/gpx_export.lua +++ b/contrib/gpx_export.lua @@ -203,5 +203,6 @@ end script_data.destroy = destroy script_data.restart = restart script_data.destroy_method = "hide" +script_data.show = restart return script_data From 14d5a79db20a1f7582e4711799e5c6b3a1884058 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sun, 16 Jul 2023 13:04:00 -0400 Subject: [PATCH 247/445] Added script_data.show to script_data blocks --- contrib/AutoGrouper.lua | 3 ++- contrib/CollectHelper.lua | 1 + contrib/HDRMerge.lua | 1 + contrib/LabelsToTags.lua | 1 + contrib/OpenInExplorer.lua | 1 + contrib/RL_out_sharp.lua | 1 + contrib/autostyle.lua | 1 + contrib/change_group_leader.lua | 1 + contrib/clear_GPS.lua | 1 + contrib/copy_attach_detach_tags.lua | 1 + contrib/cr2hdr.lua | 1 + contrib/enfuseAdvanced.lua | 1 + contrib/exportLUT.lua | 1 + contrib/ext_editor.lua | 1 + contrib/face_recognition.lua | 1 + contrib/fujifilm_dynamic_range.lua | 1 + contrib/fujifilm_ratings.lua | 1 + contrib/geoJSON_export.lua | 1 + contrib/geoToolbox.lua | 1 + contrib/gimp.lua | 1 + contrib/gpx_export.lua | 1 + contrib/hugin.lua | 1 + contrib/image_stack.lua | 1 + contrib/image_time.lua | 1 + contrib/kml_export.lua | 1 + contrib/pdf_slideshow.lua | 1 + contrib/photils.lua | 1 + contrib/rate_group.lua | 1 + contrib/rename-tags.lua | 1 + contrib/rename_images.lua | 1 + contrib/select_untagged.lua | 1 + contrib/slideshowMusic.lua | 1 + contrib/transfer_hierarchy.lua | 1 + contrib/video_ffmpeg.lua | 1 + examples/moduleExample.lua | 1 + official/check_for_updates.lua | 1 + official/copy_paste_metadata.lua | 1 + official/delete_long_tags.lua | 1 + official/delete_unused_tags.lua | 1 + official/enfuse.lua | 1 + official/generate_image_txt.lua | 1 + official/image_path_in_ui.lua | 1 + official/save_selection.lua | 1 + official/selection_to_pdf.lua | 1 + tools/executable_manager.lua | 1 + 45 files changed, 46 insertions(+), 1 deletion(-) diff --git a/contrib/AutoGrouper.lua b/contrib/AutoGrouper.lua index 58a8c1b8..79ded8cf 100644 --- a/contrib/AutoGrouper.lua +++ b/contrib/AutoGrouper.lua @@ -50,6 +50,7 @@ local script_data = {} script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them local gettext = dt.gettext -- Tell gettext where to find the .mo file translating messages for a particular domain @@ -215,4 +216,4 @@ script_data.destroy_method = "hide" script_data.restart = restart script_data.show = restart -return script_data +return script_data diff --git a/contrib/CollectHelper.lua b/contrib/CollectHelper.lua index 94c5f77a..7f609350 100644 --- a/contrib/CollectHelper.lua +++ b/contrib/CollectHelper.lua @@ -63,6 +63,7 @@ local script_data = {} script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them local function _(msgid) return gettext.dgettext("CollectHelper", msgid) diff --git a/contrib/HDRMerge.lua b/contrib/HDRMerge.lua index bf922989..3e7e29a5 100644 --- a/contrib/HDRMerge.lua +++ b/contrib/HDRMerge.lua @@ -58,6 +58,7 @@ local script_data = {} script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them local mod = 'module_HDRMerge' diff --git a/contrib/LabelsToTags.lua b/contrib/LabelsToTags.lua index f5d87ba2..a89b05d2 100644 --- a/contrib/LabelsToTags.lua +++ b/contrib/LabelsToTags.lua @@ -59,6 +59,7 @@ local script_data = {} script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them -- Lua 5.3 no longer has "unpack" but "table.unpack" unpack = unpack or table.unpack diff --git a/contrib/OpenInExplorer.lua b/contrib/OpenInExplorer.lua index a7761989..9a8cd650 100644 --- a/contrib/OpenInExplorer.lua +++ b/contrib/OpenInExplorer.lua @@ -63,6 +63,7 @@ local script_data = {} script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them -- Tell gettext where to find the .mo file translating messages for a particular domain gettext.bindtextdomain("OpenInExplorer",dt.configuration.config_dir.."/lua/locale/") diff --git a/contrib/RL_out_sharp.lua b/contrib/RL_out_sharp.lua index 40cfb204..2c854e48 100644 --- a/contrib/RL_out_sharp.lua +++ b/contrib/RL_out_sharp.lua @@ -72,6 +72,7 @@ local script_data = {} script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them -- OS compatibility local PS = dt.configuration.running_os == "windows" and "\\" or "/" diff --git a/contrib/autostyle.lua b/contrib/autostyle.lua index 64de2a80..53fc0ab5 100644 --- a/contrib/autostyle.lua +++ b/contrib/autostyle.lua @@ -49,6 +49,7 @@ local script_data = {} script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them -- run command and retrieve stdout local function get_stdout(cmd) diff --git a/contrib/change_group_leader.lua b/contrib/change_group_leader.lua index 07ce8119..c7fe5c0f 100644 --- a/contrib/change_group_leader.lua +++ b/contrib/change_group_leader.lua @@ -49,6 +49,7 @@ local script_data = {} script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them -- Tell gettext where to find the .mo file translating messages for a particular domain gettext.bindtextdomain(MODULE, dt.configuration.config_dir.."/lua/locale/") diff --git a/contrib/clear_GPS.lua b/contrib/clear_GPS.lua index 518e0372..da4668c1 100644 --- a/contrib/clear_GPS.lua +++ b/contrib/clear_GPS.lua @@ -46,6 +46,7 @@ local script_data = {} script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them local gettext = dt.gettext diff --git a/contrib/copy_attach_detach_tags.lua b/contrib/copy_attach_detach_tags.lua index dda92aed..05f6f1f4 100644 --- a/contrib/copy_attach_detach_tags.lua +++ b/contrib/copy_attach_detach_tags.lua @@ -51,6 +51,7 @@ local script_data = {} script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them -- Tell gettext where to find the .mo file translating messages for a particular domain gettext.bindtextdomain("copy_attach_detach_tags",dt.configuration.config_dir.."/lua/locale/") diff --git a/contrib/cr2hdr.lua b/contrib/cr2hdr.lua index 25d07a2f..f4a40c9d 100644 --- a/contrib/cr2hdr.lua +++ b/contrib/cr2hdr.lua @@ -44,6 +44,7 @@ local script_data = {} script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them local queue = {} local processed_files = {} diff --git a/contrib/enfuseAdvanced.lua b/contrib/enfuseAdvanced.lua index 3103821c..76ffd01e 100644 --- a/contrib/enfuseAdvanced.lua +++ b/contrib/enfuseAdvanced.lua @@ -74,6 +74,7 @@ local script_data = {} script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them -- Tell gettext where to find the .mo file translating messages for a particular domain local gettext = dt.gettext diff --git a/contrib/exportLUT.lua b/contrib/exportLUT.lua index 3d023901..fe11960e 100644 --- a/contrib/exportLUT.lua +++ b/contrib/exportLUT.lua @@ -40,6 +40,7 @@ local script_data = {} script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them local gettext = dt.gettext diff --git a/contrib/ext_editor.lua b/contrib/ext_editor.lua index 10d1ca6c..827d5270 100644 --- a/contrib/ext_editor.lua +++ b/contrib/ext_editor.lua @@ -82,6 +82,7 @@ local script_data = {} script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them -- OS compatibility local PS = dt.configuration.running_os == "windows" and "\\" or "/" diff --git a/contrib/face_recognition.lua b/contrib/face_recognition.lua index 68a497cc..5bd7048e 100644 --- a/contrib/face_recognition.lua +++ b/contrib/face_recognition.lua @@ -61,6 +61,7 @@ local script_data = {} script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them -- namespace diff --git a/contrib/fujifilm_dynamic_range.lua b/contrib/fujifilm_dynamic_range.lua index 68694ea3..a6d80875 100644 --- a/contrib/fujifilm_dynamic_range.lua +++ b/contrib/fujifilm_dynamic_range.lua @@ -70,6 +70,7 @@ local script_data = {} script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them local function detect_dynamic_range(event, image) if image.exif_maker ~= "FUJIFILM" then diff --git a/contrib/fujifilm_ratings.lua b/contrib/fujifilm_ratings.lua index 18dba2bc..c6b8738c 100644 --- a/contrib/fujifilm_ratings.lua +++ b/contrib/fujifilm_ratings.lua @@ -37,6 +37,7 @@ local script_data = {} script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them gettext.bindtextdomain("fujifilm_ratings", dt.configuration.config_dir.."/lua/locale/") diff --git a/contrib/geoJSON_export.lua b/contrib/geoJSON_export.lua index cc3d9560..cd748fee 100644 --- a/contrib/geoJSON_export.lua +++ b/contrib/geoJSON_export.lua @@ -46,6 +46,7 @@ local script_data = {} script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them -- Tell gettext where to find the .mo file translating messages for a particular domain gettext.bindtextdomain("geoJSON_export",dt.configuration.config_dir.."/lua/locale/") diff --git a/contrib/geoToolbox.lua b/contrib/geoToolbox.lua index db99d26f..30f90406 100644 --- a/contrib/geoToolbox.lua +++ b/contrib/geoToolbox.lua @@ -39,6 +39,7 @@ local script_data = {} script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them -- Tell gettext where to find the .mo file translating messages for a particular domain gettext.bindtextdomain("geoToolbox",dt.configuration.config_dir.."/lua/locale/") diff --git a/contrib/gimp.lua b/contrib/gimp.lua index d2809222..0b235f92 100644 --- a/contrib/gimp.lua +++ b/contrib/gimp.lua @@ -81,6 +81,7 @@ local script_data = {} script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them -- Tell gettext where to find the .mo file translating messages for a particular domain gettext.bindtextdomain("gimp",dt.configuration.config_dir.."/lua/locale/") diff --git a/contrib/gpx_export.lua b/contrib/gpx_export.lua index 12c45323..c25028e2 100644 --- a/contrib/gpx_export.lua +++ b/contrib/gpx_export.lua @@ -36,6 +36,7 @@ local script_data = {} script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them -- Tell gettext where to find the .mo file translating messages for a particular domain gettext.bindtextdomain("gpx_export",dt.configuration.config_dir.."/lua/locale/") diff --git a/contrib/hugin.lua b/contrib/hugin.lua index ed040f1e..77ad7cb8 100644 --- a/contrib/hugin.lua +++ b/contrib/hugin.lua @@ -63,6 +63,7 @@ local script_data = {} script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them -- Tell gettext where to find the .mo file translating messages for a particular domain gettext.bindtextdomain("hugin",dt.configuration.config_dir.."/lua/locale/") diff --git a/contrib/image_stack.lua b/contrib/image_stack.lua index 8560c131..b78b96c5 100644 --- a/contrib/image_stack.lua +++ b/contrib/image_stack.lua @@ -80,6 +80,7 @@ local script_data = {} script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them -- Tell gettext where to find the .mo file translating messages for a particular domain gettext.bindtextdomain("image_stack",dt.configuration.config_dir.."/lua/locale/") diff --git a/contrib/image_time.lua b/contrib/image_time.lua index 78b6f42e..17d54819 100644 --- a/contrib/image_time.lua +++ b/contrib/image_time.lua @@ -122,6 +122,7 @@ local script_data = {} script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them -- Tell gettext where to find the .mo file translating messages for a particular domain diff --git a/contrib/kml_export.lua b/contrib/kml_export.lua index 8451d72c..f772fb76 100644 --- a/contrib/kml_export.lua +++ b/contrib/kml_export.lua @@ -52,6 +52,7 @@ local script_data = {} script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them -- Tell gettext where to find the .mo file translating messages for a particular domain gettext.bindtextdomain("kml_export",dt.configuration.config_dir.."/lua/locale/") diff --git a/contrib/pdf_slideshow.lua b/contrib/pdf_slideshow.lua index f1824856..11948845 100644 --- a/contrib/pdf_slideshow.lua +++ b/contrib/pdf_slideshow.lua @@ -65,6 +65,7 @@ local script_data = {} script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them dt.preferences.register ("pdf_slideshow","open with","string", diff --git a/contrib/photils.lua b/contrib/photils.lua index 3be939e2..b5e99bd8 100644 --- a/contrib/photils.lua +++ b/contrib/photils.lua @@ -51,6 +51,7 @@ local script_data = {} script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them local PS = dt.configuration.running_os == "windows" and "\\" or "/" diff --git a/contrib/rate_group.lua b/contrib/rate_group.lua index 4f2fa608..9a790f81 100644 --- a/contrib/rate_group.lua +++ b/contrib/rate_group.lua @@ -51,6 +51,7 @@ local script_data = {} script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them local function apply_rating(rating) local images = dt.gui.action_images diff --git a/contrib/rename-tags.lua b/contrib/rename-tags.lua index 74d9bfed..2213b923 100644 --- a/contrib/rename-tags.lua +++ b/contrib/rename-tags.lua @@ -43,6 +43,7 @@ local script_data = {} script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them local rt = {} rt.module_installed = false diff --git a/contrib/rename_images.lua b/contrib/rename_images.lua index 584ba31a..e8e013db 100644 --- a/contrib/rename_images.lua +++ b/contrib/rename_images.lua @@ -75,6 +75,7 @@ local script_data = {} script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them -- - - - - - - - - - - - - - - - - - - - - - - - diff --git a/contrib/select_untagged.lua b/contrib/select_untagged.lua index 8740ee2f..d15941b2 100644 --- a/contrib/select_untagged.lua +++ b/contrib/select_untagged.lua @@ -31,6 +31,7 @@ local script_data = {} script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them -- Tell gettext where to find the .mo file translating messages for a particular domain gettext.bindtextdomain("select_untagged",dt.configuration.config_dir.."/lua/locale/") diff --git a/contrib/slideshowMusic.lua b/contrib/slideshowMusic.lua index 67c17363..cf62aa69 100644 --- a/contrib/slideshowMusic.lua +++ b/contrib/slideshowMusic.lua @@ -38,6 +38,7 @@ local script_data = {} script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them -- Tell gettext where to find the .mo file translating messages for a particular domain gettext.bindtextdomain("slideshowMusic",dt.configuration.config_dir.."/lua/locale/") diff --git a/contrib/transfer_hierarchy.lua b/contrib/transfer_hierarchy.lua index 840deeca..10c5f0dc 100755 --- a/contrib/transfer_hierarchy.lua +++ b/contrib/transfer_hierarchy.lua @@ -87,6 +87,7 @@ local script_data = {} script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them local MKDIR_COMMAND = darktable.configuration.running_os == "windows" and "mkdir " or "mkdir -p " local PATH_SEPARATOR = darktable.configuration.running_os == "windows" and "\\\\" or "/" diff --git a/contrib/video_ffmpeg.lua b/contrib/video_ffmpeg.lua index d670a517..165b5771 100644 --- a/contrib/video_ffmpeg.lua +++ b/contrib/video_ffmpeg.lua @@ -48,6 +48,7 @@ local script_data = {} script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them local MODULE_NAME = "video_ffmpeg" diff --git a/examples/moduleExample.lua b/examples/moduleExample.lua index b68161e8..bf5a3253 100644 --- a/examples/moduleExample.lua +++ b/examples/moduleExample.lua @@ -42,6 +42,7 @@ local script_data = {} script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them -- translation diff --git a/official/check_for_updates.lua b/official/check_for_updates.lua index 5f1b4848..b8894df8 100644 --- a/official/check_for_updates.lua +++ b/official/check_for_updates.lua @@ -41,6 +41,7 @@ local script_data = {} script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them -- compare two version strings of the form "major.minor.patch" -- returns -1, 0, 1 if the first version is smaller, equal, greater than the second version, diff --git a/official/copy_paste_metadata.lua b/official/copy_paste_metadata.lua index ec4e7c85..ffd69c87 100644 --- a/official/copy_paste_metadata.lua +++ b/official/copy_paste_metadata.lua @@ -38,6 +38,7 @@ local script_data = {} script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them -- set this to "false" if you don't want to overwrite metadata fields -- (title, description, creator, publisher and rights) that are already set diff --git a/official/delete_long_tags.lua b/official/delete_long_tags.lua index a5f54553..31ae7994 100644 --- a/official/delete_long_tags.lua +++ b/official/delete_long_tags.lua @@ -40,6 +40,7 @@ local script_data = {} script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them dt.preferences.register("delete_long_tags", "length", "integer", "maximum length of tags to keep", diff --git a/official/delete_unused_tags.lua b/official/delete_unused_tags.lua index fcaf03d6..0dfab017 100644 --- a/official/delete_unused_tags.lua +++ b/official/delete_unused_tags.lua @@ -44,6 +44,7 @@ local script_data = {} script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them -- deleting while iterating the tags list seems to break the iterator! local unused_tags = {} diff --git a/official/enfuse.lua b/official/enfuse.lua index 212f0e3f..35327cfd 100644 --- a/official/enfuse.lua +++ b/official/enfuse.lua @@ -50,6 +50,7 @@ local script_data = {} script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them -- Tell gettext where to find the .mo file translating messages for a particular domain gettext.bindtextdomain("enfuse",dt.configuration.config_dir..PS .. "lua" .. PS .. "locale" .. PS) diff --git a/official/generate_image_txt.lua b/official/generate_image_txt.lua index 11eceb0b..73b50635 100644 --- a/official/generate_image_txt.lua +++ b/official/generate_image_txt.lua @@ -47,6 +47,7 @@ local script_data = {} script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them dt.preferences.register("generate_image_txt", "enabled", diff --git a/official/image_path_in_ui.lua b/official/image_path_in_ui.lua index e256cf41..e81a6cb8 100644 --- a/official/image_path_in_ui.lua +++ b/official/image_path_in_ui.lua @@ -40,6 +40,7 @@ local script_data = {} script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them local ipiu = {} ipiu.module_installed = false diff --git a/official/save_selection.lua b/official/save_selection.lua index d05a760a..b06f933a 100644 --- a/official/save_selection.lua +++ b/official/save_selection.lua @@ -45,6 +45,7 @@ local script_data = {} script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them local buffer_count = 5 diff --git a/official/selection_to_pdf.lua b/official/selection_to_pdf.lua index b2b688e5..638ae24f 100644 --- a/official/selection_to_pdf.lua +++ b/official/selection_to_pdf.lua @@ -45,6 +45,7 @@ local script_data = {} script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them dt.preferences.register ("selection_to_pdf","Open with","string", diff --git a/tools/executable_manager.lua b/tools/executable_manager.lua index 68752880..87e752aa 100644 --- a/tools/executable_manager.lua +++ b/tools/executable_manager.lua @@ -41,6 +41,7 @@ local script_data = {} script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them local PS = dt.configuration.running_os == "windows" and "\\" or "/" From e8af665b3cb3ba932e270767d2ec3c8b75e99674 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sun, 16 Jul 2023 13:22:06 -0400 Subject: [PATCH 248/445] README.md - updated (fixed typos) echo commands to build luarc file --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c89804d8..a8aca06b 100644 --- a/README.md +++ b/README.md @@ -174,7 +174,7 @@ The recommended way to enable and disable specific scripts is using the script m ### Windows - echo "require 'tools/script_manager'" > %LOCALAPPDATA%\darktable\luarc + echo require "tools/script_manager" > %LOCALAPPDATA%\darktable\luarc ### Snap @@ -182,7 +182,7 @@ The recommended way to enable and disable specific scripts is using the script m ### Flatpak - echo require "tools/script_manager"' > ~/.var/app/org.darktable.Darktable/config/darktable/luarc + echo 'require "tools/script_manager"' > ~/.var/app/org.darktable.Darktable/config/darktable/luarc You can also create or add lines to the luarc file from the command line: From a177da2040bcd3d2776728b59a51bbd05b542732 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Mon, 17 Jul 2023 17:39:24 -0400 Subject: [PATCH 249/445] official/check_for_updates = updated instructions for additional modules required --- official/check_for_updates.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/official/check_for_updates.lua b/official/check_for_updates.lua index b8894df8..db184350 100644 --- a/official/check_for_updates.lua +++ b/official/check_for_updates.lua @@ -21,7 +21,7 @@ a simple script that will automatically look for newer releases on github and in when there is something. it will only check on startup and only once a week. USAGE -* install luasec and cjson for Lua 5.2 on your system +* install luasec and cjson for Lua 5.4 on your system * require this script from your main lua file * restart darktable From 191aecacdffb1c0fd3fb416b8977e52f26213252 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Fri, 18 Aug 2023 12:23:24 -0400 Subject: [PATCH 250/445] tools - Moved script_manager to bottom of lower left panel and moved executable_manager to middle of lower left panel to work around windows GTK window placement error. --- tools/executable_manager.lua | 2 +- tools/script_manager.lua | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/executable_manager.lua b/tools/executable_manager.lua index 87e752aa..a8690ea8 100644 --- a/tools/executable_manager.lua +++ b/tools/executable_manager.lua @@ -106,7 +106,7 @@ local function install_module() "executable manager", -- Visible name true, -- expandable false, -- resetable - {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_LEFT_BOTTOM", 100}}, -- containers + {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_LEFT_BOTTOM", 600}}, -- containers dt.new_widget("box") -- widget { orientation = "vertical", diff --git a/tools/script_manager.lua b/tools/script_manager.lua index c4546b65..f826f165 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -933,7 +933,7 @@ local function install_module() "script manager", -- Visible name true, -- expandable false, -- resetable - {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_LEFT_BOTTOM", 600}}, -- containers + {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_LEFT_BOTTOM", 100}}, -- containers sm.widgets.main_box, nil,-- view_enter nil -- view_leave From bf17dccd6902c44c6c5154323bdce48391d754f4 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Wed, 20 Sep 2023 13:48:18 -0400 Subject: [PATCH 251/445] tools/script_manager.lua - Explicitly set non running scriopts to FALSE instead of relying on no value being intrepreted as false. --- tools/script_manager.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/script_manager.lua b/tools/script_manager.lua index f826f165..be697fe7 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -467,6 +467,8 @@ local function add_script_name(name, path, category) table.insert(sm.scripts[category], script) if pref_read(script.script_name, "bool") then activate(script) + else + pref_write(script.script_name, "bool", false) end restore_log_level(old_log_level) end From 34b9831472b78aceb519dcabff0b543b714a247f Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Mon, 16 Oct 2023 22:41:12 -0400 Subject: [PATCH 252/445] tools/script_manager.lua - wrapped the scipt_dir in quotes to handle the space in username problem on windows. --- tools/script_manager.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/script_manager.lua b/tools/script_manager.lua index be697fe7..0517cb02 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -513,7 +513,7 @@ local function scan_scripts(script_dir) local script_count = 0 local find_cmd = "find -L " .. script_dir .. " -name \\*.lua -print | sort" if dt.configuration.running_os == "windows" then - find_cmd = "dir /b/s " .. script_dir .. "\\*.lua | sort" + find_cmd = "dir /b/s \s" .. script_dir .. "\\*.lua\" | sort" end log.msg(log.debug, _("find command is ") .. find_cmd) -- scan the scripts From 13f02c95ea9fc9746550a62e10f17db6353fa7df Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Tue, 17 Oct 2023 16:02:27 -0400 Subject: [PATCH 253/445] tools/script_manager - fixed quote with a " instead of s --- tools/script_manager.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/script_manager.lua b/tools/script_manager.lua index 0517cb02..e65cd204 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -513,7 +513,7 @@ local function scan_scripts(script_dir) local script_count = 0 local find_cmd = "find -L " .. script_dir .. " -name \\*.lua -print | sort" if dt.configuration.running_os == "windows" then - find_cmd = "dir /b/s \s" .. script_dir .. "\\*.lua\" | sort" + find_cmd = "dir /b/s \"" .. script_dir .. "\\*.lua\" | sort" end log.msg(log.debug, _("find command is ") .. find_cmd) -- scan the scripts From dc50d40886e7351e99ddead7f15714e4b08cacf4 Mon Sep 17 00:00:00 2001 From: ddittmar Date: Sat, 28 Oct 2023 11:14:51 +0200 Subject: [PATCH 254/445] select non-existing images --- README.md | 1 + contrib/select_non_existing.lua | 77 +++++++++++++++++++ .../de_DE/LC_MESSAGES/select_non_existing.po | 12 +++ 3 files changed, 90 insertions(+) create mode 100644 contrib/select_non_existing.lua create mode 100644 locale/de_DE/LC_MESSAGES/select_non_existing.po diff --git a/README.md b/README.md index a8aca06b..f371e8d5 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,7 @@ change_group_leader|Yes|LMW|Change which image leads group [rename_images](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/rename_images)|Yes|LMW|Rename single or multiple images [rename-tags](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/rename-tags)|Yes|LMW|Change a tag name [RL_out_sharp](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/rl_out_sharp)|No|LW|Output sharpening using GMic (Richardson-Lucy algorithm) +[select_non_existing](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/select_non_existing)|Yes|LMW|Enable selection of non-existing images in the the currently worked on images [select_untagged](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/select_untagged)|Yes|LMW|Enable selection of untagged images [slideshowMusic](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/slideshowMusic)|No|L|Play music during a slideshow [transfer_hierarchy](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/transfer_hierarchy)|Yes|LMW|Image move/copy preserving directory hierarchy diff --git a/contrib/select_non_existing.lua b/contrib/select_non_existing.lua new file mode 100644 index 00000000..9baef664 --- /dev/null +++ b/contrib/select_non_existing.lua @@ -0,0 +1,77 @@ +--[[ + This file is part of darktable, + copyright (c) 2023 Dirk Dittmar + + darktable is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + darktable is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with darktable. If not, see . +]] +--[[ +Enable selection of non-existing images in the the currently worked on images, e.g. the ones selected by the collection module. +]] + +local dt = require "darktable" +local du = require "lib/dtutils" +local df = require "lib/dtutils.file" + +-- module name +local MODULE = "select_non_existing" + +du.check_min_api_version("9.1.0", MODULE) + +-- figure out the path separator +local PS = dt.configuration.running_os == "windows" and "\\" or "/" + +local gettext = dt.gettext +gettext.bindtextdomain(MODULE, dt.configuration.config_dir..PS.."lua"..PS.."locale"..PS) + +local function _(msgid) + return gettext.dgettext(MODULE, msgid) +end + +local function stop_job(job) + job.valid = false +end + +local function select_nonexisting_images(event, images) + local selection = {} + + local job = dt.gui.create_job(_("select non existing images"), true, stop_job) + for key,image in ipairs(images) do + if(job.valid) then + job.percent = (key - 1)/#images + local filepath = image.path..PS..image.filename + local file_exists = df.test_file(filepath, "e") + dt.print_log(filepath.." exists? => "..tostring(file_exists)) + if (not file_exists) then + table.insert(selection, image) + end + else + break + end + end + stop_job(job) + + return selection +end + +local function destroy() + dt.gui.libs.select.destroy_selection(MODULE) +end + +dt.gui.libs.select.register_selection( + MODULE, + _("select non existing"), + select_nonexisting_images, + _("select all non-existing images in the current images")) + +local script_data = {} +script_data.destroy = destroy +return script_data \ No newline at end of file diff --git a/locale/de_DE/LC_MESSAGES/select_non_existing.po b/locale/de_DE/LC_MESSAGES/select_non_existing.po new file mode 100644 index 00000000..c36ff806 --- /dev/null +++ b/locale/de_DE/LC_MESSAGES/select_non_existing.po @@ -0,0 +1,12 @@ +msgid "" +msgstr "" +"Content-Type: text/plain; charset=UTF-8\n" + +msgid "select non existing images" +msgstr "nicht vorhandene Bilder auswählen" + +msgid "select non existing" +msgstr "nicht vorhandene auswählen" + +msgid "select all non-existing images in the current images" +msgstr "alle nicht vorhandenen Bilder in den aktuellen Bildern auswählen" From 5f29211f79e924b1528c3ef83a3cac32c071e9a7 Mon Sep 17 00:00:00 2001 From: Martin Straeten <39386816+MStraeten@users.noreply.github.com> Date: Thu, 11 Jan 2024 20:42:32 +0100 Subject: [PATCH 255/445] Update x-touch.lua with support for primaries slider maps knobs to the primaries sliders requires darktable 4.6.x --- examples/x-touch.lua | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/examples/x-touch.lua b/examples/x-touch.lua index 7c5b9988..d0f7cd88 100644 --- a/examples/x-touch.lua +++ b/examples/x-touch.lua @@ -96,7 +96,20 @@ for k = 1,8 do "purple", "magenta" } element = e[k] - + + + -- if the sigmoid rgb primaries is focused, + -- check sliders + elseif dt.gui.action("iop/sigmoid", "focus") ~= 0 and k <8 then + local e = { "red attenuation", "red rotation", "green attenuation", "green rotation", "blue attenuation", "blue rotation", "recover purity" } + which = "iop/sigmoid/primaries/"..e[k] + + -- if the rgb primaries is focused, + -- check sliders + elseif dt.gui.action("iop/primaries", "focus") ~= 0 and k >=1 then + local e = { "red hue", "red purity", "green hue", "green purity", "blue hue", "blue purity", "tint hue", "tint purity" } + which = "iop/primaries/" ..e[k] + -- if the tone equalizer is focused, -- select one of the sliders in the "simple" tab elseif dt.gui.action("iop/toneequal", "focus") ~= 0 then From 23835edc1f92d456471aa4099ee38274b0736c65 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sun, 14 Jan 2024 17:10:43 -0500 Subject: [PATCH 256/445] contrib/jpg_group_leader.lua - New script to make jpg images the group leader for raw + jpg image combinations. --- contrib/jpg_group_leader.lua | 196 +++++++++++++++++++++++++++++++++++ 1 file changed, 196 insertions(+) create mode 100644 contrib/jpg_group_leader.lua diff --git a/contrib/jpg_group_leader.lua b/contrib/jpg_group_leader.lua new file mode 100644 index 00000000..ab97588d --- /dev/null +++ b/contrib/jpg_group_leader.lua @@ -0,0 +1,196 @@ +--[[ + + jpg_group_leader.lua - Make jpg image group leader + + Copyright (C) 2024 Bill Ferguson . + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +]] +--[[ + jpg_group_leader - Make jpg image group leader + + After a film roll is imported, check for RAW-JPG image groups + and make the JPG image the group leader. This is on by default + but can be disabled in preferences. + + Shortcuts are included to filter existing collections or + selections of images and make the jpg the group leader. + + ADDITIONAL SOFTWARE NEEDED FOR THIS SCRIPT + None + + USAGE + Start script from script_manager + Assign keys to the shortcuts + + BUGS, COMMENTS, SUGGESTIONS + Bill Ferguson + + CHANGES +]] + +local dt = require "darktable" +local du = require "lib/dtutils" +local df = require "lib/dtutils.file" + + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- C O N S T A N T S +-- - - - - - - - - - - - - - - - - - - - - - - - + +local MODULE = "jpg_group_leader" + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- A P I C H E C K +-- - - - - - - - - - - - - - - - - - - - - - - - + +du.check_min_api_version("7.0.0", MODULE) + + +-- - - - - - - - - - - - - - - - - - - - - - - - - - +-- S C R I P T M A N A G E R I N T E G R A T I O N +-- - - - - - - - - - - - - - - - - - - - - - - - - - + +local script_data = {} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them + +-- - - - - - - - - - - - - - - - - - - - - - - - - - +-- I 1 8 N +-- - - - - - - - - - - - - - - - - - - - - - - - - - + +local gettext = dt.gettext + +-- Tell gettext where to find the .mo file translating messages for a particular domain +gettext.bindtextdomain(MODULE, dt.configuration.config_dir .. "/lua/locale/") + +local function _(msgid) + return gettext.dgettext(MODULE, msgid) +end + + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- P R E F E R E N C E S +-- - - - - - - - - - - - - - - - - - - - - - - - + +dt.preferences.register(MODULE, "on_import", "bool", _("make jpg group leader on import"), _("automatically make the jpg file the group leader when raw + jpg are imported"), true) + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- N A M E S P A C E +-- - - - - - - - - - - - - - - - - - - - - - - - + +local jgloi = {} +jgloi.images = {} + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- F U N C T I O N S +-- - - - - - - - - - - - - - - - - - - - - - - - + +local function toggle_global_toolbox_grouping() + dt.gui.libs.global_toolbox.grouping = false + dt.gui.libs.global_toolbox.grouping = true +end + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- M A I N P R O G R A M +-- - - - - - - - - - - - - - - - - - - - - - - - + +local function make_jpg_group_leader(images) + -- if the image is part of a group, make it the leader + for _, image in ipairs(images) do + if #image:get_group_members() > 1 then + image:make_group_leader() + end + end + if dt.gui.libs.global_toolbox.grouping then + -- toggle the grouping to make the new leader show + toggle_global_toolbox_grouping() + end +end + +local function make_existing_jpg_group_leader(images) + for _, image in ipairs(images) do + if string.lower(df.get_filetype(image.filename)) == "jpg" then + if #image:get_group_members() > 1 then + image:make_group_leader() + end + end + end + if dt.gui.libs.global_toolbox.grouping then + -- toggle the grouping to make the new leader show + toggle_global_toolbox_grouping() + end +end + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- D A R K T A B L E I N T E G R A T I O N +-- - - - - - - - - - - - - - - - - - - - - - - - + +local function destroy() + if dt.preferences.read(MODULE, "on_import", "bool") then + dt.destroy_event(MODULE, "post-import-film") + dt.destroy_event(MODULE, "post-import-image") + end + dt.destroy_event(MODULE .. "_collect", "shortcut") + dt.destroy_event(MODULE .. "_select", "shortcut") +end + +script_data.destroy = destroy + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- E V E N T S +-- - - - - - - - - - - - - - - - - - - - - - - - + +if dt.preferences.read(MODULE, "on_import", "bool") then + dt.register_event(MODULE, "post-import-film", + function(event, film_roll) + -- ignore the film roll, it contains all the images, not just the imported + local images = jgloi.images + if #images > 0 then + jgloi.images = {} + make_jpg_group_leader(images) + end + end + ) + + dt.register_event(MODULE, "post-import-image", + function(event, image) + if string.lower(df.get_filetype(image.filename)) == "jpg" then + table.insert(jgloi.images, image) + end + end + ) +end + +dt.register_event(MODULE .. "_collect", "shortcut", + function(event, shortcut) + -- ignore the film roll, it contains all the images, not just the imported + local images = dt.collection + make_existing_jpg_group_leader(images) + end, + _("Make jpg group leader for collection") +) + +dt.register_event(MODULE .. "_select", "shortcut", + function(event, shortcut) + local images = dt.gui.selection() + make_existing_jpg_group_leader(images) + end, + _("Make jpg group leader for selection") +) + +return script_data \ No newline at end of file From 294b6939057b215e7128419d71f211544ac2304a Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sun, 14 Jan 2024 17:15:28 -0500 Subject: [PATCH 257/445] contrib/hif_group_leader.lua - make the hif image the group leader for raw + hif image pairs. Works on import, selection, and collection. --- contrib/hif_group_leader.lua | 196 +++++++++++++++++++++++++++++++++++ 1 file changed, 196 insertions(+) create mode 100644 contrib/hif_group_leader.lua diff --git a/contrib/hif_group_leader.lua b/contrib/hif_group_leader.lua new file mode 100644 index 00000000..5fa0aa5f --- /dev/null +++ b/contrib/hif_group_leader.lua @@ -0,0 +1,196 @@ +--[[ + + hif_group_leader.lua - Make hif image group leader + + Copyright (C) 2024 Bill Ferguson . + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +]] +--[[ + hif_group_leader - Make hif image group leader + + After a film roll is imported, check for RAW-JPG image groups + and make the JPG image the group leader. This is on by default + but can be disabled in preferences. + + Shortcuts are included to filter existing collections or + selections of images and make the hif the group leader. + + ADDITIONAL SOFTWARE NEEDED FOR THIS SCRIPT + None + + USAGE + Start script from script_manager + Assign keys to the shortcuts + + BUGS, COMMENTS, SUGGESTIONS + Bill Ferguson + + CHANGES +]] + +local dt = require "darktable" +local du = require "lib/dtutils" +local df = require "lib/dtutils.file" + + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- C O N S T A N T S +-- - - - - - - - - - - - - - - - - - - - - - - - + +local MODULE = "hif_group_leader" + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- A P I C H E C K +-- - - - - - - - - - - - - - - - - - - - - - - - + +du.check_min_api_version("7.0.0", MODULE) + + +-- - - - - - - - - - - - - - - - - - - - - - - - - - +-- S C R I P T M A N A G E R I N T E G R A T I O N +-- - - - - - - - - - - - - - - - - - - - - - - - - - + +local script_data = {} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them + +-- - - - - - - - - - - - - - - - - - - - - - - - - - +-- I 1 8 N +-- - - - - - - - - - - - - - - - - - - - - - - - - - + +local gettext = dt.gettext + +-- Tell gettext where to find the .mo file translating messages for a particular domain +gettext.bindtextdomain(MODULE, dt.configuration.config_dir .. "/lua/locale/") + +local function _(msgid) + return gettext.dgettext(MODULE, msgid) +end + + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- P R E F E R E N C E S +-- - - - - - - - - - - - - - - - - - - - - - - - + +dt.preferences.register(MODULE, "on_import", "bool", _("make hif group leader on import"), _("automatically make the hif file the group leader when raw + hif are imported"), true) + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- N A M E S P A C E +-- - - - - - - - - - - - - - - - - - - - - - - - + +local jgloi = {} +jgloi.images = {} + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- F U N C T I O N S +-- - - - - - - - - - - - - - - - - - - - - - - - + +local function toggle_global_toolbox_grouping() + dt.gui.libs.global_toolbox.grouping = false + dt.gui.libs.global_toolbox.grouping = true +end + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- M A I N P R O G R A M +-- - - - - - - - - - - - - - - - - - - - - - - - + +local function make_hif_group_leader(images) + -- if the image is part of a group, make it the leader + for _, image in ipairs(images) do + if #image:get_group_members() > 1 then + image:make_group_leader() + end + end + if dt.gui.libs.global_toolbox.grouping then + -- toggle the grouping to make the new leader show + toggle_global_toolbox_grouping() + end +end + +local function make_existing_hif_group_leader(images) + for _, image in ipairs(images) do + if string.lower(df.get_filetype(image.filename)) == "hif" then + if #image:get_group_members() > 1 then + image:make_group_leader() + end + end + end + if dt.gui.libs.global_toolbox.grouping then + -- toggle the grouping to make the new leader show + toggle_global_toolbox_grouping() + end +end + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- D A R K T A B L E I N T E G R A T I O N +-- - - - - - - - - - - - - - - - - - - - - - - - + +local function destroy() + if dt.preferences.read(MODULE, "on_import", "bool") then + dt.destroy_event(MODULE, "post-import-film") + dt.destroy_event(MODULE, "post-import-image") + end + dt.destroy_event(MODULE .. "_collect", "shortcut") + dt.destroy_event(MODULE .. "_select", "shortcut") +end + +script_data.destroy = destroy + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- E V E N T S +-- - - - - - - - - - - - - - - - - - - - - - - - + +if dt.preferences.read(MODULE, "on_import", "bool") then + dt.register_event(MODULE, "post-import-film", + function(event, film_roll) + -- ignore the film roll, it contains all the images, not just the imported + local images = jgloi.images + if #images > 0 then + jgloi.images = {} + make_hif_group_leader(images) + end + end + ) + + dt.register_event(MODULE, "post-import-image", + function(event, image) + if string.lower(df.get_filetype(image.filename)) == "hif" then + table.insert(jgloi.images, image) + end + end + ) +end + +dt.register_event(MODULE .. "_collect", "shortcut", + function(event, shortcut) + -- ignore the film roll, it contains all the images, not just the imported + local images = dt.collection + make_existing_hif_group_leader(images) + end, + _("Make hif group leader for collection") +) + +dt.register_event(MODULE .. "_select", "shortcut", + function(event, shortcut) + local images = dt.gui.selection() + make_existing_hif_group_leader(images) + end, + _("Make hif group leader for selection") +) + +return script_data \ No newline at end of file From a5961eb066b4f45e672f1eb8aea9f94e26cf8b4f Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sun, 14 Jan 2024 21:19:09 -0500 Subject: [PATCH 258/445] contrib/change_group_leader.lua - adds a shortcut to cycle through the images in a group making the next on the new group leader. When the end of the group is reached the first image in the group is selected. --- contrib/change_group_leader.lua | 261 +++++++++++++------------------- 1 file changed, 109 insertions(+), 152 deletions(-) diff --git a/contrib/change_group_leader.lua b/contrib/change_group_leader.lua index c7fe5c0f..b06b445d 100644 --- a/contrib/change_group_leader.lua +++ b/contrib/change_group_leader.lua @@ -1,201 +1,158 @@ --[[ - change group leader - copyright (c) 2020, 2022 Bill Ferguson - copyright (c) 2021 Angel Angelov + change_group_leader.lua - change image grouip leader - darktable is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. + Copyright (C) 2024 Bill Ferguson - darktable is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. - You should have received a copy of the GNU General Public License - along with darktable. If not, see . -]] + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with this program. If not, see . +]] --[[ -CHANGE GROUP LEADER -automatically change the leader of raw+jpg paired image groups - -INSTALLATION -* copy this file in $CONFIGDIR/lua/ where CONFIGDIR is your darktable configuration directory -* add the following line in the file $CONFIGDIR/luarc - require "change_group_leader" - -USAGE -* in lighttable mode, select the image groups you wish to process, - select whether you want to set the leader to "jpg" or "raw", - and click "Execute" + change_group_leader - change image grouip leader + + change_group_leader changes the group leader to the next + image in the group. If the end of the group is reached + then the next image is wrapped around to the first image. + + ADDITIONAL SOFTWARE NEEDED FOR THIS SCRIPT + None + + USAGE + * enable with script_manager + * assign a key to the shortcut + + BUGS, COMMENTS, SUGGESTIONS + Bill Ferguson + + CHANGES ]] local dt = require "darktable" local du = require "lib/dtutils" +local df = require "lib/dtutils.file" -local gettext = dt.gettext +-- - - - - - - - - - - - - - - - - - - - - - - - +-- C O N S T A N T S +-- - - - - - - - - - - - - - - - - - - - - - - - local MODULE = "change_group_leader" -du.check_min_api_version("3.0.0", MODULE) +-- - - - - - - - - - - - - - - - - - - - - - - - +-- A P I C H E C K +-- - - - - - - - - - - - - - - - - - - - - - - - + +du.check_min_api_version("7.0.0", MODULE) --- return data structure for script_manager + +-- - - - - - - - - - - - - - - - - - - - - - - - - - +-- S C R I P T M A N A G E R I N T E G R A T I O N +-- - - - - - - - - - - - - - - - - - - - - - - - - - local script_data = {} script_data.destroy = nil -- function to destory the script -script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again script_data.show = nil -- only required for libs since the destroy_method only hides them +-- - - - - - - - - - - - - - - - - - - - - - - - - - +-- I 1 8 N +-- - - - - - - - - - - - - - - - - - - - - - - - - - + +local gettext = dt.gettext + -- Tell gettext where to find the .mo file translating messages for a particular domain -gettext.bindtextdomain(MODULE, dt.configuration.config_dir.."/lua/locale/") +gettext.bindtextdomain(MODULE, dt.configuration.config_dir .. "/lua/locale/") local function _(msgid) return gettext.dgettext(MODULE, msgid) end --- create a namespace to contain persistent data and widgets -chg_grp_ldr = {} - -local cgl = chg_grp_ldr - -cgl.widgets = {} +-- - - - - - - - - - - - - - - - - - - - - - - - +-- F U N C T I O N S +-- - - - - - - - - - - - - - - - - - - - - - - - -cgl.event_registered = false -cgl.module_installed = false +local function toggle_global_toolbox_grouping() + dt.gui.libs.global_toolbox.grouping = false + dt.gui.libs.global_toolbox.grouping = true +end --- - - - - - - - - - - - - - - - - - - - - - - - --- F U N C T I O N S --- - - - - - - - - - - - - - - - - - - - - - - - - -local function install_module() - if not cgl.module_installed then - dt.register_lib( - MODULE, -- Module name - _("change_group_leader"), -- Visible name - true, -- expandable - false, -- resetable - {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 700}}, -- containers - cgl.widgets.box, - nil,-- view_enter - nil -- view_leave - ) - cgl.module_installed = true - end +local function hinter_msg(msg) + dt.print_hinter(msg) + dt.control.sleep(1500) + dt.print_hinter(" ") end -local function find_group_leader(images, mode) - for _, img in ipairs(images) do - dt.print_log("checking image " .. img.id .. " named " .. img.filename) - local found = false - if mode == "jpg" then - if string.match(string.lower(img.filename), "jpg$") then - dt.print_log("jpg matched image " .. img.filename) - found = true - end - elseif mode == "raw" then - if img.is_raw and img.duplicate_index == 0 then - dt.print_log("found raw " .. img.filename) - found = true - end - elseif mode == "non-raw" then - if img.is_ldr then - dt.print_log("found ldr " .. img.filename) - found = true +-- - - - - - - - - - - - - - - - - - - - - - - - +-- M A I N P R O G R A M +-- - - - - - - - - - - - - - - - - - - - - - - - + +local function change_group_leader(image) + local group_images = image:get_group_members() + if #group_images < 2 then + hinter_msg(_("No images to change to in group")) + return + else + local position = nil + for i, img in ipairs(group_images) do + if image == img then + position = i end - else - dt.print_error(MODULE .. ": unrecognized mode " .. mode) - return end - if found then - dt.print_log("making " .. img.filename .. " group leader") - img:make_group_leader() - return + + if position == #group_images then + position = 1 + else + position = position + 1 end - end -end -local function process_image_groups(images) - if #images < 1 then - dt.print(_("No images selected.")) - dt.print_log(MODULE .. "no images seletected, returning...") - else - local mode = cgl.widgets.mode.value - for _,img in ipairs(images) do - dt.print_log("checking image " .. img.id) - local group_images = img:get_group_members() - if group_images == 1 then - dt.print_log("only one image in group for image " .. image.id) - else - find_group_leader(group_images, mode) - end + new_leader = group_images[position] + new_leader:make_group_leader() + dt.gui.selection({new_leader}) + + if dt.gui.libs.global_toolbox.grouping then + -- toggle the grouping to make the new leader show + toggle_global_toolbox_grouping() end end end --- - - - - - - - - - - - - - - - - - - - - - - - --- S C R I P T M A N A G E R I N T E G R A T I O N --- - - - - - - - - - - - - - - - - - - - - - - - +-- - - - - - - - - - - - - - - - - - - - - - - - +-- D A R K T A B L E I N T E G R A T I O N +-- - - - - - - - - - - - - - - - - - - - - - - - local function destroy() - dt.gui.libs[MODULE].visible = false + -- put things to destroy (events, storages, etc) here + dt.destroy_event(MODULE, "shortcut") end -local function restart() - dt.gui.libs[MODULE].visible = true -end +script_data.destroy = destroy --- - - - - - - - - - - - - - - - - - - - - - - - --- W I D G E T S --- - - - - - - - - - - - - - - - - - - - - - - - - -cgl.widgets.mode = dt.new_widget("combobox"){ - label = _("select new group leader"), - tooltip = _("select type of image to be group leader"), - selected = 1, - "jpg", "raw", "non-raw", -} - -cgl.widgets.execute = dt.new_widget("button"){ - label = _("Execute"), - clicked_callback = function() - process_image_groups(dt.gui.action_images) - end -} - -cgl.widgets.box = dt.new_widget("box"){ - orientation = "vertical", - cgl.widgets.mode, - cgl.widgets.execute, -} - --- - - - - - - - - - - - - - - - - - - - - - - - --- D A R K T A B L E I N T E G R A T I O N --- - - - - - - - - - - - - - - - - - - - - - - - - -if dt.gui.current_view().id == "lighttable" then - install_module() -else - if not cgl.event_registered then - dt.register_event( - "view-changed", - function(event, old_view, new_view) - if new_view.name == "lighttable" and old_view.name == "darkroom" then - install_module() - end - end - ) - cgl.event_registered = true - end -end +-- - - - - - - - - - - - - - - - - - - - - - - - +-- E V E N T S +-- - - - - - - - - - - - - - - - - - - - - - - - -script_data.destroy = destroy -script_data.restart = restart -script_data.destroy_method = "hide" -script_data.show = restart +dt.register_event(MODULE, "shortcut", + function(event, shortcut) + -- ignore the film roll, it contains all the images, not just the imported + local images = dt.gui.selection() + if #images < 1 then + dt.print(_("No image selected. Please select an image and try again")) + else + change_group_leader(images[1]) + end + end, + _("Change group leader") +) return script_data \ No newline at end of file From 8bfab0325be8e92f6fb97c2f10e8bc6d005dc469 Mon Sep 17 00:00:00 2001 From: wpferguson Date: Sun, 14 Jan 2024 22:13:38 -0500 Subject: [PATCH 259/445] Revert "Change group leader" --- contrib/change_group_leader.lua | 261 +++++++++++++++++++------------- 1 file changed, 152 insertions(+), 109 deletions(-) diff --git a/contrib/change_group_leader.lua b/contrib/change_group_leader.lua index b06b445d..c7fe5c0f 100644 --- a/contrib/change_group_leader.lua +++ b/contrib/change_group_leader.lua @@ -1,158 +1,201 @@ --[[ + change group leader - change_group_leader.lua - change image grouip leader + copyright (c) 2020, 2022 Bill Ferguson + copyright (c) 2021 Angel Angelov - Copyright (C) 2024 Bill Ferguson + darktable is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. + darktable is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . + You should have received a copy of the GNU General Public License + along with darktable. If not, see . ]] ---[[ - change_group_leader - change image grouip leader - - change_group_leader changes the group leader to the next - image in the group. If the end of the group is reached - then the next image is wrapped around to the first image. - - ADDITIONAL SOFTWARE NEEDED FOR THIS SCRIPT - None - - USAGE - * enable with script_manager - * assign a key to the shortcut - - BUGS, COMMENTS, SUGGESTIONS - Bill Ferguson - CHANGES +--[[ +CHANGE GROUP LEADER +automatically change the leader of raw+jpg paired image groups + +INSTALLATION +* copy this file in $CONFIGDIR/lua/ where CONFIGDIR is your darktable configuration directory +* add the following line in the file $CONFIGDIR/luarc + require "change_group_leader" + +USAGE +* in lighttable mode, select the image groups you wish to process, + select whether you want to set the leader to "jpg" or "raw", + and click "Execute" ]] local dt = require "darktable" local du = require "lib/dtutils" -local df = require "lib/dtutils.file" --- - - - - - - - - - - - - - - - - - - - - - - - --- C O N S T A N T S --- - - - - - - - - - - - - - - - - - - - - - - - +local gettext = dt.gettext local MODULE = "change_group_leader" --- - - - - - - - - - - - - - - - - - - - - - - - --- A P I C H E C K --- - - - - - - - - - - - - - - - - - - - - - - - - -du.check_min_api_version("7.0.0", MODULE) +du.check_min_api_version("3.0.0", MODULE) - --- - - - - - - - - - - - - - - - - - - - - - - - - - --- S C R I P T M A N A G E R I N T E G R A T I O N --- - - - - - - - - - - - - - - - - - - - - - - - - - +-- return data structure for script_manager local script_data = {} script_data.destroy = nil -- function to destory the script -script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again script_data.show = nil -- only required for libs since the destroy_method only hides them --- - - - - - - - - - - - - - - - - - - - - - - - - - --- I 1 8 N --- - - - - - - - - - - - - - - - - - - - - - - - - - - -local gettext = dt.gettext - -- Tell gettext where to find the .mo file translating messages for a particular domain -gettext.bindtextdomain(MODULE, dt.configuration.config_dir .. "/lua/locale/") +gettext.bindtextdomain(MODULE, dt.configuration.config_dir.."/lua/locale/") local function _(msgid) return gettext.dgettext(MODULE, msgid) end --- - - - - - - - - - - - - - - - - - - - - - - - --- F U N C T I O N S --- - - - - - - - - - - - - - - - - - - - - - - - +-- create a namespace to contain persistent data and widgets +chg_grp_ldr = {} -local function toggle_global_toolbox_grouping() - dt.gui.libs.global_toolbox.grouping = false - dt.gui.libs.global_toolbox.grouping = true -end +local cgl = chg_grp_ldr -local function hinter_msg(msg) - dt.print_hinter(msg) - dt.control.sleep(1500) - dt.print_hinter(" ") -end +cgl.widgets = {} --- - - - - - - - - - - - - - - - - - - - - - - - --- M A I N P R O G R A M --- - - - - - - - - - - - - - - - - - - - - - - - +cgl.event_registered = false +cgl.module_installed = false -local function change_group_leader(image) - local group_images = image:get_group_members() - if #group_images < 2 then - hinter_msg(_("No images to change to in group")) - return - else - local position = nil - for i, img in ipairs(group_images) do - if image == img then - position = i - end - end +-- - - - - - - - - - - - - - - - - - - - - - - - +-- F U N C T I O N S +-- - - - - - - - - - - - - - - - - - - - - - - - + +local function install_module() + if not cgl.module_installed then + dt.register_lib( + MODULE, -- Module name + _("change_group_leader"), -- Visible name + true, -- expandable + false, -- resetable + {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 700}}, -- containers + cgl.widgets.box, + nil,-- view_enter + nil -- view_leave + ) + cgl.module_installed = true + end +end - if position == #group_images then - position = 1 +local function find_group_leader(images, mode) + for _, img in ipairs(images) do + dt.print_log("checking image " .. img.id .. " named " .. img.filename) + local found = false + if mode == "jpg" then + if string.match(string.lower(img.filename), "jpg$") then + dt.print_log("jpg matched image " .. img.filename) + found = true + end + elseif mode == "raw" then + if img.is_raw and img.duplicate_index == 0 then + dt.print_log("found raw " .. img.filename) + found = true + end + elseif mode == "non-raw" then + if img.is_ldr then + dt.print_log("found ldr " .. img.filename) + found = true + end else - position = position + 1 + dt.print_error(MODULE .. ": unrecognized mode " .. mode) + return end + if found then + dt.print_log("making " .. img.filename .. " group leader") + img:make_group_leader() + return + end + end +end - new_leader = group_images[position] - new_leader:make_group_leader() - dt.gui.selection({new_leader}) - - if dt.gui.libs.global_toolbox.grouping then - -- toggle the grouping to make the new leader show - toggle_global_toolbox_grouping() +local function process_image_groups(images) + if #images < 1 then + dt.print(_("No images selected.")) + dt.print_log(MODULE .. "no images seletected, returning...") + else + local mode = cgl.widgets.mode.value + for _,img in ipairs(images) do + dt.print_log("checking image " .. img.id) + local group_images = img:get_group_members() + if group_images == 1 then + dt.print_log("only one image in group for image " .. image.id) + else + find_group_leader(group_images, mode) + end end end end --- - - - - - - - - - - - - - - - - - - - - - - - --- D A R K T A B L E I N T E G R A T I O N --- - - - - - - - - - - - - - - - - - - - - - - - +-- - - - - - - - - - - - - - - - - - - - - - - - +-- S C R I P T M A N A G E R I N T E G R A T I O N +-- - - - - - - - - - - - - - - - - - - - - - - - local function destroy() - -- put things to destroy (events, storages, etc) here - dt.destroy_event(MODULE, "shortcut") + dt.gui.libs[MODULE].visible = false end -script_data.destroy = destroy +local function restart() + dt.gui.libs[MODULE].visible = true +end --- - - - - - - - - - - - - - - - - - - - - - - - --- E V E N T S --- - - - - - - - - - - - - - - - - - - - - - - - +-- - - - - - - - - - - - - - - - - - - - - - - - +-- W I D G E T S +-- - - - - - - - - - - - - - - - - - - - - - - - + +cgl.widgets.mode = dt.new_widget("combobox"){ + label = _("select new group leader"), + tooltip = _("select type of image to be group leader"), + selected = 1, + "jpg", "raw", "non-raw", +} + +cgl.widgets.execute = dt.new_widget("button"){ + label = _("Execute"), + clicked_callback = function() + process_image_groups(dt.gui.action_images) + end +} + +cgl.widgets.box = dt.new_widget("box"){ + orientation = "vertical", + cgl.widgets.mode, + cgl.widgets.execute, +} + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- D A R K T A B L E I N T E G R A T I O N +-- - - - - - - - - - - - - - - - - - - - - - - - + +if dt.gui.current_view().id == "lighttable" then + install_module() +else + if not cgl.event_registered then + dt.register_event( + "view-changed", + function(event, old_view, new_view) + if new_view.name == "lighttable" and old_view.name == "darkroom" then + install_module() + end + end + ) + cgl.event_registered = true + end +end -dt.register_event(MODULE, "shortcut", - function(event, shortcut) - -- ignore the film roll, it contains all the images, not just the imported - local images = dt.gui.selection() - if #images < 1 then - dt.print(_("No image selected. Please select an image and try again")) - else - change_group_leader(images[1]) - end - end, - _("Change group leader") -) +script_data.destroy = destroy +script_data.restart = restart +script_data.destroy_method = "hide" +script_data.show = restart return script_data \ No newline at end of file From cf1dca9e1a0fdec80d4626eb00c5f039f911691c Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sun, 14 Jan 2024 22:29:27 -0500 Subject: [PATCH 260/445] contrib/cycle_group_leader.lus - adds shortcut to change the group leader to the next image in a group wrapping around when the end of the group is reached. --- contrib/cycle_group_leader.lua | 158 +++++++++++++++++++++++++++++++++ 1 file changed, 158 insertions(+) create mode 100644 contrib/cycle_group_leader.lua diff --git a/contrib/cycle_group_leader.lua b/contrib/cycle_group_leader.lua new file mode 100644 index 00000000..e4bdd11f --- /dev/null +++ b/contrib/cycle_group_leader.lua @@ -0,0 +1,158 @@ +--[[ + + cycle_group_leader.lua - change image grouip leader + + Copyright (C) 2024 Bill Ferguson + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +]] +--[[ + cycle_group_leader - change image grouip leader + + cycle_group_leader changes the group leader to the next + image in the group. If the end of the group is reached + then the next image is wrapped around to the first image. + + ADDITIONAL SOFTWARE NEEDED FOR THIS SCRIPT + None + + USAGE + * enable with script_manager + * assign a key to the shortcut + + BUGS, COMMENTS, SUGGESTIONS + Bill Ferguson + + CHANGES +]] + +local dt = require "darktable" +local du = require "lib/dtutils" +local df = require "lib/dtutils.file" + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- C O N S T A N T S +-- - - - - - - - - - - - - - - - - - - - - - - - + +local MODULE = "cycle_group_leader" + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- A P I C H E C K +-- - - - - - - - - - - - - - - - - - - - - - - - + +du.check_min_api_version("7.0.0", MODULE) + + +-- - - - - - - - - - - - - - - - - - - - - - - - - - +-- S C R I P T M A N A G E R I N T E G R A T I O N +-- - - - - - - - - - - - - - - - - - - - - - - - - - + +local script_data = {} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them + +-- - - - - - - - - - - - - - - - - - - - - - - - - - +-- I 1 8 N +-- - - - - - - - - - - - - - - - - - - - - - - - - - + +local gettext = dt.gettext + +-- Tell gettext where to find the .mo file translating messages for a particular domain +gettext.bindtextdomain(MODULE, dt.configuration.config_dir .. "/lua/locale/") + +local function _(msgid) + return gettext.dgettext(MODULE, msgid) +end + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- F U N C T I O N S +-- - - - - - - - - - - - - - - - - - - - - - - - + +local function toggle_global_toolbox_grouping() + dt.gui.libs.global_toolbox.grouping = false + dt.gui.libs.global_toolbox.grouping = true +end + +local function hinter_msg(msg) + dt.print_hinter(msg) + dt.control.sleep(1500) + dt.print_hinter(" ") +end + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- M A I N P R O G R A M +-- - - - - - - - - - - - - - - - - - - - - - - - + +local function cycle_group_leader(image) + local group_images = image:get_group_members() + if #group_images < 2 then + hinter_msg(_("No images to cycle to in group")) + return + else + local position = nil + for i, img in ipairs(group_images) do + if image == img then + position = i + end + end + + if position == #group_images then + position = 1 + else + position = position + 1 + end + + new_leader = group_images[position] + new_leader:make_group_leader() + dt.gui.selection({new_leader}) + + if dt.gui.libs.global_toolbox.grouping then + -- toggle the grouping to make the new leader show + toggle_global_toolbox_grouping() + end + end +end + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- D A R K T A B L E I N T E G R A T I O N +-- - - - - - - - - - - - - - - - - - - - - - - - + +local function destroy() + -- put things to destroy (events, storages, etc) here + dt.destroy_event(MODULE, "shortcut") +end + +script_data.destroy = destroy + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- E V E N T S +-- - - - - - - - - - - - - - - - - - - - - - - - + +dt.register_event(MODULE, "shortcut", + function(event, shortcut) + -- ignore the film roll, it contains all the images, not just the imported + local images = dt.gui.selection() + if #images < 1 then + dt.print(_("No image selected. Please select an image and try again")) + else + cycle_group_leader(images[1]) + end + end, + _("cycle group leader") +) + +return script_data From f54d4493168bf6937ab16e4f9d488016ad1a42be Mon Sep 17 00:00:00 2001 From: Martin Straeten <39386816+MStraeten@users.noreply.github.com> Date: Mon, 15 Jan 2024 07:01:43 +0100 Subject: [PATCH 261/445] increase required api version MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit … to match darktable 4.6.x --- examples/x-touch.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/x-touch.lua b/examples/x-touch.lua index d0f7cd88..73ed112b 100644 --- a/examples/x-touch.lua +++ b/examples/x-touch.lua @@ -53,7 +53,7 @@ midi:C0=iop/channelmixerrgb;focus local dt = require "darktable" local du = require "lib/dtutils" -du.check_min_api_version("9.1.0", "x-touch") +du.check_min_api_version("9.2.0", "x-touch") -- set up 8 mimic sliders with the same function for k = 1,8 do From f9fe33f930ccb01fd43edcc4d0c04f880e874910 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Fri, 19 Jan 2024 15:24:56 -0500 Subject: [PATCH 262/445] updated script_manager and executable_manager to use darktable translation facilities. Changed translatable messages with arguments to use string.format for one complete string versus snippets. Removed gen_i18n_mo since we will be using darktable's translation facilities and there's no need to generate lua specific mo files. --- tools/executable_manager.lua | 10 ++-- tools/gen_i18n_mo.lua | 108 ----------------------------------- tools/script_manager.lua | 38 ++++++------ 3 files changed, 22 insertions(+), 134 deletions(-) delete mode 100644 tools/gen_i18n_mo.lua diff --git a/tools/executable_manager.lua b/tools/executable_manager.lua index a8690ea8..75b4a6b3 100644 --- a/tools/executable_manager.lua +++ b/tools/executable_manager.lua @@ -45,9 +45,7 @@ script_data.show = nil -- only required for libs since the destroy_method only h local PS = dt.configuration.running_os == "windows" and "\\" or "/" -local gettext = dt.gettext - -gettext.bindtextdomain("executable_manager",dt.configuration.config_dir.."/lua/locale/") +local gettext = dt.gettext.gettext local exec_man = {} -- our own namespace exec_man.module_installed = false @@ -58,7 +56,7 @@ exec_man.event_registered = false -- - - - - - - - - - - - - - - - - - - - - - - - - - - - local function _(msg) - return gettext.dgettext("executable_manager", msg) + return gettext(msg) end local function grep(file, pattern) @@ -167,7 +165,7 @@ for i,exec in ipairs(exec_table) do editable = false } executable_path_widgets[exec] = dt.new_widget("file_chooser_button"){ - title = _("select ") .. exec .. _(" executable"), + title = _(string.format("select %s executable", exec)), value = df.get_executable_path_preference(exec), is_directory = false, changed_callback = function(self) @@ -210,7 +208,7 @@ for i,exec in ipairs(exec_table) do dt.new_widget("section_label"){label = _("reset")}, dt.new_widget("button"){ label = _("clear"), - tooltip = _("Clear path for ") .. exec, + tooltip = _(string.format("Clear path for %s", exec)), clicked_callback = function() df.set_executable_path_preference(exec, "") executable_path_widgets[exec].value = "" diff --git a/tools/gen_i18n_mo.lua b/tools/gen_i18n_mo.lua deleted file mode 100644 index 6aa453c2..00000000 --- a/tools/gen_i18n_mo.lua +++ /dev/null @@ -1,108 +0,0 @@ ---[[ - gen_18n_mo.lua - generate .mo files from .po files and put them in the correct place - - Copyright (C) 2016,2018 Bill Ferguson - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -]] ---[[ - gen_i18n_mo - generate translation files from the source and place them in the appropriate locale directory - - gen_i18n_mo finds all the .po files scattered throughout the script tree, compiles them into - .mo files and places them in the correct locale directory for use by the gettext tools. - -]] - -local dt = require "darktable" -local du = require "lib/dtutils" -local df = require "lib/dtutils.file" -local log = require "lib/dtutils.log" -local dtsys = require "lib/dtutils.system" - -du.check_min_api_version("5.0.0", "gen_I18n_mo") - -local function destroy() - -- nothing to destroy -end - --- figure out the path separator - -local PS = dt.configuration.running_os == "windows" and "\\" or "/" - -local LUA_DIR = dt.configuration.config_dir .. PS .. "lua" .. PS -local LOCALE_DIR = dt.configuration.config_dir .. PS .. "lua" .. PS .. "locale" .. PS - --- check if we have msgfmt - -local msgfmt_executable = df.check_if_bin_exists("msgfmt") - -if msgfmt_executable then - - -- find the .po files - - local find_cmd = "find -L " .. LUA_DIR .. " -name \\*.po -print" - if dt.configuration.running_os == "windows" then - find_cmd = "dir /b/s " .. LUA_DIR .. "\\*.po" - end - - local output = io.popen(find_cmd) - - -- for each .po file.... - - for line in output:lines() do - local fname = df.get_filename(line) - - -- get the language used... this depends on the file being named using - -- the convention /..../lang/LC_MESSAGES/file.po where lang is de_DE, fr_FR, etc. - - local path_parts = du.split(line, PS) - local lang = path_parts[#path_parts - 2] - - -- ensure there is a destination directory for them - - local mkdir_cmd = "mkdir -p " - if dt.configuration.running_os == "windows" then - mkdir_cmd = "mkdir " - end - - if not df.check_if_file_exists(LOCALE_DIR .. lang .. PS .. "LC_MESSAGES") then - log.msg(log.info, "Creating locale", lang) - os.execute(mkdir_cmd .. LOCALE_DIR .. lang .. PS .. "LC_MESSAGES") - end - - -- generate the mo file - - fname = string.gsub(fname, ".po$", ".mo") - log.msg(log.info, "Compiling translation to", fname) - local result = os.execute(msgfmt_executable .. " -o " .. LOCALE_DIR .. lang .. PS .. "LC_MESSAGES" .. PS .. fname .. " " .. line) - end -else - log.msg(log.screen, "ERROR: msgfmt executable not found. Please install or specifiy location in preferences.") -end -dt.preferences.register("executable_paths", "msgfmt", -- name - "file", -- type - 'gen_i18n_mo: msgfmt location', -- label - 'Install location of msgfmt. Requires restart to take effect.', -- tooltip - "msgfmt", -- default - dt.new_widget("file_chooser_button"){ - title = "Select msgfmt[.exe] file", - value = "", - is_directory = false, - } -) - -local script_data = {} -script_data.destroy = destroy - -return script_data diff --git a/tools/script_manager.lua b/tools/script_manager.lua index e65cd204..6a5d2acd 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -56,14 +56,12 @@ local dtsys = require "lib/dtutils.system" local log = require "lib/dtutils.log" local debug = require "darktable.debug" -local gettext = dt.gettext +-- set up translation - --- Tell gettext where to find the .mo file translating messages for a particular domain -gettext.bindtextdomain("script_manager",dt.configuration.config_dir.."/lua/locale/") +local gettext = dt.gettext.gettext local function _(msgid) - return gettext.dgettext("script_manager", msgid) + return gettext(msgid) end -- api check @@ -369,7 +367,7 @@ local function get_script_doc(script) -- assume that the second block comment is the documentation description = string.match(content, "%-%-%[%[.-%]%].-%-%-%[%[(.-)%]%]") else - log.msg(log.error, _("Cant read from " .. script)) + log.msg(log.error, "Cant read from " .. script) end if description then restore_log_level(old_log_level) @@ -392,7 +390,7 @@ local function activate(script) script_manager_running_script = nil if status then pref_write(script.script_name, "bool", true) - log.msg(log.screen, _("Loaded ") .. script.script_name) + log.msg(log.screen, string.format(_("Loaded %s"), script.script_name)) script.running = true if err ~= true then log.msg(log.debug, "got lib data") @@ -404,7 +402,7 @@ local function activate(script) script.data = nil end else - log.msg(log.screen, script.script_name .. _(" failed to load")) + log.msg(log.screen, string.format(_("%s failed to load"), script.script_name)) log.msg(log.error, "Error loading " .. script.script_name) log.msg(log.error, "Error message: " .. err) end @@ -443,11 +441,11 @@ local function deactivate(script) script.running = false end log.msg(log.info, "turned off " .. script.script_name) - log.msg(log.screen, script.name .. _(" stopped")) + log.msg(log.screen, string.format(_("%s stopped"), script.name)) else script.running = false log.msg(log.info, "setting " .. script.script_name .. " to not start") - log.msg(log.screen, script.name .. _(" will not start when darktable is restarted")) + log.msg(log.screen, string.format(_("%s will not start when darktable is restarted"), script.name)) end restore_log_level(old_log_level) end @@ -515,7 +513,7 @@ local function scan_scripts(script_dir) if dt.configuration.running_os == "windows" then find_cmd = "dir /b/s \"" .. script_dir .. "\\*.lua\" | sort" end - log.msg(log.debug, _("find command is ") .. find_cmd) + log.msg(log.debug, "find command is " .. find_cmd) -- scan the scripts local output = io.popen(find_cmd) for line in output:lines() do @@ -589,7 +587,7 @@ local function scan_repositories() if dt.configuration.running_os == "windows" then find_cmd = "dir /b/s /a:d " .. LUA_DIR .. PS .. "*.git | sort" end - log.msg(log.debug, _("find command is ") .. find_cmd) + log.msg(log.debug, "find command is " .. find_cmd) local output = io.popen(find_cmd) for line in output:lines() do local l = string.gsub(line, ds.sanitize_lua(LUA_DIR) .. PS, "") -- strip the lua dir off @@ -627,7 +625,7 @@ local function install_scripts() local category = sm.widgets.new_category.text if string.match(du.join(sm.categories, " "), ds.sanitize_lua(category)) then - log.msg(log.screen, _("category ") .. category .. _(" is already in use. Please specify a different category name.")) + log.msg(log.screen, string.format(_("category %s is already in use. Please specify a different category name."), category)) log.msg(log.error, "category " .. category .. " already exists, returning...") restore_log_level(old_log_level) return @@ -658,7 +656,7 @@ local function install_scripts() local count = scan_scripts(LUA_DIR .. PS .. category) if count > 0 then update_combobox_choices(sm.widgets.category_selector, sm.categories, sm.widgets.category_selector.selected) - dt.print(_("scripts successfully installed into category ") .. category) + dt.print(string.format(_("scripts successfully installed into category "), category)) table.insert(sm.installed_repositories, {name = category, directory = LUA_DIR .. PS .. category}) update_script_update_choices() for i = 1, #sm.widgets.category_selector do @@ -719,14 +717,14 @@ local function populate_buttons(category, first, last) button.label = script.name button.name = "sm_started" else - button.label = script.name .. _(" started") + button.label = string.format(_("%s started"), script.name) end else if sm.use_color then button.label = script.name button.name = "sm_stopped" else - button.label = script.name .. _(" stopped") + button.label = string.format(_("%s stopped"), script.name) end end button.ellipsize = "middle" @@ -749,7 +747,7 @@ local function populate_buttons(category, first, last) if sm.use_color then this.name = "sm_stopped" else - this.label = script.name .. _(" stopped") + this.label = string.format(_("%s stopped"), script.name) end else log.msg(log.debug, "activating " .. script.name .. " on " .. script.path .. " for button " .. this.label) @@ -758,7 +756,7 @@ local function populate_buttons(category, first, last) if sm.use_color then this.name = "sm_started" else - this.label = script.name .. " started" + this.label = string.format(_("%s started"), script.name) end end end @@ -826,7 +824,7 @@ local function paginate(direction) else last = first + sm.page_status.num_buttons - 1 end - sm.widgets.page_status.label = _("Page ") .. cur_page .. _(" of ") .. max_pages + sm.widgets.page_status.label = string.format(_("Page %d of %d"), cur_page, max_pages) populate_buttons(category, first, last) restore_log_level(old_log_level) @@ -1125,7 +1123,7 @@ sm.widgets.install_update = dt.new_widget("box"){ sm.widgets.category_selector = dt.new_widget("combobox"){ label = _("category"), - tooltip = _( "select the script category"), + tooltip = _("select the script category"), selected = 1, changed_callback = function(self) if sm.run then From c11845cbf9043e6ab3e0a5bc28bf3ede4eb68882 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Fri, 19 Jan 2024 18:57:18 -0500 Subject: [PATCH 263/445] updated example scripts to use darktable translation facilities --- examples/api_version.lua | 11 +++++++++- examples/darkroom_demo.lua | 7 +++---- examples/gettextExample.lua | 16 ++++++--------- examples/hello_world.lua | 10 ++++++++- examples/lighttable_demo.lua | 21 +++++++++---------- examples/moduleExample.lua | 6 ++---- examples/multi_os.lua | 13 +++++------- examples/panels_demo.lua | 5 ++--- examples/preferenceExamples.lua | 36 ++++++++++++++++++++------------- examples/printExamples.lua | 10 ++++++++- examples/running_os.lua | 10 ++++++++- 11 files changed, 87 insertions(+), 58 deletions(-) diff --git a/examples/api_version.lua b/examples/api_version.lua index f2aaff72..1f86f6b7 100644 --- a/examples/api_version.lua +++ b/examples/api_version.lua @@ -23,6 +23,14 @@ USAGE ]] local dt = require "darktable" +-- translation facilities + +local gettext = dt.gettext.gettext + +local function _(msg) + return gettext(msg) +end + -- script_manager integration to allow a script to be removed -- without restarting darktable local function destroy() @@ -30,7 +38,8 @@ local function destroy() end local result = dt.configuration.api_version_string -dt.print_error("API Version: "..result) +dt.print_log("API Version: " .. result) +dt.print(string.format(_("API Version: %s"), result)) -- set the destroy routine so that script_manager can call it when -- it's time to destroy the script and then return the data to diff --git a/examples/darkroom_demo.lua b/examples/darkroom_demo.lua index b4edcc56..6ca9f89e 100644 --- a/examples/darkroom_demo.lua +++ b/examples/darkroom_demo.lua @@ -58,11 +58,10 @@ local PS = dt.configuration.running_os == "windows" and "\\" or "/" -- - - - - - - - - - - - - - - - - - - - - - - - -- T R A N S L A T I O N S -- - - - - - - - - - - - - - - - - - - - - - - - -local gettext = dt.gettext -gettext.bindtextdomain(MODULE_NAME, dt.configuration.config_dir..PS.."lua"..PS.."locale"..PS) +local gettext = dt.gettext.gettext local function _(msgid) - return gettext.dgettext(MODULE_NAME, msgid) + return gettext(msgid) end -- - - - - - - - - - - - - - - - - - - - - - - - @@ -98,7 +97,7 @@ sleep(1500) -- display first 10 images of collection pausing for a second between each for i, img in ipairs(dt.collection) do - dt.print(_("Displaying image " .. i)) + dt.print(string.format(_("Displaying image "), i)) dt.gui.views.darkroom.display_image(img) sleep(1500) if i == max_images then diff --git a/examples/gettextExample.lua b/examples/gettextExample.lua index 59a676c1..f74b5033 100644 --- a/examples/gettextExample.lua +++ b/examples/gettextExample.lua @@ -67,22 +67,18 @@ end -- Not translated Text dt.print_error("Hello World!") -local gettext = dt.gettext --- Translate a string using the darktable textdomain -dt.print_error(gettext.gettext("image")) - --- Tell gettext where to find the .mo file translating messages for a particular domain +local gettext = dt.gettext.gettext -gettext.bindtextdomain("gettextExample",dt.configuration.config_dir.."/lua/locale/") --- Translate a string using the specified textdomain -dt.print_error(gettext.dgettext("gettextExample", 'Hello World!')) +-- Translate a string using the darktable textdomain +dt.print_error(gettext("image")) -- Define a local function called _ to make the code more readable and have it call dgettext -- with the proper domain. local function _(msgid) - return gettext.dgettext("gettextExample", msgid) + return gettext(msgid) end -dt.print_error(_('Hello World!')) + +dt.print_error(_("Hello World!")) -- set the destroy routine so that script_manager can call it when -- it's time to destroy the script and then return the data to diff --git a/examples/hello_world.lua b/examples/hello_world.lua index f8fba8d4..3839ebda 100644 --- a/examples/hello_world.lua +++ b/examples/hello_world.lua @@ -29,15 +29,23 @@ USAGE local dt = require "darktable" local du = require "lib/dtutils" +-- translation facilities + du.check_min_api_version("2.0.0", "hello_world") +local gettext = dt.gettext.gettext + +local function _(msg) + return gettext(msg) +end + -- script_manager integration to allow a script to be removed -- without restarting darktable local function destroy() -- nothing to destroy end -dt.print("hello, world") +dt.print(_("hello, world")) -- set the destroy routine so that script_manager can call it when -- it's time to destroy the script and then return the data to diff --git a/examples/lighttable_demo.lua b/examples/lighttable_demo.lua index fc071325..768e4ab3 100644 --- a/examples/lighttable_demo.lua +++ b/examples/lighttable_demo.lua @@ -59,11 +59,10 @@ end -- - - - - - - - - - - - - - - - - - - - - - - - -- T R A N S L A T I O N S -- - - - - - - - - - - - - - - - - - - - - - - - -local gettext = dt.gettext -gettext.bindtextdomain(MODULE_NAME, dt.configuration.config_dir..PS.."lua"..PS.."locale"..PS) +local gettext = dt.gettext.gettext local function _(msgid) - return gettext.dgettext(MODULE_NAME, msgid) + return gettext(msgid) end -- - - - - - - - - - - - - - - - - - - - - - - - @@ -145,17 +144,17 @@ sleep(2000) for n, layout in ipairs(layouts) do dt.gui.libs.lighttable_mode.layout(layout) - dt.print(_("set lighttable layout to " .. layout)) - dt.print_log(_("set lighttable layout to " .. layout)) + dt.print(string.format(_("set lighttable layout to %s"), layout)) + dt.print_log("set lighttable layout to " .. layout) sleep(1500) for i = 1, 10 do dt.gui.libs.lighttable_mode.zoom_level(i) - dt.print(_("Set zoom level to " .. i)) + dt.print(string.format(_("Set zoom level to %d"), i)) sleep(1500) end for i = 9, 1, -1 do dt.gui.libs.lighttable_mode.zoom_level(i) - dt.print(_("Set zoom level to " .. i)) + dt.print(string.format(_("Set zoom level to %d"), i)) sleep(1500) end end @@ -174,12 +173,12 @@ dt.print_log("starting sorts") for n, sort in ipairs(sorts) do dt.gui.libs.filter.sort(sort) - dt.print(_("set lighttable sort to " .. sort)) + dt.print(string.format(_("set lighttable sort to %s"), sort)) sleep(1500) for m, sort_order in ipairs(sort_orders) do dt.gui.libs.filter.sort_order(sort_order) - dt.print(_("sort order set to " .. sort_order)) + dt.print(string.format(_("sort order set to %s"), sort_order)) sleep(1500) end end @@ -190,12 +189,12 @@ dt.print(_("lighttable filtering demonstration")) for n, rating in ipairs(ratings) do dt.gui.libs.filter.rating(rating) - dt.print(_("set filter to " .. rating)) + dt.print(string.format(_("set filter to %s"), rating)) sleep(1500) for m, rating_comparator in ipairs(rating_comparators) do dt.gui.libs.filter.rating_comparator(rating_comparator) - dt.print(_("set rating comparator to " .. rating_comparator)) + dt.print(string.format(_("set rating comparator to %s"), rating_comparator)) sleep(1500) end end diff --git a/examples/moduleExample.lua b/examples/moduleExample.lua index bf5a3253..23184aad 100644 --- a/examples/moduleExample.lua +++ b/examples/moduleExample.lua @@ -47,12 +47,10 @@ script_data.show = nil -- only required for libs since the destroy_method only h -- translation -- https://www.darktable.org/lua-api/index.html#darktable_gettext -local gettext = dt.gettext - -gettext.bindtextdomain("moduleExample", dt.configuration.config_dir .. "/lua/locale/") +local gettext = dt.gettext.gettext local function _(msgid) - return gettext.dgettext("moduleExample", msgid) + return gettext(msgid) end -- declare a local namespace and a couple of variables we'll need to install the module diff --git a/examples/multi_os.lua b/examples/multi_os.lua index 4ab650ff..7486a254 100644 --- a/examples/multi_os.lua +++ b/examples/multi_os.lua @@ -70,13 +70,10 @@ local dtsys = require "lib/dtutils.system" -- system utilities translations, inserting this lays the groundwork for anyone who wants to translate the strings. ]] -local gettext = dt.gettext - --- Tell gettext where to find the .mo file translating messages for a particular domain -gettext.bindtextdomain("multi_os",dt.configuration.config_dir.."/lua/locale/") +local gettext = dt.gettext.gettext local function _(msgid) - return gettext.dgettext("multi_os", msgid) + return gettext(msgid) end --[[ @@ -187,7 +184,7 @@ local function extract_embedded_jpeg(images) end else dt.print_error(image.filename .. " is not a raw file. No image can be extracted") -- print debugging error message - dt.print(image.filename .. " is not a raw file. No image can be extracted") -- print the error to the screen + dt.print(string.format(_("%s is not a raw file. No image can be extracted"), image.filename)) -- print the error to the screen end end else @@ -241,7 +238,7 @@ end dt.gui.libs.image.register_action( "multi_os", _("extract embedded jpeg"), function(event, images) extract_embedded_jpeg(images) end, - "extract embedded jpeg" + _("extract embedded jpeg") ) --[[ @@ -251,7 +248,7 @@ dt.gui.libs.image.register_action( dt.register_event( "multi_os", "shortcut", function(event, shortcut) extract_embedded_jpeg(dt.gui.action_images) end, - "extract embedded jpeg" + _("extract embedded jpeg") ) --[[ diff --git a/examples/panels_demo.lua b/examples/panels_demo.lua index 1f74d718..59383980 100644 --- a/examples/panels_demo.lua +++ b/examples/panels_demo.lua @@ -59,11 +59,10 @@ local PS = dt.configuration.running_os == "windows" and "\\" or "/" -- - - - - - - - - - - - - - - - - - - - - - - - -- T R A N S L A T I O N S -- - - - - - - - - - - - - - - - - - - - - - - - -local gettext = dt.gettext -gettext.bindtextdomain(MODULE_NAME, dt.configuration.config_dir..PS.."lua"..PS.."locale"..PS) +local gettext = dt.gettext.gettext local function _(msgid) - return gettext.dgettext(MODULE_NAME, msgid) + return gettext(msgid) end -- - - - - - - - - - - - - - - - - - - - - - - - diff --git a/examples/preferenceExamples.lua b/examples/preferenceExamples.lua index 99f85188..74e6152b 100644 --- a/examples/preferenceExamples.lua +++ b/examples/preferenceExamples.lua @@ -24,28 +24,36 @@ USAGE local dt = require "darktable" local du = require "lib/dtutils" +-- translation facilities + +local gettext = dt.gettext.gettext + +local function _(msg) + return gettext(msg) +end + du.check_min_api_version("2.0.1", "preferenceExamples") dt.preferences.register("preferenceExamples", -- script: This is a string used to avoid name collision in preferences (i.e namespace). Set it to something unique, usually the name of the script handling the preference. "preferenceExamplesString", -- name "string", -- type - "Example String", -- label - "Example String Tooltip", -- tooltip + _("Example String"), -- label + _("Example String Tooltip"), -- tooltip "String") -- default dt.preferences.register("preferenceExamples", -- script: This is a string used to avoid name collision in preferences (i.e namespace). Set it to something unique, usually the name of the script handling the preference. "preferenceExamplesBool", -- name "bool", -- type - "Example Boolean", -- label - "Example Boolean Tooltip", -- tooltip + _("Example Boolean"), -- label + _("Example Boolean Tooltip"), -- tooltip true) -- default dt.preferences.register("preferenceExamples", -- script: This is a string used to avoid name collision in preferences (i.e namespace). Set it to something unique, usually the name of the script handling the preference. "preferenceExamplesInteger", -- name "integer", -- type - "Example Integer", -- label - "Example Integer Tooltip", -- tooltip + _("Example Integer"), -- label + _("Example Integer Tooltip"), -- tooltip 2, -- default 1, -- min 99) -- max @@ -53,8 +61,8 @@ dt.preferences.register("preferenceExamples", -- script: This is a string dt.preferences.register("preferenceExamples", -- script: This is a string used to avoid name collision in preferences (i.e namespace). Set it to something unique, usually the name of the script handling the preference. "preferenceExamplesFloat", -- name "float", -- type - "Example Float", -- label - "Example Float Tooltip", -- tooltip + _("Example Float"), -- label + _("Example Float Tooltip"), -- tooltip 1.3, -- default 1, -- min 99, -- max @@ -63,22 +71,22 @@ dt.preferences.register("preferenceExamples", -- script: This is a string dt.preferences.register("preferenceExamples", -- script: This is a string used to avoid name collision in preferences (i.e namespace). Set it to something unique, usually the name of the script handling the preference. "preferenceExamplesFile", -- name "file", -- type - "Example File", -- label - "Example File Tooltip", -- tooltip + _("Example File"), -- label + _("Example File Tooltip"), -- tooltip "") -- default dt.preferences.register("preferenceExamples", -- script: This is a string used to avoid name collision in preferences (i.e namespace). Set it to something unique, usually the name of the script handling the preference. "preferenceExamplesDirectory", -- name "directory", -- type - "Example Directory", -- label - "Example Directory Tooltip", -- tooltip + _("Example Directory"), -- label + _("Example Directory Tooltip"), -- tooltip "") -- default dt.preferences.register("preferenceExamples", -- script: This is a string used to avoid name collision in preferences (i.e namespace). Set it to something unique, usually the name of the script handling the preference. "preferenceExamplesEnum", -- name "enum", -- type - "Example Enum", -- label - "Example Enum Tooltip", -- tooltip + _("Example Enum"), -- label + _("Example Enum Tooltip"), -- tooltip "Enum 1", -- default "Enum 1", "Enum 2") -- values diff --git a/examples/printExamples.lua b/examples/printExamples.lua index b220b7a0..b7be20c3 100644 --- a/examples/printExamples.lua +++ b/examples/printExamples.lua @@ -24,6 +24,14 @@ local du = require "lib/dtutils" du.check_min_api_version("5.0.0", "printExamples") +-- translation facilities + +local gettext = dt.gettext.gettext + +local function _(msg) + return gettext(msg) +end + -- script_manager integration to allow a script to be removed -- without restarting darktable local function destroy() @@ -32,7 +40,7 @@ end -- Will print a string to the darktable control log (the long -- overlayed window that appears over the main panel). -dt.print("print") +dt.print(_("print")) -- This function will print its parameter if the Lua logdomain is -- activated. Start darktable with the "-d lua" command line option diff --git a/examples/running_os.lua b/examples/running_os.lua index d214b2a9..a179e9f8 100644 --- a/examples/running_os.lua +++ b/examples/running_os.lua @@ -30,13 +30,21 @@ local du = require "lib/dtutils" du.check_min_api_version("5.0.0", "running_os") +-- translation facilities + +local gettext = dt.gettext.gettext + +local function _(msg) + return gettext(msg) +end + -- script_manager integration to allow a script to be removed -- without restarting darktable local function destroy() -- nothing to destroy end -dt.print("You are running: "..dt.configuration.running_os) +dt.print(string.format(_("You are running: %s"), dt.configuration.running_os)) -- set the destroy routine so that script_manager can call it when -- it's time to destroy the script and then return the data to From 37dba718a28b0af9feb27779ec97fc4904452884 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sat, 20 Jan 2024 15:25:16 -0500 Subject: [PATCH 264/445] updated official scripts to use darktable translation facilities --- official/copy_paste_metadata.lua | 11 ++++------- official/delete_long_tags.lua | 2 +- official/delete_unused_tags.lua | 2 +- official/enfuse.lua | 21 +++++++++------------ official/generate_image_txt.lua | 16 +++++++++++----- official/import_filter_manager.lua | 12 +++++++++--- official/import_filters.lua | 2 +- official/save_selection.lua | 12 +++++++++--- official/selection_to_pdf.lua | 26 ++++++++++++++++---------- 9 files changed, 61 insertions(+), 43 deletions(-) diff --git a/official/copy_paste_metadata.lua b/official/copy_paste_metadata.lua index ffd69c87..3afb953b 100644 --- a/official/copy_paste_metadata.lua +++ b/official/copy_paste_metadata.lua @@ -27,7 +27,7 @@ USAGE local dt = require "darktable" local du = require "lib/dtutils" -local gettext = dt.gettext +local gettext = dt.gettext.gettext du.check_min_api_version("7.0.0", "copy_paste_metadata") @@ -58,11 +58,8 @@ local publisher = "" local rights = "" local tags = {} --- Tell gettext where to find the .mo file translating messages for a particular domain -gettext.bindtextdomain("copy_paste_metadata",dt.configuration.config_dir.."/lua/locale/") - local function _(msgid) - return gettext.dgettext("copy_paste_metadata", msgid) + return gettext(msgid) end local function copy(image) @@ -147,13 +144,13 @@ dt.gui.libs.image.register_action( dt.register_event( "capmd1", "shortcut", function(event, shortcut) copy(dt.gui.action_images[1]) end, - "copy metadata" + _("copy metadata") ) dt.register_event( "capmd2", "shortcut", function(event, shortcut) paste(dt.gui.action_images) end, - "paste metadata" + _("paste metadata") ) script_data.destroy = destroy diff --git a/official/delete_long_tags.lua b/official/delete_long_tags.lua index 31ae7994..2c5d0e6e 100644 --- a/official/delete_long_tags.lua +++ b/official/delete_long_tags.lua @@ -59,7 +59,7 @@ local long_tags = {} for _,t in ipairs(dt.tags) do local len = #t.name if len > max_length then - print("deleting tag `"..t.name.."' (length: "..len..")") + dt.print_log("deleting tag `"..t.name.."' (length: "..len..")") table.insert(long_tags, t.name) end end diff --git a/official/delete_unused_tags.lua b/official/delete_unused_tags.lua index 0dfab017..e169068e 100644 --- a/official/delete_unused_tags.lua +++ b/official/delete_unused_tags.lua @@ -56,7 +56,7 @@ for _, t in ipairs(dt.tags) do end for _,name in pairs(unused_tags) do - print("deleting tag `" .. name .. "'") + dt.print_log("deleting tag `" .. name .. "'") tag = dt.tags.find(name) tag:delete() end diff --git a/official/enfuse.lua b/official/enfuse.lua index 35327cfd..fb94229e 100644 --- a/official/enfuse.lua +++ b/official/enfuse.lua @@ -39,7 +39,7 @@ local dtsys = require "lib/dtutils.system" local PS = dt.configuration.running_os == "windows" and "\\" or "/" -local gettext = dt.gettext +local gettext = dt.gettext.gettext du.check_min_api_version("7.0.0", "enfuse") @@ -52,16 +52,13 @@ script_data.destroy_method = nil -- set to hide for libs since we can't destroy script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again script_data.show = nil -- only required for libs since the destroy_method only hides them --- Tell gettext where to find the .mo file translating messages for a particular domain -gettext.bindtextdomain("enfuse",dt.configuration.config_dir..PS .. "lua" .. PS .. "locale" .. PS) - local enf = {} enf.event_registered = false enf.module_installed = false enf.lib_widgets = {} local function _(msgid) - return gettext.dgettext("enfuse", msgid) + return gettext(msgid) end local function install_module() @@ -132,7 +129,7 @@ if enfuse_installed then exposure_mu = dt.new_widget("slider") { label = "exposure mu", - tooltip = "center also known as MEAN of Gaussian weighting function (0 <= MEAN <= 1); default: 0.5", + tooltip = _("center also known as MEAN of Gaussian weighting function (0 <= MEAN <= 1); default: 0.5"), hard_min = 0, hard_max = 1, value = dt.preferences.read("enfuse", "exposure_mu", "float") @@ -141,7 +138,7 @@ if enfuse_installed then exposure_mu = dt.new_widget("slider") { label = "exposure optimum", - tooltip = "optimum exposure value, usually the maximum of the weighting function (0 <= OPTIMUM <=1); default 0.5", + tooltip = _("optimum exposure value, usually the maximum of the weighting function (0 <= OPTIMUM <=1); default 0.5"), hard_min = 0, hard_max = 1, value = dt.preferences.read("enfuse", "exposure_optimum", "float") @@ -151,7 +148,7 @@ if enfuse_installed then local depth = dt.new_widget("combobox") { label = "depth", - tooltip = "the number of bits per channel of the output image", + tooltip = _("the number of bits per channel of the output image"), value = dt.preferences.read("enfuse", "depth", "integer"), changed_callback = function(w) dt.preferences.write("enfuse", "depth", "integer", w.selected) end, "8", "16", "32" @@ -160,14 +157,14 @@ if enfuse_installed then local blend_colorspace = dt.new_widget("combobox") { label = "blend colorspace", - tooltip = "Force blending in selected colorspace", + tooltip = _("force blending in selected colorspace"), changed_callback = function(w) dt.preferences.write("enfuse", "blend_colorspace", "string", w.selected) end, "", "identity", "ciecam" } local enfuse_button = dt.new_widget("button") { - label = enfuse_installed and "run enfuse" or "enfuse not installed", + label = enfuse_installed and _("run enfuse") or _("enfuse not installed"), clicked_callback = function () -- remember exposure_mu -- TODO: find a way to save it whenever the value changes @@ -185,7 +182,7 @@ if enfuse_installed then end local f = io.open(response_file, "w") if not f then - dt.print(string.format(_("Error writing to `%s`"), response_file)) + dt.print(string.format(_("Error writing to '%s'"), response_file)) os.remove(response_file) return end @@ -251,7 +248,7 @@ if enfuse_installed then ..blend_colorspace_option .." -o \""..output_image.."\" \"@"..response_file.."\"" if dtsys.external_command( command) > 0 then - dt.print(_("Enfuse failed, see terminal output for details")) + dt.print(_("enfuse failed, see terminal output for details")) os.remove(response_file) return end diff --git a/official/generate_image_txt.lua b/official/generate_image_txt.lua index 73b50635..3eeafbe6 100644 --- a/official/generate_image_txt.lua +++ b/official/generate_image_txt.lua @@ -38,6 +38,12 @@ local dt = require "darktable" local du = require "lib/dtutils" require "darktable.debug" +local gettext = dt.gettext.gettext + +local function _(msg) + return gettext(msg) +end + du.check_min_api_version("7.0.0", "generate_image_txt") -- return data structure for script_manager @@ -52,21 +58,21 @@ script_data.show = nil -- only required for libs since the destroy_method only h dt.preferences.register("generate_image_txt", "enabled", "bool", - "create txt sidecars to display with images", - "the txt files created get shown when the lighttable is zoomed in to one image. also enable the txt overlay setting in the gui tab", + _("create txt sidecars to display with images"), + _("the txt files created get shown when the lighttable is zoomed in to one image. also enable the txt overlay setting in the gui tab"), false) dt.preferences.register("generate_image_txt", "command", "string", - "command to generate the txt sidecar", - "the output of this command gets written to the txt file. use $(FILE_NAME) for the image file", + _("command to generate the txt sidecar"), + _("the output of this command gets written to the txt file. use $(FILE_NAME) for the image file"), "exiv2 $(FILE_NAME)") local check_command = function(command) if not command:find("$(FILE_NAME)", 1, true) then - dt.print("the command for txt sidecars looks bad. better check the preferences") + dt.print(_("the command for txt sidecars looks bad. better check the preferences")) end end diff --git a/official/import_filter_manager.lua b/official/import_filter_manager.lua index c648c1a4..7a81f2cc 100644 --- a/official/import_filter_manager.lua +++ b/official/import_filter_manager.lua @@ -32,20 +32,26 @@ USAGE local dt = require "darktable" +local gettext = dt.gettext.gettext + +local function _(msg) + return gettext(msg) +end + local import_filter_list = {} local n_import_filters = 1 -- allow changing the filter from the preferences dt.preferences.register("import_filter_manager", "active_filter", "string", - "import filter", "the name of the filter used for importing images", "") + _("import filter"), _("the name of the filter used for importing images"), "") -- the dropdown to select the active filter from the import dialog local filter_dropdown = dt.new_widget("combobox") { - label = "import filter", + label = _("import filter"), editable = false, - tooltip = "import filters are applied after completion of the import dialog", + tooltip = _("import filters are applied after completion of the import dialog"), changed_callback = function(widget) dt.preferences.write("import_filter_manager", "active_filter", "string", widget.value) diff --git a/official/import_filters.lua b/official/import_filters.lua index 584a2718..807dec61 100644 --- a/official/import_filters.lua +++ b/official/import_filters.lua @@ -34,7 +34,7 @@ local dt = require "darktable" -- ignore jpeg dt.register_import_filter("ignore jpegs", function(event, images) - dt.print_error("ignoring all jpegs") + dt.print_log("ignoring all jpegs") for i, img in ipairs(images) do local extension = img:match("[^.]*$"):upper() if (extension == "JPG") or (extension == "JPEG") then diff --git a/official/save_selection.lua b/official/save_selection.lua index b06f933a..22841a92 100644 --- a/official/save_selection.lua +++ b/official/save_selection.lua @@ -38,6 +38,12 @@ local du = require "lib/dtutils" du.check_min_api_version("7.0.0", "save_selection") +local gettext = dt.gettext.gettext + +local function _(msg) + return gettext(msg) +end + -- return data structure for script_manager local script_data = {} @@ -61,16 +67,16 @@ for i = 1, buffer_count do local saved_selection dt.register_event("save_selection save " .. i, "shortcut", function() saved_selection = dt.gui.selection() - end, "save to buffer " .. i) + end, string.format(_("save to buffer %d"), i)) dt.register_event("save_selection restore " .. i, "shortcut", function() dt.gui.selection(saved_selection) - end, "restore from buffer " .. i) + end, string.format(_("restore from buffer %d"), i)) end local bounce_buffer = {} dt.register_event("save_selection switch", "shortcut", function() bounce_buffer = dt.gui.selection(bounce_buffer) -end, "switch selection with temporary buffer") +end, _("switch selection with temporary buffer")) script_data.destroy = destroy diff --git a/official/selection_to_pdf.lua b/official/selection_to_pdf.lua index 638ae24f..9e1d7b42 100644 --- a/official/selection_to_pdf.lua +++ b/official/selection_to_pdf.lua @@ -38,6 +38,12 @@ local du = require "lib/dtutils" du.check_min_api_version("7.0.0", "selection_to_pdf") +local gettext = dt.gettext.gettext + +local function _(msg) + return gettext(msg) +end + -- return data structure for script_manager local script_data = {} @@ -49,16 +55,16 @@ script_data.show = nil -- only required for libs since the destroy_method only h dt.preferences.register ("selection_to_pdf","Open with","string", - "a pdf viewer", - "Can be an absolute pathname or the tool may be in the PATH", + _("a pdf viewer"), + _("Can be an absolute pathname or the tool may be in the PATH"), "xdg-open") local title_widget = dt.new_widget("entry") { - placeholder="Title" + placeholder = _("Title") } local no_of_thumbs_widget = dt.new_widget("slider") { - label = "Thumbs per Line", + label = _("Thumbs per Line"), soft_min = 1, -- The soft minimum value for the slider, the slider can't go beyond this point soft_max = 10, -- The soft maximum value for the slider, the slider can't go beyond this point hard_min = 1, -- The hard minimum value for the slider, the user can't manually enter a value beyond this point @@ -66,10 +72,10 @@ local no_of_thumbs_widget = dt.new_widget("slider") value = 4 -- The current value of the slider } local widget = dt.new_widget("box") { - orientation=horizontal, - dt.new_widget("label"){label = "Title:"}, + orientation = horizontal, + dt.new_widget("label"){label = _("Title:")}, title_widget, - dt.new_widget("label"){label = "Thumbnails per row:"}, + dt.new_widget("label"){label = _("Thumbnails per row:")}, no_of_thumbs_widget } @@ -116,7 +122,7 @@ local function destroy() dt.print_log("done destroying") end -dt.register_storage("export_pdf","Export thumbnails to pdf", +dt.register_storage(_("export_pdf"),_("Export thumbnails to pdf"), nil, function(storage,image_table) local my_title = title_widget.text @@ -163,7 +169,7 @@ dt.register_storage("export_pdf","Export thumbnails to pdf", local command = "pdflatex -halt-on-error -output-directory "..dir.." "..locfile local result = dt.control.execute(command) if result ~= 0 then - dt.print("Problem running pdflatex") -- this one is probably usefull to the user + dt.print(_("Problem running pdflatex")) -- this one is probably usefull to the user error("Problem running "..command) end @@ -173,7 +179,7 @@ dt.register_storage("export_pdf","Export thumbnails to pdf", command = command.." "..pdffile local result = dt.control.execute(command) if result ~= 0 then - dt.print("Problem running pdf viewer") -- this one is probably usefull to the user + dt.print(_("Problem running pdf viewer")) -- this one is probably usefull to the user error("Problem running "..command) end From 66b33d6f48c496ce64fe1ef6f835d790b1b7858a Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sat, 20 Jan 2024 20:22:32 -0500 Subject: [PATCH 265/445] updated contrib scripts to use darktable translation facilities --- contrib/AutoGrouper.lua | 6 ++-- contrib/CollectHelper.lua | 7 ++-- contrib/HDRMerge.lua | 10 +++--- contrib/LabelsToTags.lua | 50 ++++++++++++++++------------- contrib/OpenInExplorer.lua | 7 ++-- contrib/RL_out_sharp.lua | 8 ++--- contrib/autostyle.lua | 24 ++++++++------ contrib/change_group_leader.lua | 7 ++-- contrib/clear_GPS.lua | 6 ++-- contrib/color_profile_manager.lua | 11 +++---- contrib/copy_attach_detach_tags.lua | 7 ++-- contrib/cr2hdr.lua | 14 +++++--- contrib/cycle_group_leader.lua | 7 ++-- contrib/enfuseAdvanced.lua | 22 ++++++------- contrib/exportLUT.lua | 8 ++--- contrib/ext_editor.lua | 24 +++++++------- contrib/face_recognition.lua | 13 +++----- contrib/fujifilm_ratings.lua | 10 +++--- contrib/geoJSON_export.lua | 7 ++-- contrib/geoToolbox.lua | 15 ++++----- contrib/gimp.lua | 9 ++---- contrib/gpx_export.lua | 9 ++---- contrib/harmonic_armature_guide.lua | 7 ++-- contrib/hif_group_leader.lua | 7 ++-- contrib/hugin.lua | 11 +++---- contrib/image_stack.lua | 19 +++++------ contrib/image_time.lua | 16 ++++----- contrib/jpg_group_leader.lua | 7 ++-- contrib/kml_export.lua | 7 ++-- contrib/passport_guide.lua | 7 ++-- contrib/pdf_slideshow.lua | 13 +++----- contrib/photils.lua | 8 ++--- contrib/quicktag.lua | 7 ++-- contrib/rate_group.lua | 24 ++++++++------ contrib/rename-tags.lua | 28 +++++++++------- contrib/rename_images.lua | 17 ++++------ contrib/select_non_existing.lua | 5 ++- contrib/select_untagged.lua | 7 ++-- contrib/slideshowMusic.lua | 11 +++---- contrib/transfer_hierarchy.lua | 12 +++---- contrib/video_ffmpeg.lua | 9 +++--- 41 files changed, 224 insertions(+), 279 deletions(-) diff --git a/contrib/AutoGrouper.lua b/contrib/AutoGrouper.lua index 79ded8cf..decc9b93 100644 --- a/contrib/AutoGrouper.lua +++ b/contrib/AutoGrouper.lua @@ -52,12 +52,10 @@ script_data.destroy_method = nil -- set to hide for libs since we can't destroy script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again script_data.show = nil -- only required for libs since the destroy_method only hides them -local gettext = dt.gettext --- Tell gettext where to find the .mo file translating messages for a particular domain -gettext.bindtextdomain("AutoGrouper",dt.configuration.config_dir.."/lua/locale/") +local gettext = dt.gettext.gettext local function _(msgid) - return gettext.dgettext("AutoGrouper", msgid) + return gettext(msgid) end local Ag = {} diff --git a/contrib/CollectHelper.lua b/contrib/CollectHelper.lua index 7f609350..9e6f12c9 100644 --- a/contrib/CollectHelper.lua +++ b/contrib/CollectHelper.lua @@ -47,13 +47,10 @@ In the "Selected Images" module click on "Collect on this Image" local dt = require "darktable" local du = require "lib/dtutils" -local gettext = dt.gettext +local gettext = dt.gettext.gettext local previous = nil local all_active = false --- Tell gettext where to find the .mo file translating messages for a particular domain -gettext.bindtextdomain("CollectHelper",dt.configuration.config_dir.."/lua/locale/") - du.check_min_api_version("7.0.0", "CollectHelper") -- return data structure for script_manager @@ -66,7 +63,7 @@ script_data.restart = nil -- how to restart the (lib) script after it's been hid script_data.show = nil -- only required for libs since the destroy_method only hides them local function _(msgid) - return gettext.dgettext("CollectHelper", msgid) + return gettext(msgid) end -- FUNCTION -- diff --git a/contrib/HDRMerge.lua b/contrib/HDRMerge.lua index 3e7e29a5..a662f215 100644 --- a/contrib/HDRMerge.lua +++ b/contrib/HDRMerge.lua @@ -67,10 +67,10 @@ if dt.configuration.running_os == 'windows' then os_path_seperator = '\\' end local CURR_API_STRING = dt.configuration.api_version_string -- Tell gettext where to find the .mo file translating messages for a particular domain -local gettext = dt.gettext -gettext.bindtextdomain('HDRMerge', dt.configuration.config_dir..'/lua/locale/') +local gettext = dt.gettext.gettext + local function _(msgid) - return gettext.dgettext('HDRMerge', msgid) + return gettext(msgid) end local temp @@ -208,7 +208,7 @@ end local function main() PreCall({HDRM}) --check if furst run then check if install OK if HDRM.install_error then - dt.print_error(_('HDRMerge install issue')) + dt.print_error('HDRMerge install issue') dt.print(_('HDRMerge install issue, please ensure the binary path is proper')) return end @@ -277,7 +277,7 @@ local function main() end dt.print(_('HDRMerge completed successfully')) else - dt.print_error(_('HDRMerge failed')) + dt.print_error('HDRMerge failed') dt.print(_('HDRMerge failed')) end diff --git a/contrib/LabelsToTags.lua b/contrib/LabelsToTags.lua index a89b05d2..83feada2 100644 --- a/contrib/LabelsToTags.lua +++ b/contrib/LabelsToTags.lua @@ -52,6 +52,12 @@ local du = require "lib/dtutils" du.check_min_api_version("7.0.0", "LabelsToTags") +local gettext = dt.gettext.gettext + +local function _(msgid) + return gettext(msgid) +end + -- return data structure for script_manager local script_data = {} @@ -68,7 +74,7 @@ local ltt = {} ltt.module_installed = false ltt.event_registered = false -local LIB_ID = "LabelsToTags" +local LIB_ID = _("LabelsToTags") -- Helper functions: BEGIN @@ -109,23 +115,23 @@ end local initialAvailableMappings = { - ["Colors"] = { ["+*****"] = { "Red" }, - ["*+****"] = { "Yellow" }, - ["**+***"] = { "Green" }, - ["***+**"] = { "Blue" }, - ["****+*"] = { "Purple" } }, - ["Single colors"] = { ["+----*"] = { "Red", "Only red" }, - ["-+---*"] = { "Yellow", "Only yellow" }, - ["--+--*"] = { "Green", "Only green" }, - ["---+-*"] = { "Blue", "Only blue" }, - ["----+*"] = { "Purple", "Only purple" } }, - ["Ratings"] = { ["*****0"] = { "No stars", "Not rejected" }, - ["*****1"] = { "One star", "Not rejected" }, - ["*****2"] = { "Two stars", "Not rejected" }, - ["*****3"] = { "Three stars", "Not rejected" }, - ["*****4"] = { "Four stars", "Not rejected" }, - ["*****5"] = { "Five stars", "Not rejected" }, - ["*****R"] = { "Rejected" } } + [_("Colors")] = { ["+*****"] = { _("Red") }, + ["*+****"] = { _("Yellow") }, + ["**+***"] = { _("Green") }, + ["***+**"] = { _("Blue") }, + ["****+*"] = { _("Purple") } }, + [_("Single colors")] = { ["+----*"] = { _("Red"), _("Only red") }, + ["-+---*"] = { _("Yellow"), _("Only yellow") }, + ["--+--*"] = { _("Green"), _("Only green") }, + ["---+-*"] = { _("Blue"), _("Only blue") }, + ["----+*"] = { _("Purple"), _("Only purple") } }, + [_("Ratings")] = { ["*****0"] = { _("No stars"), _("Not rejected") }, + ["*****1"] = { _("One star"), _("Not rejected") }, + ["*****2"] = { _("Two stars"), _("Not rejected") }, + ["*****3"] = { _("Three stars"), _("Not rejected") }, + ["*****4"] = { _("Four stars"), _("Not rejected") }, + ["*****5"] = { _("Five stars"), _("Not rejected") }, + ["*****R"] = { _("Rejected") } } } local availableMappings = {} @@ -140,14 +146,14 @@ end local function getComboboxTooltip() if availableMappings == nil or next(availableMappings) == nil then - return("No registered mappings -- using defaults") + return(_("No registered mappings -- using defaults")) else - return("Select a label-to-tag mapping") + return(_("Select a label-to-tag mapping")) end end local mappingComboBox = darktable.new_widget("combobox"){ - label = "mapping", + label = _("mapping"), value = 1, tooltip = getComboboxTooltip(), reset_callback = function(selfC) @@ -170,7 +176,7 @@ local mappingComboBox = darktable.new_widget("combobox"){ } local function doTagging(selfC) - local job = darktable.gui.create_job(string.format("labels to tags (%d image" .. (#(darktable.gui.action_images) == 1 and "" or "s") .. ")",#(darktable.gui.action_images)),true) + local job = darktable.gui.create_job(string.format(_("labels to tags (%d image%s)"), #(darktable.gui.action_images), (#(darktable.gui.action_images) == 1 and "" or "s")), true) job.percent = 0.0 local pctIncrement = 1.0 / #(darktable.gui.action_images) diff --git a/contrib/OpenInExplorer.lua b/contrib/OpenInExplorer.lua index 9a8cd650..443a09ad 100644 --- a/contrib/OpenInExplorer.lua +++ b/contrib/OpenInExplorer.lua @@ -51,7 +51,7 @@ local dt = require "darktable" local du = require "lib/dtutils" local df = require "lib/dtutils.file" local dsys = require "lib/dtutils.system" -local gettext = dt.gettext +local gettext = dt.gettext.gettext --Check API version du.check_min_api_version("7.0.0", "OpenInExplorer") @@ -65,11 +65,8 @@ script_data.destroy_method = nil -- set to hide for libs since we can't destroy script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again script_data.show = nil -- only required for libs since the destroy_method only hides them --- Tell gettext where to find the .mo file translating messages for a particular domain -gettext.bindtextdomain("OpenInExplorer",dt.configuration.config_dir.."/lua/locale/") - local function _(msgid) - return gettext.dgettext("OpenInExplorer", msgid) + return gettext(msgid) end local act_os = dt.configuration.running_os diff --git a/contrib/RL_out_sharp.lua b/contrib/RL_out_sharp.lua index 2c854e48..44d961eb 100644 --- a/contrib/RL_out_sharp.lua +++ b/contrib/RL_out_sharp.lua @@ -78,10 +78,10 @@ script_data.show = nil -- only required for libs since the destroy_method only h local PS = dt.configuration.running_os == "windows" and "\\" or "/" -- translation -local gettext = dt.gettext -gettext.bindtextdomain(MODULE_NAME, dt.configuration.config_dir..PS.."lua"..PS.."locale"..PS) +local gettext = dt.gettext.gettext + local function _(msgid) - return gettext.dgettext(MODULE_NAME, msgid) + return gettext(msgid) end -- initialize module preferences @@ -137,7 +137,7 @@ local function export2RL(storage, image_table, extra_data) for image, temp_name in pairs(image_table) do i = i + 1 - dt.print(_("sharpening image ")..i.." ...") + dt.print(string.format(_("sharpening image %d ..."), i)) -- create unique filename new_name = output_folder..PS..df.get_basename(temp_name)..".jpg" new_name = df.create_unique_filename(new_name) diff --git a/contrib/autostyle.lua b/contrib/autostyle.lua index 53fc0ab5..cf3ebe7c 100644 --- a/contrib/autostyle.lua +++ b/contrib/autostyle.lua @@ -42,6 +42,12 @@ local filelib = require "lib/dtutils.file" du.check_min_api_version("7.0.0", "autostyle") +local gettext = darktable.gettext.gettext + +local function _(msgid) + return gettext(msgid) +end + -- return data structure for script_manager local script_data = {} @@ -92,19 +98,19 @@ local function autostyle_apply_one_image (image) -- check they all exist (correct syntax) if (not tag) then - darktable.print("EXIF TAG not found in " .. pref) + darktable.print(string.format(_("EXIF TAG not found in %s"), pref)) return 0 end if (not value) then - darktable.print("value to match not found in " .. pref) + darktable.print(string.format(_("value to match not found in %s"), pref)) return 0 end if (not style_name) then - darktable.print("style name not found in " .. pref) + darktable.print(string.format(_("style name not found in %s"), pref)) return 0 end if not filelib.check_if_bin_exists("exiftool") then - darktable.print("Can't find exiftool") + darktable.print(_("Can't find exiftool")) return 0 end @@ -118,7 +124,7 @@ local function autostyle_apply_one_image (image) end end if (not style) then - darktable.print("style not found for autostyle: " .. style_name) + darktable.print(string.format(_("style not found for autostyle: %s"), style_name)) return 0 end @@ -127,7 +133,7 @@ local function autostyle_apply_one_image (image) --darktable.print_error("dr_attr:" .. auto_dr_attr) -- If the lookup fails, stop here if (not ok) then - darktable.print("Couldn't get attribute " .. auto_dr_attr .. " from exiftool's output") + darktable.print(string.format(_("Couldn't get attribute %s from exiftool's output"), auto_dr_attr)) return 0 end if auto_dr_attr == value then @@ -154,7 +160,7 @@ local function autostyle_apply(shortcut) images_submitted = images_submitted + 1 images_processed = images_processed + autostyle_apply_one_image(image) end - darktable.print("Applied auto style to " .. images_processed .. " out of " .. images_submitted .. " image(s)") + darktable.print(string.format(_("Applied auto style to %d out of %d image(s)"), images_processed, images_submitted)) end local function destroy() @@ -164,9 +170,9 @@ end -- Registering events darktable.register_event("autostyle", "shortcut", autostyle_apply, - "Apply your chosen style from exiftool tags") + _("Apply your chosen style from exiftool tags")) -darktable.preferences.register("autostyle", "exif_tag", "string", "Autostyle: EXIF_tag=value=>style", "apply a style automatically if an EXIF_tag matches value. Find the tag with exiftool", "") +darktable.preferences.register("autostyle", "exif_tag", "string", "Autostyle: EXIF_tag=value=>style", _("apply a style automatically if an EXIF_tag matches value. Find the tag with exiftool"), "") darktable.register_event("autostyle", "post-import-image", autostyle_apply_one_image_event) diff --git a/contrib/change_group_leader.lua b/contrib/change_group_leader.lua index c7fe5c0f..786c91e9 100644 --- a/contrib/change_group_leader.lua +++ b/contrib/change_group_leader.lua @@ -36,7 +36,7 @@ USAGE local dt = require "darktable" local du = require "lib/dtutils" -local gettext = dt.gettext +local gettext = dt.gettext.gettext local MODULE = "change_group_leader" @@ -51,11 +51,8 @@ script_data.destroy_method = nil -- set to hide for libs since we can't destroy script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again script_data.show = nil -- only required for libs since the destroy_method only hides them --- Tell gettext where to find the .mo file translating messages for a particular domain -gettext.bindtextdomain(MODULE, dt.configuration.config_dir.."/lua/locale/") - local function _(msgid) - return gettext.dgettext(MODULE, msgid) + return gettext(msgid) end -- create a namespace to contain persistent data and widgets diff --git a/contrib/clear_GPS.lua b/contrib/clear_GPS.lua index da4668c1..9f21b1e5 100644 --- a/contrib/clear_GPS.lua +++ b/contrib/clear_GPS.lua @@ -48,18 +48,16 @@ script_data.destroy_method = nil -- set to hide for libs since we can't destroy script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again script_data.show = nil -- only required for libs since the destroy_method only hides them -local gettext = dt.gettext +local gettext = dt.gettext.gettext -- not a number local NaN = 0/0 du.check_min_api_version("7.0.0", "clear_GPS") --- Tell gettext where to find the .mo file translating messages for a particular domain -gettext.bindtextdomain("clear_GPS",dt.configuration.config_dir.."/lua/locale/") local function _(msgid) - return gettext.dgettext("clear_GPS", msgid) + return gettext(msgid) end local function clear_GPS(images) diff --git a/contrib/color_profile_manager.lua b/contrib/color_profile_manager.lua index bd097558..b8ef21f2 100644 --- a/contrib/color_profile_manager.lua +++ b/contrib/color_profile_manager.lua @@ -52,13 +52,10 @@ du.check_min_api_version("7.0.0", "color_profile_manager") -- L O C A L I Z A T I O N -- - - - - - - - - - - - - - - - - - - - - - - - -local gettext = dt.gettext - --- Tell gettext where to find the .mo file translating messages for a particular domain -gettext.bindtextdomain("color_profile_manager", dt.configuration.config_dir .. "/lua/locale/") +local gettext = dt.gettext.gettext local function _(msgid) - return gettext.dgettext("color_profile_manager", msgid) + return gettext(msgid) end -- - - - - - - - - - - - - - - - - - - - - - - - @@ -119,13 +116,13 @@ end local function add_profile(file, dir) df.file_copy(file, dir) - dt.print(_("added color profile " .. file .. " to " .. dir)) + dt.print(string.format(_("added color profile %s to %s"), file, dir)) dt.print_log("color profile " .. file .. " added to " .. dir) end local function remove_profile(file, dir) os.remove(dir .. PS .. file) - dt.print(_("removed color profile " .. file .. " from " .. dir)) + dt.print(string.format(_("removed color profile %s from %s"), file, dir)) dt.print_log("color profile " .. file .. " removed from " .. dir) end diff --git a/contrib/copy_attach_detach_tags.lua b/contrib/copy_attach_detach_tags.lua index 05f6f1f4..1de8db29 100644 --- a/contrib/copy_attach_detach_tags.lua +++ b/contrib/copy_attach_detach_tags.lua @@ -40,7 +40,7 @@ local dt = require "darktable" local du = require "lib/dtutils" local debug = require "darktable.debug" -local gettext = dt.gettext +local gettext = dt.gettext.gettext du.check_min_api_version("7.0.0", "copy_attach_detach_tags") @@ -53,11 +53,8 @@ script_data.destroy_method = nil -- set to hide for libs since we can't destroy script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again script_data.show = nil -- only required for libs since the destroy_method only hides them --- Tell gettext where to find the .mo file translating messages for a particular domain -gettext.bindtextdomain("copy_attach_detach_tags",dt.configuration.config_dir.."/lua/locale/") - local function _(msgid) - return gettext.dgettext("copy_attach_detach_tags", msgid) + return gettext(msgid) end local cadt = {} diff --git a/contrib/cr2hdr.lua b/contrib/cr2hdr.lua index f4a40c9d..53b1e147 100644 --- a/contrib/cr2hdr.lua +++ b/contrib/cr2hdr.lua @@ -37,6 +37,12 @@ local du = require "lib/dtutils" du.check_min_api_version("7.0.0", "cr2hdr") +local gettext = dt.gettext.gettext + +local function _(msgid) + return gettext(msgid) +end + -- return data structure for script_manager local script_data = {} @@ -87,7 +93,7 @@ end local function convert_images() if next(queue) == nil then return end - job = darktable.gui.create_job("Dual ISO conversion", true, stop_conversion) + job = darktable.gui.create_job(_("Dual ISO conversion"), true, stop_conversion) for key,image in pairs(queue) do if job.valid then job.percent = (key-1)/#queue @@ -98,7 +104,7 @@ local function convert_images() end local success_count = 0 for _ in pairs(processed_files) do success_count = success_count + 1 end - darktable.print("Dual ISO conversion successful on " .. success_count .. "/" .. #queue .. " images.") + darktable.print(string.format(_("Dual ISO conversion successful on %d/%d images."), success_count, #queue)) job.valid = false processed_files = {} queue = {} @@ -122,13 +128,13 @@ local function destroy() end darktable.register_event("cr2hdr", "shortcut", - convert_action_images, "Run cr2hdr (Magic Lantern DualISO converter) on selected images") + convert_action_images, _("Run cr2hdr (Magic Lantern DualISO converter) on selected images")) darktable.register_event("cr2hdr", "post-import-image", file_imported) darktable.register_event("cr2hdr", "post-import-film", film_imported) -darktable.preferences.register("cr2hdr", "onimport", "bool", "Invoke on import", "If true then cr2hdr will try to proccess every file during importing. Warning: cr2hdr is quite slow even in figuring out on whether the file is Dual ISO or not.", false) +darktable.preferences.register("cr2hdr", "onimport", "bool", _("Invoke on import"), _("If true then cr2hdr will try to proccess every file during importing. Warning: cr2hdr is quite slow even in figuring out on whether the file is Dual ISO or not."), false) script_data.destroy = destroy diff --git a/contrib/cycle_group_leader.lua b/contrib/cycle_group_leader.lua index e4bdd11f..dde85461 100644 --- a/contrib/cycle_group_leader.lua +++ b/contrib/cycle_group_leader.lua @@ -69,13 +69,10 @@ script_data.show = nil -- only required for libs since the destroy_method only h -- I 1 8 N -- - - - - - - - - - - - - - - - - - - - - - - - - - -local gettext = dt.gettext - --- Tell gettext where to find the .mo file translating messages for a particular domain -gettext.bindtextdomain(MODULE, dt.configuration.config_dir .. "/lua/locale/") +local gettext = dt.gettext.gettext local function _(msgid) - return gettext.dgettext(MODULE, msgid) + return gettext(msgid) end -- - - - - - - - - - - - - - - - - - - - - - - - diff --git a/contrib/enfuseAdvanced.lua b/contrib/enfuseAdvanced.lua index 76ffd01e..f8aeb9be 100644 --- a/contrib/enfuseAdvanced.lua +++ b/contrib/enfuseAdvanced.lua @@ -77,10 +77,10 @@ script_data.restart = nil -- how to restart the (lib) script after it's been hid script_data.show = nil -- only required for libs since the destroy_method only hides them -- Tell gettext where to find the .mo file translating messages for a particular domain -local gettext = dt.gettext -gettext.bindtextdomain('enfuseAdvanced',dt.configuration.config_dir..'/lua/locale/') +local gettext = dt.gettext.gettext + local function _(msgid) - return gettext.dgettext('enfuseAdvanced', msgid) + return gettext(msgid) end -- INITS -- @@ -260,7 +260,7 @@ local function ExeUpdate(prog_tbl) --updates executable paths and verifies them if not prog.bin then prog.install_error = true dt.preferences.write(mod, 'bin_exists', 'bool', false) - dt.print(_('issue with ')..prog.name.._(' executable')) + dt.print(string.format(_("issue with %s executable"), prog.name)) else prog.bin = CleanSpaces(prog.bin) end @@ -377,7 +377,7 @@ local function SaveToPreference(preset) --save the present values of enfuse GUI dt.preferences.write(mod, preset..argument, arg_data.style, temp) end end - dt.print(_('saved to ')..preset) + dt.print(string.format(_("saved to %s"), preset)) end local function LoadFromPreference(preset) --load values from the specified 'preset' into the GUI elements @@ -393,7 +393,7 @@ local function LoadFromPreference(preset) --load values from the specified 'pres dt.preferences.write(mod, 'active_'..argument, arg_data.style, temp) end end - dt.print(_('loaded from ')..preset) + dt.print(string.format(_("loaded from %s"), preset)) end local function remove_temp_files(images_to_remove) --deletes all files specified by the input string @@ -428,7 +428,7 @@ local function support_format(storage, format) --tells dt we only support TIFF e end local function show_status(storage, image, format, filename, number, total, high_quality, extra_data) --outputs message to user showing script export status - dt.print(_('export for image fusion ')..tostring(math.floor(number))..' / '..tostring(math.floor(total))) + dt.print(string.format(_("export for image fusion %d / %d"), math.floor(number), math.floor(total))) end local function main(storage, image_table, extra_data) @@ -456,8 +456,8 @@ local function main(storage, image_table, extra_data) job.valid = false if resp ~= 0 then remove_temp_files(images_to_remove) - dt.print_error(AIS.name.._(' failed')) - dt.print(AIS.name.._(' failed')) + dt.print(string.format(_("%s failed"), AIS.name)) + dt.print_error(AIS.name .. ' failed') return end end @@ -483,8 +483,8 @@ local function main(storage, image_table, extra_data) local resp = dsys.external_command(run_cmd) if resp ~= 0 then remove_temp_files(images_to_remove) - dt.print_error(ENF.name.._(' failed')) - dt.print(ENF.name.._(' failed')) + dt.print_error(ENF.name..' failed') + dt.print(string.format(_("%s failed"), ENF.name)) return end diff --git a/contrib/exportLUT.lua b/contrib/exportLUT.lua index fe11960e..6a22f837 100644 --- a/contrib/exportLUT.lua +++ b/contrib/exportLUT.lua @@ -42,12 +42,10 @@ script_data.destroy_method = nil -- set to hide for libs since we can't destroy script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again script_data.show = nil -- only required for libs since the destroy_method only hides them -local gettext = dt.gettext - -gettext.bindtextdomain("exportLUT",dt.configuration.config_dir.."/lua/locale/") +local gettext = dt.gettext.gettext local function _(msgid) - return gettext.dgettext("exportLUT", msgid) + return gettext(msgid) end du.check_min_api_version("5.0.0", "exportLUT") @@ -127,7 +125,7 @@ local function export_luts() io_lut:write_image(identity, output_path(style.name, job)) count = count + 1 job.percent = count / size - dt.print(_("Exported: ") .. output_path(style.name, job)) + dt.print(string.format(_("Exported: %s"), output_path(style.name, job))) end dt.print(_("Done exporting haldCLUTs")) job.valid = false diff --git a/contrib/ext_editor.lua b/contrib/ext_editor.lua index 827d5270..b28a7f95 100644 --- a/contrib/ext_editor.lua +++ b/contrib/ext_editor.lua @@ -95,10 +95,10 @@ ee.widgets = {} -- translation -local gettext = dt.gettext -gettext.bindtextdomain(MODULE_NAME, dt.configuration.config_dir..PS.."lua"..PS.."locale"..PS) +local gettext = dt.gettext.gettext + local function _(msgid) - return gettext.dgettext(MODULE_NAME, msgid) + return gettext(msgid) end -- maximum number of external programs, can be increased to necessity @@ -156,7 +156,7 @@ local function UpdateProgramList(combobox, button_edit, button_edit_copy, update button_edit.sensitive = active button_edit_copy.sensitive = active - if update_button_pressed then dt.print(n_entries.._(" editors configured")) end + if update_button_pressed then dt.print(string.format(_("%d editors configured"), n_entries)) end end @@ -223,17 +223,17 @@ local function OpenWith(images, choice, copy) -- physical copy, check result, return if error local copy_success = df.file_copy(name, new_name) if not copy_success then - dt.print(_("error copying file ")..name) + dt.print(string.format(_("error copying file %s"), name)) return end end -- launch the external editor, check result, return if error local run_cmd = bin.." "..df.sanitize_filename(new_name) - dt.print(_("launching ")..friendly_name.."...") + dt.print(string.format(_("launching %s..."), friendly_name)) local result = dtsys.external_command(run_cmd) if result ~= 0 then - dt.print(_("error launching ")..friendly_name) + dt.print(string.format(_("error launching %s"), friendly_name)) return end @@ -326,7 +326,7 @@ local function export2collection(storage, image_table, extra_data) -- move image to collection folder, check result, return if error move_success = df.file_move(temp_name, new_name) if not move_success then - dt.print(_("error moving file ")..temp_name) + dt.print(string.format(_("error moving file %s"), temp_name)) return end @@ -378,7 +378,7 @@ end local function restart() for i = 1, MAX_EDITORS do dt.register_event(MODULE_NAME .. i, "shortcut", - program_shortcut, _("edit with program ")..string.format("%02d", i)) + program_shortcut, string.format(_("edit with program %02d"), i)) end dt.register_storage("exp2coll", _("collection"), nil, export2collection) dt.gui.libs[MODULE_NAME].visible = true @@ -476,11 +476,11 @@ dt.register_storage("exp2coll", _("collection"), nil, export2collection) -- register the new preferences ----------------------------------------------- for i = MAX_EDITORS, 1, -1 do dt.preferences.register(MODULE_NAME, "program_path_"..i, "file", - _("executable for external editor ")..i, + string.format(_("executable for external editor %d"), i), _("select executable for external editor") , _("(None)")) dt.preferences.register(MODULE_NAME, "program_name_"..i, "string", - _("name of external editor ")..i, + string.format(_("name of external editor %d"), i), _("friendly name of external editor"), "") end dt.preferences.register(MODULE_NAME, "show_in_darkrooom", "bool", @@ -491,7 +491,7 @@ dt.preferences.register(MODULE_NAME, "show_in_darkrooom", "bool", -- register the new shortcuts ------------------------------------------------- for i = 1, MAX_EDITORS do dt.register_event(MODULE_NAME .. i, "shortcut", - program_shortcut, _("edit with program ")..string.format("%02d", i)) + program_shortcut, string.format(_("edit with program %02d"), i)) end diff --git a/contrib/face_recognition.lua b/contrib/face_recognition.lua index 5bd7048e..7325d7e9 100644 --- a/contrib/face_recognition.lua +++ b/contrib/face_recognition.lua @@ -44,7 +44,7 @@ local dt = require "darktable" local du = require "lib/dtutils" local df = require "lib/dtutils.file" local dtsys = require "lib/dtutils.system" -local gettext = dt.gettext +local gettext = dt.gettext.gettext -- constants @@ -69,11 +69,8 @@ local fc = {} fc.module_installed = false fc.event_registered = false --- Tell gettext where to find the .mo file translating messages for a particular domain -gettext.bindtextdomain("face_recognition", dt.configuration.config_dir.."/lua/locale/") - local function _(msgid) - return gettext.dgettext("face_recognition", msgid) + return gettext(msgid) end local function build_image_table(images) @@ -399,7 +396,7 @@ fc.category_tags = dt.new_widget("entry"){ fc.tolerance = dt.new_widget("slider"){ label = _("tolerance"), - tooltip = ("detection tolerance - 0.6 default - lower if too many faces detected"), + tooltip = _("detection tolerance - 0.6 default - lower if too many faces detected"), soft_min = 0.0, hard_min = 0.0, soft_max = 1.0, @@ -482,12 +479,12 @@ table.insert(widgets, fc.num_cores) table.insert(widgets, fc.export_format) table.insert(widgets, dt.new_widget("box"){ orientation = "horizontal", - dt.new_widget("label"){ label = _("width ")}, + dt.new_widget("label"){ label = _("width")}, fc.width, }) table.insert(widgets, dt.new_widget("box"){ orientation = "horizontal", - dt.new_widget("label"){ label = _("height ")}, + dt.new_widget("label"){ label = _("height")}, fc.height, }) table.insert(widgets, fc.execute) diff --git a/contrib/fujifilm_ratings.lua b/contrib/fujifilm_ratings.lua index c6b8738c..c64fffaa 100644 --- a/contrib/fujifilm_ratings.lua +++ b/contrib/fujifilm_ratings.lua @@ -26,7 +26,7 @@ Dependencies: local dt = require "darktable" local du = require "lib/dtutils" local df = require "lib/dtutils.file" -local gettext = dt.gettext +local gettext = dt.gettext.gettext du.check_min_api_version("7.0.0", "fujifilm_ratings") @@ -39,10 +39,8 @@ script_data.destroy_method = nil -- set to hide for libs since we can't destroy script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again script_data.show = nil -- only required for libs since the destroy_method only hides them -gettext.bindtextdomain("fujifilm_ratings", dt.configuration.config_dir.."/lua/locale/") - local function _(msgid) - return gettext.dgettext("fujifilm_ratings", msgid) + return gettext(msgid) end local function detect_rating(event, image) @@ -60,7 +58,7 @@ local function detect_rating(event, image) if string.len(jpeg_result) > 0 then jpeg_result = string.gsub(jpeg_result, "^Rating.*(%d)", "%1") image.rating = tonumber(jpeg_result) - dt.print_error(_("Using JPEG Rating: ") .. tostring(jpeg_result)) + dt.print_error(string.format(_("Using JPEG Rating: %d"), jpeg_result)) return end command = "exiftool -Rating " .. RAF_filename @@ -71,7 +69,7 @@ local function detect_rating(event, image) if string.len(raf_result) > 0 then raf_result = string.gsub(raf_result, "^Rating.*(%d)", "%1") image.rating = tonumber(raf_result) - dt.print_error(_("Using RAF Rating: ") .. tostring(raf_result)) + dt.print_error(string.format(_("Using RAF Rating: %d"), raf_result)) end end diff --git a/contrib/geoJSON_export.lua b/contrib/geoJSON_export.lua index cd748fee..dac5f5f4 100644 --- a/contrib/geoJSON_export.lua +++ b/contrib/geoJSON_export.lua @@ -35,7 +35,7 @@ USAGE local dt = require "darktable" local du = require "lib/dtutils" local df = require "lib/dtutils.file" -local gettext = dt.gettext +local gettext = dt.gettext.gettext du.check_min_api_version("7.0.0", "geoJSON_export") @@ -48,11 +48,8 @@ script_data.destroy_method = nil -- set to hide for libs since we can't destroy script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again script_data.show = nil -- only required for libs since the destroy_method only hides them --- Tell gettext where to find the .mo file translating messages for a particular domain -gettext.bindtextdomain("geoJSON_export",dt.configuration.config_dir.."/lua/locale/") - local function _(msgid) - return gettext.dgettext("geoJSON_export", msgid) + return gettext(msgid) end -- Sort a table diff --git a/contrib/geoToolbox.lua b/contrib/geoToolbox.lua index 30f90406..b595015f 100644 --- a/contrib/geoToolbox.lua +++ b/contrib/geoToolbox.lua @@ -28,7 +28,7 @@ require "geoToolbox" local dt = require "darktable" local du = require "lib/dtutils" local df = require "lib/dtutils.file" -local gettext = dt.gettext +local gettext = dt.gettext.gettext du.check_min_api_version("7.0.0", "geoToolbox") @@ -41,11 +41,8 @@ script_data.destroy_method = nil -- set to hide for libs since we can't destroy script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again script_data.show = nil -- only required for libs since the destroy_method only hides them --- Tell gettext where to find the .mo file translating messages for a particular domain -gettext.bindtextdomain("geoToolbox",dt.configuration.config_dir.."/lua/locale/") - local function _(msgid) - return gettext.dgettext("geoToolbox", msgid) + return gettext(msgid) end @@ -300,9 +297,9 @@ local function copy_gps() end end - label_copy_gps_lat.label = _("latitude: ") .. copy_gps_latitude - label_copy_gps_lon.label = _("longitude: ") ..copy_gps_longitude - label_copy_gps_ele.label = _("elevation: ") .. copy_gps_elevation + label_copy_gps_lat.label = string.format(_("latitude: "), copy_gps_latitude) + label_copy_gps_lon.label = string.format(_("longitude: "),copy_gps_longitude) + label_copy_gps_ele.label = string.format(_("elevation: "), copy_gps_elevation) return end @@ -582,7 +579,7 @@ local function altitude_profile() file = io.open(exportDirectory.."/"..exportFilename, "w") file:write(csv_file) file:close() - dt.print(_("File created in ")..exportDirectory) + dt.print(string.format(_("File created in %s"), exportDirectory)) end diff --git a/contrib/gimp.lua b/contrib/gimp.lua index 0b235f92..843bbcea 100644 --- a/contrib/gimp.lua +++ b/contrib/gimp.lua @@ -69,7 +69,7 @@ local dt = require "darktable" local du = require "lib/dtutils" local df = require "lib/dtutils.file" local dtsys = require "lib/dtutils.system" -local gettext = dt.gettext +local gettext = dt.gettext.gettext local gimp_widget = nil du.check_min_api_version("7.0.0", "gimp") @@ -83,11 +83,8 @@ script_data.destroy_method = nil -- set to hide for libs since we can't destroy script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again script_data.show = nil -- only required for libs since the destroy_method only hides them --- Tell gettext where to find the .mo file translating messages for a particular domain -gettext.bindtextdomain("gimp",dt.configuration.config_dir.."/lua/locale/") - local function _(msgid) - return gettext.dgettext("gimp", msgid) + return gettext(msgid) end local function group_if_not_member(img, new_img) @@ -119,7 +116,7 @@ local function gimp_edit(storage, image_table, extra_data) --finalize local gimp_executable = df.check_if_bin_exists("gimp") if not gimp_executable then - dt.print_error(_("GIMP not found")) + dt.print_error("GIMP not found") return end diff --git a/contrib/gpx_export.lua b/contrib/gpx_export.lua index c25028e2..6e29c8ee 100644 --- a/contrib/gpx_export.lua +++ b/contrib/gpx_export.lua @@ -25,7 +25,7 @@ For each source folder, a separate is generated in the gpx file. local dt = require "darktable" local df = require "lib/dtutils.file" local dl = require "lib/dtutils" -local gettext = dt.gettext +local gettext = dt.gettext.gettext dl.check_min_api_version("7.0.0", "gpx_export") @@ -38,9 +38,6 @@ script_data.destroy_method = nil -- set to hide for libs since we can't destroy script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again script_data.show = nil -- only required for libs since the destroy_method only hides them --- Tell gettext where to find the .mo file translating messages for a particular domain -gettext.bindtextdomain("gpx_export",dt.configuration.config_dir.."/lua/locale/") - local function _(msgid) return gettext.dgettext("gpx_export", msgid) end @@ -132,11 +129,11 @@ local function create_gpx_file() local file = io.open(path, "w") if (file == nil) then - dt.print(_("invalid path: ")..path) + dt.print(string.format(_("invalid path: %s"), path)) else file:write(gpx_file) file:close() - dt.print(_("gpx file created: ")..path) + dt.print(string.format(_("gpx file created: "), path)) end end diff --git a/contrib/harmonic_armature_guide.lua b/contrib/harmonic_armature_guide.lua index e5c23f27..308c5efb 100644 --- a/contrib/harmonic_armature_guide.lua +++ b/contrib/harmonic_armature_guide.lua @@ -32,15 +32,12 @@ USAGE local dt = require "darktable" local du = require "lib/dtutils" -local gettext = dt.gettext +local gettext = dt.gettext.gettext du.check_min_api_version("2.0.0", "harmonic_armature_guide") --- Tell gettext where to find the .mo file translating messages for a particular domain -gettext.bindtextdomain("harmonic_armature_guide",dt.configuration.config_dir.."/lua/locale/") - local function _(msgid) - return gettext.dgettext("harmonic_armature_guide", msgid) + return gettext(msgid) end dt.guides.register_guide("harmonic armature", diff --git a/contrib/hif_group_leader.lua b/contrib/hif_group_leader.lua index 5fa0aa5f..14327db0 100644 --- a/contrib/hif_group_leader.lua +++ b/contrib/hif_group_leader.lua @@ -73,13 +73,10 @@ script_data.show = nil -- only required for libs since the destroy_method only h -- I 1 8 N -- - - - - - - - - - - - - - - - - - - - - - - - - - -local gettext = dt.gettext - --- Tell gettext where to find the .mo file translating messages for a particular domain -gettext.bindtextdomain(MODULE, dt.configuration.config_dir .. "/lua/locale/") +local gettext = dt.gettext.gettext local function _(msgid) - return gettext.dgettext(MODULE, msgid) + return gettext(msgid) end diff --git a/contrib/hugin.lua b/contrib/hugin.lua index 77ad7cb8..6621a184 100644 --- a/contrib/hugin.lua +++ b/contrib/hugin.lua @@ -40,7 +40,7 @@ local du = require "lib/dtutils" local df = require "lib/dtutils.file" local log = require "lib/dtutils.log" local dtsys = require "lib/dtutils.system" -local gettext = dt.gettext +local gettext = dt.gettext.gettext local namespace = 'module_hugin' local user_pref_str = 'prefer_gui' @@ -65,11 +65,8 @@ script_data.destroy_method = nil -- set to hide for libs since we can't destroy script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again script_data.show = nil -- only required for libs since the destroy_method only hides them --- Tell gettext where to find the .mo file translating messages for a particular domain -gettext.bindtextdomain("hugin",dt.configuration.config_dir.."/lua/locale/") - local function _(msgid) - return gettext.dgettext("hugin", msgid) + return gettext(msgid) end local function user_preference_changed(widget) @@ -201,7 +198,7 @@ local function create_panorama(storage, image_table, extra_data) --finalize if df.check_if_file_exists(src_path) then log.msg(log.debug, "found ", src_path, " importing to ", dst_path) df.file_move(src_path, dst_path) - dt.print(_("importing file "..dst_path)) + dt.print(string.format(_("importing file %s"), dst_path)) dt.database.import(dst_path) end end @@ -227,7 +224,7 @@ hugin_widget = dt.new_widget("box") { orientation = "vertical", dt.new_widget("check_button") { - label = _(" launch hugin gui"), + label = _("launch hugin gui"), value = user_prefer_gui, tooltip = _('launch hugin in gui mode'), clicked_callback = user_preference_changed diff --git a/contrib/image_stack.lua b/contrib/image_stack.lua index b78b96c5..d8abc9a9 100644 --- a/contrib/image_stack.lua +++ b/contrib/image_stack.lua @@ -64,7 +64,7 @@ local dt = require "darktable" local du = require "lib/dtutils" local df = require "lib/dtutils.file" local dtsys = require "lib/dtutils.system" -local gettext = dt.gettext +local gettext = dt.gettext.gettext local job = nil -- path separator constant @@ -82,11 +82,8 @@ script_data.destroy_method = nil -- set to hide for libs since we can't destroy script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again script_data.show = nil -- only required for libs since the destroy_method only hides them --- Tell gettext where to find the .mo file translating messages for a particular domain -gettext.bindtextdomain("image_stack",dt.configuration.config_dir.."/lua/locale/") - local function _(msgid) - return gettext.dgettext("image_stack", msgid) + return gettext(msgid) end -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -452,7 +449,7 @@ local function copy_image_attributes(from, to, ...) to.rights = from.rights to.description = from.description else - dt.print_error(_("Unrecognized option to copy_image_attributes: " .. arg)) + dt.print_error("Unrecognized option to copy_image_attributes: " .. arg) end end end @@ -496,7 +493,7 @@ local function image_stack(storage, image_table, extra_data) if image_count < 2 then dt.print(_("ERROR: at least 2 images required for image stacking, exiting...")) - dt.print_error(_(image_count .. " image(s) selected, at least 2 required")) + dt.print_error(image_count .. " image(s) selected, at least 2 required") return end @@ -520,13 +517,13 @@ local function image_stack(storage, image_table, extra_data) job.percent = job.percent + percent_step else dt.print(_("ERROR: image alignment failed")) - dt.print_error(_("image alignment failed")) + dt.print_error("image alignment failed") cleanup(img_list) return end else dt.print(_("ERROR: align_image_stack not found")) - dt.print_error(_("align_image_stack not found")) + dt.print_error("align_image_stack not found") cleanup(img_list) return end @@ -540,7 +537,7 @@ local function image_stack(storage, image_table, extra_data) local ignore_tif_tags = " -quiet -define tiff:ignore-tags=40965,42032,42033,42034,42036,18246,18249,36867,34864,34866 " if convert_executable then local convert_command = convert_executable .. ignore_tif_tags .. convert_arguments - dt.print_log(_("convert command is " .. convert_command)) + dt.print_log("convert command is " .. convert_command) dt.print(_("processing image stack")) local result = dtsys.external_command(convert_command) if result == 0 then @@ -580,7 +577,7 @@ local function image_stack(storage, image_table, extra_data) end else dt.print(_("ERROR: convert executable not found")) - dt.print_error(_("convert executable not found")) + dt.print_error("convert executable not found") cleanup(img_list) end job.valid = false diff --git a/contrib/image_time.lua b/contrib/image_time.lua index 17d54819..1655a120 100644 --- a/contrib/image_time.lua +++ b/contrib/image_time.lua @@ -107,7 +107,7 @@ local dt = require "darktable" local du = require "lib/dtutils" local df = require "lib/dtutils.file" local ds = require "lib/dtutils.string" -local gettext = dt.gettext +local gettext = dt.gettext.gettext local img_time = {} img_time.module_installed = false @@ -125,11 +125,9 @@ script_data.restart = nil -- how to restart the (lib) script after it's been hid script_data.show = nil -- only required for libs since the destroy_method only hides them --- Tell gettext where to find the .mo file translating messages for a particular domain -gettext.bindtextdomain("image_time",dt.configuration.config_dir.."/lua/locale/") local function _(msgid) - return gettext.dgettext("image_time", msgid) + return gettext(msgid) end local PS = dt.configuration.runnin_os == "windows" and "\\" or "/" @@ -249,7 +247,7 @@ local function _get_windows_image_file_creation_time(image) end p:close() else - dt.print(_("unable to get information for ") .. image.filename) + dt.print(string.format(_("unable to get information for "), image.filename)) datetime = ERROR end return datetime @@ -266,7 +264,7 @@ local function _get_nix_image_file_creation_time(image) end p:close() else - dt.print(_("unable to get information for ") .. image.filename) + dt.print(string.format(_("unable to get information for "), image.filename)) datetime = ERROR end return datetime @@ -314,7 +312,7 @@ local function reset_time(images) image.exif_datetime_taken = get_original_image_time(image) end else - dt.print_error(_("reset time: no images selected")) + dt.print_error("reset time: no images selected") dt.print(_("please select the images that need their time reset")) end end @@ -430,8 +428,8 @@ end img_time.widgets = { -- name, type, tooltip, placeholder, {"ayr", "combobox", _("years"), _("years to adjust by, 0 - ?"), {seq(0,20)}, 1}, - {"amo", "combobox", _("months"), ("months to adjust by, 0-12"), {seq(0,12)}, 1}, - {"ady", "combobox", _("days"), ("days to adjust by, 0-31"), {seq(0,31)}, 1}, + {"amo", "combobox", _("months"), _("months to adjust by, 0-12"), {seq(0,12)}, 1}, + {"ady", "combobox", _("days"), _("days to adjust by, 0-31"), {seq(0,31)}, 1}, {"ahr", "combobox", _("hours"), _("hours to adjust by, 0-23"), {seq(0,23)}, 1}, {"amn", "combobox", _("minutes"), _("minutes to adjust by, 0-59"), {seq(0,59)}, 1}, {"asc", "combobox", _("seconds"), _("seconds to adjust by, 0-59"), {seq(0,59)}, 1}, diff --git a/contrib/jpg_group_leader.lua b/contrib/jpg_group_leader.lua index ab97588d..e30afb80 100644 --- a/contrib/jpg_group_leader.lua +++ b/contrib/jpg_group_leader.lua @@ -73,13 +73,10 @@ script_data.show = nil -- only required for libs since the destroy_method only h -- I 1 8 N -- - - - - - - - - - - - - - - - - - - - - - - - - - -local gettext = dt.gettext - --- Tell gettext where to find the .mo file translating messages for a particular domain -gettext.bindtextdomain(MODULE, dt.configuration.config_dir .. "/lua/locale/") +local gettext = dt.gettext.gettext local function _(msgid) - return gettext.dgettext(MODULE, msgid) + return gettext(msgid) end diff --git a/contrib/kml_export.lua b/contrib/kml_export.lua index f772fb76..07293091 100644 --- a/contrib/kml_export.lua +++ b/contrib/kml_export.lua @@ -39,7 +39,7 @@ local df = require "lib/dtutils.file" local ds = require "lib/dtutils.string" local dsys = require "lib/dtutils.system" -local gettext = dt.gettext +local gettext = dt.gettext.gettext local PS = dt.configuration.running_os == "windows" and "\\" or "/" @@ -54,11 +54,8 @@ script_data.destroy_method = nil -- set to hide for libs since we can't destroy script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again script_data.show = nil -- only required for libs since the destroy_method only hides them --- Tell gettext where to find the .mo file translating messages for a particular domain -gettext.bindtextdomain("kml_export",dt.configuration.config_dir.."/lua/locale/") - local function _(msgid) - return gettext.dgettext("kml_export", msgid) + return gettext(msgid) end local function show_status(storage, image, format, filename, number, total, high_quality, extra_data) diff --git a/contrib/passport_guide.lua b/contrib/passport_guide.lua index 0b617286..6e101838 100644 --- a/contrib/passport_guide.lua +++ b/contrib/passport_guide.lua @@ -37,15 +37,12 @@ USAGE local dt = require "darktable" local du = require "lib/dtutils" -local gettext = dt.gettext +local gettext = dt.gettext.gettext du.check_min_api_version("2.0.0", "passport_guide") --- Tell gettext where to find the .mo file translating messages for a particular domain -gettext.bindtextdomain("passport_guide",dt.configuration.config_dir.."/lua/locale/") - local function _(msgid) - return gettext.dgettext("passport_guide", msgid) + return gettext(msgid) end dt.guides.register_guide("passport", diff --git a/contrib/pdf_slideshow.lua b/contrib/pdf_slideshow.lua index 11948845..adffffe0 100644 --- a/contrib/pdf_slideshow.lua +++ b/contrib/pdf_slideshow.lua @@ -42,17 +42,14 @@ local dt = require "darktable" local du = require "lib/dtutils" local df = require "lib/dtutils.file" -local gettext = dt.gettext - --- Tell gettext where to find the .mo file translating messages for a particular domain -gettext.bindtextdomain("pdf_slideshow",dt.configuration.config_dir.."/lua/locale/") +local gettext = dt.gettext.gettext local function _(msgid) - return gettext.dgettext("pdf_slideshow", msgid) + return gettext(msgid) end if not df.check_if_bin_exists("pdflatex") then - dt.print_error(_("pdflatex not found")) + dt.print_error("pdflatex not found") return end @@ -231,7 +228,7 @@ dt.register_storage("pdf_slideshow",_("pdf slideshow"), local result = dt.control.execute(command) if result ~= 0 then dt.print(_("problem running pdflatex")) -- this one is probably usefull to the user - error(_("problem running ")..command) + error("problem running ")..command) end -- open the PDF @@ -241,7 +238,7 @@ dt.register_storage("pdf_slideshow",_("pdf slideshow"), local result = dt.control.execute(command) if result ~= 0 then dt.print(_("problem running pdf viewer")) -- this one is probably usefull to the user - error(_("problem running ")..command) + error("problem running "..command) end -- finally do some clean-up diff --git a/contrib/photils.lua b/contrib/photils.lua index b5e99bd8..0e6662f8 100644 --- a/contrib/photils.lua +++ b/contrib/photils.lua @@ -55,9 +55,7 @@ script_data.show = nil -- only required for libs since the destroy_method only h local PS = dt.configuration.running_os == "windows" and "\\" or "/" -local gettext = dt.gettext -gettext.bindtextdomain(MODULE_NAME, - dt.configuration.config_dir .. PS .. "lua" .. PS .. "locale" .. PS) +local gettext = dt.gettext.gettext local exporter = dt.new_format("jpeg") exporter.quality = 80 @@ -67,7 +65,7 @@ exporter.max_width = 224 -- helper functions local function _(msgid) - return gettext.dgettext(MODULE_NAME, msgid) + return gettext(msgid) end local function num_keys(tbl) @@ -428,7 +426,7 @@ end if not photils_installed then GUI.warning_label.label = _("photils-cli not found") - dt.print_log(_("photils-cli not found")) + dt.print_log("photils-cli not found") else GUI.warning_label.label = _("Select an image, click \"get tags\" and get \nsuggestions for tags.") end diff --git a/contrib/quicktag.lua b/contrib/quicktag.lua index 15f1d8db..82ccb539 100644 --- a/contrib/quicktag.lua +++ b/contrib/quicktag.lua @@ -62,13 +62,10 @@ qt.module_installed = false qt.event_registered = false qt.widget_table = {} -local gettext = dt.gettext - --- Tell gettext where to find the .mo file translating messages for a particular domain -gettext.bindtextdomain("quicktag",dt.configuration.config_dir.."/lua/locale/") +local gettext = dt.gettext.gettext local function _(msgid) - return gettext.dgettext("quicktag", msgid) + return gettext(msgid) end -- maximum length of button labels diff --git a/contrib/rate_group.lua b/contrib/rate_group.lua index 9a790f81..ca85b263 100644 --- a/contrib/rate_group.lua +++ b/contrib/rate_group.lua @@ -44,6 +44,12 @@ local du = require "lib/dtutils" -- added version check du.check_min_api_version("7.0.0", "rate_group") +local gettext = dt.gettext.gettext + +local function _(msgid) + return gettext(msgid) +end + -- return data structure for script_manager local script_data = {} @@ -62,9 +68,9 @@ local function apply_rating(rating) end end if rating < 0 then - dt.print("rejecting group(s)") + dt.print(_("rejecting group(s)")) else - dt.print("applying rating " ..rating.. " to group(s)") + dt.print(string.format(_("applying rating %d to group(s)"), rating)) end end @@ -81,37 +87,37 @@ end dt.register_event("rg_reject", "shortcut", function(event, shortcut) apply_rating(-1) -end, "Reject group") +end, _("Reject group")) dt.register_event("rg0", "shortcut", function(event, shortcut) apply_rating(0) -end, "Rate group 0") +end, _("Rate group 0")) dt.register_event("rg1", "shortcut", function(event, shortcut) apply_rating(1) -end, "Rate group 1") +end, _("Rate group 1")) dt.register_event("rg2", "shortcut", function(event, shortcut) apply_rating(2) -end, "Rate group 2") +end, _("Rate group 2")) dt.register_event("rg3", "shortcut", function(event, shortcut) apply_rating(3) -end, "Rate group 3") +end, _("Rate group 3")) dt.register_event("rg4", "shortcut", function(event, shortcut) apply_rating(4) -end, "Rate group 4") +end, _("Rate group 4")) dt.register_event("rg5", "shortcut", function(event, shortcut) apply_rating(5) -end, "Rate group 5") +end, _("Rate group 5")) script_data.destroy = destroy diff --git a/contrib/rename-tags.lua b/contrib/rename-tags.lua index 2213b923..4e03af77 100644 --- a/contrib/rename-tags.lua +++ b/contrib/rename-tags.lua @@ -36,6 +36,12 @@ local debug = require "darktable.debug" du.check_min_api_version("7.0.0", "rename-tags") du.deprecated("contrib/rename-tags.lua","darktable release 4.0") +local gettext = dt.gettext.gettext + +local function _(msgid) + return gettext(msgid) +end + -- return data structure for script_manager local script_data = {} @@ -50,8 +56,8 @@ rt.module_installed = false rt.event_registered = false -- GUI entries -local old_tag = darktable.new_widget("entry") { tooltip = "Enter old tag" } -local new_tag = darktable.new_widget("entry") { tooltip = "Enter new tag" } +local old_tag = darktable.new_widget("entry") { tooltip = _("Enter old tag") } +local new_tag = darktable.new_widget("entry") { tooltip = _("Enter new tag") } local function rename_reset() old_tag.text = '' @@ -62,11 +68,11 @@ end local function rename_tags() -- If entries are empty, return if old_tag.text == '' then - darktable.print ("Old tag can't be empty") + darktable.print (_("Old tag can't be empty")) return end if new_tag.text == '' then - darktable.print ("New tag can't be empty") + darktable.print (_("New tag can't be empty")) return end @@ -76,12 +82,12 @@ local function rename_tags() local ot = darktable.tags.find (old_tag.text) if not ot then - darktable.print ("Old tag does not exist") + darktable.print (_("Old tag does not exist")) return end -- Show job - local job = darktable.gui.create_job ("Renaming tag", true) + local job = darktable.gui.create_job (_("Renaming tag"), true) old_tag.editable = false new_tag.editable = false @@ -104,7 +110,7 @@ local function rename_tags() darktable.tags.delete (ot) job.valid = false - darktable.print ("Renamed tags for " .. count .. " images") + darktable.print (string.format(_("Renamed tags for %d images"), count)) old_tag.editable = true new_tag.editable = true @@ -115,7 +121,7 @@ end local function install_module() if not rt.module_installed then - darktable.register_lib ("rename_tags", "rename tag", true, true, {[darktable.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 20},}, rt.rename_widget, nil, nil) + darktable.register_lib ("rename_tags", _("rename tag"), true, true, {[darktable.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 20},}, rt.rename_widget, nil, nil) rt.module_installed = true end end @@ -131,13 +137,13 @@ end -- GUI local old_widget = darktable.new_widget ("box") { orientation = "horizontal", - darktable.new_widget("label") { label = "Old tag" }, + darktable.new_widget("label") { label = _("Old tag") }, old_tag } local new_widget = darktable.new_widget ("box") { orientation = "horizontal", - darktable.new_widget("label") { label = "New tag" }, + darktable.new_widget("label") { label = _("New tag") }, new_tag } @@ -146,7 +152,7 @@ rt.rename_widget = darktable.new_widget ("box") { reset_callback = rename_reset, old_widget, new_widget, - darktable.new_widget("button") { label = "Go", clicked_callback = rename_tags } + darktable.new_widget("button") { label = _("Go"), clicked_callback = rename_tags } } if darktable.gui.current_view().id == "lighttable" then diff --git a/contrib/rename_images.lua b/contrib/rename_images.lua index e8e013db..cf133cf1 100644 --- a/contrib/rename_images.lua +++ b/contrib/rename_images.lua @@ -46,13 +46,10 @@ local df = require "lib/dtutils.file" du.check_min_api_version("7.0.0", "rename_images") -local gettext = dt.gettext - --- Tell gettext where to find the .mo file translating messages for a particular domain -gettext.bindtextdomain("rename_images",dt.configuration.config_dir.."/lua/locale/") +local gettext = dt.gettext.gettext local function _(msgid) - return gettext.dgettext("rename_images", msgid) + return gettext(msgid) end -- namespace variable @@ -86,7 +83,7 @@ local MODULE_NAME = "rename_images" local PS = dt.configuration.running_os == "windows" and "\\" or "/" local USER = os.getenv("USERNAME") local HOME = os.getenv(dt.configuration.running_os == "windows" and "HOMEPATH" or "HOME") -local PICTURES = HOME .. PS .. dt.configuration.running_os == "windows" and "My Pictures" or "Pictures" +local PICTURES = HOME .. PS .. dt.configuration.running_os == "windows" and _("My Pictures") or _("Pictures") local DESKTOP = HOME .. PS .. "Desktop" -- - - - - - - - - - - - - - - - - - - - - - - - @@ -158,8 +155,8 @@ local function substitute_list(str) if rename.substitutes[var] then str = string.gsub(str, "%$%("..var.."%)", rename.substitutes[var]) else - dt.print_error(_("unrecognized variable " .. var)) - dt.print(_("unknown variable " .. var .. ", aborting...")) + dt.print_error("unrecognized variable " .. var) + dt.print(string.format(_("unknown variable %s, aborting..."), var)) return -1 end end @@ -210,7 +207,7 @@ local function do_rename(images) if #images > 0 then local pattern = rename.widgets.pattern.text dt.preferences.write(MODULE_NAME, "pattern", "string", pattern) - dt.print_log(_("pattern is " .. pattern)) + dt.print_log("pattern is " .. pattern) if string.len(pattern) > 0 then local datetime = os.date("*t") @@ -250,7 +247,7 @@ local function do_rename(images) stop_job(job) local collect_rules = dt.gui.libs.collect.filter() dt.gui.libs.collect.filter(collect_rules) - dt.print(_("renamed " .. #images .. " images")) + dt.print(string.format(_("renamed %d images"), #images)) else -- pattern length dt.print_error("no pattern supplied, returning...") dt.print(_("please enter the new name or pattern")) diff --git a/contrib/select_non_existing.lua b/contrib/select_non_existing.lua index 9baef664..9536f03b 100644 --- a/contrib/select_non_existing.lua +++ b/contrib/select_non_existing.lua @@ -29,11 +29,10 @@ du.check_min_api_version("9.1.0", MODULE) -- figure out the path separator local PS = dt.configuration.running_os == "windows" and "\\" or "/" -local gettext = dt.gettext -gettext.bindtextdomain(MODULE, dt.configuration.config_dir..PS.."lua"..PS.."locale"..PS) +local gettext = dt.gettext.gettext local function _(msgid) - return gettext.dgettext(MODULE, msgid) + return gettext(msgid) end local function stop_job(job) diff --git a/contrib/select_untagged.lua b/contrib/select_untagged.lua index d15941b2..bb887f2e 100644 --- a/contrib/select_untagged.lua +++ b/contrib/select_untagged.lua @@ -20,7 +20,7 @@ Enable selection of untagged images (darktable|* tags are ignored) local dt = require "darktable" local du = require "lib/dtutils" -local gettext = dt.gettext +local gettext = dt.gettext.gettext du.check_min_api_version("7.0.0", "select_untagged") @@ -33,11 +33,8 @@ script_data.destroy_method = nil -- set to hide for libs since we can't destroy script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again script_data.show = nil -- only required for libs since the destroy_method only hides them --- Tell gettext where to find the .mo file translating messages for a particular domain -gettext.bindtextdomain("select_untagged",dt.configuration.config_dir.."/lua/locale/") - local function _(msgid) - return gettext.dgettext("select_untagged", msgid) + return gettext(msgid) end local function stop_job(job) diff --git a/contrib/slideshowMusic.lua b/contrib/slideshowMusic.lua index cf62aa69..71bae54e 100644 --- a/contrib/slideshowMusic.lua +++ b/contrib/slideshowMusic.lua @@ -27,7 +27,7 @@ USAGE local dt = require "darktable" local du = require "lib/dtutils" local df = require "lib/dtutils.file" -local gettext = dt.gettext +local gettext = dt.gettext.gettext du.check_min_api_version("7.0.0", "slideshowMusic") @@ -40,11 +40,8 @@ script_data.destroy_method = nil -- set to hide for libs since we can't destroy script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again script_data.show = nil -- only required for libs since the destroy_method only hides them --- Tell gettext where to find the .mo file translating messages for a particular domain -gettext.bindtextdomain("slideshowMusic",dt.configuration.config_dir.."/lua/locale/") - local function _(msgid) - return gettext.dgettext("slideshowMusic", msgid) + return gettext(msgid) end local function playSlideshowMusic(_, old_view, new_view) @@ -54,7 +51,7 @@ local function playSlideshowMusic(_, old_view, new_view) playMusic = dt.preferences.read("slideshowMusic","PlaySlideshowMusic","bool") if not df.check_if_bin_exists("rhythmbox-client") then - dt.print_error(_("rhythmbox-client not found")) + dt.print_error("rhythmbox-client not found") return end @@ -70,7 +67,7 @@ local function playSlideshowMusic(_, old_view, new_view) if (old_view and old_view.id == "slideshow") then stopCommand = "rhythmbox-client --pause" --dt.print_error(stopCommand) - dt.control.execute( stopCommand) + dt.control.execute(stopCommand) end end end diff --git a/contrib/transfer_hierarchy.lua b/contrib/transfer_hierarchy.lua index 10c5f0dc..15bea2a9 100755 --- a/contrib/transfer_hierarchy.lua +++ b/contrib/transfer_hierarchy.lua @@ -96,10 +96,8 @@ local PATH_SEGMENT_REGEX = "(" .. PATH_SEPARATOR .. "?)([^" .. PATH_SEPARATOR .. unpack = unpack or table.unpack gmatch = string.gfind or string.gmatch -darktable.gettext.bindtextdomain(LIB_ID, darktable.configuration.config_dir .. PATH_SEPARATOR .. "lua" .. PATH_SEPARATOR .. "locale" .. PATH_SEPARATOR) - local function _(msgid) - return darktable.gettext.dgettext(LIB_ID, msgid) + return darktable.gettext.gettext(msgid) end -- Header material: END @@ -268,17 +266,17 @@ local function doTransfer(transferFunc) films[film] = destBase .. string.sub(film.path, #sourceBase+1) if not pathExists(films[film]) then if createDirectory(films[film]) == nil then - darktable.print(_("transfer hierarchy: ERROR: could not create directory: " .. films[film])) + darktable.print(string.format(_("transfer hierarchy: ERROR: could not create directory: %s"), films[film])) return end end if not pathIsDirectory(films[film]) then - darktable.print(_("transfer hierarchy: ERROR: not a directory: " .. films[film])) + darktable.print(string.format(_("transfer hierarchy: ERROR: not a directory: %s"), films[film])) return end destFilms[film] = darktable.films.new(films[film]) if destFilms[film] == nil then - darktable.print(_("transfer hierarchy: ERROR: could not create film: " .. film.path)) + darktable.print(string.format(_("transfer hierarchy: ERROR: could not create film: %s"), film.path)) end end @@ -287,7 +285,7 @@ local function doTransfer(transferFunc) srcFilms[img] = img.film end - local job = darktable.gui.create_job(string.format(_("transfer hierarchy") .. " (%d image" .. (#(darktable.gui.action_images) == 1 and "" or "s") .. ")", #(darktable.gui.action_images)), true, stopTransfer) + local job = darktable.gui.create_job(string.format(_("transfer hierarchy (%d image%s)"), #(darktable.gui.action_images), (#(darktable.gui.action_images) == 1 and "" or "s")), true, stopTransfer) job.percent = 0.0 local pctIncrement = 1.0 / #(darktable.gui.action_images) for _,img in ipairs(darktable.gui.action_images) do diff --git a/contrib/video_ffmpeg.lua b/contrib/video_ffmpeg.lua index 165b5771..7c902ed6 100644 --- a/contrib/video_ffmpeg.lua +++ b/contrib/video_ffmpeg.lua @@ -37,7 +37,7 @@ local dt = require "darktable" local du = require "lib/dtutils" local df = require "lib/dtutils.file" local dsys = require "lib/dtutils.system" -local gettext = dt.gettext +local gettext = dt.gettext.gettext du.check_min_api_version("7.0.0", "video_ffmpeg") @@ -53,10 +53,9 @@ script_data.show = nil -- only required for libs since the destroy_method only h local MODULE_NAME = "video_ffmpeg" local PS = dt.configuration.running_os == "windows" and "\\" or "/" -gettext.bindtextdomain(MODULE_NAME, dt.configuration.config_dir..PS.."lua"..PS.."locale"..PS) local function _(msgid) - return gettext.dgettext(MODULE_NAME, msgid) + return gettext(msgid) end @@ -375,7 +374,7 @@ local module_widget = dt.new_widget("box") { ---- EXPORT & REGISTRATION local function show_status(enf_storage, image, format, filename, number, total, high_quality, extra_data) - dt.print(_("export ")..tostring(number).." / "..tostring(total)) + dt.print(string.format(_("export %d / %d"), number), total)) end local function init_export(storage, img_format, images, high_quality, extra_data) @@ -465,7 +464,7 @@ end dt.register_storage( "module_video_ffmpeg", - _(MODULE_NAME), + _("video ffmpeg"), show_status, finalize_export, nil, From 4735be470a6fa13c4a189316bf1ff429bf3e6308 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Wed, 24 Jan 2024 13:16:42 -0500 Subject: [PATCH 266/445] tools/script_manager - don't set lib visibility unless we are in lighttable view --- tools/script_manager.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/script_manager.lua b/tools/script_manager.lua index e65cd204..74697d5b 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -397,7 +397,7 @@ local function activate(script) if err ~= true then log.msg(log.debug, "got lib data") script.data = err - if script.data.destroy_method and script.data.destroy_method == "hide" and script.data.show then + if script.data.destroy_method and script.data.destroy_method == "hide" and script.data.show and dt.gui.current_view().id == "lighttable" then script.data.show() end else From febc3b165956b43c3e7384c3c1822ffaaa6fdbfe Mon Sep 17 00:00:00 2001 From: Michael Meister Date: Fri, 19 Jan 2024 19:29:49 +0100 Subject: [PATCH 267/445] tools/script_manager - fixed crash The script manager crashes if a LUA script was not copied to a subfolder but directly into the LUA directory. The reason is that the regular expression, which among other things extracts the category of the script from its file path, does not match and thus the category is null. To prevent this, a null check has been added. --- tools/script_manager.lua | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tools/script_manager.lua b/tools/script_manager.lua index 74697d5b..7376ed43 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -497,14 +497,15 @@ local function process_script_data(script_file) -- add the script data local category,path,name,filename,filetype = string.match(script_file, pattern) - log.msg(log.debug, "category is " .. category) - log.msg(log.debug, "name is " .. name) - add_script_category(category) + if category and name and path then + log.msg(log.debug, "category is " .. category) + log.msg(log.debug, "name is " .. name) - if name then + add_script_category(category) add_script_name(name, path, category) end + restore_log_level(old_log_level) end From 05a73d8810667664325fd3430c18f4dd875b9758 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Fri, 29 Mar 2024 12:45:28 -0400 Subject: [PATCH 268/445] changed translatable strings to lower case --- official/enfuse.lua | 16 ++++++++-------- official/selection_to_pdf.lua | 16 ++++++++-------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/official/enfuse.lua b/official/enfuse.lua index fb94229e..74999ad2 100644 --- a/official/enfuse.lua +++ b/official/enfuse.lua @@ -129,7 +129,7 @@ if enfuse_installed then exposure_mu = dt.new_widget("slider") { label = "exposure mu", - tooltip = _("center also known as MEAN of Gaussian weighting function (0 <= MEAN <= 1); default: 0.5"), + tooltip = _("center also known as mean of gaussian weighting function (0 <= mean <= 1); default: 0.5"), hard_min = 0, hard_max = 1, value = dt.preferences.read("enfuse", "exposure_mu", "float") @@ -138,7 +138,7 @@ if enfuse_installed then exposure_mu = dt.new_widget("slider") { label = "exposure optimum", - tooltip = _("optimum exposure value, usually the maximum of the weighting function (0 <= OPTIMUM <=1); default 0.5"), + tooltip = _("optimum exposure value, usually the maximum of the weighting function (0 <= optimum <=1); default 0.5"), hard_min = 0, hard_max = 1, value = dt.preferences.read("enfuse", "exposure_optimum", "float") @@ -182,7 +182,7 @@ if enfuse_installed then end local f = io.open(response_file, "w") if not f then - dt.print(string.format(_("Error writing to '%s'"), response_file)) + dt.print(string.format(_("error writing to '%s'"), response_file)) os.remove(response_file) return end @@ -205,9 +205,9 @@ if enfuse_installed then if dt.configuration.running_os == "windows" then tmp_exported = dt.configuration.tmp_dir .. tmp_exported -- windows os.tmpname() defaults to root directory end - dt.print(string.format(_("Converting raw file '%s' to tiff..."), i.filename)) + dt.print(string.format(_("converting raw file '%s' to tiff..."), i.filename)) tiff_exporter:write_image(i, tmp_exported, false) - dt.print_log(string.format("Raw file '%s' converted to '%s'", i.filename, tmp_exported)) + dt.print_log(string.format("raw file '%s' converted to '%s'", i.filename, tmp_exported)) cnt = cnt + 1 f:write(tmp_exported.."\n") @@ -215,14 +215,14 @@ if enfuse_installed then -- other images will be skipped else - dt.print(string.format(_("Skipping %s..."), i.filename)) + dt.print(string.format(_("skipping %s..."), i.filename)) n_skipped = n_skipped + 1 end end f:close() -- bail out if there is nothing to do if cnt == 0 then - dt.print(_("No suitable images selected, nothing to do for enfuse")) + dt.print(_("no suitable images selected, nothing to do for enfuse")) os.remove(response_file) return end @@ -296,7 +296,7 @@ if enfuse_installed then else dt.print_error("enfuse executable not found") error("enfuse executable not found") - dt.print(_("Could not find enfuse executable. Not loading enfuse exporter...")) + dt.print(_("could not find enfuse executable, not loading enfuse exporter...")) end script_data.destroy = destroy diff --git a/official/selection_to_pdf.lua b/official/selection_to_pdf.lua index 9e1d7b42..68063132 100644 --- a/official/selection_to_pdf.lua +++ b/official/selection_to_pdf.lua @@ -56,15 +56,15 @@ script_data.show = nil -- only required for libs since the destroy_method only h dt.preferences.register ("selection_to_pdf","Open with","string", _("a pdf viewer"), - _("Can be an absolute pathname or the tool may be in the PATH"), + _("can be an absolute pathname or the tool may be in the PATH"), "xdg-open") local title_widget = dt.new_widget("entry") { - placeholder = _("Title") + placeholder = _("title") } local no_of_thumbs_widget = dt.new_widget("slider") { - label = _("Thumbs per Line"), + label = _("thumbs per line"), soft_min = 1, -- The soft minimum value for the slider, the slider can't go beyond this point soft_max = 10, -- The soft maximum value for the slider, the slider can't go beyond this point hard_min = 1, -- The hard minimum value for the slider, the user can't manually enter a value beyond this point @@ -73,9 +73,9 @@ local no_of_thumbs_widget = dt.new_widget("slider") } local widget = dt.new_widget("box") { orientation = horizontal, - dt.new_widget("label"){label = _("Title:")}, + dt.new_widget("label"){label = _("title:")}, title_widget, - dt.new_widget("label"){label = _("Thumbnails per row:")}, + dt.new_widget("label"){label = _("thumbnails per row:")}, no_of_thumbs_widget } @@ -122,7 +122,7 @@ local function destroy() dt.print_log("done destroying") end -dt.register_storage(_("export_pdf"),_("Export thumbnails to pdf"), +dt.register_storage(_("export_pdf"),_("export thumbnails to pdf"), nil, function(storage,image_table) local my_title = title_widget.text @@ -169,7 +169,7 @@ dt.register_storage(_("export_pdf"),_("Export thumbnails to pdf"), local command = "pdflatex -halt-on-error -output-directory "..dir.." "..locfile local result = dt.control.execute(command) if result ~= 0 then - dt.print(_("Problem running pdflatex")) -- this one is probably usefull to the user + dt.print(_("problem running pdflatex")) -- this one is probably usefull to the user error("Problem running "..command) end @@ -179,7 +179,7 @@ dt.register_storage(_("export_pdf"),_("Export thumbnails to pdf"), command = command.." "..pdffile local result = dt.control.execute(command) if result ~= 0 then - dt.print(_("Problem running pdf viewer")) -- this one is probably usefull to the user + dt.print(_("problem running pdf viewer")) -- this one is probably usefull to the user error("Problem running "..command) end From 1fd2ca20aba1814bf787f2c4917e0c29d900cb8b Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Fri, 29 Mar 2024 12:55:08 -0400 Subject: [PATCH 269/445] changed translatable strings to lower case --- tools/executable_manager.lua | 4 ++-- tools/script_manager.lua | 22 +++++++++++----------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/tools/executable_manager.lua b/tools/executable_manager.lua index 75b4a6b3..70557412 100644 --- a/tools/executable_manager.lua +++ b/tools/executable_manager.lua @@ -140,7 +140,7 @@ local matches = grep(DARKTABLERC, "executable_paths") -- check if we have something to manage and exit if not if #matches == 0 then - dt.print(_("No executable paths found, exiting...")) + dt.print(_("no executable paths found, exiting...")) return end @@ -208,7 +208,7 @@ for i,exec in ipairs(exec_table) do dt.new_widget("section_label"){label = _("reset")}, dt.new_widget("button"){ label = _("clear"), - tooltip = _(string.format("Clear path for %s", exec)), + tooltip = string.format(_("clear path for %s"), exec), clicked_callback = function() df.set_executable_path_preference(exec, "") executable_path_widgets[exec].value = "" diff --git a/tools/script_manager.lua b/tools/script_manager.lua index 6a5d2acd..a7a5683d 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -390,7 +390,7 @@ local function activate(script) script_manager_running_script = nil if status then pref_write(script.script_name, "bool", true) - log.msg(log.screen, string.format(_("Loaded %s"), script.script_name)) + log.msg(log.screen, string.format(_("loaded %s"), script.script_name)) script.running = true if err ~= true then log.msg(log.debug, "got lib data") @@ -541,7 +541,7 @@ local function update_scripts() local git = sm.executables.git if not git then - dt.print(_("ERROR: git not found. Install or specify the location of the git executable.")) + dt.print(_("ERROR: git not found, install or specify the location of the git executable.")) return end @@ -625,7 +625,7 @@ local function install_scripts() local category = sm.widgets.new_category.text if string.match(du.join(sm.categories, " "), ds.sanitize_lua(category)) then - log.msg(log.screen, string.format(_("category %s is already in use. Please specify a different category name."), category)) + log.msg(log.screen, string.format(_("category %s is already in use, please specify a different category name."), category)) log.msg(log.error, "category " .. category .. " already exists, returning...") restore_log_level(old_log_level) return @@ -636,7 +636,7 @@ local function install_scripts() local git = sm.executables.git if not git then - dt.print(_("ERROR: git not found. Install or specify the location of the git executable.")) + dt.print(_("ERROR: git not found, install or specify the location of the git executable.")) restore_log_level(old_log_level) return end @@ -672,7 +672,7 @@ local function install_scripts() sm.widgets.new_category.text = "" sm.widgets.main_menu.selected = 3 else - dt.print(_("No scripts found to install")) + dt.print(_("no scripts found to install")) log.msg(log.error, "scan_scripts returned " .. count .. " scripts found. Not adding to category_selector") end else @@ -824,7 +824,7 @@ local function paginate(direction) else last = first + sm.page_status.num_buttons - 1 end - sm.widgets.page_status.label = string.format(_("Page %d of %d"), cur_page, max_pages) + sm.widgets.page_status.label = string.format(_("page %d of %d"), cur_page, max_pages) populate_buttons(category, first, last) restore_log_level(old_log_level) @@ -1087,7 +1087,7 @@ sm.widgets.add_scripts = dt.new_widget("box"){ } sm.widgets.allow_disable = dt.new_widget("check_button"){ - label = _('Enable "Disable Scripts" button'), + label = _('enable "disable scripts" button'), value = false, clicked_callback = function(this) if this.value == true then @@ -1097,7 +1097,7 @@ sm.widgets.allow_disable = dt.new_widget("check_button"){ } sm.widgets.disable_scripts = dt.new_widget("button"){ - label = _("Disable Scripts"), + label = _("disable scripts"), sensitive = false, clicked_callback = function(this) local LUARC = dt.configuration.config_dir .. PS .. "luarc" @@ -1143,7 +1143,7 @@ end local page_back = "<" local page_forward = ">" -sm.widgets.page_status = dt.new_widget("label"){label = _("Page:")} +sm.widgets.page_status = dt.new_widget("label"){label = _("page:")} sm.widgets.page_back = dt.new_widget("button"){ label = page_back, clicked_callback = function(this) @@ -1171,7 +1171,7 @@ sm.widgets.page_control = dt.new_widget("box"){ sm.widgets.scripts = dt.new_widget("box"){ orientation = vertical, - dt.new_widget("label"){label = _("Scripts")}, + dt.new_widget("label"){label = _("scripts")}, sm.widgets.category_selector, sm.widgets.page_control, table.unpack(sm.widgets.buttons) @@ -1200,7 +1200,7 @@ sm.widgets.change_buttons = dt.new_widget("button"){ sm.widgets.configure = dt.new_widget("box"){ orientation = "vertical", - dt.new_widget("label"){label = _("Configuration")}, + dt.new_widget("label"){label = _("configuration")}, sm.widgets.num_buttons, sm.widgets.change_buttons, } From e47ab3474556b58025e38983c3b0729cb849b4c5 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Fri, 29 Mar 2024 13:10:41 -0400 Subject: [PATCH 270/445] changed translatable strings to lower case --- examples/api_version.lua | 2 +- examples/darkroom_demo.lua | 6 +++--- examples/gettextExample.lua | 2 +- examples/lighttable_demo.lua | 4 ++-- examples/moduleExample.lua | 16 ++++++++-------- examples/multi_os.lua | 8 ++++---- examples/panels_demo.lua | 14 +++++++------- examples/preferenceExamples.lua | 28 ++++++++++++++-------------- examples/running_os.lua | 2 +- 9 files changed, 41 insertions(+), 41 deletions(-) diff --git a/examples/api_version.lua b/examples/api_version.lua index 1f86f6b7..49dc62a8 100644 --- a/examples/api_version.lua +++ b/examples/api_version.lua @@ -39,7 +39,7 @@ end local result = dt.configuration.api_version_string dt.print_log("API Version: " .. result) -dt.print(string.format(_("API Version: %s"), result)) +dt.print(string.format(_("API version: %s"), result)) -- set the destroy routine so that script_manager can call it when -- it's time to destroy the script and then return the data to diff --git a/examples/darkroom_demo.lua b/examples/darkroom_demo.lua index 6ca9f89e..bdd7f847 100644 --- a/examples/darkroom_demo.lua +++ b/examples/darkroom_demo.lua @@ -91,13 +91,13 @@ dt.gui.current_view(dt.gui.views.darkroom) local max_images = 10 -dt.print(_("Showing images, with a pause in between each")) +dt.print(_("showing images, with a pause in between each")) sleep(1500) -- display first 10 images of collection pausing for a second between each for i, img in ipairs(dt.collection) do - dt.print(string.format(_("Displaying image "), i)) + dt.print(string.format(_("displaying image "), i)) dt.gui.views.darkroom.display_image(img) sleep(1500) if i == max_images then @@ -107,7 +107,7 @@ end -- return to lighttable view -dt.print(_("Restoring view")) +dt.print(_("restoring view")) sleep(1500) dt.gui.current_view(current_view) diff --git a/examples/gettextExample.lua b/examples/gettextExample.lua index f74b5033..f0f51e95 100644 --- a/examples/gettextExample.lua +++ b/examples/gettextExample.lua @@ -78,7 +78,7 @@ local function _(msgid) return gettext(msgid) end -dt.print_error(_("Hello World!")) +dt.print_error(_("hello world!")) -- set the destroy routine so that script_manager can call it when -- it's time to destroy the script and then return the data to diff --git a/examples/lighttable_demo.lua b/examples/lighttable_demo.lua index 768e4ab3..e1e0732c 100644 --- a/examples/lighttable_demo.lua +++ b/examples/lighttable_demo.lua @@ -149,12 +149,12 @@ for n, layout in ipairs(layouts) do sleep(1500) for i = 1, 10 do dt.gui.libs.lighttable_mode.zoom_level(i) - dt.print(string.format(_("Set zoom level to %d"), i)) + dt.print(string.format(_("set zoom level to %d"), i)) sleep(1500) end for i = 9, 1, -1 do dt.gui.libs.lighttable_mode.zoom_level(i) - dt.print(string.format(_("Set zoom level to %d"), i)) + dt.print(string.format(_("set zoom level to %d"), i)) sleep(1500) end end diff --git a/examples/moduleExample.lua b/examples/moduleExample.lua index 23184aad..56741328 100644 --- a/examples/moduleExample.lua +++ b/examples/moduleExample.lua @@ -78,9 +78,9 @@ local function install_module() orientation = "vertical", dt.new_widget("button") { - label = _("MyButton"), + label = _("my button"), clicked_callback = function (_) - dt.print(_("Button clicked")) + dt.print(_("button clicked")) end }, table.unpack(mE.widgets), @@ -103,10 +103,10 @@ local function restart() end -- https://www.darktable.org/lua-api/types_lua_check_button.html -local check_button = dt.new_widget("check_button"){label = _("MyCheck_button"), value = true} +local check_button = dt.new_widget("check_button"){label = _("my check_button"), value = true} -- https://www.darktable.org/lua-api/types_lua_combobox.html -local combobox = dt.new_widget("combobox"){label = _("MyCombobox"), value = 2, "8", "16", "32"} +local combobox = dt.new_widget("combobox"){label = _("my combobox"), value = 2, "8", "16", "32"} -- https://www.darktable.org/lua-api/types_lua_entry.html local entry = dt.new_widget("entry") @@ -115,21 +115,21 @@ local entry = dt.new_widget("entry") placeholder = _("placeholder"), is_password = false, editable = true, - tooltip = _("Tooltip Text"), + tooltip = _("tooltip text"), reset_callback = function(self) self.text = "text" end } -- https://www.darktable.org/lua-api/types_lua_file_chooser_button.html local file_chooser_button = dt.new_widget("file_chooser_button") { - title = _("MyFile_chooser_button"), -- The title of the window when choosing a file + title = _("my file_chooser_button"), -- The title of the window when choosing a file value = "", -- The currently selected file is_directory = false -- True if the file chooser button only allows directories to be selecte } -- https://www.darktable.org/lua-api/types_lua_label.html local label = dt.new_widget("label") -label.label = _("MyLabel") -- This is an alternative way to the "{}" syntax to set a property +label.label = _("my label") -- This is an alternative way to the "{}" syntax to set a property -- https://www.darktable.org/lua-api/types_lua_separator.html local separator = dt.new_widget("separator"){} @@ -137,7 +137,7 @@ local separator = dt.new_widget("separator"){} -- https://www.darktable.org/lua-api/types_lua_slider.html local slider = dt.new_widget("slider") { - label = _("MySlider"), + label = _("my slider"), soft_min = 10, -- The soft minimum value for the slider, the slider can't go beyond this point soft_max = 100, -- The soft maximum value for the slider, the slider can't go beyond this point hard_min = 0, -- The hard minimum value for the slider, the user can't manually enter a value beyond this point diff --git a/examples/multi_os.lua b/examples/multi_os.lua index 7486a254..5c084cf8 100644 --- a/examples/multi_os.lua +++ b/examples/multi_os.lua @@ -184,12 +184,12 @@ local function extract_embedded_jpeg(images) end else dt.print_error(image.filename .. " is not a raw file. No image can be extracted") -- print debugging error message - dt.print(string.format(_("%s is not a raw file. No image can be extracted"), image.filename)) -- print the error to the screen + dt.print(string.format(_("%s is not a raw file, no image can be extracted"), image.filename)) -- print the error to the screen end end else dt.print_error("ufraw-batch not found. Exiting...") -- print debugging error message - dt.print("ufraw-batch not found. Exiting...") -- print the error to the screen + dt.print("ufraw-batch not found, exiting...") -- print the error to the screen end end @@ -213,7 +213,7 @@ end if dt.configuration.running_os ~= "linux" then local executable = "ufraw-batch" local ufraw_batch_path_widget = dt.new_widget("file_chooser_button"){ - title = _("Select ufraw-batch[.exe] executable"), + title = _("select ufraw-batch[.exe] executable"), value = df.get_executable_path_preference(executable), is_directory = false, changed_callback = function(self) @@ -225,7 +225,7 @@ if dt.configuration.running_os ~= "linux" then dt.preferences.register("executable_paths", "ufraw-batch", -- name "file", -- type _('multi_os: ufraw-batch location'), -- label - _('Installed location of ufraw-batch. Requires restart to take effect.'), -- tooltip + _('Installed location of ufraw-batch, requires restart to take effect.'), -- tooltip "ufraw-batch", -- default ufraw_batch_path_widget ) diff --git a/examples/panels_demo.lua b/examples/panels_demo.lua index 59383980..971d69bf 100644 --- a/examples/panels_demo.lua +++ b/examples/panels_demo.lua @@ -93,29 +93,29 @@ dt.gui.panel_show_all() -- hide center_top, center_bottom, left, top, right, bottom in order -dt.print(_("Hiding all panels, one at a tme")) +dt.print(_("hiding all panels, one at a tme")) sleep(1500) for i = 1, #panels do - dt.print(_("Hiding " .. panels[i])) + dt.print(_("hiding " .. panels[i])) dt.gui.panel_hide(panels[i]) sleep(1500) end -- display left, then top, then right, then bottom - dt.print(_("Make panels visible, one at a time")) + dt.print(_("make panels visible, one at a time")) sleep(1500) for i = #panels, 1, -1 do - dt.print(_("Showing " .. panels[i])) + dt.print(_("showing " .. panels[i])) dt.gui.panel_show(panels[i]) sleep(1500) end -- hide all -dt.print(_("Hiding all panels")) +dt.print(_("hiding all panels")) sleep(1500) dt.gui.panel_hide_all() @@ -123,7 +123,7 @@ sleep(1500) -- show all -dt.print(_("Showing all panels")) +dt.print(_("showing all panels")) sleep(1500) dt.gui.panel_show_all() @@ -131,7 +131,7 @@ sleep(1500) -- restore -dt.print(_("Restoring panels to starting configuration")) +dt.print(_("restoring panels to starting configuration")) for i = 1, #panels do if panel_status[i] then dt.gui.panel_show(panels[i]) diff --git a/examples/preferenceExamples.lua b/examples/preferenceExamples.lua index 74e6152b..aa8eae23 100644 --- a/examples/preferenceExamples.lua +++ b/examples/preferenceExamples.lua @@ -38,22 +38,22 @@ du.check_min_api_version("2.0.1", "preferenceExamples") dt.preferences.register("preferenceExamples", -- script: This is a string used to avoid name collision in preferences (i.e namespace). Set it to something unique, usually the name of the script handling the preference. "preferenceExamplesString", -- name "string", -- type - _("Example String"), -- label - _("Example String Tooltip"), -- tooltip + _("example string"), -- label + _("example string tooltip"), -- tooltip "String") -- default dt.preferences.register("preferenceExamples", -- script: This is a string used to avoid name collision in preferences (i.e namespace). Set it to something unique, usually the name of the script handling the preference. "preferenceExamplesBool", -- name "bool", -- type - _("Example Boolean"), -- label - _("Example Boolean Tooltip"), -- tooltip + _("example boolean"), -- label + _("example boolean tooltip"), -- tooltip true) -- default dt.preferences.register("preferenceExamples", -- script: This is a string used to avoid name collision in preferences (i.e namespace). Set it to something unique, usually the name of the script handling the preference. "preferenceExamplesInteger", -- name "integer", -- type - _("Example Integer"), -- label - _("Example Integer Tooltip"), -- tooltip + _("example integer"), -- label + _("example integer tooltip"), -- tooltip 2, -- default 1, -- min 99) -- max @@ -61,8 +61,8 @@ dt.preferences.register("preferenceExamples", -- script: This is a string dt.preferences.register("preferenceExamples", -- script: This is a string used to avoid name collision in preferences (i.e namespace). Set it to something unique, usually the name of the script handling the preference. "preferenceExamplesFloat", -- name "float", -- type - _("Example Float"), -- label - _("Example Float Tooltip"), -- tooltip + _("example float"), -- label + _("example float tooltip"), -- tooltip 1.3, -- default 1, -- min 99, -- max @@ -71,22 +71,22 @@ dt.preferences.register("preferenceExamples", -- script: This is a string dt.preferences.register("preferenceExamples", -- script: This is a string used to avoid name collision in preferences (i.e namespace). Set it to something unique, usually the name of the script handling the preference. "preferenceExamplesFile", -- name "file", -- type - _("Example File"), -- label - _("Example File Tooltip"), -- tooltip + _("example file"), -- label + _("example file tooltip"), -- tooltip "") -- default dt.preferences.register("preferenceExamples", -- script: This is a string used to avoid name collision in preferences (i.e namespace). Set it to something unique, usually the name of the script handling the preference. "preferenceExamplesDirectory", -- name "directory", -- type - _("Example Directory"), -- label - _("Example Directory Tooltip"), -- tooltip + _("example directory"), -- label + _("example directory tooltip"), -- tooltip "") -- default dt.preferences.register("preferenceExamples", -- script: This is a string used to avoid name collision in preferences (i.e namespace). Set it to something unique, usually the name of the script handling the preference. "preferenceExamplesEnum", -- name "enum", -- type - _("Example Enum"), -- label - _("Example Enum Tooltip"), -- tooltip + _("example enum"), -- label + _("example enum tooltip"), -- tooltip "Enum 1", -- default "Enum 1", "Enum 2") -- values diff --git a/examples/running_os.lua b/examples/running_os.lua index a179e9f8..2c68bf05 100644 --- a/examples/running_os.lua +++ b/examples/running_os.lua @@ -44,7 +44,7 @@ local function destroy() -- nothing to destroy end -dt.print(string.format(_("You are running: %s"), dt.configuration.running_os)) +dt.print(string.format(_("you are running: %s"), dt.configuration.running_os)) -- set the destroy routine so that script_manager can call it when -- it's time to destroy the script and then return the data to From 231e9b352bb560fb0e7c0c36eccc88770eb988e5 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Fri, 29 Mar 2024 14:17:19 -0400 Subject: [PATCH 271/445] changed translatable strings to lower case --- contrib/CollectHelper.lua | 22 ++++++++--------- contrib/HDRMerge.lua | 8 +++--- contrib/LabelsToTags.lua | 38 ++++++++++++++--------------- contrib/OpenInExplorer.lua | 20 +++++++-------- contrib/autostyle.lua | 12 ++++----- contrib/change_group_leader.lua | 4 +-- contrib/clear_GPS.lua | 4 +-- contrib/copy_attach_detach_tags.lua | 10 ++++---- contrib/cr2hdr.lua | 8 +++--- contrib/cycle_group_leader.lua | 4 +-- contrib/enfuseAdvanced.lua | 14 +++++------ contrib/exportLUT.lua | 12 ++++----- contrib/ext_editor.lua | 2 +- contrib/face_recognition.lua | 10 ++++---- contrib/fujifilm_ratings.lua | 4 +-- contrib/geoJSON_export.lua | 14 +++++------ contrib/geoToolbox.lua | 36 +++++++++++++-------------- contrib/gimp.lua | 6 ++--- contrib/hif_group_leader.lua | 4 +-- contrib/image_stack.lua | 8 +++--- contrib/image_time.lua | 12 ++++----- contrib/jpg_group_leader.lua | 4 +-- contrib/kml_export.lua | 26 ++++++++++---------- contrib/photils.lua | 18 +++++++------- contrib/rate_group.lua | 14 +++++------ contrib/rename-tags.lua | 20 +++++++-------- contrib/slideshowMusic.lua | 6 ++--- contrib/transfer_hierarchy.lua | 2 +- contrib/video_ffmpeg.lua | 2 +- 29 files changed, 172 insertions(+), 172 deletions(-) diff --git a/contrib/CollectHelper.lua b/contrib/CollectHelper.lua index 9e6f12c9..7e72d55f 100644 --- a/contrib/CollectHelper.lua +++ b/contrib/CollectHelper.lua @@ -69,7 +69,7 @@ end -- FUNCTION -- local function CheckSingleImage(selection) if #selection ~= 1 then - dt.print(_("Please select a single image")) + dt.print(_("please select a single image")) return true end return false @@ -202,47 +202,47 @@ end dt.gui.libs.image.register_action( "CollectHelper_prev", _("collect: previous"), function() PreviousCollection() end, - _("Sets the Collect parameters to be the previously active parameters") + _("sets the collect parameters to be the previously active parameters") ) if dt.preferences.read('module_CollectHelper','folder','bool') then dt.gui.libs.image.register_action( "CollectHelper_folder", _("collect: folder"), function() CollectOnFolder(_ , false) end, - _("Sets the Collect parameters to be the selected images's folder") + _("sets the collect parameters to be the selected images's folder") ) end if dt.preferences.read('module_CollectHelper','colors','bool') then dt.gui.libs.image.register_action( "CollectHelper_labels", _("collect: color label(s)"), function() CollectOnColors(_ , false) end, - _("Sets the Collect parameters to be the selected images's color label(s)") + _("sets the collect parameters to be the selected images's color label(s)") ) end if dt.preferences.read('module_CollectHelper','all_and','bool') then dt.gui.libs.image.register_action( "CollectHelper_and", _("collect: all (AND)"), function() CollectOnAll_AND() end, - _("Sets the Collect parameters based on all activated CollectHelper options") + _("sets the collect parameters based on all activated CollectHelper options") ) end -- PREFERENCES -- dt.preferences.register("module_CollectHelper", "all_and", -- name "bool", -- type - _('CollectHelper: All'), -- label - _('Will create a collect parameter set that utilizes all enabled CollectHelper types (AND)'), -- tooltip + _('CollectHelper: all'), -- label + _('will create a collect parameter set that utilizes all enabled CollectHelper types (and)'), -- tooltip true -- default ) dt.preferences.register("module_CollectHelper", "colors", -- name "bool", -- type - _('CollectHelper: Color Label(s)'), -- label - _('Enable the button that allows you to swap to a collection based on selected image\'s COLOR LABEL(S)'), -- tooltip + _('CollectHelper: color label(s)'), -- label + _('enable the button that allows you to swap to a collection based on selected image\'s color label(s)'), -- tooltip true -- default ) dt.preferences.register("module_CollectHelper", "folder", -- name "bool", -- type - _('CollectHelper: Folder'), -- label - _('Enable the button that allows you to swap to a collection based on selected image\'s FOLDER location'), -- tooltip + _('CollectHelper: folder'), -- label + _('enable the button that allows you to swap to a collection based on selected image\'s folder location'), -- tooltip true -- default ) diff --git a/contrib/HDRMerge.lua b/contrib/HDRMerge.lua index a662f215..c4fd75b8 100644 --- a/contrib/HDRMerge.lua +++ b/contrib/HDRMerge.lua @@ -378,7 +378,7 @@ local lbl_import = dt.new_widget('section_label'){ } GUI.Target.style = dt.new_widget('combobox'){ label = _('apply style on import'), - tooltip = _('Apply selected style on auto-import to newly created image'), + tooltip = _('apply selected style on auto-import to newly created image'), selected = 1, _('none'), changed_callback = function(self) @@ -407,9 +407,9 @@ GUI.Target.copy_tags = dt.new_widget('check_button'){ temp = dt.preferences.read(mod, 'active_add_tags', 'string') if temp == '' then temp = nil end GUI.Target.add_tags = dt.new_widget('entry'){ - tooltip = _('Additional tags to be added on import. Seperate with commas, all spaces will be removed'), + tooltip = _('additional tags to be added on import, seperate with commas, all spaces will be removed'), text = temp, - placeholder = _('Enter tags, seperated by commas'), + placeholder = _('enter tags, seperated by commas'), editable = true } GUI.run = dt.new_widget('button'){ @@ -418,7 +418,7 @@ GUI.run = dt.new_widget('button'){ clicked_callback = function() main() end } GUI.exes.HDRMerge = dt.new_widget('file_chooser_button'){ - title = _('Select HDRmerge executable'), + title = _('select HDRmerge executable'), value = df.get_executable_path_preference(HDRM.name), is_directory = false } diff --git a/contrib/LabelsToTags.lua b/contrib/LabelsToTags.lua index 83feada2..bc3a212c 100644 --- a/contrib/LabelsToTags.lua +++ b/contrib/LabelsToTags.lua @@ -115,23 +115,23 @@ end local initialAvailableMappings = { - [_("Colors")] = { ["+*****"] = { _("Red") }, - ["*+****"] = { _("Yellow") }, - ["**+***"] = { _("Green") }, - ["***+**"] = { _("Blue") }, - ["****+*"] = { _("Purple") } }, - [_("Single colors")] = { ["+----*"] = { _("Red"), _("Only red") }, - ["-+---*"] = { _("Yellow"), _("Only yellow") }, - ["--+--*"] = { _("Green"), _("Only green") }, - ["---+-*"] = { _("Blue"), _("Only blue") }, - ["----+*"] = { _("Purple"), _("Only purple") } }, - [_("Ratings")] = { ["*****0"] = { _("No stars"), _("Not rejected") }, - ["*****1"] = { _("One star"), _("Not rejected") }, - ["*****2"] = { _("Two stars"), _("Not rejected") }, - ["*****3"] = { _("Three stars"), _("Not rejected") }, - ["*****4"] = { _("Four stars"), _("Not rejected") }, - ["*****5"] = { _("Five stars"), _("Not rejected") }, - ["*****R"] = { _("Rejected") } } + [_("colors")] = { ["+*****"] = { _("red") }, + ["*+****"] = { _("yellow") }, + ["**+***"] = { _("green") }, + ["***+**"] = { _("blue") }, + ["****+*"] = { _("purple") } }, + [_("single colors")] = { ["+----*"] = { _("red"), _("only red") }, + ["-+---*"] = { _("Yellow"), _("only yellow") }, + ["--+--*"] = { _("Green"), _("only green") }, + ["---+-*"] = { _("Blue"), _("only blue") }, + ["----+*"] = { _("Purple"), _("only purple") } }, + [_("ratings")] = { ["*****0"] = { _("no stars"), _("not rejected") }, + ["*****1"] = { _("one star"), _("not rejected") }, + ["*****2"] = { _("two stars"), _("not rejected") }, + ["*****3"] = { _("three stars"), _("not rejected") }, + ["*****4"] = { _("four stars"), _("not rejected") }, + ["*****5"] = { _("five stars"), _("not rejected") }, + ["*****R"] = { _("rejected") } } } local availableMappings = {} @@ -146,9 +146,9 @@ end local function getComboboxTooltip() if availableMappings == nil or next(availableMappings) == nil then - return(_("No registered mappings -- using defaults")) + return(_("no registered mappings -- using defaults")) else - return(_("Select a label-to-tag mapping")) + return(_("select a label-to-tag mapping")) end end diff --git a/contrib/OpenInExplorer.lua b/contrib/OpenInExplorer.lua index 443a09ad..522e92b8 100644 --- a/contrib/OpenInExplorer.lua +++ b/contrib/OpenInExplorer.lua @@ -74,7 +74,7 @@ local PS = act_os == "windows" and "\\" or "/" --Detect OS and quit if it is not supported. if act_os ~= "macos" and act_os ~= "windows" and act_os ~= "linux" then - dt.print(_("OpenInExplorer plug-in only supports Linux, macOS, and Windows at this time")) + dt.print(_("OpenInExplorer plug-in only supports linux, macos, and windows at this time")) dt.print_error("OpenInExplorer plug-in only supports Linux, macOS, and Windows at this time") return end @@ -90,11 +90,11 @@ local function check_if_links_dir_exists() local dir_exists = true if not links_dir then --Just for paranoic reasons. I tried, but I couldn't devise a setting for a nil value. - dt.print(_("No links directory selected.\nPlease check the dt preferences (lua options)")) + dt.print(_("no links directory selected\nplease check the dt preferences (lua options)")) dt.print_error("OpenInExplorer: No links directory selected") dir_exists = false elseif not df.check_if_file_exists(links_dir) then - dt.print(string.format(_("Links directory '%s' not found.\nPlease check the dt preferences (lua options)"), links_dir)) + dt.print(string.format(_("links directory '%s' not found\nplease check the dt preferences (lua options)"), links_dir)) dt.print_error(string.format("OpenInExplorer: Links directory '%s' not found", links_dir)) dir_exists = false end @@ -151,7 +151,7 @@ local function set_links(selected_images) end ]] if dsys.external_command(run_cmd) ~= 0 then - dt.print(_("Failed to create links. Missing rights?")) + dt.print(_("failed to create links, missing rights?")) dt.print_error("OpenInExplorer: Failed to create links") return end @@ -167,13 +167,13 @@ end local function open_in_fmanager() local images = dt.gui.selection() if #images == 0 then - dt.print(_("Please select an image")) + dt.print(_("please select an image")) else if use_links and not check_if_links_dir_exists() then return end if #images > 15 and not use_links then - dt.print(_("Please select fewer images (max. 15)")) + dt.print(_("please select fewer images (max. 15)")) elseif use_links then set_links(images) else @@ -200,7 +200,7 @@ end dt.gui.libs.image.register_action( "OpenInExplorer", _("show in file explorer"), function() open_in_fmanager() end, - _("Open the file manager at the selected image's location") + _("open the file manager at the selected image's location") ) @@ -208,17 +208,17 @@ if act_os ~= "windows" then dt.preferences.register("OpenInExplorer", "linked_image_files_dir", -- name "directory", -- type _("OpenInExplorer: linked files directory"), -- label - _("Directory to store the links to the file names. Requires restart to take effect"), -- tooltip + _("directory to store the links to the file names, requires restart to take effect"), -- tooltip "Links to image files", -- default dt.new_widget("file_chooser_button"){ - title = _("Select directory"), + title = _("select directory"), is_directory = true, } ) dt.preferences.register("OpenInExplorer", "use_links", -- name "bool", -- type _("OpenInExplorer: use links"), -- label - _("Use links instead of multiple windows. Requires restart to take effect"), -- tooltip + _("use links instead of multiple windows, requires restart to take effect"), -- tooltip false, -- default "" ) diff --git a/contrib/autostyle.lua b/contrib/autostyle.lua index cf3ebe7c..4c1284e2 100644 --- a/contrib/autostyle.lua +++ b/contrib/autostyle.lua @@ -98,7 +98,7 @@ local function autostyle_apply_one_image (image) -- check they all exist (correct syntax) if (not tag) then - darktable.print(string.format(_("EXIF TAG not found in %s"), pref)) + darktable.print(string.format(_("EXIF tag not found in %s"), pref)) return 0 end if (not value) then @@ -110,7 +110,7 @@ local function autostyle_apply_one_image (image) return 0 end if not filelib.check_if_bin_exists("exiftool") then - darktable.print(_("Can't find exiftool")) + darktable.print(_("can't find exiftool")) return 0 end @@ -133,7 +133,7 @@ local function autostyle_apply_one_image (image) --darktable.print_error("dr_attr:" .. auto_dr_attr) -- If the lookup fails, stop here if (not ok) then - darktable.print(string.format(_("Couldn't get attribute %s from exiftool's output"), auto_dr_attr)) + darktable.print(string.format(_("couldn't get attribute %s from exiftool's output"), auto_dr_attr)) return 0 end if auto_dr_attr == value then @@ -160,7 +160,7 @@ local function autostyle_apply(shortcut) images_submitted = images_submitted + 1 images_processed = images_processed + autostyle_apply_one_image(image) end - darktable.print(string.format(_("Applied auto style to %d out of %d image(s)"), images_processed, images_submitted)) + darktable.print(string.format(_("applied auto style to %d out of %d image(s)"), images_processed, images_submitted)) end local function destroy() @@ -170,9 +170,9 @@ end -- Registering events darktable.register_event("autostyle", "shortcut", autostyle_apply, - _("Apply your chosen style from exiftool tags")) + _("apply your chosen style from exiftool tags")) -darktable.preferences.register("autostyle", "exif_tag", "string", "Autostyle: EXIF_tag=value=>style", _("apply a style automatically if an EXIF_tag matches value. Find the tag with exiftool"), "") +darktable.preferences.register("autostyle", "exif_tag", "string", "Autostyle: EXIF_tag=value=>style", _("apply a style automatically if an EXIF tag matches value, find the tag with exiftool"), "") darktable.register_event("autostyle", "post-import-image", autostyle_apply_one_image_event) diff --git a/contrib/change_group_leader.lua b/contrib/change_group_leader.lua index 786c91e9..0c70ac34 100644 --- a/contrib/change_group_leader.lua +++ b/contrib/change_group_leader.lua @@ -118,7 +118,7 @@ end local function process_image_groups(images) if #images < 1 then - dt.print(_("No images selected.")) + dt.print(_("o images selected")) dt.print_log(MODULE .. "no images seletected, returning...") else local mode = cgl.widgets.mode.value @@ -158,7 +158,7 @@ cgl.widgets.mode = dt.new_widget("combobox"){ } cgl.widgets.execute = dt.new_widget("button"){ - label = _("Execute"), + label = _("execute"), clicked_callback = function() process_image_groups(dt.gui.action_images) end diff --git a/contrib/clear_GPS.lua b/contrib/clear_GPS.lua index 9f21b1e5..7e12e094 100644 --- a/contrib/clear_GPS.lua +++ b/contrib/clear_GPS.lua @@ -79,13 +79,13 @@ script_data.destroy = destroy dt.gui.libs.image.register_action( "clear_GPS", _("clear GPS data"), function(event, images) clear_GPS(images) end, - _("Clear GPS data from selected images") + _("clear GPS data from selected images") ) dt.register_event( "clear_GPS", "shortcut", function(event, shortcut) clear_GPS(dt.gui.action_images) end, - _("Clear GPS data") + _("clear GPS data") ) return script_data diff --git a/contrib/copy_attach_detach_tags.lua b/contrib/copy_attach_detach_tags.lua index 1de8db29..de78f13e 100644 --- a/contrib/copy_attach_detach_tags.lua +++ b/contrib/copy_attach_detach_tags.lua @@ -96,7 +96,7 @@ local function mcopy_tags() end end - dt.print(_('Image tags copied ...')) + dt.print(_('image tags copied ...')) --create UI tag list local taglist = "" @@ -118,7 +118,7 @@ local function mcopy_tags() local function attach_tags() if next(image_tags) == nil then - dt.print(_('No tag to attach, please copy tags first.')) + dt.print(_('no tag to attach, please copy tags first.')) return true end @@ -142,7 +142,7 @@ local function attach_tags() end end end - dt.print(_('Tags attached ...')) + dt.print(_('tags attached ...')) end local function detach_tags() @@ -158,13 +158,13 @@ local function detach_tags() end end end - dt.print(_('Tags removed from image(s).')) + dt.print(_('tags removed from image(s).')) end local function replace_tags() detach_tags() attach_tags() - dt.print(_('Tags replaced')) + dt.print(_('tags replaced')) end local function install_module() diff --git a/contrib/cr2hdr.lua b/contrib/cr2hdr.lua index 53b1e147..8b6f54d3 100644 --- a/contrib/cr2hdr.lua +++ b/contrib/cr2hdr.lua @@ -93,7 +93,7 @@ end local function convert_images() if next(queue) == nil then return end - job = darktable.gui.create_job(_("Dual ISO conversion"), true, stop_conversion) + job = darktable.gui.create_job(_("dual ISO conversion"), true, stop_conversion) for key,image in pairs(queue) do if job.valid then job.percent = (key-1)/#queue @@ -104,7 +104,7 @@ local function convert_images() end local success_count = 0 for _ in pairs(processed_files) do success_count = success_count + 1 end - darktable.print(string.format(_("Dual ISO conversion successful on %d/%d images."), success_count, #queue)) + darktable.print(string.format(_("dual ISO conversion successful on %d/%d images."), success_count, #queue)) job.valid = false processed_files = {} queue = {} @@ -128,13 +128,13 @@ local function destroy() end darktable.register_event("cr2hdr", "shortcut", - convert_action_images, _("Run cr2hdr (Magic Lantern DualISO converter) on selected images")) + convert_action_images, _("run cr2hdr (Magic Lantern DualISO converter) on selected images")) darktable.register_event("cr2hdr", "post-import-image", file_imported) darktable.register_event("cr2hdr", "post-import-film", film_imported) -darktable.preferences.register("cr2hdr", "onimport", "bool", _("Invoke on import"), _("If true then cr2hdr will try to proccess every file during importing. Warning: cr2hdr is quite slow even in figuring out on whether the file is Dual ISO or not."), false) +darktable.preferences.register("cr2hdr", "onimport", "bool", _("invoke on import"), _("if true then cr2hdr will try to proccess every file during importing\nwarning: cr2hdr is quite slow even in figuring out on whether the file is dual ISO or not."), false) script_data.destroy = destroy diff --git a/contrib/cycle_group_leader.lua b/contrib/cycle_group_leader.lua index dde85461..d2bf3da5 100644 --- a/contrib/cycle_group_leader.lua +++ b/contrib/cycle_group_leader.lua @@ -97,7 +97,7 @@ end local function cycle_group_leader(image) local group_images = image:get_group_members() if #group_images < 2 then - hinter_msg(_("No images to cycle to in group")) + hinter_msg(_("no images to cycle to in group")) return else local position = nil @@ -144,7 +144,7 @@ dt.register_event(MODULE, "shortcut", -- ignore the film roll, it contains all the images, not just the imported local images = dt.gui.selection() if #images < 1 then - dt.print(_("No image selected. Please select an image and try again")) + dt.print(_("no image selected, please select an image and try again")) else cycle_group_leader(images[1]) end diff --git a/contrib/enfuseAdvanced.lua b/contrib/enfuseAdvanced.lua index f8aeb9be..8698f479 100644 --- a/contrib/enfuseAdvanced.lua +++ b/contrib/enfuseAdvanced.lua @@ -729,7 +729,7 @@ GUI.ENF.hard_masks = dt.new_widget('check_button'){ GUI.ENF.save_masks = dt.new_widget('check_button'){ label = _('save masks'), value = dt.preferences.read(mod, 'active_save_masks', 'bool'), - tooltip = _('Save the generated weight masks to your home directory,\nenblend saves masks as 8 bit grayscale, \ni.e. single channel images. \nfor accuracy we recommend to choose a lossless format.'), + tooltip = _('save the generated weight masks to your home directory,\nenblend saves masks as 8 bit grayscale, \ni.e. single channel images. \nfor accuracy we recommend to choose a lossless format.'), clicked_callback = function(self) dt.preferences.write(mod, 'active_save_masks', 'bool', self.value) end, reset_callback = function(self) self.value = false end } @@ -882,7 +882,7 @@ GUI.Target.output_directory = dt.new_widget('file_chooser_button'){ GUI.Target.source_location = dt.new_widget('check_button'){ label = _('save to source image location'), value = dt.preferences.read(mod, 'active_source_location', 'bool'), - tooltip = _('If checked ignores the location above and saves output image(s) to the same location as the source images.'), + tooltip = _('if checked ignores the location above and saves output image(s) to the same location as the source images.'), clicked_callback = function(self) dt.preferences.write(mod, 'active_source_location', 'bool', self.value) end, reset_callback = function(self) self.value = true end } @@ -916,8 +916,8 @@ GUI.Target.auto_import = dt.new_widget('check_button'){ } temp = dt.preferences.read(mod, 'active_apply_style_ind', 'integer') GUI.Target.apply_style = dt.new_widget('combobox'){ - label = _('Apply Style on Import'), - tooltip = _('Apply selected style on auto-import to newly created blended image'), + label = _('apply style on Import'), + tooltip = _('apply selected style on auto-import to newly created blended image'), selected = 1, 'none', changed_callback = function(self) @@ -938,16 +938,16 @@ GUI.Target.apply_style.selected = temp GUI.Target.copy_tags = dt.new_widget('check_button'){ label = _('copy tags'), value = dt.preferences.read(mod, 'active_copy_tags', 'bool'), - tooltip = _('Copy tags from first image.'), + tooltip = _('copy tags from first image.'), clicked_callback = function(self) dt.preferences.write(mod, 'active_copy_tags', 'bool', self.value) end, reset_callback = function(self) self.value = true end } temp = dt.preferences.read(mod, 'active_add_tags', 'string') if temp == '' then temp = nil end GUI.Target.add_tags = dt.new_widget('entry'){ - tooltip = _('Additional tags to be added on import. Seperate with commas, all spaces will be removed'), + tooltip = _('additional tags to be added on import, seperate with commas, all spaces will be removed'), text = temp, - placeholder = 'Enter tags, seperated by commas', + placeholder = _('enter tags, seperated by commas'), editable = true } temp = dt.preferences.read(mod, 'active_current_preset_ind', 'integer') diff --git a/contrib/exportLUT.lua b/contrib/exportLUT.lua index 6a22f837..7cc5b63a 100644 --- a/contrib/exportLUT.lua +++ b/contrib/exportLUT.lua @@ -62,13 +62,13 @@ local mkdir_command = 'mkdir -p ' if dt.configuration.running_os == 'windows' then mkdir_command = 'mkdir ' end local file_chooser_button = dt.new_widget("file_chooser_button"){ - title = _("Identity_file_chooser"), + title = _("identity_file_chooser"), value = "", is_directory = false } local export_chooser_button = dt.new_widget("file_chooser_button"){ - title = _("Export_location_chooser"), + title = _("export_location_chooser"), value = "", is_directory = true } @@ -104,9 +104,9 @@ end local function export_luts() local identity = dt.database.import(file_chooser_button.value) if(type(identity) ~= "userdata") then - dt.print(_("Invalid identity lut file")) + dt.print(_("invalid identity lut file")) else - local job = dt.gui.create_job(_('Exporting styles as haldCLUTs'), true, end_job) + local job = dt.gui.create_job(_('exporting styles as haldCLUTs'), true, end_job) local size = 1 @@ -125,9 +125,9 @@ local function export_luts() io_lut:write_image(identity, output_path(style.name, job)) count = count + 1 job.percent = count / size - dt.print(string.format(_("Exported: %s"), output_path(style.name, job))) + dt.print(string.format(_("exported: %s"), output_path(style.name, job))) end - dt.print(_("Done exporting haldCLUTs")) + dt.print(_("done exporting haldCLUTs")) job.valid = false identity:reset() end diff --git a/contrib/ext_editor.lua b/contrib/ext_editor.lua index b28a7f95..a6485d49 100644 --- a/contrib/ext_editor.lua +++ b/contrib/ext_editor.lua @@ -477,7 +477,7 @@ dt.register_storage("exp2coll", _("collection"), nil, export2collection) for i = MAX_EDITORS, 1, -1 do dt.preferences.register(MODULE_NAME, "program_path_"..i, "file", string.format(_("executable for external editor %d"), i), - _("select executable for external editor") , _("(None)")) + _("select executable for external editor") , _("(none)")) dt.preferences.register(MODULE_NAME, "program_name_"..i, "string", string.format(_("name of external editor %d"), i), diff --git a/contrib/face_recognition.lua b/contrib/face_recognition.lua index 7325d7e9..8c23fa77 100644 --- a/contrib/face_recognition.lua +++ b/contrib/face_recognition.lua @@ -132,7 +132,7 @@ local function do_export(img_tbl, images) job.percent = 0.0 for export,img in pairs(img_tbl) do exp_cnt = exp_cnt + 1 - dt.print(string.format(_("Exporting image %i of %i images"), exp_cnt, images)) + dt.print(string.format(_("exporting image %i of %i images"), exp_cnt, images)) exporter:write_image(img, export, upsize) job.percent = job.percent + percent_step end @@ -202,7 +202,7 @@ local function face_recognition () local bin_path = df.check_if_bin_exists("face_recognition") if not bin_path then - dt.print(_("Face recognition not found")) + dt.print(_("face recognition not found")) return end @@ -254,7 +254,7 @@ local function face_recognition () local command = bin_path .. " --cpus " .. nrCores .. " --tolerance " .. tolerance .. " " .. knownPath .. " " .. path .. " > " .. OUTPUT os.setlocale() dt.print_log("Face recognition: Running command: " .. command) - dt.print(_("Starting face recognition...")) + dt.print(_("starting face recognition...")) dtsys.external_command(command) @@ -262,9 +262,9 @@ local function face_recognition () local f = io.open(OUTPUT, "rb") if not f then - dt.print(_("Face recognition failed")) + dt.print(_("face recognition failed")) else - dt.print(_("Face recognition finished")) + dt.print(_("face recognition finished")) f:close () end diff --git a/contrib/fujifilm_ratings.lua b/contrib/fujifilm_ratings.lua index c64fffaa..8e196489 100644 --- a/contrib/fujifilm_ratings.lua +++ b/contrib/fujifilm_ratings.lua @@ -58,7 +58,7 @@ local function detect_rating(event, image) if string.len(jpeg_result) > 0 then jpeg_result = string.gsub(jpeg_result, "^Rating.*(%d)", "%1") image.rating = tonumber(jpeg_result) - dt.print_error(string.format(_("Using JPEG Rating: %d"), jpeg_result)) + dt.print_error(string.format(_("using JPEG rating: %d"), jpeg_result)) return end command = "exiftool -Rating " .. RAF_filename @@ -69,7 +69,7 @@ local function detect_rating(event, image) if string.len(raf_result) > 0 then raf_result = string.gsub(raf_result, "^Rating.*(%d)", "%1") image.rating = tonumber(raf_result) - dt.print_error(string.format(_("Using RAF Rating: %d"), raf_result)) + dt.print_error(string.format(_("using RAF rating: %d"), raf_result)) end end diff --git a/contrib/geoJSON_export.lua b/contrib/geoJSON_export.lua index dac5f5f4..a6dfc519 100644 --- a/contrib/geoJSON_export.lua +++ b/contrib/geoJSON_export.lua @@ -77,7 +77,7 @@ local function spairs(_table, order) -- Code copied from http://stackoverflow.co end local function show_status(storage, image, format, filename, number, total, high_quality, extra_data) - dt.print(string.format(_("Export Image %i/%i"), number, total)) + dt.print(string.format(_("export image %i/%i"), number, total)) end local function create_geoJSON_file(storage, image_table, extra_data) @@ -306,19 +306,19 @@ dt.preferences.register("geoJSON_export", "CreateMapBoxHTMLFile", "bool", _("geoJSON export: Create an additional HTML file"), - _("Creates a HTML file, that loads the geoJASON file. (Needs a MapBox key"), + _("creates an HTML file that loads the geoJSON file. (needs a MapBox key"), false ) dt.preferences.register("geoJSON_export", "mapBoxKey", "string", - _("geoJSON export: MapBox Key"), + _("geoJSON export: MapBox key"), _("https://www.mapbox.com/studio/account/tokens"), '' ) dt.preferences.register("geoJSON_export", "OpengeoJSONFile", "bool", - _("geoJSON export: Open geoJSON file after export"), - _("Opens the geoJSON file after the export with the standard program for geoJSON files"), + _("geoJSON export: open geoJSON file after export"), + _("opens the geoJSON file after the export with the standard program for geoJSON files"), false ) local handle = io.popen("xdg-user-dir DESKTOP") @@ -330,8 +330,8 @@ end dt.preferences.register("geoJSON_export", "ExportDirectory", "directory", - _("geoJSON export: Export directory"), - _("A directory that will be used to export the geoJSON files"), + _("geoJSON export: export directory"), + _("a directory that will be used to export the geoJSON files"), result ) -- Register diff --git a/contrib/geoToolbox.lua b/contrib/geoToolbox.lua index b595015f..ee895ca5 100644 --- a/contrib/geoToolbox.lua +++ b/contrib/geoToolbox.lua @@ -53,7 +53,7 @@ gT.event_registered = false -- local labelDistance = dt.new_widget("label") -labelDistance.label = _("Distance:") +labelDistance.label = _("distance:") local label_copy_gps_lat = dt.new_widget("check_button") { @@ -490,7 +490,7 @@ local function calc_distance() distanceUnit = _("km") end - return string.format(_("Distance: %.2f %s"), distance, distanceUnit) + return string.format(_("distance: %.2f %s"), distance, distanceUnit) end local function print_calc_distance() @@ -513,12 +513,12 @@ local altitude_filename = dt.new_widget("entry") text = "altitude.csv", placeholder = "altitude.csv", editable = true, - tooltip = _("Name of the exported file"), + tooltip = _("name of the exported file"), reset_callback = function(self) self.text = "text" end } local function altitude_profile() - dt.print(_("Start export")) + dt.print(_("start export")) local sel_images = dt.gui.action_images local lat1 = 0; @@ -579,7 +579,7 @@ local function altitude_profile() file = io.open(exportDirectory.."/"..exportFilename, "w") file:write(csv_file) file:close() - dt.print(string.format(_("File created in %s"), exportDirectory)) + dt.print(string.format(_("file created in %s"), exportDirectory)) end @@ -609,14 +609,14 @@ end local function restart() dt.register_event("geoToolbox_cd", "shortcut", - print_calc_distance, _("Calculate the distance from latitude and longitude in km")) + print_calc_distance, _("calculate the distance from latitude and longitude in km")) dt.register_event("geoToolbox", "mouse-over-image-changed", toolbox_calc_distance) dt.register_event("geoToolbox_wg", "shortcut", - select_with_gps, _("Select all images with GPS information")) + select_with_gps, _("select all images with GPS information")) dt.register_event("geoToolbox_ng", "shortcut", - select_without_gps, _("Select all images without GPS information")) + select_without_gps, _("select all images without GPS information")) dt.gui.libs["geoToolbox"].visible = true end @@ -639,20 +639,20 @@ gT.widget = dt.new_widget("box") dt.new_widget("button") { label = _("select geo images"), - tooltip = _("Select all images with GPS information"), + tooltip = _("select all images with GPS information"), clicked_callback = select_with_gps }, dt.new_widget("button") { label = _("select non-geo images"), - tooltip = _("Select all images without GPS information"), + tooltip = _("select all images without GPS information"), clicked_callback = select_without_gps }, separator,-------------------------------------------------------- dt.new_widget("button") { label = _("copy GPS data"), - tooltip = _("Copy GPS data"), + tooltip = _("copy GPS data"), clicked_callback = copy_gps }, label_copy_gps_lat, @@ -661,7 +661,7 @@ gT.widget = dt.new_widget("box") dt.new_widget("button") { label = _("paste GPS data"), - tooltip = _("Paste GPS data"), + tooltip = _("paste GPS data"), clicked_callback = paste_gps }, separator2,-------------------------------------------------------- @@ -691,14 +691,14 @@ gT.widget = dt.new_widget("box") dt.new_widget("button") { label = _("open in Gnome Maps"), - tooltip = _("Open location in Gnome Maps"), + tooltip = _("open location in Gnome Maps"), clicked_callback = open_location_in_gnome_maps }, separator4,-------------------------------------------------------- dt.new_widget("button") { label = _("reverse geocode"), - tooltip = _("This just shows the name of the location, but doesn't add it as tag"), + tooltip = _("this just shows the name of the location, but doesn't add it as tag"), clicked_callback = reverse_geocode }, separator5,-------------------------------------------------------- @@ -708,7 +708,7 @@ gT.widget = dt.new_widget("box") dt.new_widget("button") { label = _("export altitude CSV file"), - tooltip = _("Create an altitude profile using the GPS data in the metadata"), + tooltip = _("create an altitude profile using the GPS data in the metadata"), clicked_callback = altitude_profile }, labelDistance @@ -741,14 +741,14 @@ dt.preferences.register("geoToolbox", -- Register dt.register_event("geoToolbox_cd", "shortcut", - print_calc_distance, _("Calculate the distance from latitude and longitude in km")) + print_calc_distance, _("calculate the distance from latitude and longitude in km")) dt.register_event("geoToolbox", "mouse-over-image-changed", toolbox_calc_distance) dt.register_event("geoToolbox_wg", "shortcut", - select_with_gps, _("Select all images with GPS information")) + select_with_gps, _("select all images with GPS information")) dt.register_event("geoToolbox_ng", "shortcut", - select_without_gps, _("Select all images without GPS information")) + select_without_gps, _("select all images without GPS information")) script_data.destroy = destroy script_data.restart = restart diff --git a/contrib/gimp.lua b/contrib/gimp.lua index 843bbcea..db1e48f3 100644 --- a/contrib/gimp.lua +++ b/contrib/gimp.lua @@ -106,7 +106,7 @@ end local function show_status(storage, image, format, filename, number, total, high_quality, extra_data) - dt.print(string.format(_("Export Image %i/%i"), number, total)) + dt.print(string.format(_("export image %i/%i"), number, total)) end local function gimp_edit(storage, image_table, extra_data) --finalize @@ -139,7 +139,7 @@ local function gimp_edit(storage, image_table, extra_data) --finalize img_list = img_list ..exp_img.. " " end - dt.print(_("Launching GIMP...")) + dt.print(_("launching GIMP...")) local gimpStartCommand gimpStartCommand = gimp_executable .. " " .. img_list @@ -210,7 +210,7 @@ gimp_widget = dt.new_widget("check_button"){ end } -dt.register_storage("module_gimp", _("Edit with GIMP"), show_status, gimp_edit, nil, nil, gimp_widget) +dt.register_storage("module_gimp", _("edit with GIMP"), show_status, gimp_edit, nil, nil, gimp_widget) -- script_data.destroy = destroy diff --git a/contrib/hif_group_leader.lua b/contrib/hif_group_leader.lua index 14327db0..c50d8b26 100644 --- a/contrib/hif_group_leader.lua +++ b/contrib/hif_group_leader.lua @@ -179,7 +179,7 @@ dt.register_event(MODULE .. "_collect", "shortcut", local images = dt.collection make_existing_hif_group_leader(images) end, - _("Make hif group leader for collection") + _("make hif group leader for collection") ) dt.register_event(MODULE .. "_select", "shortcut", @@ -187,7 +187,7 @@ dt.register_event(MODULE .. "_select", "shortcut", local images = dt.gui.selection() make_existing_hif_group_leader(images) end, - _("Make hif group leader for selection") + _("make hif group leader for selection") ) return script_data \ No newline at end of file diff --git a/contrib/image_stack.lua b/contrib/image_stack.lua index d8abc9a9..f6aad52d 100644 --- a/contrib/image_stack.lua +++ b/contrib/image_stack.lua @@ -256,7 +256,7 @@ end -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - local function show_status(storage, image, format, filename, number, total, high_quality, extra_data) - dt.print(string.format(_("Export Image %i/%i"), number, total)) + dt.print(string.format(_("export image %i/%i"), number, total)) end -- read the gui and populate the align_image_stack arguments @@ -551,7 +551,7 @@ local function image_stack(storage, image_table, extra_data) local import_filename = df.create_unique_filename(film_roll_path .. PS .. df.get_filename(output_filename)) df.file_move(output_filename, import_filename) imported_image = dt.database.import(import_filename) - local created_tag = dt.tags.create(_("Created with|image_stack")) + local created_tag = dt.tags.create(_("created with|image_stack")) dt.tags.attach(created_tag, imported_image) -- all the images are the same except for time, so just copy the attributes -- from the first @@ -565,7 +565,7 @@ local function image_stack(storage, image_table, extra_data) if tag_source then dt.print(_("tagging source images")) - local source_tag = dt.tags.create(_("Source file|" .. imported_image.filename)) + local source_tag = dt.tags.create(_("source file|" .. imported_image.filename)) for img, _ in pairs(image_table) do dt.tags.attach(source_tag, img) end @@ -589,7 +589,7 @@ end dt.preferences.register("align_image_stack", "align_use_gpu", -- name "bool", -- type - _('align image stack: use GPU for remaping'), -- label + _('align image stack: use GPU for remapping'), -- label _('set the GPU remapping for image align'), -- tooltip false) diff --git a/contrib/image_time.lua b/contrib/image_time.lua index 1655a120..1f0a7d2f 100644 --- a/contrib/image_time.lua +++ b/contrib/image_time.lua @@ -173,7 +173,7 @@ local function calculate_difference(images) img_time.diff_entry.text = calc_time_difference(images[1], images[2]) img_time.btn.sensitive = true else - dt.print(_("Error: 2 images must be selected")) + dt.print(_("ERROR: 2 images must be selected")) end end @@ -247,7 +247,7 @@ local function _get_windows_image_file_creation_time(image) end p:close() else - dt.print(string.format(_("unable to get information for "), image.filename)) + dt.print(string.format(_("unable to get information for $s"), image.filename)) datetime = ERROR end return datetime @@ -264,7 +264,7 @@ local function _get_nix_image_file_creation_time(image) end p:close() else - dt.print(string.format(_("unable to get information for "), image.filename)) + dt.print(string.format(_("unable to get information for %s"), image.filename)) datetime = ERROR end return datetime @@ -455,13 +455,13 @@ end img_time.syr.selected = #img_time.syr img_time.diff_entry = dt.new_widget("entry"){ - tooltip = _("Time difference between images in seconds"), - placeholder = _("Select 2 images and use the calculate button"), + tooltip = _("time difference between images in seconds"), + placeholder = _("select 2 images and use the calculate button"), text = "", } img_time.calc_btn = dt.new_widget("button"){ - label = _("Calculate"), + label = _("calculate"), tooltip = _("calculate time difference between 2 images"), clicked_callback = function() calculate_difference(dt.gui.action_images) diff --git a/contrib/jpg_group_leader.lua b/contrib/jpg_group_leader.lua index e30afb80..63d9801f 100644 --- a/contrib/jpg_group_leader.lua +++ b/contrib/jpg_group_leader.lua @@ -179,7 +179,7 @@ dt.register_event(MODULE .. "_collect", "shortcut", local images = dt.collection make_existing_jpg_group_leader(images) end, - _("Make jpg group leader for collection") + _("make jpg group leader for collection") ) dt.register_event(MODULE .. "_select", "shortcut", @@ -187,7 +187,7 @@ dt.register_event(MODULE .. "_select", "shortcut", local images = dt.gui.selection() make_existing_jpg_group_leader(images) end, - _("Make jpg group leader for selection") + _("make jpg group leader for selection") ) return script_data \ No newline at end of file diff --git a/contrib/kml_export.lua b/contrib/kml_export.lua index 07293091..79ac384c 100644 --- a/contrib/kml_export.lua +++ b/contrib/kml_export.lua @@ -59,7 +59,7 @@ local function _(msgid) end local function show_status(storage, image, format, filename, number, total, high_quality, extra_data) - dt.print(string.format(_("Export Image %i/%i"), number, total)) + dt.print(string.format(_("export image %i/%i"), number, total)) end -- Add duplicate index to filename @@ -317,14 +317,14 @@ if dt.configuration.running_os == "windows" then "OpenKmlFile", "bool", _("KML export: Open KML file after export"), - _("Opens the KML file after the export with the standard program for KML files"), + _("opens the KML file after the export with the standard program for KML files"), false ) else dt.preferences.register("kml_export", "OpenKmlFile", "bool", - _("KML export: Open KML/KMZ file after export"), - _("Opens the KML file after the export with the standard program for KML files"), + _("KML export: open KML/KMZ file after export"), + _("opens the KML file after the export with the standard program for KML files"), false ) end @@ -343,23 +343,23 @@ end dt.preferences.register("kml_export", "ExportDirectory", "directory", - _("KML export: Export directory"), - _("A directory that will be used to export the KML/KMZ files"), + _("KML export: export directory"), + _("a directory that will be used to export the KML/KMZ files"), defaultDir ) if dt.configuration.running_os ~= "linux" then dt.preferences.register("kml_export", "magickPath", -- name "file", -- type - _("KML export: ImageMagick binary Location"), -- label - _("Install location of magick[.exe]. Requires restart to take effect."), -- tooltip + _("KML export: ImageMagick binary location"), -- label + _("install location of magick[.exe], requires restart to take effect"), -- tooltip "magick") -- default end dt.preferences.register("kml_export", "CreatePath", "bool", - _("KML export: Connect images with path"), + _("KML export: connect images with path"), _("connect all images with a path"), false ) @@ -367,16 +367,16 @@ if dt.configuration.running_os == "linux" then dt.preferences.register("kml_export", "CreateKMZ", "bool", - _("KML export: Create KMZ file"), - _("Compress all imeges to one KMZ file"), + _("KML export: create KMZ file"), + _("compress all imeges to one KMZ file"), true ) end -- Register if dt.configuration.running_os == "windows" then - dt.register_storage("kml_export", _("KML Export"), nil, create_kml_file) + dt.register_storage("kml_export", _("KML export"), nil, create_kml_file) else - dt.register_storage("kml_export", _("KML/KMZ Export"), nil, create_kml_file) + dt.register_storage("kml_export", _("KML/KMZ export"), nil, create_kml_file) end script_data.destroy = destroy diff --git a/contrib/photils.lua b/contrib/photils.lua index 0e6662f8..f26998fb 100644 --- a/contrib/photils.lua +++ b/contrib/photils.lua @@ -176,7 +176,7 @@ function PHOTILS.image_changed() end function PHOTILS.tagged_image_has_changed() - GUI.warning.label = _("The suggested tags were not generated\n for the currently selected image!") + GUI.warning.label = _("the suggested tags were not generated\n for the currently selected image!") end function PHOTILS.paginate() @@ -233,7 +233,7 @@ end function PHOTILS.attach_tags() local num_selected = #dt.gui.selection() - local job = dt.gui.create_job(_("Apply tag to image"), true) + local job = dt.gui.create_job(_("apply tag to image"), true) for i = 1, num_selected, 1 do local image = dt.gui.selection()[i] @@ -245,7 +245,7 @@ function PHOTILS.attach_tags() job.percent = i / num_selected end - dt.print(_("Tags successfully attached to image")) + dt.print(_("tags successfully attached to image")) job.valid = false end @@ -311,11 +311,11 @@ function PHOTILS.on_tags_clicked() local images = dt.gui.selection() if #images == 0 then - dt.print(_("No image selected.")) + dt.print(_("no image selected.")) dt.control.sleep(2000) else if #images > 1 then - dt.print(_("This plugin can only handle a single image.")) + dt.print(_("this plugin can only handle a single image.")) dt.gui.selection({images[1]}) dt.control.sleep(2000) end @@ -428,7 +428,7 @@ if not photils_installed then GUI.warning_label.label = _("photils-cli not found") dt.print_log("photils-cli not found") else - GUI.warning_label.label = _("Select an image, click \"get tags\" and get \nsuggestions for tags.") + GUI.warning_label.label = _("select an image, click \"get tags\" and get \nsuggestions for tags.") end GUI.pagination = dt.new_widget("box") { @@ -471,9 +471,9 @@ dt.preferences.register(MODULE_NAME, "export_image_before_for_tags", "bool", _("photils: use exported image for tag request"), - _("If enabled, the image passed to photils for tag suggestion is based on the exported, already edited image. " .. - "Otherwise, the embedded thumbnail of the RAW file will be used for tag suggestion." .. - "The embedded thumbnail could speedup the tag suggestion but can fail if the RAW file is not supported."), + _("if enabled, the image passed to photils for tag suggestion is based on the exported, already edited image. " .. + "otherwise, the embedded thumbnail of the RAW file will be used for tag suggestion." .. + "the embedded thumbnail could speedup the tag suggestion but can fail if the RAW file is not supported."), true) dt.register_event("photils", "mouse-over-image-changed", diff --git a/contrib/rate_group.lua b/contrib/rate_group.lua index ca85b263..4b02d5e9 100644 --- a/contrib/rate_group.lua +++ b/contrib/rate_group.lua @@ -87,37 +87,37 @@ end dt.register_event("rg_reject", "shortcut", function(event, shortcut) apply_rating(-1) -end, _("Reject group")) +end, _("reject group")) dt.register_event("rg0", "shortcut", function(event, shortcut) apply_rating(0) -end, _("Rate group 0")) +end, _("rate group 0")) dt.register_event("rg1", "shortcut", function(event, shortcut) apply_rating(1) -end, _("Rate group 1")) +end, _("rate group 1")) dt.register_event("rg2", "shortcut", function(event, shortcut) apply_rating(2) -end, _("Rate group 2")) +end, _("rate group 2")) dt.register_event("rg3", "shortcut", function(event, shortcut) apply_rating(3) -end, _("Rate group 3")) +end, _("rate group 3")) dt.register_event("rg4", "shortcut", function(event, shortcut) apply_rating(4) -end, _("Rate group 4")) +end, _("rate group 4")) dt.register_event("rg5", "shortcut", function(event, shortcut) apply_rating(5) -end, _("Rate group 5")) +end, _("rate group 5")) script_data.destroy = destroy diff --git a/contrib/rename-tags.lua b/contrib/rename-tags.lua index 4e03af77..05d94913 100644 --- a/contrib/rename-tags.lua +++ b/contrib/rename-tags.lua @@ -56,8 +56,8 @@ rt.module_installed = false rt.event_registered = false -- GUI entries -local old_tag = darktable.new_widget("entry") { tooltip = _("Enter old tag") } -local new_tag = darktable.new_widget("entry") { tooltip = _("Enter new tag") } +local old_tag = darktable.new_widget("entry") { tooltip = _("enter old tag") } +local new_tag = darktable.new_widget("entry") { tooltip = _("enter new tag") } local function rename_reset() old_tag.text = '' @@ -68,11 +68,11 @@ end local function rename_tags() -- If entries are empty, return if old_tag.text == '' then - darktable.print (_("Old tag can't be empty")) + darktable.print (_("old tag can't be empty")) return end if new_tag.text == '' then - darktable.print (_("New tag can't be empty")) + darktable.print (_("new tag can't be empty")) return end @@ -82,12 +82,12 @@ local function rename_tags() local ot = darktable.tags.find (old_tag.text) if not ot then - darktable.print (_("Old tag does not exist")) + darktable.print (_("old tag does not exist")) return end -- Show job - local job = darktable.gui.create_job (_("Renaming tag"), true) + local job = darktable.gui.create_job (_("renaming tag"), true) old_tag.editable = false new_tag.editable = false @@ -110,7 +110,7 @@ local function rename_tags() darktable.tags.delete (ot) job.valid = false - darktable.print (string.format(_("Renamed tags for %d images"), count)) + darktable.print (string.format(_("renamed tags for %d images"), count)) old_tag.editable = true new_tag.editable = true @@ -137,13 +137,13 @@ end -- GUI local old_widget = darktable.new_widget ("box") { orientation = "horizontal", - darktable.new_widget("label") { label = _("Old tag") }, + darktable.new_widget("label") { label = _("old tag") }, old_tag } local new_widget = darktable.new_widget ("box") { orientation = "horizontal", - darktable.new_widget("label") { label = _("New tag") }, + darktable.new_widget("label") { label = _("new tag") }, new_tag } @@ -152,7 +152,7 @@ rt.rename_widget = darktable.new_widget ("box") { reset_callback = rename_reset, old_widget, new_widget, - darktable.new_widget("button") { label = _("Go"), clicked_callback = rename_tags } + darktable.new_widget("button") { label = _("go"), clicked_callback = rename_tags } } if darktable.gui.current_view().id == "lighttable" then diff --git a/contrib/slideshowMusic.lua b/contrib/slideshowMusic.lua index 71bae54e..abb72137 100644 --- a/contrib/slideshowMusic.lua +++ b/contrib/slideshowMusic.lua @@ -80,12 +80,12 @@ function destroy() end -- Preferences -dt.preferences.register("slideshowMusic", "SlideshowMusic", "file", _("Slideshow background music file"), "", "") +dt.preferences.register("slideshowMusic", "SlideshowMusic", "file", _("slideshow background music file"), "", "") dt.preferences.register("slideshowMusic", "PlaySlideshowMusic", "bool", - _("Play slideshow background music"), - _("Plays music with rhythmbox if a slideshow starts"), + _("play slideshow background music"), + _("plays music with rhythmbox if a slideshow starts"), true) -- Register dt.register_event("slideshow_music", "view-changed", diff --git a/contrib/transfer_hierarchy.lua b/contrib/transfer_hierarchy.lua index 15bea2a9..6fdb2dcd 100755 --- a/contrib/transfer_hierarchy.lua +++ b/contrib/transfer_hierarchy.lua @@ -149,7 +149,7 @@ end -- Widgets and business logic: BEGIN local sourceTextBox = darktable.new_widget("entry") { - tooltip = _("Lowest directory containing all selected images"), + tooltip = _("lowest directory containing all selected images"), editable = false } sourceTextBox.reset_callback = function() sourceTextBox.text = "" end diff --git a/contrib/video_ffmpeg.lua b/contrib/video_ffmpeg.lua index 7c902ed6..63f40b58 100644 --- a/contrib/video_ffmpeg.lua +++ b/contrib/video_ffmpeg.lua @@ -293,7 +293,7 @@ else end local output_directory_chooser = dt.new_widget("file_chooser_button"){ - title = _("Select export path"), + title = _("select export path"), is_directory = true, tooltip =_("select the target directory for the timelapse. \nthe filename is created automatically."), value = string_pref_read("export_path", defaultVideoDir), From 06ab263e7494e46e54c015eff4434e5e6a57234e Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Fri, 29 Mar 2024 16:04:07 -0400 Subject: [PATCH 272/445] examples/gui_action.lua - changed nan to NaN --- examples/gui_action.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/gui_action.lua b/examples/gui_action.lua index cbf33a4a..205366ee 100644 --- a/examples/gui_action.lua +++ b/examples/gui_action.lua @@ -90,7 +90,7 @@ dt.register_lib( label = "execute action", tooltip = "execute the action specified in the fields above", clicked_callback = function(_) - local sp = nan + local sp = NaN if wg.check.value then sp = wg.speed.text end wg.return_value.text = dt.gui.action(wg.action.text, wg.instance.value, wg.element.text, wg.effect.text, sp) end @@ -102,4 +102,4 @@ dt.register_lib( wg.return_value }, } - ) \ No newline at end of file + ) From 86ee8adbce3a73660c4c441b796b7628af901106 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Mon, 1 Apr 2024 18:26:41 -0400 Subject: [PATCH 273/445] tools/script_manager - changed category/categories to folder/folders to accurately refrect reality and to open the possibility of actually categorizing scripts. --- tools/script_manager.lua | 170 +++++++++++++++++++-------------------- 1 file changed, 85 insertions(+), 85 deletions(-) diff --git a/tools/script_manager.lua b/tools/script_manager.lua index 7376ed43..f8e6c73b 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -22,9 +22,9 @@ manage the lua scripts. On startup script_manager scans the lua scripts directory to see what scripts are present. - Scripts are sorted by 'category' based on what sub-directory they are in. With no - additional script repositories iinstalled, the categories are contrib, examples, official - and tools. When a category is selected the buttons show the script name and whether the + Scripts are sorted by 'folder' based on what sub-directory they are in. With no + additional script repositories iinstalled, the folders are contrib, examples, official + and tools. When a folder is selected the buttons show the script name and whether the script is started or stopped. The button is a toggle, so if the script is stopped click the button to start it and vice versa. @@ -128,7 +128,7 @@ sm.event_registered = false -- set up tables to contain all the widgets and choices sm.widgets = {} -sm.categories = {} +sm.folders = {} -- set log level for functions @@ -137,14 +137,14 @@ sm.log_level = DEFAULT_LOG_LEVEL --[[ sm.scripts is a table of tables for containing the scripts - It is organized as into category (folder) subtables containing + It is organized as into folder (folder) subtables containing each script definition, which is a table sm.scripts- | - - category------------| + - folder------------| | - script - - category----| | + - folder----| | - script| | - script - script| @@ -152,7 +152,7 @@ sm.log_level = DEFAULT_LOG_LEVEL and a script table looks like name the name of the script file without the lua extension - path category (folder), path separator, path, name without the lua extension + path folder (folder), path separator, path, name without the lua extension doc the header comments from the script to be used as a tooltip script_name the folder, path separator, and name without the lua extension running true if running, false if not, hidden if running but the @@ -178,7 +178,7 @@ sm.page_status = {} sm.page_status.num_buttons = DEFAULT_BUTTONS_PER_PAGE sm.page_status.buttons_created = 0 sm.page_status.current_page = 0 -sm.page_status.category = "" +sm.page_status.folder = "" -- use color in the interface? sm.use_color = false @@ -348,12 +348,12 @@ end -- script handling ------------------ -local function add_script_category(category) +local function add_script_folder(folder) local old_log_level = set_log_level(sm.log_level) - if #sm.categories == 0 or not string.match(du.join(sm.categories, " "), ds.sanitize_lua(category)) then - table.insert(sm.categories, category) - sm.scripts[category] = {} - log.msg(log.debug, "created category " .. category) + if #sm.folders == 0 or not string.match(du.join(sm.folders, " "), ds.sanitize_lua(folder)) then + table.insert(sm.folders, folder) + sm.scripts[folder] = {} + log.msg(log.debug, "created folder " .. folder) end restore_log_level(old_log_level) end @@ -452,19 +452,19 @@ local function deactivate(script) restore_log_level(old_log_level) end -local function add_script_name(name, path, category) +local function add_script_name(name, path, folder) local old_log_level = set_log_level(sm.log_level) - log.msg(log.debug, "category is " .. category) + log.msg(log.debug, "folder is " .. folder) log.msg(log.debug, "name is " .. name) local script = { name = name, - path = category .. "/" .. path .. name, + path = folder .. "/" .. path .. name, running = false, - doc = get_script_doc(category .. "/" .. path .. name), - script_name = category .. "/" .. name, + doc = get_script_doc(folder .. "/" .. path .. name), + script_name = folder .. "/" .. name, data = nil } - table.insert(sm.scripts[category], script) + table.insert(sm.scripts[folder], script) if pref_read(script.script_name, "bool") then activate(script) else @@ -476,10 +476,10 @@ end local function process_script_data(script_file) local old_log_level = set_log_level(sm.log_level) - -- the script file supplied is category/filename.filetype - -- the following pattern splits the string into category, path, name, fileename, and filetype + -- the script file supplied is folder/filename.filetype + -- the following pattern splits the string into folder, path, name, fileename, and filetype -- for example contrib/gimp.lua becomes - -- category - contrib + -- folder - contrib -- path - -- name - gimp.lua -- filename - gimp @@ -496,14 +496,14 @@ local function process_script_data(script_file) log.msg(log.info, "processing " .. script_file) -- add the script data - local category,path,name,filename,filetype = string.match(script_file, pattern) + local folder,path,name,filename,filetype = string.match(script_file, pattern) - if category and name and path then - log.msg(log.debug, "category is " .. category) + if folder and name and path then + log.msg(log.debug, "folder is " .. folder) log.msg(log.debug, "name is " .. name) - add_script_category(category) - add_script_name(name, path, category) + add_script_folder(folder) + add_script_name(name, path, folder) end restore_log_level(old_log_level) @@ -594,25 +594,25 @@ local function scan_repositories() local output = io.popen(find_cmd) for line in output:lines() do local l = string.gsub(line, ds.sanitize_lua(LUA_DIR) .. PS, "") -- strip the lua dir off - local category = string.match(l, "(.-)" .. PS) -- get everything to teh first / - if category then -- if we have a category (.git doesn't) - log.msg(log.debug, "found category " .. category) - if not string.match(category, "plugins") and not string.match(category, "%.git") then -- skip plugins + local folder = string.match(l, "(.-)" .. PS) -- get everything to teh first / + if folder then -- if we have a folder (.git doesn't) + log.msg(log.debug, "found folder " .. folder) + if not string.match(folder, "plugins") and not string.match(folder, "%.git") then -- skip plugins if #sm.installed_repositories == 1 then - log.msg(log.debug, "only 1 repo, adding " .. category) - table.insert(sm.installed_repositories, {name = category, directory = LUA_DIR .. PS .. category}) + log.msg(log.debug, "only 1 repo, adding " .. folder) + table.insert(sm.installed_repositories, {name = folder, directory = LUA_DIR .. PS .. folder}) else log.msg(log.debug, "more than 1 repo, we have to search the repos to make sure it's not there") local found = nil for _, repo in ipairs(sm.installed_repositories) do - if string.match(repo.name, ds.sanitize_lua(category)) then + if string.match(repo.name, ds.sanitize_lua(folder)) then log.msg(log.debug, "matched " .. repo.name) found = true break end end if not found then - table.insert(sm.installed_repositories, {name = category, directory = LUA_DIR .. PS .. category}) + table.insert(sm.installed_repositories, {name = folder, directory = LUA_DIR .. PS .. folder}) end end end @@ -625,11 +625,11 @@ end local function install_scripts() local old_log_level = set_log_level(sm.log_level) local url = sm.widgets.script_url.text - local category = sm.widgets.new_category.text + local folder = sm.widgets.new_folder.text - if string.match(du.join(sm.categories, " "), ds.sanitize_lua(category)) then - log.msg(log.screen, _("category ") .. category .. _(" is already in use. Please specify a different category name.")) - log.msg(log.error, "category " .. category .. " already exists, returning...") + if string.match(du.join(sm.folders, " "), ds.sanitize_lua(folder)) then + log.msg(log.screen, _("folder ") .. folder .. _(" is already in use. Please specify a different folder name.")) + log.msg(log.error, "folder " .. folder .. " already exists, returning...") restore_log_level(old_log_level) return end @@ -644,7 +644,7 @@ local function install_scripts() return end - local git_command = "cd " .. LUA_DIR .. " " .. CS .. " " .. git .. " clone " .. url .. " " .. category + local git_command = "cd " .. LUA_DIR .. " " .. CS .. " " .. git .. " clone " .. url .. " " .. folder log.msg(log.debug, "update git command is " .. git_command) if dt.configuration.running_os == "windows" then @@ -656,27 +656,27 @@ local function install_scripts() log.msg(log.info, "result from import is " .. result) if result == 0 then - local count = scan_scripts(LUA_DIR .. PS .. category) + local count = scan_scripts(LUA_DIR .. PS .. folder) if count > 0 then - update_combobox_choices(sm.widgets.category_selector, sm.categories, sm.widgets.category_selector.selected) - dt.print(_("scripts successfully installed into category ") .. category) - table.insert(sm.installed_repositories, {name = category, directory = LUA_DIR .. PS .. category}) + update_combobox_choices(sm.widgets.folder_selector, sm.folders, sm.widgets.folder_selector.selected) + dt.print(_("scripts successfully installed into folder ") .. folder) + table.insert(sm.installed_repositories, {name = folder, directory = LUA_DIR .. PS .. folder}) update_script_update_choices() - for i = 1, #sm.widgets.category_selector do - if string.match(sm.widgets.category_selector[i], ds.sanitize_lua(category)) then - log.msg(log.debug, "setting category selector to " .. i) - sm.widgets.category_selector.selected = i + for i = 1, #sm.widgets.folder_selector do + if string.match(sm.widgets.folder_selector[i], ds.sanitize_lua(folder)) then + log.msg(log.debug, "setting folder selector to " .. i) + sm.widgets.folder_selector.selected = i break end i = i + 1 end log.msg(log.debug, "clearing text fields") sm.widgets.script_url.text = "" - sm.widgets.new_category.text = "" + sm.widgets.new_folder.text = "" sm.widgets.main_menu.selected = 3 else dt.print(_("No scripts found to install")) - log.msg(log.error, "scan_scripts returned " .. count .. " scripts found. Not adding to category_selector") + log.msg(log.error, "scan_scripts returned " .. count .. " scripts found. Not adding to folder_selector") end else dt.print(_("failed to download scripts")) @@ -696,10 +696,10 @@ local function clear_button(number) restore_log_level(old_log_level) end -local function find_script(category, name) +local function find_script(folder, name) local old_log_level = set_log_level(sm.log_level) - log.msg(log.debug, "looking for script " .. name .. " in category " .. category) - for _, script in ipairs(sm.scripts[category]) do + log.msg(log.debug, "looking for script " .. name .. " in folder " .. folder) + for _, script in ipairs(sm.scripts[folder]) do if string.match(script.name, "^" .. ds.sanitize_lua(name) .. "$") then return script end @@ -708,12 +708,12 @@ local function find_script(category, name) return nil end -local function populate_buttons(category, first, last) +local function populate_buttons(folder, first, last) local old_log_level = set_log_level(sm.log_level) - log.msg(log.debug, "category is " .. category .. " and first is " .. first .. " and last is " .. last) + log.msg(log.debug, "folder is " .. folder .. " and first is " .. first .. " and last is " .. last) local button_num = 1 for i = first, last do - script = sm.scripts[category][i] + script = sm.scripts[folder][i] button = sm.widgets.buttons[button_num] if script.running == true then if sm.use_color then @@ -741,7 +741,7 @@ local function populate_buttons(category, first, last) else script_name, state = string.match(this.label, "(.-) (.+)") end - local script = find_script(sm.widgets.category_selector.value, script_name) + local script = find_script(sm.widgets.folder_selector.value, script_name) if script then log.msg(log.debug, "found script " .. script.name .. " with path " .. script.path) if script.running == true then @@ -779,9 +779,9 @@ end local function paginate(direction) local old_log_level = set_log_level(sm.log_level) - local category = sm.page_status.category - log.msg(log.debug, "category is " .. category) - local num_scripts = #sm.scripts[category] + local folder = sm.page_status.folder + log.msg(log.debug, "folder is " .. folder) + local num_scripts = #sm.scripts[folder] log.msg(log.debug, "num_scripts is " .. num_scripts) local max_pages = math.ceil(num_scripts / sm.page_status.num_buttons) local cur_page = sm.page_status.current_page @@ -829,18 +829,18 @@ local function paginate(direction) end sm.widgets.page_status.label = _("Page ") .. cur_page .. _(" of ") .. max_pages - populate_buttons(category, first, last) + populate_buttons(folder, first, last) restore_log_level(old_log_level) end -local function change_category(category) +local function change_folder(folder) local old_log_level = set_log_level(sm.log_level) - if not category then - log.msg(log.debug "setting category to selector value " .. sm.widgets.category_selector.value) - sm.page_status.category = sm.widgets.category_selector.value + if not folder then + log.msg(log.debug "setting folder to selector value " .. sm.widgets.folder_selector.value) + sm.page_status.folder = sm.widgets.folder_selector.value else - log.msg(log.debug, "setting catgory to argument " .. category) - sm.page_status.category = category + log.msg(log.debug, "setting catgory to argument " .. folder) + sm.page_status.folder = folder end paginate(2) @@ -898,14 +898,14 @@ local function load_preferences() end update_script_update_choices() log.msg(log.debug, "updated installed scripts") - -- category selector - local val = pref_read("category_selector", "integer") + -- folder selector + local val = pref_read("folder_selector", "integer") if val == 0 then val = 1 end - sm.widgets.category_selector.selected = val - sm.page_status.category = sm.widgets.category_selector.value - log.msg(log.debug, "updated category selector and set it to " .. sm.widgets.category_selector.value) + sm.widgets.folder_selector.selected = val + sm.page_status.folder = sm.widgets.folder_selector.value + log.msg(log.debug, "updated folder selector and set it to " .. sm.widgets.folder_selector.value) -- num_buttons local val = pref_read("num_buttons", "integer") if val == 0 then @@ -1069,18 +1069,18 @@ sm.widgets.script_url = dt.new_widget("entry"){ tooltip = _("enter the URL of the git repository containing the scripts you wish to add") } -sm.widgets.new_category = dt.new_widget("entry"){ +sm.widgets.new_folder = dt.new_widget("entry"){ text = "", - placeholder = _("name of new category"), - tooltip = _("enter a category name for the additional scripts") + placeholder = _("name of new folder"), + tooltip = _("enter a folder name for the additional scripts") } sm.widgets.add_scripts = dt.new_widget("box"){ orientation = vertical, dt.new_widget("label"){label = _("URL to download additional scripts from")}, sm.widgets.script_url, - dt.new_widget("label"){label = _("new category to place scripts in")}, - sm.widgets.new_category, + dt.new_widget("label"){label = _("new folder to place scripts in")}, + sm.widgets.new_folder, dt.new_widget("button"){ label = _("install additional scripts"), clicked_callback = function(this) @@ -1124,17 +1124,17 @@ sm.widgets.install_update = dt.new_widget("box"){ -- manage the scripts -sm.widgets.category_selector = dt.new_widget("combobox"){ - label = _("category"), - tooltip = _( "select the script category"), +sm.widgets.folder_selector = dt.new_widget("combobox"){ + label = _("folder"), + tooltip = _( "select the script folder"), selected = 1, changed_callback = function(self) if sm.run then - pref_write("category_selector", "integer", self.selected) - change_category(self.value) + pref_write("folder_selector", "integer", self.selected) + change_folder(self.value) end end, - table.unpack(sm.categories), + table.unpack(sm.folders), } sm.widgets.buttons ={} @@ -1175,7 +1175,7 @@ sm.widgets.page_control = dt.new_widget("box"){ sm.widgets.scripts = dt.new_widget("box"){ orientation = vertical, dt.new_widget("label"){label = _("Scripts")}, - sm.widgets.category_selector, + sm.widgets.folder_selector, sm.widgets.page_control, table.unpack(sm.widgets.buttons) } From e78e718769d1f290bc59e26143a0c5c2d5b98090 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Tue, 2 Apr 2024 17:54:10 -0400 Subject: [PATCH 274/445] tools/script_manager - allow for inclusion of directory/package specific libraries by adding "local" libraries to the search path to ensure they are found when needed. --- tools/script_manager.lua | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tools/script_manager.lua b/tools/script_manager.lua index 7376ed43..bb96401c 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -509,6 +509,25 @@ local function process_script_data(script_file) restore_log_level(old_log_level) end +local function ensure_lib_in_search_path(line) + local old_log_level = set_log_level(sm.log_level) + set_log_level(log.debug) + log.msg(log.debug, "line is " .. line) + if string.match(line, ds.sanitize_lua(dt.configuration.config_dir .. PS .. "lua/lib")) then + log.msg(log.debug, line .. " is already in search path, returning...") + return + end + local path = string.match(line, "(.+)/lib/.+lua") + log.msg(log.debug, "extracted path is " .. path) + log.msg(log.debug, "package.path is " .. package.path) + if not string.match(package.path, ds.sanitize_lua(path)) then + log.msg(log.debug, "path isn't in package.path, adding...") + package.path = package.path .. ";" .. path .. "/?.lua" + log.msg(log.debug, "new package.path is " .. package.path) + end + restore_log_level(old_log_level) +end + local function scan_scripts(script_dir) local old_log_level = set_log_level(sm.log_level) local script_count = 0 @@ -529,6 +548,8 @@ local function scan_scripts(script_dir) process_script_data(script_file) script_count = script_count + 1 end + else + ensure_lib_in_search_path(line) -- but let's make sure libraries can be found end end end From a11726889d42bcb7fc9f3dcc0705855fd601b22b Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Tue, 2 Apr 2024 19:09:31 -0400 Subject: [PATCH 275/445] tools/script_manager - add support for "local" libraries by adding entries in the package.path search path if required --- contrib/micharambou | 1 + data/icons/power.png | Bin 0 -> 426 bytes data/icons/poweroff.png | Bin 0 -> 599 bytes development | 1 + tools/script_manager.lua | 21 +++++++++++++++++++++ 5 files changed, 23 insertions(+) create mode 120000 contrib/micharambou create mode 100644 data/icons/power.png create mode 100644 data/icons/poweroff.png create mode 120000 development diff --git a/contrib/micharambou b/contrib/micharambou new file mode 120000 index 00000000..bbe4f2d2 --- /dev/null +++ b/contrib/micharambou @@ -0,0 +1 @@ +/home/bill/src/dtluadev/gitannex/micharambou/ \ No newline at end of file diff --git a/data/icons/power.png b/data/icons/power.png new file mode 100644 index 0000000000000000000000000000000000000000..f9d1fe578f888f3ecf937287e3d94e05a112229d GIT binary patch literal 426 zcmV;b0agBqP)pF8FWQhbW?9;ba!ELWdL_~cP?peYja~^aAhuUa%Y?FJQ@H10XIoR zK~yM_jgmhvL{SjM&%9Oo7YTMLGz%ws)~H1CJIeN?*DO=dPQvs*J86J2)w%92d49tXMh`uaSc>rGa1kT+Q2jL<*^NH0T%jy08L>r U|26I@$^ZZW07*qoM6N<$g6#{bzW@LL literal 0 HcmV?d00001 diff --git a/data/icons/poweroff.png b/data/icons/poweroff.png new file mode 100644 index 0000000000000000000000000000000000000000..1fb1e75c828d38f907b7ff7556dc73de0455ff10 GIT binary patch literal 599 zcmV-d0;v6oP)pF8FWQhbW?9;ba!ELWdL_~cP?peYja~^aAhuUa%Y?FJQ@H10pv+U zK~yM_jgY--lTjGOf6sm2bnzpxR7tEc5sm0#Qi^uaKR~1y-av7%Aa!zZut@(0QOV+0 zce_YYQ$HZ6xL7QeYLh__ba_pn6&(~EY~SWS4sTLZNs4E=mwV57&N+`m7o>9eQ_=Y0 zg;?TH^~dsuPn|fXn^=)!z;;!Jx^djUPTqu~7c9=ndgcDde~JBB@1P@E7WB4XnYq61 zoXqCO6uk7yg@&HC=i4)?1t4xlh) z>hB(w5ncj)HVB?{8;}|-B#gL^fnMN6ty+5K0vI=Pwh;vL0)sXP-Y0Wj(LtXQi7e~t zN&;hswPDAB9f0qw+0k&BO(X|S?-n)pfD>JF3$MhOGydBLOB=+k?^M?FtS~C*5YPvF lQ)J$#z3W$JN@3j)e*jLFrNd8l&ny4{002ovPDHLkV1h8c408Yg literal 0 HcmV?d00001 diff --git a/development b/development new file mode 120000 index 00000000..1c69f2fb --- /dev/null +++ b/development @@ -0,0 +1 @@ +/home/bill/src/lua-scripts.local/development/ \ No newline at end of file diff --git a/tools/script_manager.lua b/tools/script_manager.lua index f8e6c73b..d54f9e6f 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -509,6 +509,25 @@ local function process_script_data(script_file) restore_log_level(old_log_level) end +local function ensure_lib_in_search_path(line) + local old_log_level = set_log_level(sm.log_level) + set_log_level(log.debug) + log.msg(log.debug, "line is " .. line) + if string.match(line, ds.sanitize_lua(dt.configuration.config_dir .. PS .. "lua/lib")) then + log.msg(log.debug, line .. " is already in search path, returning...") + return + end + local path = string.match(line, "(.+)/lib/.+lua") + log.msg(log.debug, "extracted path is " .. path) + log.msg(log.debug, "package.path is " .. package.path) + if not string.match(package.path, ds.sanitize_lua(path)) then + log.msg(log.debug, "path isn't in package.path, adding...") + package.path = package.path .. ";" .. path .. "/?.lua" + log.msg(log.debug, "new package.path is " .. package.path) + end + restore_log_level(old_log_level) +end + local function scan_scripts(script_dir) local old_log_level = set_log_level(sm.log_level) local script_count = 0 @@ -529,6 +548,8 @@ local function scan_scripts(script_dir) process_script_data(script_file) script_count = script_count + 1 end + else + ensure_lib_in_search_path(line) -- but let's make sure libraries can be found end end end From 9c4e906033df371c66e17b8c9d8c070837ce0784 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Fri, 5 Apr 2024 20:37:34 -0400 Subject: [PATCH 276/445] data/icons - added 20px icons --- data/icons/blank20.png | Bin 0 -> 5678 bytes data/icons/path20.png | Bin 0 -> 6265 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 data/icons/blank20.png create mode 100644 data/icons/path20.png diff --git a/data/icons/blank20.png b/data/icons/blank20.png new file mode 100644 index 0000000000000000000000000000000000000000..81ed51574807dde06248d05f94fe17aad24b193a GIT binary patch literal 5678 zcmeHKd010d7Eff8SY$^*g%A|$60$=Q2*bWqK$g^iqLAdhK!7YHfh4SoUw6r(JBzi;}VN#4u5=brOB=lt%u_uZT6 z@8_w5Fhjs#Fdc6%w?OFM2)c~tYeILA?(3B>nC627daxvrDMboJ0uDC@L`vjB5DCh- z92iV?_i6B^eGjd_c^6?EGSAB^ZD`zKrG5JgamHraEfOi$Z)Mm4(f(Mti3`Jvv8*R7 zb!=SAkzSj=c0=t6k0ep&UNiIWnjD|r3%WL(@~(X{IHBJn|DIa9jYr3?T}LLTJyR15 zg(RKzFZPz=$F|L+l=iI&k{d`cZKw4InSE)0pm#ntlU4Se=DAm0ZtimlVQ7`o?McUi@UT6Mc^jjkx>L~$$P z?(Wf~U#p#GYQ9r*;KlV;kG-0D>l6lzyFjR11V8dXQF5S9;vI3v%#(c5_>_ZTd0^Vv zbcSP6MsD-jdW($0`@E#{8WSiH+f~Q&`m-WUw_lobR$o!%j=p(t9vUY;sS1LiNM}z(onbsZ!Gm;Az`--*8O6X(;k>+xd0aBzf5ZI;M&Z~+H0ID;irl=%}*)aHYhjvxmANR!jZ`5tVTzG9e z;Ao|5N{uND@cbuHj!N-4WZQA7rmA+}yET}QpJVoZ&-hJP*U214Z>oQKZj>*mEPLDQ z7-r#w{=M?1^VOAimqd+_5_fu;`?cZJ!i_}p?myB~9R4>hd&Q8??qasdnnC(}XYbf+ z98ufW@GY4@g;xAF8@FW*>jzENwp_}YStYu7_$^Y@fB!Y2?lCuVY1`?b5s#c*w|;p3 zz1b^Md0EsYT`cNgVdnm*aSJcAM4i+>Zk~AJ8_l{vlTIqs-UU|)xGBB$9WNS|++V#V zrl`R)GJzUrn_@SwE@^(%&-syI3uH|ej%x;kJy~*C`qL*V+?#y=NDZ-Jf2eZay<~T`xwisXyIyKG(zi zxy8=&%hS8Eq1z8T$=ixsJ)$4#%qq4?CcI^)yABr|`_(sD+P5g2d}M*`eZ1nr){RlJ zGn9~+Dc8it{tLFd?L*mqvR(1dfeEvl7YI8W zgFL*RA+3)`TIZ}WDKUrrEQT-dBuf{Y!u6jY-hN81pD)j{gS^K z<1%J<`efz&=CSuOqsZ{(pDv7N?LBLgMHY9=tmx9J7)u_S*3Co4)b4nsZLVhilRsXc zLGOLo(=M=lXV06ula8S<^{+M;EcWPZDp=&wwC#4mT`e+nX_os)N4o=dX!UWs_Tt9SGS?7-TrRC7pn6UX3T$S|!xN@7 z-oRk+bgrwbzqhOFhu0nSk}FQ$L-V@iZwLlV2 z`qa2+JKf?D3ckx~m_E__HcKxV{tap^p`)na7%^#dw1j$m?7l-s%d@UO7z<3)=AmNK zOv`VoONu8mkDgk4vTeA{(0W?d3Mc)s+!l7H#$}t$>4#}T8}-gsC`K1^fc<~%2to!8R{w%eC>}D z&vVbGWQHOdR);?fcG58ee$}1PY>9|AuCTsv%*$Xz9$TD?E0r#aBrP3&+Z(%arPH|S z`Csg3HX0VaTYll@O_rxZVJnRN{bnI;K%})e1rG$pmm$%IgVp=GMh?7C+(7GXdHJZP z@5*Dfyt0ro!Pf1r;Z1ILMja=|MoWHcp*?-`4)#h{Bzd%q*8*)z%(&3@BiPr6$`J^U^Qnbc;vNryybtJqT8Qb;E)Ek2iUn~ZHs~G?@+DTELICWK_QE((j4B;~ zjR9jo9;7OUyy8A{>FMq3|ItE8K?Ij4R9Qh}f2Jwna{eOgv)Gh9s&qaL1Tz1K`O~8&*hUe`@Ln-}J0Rfu}P*smO4iT^=67A4LTNa2WQa~n}$!25G910c$ zNH`pc$YFm1<;@pMn0z*LC#En9y)?dCUk9BjiV@I+TP{o&CLOD7+2!FNuE)Q^J7^Xeb{pKTh^n2c63UgCtBP zn>afh9!DV%30OSIj)0wuS%tR&6p5iqRAS<=HiS7`<*-npWFTUh$~uJrRIpGkR96wm zln6w0fgpy4QbHh=ma6hbI?N4<7gr2v$dwiUzUG6#*tyo+6o}!fx{yd!*+MMOIT17C zK|tjQvYYE-M>6>lAT+<<7t{wi_kRo)heM%Y32a+58^?sk8(?4{yOl0d}tRWg^n|0uSeRTqmU+Rou?aY zR{1TxP*DI$w1r+FVi;`UCFKRbBB%r)p_atk*IjEwT^+8En0a<&5E7YqyE)Uz9qjPM j8b`y8cBKVi5t^$Yz%m%T)O4pCqyh7G_j5b#5}x)S(L1|$ literal 0 HcmV?d00001 diff --git a/data/icons/path20.png b/data/icons/path20.png new file mode 100644 index 0000000000000000000000000000000000000000..1021d86405b81bbfa10a78e4ea7e8de8651462dd GIT binary patch literal 6265 zcmeH~c|26@`^Se0i3}x0dZrh=5n)9dy7{@2W$nK}1;UGMw4KKFI*bDsofCmVTLRapoG zB5!AF=?eZX2M=W#De&9+aZ@e?BGnh>?#*{431A#9o5lzPVEj-H00V>!8U!MII^w;x zL_=F{ny&04X=@wZKW?nOq2aAt*0YT3YnpYF!-39rM>W5-?&dmOS7yKP;!Vdhv(`}y zvpn#<$pHneJ`tCL9 zFZEGjmmT`89^8bMS;xkQE)kW&&Ii263@a;9E?zMezGTn#k(pUQDm>=-ZQ@nR4X@oZ zXXM*XM>}cx9%6N#VlV2bG~(1+Y!rME>qfeDQ?}<2g7c)cG9pIWite?%Pz_btE`ZC+K`}m%ZhqnK730>TM zI?Q(@P|$p2UHEIIvuW0~Ua*=bk052?he+K{_DfRiOI7ESP=~$r z&g5yvjz;cXs1I9fxKk=n#~?Dbs47BFWzu=saXq+>mX!zx+}9EL51AFN+PYNhJk9fx zukJRkVx6OIPU|Bb594@n{fYdmL;h+7B}Q+`f#H(vAzdR0zBdv_hCeLJ%~8V> zZ9iM?&f2%5D1QIT9?RAG5bL$tFxFCu)oH7Xyj`1KHW<+gm7L6i%rI3|>B8aVH(WIO-jl*pt@l{($a^}z z;Lv_8pf^W#+J^irVA3to6JYx;8y>k{CcS2`-hYq%yV{EF$D6yLUK8ZnMicXvmb{{g zc*Wd)3%|#ymQy>b`ew#2O0F4;XUlYSL2rpZxpW(^Jl)oDL)h%Fi7^qXapYm*;aK^% zoabc=(wB})6fm!O7iQFJss-?N#uRJ4_S|hyN?L!%Vb#QieVNyI)}Bs2;{&+f4f%lw z2+ODPJA$_^ZOC~jGIn?&)p9qAAI(dbmvi0m&s5rj74&Gq7D!oQ#X#iFCo7>@<5O2Q zBuRaZ6ty*W8Y|Csz3^c*X2~YV?~Zb7-FvC!gYT$Z^>I41`s<-7zn6+%qxRdIPX;TV zh#iM2YA3mM_#H0q`O7fr$i~H}7!3c|`x|*WIMl77x)=I(tOOM;H`_%2lzIsnTh(<=rmDWWy~I9qX=T)?jKskE z&PuW$-M;%%zzEx{a?#9+_s^F|CR)T=20mZ(q2{E|2~e3+4NopQevsVuZZt*l(T4qY zI%#%&2jVVBM~-fT*y%T^TU&3k3?GCA?1-gikZo197*rFkke`BX(is}e&t8A)_?>BJ zQq5`Gb!XS{g16}0GThpg<)+%u*m1X^?zA0kRYRQ=aV!VAR^4Tv2paV!jk>+Z6rN1( zD{%oPlwZ}AS3G#U;VRz#?@pVN+cJ;0>u$B(YQH5|O-3z0Gc>wBG9HoQP^YX+xQ>6T zpB<4S|NQj$dTl-PCjzC~+*5+LS@|;j&J6(ywsL2kV=xPfVLC@@NF#l^psV?ij{s8y+H1ZY-FZ% zI7BWd&AG{J*`$5*^<>%H-N=&}k(`osD4B@r%}75brPp^eZ}&fGzkd7z8U1y!)>{7~ zri?QOg_4^%ni8LHrEw$wIu|LMT=2yCu4>%Ax6HE@$flzNThaX@r$+VRU8j1D<>T%Z z%iRe*fcW&x)EMJ6THREIzOh=9E`S!)n_>4a8-%Sy$kIP0W=~3(yZ2!14`{n2nR8bt zy;bP@Izp&>9zClNU6pb3iyz0pWaG)c^oJCJs8`nzhK$iE7!1DZNFP$1exI`QY~p@b z8LsdIG)%ERLCtT-+R>=ZHSX-9S36e-O?$#uKP`367T!xgGrfi&DsY&(QPK0f@PW3O z^V)~z_Yf+)Zl#PO&0t}v8+`t)IZKs-C@TU zX-Cy#%T;Wui(kBGCO@ve<>MvoWd@y=2nyl2@{cNw*~=ox4uZkd*P(&W+M1NH25d*l*heSez%yE+$gVe75UDn(cG6t^s^ zcXzxHzILGSZs@@x&-|i~MxW(17VQB}4gX_(v<7}0W)>Sw)XA-}PM;;NUxEGS@Angl z*Y+lClfAC9>!tT5c~xq=!mLy!JwW+_*3E2NrNPjk^hC^Afr=k~^}tj|kgxWp@m1Fz zZJ704c5+7Z=EH|%o2n`TC#dUTipdME^vboVD|KcixGhm-fZGpmM+YK>%|w!@ zY%+ipGCAP(1OhQO6>>yK$=ML`TP_6)v9n7TwRv`e3ukka2O8Mc>3FZdQr9-8l zfIxr=n)1L=F~1CHW9R7n!$T|qox$YHd4Xd8V##OF{uS$&*u*_^>HHiB=>CKIi}m;1 z=ZrxsM@OP1n-VMz&(6{WE*_sqWm6bb;{0C#N5&W$8Y1vm8VP~J7@!d(l0F7OGs55~ zcnk?o!5jR9vSac1Bo+k_qd+*40dmNO1^|^r!XS){NFV}FAs~zl0StmdBVcg)hGd*R z4fhjb3zq>_B`NUdsKh8Lh|)I#a0Ubt9)ZSE&|oxF0>Y3+Fhl@o10zEM8K4o!ggF$I zLbPUcnIv#J8B7u#Kyg^~xel@5L^EeQ6F3%${us95EKIS=|C&1-_l_+Ln&`AAxu6SCAU^1YvBypXBfH^Ff3(=LQ1(=DR3P*}(p1PRjMaS_}LDu})|#4uJ+g`tDc^5kny2 zvEV5YjfSJXC5#eZ)!#EVM*Sa6jOPq~S_VMB`8IHQ0aq*3kLBu{W?~uti?45U@n0MP zME@D&xAgrZ*B`llOM%}q{!?9lA{5yC7?L1)FVqE5J{4q zrJ1|oz0}rw7d?UHQsd9dD!c9k_`0vT;$VJNiUiY)J9oqrhC7yPmz?%q1_jPq{liOhS5q)pEPGKbjdP_!P_dBr=6E z23K4?>ThJfH(sha9+Msxy1C1_Kc_DIfV-N=cm^obM~gJ_@IT^*eYlEg#jmmeyOynJ!{do)8eGidEWAN3)SPXYZklWq)3{VUBUHS6Vb&?OZ;D_z;!%DI>+7Hr9y>-(&z{uGP{Y+J zb=Rz&?ksH+iJE#jDe857E)$lwJN{nVxpF~>;x<-Vnx;r(zj$P`@9uLUz0+~IY0bgmF+l+%ZJpC Date: Fri, 5 Apr 2024 20:38:10 -0400 Subject: [PATCH 277/445] tools/script_manager added parser for script_data.metadata blocks in scripts. Parsed data block is used as the tooltip. Fallback is the comment block at the top of the script. --- tools/script_manager.lua | 158 +++++++++++++++++++++++++++------------ 1 file changed, 109 insertions(+), 49 deletions(-) diff --git a/tools/script_manager.lua b/tools/script_manager.lua index d54f9e6f..39072052 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -68,7 +68,7 @@ end -- api check -du.check_min_api_version("5.0.0", "script_manager") +du.check_min_api_version("9.3.0", "script_manager") -- - - - - - - - - - - - - - - - - - - - - - - - -- C O N S T A N T S @@ -93,6 +93,10 @@ local LUA_SCRIPT_REPO = "https://github.com/darktable-org/lua-scripts.git" local LUA_API_VER = "API-" .. dt.configuration.api_version_string +-- local POWER_ICON = dt.configuration.config_dir .. "/lua/data/data/icons/power.png" +local POWER_ICON = dt.configuration.config_dir .. "/lua/data/icons/path20.png" +local BLANK_ICON = dt.configuration.config_dir .. "/lua/data/icons/blank20.png" + -- - - - - - - - - - - - - - - - - - - - - - - - -- P R E F E R E N C E S -- - - - - - - - - - - - - - - - - - - - - - - - @@ -344,6 +348,10 @@ local function string_dequote(str) return string.gsub(str, "['\"]", "") end +local function string_dei18n(str) + return string.match(str, "%_%((.+)%)") +end + ------------------ -- script handling ------------------ @@ -358,6 +366,51 @@ local function add_script_folder(folder) restore_log_level(old_log_level) end +local function get_script_metadata(script) + local old_log_level = set_log_level(sm.log_level) + -- set_log_level(log.debug) + + log.msg(log.debug, "processing metatdata for " .. script) + + local description = nil + local metadata = nil + + f = io.open(LUA_DIR .. PS .. script .. ".lua") + if f then + -- slurp the file + local content = f:read("*all") + f:close() + -- grab the script_data.metadata table + description = string.match(content, "script_data%.metadata = %{\r?\n(.-)\r?\n%}") + else + log.msg(log.error, _("Cant read from " .. script)) + end + + if description then + metadata = "" + -- format it into a string block for display + local lines = du.split(description, "\n") + log.msg(log.debug, "got " .. #lines .. " lines") + local first = 1 + for i = 1, #lines do + log.msg(log.debug, "splitting line " .. lines[i]) + local parts = du.split(lines[i], " = ") + log.msg(log.debug, "got value " .. parts[1] .. " and data " .. parts[2]) + if string.match(parts[2], "%_%(") then + parts[2] = _(string_dequote(string_dei18n(parts[2]))) + else + parts[2] = string_dequote(parts[2]) + end + metadata = metadata .. string.format("%s%-10s\t%s", first and "" or "\n", parts[1], parts[2]) + first = nil + end + log.msg(log.debug, "script data is \n" .. metadata) + end + + restore_log_level(old_log_level) + return metadata +end + local function get_script_doc(script) local old_log_level = set_log_level(sm.log_level) local description = nil @@ -461,6 +514,7 @@ local function add_script_name(name, path, folder) path = folder .. "/" .. path .. name, running = false, doc = get_script_doc(folder .. "/" .. path .. name), + metadata = get_script_metadata(folder .. "/" .. path .. name), script_name = folder .. "/" .. name, data = nil } @@ -511,7 +565,7 @@ end local function ensure_lib_in_search_path(line) local old_log_level = set_log_level(sm.log_level) - set_log_level(log.debug) + -- set_log_level(log.debug) log.msg(log.debug, "line is " .. line) if string.match(line, ds.sanitize_lua(dt.configuration.config_dir .. PS .. "lua/lib")) then log.msg(log.debug, line .. " is already in search path, returning...") @@ -710,10 +764,12 @@ end local function clear_button(number) local old_log_level = set_log_level(sm.log_level) local button = sm.widgets.buttons[number] - button.label = "" + local label = sm.widgets.labels[number] + button.image = BLANK_ICON button.tooltip = "" button.sensitive = false - --button.name = "" + label.label = "" + button.name = "" restore_log_level(old_log_level) end @@ -734,58 +790,36 @@ local function populate_buttons(folder, first, last) log.msg(log.debug, "folder is " .. folder .. " and first is " .. first .. " and last is " .. last) local button_num = 1 for i = first, last do - script = sm.scripts[folder][i] - button = sm.widgets.buttons[button_num] + local script = sm.scripts[folder][i] + local button = sm.widgets.buttons[button_num] + local label = sm.widgets.labels[button_num] if script.running == true then - if sm.use_color then - button.label = script.name - button.name = "sm_started" - else - button.label = script.name .. _(" started") - end + button.name = "pb_on" else - if sm.use_color then - button.label = script.name - button.name = "sm_stopped" - else - button.label = script.name .. _(" stopped") - end + button.name = "pb_off" end - button.ellipsize = "middle" + button.image = POWER_ICON + label.label = script.name + label.name = "pb_label" + button.ellipsize = "end" button.sensitive = true - button.tooltip = script.doc + label.tooltip = script.metadata and script.metadata or script.doc button.clicked_callback = function (this) - local script_name = nil + local cb_script = script local state = nil - if sm.use_color then - script_name = string.match(this.label, "(.+)") - else - script_name, state = string.match(this.label, "(.-) (.+)") - end - local script = find_script(sm.widgets.folder_selector.value, script_name) - if script then - log.msg(log.debug, "found script " .. script.name .. " with path " .. script.path) - if script.running == true then - log.msg(log.debug, "deactivating " .. script.name .. " on " .. script.path .. " for button " .. this.label) - deactivate(script) - if sm.use_color then - this.name = "sm_stopped" - else - this.label = script.name .. _(" stopped") - end + if cb_script then + log.msg(log.debug, "found script " .. cb_script.name .. " with path " .. cb_script.path) + if cb_script.running == true then + log.msg(log.debug, "deactivating " .. cb_script.name .. " on " .. cb_script.path) + deactivate(cb_script) + this.name = "pb_off" else - log.msg(log.debug, "activating " .. script.name .. " on " .. script.path .. " for button " .. this.label) - local result = activate(script) + log.msg(log.debug, "activating " .. cb_script.name .. " on " .. script.path) + local result = activate(cb_script) if result then - if sm.use_color then - this.name = "sm_started" - else - this.label = script.name .. " started" - end + this.name = "pb_on" end end - else - log.msg(log.error, "script " .. script_name .. " not found") end end button_num = button_num + 1 @@ -870,18 +904,34 @@ end local function change_num_buttons() local old_log_level = set_log_level(sm.log_level) + -- set_log_level(log.debug) cur_buttons = sm.page_status.num_buttons new_buttons = sm.widgets.num_buttons.value pref_write("num_buttons", "integer", new_buttons) if new_buttons < cur_buttons then + log.msg(log.debug, "took new is less than current branch") for i = 1, cur_buttons - new_buttons do table.remove(sm.widgets.scripts) end log.msg(log.debug, "finished removing widgets, now there are " .. #sm.widgets.buttons) elseif new_buttons > cur_buttons then + log.msg(log.debug, "took new is greater than current branch") + log.msg(log.debug, "number of scripts is " .. #sm.widgets.scripts) + log.msg(log.debug, "number of buttons is " .. #sm.widgets.buttons) + log.msg(log.debug, "number of labels is " .. #sm.widgets.labels) + log.msg(log.debug, "number of boxes is " .. #sm.widgets.boxes) if new_buttons > sm.page_status.buttons_created then for i = sm.page_status.buttons_created + 1, new_buttons do + log.msg(log.debug, "i is " .. i) table.insert(sm.widgets.buttons, dt.new_widget("button"){}) + log.msg(log.debug, "inserted new button") + log.msg(log.debug, "number of buttons is " .. #sm.widgets.buttons) + table.insert(sm.widgets.labels, dt.new_widget("label"){}) + log.msg(log.debug, "inserted new label") + log.msg(log.debug, "number of labels is " .. #sm.widgets.labels) + table.insert(sm.widgets.boxes, dt.new_widget("box"){ orientation = "horizontal", expand = false, fill = false, + sm.widgets.buttons[i], sm.widgets.labels[i]}) + log.msg(log.debug, "inserted new box") sm.page_status.buttons_created = sm.page_status.buttons_created + 1 end end @@ -889,7 +939,7 @@ local function change_num_buttons() log.msg(log.debug, #sm.widgets.buttons .. " buttons are available") for i = cur_buttons + 1, new_buttons do log.msg(log.debug, "inserting button " .. i .. " into scripts widget") - table.insert(sm.widgets.scripts, sm.widgets.buttons[i]) + table.insert(sm.widgets.scripts, sm.widgets.boxes[i]) end log.msg(log.debug, "finished adding widgets, now there are " .. #sm.widgets.buttons) else -- no change @@ -1158,10 +1208,20 @@ sm.widgets.folder_selector = dt.new_widget("combobox"){ table.unpack(sm.folders), } +-- a script "button" consists of: +-- a button to start and stop the script +-- a label that contains the name of the script +-- a horizontal box that contains the button and the label + sm.widgets.buttons ={} +sm.widgets.labels = {} +sm.widgets.boxes = {} for i =1, DEFAULT_BUTTONS_PER_PAGE do table.insert(sm.widgets.buttons, dt.new_widget("button"){}) - sm.page_status.buttons_create = sm.page_status.buttons_created + 1 + table.insert(sm.widgets.labels, dt.new_widget("label"){}) + table.insert(sm.widgets.boxes, dt.new_widget("box"){ orientation = "horizontal", expand = false, fill = false, + sm.widgets.buttons[i], sm.widgets.labels[i]}) + sm.page_status.buttons_created = sm.page_status.buttons_created + 1 end local page_back = "<" @@ -1198,7 +1258,7 @@ sm.widgets.scripts = dt.new_widget("box"){ dt.new_widget("label"){label = _("Scripts")}, sm.widgets.folder_selector, sm.widgets.page_control, - table.unpack(sm.widgets.buttons) + table.unpack(sm.widgets.boxes) } -- configure options From 3b0ff3475a13dca20df22c706d95bc10a60f58ea Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Fri, 5 Apr 2024 21:12:45 -0400 Subject: [PATCH 278/445] tools/script_manager added blank lines to improve code readability --- tools/script_manager.lua | 177 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 174 insertions(+), 3 deletions(-) diff --git a/tools/script_manager.lua b/tools/script_manager.lua index 39072052..435768c3 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -216,17 +216,24 @@ end local function pref_read(name, pref_type) local old_log_level = set_log_level(sm.log_level) + log.msg(log.debug, "name is " .. name .. " and type is " .. pref_type) + local val = dt.preferences.read(MODULE, name, pref_type) + log.msg(log.debug, "read value " .. tostring(val)) + restore_log_level(old_log_level) return val end local function pref_write(name, pref_type, value) local old_log_level = set_log_level(sm.log_level) + log.msg(log.debug, "writing value " .. tostring(value) .. " for name " .. name) + dt.preferences.write(MODULE, name, pref_type, value) + restore_log_level(old_log_level) end @@ -236,12 +243,15 @@ end local function get_repo_status(repo) local old_log_level = set_log_level(sm.log_level) + local p = io.popen("cd " .. repo .. CS .. "git status") + if p then local data = p:read("*a") p:close() return data end + log.msg(log.error, "unable to get status of " .. repo) restore_log_level(old_log_level) return nil @@ -249,8 +259,11 @@ end local function get_current_repo_branch(repo) local old_log_level = set_log_level(sm.log_level) + local branch = nil + local p = io.popen("cd " .. repo .. CS .. "git branch --all") + if p then local data = p:read("*a") p:close() @@ -258,23 +271,29 @@ local function get_current_repo_branch(repo) for _, b in ipairs(branches) do log.msg(log.debug, "branch for testing is " .. b) branch = string.match(b, "^%* (.-)$") + if branch then log.msg(log.info, "current repo branch is " .. branch) return branch end + end end + if not branch then log.msg(log.error, "no current branch detected in repo_data") end + restore_log_level(old_log_level) return nil end local function get_repo_branches(repo) local old_log_level = set_log_level(sm.log_level) + local branches = {} local p = io.popen("cd " .. repo .. CS .. "git pull --all" .. CS .. "git branch --all") + if p then local data = p:read("*a") p:close() @@ -289,12 +308,14 @@ local function get_repo_branches(repo) end end end + restore_log_level(old_log_level) return branches end local function is_repo_clean(repo_data) local old_log_level = set_log_level(sm.log_level) + if string.match(repo_data, "\n%s-%a.-%a:%s-%a%g-\n") then log.msg(log.info, "repo is dirty") return false @@ -302,13 +323,17 @@ local function is_repo_clean(repo_data) log.msg(log.info, "repo is clean") return true end + restore_log_level(old_log_level) end local function checkout_repo_branch(repo, branch) local old_log_level = set_log_level(sm.log_level) + log.msg(log.info, "checkout out branch " .. branch .. " from repository " .. repo) + os.execute("cd " .. repo .. CS .. "git checkout " .. branch) + restore_log_level(old_log_level) end @@ -318,16 +343,20 @@ end local function update_combobox_choices(combobox, choice_table, selected) local old_log_level = set_log_level(sm.log_level) + local items = #combobox local choices = #choice_table + for i, name in ipairs(choice_table) do combobox[i] = name end + if choices < items then for j = items, choices + 1, -1 do combobox[j] = nil end end + if not selected then selected = 1 end @@ -338,8 +367,10 @@ end local function string_trim(str) local old_log_level = set_log_level(sm.log_level) + local result = string.gsub(str, "^%s+", "") result = string.gsub(result, "%s+$", "") + restore_log_level(old_log_level) return result end @@ -358,11 +389,13 @@ end local function add_script_folder(folder) local old_log_level = set_log_level(sm.log_level) + if #sm.folders == 0 or not string.match(du.join(sm.folders, " "), ds.sanitize_lua(folder)) then table.insert(sm.folders, folder) sm.scripts[folder] = {} log.msg(log.debug, "created folder " .. folder) end + restore_log_level(old_log_level) end @@ -435,18 +468,26 @@ end local function activate(script) local old_log_level = set_log_level(sm.log_level) + local status = nil -- status of start function local err = nil -- error message returned if module doesn't start + log.msg(log.info, "activating " .. script.name) + if script.running == false then + script_manager_running_script = script.name + status, err = du.prequire(script.path) log.msg(log.debug, "prequire returned " .. tostring(status) .. " and for err " .. tostring(err)) + script_manager_running_script = nil + if status then pref_write(script.script_name, "bool", true) log.msg(log.screen, _("Loaded ") .. script.script_name) script.running = true + if err ~= true then log.msg(log.debug, "got lib data") script.data = err @@ -456,17 +497,20 @@ local function activate(script) else script.data = nil end + else log.msg(log.screen, script.script_name .. _(" failed to load")) log.msg(log.error, "Error loading " .. script.script_name) log.msg(log.error, "Error message: " .. err) end + else -- script is a lib and loaded but hidden and the user wants to reload script.data.restart() script.running = true status = true pref_write(script.script_name, "bool", true) end + restore_log_level(old_log_level) return status end @@ -481,9 +525,13 @@ local function deactivate(script) -- deactivate it.... local old_log_level = set_log_level(sm.log_level) + pref_write(script.script_name, "bool", false) + if script.data then + script.data.destroy() + if script.data.destroy_method then if string.match(script.data.destroy_method, "hide") then script.running = "hidden" @@ -495,20 +543,26 @@ local function deactivate(script) package.loaded[script.script_name] = nil script.running = false end + log.msg(log.info, "turned off " .. script.script_name) log.msg(log.screen, script.name .. _(" stopped")) + else script.running = false + log.msg(log.info, "setting " .. script.script_name .. " to not start") log.msg(log.screen, script.name .. _(" will not start when darktable is restarted")) end + restore_log_level(old_log_level) end local function add_script_name(name, path, folder) local old_log_level = set_log_level(sm.log_level) + log.msg(log.debug, "folder is " .. folder) log.msg(log.debug, "name is " .. name) + local script = { name = name, path = folder .. "/" .. path .. name, @@ -518,12 +572,15 @@ local function add_script_name(name, path, folder) script_name = folder .. "/" .. name, data = nil } + table.insert(sm.scripts[folder], script) + if pref_read(script.script_name, "bool") then activate(script) else pref_write(script.script_name, "bool", false) end + restore_log_level(old_log_level) end @@ -565,31 +622,43 @@ end local function ensure_lib_in_search_path(line) local old_log_level = set_log_level(sm.log_level) - -- set_log_level(log.debug) + log.msg(log.debug, "line is " .. line) + if string.match(line, ds.sanitize_lua(dt.configuration.config_dir .. PS .. "lua/lib")) then log.msg(log.debug, line .. " is already in search path, returning...") return end + local path = string.match(line, "(.+)/lib/.+lua") + log.msg(log.debug, "extracted path is " .. path) log.msg(log.debug, "package.path is " .. package.path) + if not string.match(package.path, ds.sanitize_lua(path)) then + log.msg(log.debug, "path isn't in package.path, adding...") + package.path = package.path .. ";" .. path .. "/?.lua" + log.msg(log.debug, "new package.path is " .. package.path) end + restore_log_level(old_log_level) end local function scan_scripts(script_dir) local old_log_level = set_log_level(sm.log_level) + local script_count = 0 local find_cmd = "find -L " .. script_dir .. " -name \\*.lua -print | sort" + if dt.configuration.running_os == "windows" then find_cmd = "dir /b/s \"" .. script_dir .. "\\*.lua\" | sort" end + log.msg(log.debug, _("find command is ") .. find_cmd) + -- scan the scripts local output = io.popen(find_cmd) for line in output:lines() do @@ -608,6 +677,7 @@ local function scan_scripts(script_dir) end end end + restore_log_level(old_log_level) return script_count end @@ -646,39 +716,54 @@ end local function update_script_update_choices() local old_log_level = set_log_level(sm.log_level) + local installs = {} local pref_string = "" + for i, repo in ipairs(sm.installed_repositories) do table.insert(installs, repo.name) pref_string = pref_string .. i .. "," .. repo.name .. "," .. repo.directory .. "," end + update_combobox_choices(sm.widgets.update_script_choices, installs, 1) + log.msg(log.debug, "repo pref string is " .. pref_string) pref_write("installed_repos", "string", pref_string) + restore_log_level(old_log_level) end local function scan_repositories() local old_log_level = set_log_level(sm.log_level) + local script_count = 0 local find_cmd = "find -L " .. LUA_DIR .. " -name \\*.git -print | sort" + if dt.configuration.running_os == "windows" then find_cmd = "dir /b/s /a:d " .. LUA_DIR .. PS .. "*.git | sort" end + log.msg(log.debug, _("find command is ") .. find_cmd) + local output = io.popen(find_cmd) + for line in output:lines() do local l = string.gsub(line, ds.sanitize_lua(LUA_DIR) .. PS, "") -- strip the lua dir off - local folder = string.match(l, "(.-)" .. PS) -- get everything to teh first / + local folder = string.match(l, "(.-)" .. PS) -- get everything to the first / + if folder then -- if we have a folder (.git doesn't) + log.msg(log.debug, "found folder " .. folder) + if not string.match(folder, "plugins") and not string.match(folder, "%.git") then -- skip plugins + if #sm.installed_repositories == 1 then log.msg(log.debug, "only 1 repo, adding " .. folder) table.insert(sm.installed_repositories, {name = folder, directory = LUA_DIR .. PS .. folder}) else log.msg(log.debug, "more than 1 repo, we have to search the repos to make sure it's not there") local found = nil + for _, repo in ipairs(sm.installed_repositories) do if string.match(repo.name, ds.sanitize_lua(folder)) then log.msg(log.debug, "matched " .. repo.name) @@ -686,19 +771,24 @@ local function scan_repositories() break end end + if not found then table.insert(sm.installed_repositories, {name = folder, directory = LUA_DIR .. PS .. folder}) end + end end end end + update_script_update_choices() + restore_log_level(old_log_level) end local function install_scripts() local old_log_level = set_log_level(sm.log_level) + local url = sm.widgets.script_url.text local folder = sm.widgets.new_folder.text @@ -732,11 +822,13 @@ local function install_scripts() if result == 0 then local count = scan_scripts(LUA_DIR .. PS .. folder) + if count > 0 then update_combobox_choices(sm.widgets.folder_selector, sm.folders, sm.widgets.folder_selector.selected) dt.print(_("scripts successfully installed into folder ") .. folder) table.insert(sm.installed_repositories, {name = folder, directory = LUA_DIR .. PS .. folder}) update_script_update_choices() + for i = 1, #sm.widgets.folder_selector do if string.match(sm.widgets.folder_selector[i], ds.sanitize_lua(folder)) then log.msg(log.debug, "setting folder selector to " .. i) @@ -745,6 +837,7 @@ local function install_scripts() end i = i + 1 end + log.msg(log.debug, "clearing text fields") sm.widgets.script_url.text = "" sm.widgets.new_folder.text = "" @@ -753,6 +846,7 @@ local function install_scripts() dt.print(_("No scripts found to install")) log.msg(log.error, "scan_scripts returned " .. count .. " scripts found. Not adding to folder_selector") end + else dt.print(_("failed to download scripts")) end @@ -763,47 +857,59 @@ end local function clear_button(number) local old_log_level = set_log_level(sm.log_level) + local button = sm.widgets.buttons[number] local label = sm.widgets.labels[number] + button.image = BLANK_ICON button.tooltip = "" button.sensitive = false label.label = "" button.name = "" + restore_log_level(old_log_level) end local function find_script(folder, name) local old_log_level = set_log_level(sm.log_level) + log.msg(log.debug, "looking for script " .. name .. " in folder " .. folder) + for _, script in ipairs(sm.scripts[folder]) do if string.match(script.name, "^" .. ds.sanitize_lua(name) .. "$") then return script end end + restore_log_level(old_log_level) return nil end local function populate_buttons(folder, first, last) local old_log_level = set_log_level(sm.log_level) + log.msg(log.debug, "folder is " .. folder .. " and first is " .. first .. " and last is " .. last) + local button_num = 1 + for i = first, last do local script = sm.scripts[folder][i] local button = sm.widgets.buttons[button_num] local label = sm.widgets.labels[button_num] + if script.running == true then button.name = "pb_on" else button.name = "pb_off" end + button.image = POWER_ICON label.label = script.name label.name = "pb_label" button.ellipsize = "end" button.sensitive = true label.tooltip = script.metadata and script.metadata or script.doc + button.clicked_callback = function (this) local cb_script = script local state = nil @@ -822,23 +928,30 @@ local function populate_buttons(folder, first, last) end end end + button_num = button_num + 1 end + if button_num <= sm.page_status.num_buttons then for i = button_num, sm.page_status.num_buttons do clear_button(i) end end + restore_log_level(old_log_level) end local function paginate(direction) local old_log_level = set_log_level(sm.log_level) + local folder = sm.page_status.folder log.msg(log.debug, "folder is " .. folder) + local num_scripts = #sm.scripts[folder] log.msg(log.debug, "num_scripts is " .. num_scripts) + local max_pages = math.ceil(num_scripts / sm.page_status.num_buttons) + local cur_page = sm.page_status.current_page log.msg(log.debug, "max pages is " .. max_pages) @@ -860,7 +973,9 @@ local function paginate(direction) log.msg(log.debug, "took path 2") cur_page = 1 end + log.msg(log.debug, "cur_page is " .. cur_page .. " and max_pages is " .. max_pages) + if cur_page == max_pages and cur_page == 1 then sm.widgets.page_forward.sensitive = false sm.widgets.page_back.sensitive = false @@ -876,20 +991,25 @@ local function paginate(direction) end sm.page_status.current_page = cur_page + first = (cur_page * sm.page_status.num_buttons) - (sm.page_status.num_buttons - 1) + if first + sm.page_status.num_buttons > num_scripts then last = num_scripts else last = first + sm.page_status.num_buttons - 1 end + sm.widgets.page_status.label = _("Page ") .. cur_page .. _(" of ") .. max_pages populate_buttons(folder, first, last) + restore_log_level(old_log_level) end local function change_folder(folder) local old_log_level = set_log_level(sm.log_level) + if not folder then log.msg(log.debug "setting folder to selector value " .. sm.widgets.folder_selector.value) sm.page_status.folder = sm.widgets.folder_selector.value @@ -899,20 +1019,25 @@ local function change_folder(folder) end paginate(2) + restore_log_level(old_log_level) end local function change_num_buttons() local old_log_level = set_log_level(sm.log_level) - -- set_log_level(log.debug) + cur_buttons = sm.page_status.num_buttons new_buttons = sm.widgets.num_buttons.value + pref_write("num_buttons", "integer", new_buttons) + if new_buttons < cur_buttons then log.msg(log.debug, "took new is less than current branch") + for i = 1, cur_buttons - new_buttons do table.remove(sm.widgets.scripts) end + log.msg(log.debug, "finished removing widgets, now there are " .. #sm.widgets.buttons) elseif new_buttons > cur_buttons then log.msg(log.debug, "took new is greater than current branch") @@ -920,7 +1045,9 @@ local function change_num_buttons() log.msg(log.debug, "number of buttons is " .. #sm.widgets.buttons) log.msg(log.debug, "number of labels is " .. #sm.widgets.labels) log.msg(log.debug, "number of boxes is " .. #sm.widgets.boxes) + if new_buttons > sm.page_status.buttons_created then + for i = sm.page_status.buttons_created + 1, new_buttons do log.msg(log.debug, "i is " .. i) table.insert(sm.widgets.buttons, dt.new_widget("button"){}) @@ -934,73 +1061,97 @@ local function change_num_buttons() log.msg(log.debug, "inserted new box") sm.page_status.buttons_created = sm.page_status.buttons_created + 1 end + end + log.msg(log.debug, "cur_buttons is " .. cur_buttons .. " and new_buttons is " .. new_buttons) log.msg(log.debug, #sm.widgets.buttons .. " buttons are available") + for i = cur_buttons + 1, new_buttons do log.msg(log.debug, "inserting button " .. i .. " into scripts widget") table.insert(sm.widgets.scripts, sm.widgets.boxes[i]) end + log.msg(log.debug, "finished adding widgets, now there are " .. #sm.widgets.buttons) else -- no change log.msg(log.debug, "no change, just returning") return end + sm.page_status.num_buttons = new_buttons log.msg(log.debug, "num_buttons set to " .. sm.page_status.num_buttons) paginate(2) -- force the buttons to repopulate sm.widgets.main_menu.selected = 3 -- jump back to start/stop scripts + restore_log_level(old_log_level) end local function load_preferences() local old_log_level = set_log_level(sm.log_level) + -- load the prefs and update settings -- update_script_choices + local pref_string = pref_read("installed_repos", "string") local entries = du.split(pref_string, ",") + while #entries > 2 do local num = table.remove(entries, 1) local name = table.remove(entries, 1) local directory = table.remove(entries, 1) + if not string.match(sm.installed_repositories[1].name, "^" .. ds.sanitize_lua(name) .. "$") then table.insert(sm.installed_repositories, {name = name, directory = directory}) end + end + update_script_update_choices() log.msg(log.debug, "updated installed scripts") + -- folder selector local val = pref_read("folder_selector", "integer") + if val == 0 then val = 1 end + sm.widgets.folder_selector.selected = val sm.page_status.folder = sm.widgets.folder_selector.value log.msg(log.debug, "updated folder selector and set it to " .. sm.widgets.folder_selector.value) + -- num_buttons local val = pref_read("num_buttons", "integer") + if val == 0 then val = DEFAULT_BUTTONS_PER_PAGE end + sm.widgets.num_buttons.value = val log.msg(log.debug, "set page buttons to " .. val) + change_num_buttons() log.msg(log.debug, "paginated") + -- main menu local val = pref_read("main_menu_action", "integer") log.msg(log.debug, "read " .. val .. " for main menu") + if val == 0 then val = 3 end + sm.widgets.main_menu.selected = val log.msg(log.debug, "set main menu to val " .. val .. " which is " .. sm.widgets.main_menu.value) log.msg(log.debug, "set main menu to " .. sm.widgets.main_menu.value) + restore_log_level(old_log_level) end local function install_module() local old_log_level = set_log_level(sm.log_level) + if not sm.module_installed then dt.register_lib( "script_manager", -- Module name @@ -1014,6 +1165,7 @@ local function install_module() ) sm.module_installed = true end + sm.run = true sm.use_color = pref_read("use_color", "bool") log.msg(log.debug, "set run to true, loading preferences") @@ -1030,6 +1182,7 @@ local function install_module() dt.control.sleep(5000) dt.print_log("setting sm expanded true") dt.gui.libs["script_manager"].expanded = true]] + restore_log_level(old_log_level) end @@ -1048,22 +1201,28 @@ if check_for_updates then local repo = LUA_DIR if current_branch then + if sm.executables.git and clean and + (current_branch == "master" or string.match(current_branch, "^API%-")) then -- only make changes to clean branches local branches = get_repo_branches(LUA_DIR) + if current_branch ~= LUA_API_VER and current_branch ~= "master" then -- probably upgraded from an earlier api version so get back to master -- to use the latest version of script_manager to get the proper API checkout_repo_branch(repo, "master") log.msg(log.screen, "lua API version reset, please restart darktable") + elseif LUA_API_VER == current_branch then -- do nothing, we are fine log.msg(log.debug, "took equal branch, doing nothing") + elseif string.match(LUA_API_VER, "dev") then -- we are on a dev API version, so checkout the dev -- api version or checkout/stay on master log.msg(log.debug, "took the dev branch") local match = false + for _, branch in ipairs(branches) do log.msg(log.debug, "checking branch " .. branch .. " against API " .. LUA_API_VER) if LUA_API_VER == branch then @@ -1072,6 +1231,7 @@ if check_for_updates then checkout_repo_branch(repo, branch) end end + if not match then if current_branch == "master" then log.msg(log.info, "staying on master, no dev branch yet") @@ -1080,25 +1240,33 @@ if check_for_updates then checkout_repo_branch(repo, "master") end end + elseif #branches > 0 and LUA_API_VER > branches[#branches] then log.msg(log.info, "no newer branches, staying on master") -- stay on master + else -- checkout the appropriate branch for API version if it exists log.msg(log.info, "checking out the appropriate API branch") + local match = false + for _, branch in ipairs(branches) do log.msg(log.debug, "checking branch " .. branch .. " against API " .. LUA_API_VER) + if LUA_API_VER == branch then match = true log.msg(log.info, "checking out repo branch " .. branch) checkout_repo_branch(repo, branch) log.msg(log.screen, "you must restart darktable to use the correct version of the lua") end + end + if not match then log.msg(log.warn, "no matching branch found for " .. LUA_API_VER) end + end end end @@ -1216,6 +1384,7 @@ sm.widgets.folder_selector = dt.new_widget("combobox"){ sm.widgets.buttons ={} sm.widgets.labels = {} sm.widgets.boxes = {} + for i =1, DEFAULT_BUTTONS_PER_PAGE do table.insert(sm.widgets.buttons, dt.new_widget("button"){}) table.insert(sm.widgets.labels, dt.new_widget("label"){}) @@ -1228,6 +1397,7 @@ local page_back = "<" local page_forward = ">" sm.widgets.page_status = dt.new_widget("label"){label = _("Page:")} + sm.widgets.page_back = dt.new_widget("button"){ label = page_back, clicked_callback = function(this) @@ -1297,6 +1467,7 @@ sm.widgets.color = dt.new_widget("check_button"){ sm.use_color = this.value end } + table.insert(sm.widgets.configure, sm.widgets.color) -- stack for the options From ddf0c8940208bfe79c5a67aa2aa43ac71ad87ac1 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sat, 6 Apr 2024 21:28:58 -0400 Subject: [PATCH 279/445] tools/script_manager - cleaned up layout of panels and added some spacing so what is being operated on is more appearent --- tools/script_manager.lua | 44 +++++++++++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/tools/script_manager.lua b/tools/script_manager.lua index 435768c3..6e60af3b 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -1351,14 +1351,25 @@ sm.widgets.disable_scripts = dt.new_widget("button"){ sm.widgets.install_update = dt.new_widget("box"){ orientation = "vertical", - dt.new_widget("section_label"){label = _("update scripts")}, + dt.new_widget("section_label"){label = _(" ")}, + dt.new_widget("label"){label = " "}, + dt.new_widget("label"){label = _("update scripts")}, + dt.new_widget("label"){label = " "}, sm.widgets.update_script_choices, sm.widgets.update, - dt.new_widget("section_label"){label = _("add more scripts")}, + dt.new_widget("section_label"){label = " "}, + dt.new_widget("label"){label = " "}, + dt.new_widget("label"){label = _("add more scripts")}, + dt.new_widget("label"){label = " "}, sm.widgets.add_scripts, - dt.new_widget("section_label"){label = _("disable scripts")}, + dt.new_widget("section_label"){label = " "}, + dt.new_widget("label"){label = " "}, + dt.new_widget("label"){label = _("disable scripts")}, + dt.new_widget("label"){label = " "}, sm.widgets.allow_disable, - sm.widgets.disable_scripts + sm.widgets.disable_scripts, + dt.new_widget("section_label"){label = " "}, + dt.new_widget("label"){label = " "}, } -- manage the scripts @@ -1425,10 +1436,12 @@ sm.widgets.page_control = dt.new_widget("box"){ sm.widgets.scripts = dt.new_widget("box"){ orientation = vertical, + dt.new_widget("section_label"){label = _(" ")}, + dt.new_widget("label"){label = " "}, dt.new_widget("label"){label = _("Scripts")}, sm.widgets.folder_selector, sm.widgets.page_control, - table.unpack(sm.widgets.boxes) + table.unpack(sm.widgets.boxes), } -- configure options @@ -1452,13 +1465,6 @@ sm.widgets.change_buttons = dt.new_widget("button"){ end } -sm.widgets.configure = dt.new_widget("box"){ - orientation = "vertical", - dt.new_widget("label"){label = _("Configuration")}, - sm.widgets.num_buttons, - sm.widgets.change_buttons, -} - sm.widgets.color = dt.new_widget("check_button"){ label = _("use color interface?"), value = pref_read("use_color", "bool"), @@ -1468,7 +1474,21 @@ sm.widgets.color = dt.new_widget("check_button"){ end } +sm.widgets.configure = dt.new_widget("box"){ + orientation = "vertical", + dt.new_widget("section_label"){label = " "}, + dt.new_widget("label"){label = " "}, + dt.new_widget("label"){label = _("Configuration")}, + dt.new_widget("label"){label = " "}, + sm.widgets.num_buttons, + dt.new_widget("label"){label = " "}, + sm.widgets.change_buttons, + dt.new_widget("label"){label = " "}, +} + table.insert(sm.widgets.configure, sm.widgets.color) +table.insert(sm.widgets.configure, dt.new_widget("section_label"){label = " "}) +table.insert(sm.widgets.configure, dt.new_widget("label"){label = " "}) -- stack for the options From 125af63bda044b4b72625d2c35ade9634f95d037 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sat, 6 Apr 2024 21:48:51 -0400 Subject: [PATCH 280/445] tools/script_manager - revert ensure_lib_in_path because of windows problems. --- tools/script_manager.lua | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/tools/script_manager.lua b/tools/script_manager.lua index bb96401c..31a72280 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -509,25 +509,6 @@ local function process_script_data(script_file) restore_log_level(old_log_level) end -local function ensure_lib_in_search_path(line) - local old_log_level = set_log_level(sm.log_level) - set_log_level(log.debug) - log.msg(log.debug, "line is " .. line) - if string.match(line, ds.sanitize_lua(dt.configuration.config_dir .. PS .. "lua/lib")) then - log.msg(log.debug, line .. " is already in search path, returning...") - return - end - local path = string.match(line, "(.+)/lib/.+lua") - log.msg(log.debug, "extracted path is " .. path) - log.msg(log.debug, "package.path is " .. package.path) - if not string.match(package.path, ds.sanitize_lua(path)) then - log.msg(log.debug, "path isn't in package.path, adding...") - package.path = package.path .. ";" .. path .. "/?.lua" - log.msg(log.debug, "new package.path is " .. package.path) - end - restore_log_level(old_log_level) -end - local function scan_scripts(script_dir) local old_log_level = set_log_level(sm.log_level) local script_count = 0 @@ -549,7 +530,7 @@ local function scan_scripts(script_dir) script_count = script_count + 1 end else - ensure_lib_in_search_path(line) -- but let's make sure libraries can be found + -- ensure_lib_in_search_path(line) -- but let's make sure libraries can be found end end end From 63d5aad465b6d1c537c48e73013c900805fff00e Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Mon, 8 Apr 2024 23:30:30 -0400 Subject: [PATCH 281/445] tools/script_manager reimplemented ensure_lib_in_path with a windows aware path specification --- tools/script_manager.lua | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/tools/script_manager.lua b/tools/script_manager.lua index 31a72280..6dcd6b6c 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -509,6 +509,35 @@ local function process_script_data(script_file) restore_log_level(old_log_level) end +local function ensure_lib_in_search_path(line) + local old_log_level = set_log_level(sm.log_level) + set_log_level(log.debug) + + log.msg(log.debug, "line is " .. line) + + if string.match(line, ds.sanitize_lua(dt.configuration.config_dir .. PS .. "lua" .. PS .. "lib")) then + log.msg(log.debug, line .. " is already in search path, returning...") + return + end + + local pattern = dt.configuration.running_os == "windows" and "(.+)\\lib\\.+lua" or "(.+)/lib/.+lua" + local path = string.match(line, pattern) + + log.msg(log.debug, "extracted path is " .. path) + log.msg(log.debug, "package.path is " .. package.path) + + if not string.match(package.path, ds.sanitize_lua(path)) then + + log.msg(log.debug, "path isn't in package.path, adding...") + + package.path = package.path .. ";" .. path .. "/?.lua" + + log.msg(log.debug, "new package.path is " .. package.path) + end + + restore_log_level(old_log_level) +end + local function scan_scripts(script_dir) local old_log_level = set_log_level(sm.log_level) local script_count = 0 @@ -530,7 +559,7 @@ local function scan_scripts(script_dir) script_count = script_count + 1 end else - -- ensure_lib_in_search_path(line) -- but let's make sure libraries can be found + ensure_lib_in_search_path(line) -- but let's make sure libraries can be found end end end From b1b3392b92ae816502ca7fd97528d2ab7ce4e9a0 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Tue, 9 Apr 2024 21:41:42 -0400 Subject: [PATCH 282/445] tools/script_manager removed color interface check button. Color can be specified in the CSS using the tags that are present if desired. Cleaned up formatting of configuration items. Added a few debugging messages. --- tools/script_manager.lua | 25 ++++++------------------- 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/tools/script_manager.lua b/tools/script_manager.lua index 6e60af3b..2313e309 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -184,9 +184,6 @@ sm.page_status.buttons_created = 0 sm.page_status.current_page = 0 sm.page_status.folder = "" --- use color in the interface? -sm.use_color = false - -- installed script repositories sm.installed_repositories = { {name = "lua-scripts", directory = LUA_DIR}, @@ -630,7 +627,8 @@ local function ensure_lib_in_search_path(line) return end - local path = string.match(line, "(.+)/lib/.+lua") + local pattern = dt.configuration.running_os == "windows" and "(.+)\\lib\\.+lua" or "(.+)/lib/.+lua" + local path = string.match(line, pattern) log.msg(log.debug, "extracted path is " .. path) log.msg(log.debug, "package.path is " .. package.path) @@ -657,11 +655,12 @@ local function scan_scripts(script_dir) find_cmd = "dir /b/s \"" .. script_dir .. "\\*.lua\" | sort" end - log.msg(log.debug, _("find command is ") .. find_cmd) + log.msg(log.debug, "find command is " .. find_cmd) -- scan the scripts local output = io.popen(find_cmd) for line in output:lines() do + log.msg(log.debug, "line is " .. line) local l = string.gsub(line, ds.sanitize_lua(LUA_DIR) .. PS, "") -- strip the lua dir off local script_file = l:sub(1,-5) -- strip off .lua\n if not string.match(script_file, "script_manager") then -- let's not include ourself @@ -1334,6 +1333,8 @@ sm.widgets.allow_disable = dt.new_widget("check_button"){ clicked_callback = function(this) if this.value == true then sm.widgets.disable_scripts.sensitive = true + else + sm.widgets.disable_scripts.sensitive = false end end, } @@ -1368,7 +1369,6 @@ sm.widgets.install_update = dt.new_widget("box"){ dt.new_widget("label"){label = " "}, sm.widgets.allow_disable, sm.widgets.disable_scripts, - dt.new_widget("section_label"){label = " "}, dt.new_widget("label"){label = " "}, } @@ -1465,15 +1465,6 @@ sm.widgets.change_buttons = dt.new_widget("button"){ end } -sm.widgets.color = dt.new_widget("check_button"){ - label = _("use color interface?"), - value = pref_read("use_color", "bool"), - clicked_callback = function(this) - pref_write("use_color", "bool", this.value) - sm.use_color = this.value - end -} - sm.widgets.configure = dt.new_widget("box"){ orientation = "vertical", dt.new_widget("section_label"){label = " "}, @@ -1486,10 +1477,6 @@ sm.widgets.configure = dt.new_widget("box"){ dt.new_widget("label"){label = " "}, } -table.insert(sm.widgets.configure, sm.widgets.color) -table.insert(sm.widgets.configure, dt.new_widget("section_label"){label = " "}) -table.insert(sm.widgets.configure, dt.new_widget("label"){label = " "}) - -- stack for the options sm.widgets.main_stack = dt.new_widget("stack"){ From 52b4508e08474163c6e3f99ff8e5aa490f4d71b9 Mon Sep 17 00:00:00 2001 From: Christian Sueltrop Date: Mon, 6 May 2024 21:53:46 +0200 Subject: [PATCH 283/445] Added LUA script "passport_guide_germany.lua", which implements a cropping guide for passport photos according to the standards for German passport and ID card photos. --- contrib/passport_guide_germany.lua | 105 +++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 contrib/passport_guide_germany.lua diff --git a/contrib/passport_guide_germany.lua b/contrib/passport_guide_germany.lua new file mode 100644 index 00000000..f020ae7d --- /dev/null +++ b/contrib/passport_guide_germany.lua @@ -0,0 +1,105 @@ +--[[ + German passport photo cropping guide for darktable. + Derived from the passport cropping guide by Kåre Hampf. + + copyright (c) 2017 Kåre Hampf + copyright (c) 2024 Christian Sültrop + + darktable is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + darktable is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with darktable. If not, see . +]] + +--[[ +PASSPORT CROPPING GUIDE +Guides for cropping passport and ID card ("Personalausweis") photos based on the "Passbild-Schablone" +from the German Federal Ministry of the Interior and Community. +(https://www.bmi.bund.de/SharedDocs/downloads/DE/veroeffentlichungen/themen/moderne-verwaltung/ausweise/passbild-schablone-erwachsene.pdf?__blob=publicationFile&v=3) + +INSTALLATION +* copy this file in $CONFIGDIR/lua/ where CONFIGDIR is your darktable configuration directory +* add the following line in the file $CONFIGDIR/luarc + require "passport_guide_germany" +* (optional) add the line: + "plugins/darkroom/clipping/extra_aspect_ratios/passport 35x45mm=45:35" + to $CONFIGDIR/darktablerc + +USAGE +* when using the cropping tool, select "Passport Photo Germany" as guide and if you added the line in yout rc + select "passport 35x45mm" as aspect +]] + +local dt = require "darktable" +local du = require "lib/dtutils" +local gettext = dt.gettext + +du.check_min_api_version("2.0.0", "passport_guide_germany") + +-- Tell gettext where to find the .mo file translating messages for a particular domain +gettext.bindtextdomain("passport_guide_germany",dt.configuration.config_dir.."/lua/locale/") + +local function _(msgid) + return gettext.dgettext("passport_guide_germany", msgid) +end + +dt.guides.register_guide("Passport Photo Germany", +-- draw +function(cairo, x, y, width, height, zoom_scale) + local _width, _height + + -- get the max 35x45 rectangle + local aspect_ratio = 45 / 35 + if width * aspect_ratio > height then + _width = height / aspect_ratio + _height = height + else + _width = width + _height = width * aspect_ratio + end + + cairo:save() + + cairo:translate(x + (width - _width) / 2, y + (height - _height) / 2) + cairo:scale(_width / 35, _height / 45) + + -- the outer rectangle + cairo:rectangle( 0, 0, 35, 45) + + -- Nose position: The nose tip must be between these lines + cairo:draw_line(15.5, 45, 15.5, 13) + cairo:draw_line(35-15.5, 45, 35-15.5, 13) + + -- Face height + -- optimum face height: The upper end of the head should be between these lines + cairo:draw_line(0, 4, 35, 4) + cairo:draw_line(0, 8, 35, 8) + + -- tolerated face height: The upper end of the head must not be below this line + cairo:draw_line(6, 13, 30, 13) + + -- Eye area: The eyes must be between these lines + cairo:draw_line(0, 13, 35, 13) + cairo:draw_line(0, 23, 35, 23) + + -- Cheek line: The cheek must lie on this line + cairo:draw_line(9, 45-5, 27, 45-5) + + cairo:restore() +end, +-- gui +function() + return dt.new_widget("label"){label = _("Passport Photo Germany"), halign = "start"} +end +) + +-- kate: tab-indents: off; indent-width 2; replace-tabs on; remove-trailing-space on; hl Lua; +-- vim: shiftwidth=2 expandtab tabstop=2 cindent syntax=lua From cd3788f0129f0704e1191dc9667dc4e3333061e3 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Tue, 14 May 2024 22:39:22 -0400 Subject: [PATCH 284/445] all scripts - added bindtextdomain back in because 4.8 isn't ready to handle the translations yet. In 5.0 this will be removed and darktable will handle translating the strings. --- contrib/AutoGrouper.lua | 1 + contrib/CollectHelper.lua | 2 ++ contrib/HDRMerge.lua | 2 ++ contrib/LabelsToTags.lua | 2 ++ contrib/OpenInExplorer.lua | 2 ++ contrib/RL_out_sharp.lua | 2 ++ contrib/autostyle.lua | 1 + contrib/change_group_leader.lua | 2 ++ contrib/clear_GPS.lua | 1 + contrib/color_profile_manager.lua | 2 ++ contrib/copy_attach_detach_tags.lua | 2 ++ contrib/cr2hdr.lua | 2 ++ contrib/cycle_group_leader.lua | 2 ++ contrib/enfuseAdvanced.lua | 2 ++ contrib/exportLUT.lua | 2 ++ contrib/ext_editor.lua | 2 ++ contrib/face_recognition.lua | 2 ++ contrib/fujifilm_ratings.lua | 2 ++ contrib/geoJSON_export.lua | 2 ++ contrib/geoToolbox.lua | 2 ++ contrib/gimp.lua | 2 ++ contrib/gpx_export.lua | 2 ++ contrib/harmonic_armature_guide.lua | 2 ++ contrib/hif_group_leader.lua | 2 ++ contrib/hugin.lua | 2 ++ contrib/image_stack.lua | 2 ++ contrib/image_time.lua | 2 ++ contrib/jpg_group_leader.lua | 2 ++ contrib/kml_export.lua | 2 ++ contrib/passport_guide.lua | 2 ++ contrib/pdf_slideshow.lua | 2 ++ contrib/photils.lua | 2 ++ contrib/quicktag.lua | 2 ++ contrib/rate_group.lua | 2 ++ contrib/rename-tags.lua | 2 ++ contrib/rename_images.lua | 2 ++ contrib/select_non_existing.lua | 2 ++ contrib/select_untagged.lua | 2 ++ contrib/slideshowMusic.lua | 2 ++ contrib/transfer_hierarchy.lua | 2 ++ contrib/video_ffmpeg.lua | 2 ++ examples/api_version.lua | 2 ++ examples/darkroom_demo.lua | 6 ++++-- examples/gettextExample.lua | 2 ++ examples/hello_world.lua | 2 ++ examples/lighttable_demo.lua | 2 ++ examples/moduleExample.lua | 2 ++ examples/multi_os.lua | 2 ++ examples/panels_demo.lua | 4 +++- examples/preferenceExamples.lua | 2 ++ examples/printExamples.lua | 2 ++ examples/running_os.lua | 2 ++ official/copy_paste_metadata.lua | 2 ++ official/enfuse.lua | 2 ++ official/generate_image_txt.lua | 2 ++ official/import_filter_manager.lua | 2 ++ official/save_selection.lua | 2 ++ official/selection_to_pdf.lua | 2 ++ tools/executable_manager.lua | 2 ++ tools/script_manager.lua | 2 ++ 60 files changed, 120 insertions(+), 3 deletions(-) diff --git a/contrib/AutoGrouper.lua b/contrib/AutoGrouper.lua index decc9b93..4d8ced3b 100644 --- a/contrib/AutoGrouper.lua +++ b/contrib/AutoGrouper.lua @@ -53,6 +53,7 @@ script_data.restart = nil -- how to restart the (lib) script after it's been hid script_data.show = nil -- only required for libs since the destroy_method only hides them local gettext = dt.gettext.gettext +gettext.bindtextdomain(MOD, dt.configuration.config_dir .."/lua/locale/") local function _(msgid) return gettext(msgid) diff --git a/contrib/CollectHelper.lua b/contrib/CollectHelper.lua index 7e72d55f..4e37f06f 100644 --- a/contrib/CollectHelper.lua +++ b/contrib/CollectHelper.lua @@ -62,6 +62,8 @@ script_data.destroy_method = nil -- set to hide for libs since we can't destroy script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again script_data.show = nil -- only required for libs since the destroy_method only hides them +gettext.bindtextdomain("CollectHelper", dt.configuration.config_dir .."/lua/locale/") + local function _(msgid) return gettext(msgid) end diff --git a/contrib/HDRMerge.lua b/contrib/HDRMerge.lua index c4fd75b8..f365ec42 100644 --- a/contrib/HDRMerge.lua +++ b/contrib/HDRMerge.lua @@ -69,6 +69,8 @@ local CURR_API_STRING = dt.configuration.api_version_string -- Tell gettext where to find the .mo file translating messages for a particular domain local gettext = dt.gettext.gettext +gettext.bindtextdomain("HDRMerge", dt.configuration.config_dir .."/lua/locale/") + local function _(msgid) return gettext(msgid) end diff --git a/contrib/LabelsToTags.lua b/contrib/LabelsToTags.lua index bc3a212c..c41c6ad6 100644 --- a/contrib/LabelsToTags.lua +++ b/contrib/LabelsToTags.lua @@ -54,6 +54,8 @@ du.check_min_api_version("7.0.0", "LabelsToTags") local gettext = dt.gettext.gettext +gettext.bindtextdomain("LabelsToTags", dt.configuration.config_dir .."/lua/locale/") + local function _(msgid) return gettext(msgid) end diff --git a/contrib/OpenInExplorer.lua b/contrib/OpenInExplorer.lua index 522e92b8..d375af75 100644 --- a/contrib/OpenInExplorer.lua +++ b/contrib/OpenInExplorer.lua @@ -65,6 +65,8 @@ script_data.destroy_method = nil -- set to hide for libs since we can't destroy script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again script_data.show = nil -- only required for libs since the destroy_method only hides them +gettext.bindtextdomain("OpenInExplorer", dt.configuration.config_dir .."/lua/locale/") + local function _(msgid) return gettext(msgid) end diff --git a/contrib/RL_out_sharp.lua b/contrib/RL_out_sharp.lua index 44d961eb..fcbfb5c0 100644 --- a/contrib/RL_out_sharp.lua +++ b/contrib/RL_out_sharp.lua @@ -80,6 +80,8 @@ local PS = dt.configuration.running_os == "windows" and "\\" or "/" -- translation local gettext = dt.gettext.gettext +gettext.bindtextdomain("RL_out_sharp", dt.configuration.config_dir .."/lua/locale/") + local function _(msgid) return gettext(msgid) end diff --git a/contrib/autostyle.lua b/contrib/autostyle.lua index 4c1284e2..426b76fd 100644 --- a/contrib/autostyle.lua +++ b/contrib/autostyle.lua @@ -43,6 +43,7 @@ local filelib = require "lib/dtutils.file" du.check_min_api_version("7.0.0", "autostyle") local gettext = darktable.gettext.gettext +gettext.bindtextdomain("autostyle", dt.configuration.config_dir .."/lua/locale/") local function _(msgid) return gettext(msgid) diff --git a/contrib/change_group_leader.lua b/contrib/change_group_leader.lua index 0c70ac34..b70310df 100644 --- a/contrib/change_group_leader.lua +++ b/contrib/change_group_leader.lua @@ -40,6 +40,8 @@ local gettext = dt.gettext.gettext local MODULE = "change_group_leader" +gettext.bindtextdomain(MODULE, dt.configuration.config_dir .."/lua/locale/") + du.check_min_api_version("3.0.0", MODULE) -- return data structure for script_manager diff --git a/contrib/clear_GPS.lua b/contrib/clear_GPS.lua index 7e12e094..da915027 100644 --- a/contrib/clear_GPS.lua +++ b/contrib/clear_GPS.lua @@ -49,6 +49,7 @@ script_data.restart = nil -- how to restart the (lib) script after it's been hid script_data.show = nil -- only required for libs since the destroy_method only hides them local gettext = dt.gettext.gettext +gettext.bindtextdomain("clear_GPS", dt.configuration.config_dir .."/lua/locale/") -- not a number local NaN = 0/0 diff --git a/contrib/color_profile_manager.lua b/contrib/color_profile_manager.lua index b8ef21f2..61b40284 100644 --- a/contrib/color_profile_manager.lua +++ b/contrib/color_profile_manager.lua @@ -54,6 +54,8 @@ du.check_min_api_version("7.0.0", "color_profile_manager") local gettext = dt.gettext.gettext +gettext.bindtextdomain("color_profile_manager", dt.configuration.config_dir .."/lua/locale/") + local function _(msgid) return gettext(msgid) end diff --git a/contrib/copy_attach_detach_tags.lua b/contrib/copy_attach_detach_tags.lua index de78f13e..fb9f4870 100644 --- a/contrib/copy_attach_detach_tags.lua +++ b/contrib/copy_attach_detach_tags.lua @@ -53,6 +53,8 @@ script_data.destroy_method = nil -- set to hide for libs since we can't destroy script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again script_data.show = nil -- only required for libs since the destroy_method only hides them +gettext.bindtextdomain("copy_attach_detach_tags", dt.configuration.config_dir .."/lua/locale/") + local function _(msgid) return gettext(msgid) end diff --git a/contrib/cr2hdr.lua b/contrib/cr2hdr.lua index 8b6f54d3..04232c27 100644 --- a/contrib/cr2hdr.lua +++ b/contrib/cr2hdr.lua @@ -39,6 +39,8 @@ du.check_min_api_version("7.0.0", "cr2hdr") local gettext = dt.gettext.gettext +gettext.bindtextdomain("cr2hdr", dt.configuration.config_dir .."/lua/locale/") + local function _(msgid) return gettext(msgid) end diff --git a/contrib/cycle_group_leader.lua b/contrib/cycle_group_leader.lua index d2bf3da5..1b8d6841 100644 --- a/contrib/cycle_group_leader.lua +++ b/contrib/cycle_group_leader.lua @@ -71,6 +71,8 @@ script_data.show = nil -- only required for libs since the destroy_method only h local gettext = dt.gettext.gettext +gettext.bindtextdomain("cycle_group_leader", dt.configuration.config_dir .."/lua/locale/") + local function _(msgid) return gettext(msgid) end diff --git a/contrib/enfuseAdvanced.lua b/contrib/enfuseAdvanced.lua index 8698f479..42b62b15 100644 --- a/contrib/enfuseAdvanced.lua +++ b/contrib/enfuseAdvanced.lua @@ -79,6 +79,8 @@ script_data.show = nil -- only required for libs since the destroy_method only h -- Tell gettext where to find the .mo file translating messages for a particular domain local gettext = dt.gettext.gettext +gettext.bindtextdomain("enfuseAdvanced", dt.configuration.config_dir .."/lua/locale/") + local function _(msgid) return gettext(msgid) end diff --git a/contrib/exportLUT.lua b/contrib/exportLUT.lua index 7cc5b63a..4b044558 100644 --- a/contrib/exportLUT.lua +++ b/contrib/exportLUT.lua @@ -44,6 +44,8 @@ script_data.show = nil -- only required for libs since the destroy_method only h local gettext = dt.gettext.gettext +gettext.bindtextdomain("exportLUT", dt.configuration.config_dir .."/lua/locale/") + local function _(msgid) return gettext(msgid) end diff --git a/contrib/ext_editor.lua b/contrib/ext_editor.lua index a6485d49..0650cd70 100644 --- a/contrib/ext_editor.lua +++ b/contrib/ext_editor.lua @@ -97,6 +97,8 @@ ee.widgets = {} -- translation local gettext = dt.gettext.gettext +gettext.bindtextdomain("ext_editor", dt.configuration.config_dir .."/lua/locale/") + local function _(msgid) return gettext(msgid) end diff --git a/contrib/face_recognition.lua b/contrib/face_recognition.lua index 8c23fa77..233b4b7b 100644 --- a/contrib/face_recognition.lua +++ b/contrib/face_recognition.lua @@ -69,6 +69,8 @@ local fc = {} fc.module_installed = false fc.event_registered = false +gettext.bindtextdomain("face_recognition", dt.configuration.config_dir .."/lua/locale/") + local function _(msgid) return gettext(msgid) end diff --git a/contrib/fujifilm_ratings.lua b/contrib/fujifilm_ratings.lua index 8e196489..df73b464 100644 --- a/contrib/fujifilm_ratings.lua +++ b/contrib/fujifilm_ratings.lua @@ -39,6 +39,8 @@ script_data.destroy_method = nil -- set to hide for libs since we can't destroy script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again script_data.show = nil -- only required for libs since the destroy_method only hides them +gettext.bindtextdomain("fujifilm_ratings", dt.configuration.config_dir .."/lua/locale/") + local function _(msgid) return gettext(msgid) end diff --git a/contrib/geoJSON_export.lua b/contrib/geoJSON_export.lua index a6dfc519..18247ee5 100644 --- a/contrib/geoJSON_export.lua +++ b/contrib/geoJSON_export.lua @@ -48,6 +48,8 @@ script_data.destroy_method = nil -- set to hide for libs since we can't destroy script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again script_data.show = nil -- only required for libs since the destroy_method only hides them +gettext.bindtextdomain("geoJSON_export", dt.configuration.config_dir .."/lua/locale/") + local function _(msgid) return gettext(msgid) end diff --git a/contrib/geoToolbox.lua b/contrib/geoToolbox.lua index ee895ca5..33a67368 100644 --- a/contrib/geoToolbox.lua +++ b/contrib/geoToolbox.lua @@ -41,6 +41,8 @@ script_data.destroy_method = nil -- set to hide for libs since we can't destroy script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again script_data.show = nil -- only required for libs since the destroy_method only hides them +gettext.bindtextdomain("geoToolbox", dt.configuration.config_dir .."/lua/locale/") + local function _(msgid) return gettext(msgid) end diff --git a/contrib/gimp.lua b/contrib/gimp.lua index db1e48f3..e8d2a4e8 100644 --- a/contrib/gimp.lua +++ b/contrib/gimp.lua @@ -83,6 +83,8 @@ script_data.destroy_method = nil -- set to hide for libs since we can't destroy script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again script_data.show = nil -- only required for libs since the destroy_method only hides them +gettext.bindtextdomain("gimp", dt.configuration.config_dir .."/lua/locale/") + local function _(msgid) return gettext(msgid) end diff --git a/contrib/gpx_export.lua b/contrib/gpx_export.lua index 6e29c8ee..39bb5193 100644 --- a/contrib/gpx_export.lua +++ b/contrib/gpx_export.lua @@ -38,6 +38,8 @@ script_data.destroy_method = nil -- set to hide for libs since we can't destroy script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again script_data.show = nil -- only required for libs since the destroy_method only hides them +gettext.bindtextdomain("gpx_export", dt.configuration.config_dir .."/lua/locale/") + local function _(msgid) return gettext.dgettext("gpx_export", msgid) end diff --git a/contrib/harmonic_armature_guide.lua b/contrib/harmonic_armature_guide.lua index 308c5efb..2e8afd8d 100644 --- a/contrib/harmonic_armature_guide.lua +++ b/contrib/harmonic_armature_guide.lua @@ -36,6 +36,8 @@ local gettext = dt.gettext.gettext du.check_min_api_version("2.0.0", "harmonic_armature_guide") +gettext.bindtextdomain("harmonic_armature_guide", dt.configuration.config_dir .."/lua/locale/") + local function _(msgid) return gettext(msgid) end diff --git a/contrib/hif_group_leader.lua b/contrib/hif_group_leader.lua index c50d8b26..4c7fb61e 100644 --- a/contrib/hif_group_leader.lua +++ b/contrib/hif_group_leader.lua @@ -75,6 +75,8 @@ script_data.show = nil -- only required for libs since the destroy_method only h local gettext = dt.gettext.gettext +gettext.bindtextdomain("hif_group_leader", dt.configuration.config_dir .."/lua/locale/") + local function _(msgid) return gettext(msgid) end diff --git a/contrib/hugin.lua b/contrib/hugin.lua index 6621a184..451eb956 100644 --- a/contrib/hugin.lua +++ b/contrib/hugin.lua @@ -65,6 +65,8 @@ script_data.destroy_method = nil -- set to hide for libs since we can't destroy script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again script_data.show = nil -- only required for libs since the destroy_method only hides them +gettext.bindtextdomain("hugin", dt.configuration.config_dir .."/lua/locale/") + local function _(msgid) return gettext(msgid) end diff --git a/contrib/image_stack.lua b/contrib/image_stack.lua index f6aad52d..424b2fc4 100644 --- a/contrib/image_stack.lua +++ b/contrib/image_stack.lua @@ -82,6 +82,8 @@ script_data.destroy_method = nil -- set to hide for libs since we can't destroy script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again script_data.show = nil -- only required for libs since the destroy_method only hides them +gettext.bindtextdomain("image_stack", dt.configuration.config_dir .."/lua/locale/") + local function _(msgid) return gettext(msgid) end diff --git a/contrib/image_time.lua b/contrib/image_time.lua index 1f0a7d2f..81bce253 100644 --- a/contrib/image_time.lua +++ b/contrib/image_time.lua @@ -126,6 +126,8 @@ script_data.show = nil -- only required for libs since the destroy_method only h +gettext.bindtextdomain("image_time", dt.configuration.config_dir .."/lua/locale/") + local function _(msgid) return gettext(msgid) end diff --git a/contrib/jpg_group_leader.lua b/contrib/jpg_group_leader.lua index 63d9801f..d8fd7283 100644 --- a/contrib/jpg_group_leader.lua +++ b/contrib/jpg_group_leader.lua @@ -75,6 +75,8 @@ script_data.show = nil -- only required for libs since the destroy_method only h local gettext = dt.gettext.gettext +gettext.bindtextdomain("jpg_group_leader", dt.configuration.config_dir .."/lua/locale/") + local function _(msgid) return gettext(msgid) end diff --git a/contrib/kml_export.lua b/contrib/kml_export.lua index 79ac384c..25eb5d2e 100644 --- a/contrib/kml_export.lua +++ b/contrib/kml_export.lua @@ -54,6 +54,8 @@ script_data.destroy_method = nil -- set to hide for libs since we can't destroy script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again script_data.show = nil -- only required for libs since the destroy_method only hides them +gettext.bindtextdomain("kml_export", dt.configuration.config_dir .."/lua/locale/") + local function _(msgid) return gettext(msgid) end diff --git a/contrib/passport_guide.lua b/contrib/passport_guide.lua index 6e101838..0b233c64 100644 --- a/contrib/passport_guide.lua +++ b/contrib/passport_guide.lua @@ -41,6 +41,8 @@ local gettext = dt.gettext.gettext du.check_min_api_version("2.0.0", "passport_guide") +gettext.bindtextdomain("passport_guide", dt.configuration.config_dir .."/lua/locale/") + local function _(msgid) return gettext(msgid) end diff --git a/contrib/pdf_slideshow.lua b/contrib/pdf_slideshow.lua index adffffe0..b6fb1803 100644 --- a/contrib/pdf_slideshow.lua +++ b/contrib/pdf_slideshow.lua @@ -44,6 +44,8 @@ local df = require "lib/dtutils.file" local gettext = dt.gettext.gettext +gettext.bindtextdomain("pdf_slideshow", dt.configuration.config_dir .."/lua/locale/") + local function _(msgid) return gettext(msgid) end diff --git a/contrib/photils.lua b/contrib/photils.lua index f26998fb..250915ef 100644 --- a/contrib/photils.lua +++ b/contrib/photils.lua @@ -64,6 +64,8 @@ exporter.max_width = 224 -- helper functions +gettext.bindtextdomain("photils", dt.configuration.config_dir .."/lua/locale/") + local function _(msgid) return gettext(msgid) end diff --git a/contrib/quicktag.lua b/contrib/quicktag.lua index 82ccb539..1ab5f3f0 100644 --- a/contrib/quicktag.lua +++ b/contrib/quicktag.lua @@ -64,6 +64,8 @@ qt.widget_table = {} local gettext = dt.gettext.gettext +gettext.bindtextdomain("quicktag", dt.configuration.config_dir .."/lua/locale/") + local function _(msgid) return gettext(msgid) end diff --git a/contrib/rate_group.lua b/contrib/rate_group.lua index 4b02d5e9..d8e7130b 100644 --- a/contrib/rate_group.lua +++ b/contrib/rate_group.lua @@ -46,6 +46,8 @@ du.check_min_api_version("7.0.0", "rate_group") local gettext = dt.gettext.gettext +gettext.bindtextdomain("rate_group", dt.configuration.config_dir .."/lua/locale/") + local function _(msgid) return gettext(msgid) end diff --git a/contrib/rename-tags.lua b/contrib/rename-tags.lua index 05d94913..90597bb3 100644 --- a/contrib/rename-tags.lua +++ b/contrib/rename-tags.lua @@ -38,6 +38,8 @@ du.deprecated("contrib/rename-tags.lua","darktable release 4.0") local gettext = dt.gettext.gettext +gettext.bindtextdomain("rename-tags", dt.configuration.config_dir .."/lua/locale/") + local function _(msgid) return gettext(msgid) end diff --git a/contrib/rename_images.lua b/contrib/rename_images.lua index cf133cf1..e63a1ab1 100644 --- a/contrib/rename_images.lua +++ b/contrib/rename_images.lua @@ -48,6 +48,8 @@ du.check_min_api_version("7.0.0", "rename_images") local gettext = dt.gettext.gettext +gettext.bindtextdomain("rename_images", dt.configuration.config_dir .."/lua/locale/") + local function _(msgid) return gettext(msgid) end diff --git a/contrib/select_non_existing.lua b/contrib/select_non_existing.lua index 9536f03b..a8225b17 100644 --- a/contrib/select_non_existing.lua +++ b/contrib/select_non_existing.lua @@ -31,6 +31,8 @@ local PS = dt.configuration.running_os == "windows" and "\\" or "/" local gettext = dt.gettext.gettext +gettext.bindtextdomain("select_non_existing", dt.configuration.config_dir .."/lua/locale/") + local function _(msgid) return gettext(msgid) end diff --git a/contrib/select_untagged.lua b/contrib/select_untagged.lua index bb887f2e..97bf3382 100644 --- a/contrib/select_untagged.lua +++ b/contrib/select_untagged.lua @@ -33,6 +33,8 @@ script_data.destroy_method = nil -- set to hide for libs since we can't destroy script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again script_data.show = nil -- only required for libs since the destroy_method only hides them +gettext.bindtextdomain("select_untagged", dt.configuration.config_dir .."/lua/locale/") + local function _(msgid) return gettext(msgid) end diff --git a/contrib/slideshowMusic.lua b/contrib/slideshowMusic.lua index abb72137..666402e3 100644 --- a/contrib/slideshowMusic.lua +++ b/contrib/slideshowMusic.lua @@ -40,6 +40,8 @@ script_data.destroy_method = nil -- set to hide for libs since we can't destroy script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again script_data.show = nil -- only required for libs since the destroy_method only hides them +gettext.bindtextdomain("slideshowMusic", dt.configuration.config_dir .."/lua/locale/") + local function _(msgid) return gettext(msgid) end diff --git a/contrib/transfer_hierarchy.lua b/contrib/transfer_hierarchy.lua index 6fdb2dcd..574ef4b9 100755 --- a/contrib/transfer_hierarchy.lua +++ b/contrib/transfer_hierarchy.lua @@ -96,6 +96,8 @@ local PATH_SEGMENT_REGEX = "(" .. PATH_SEPARATOR .. "?)([^" .. PATH_SEPARATOR .. unpack = unpack or table.unpack gmatch = string.gfind or string.gmatch +gettext.bindtextdomain("transfer_hierarchy", dt.configuration.config_dir .."/lua/locale/") + local function _(msgid) return darktable.gettext.gettext(msgid) end diff --git a/contrib/video_ffmpeg.lua b/contrib/video_ffmpeg.lua index 63f40b58..5c4369c6 100644 --- a/contrib/video_ffmpeg.lua +++ b/contrib/video_ffmpeg.lua @@ -54,6 +54,8 @@ local MODULE_NAME = "video_ffmpeg" local PS = dt.configuration.running_os == "windows" and "\\" or "/" +gettext.bindtextdomain("video_ffmpeg", dt.configuration.config_dir .."/lua/locale/") + local function _(msgid) return gettext(msgid) end diff --git a/examples/api_version.lua b/examples/api_version.lua index 49dc62a8..d89416cf 100644 --- a/examples/api_version.lua +++ b/examples/api_version.lua @@ -27,6 +27,8 @@ local dt = require "darktable" local gettext = dt.gettext.gettext +gettext.bindtextdomain("api_version", dt.configuration.config_dir .."/lua/locale/") + local function _(msg) return gettext(msg) end diff --git a/examples/darkroom_demo.lua b/examples/darkroom_demo.lua index bdd7f847..2a528883 100644 --- a/examples/darkroom_demo.lua +++ b/examples/darkroom_demo.lua @@ -40,7 +40,7 @@ local du = require "lib/dtutils" -- V E R S I O N C H E C K -- - - - - - - - - - - - - - - - - - - - - - - - -du.check_min_api_version("5.0.2", "darkroom_mode") -- darktable 3.0 +du.check_min_api_version("5.0.2", "darkroom_demo") -- darktable 3.0 -- script_manager integration to allow a script to be removed -- without restarting darktable @@ -52,7 +52,7 @@ end -- C O N S T A N T S -- - - - - - - - - - - - - - - - - - - - - - - - -local MODULE_NAME = "darkroom" +local MODULE_NAME = "darkroom_demo" local PS = dt.configuration.running_os == "windows" and "\\" or "/" -- - - - - - - - - - - - - - - - - - - - - - - - @@ -60,6 +60,8 @@ local PS = dt.configuration.running_os == "windows" and "\\" or "/" -- - - - - - - - - - - - - - - - - - - - - - - - local gettext = dt.gettext.gettext +gettext.bindtextdomain("darkroom_demo", dt.configuration.config_dir .."/lua/locale/") + local function _(msgid) return gettext(msgid) end diff --git a/examples/gettextExample.lua b/examples/gettextExample.lua index f0f51e95..7c1e241f 100644 --- a/examples/gettextExample.lua +++ b/examples/gettextExample.lua @@ -69,6 +69,8 @@ dt.print_error("Hello World!") local gettext = dt.gettext.gettext +gettext.bindtextdomain("gettextExample", dt.configuration.config_dir .."/lua/locale/") + -- Translate a string using the darktable textdomain dt.print_error(gettext("image")) diff --git a/examples/hello_world.lua b/examples/hello_world.lua index 3839ebda..75e52ca8 100644 --- a/examples/hello_world.lua +++ b/examples/hello_world.lua @@ -35,6 +35,8 @@ du.check_min_api_version("2.0.0", "hello_world") local gettext = dt.gettext.gettext +gettext.bindtextdomain("hello_world", dt.configuration.config_dir .."/lua/locale/") + local function _(msg) return gettext(msg) end diff --git a/examples/lighttable_demo.lua b/examples/lighttable_demo.lua index e1e0732c..6047e889 100644 --- a/examples/lighttable_demo.lua +++ b/examples/lighttable_demo.lua @@ -61,6 +61,8 @@ end -- - - - - - - - - - - - - - - - - - - - - - - - local gettext = dt.gettext.gettext +gettext.bindtextdomain("lighttable_demo", dt.configuration.config_dir .."/lua/locale/") + local function _(msgid) return gettext(msgid) end diff --git a/examples/moduleExample.lua b/examples/moduleExample.lua index 56741328..06ba003e 100644 --- a/examples/moduleExample.lua +++ b/examples/moduleExample.lua @@ -49,6 +49,8 @@ script_data.show = nil -- only required for libs since the destroy_method only h -- https://www.darktable.org/lua-api/index.html#darktable_gettext local gettext = dt.gettext.gettext +gettext.bindtextdomain("moduleExample", dt.configuration.config_dir .."/lua/locale/") + local function _(msgid) return gettext(msgid) end diff --git a/examples/multi_os.lua b/examples/multi_os.lua index 5c084cf8..8d8758a8 100644 --- a/examples/multi_os.lua +++ b/examples/multi_os.lua @@ -72,6 +72,8 @@ local dtsys = require "lib/dtutils.system" -- system utilities local gettext = dt.gettext.gettext +gettext.bindtextdomain("multi_os", dt.configuration.config_dir .."/lua/locale/") + local function _(msgid) return gettext(msgid) end diff --git a/examples/panels_demo.lua b/examples/panels_demo.lua index 971d69bf..ad7c924e 100644 --- a/examples/panels_demo.lua +++ b/examples/panels_demo.lua @@ -53,7 +53,7 @@ end -- C O N S T A N T S -- - - - - - - - - - - - - - - - - - - - - - - - -local MODULE_NAME = "panels" +local MODULE_NAME = "panels_demo" local PS = dt.configuration.running_os == "windows" and "\\" or "/" -- - - - - - - - - - - - - - - - - - - - - - - - @@ -61,6 +61,8 @@ local PS = dt.configuration.running_os == "windows" and "\\" or "/" -- - - - - - - - - - - - - - - - - - - - - - - - local gettext = dt.gettext.gettext +gettext.bindtextdomain("panels_demo", dt.configuration.config_dir .."/lua/locale/") + local function _(msgid) return gettext(msgid) end diff --git a/examples/preferenceExamples.lua b/examples/preferenceExamples.lua index aa8eae23..c9040d85 100644 --- a/examples/preferenceExamples.lua +++ b/examples/preferenceExamples.lua @@ -28,6 +28,8 @@ local du = require "lib/dtutils" local gettext = dt.gettext.gettext +gettext.bindtextdomain("preferenceExamples", dt.configuration.config_dir .."/lua/locale/") + local function _(msg) return gettext(msg) end diff --git a/examples/printExamples.lua b/examples/printExamples.lua index b7be20c3..c68ddd59 100644 --- a/examples/printExamples.lua +++ b/examples/printExamples.lua @@ -28,6 +28,8 @@ du.check_min_api_version("5.0.0", "printExamples") local gettext = dt.gettext.gettext +gettext.bindtextdomain("printExamples", dt.configuration.config_dir .."/lua/locale/") + local function _(msg) return gettext(msg) end diff --git a/examples/running_os.lua b/examples/running_os.lua index 2c68bf05..6a710958 100644 --- a/examples/running_os.lua +++ b/examples/running_os.lua @@ -34,6 +34,8 @@ du.check_min_api_version("5.0.0", "running_os") local gettext = dt.gettext.gettext +gettext.bindtextdomain("running_os", dt.configuration.config_dir .."/lua/locale/") + local function _(msg) return gettext(msg) end diff --git a/official/copy_paste_metadata.lua b/official/copy_paste_metadata.lua index 3afb953b..a44270ef 100644 --- a/official/copy_paste_metadata.lua +++ b/official/copy_paste_metadata.lua @@ -58,6 +58,8 @@ local publisher = "" local rights = "" local tags = {} +gettext.bindtextdomain("copy_paste_metadata", dt.configuration.config_dir .."/lua/locale/") + local function _(msgid) return gettext(msgid) end diff --git a/official/enfuse.lua b/official/enfuse.lua index 74999ad2..9aa5815a 100644 --- a/official/enfuse.lua +++ b/official/enfuse.lua @@ -57,6 +57,8 @@ enf.event_registered = false enf.module_installed = false enf.lib_widgets = {} +gettext.bindtextdomain("enfuse", dt.configuration.config_dir .."/lua/locale/") + local function _(msgid) return gettext(msgid) end diff --git a/official/generate_image_txt.lua b/official/generate_image_txt.lua index 3eeafbe6..c9559887 100644 --- a/official/generate_image_txt.lua +++ b/official/generate_image_txt.lua @@ -40,6 +40,8 @@ require "darktable.debug" local gettext = dt.gettext.gettext +gettext.bindtextdomain("generate_image_txt", dt.configuration.config_dir .."/lua/locale/") + local function _(msg) return gettext(msg) end diff --git a/official/import_filter_manager.lua b/official/import_filter_manager.lua index 7a81f2cc..05bc45dd 100644 --- a/official/import_filter_manager.lua +++ b/official/import_filter_manager.lua @@ -34,6 +34,8 @@ local dt = require "darktable" local gettext = dt.gettext.gettext +gettext.bindtextdomain("import_filter_manager", dt.configuration.config_dir .."/lua/locale/") + local function _(msg) return gettext(msg) end diff --git a/official/save_selection.lua b/official/save_selection.lua index 22841a92..f37ad0be 100644 --- a/official/save_selection.lua +++ b/official/save_selection.lua @@ -40,6 +40,8 @@ du.check_min_api_version("7.0.0", "save_selection") local gettext = dt.gettext.gettext +gettext.bindtextdomain("save_selection", dt.configuration.config_dir .."/lua/locale/") + local function _(msg) return gettext(msg) end diff --git a/official/selection_to_pdf.lua b/official/selection_to_pdf.lua index 68063132..116f0d75 100644 --- a/official/selection_to_pdf.lua +++ b/official/selection_to_pdf.lua @@ -40,6 +40,8 @@ du.check_min_api_version("7.0.0", "selection_to_pdf") local gettext = dt.gettext.gettext +gettext.bindtextdomain("selection_to_pdf", dt.configuration.config_dir .."/lua/locale/") + local function _(msg) return gettext(msg) end diff --git a/tools/executable_manager.lua b/tools/executable_manager.lua index 70557412..48659746 100644 --- a/tools/executable_manager.lua +++ b/tools/executable_manager.lua @@ -55,6 +55,8 @@ exec_man.event_registered = false -- F U N C T I O N S -- - - - - - - - - - - - - - - - - - - - - - - - - - - - +gettext.bindtextdomain("executable_manager", dt.configuration.config_dir .."/lua/locale/") + local function _(msg) return gettext(msg) end diff --git a/tools/script_manager.lua b/tools/script_manager.lua index a7a5683d..22997ddd 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -60,6 +60,8 @@ local debug = require "darktable.debug" local gettext = dt.gettext.gettext +gettext.bindtextdomain("script_manager", dt.configuration.config_dir .."/lua/locale/") + local function _(msgid) return gettext(msgid) end From f6916c3a15f0b57721501934dbc48a063787ecd6 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Wed, 15 May 2024 14:51:14 -0400 Subject: [PATCH 285/445] tools/script_manager - lower cased mixed case buttons and headings --- tools/script_manager.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/script_manager.lua b/tools/script_manager.lua index 2313e309..28bd1d98 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -1328,7 +1328,7 @@ sm.widgets.add_scripts = dt.new_widget("box"){ } sm.widgets.allow_disable = dt.new_widget("check_button"){ - label = _('Enable "Disable Scripts" button'), + label = _('enable "disable scripts" button'), value = false, clicked_callback = function(this) if this.value == true then @@ -1340,7 +1340,7 @@ sm.widgets.allow_disable = dt.new_widget("check_button"){ } sm.widgets.disable_scripts = dt.new_widget("button"){ - label = _("Disable Scripts"), + label = _("disable scripts"), sensitive = false, clicked_callback = function(this) local LUARC = dt.configuration.config_dir .. PS .. "luarc" @@ -1469,7 +1469,7 @@ sm.widgets.configure = dt.new_widget("box"){ orientation = "vertical", dt.new_widget("section_label"){label = " "}, dt.new_widget("label"){label = " "}, - dt.new_widget("label"){label = _("Configuration")}, + dt.new_widget("label"){label = _("configuration")}, dt.new_widget("label"){label = " "}, sm.widgets.num_buttons, dt.new_widget("label"){label = " "}, From 55e68f8cd0a4378c5814b988a3d533a1dc548dcf Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Wed, 15 May 2024 21:23:13 -0400 Subject: [PATCH 286/445] Added metadata fields to scripts that script_manager can access and display as a tooltip. Added script_manager integration to those scripts that didn't have it. --- contrib/AutoGrouper.lua | 443 ++++++------- contrib/CollectHelper.lua | 513 +++++++-------- contrib/HDRMerge.lua | 967 ++++++++++++++-------------- contrib/LabelsToTags.lua | 11 +- contrib/OpenInExplorer.lua | 481 +++++++------- contrib/RL_out_sharp.lua | 25 +- contrib/autostyle.lua | 9 +- contrib/change_group_leader.lua | 17 +- contrib/clear_GPS.lua | 22 +- contrib/color_profile_manager.lua | 9 +- contrib/copy_attach_detach_tags.lua | 19 +- contrib/cr2hdr.lua | 11 +- contrib/cycle_group_leader.lua | 33 +- contrib/enfuseAdvanced.lua | 25 +- contrib/exportLUT.lua | 23 +- contrib/ext_editor.lua | 25 +- contrib/face_recognition.lua | 19 +- contrib/fujifilm_dynamic_range.lua | 14 + contrib/fujifilm_ratings.lua | 19 +- contrib/geoJSON_export.lua | 19 +- contrib/geoToolbox.lua | 19 +- contrib/gimp.lua | 19 +- contrib/gpx_export.lua | 21 +- contrib/harmonic_armature_guide.lua | 26 +- contrib/hif_group_leader.lua | 31 +- contrib/hugin.lua | 19 +- contrib/image_stack.lua | 19 +- contrib/image_time.lua | 19 +- contrib/jpg_group_leader.lua | 31 +- contrib/kml_export.lua | 19 +- contrib/passport_guide.lua | 24 +- contrib/passport_guide_germany.lua | 24 +- contrib/pdf_slideshow.lua | 11 +- contrib/photils.lua | 21 +- contrib/quicktag.lua | 23 +- contrib/rate_group.lua | 9 +- contrib/rename-tags.lua | 11 +- contrib/rename_images.lua | 9 +- contrib/select_non_existing.lua | 10 +- contrib/select_untagged.lua | 19 +- contrib/slideshowMusic.lua | 19 +- contrib/transfer_hierarchy.lua | 19 +- contrib/video_ffmpeg.lua | 22 +- examples/api_version.lua | 10 +- examples/darkroom_demo.lua | 10 +- examples/gettextExample.lua | 10 +- examples/gui_action.lua | 38 ++ examples/hello_world.lua | 10 +- examples/lighttable_demo.lua | 10 +- examples/moduleExample.lua | 25 +- examples/multi_os.lua | 10 +- examples/panels_demo.lua | 10 +- examples/preferenceExamples.lua | 19 +- examples/printExamples.lua | 10 +- examples/running_os.lua | 10 +- examples/x-touch.lua | 357 +++++----- official/check_for_updates.lua | 15 + official/copy_paste_metadata.lua | 19 +- official/delete_long_tags.lua | 15 + official/delete_unused_tags.lua | 15 + official/enfuse.lua | 19 +- official/generate_image_txt.lua | 9 +- official/image_path_in_ui.lua | 15 + official/import_filter_manager.lua | 24 +- official/import_filters.lua | 30 + official/save_selection.lua | 11 +- official/selection_to_pdf.lua | 11 +- tools/executable_manager.lua | 23 +- tools/get_lib_manpages.lua | 16 + tools/get_libdoc.lua | 16 + 70 files changed, 2308 insertions(+), 1607 deletions(-) diff --git a/contrib/AutoGrouper.lua b/contrib/AutoGrouper.lua index 4d8ced3b..90f65dbc 100644 --- a/contrib/AutoGrouper.lua +++ b/contrib/AutoGrouper.lua @@ -1,218 +1,225 @@ ---[[AutoGrouper plugin for darktable - - copyright (c) 2019 Kevin Ertel - - darktable is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - darktable is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with darktable. If not, see . -]] - ---[[About this Plugin -This plugin adds the module "Auto Group" to darktable's lighttable view - -----REQUIRED SOFTWARE---- -None - -----USAGE---- -Install: (see here for more detail: https://github.com/darktable-org/lua-scripts ) - 1) Copy this file in to your "lua/contrib" folder where all other scripts reside. - 2) Require this file in your luarc file, as with any other dt plug-in - -Set a gap amount in second which will be used to determine when images should no -longer be added to a group. If an image is more then the specified amount of time -from the last image in the group it will not be added. Images without timestamps -in exif data will be ignored. - -There are two buttons. One allows the grouping to be performed only on the currently -selected images, the other button performs grouping on the entire active collection -]] - -local dt = require "darktable" -local du = require "lib/dtutils" - -du.check_min_api_version("7.0.0", "AutoGrouper") - -local MOD = 'autogrouper' - --- return data structure for script_manager - -local script_data = {} - -script_data.destroy = nil -- function to destory the script -script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil -script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again -script_data.show = nil -- only required for libs since the destroy_method only hides them - -local gettext = dt.gettext.gettext -gettext.bindtextdomain(MOD, dt.configuration.config_dir .."/lua/locale/") - -local function _(msgid) - return gettext(msgid) -end - -local Ag = {} -Ag.module_installed = false -Ag.event_registered = false - -local GUI = { - gap = {}, - selected = {}, - collection = {} -} - - -local function InRange(test, low, high) --tests if test value is within range of low and high (inclusive) - if test >= low and test <= high then - return true - else - return false - end -end - -local function CompTime(first, second) --compares the timestamps and returns true if first was taken before second - first_time = first.exif_datetime_taken - if string.match(first_time, '[0-9]') == nil then first_time = '9999:99:99 99:99:99' end - first_time = tonumber(string.gsub(first_time, '[^0-9]*','')) - second_time = second.exif_datetime_taken - if string.match(second_time, '[0-9]') == nil then second_time = '9999:99:99 99:99:99' end - second_time = tonumber(string.gsub(second_time, '[^0-9]*','')) - return first_time < second_time -end - -local function SeperateTime(str) --seperates the timestamp into individual components for used with OS.time operations - local cleaned = string.gsub(str, '[^%d]',':') - cleaned = string.gsub(cleaned, '::*',':') --YYYY:MM:DD:hh:mm:ss - local year = string.sub(cleaned,1,4) - local month = string.sub(cleaned,6,7) - local day = string.sub(cleaned,9,10) - local hour = string.sub(cleaned,12,13) - local min = string.sub(cleaned,15,16) - local sec = string.sub(cleaned,18,19) - return {year = year, month = month, day = day, hour = hour, min = min, sec = sec} -end - -local function GetTimeDiff(curr_image, prev_image) --returns the time difference (in sec.) from current image and the previous image - local curr_time = SeperateTime(curr_image.exif_datetime_taken) - local prev_time = SeperateTime(prev_image.exif_datetime_taken) - return os.time(curr_time)-os.time(prev_time) -end - -local function main(on_collection) - local images = {} - if on_collection then - local col_images = dt.collection - for i,image in ipairs(col_images) do --copy images to a standard table, table.sort barfs on type dt_lua_singleton_image_collection - table.insert(images,i,image) - end - else - images = dt.gui.selection() - end - dt.preferences.write(MOD, 'active_gap', 'integer', GUI.gap.value) - if #images < 2 then - dt.print('please select at least 2 images') - return - end - table.sort(images, function(first, second) return CompTime(first,second) end) --sort images by timestamp - - for i, image in ipairs(images) do - if i == 1 then - prev_image = image - elseif string.match(image.exif_datetime_taken, '[%d]') ~= nil then --make sure current image has a timestamp, if so check if it is within the user specified gap value and add to group - local curr_image = image - if GetTimeDiff(curr_image, prev_image) <= GUI.gap.value then - images[i]:group_with(images[i-1]) - end - prev_image = curr_image - end - end -end - -local function install_module() - if not Ag.module_installed then - dt.print_log("installing module") - dt.register_lib( - MOD, -- Module name - _('auto group'), -- name - true, -- expandable - true, -- resetable - {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 99}}, -- containers - dt.new_widget("box"){ - orientation = "vertical", - GUI.gap, - GUI.selected, - GUI.collection - } - ) - Ag.module_installed = true - dt.print_log("module installed") - dt.print_log("styles module visibility is " .. tostring(dt.gui.libs["styles"].visible)) - end -end - -local function destroy() - dt.gui.libs[MOD].visible = false -end - -local function restart() - dt.gui.libs[MOD].visible = true -end - --- GUI -- -temp = dt.preferences.read(MOD, 'active_gap', 'integer') -if not InRange(temp, 1, 86400) then temp = 3 end -GUI.gap = dt.new_widget('slider'){ - label = _('group gap [sec.]'), - tooltip = _('minimum gap, in seconds, between groups'), - soft_min = 1, - soft_max = 60, - hard_min = 1, - hard_max = 86400, - step = 1, - digits = 0, - value = temp, - reset_callback = function(self) - self.value = 3 - end -} -GUI.selected = dt.new_widget("button"){ - label = _('auto group: selected'), - tooltip =_('auto group selected images'), - clicked_callback = function() main(false) end -} -GUI.collection = dt.new_widget("button"){ - label = _('auto group: collection'), - tooltip =_('auto group the entire collection'), - clicked_callback = function() main(true) end -} - -if dt.gui.current_view().id == "lighttable" then - install_module() -else - if not Ag.event_registered then - dt.register_event( - "AutoGrouper", "view-changed", - function(event, old_view, new_view) - if new_view.name == "lighttable" and old_view.name == "darkroom" then - install_module() - end - end - ) - Ag.event_registered = true - end -end - -script_data.destroy = destroy -script_data.destroy_method = "hide" -script_data.restart = restart -script_data.show = restart - -return script_data +--[[AutoGrouper plugin for darktable + + copyright (c) 2019 Kevin Ertel + + darktable is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + darktable is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with darktable. If not, see . +]] + +--[[About this Plugin +This plugin adds the module "Auto Group" to darktable's lighttable view + +----REQUIRED SOFTWARE---- +None + +----USAGE---- +Install: (see here for more detail: https://github.com/darktable-org/lua-scripts ) + 1) Copy this file in to your "lua/contrib" folder where all other scripts reside. + 2) Require this file in your luarc file, as with any other dt plug-in + +Set a gap amount in second which will be used to determine when images should no +longer be added to a group. If an image is more then the specified amount of time +from the last image in the group it will not be added. Images without timestamps +in exif data will be ignored. + +There are two buttons. One allows the grouping to be performed only on the currently +selected images, the other button performs grouping on the entire active collection +]] + +local dt = require "darktable" +local du = require "lib/dtutils" + +du.check_min_api_version("7.0.0", "AutoGrouper") + +local MOD = 'autogrouper' + +local gettext = dt.gettext +gettext.bindtextdomain(MOD, dt.configuration.config_dir .."/lua/locale/") + +local function _(msgid) + return gettext.gettext(msgid) +end + +-- return data structure for script_manager + +local script_data = {} + +script_data.metadata = { + name = "AutoGrouper", + purpose = _("automatically group images by time interval"), + author = "Kevin Ertel", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/AutoGrouper/" +} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them + +local Ag = {} +Ag.module_installed = false +Ag.event_registered = false + +local GUI = { + gap = {}, + selected = {}, + collection = {} +} + + +local function InRange(test, low, high) --tests if test value is within range of low and high (inclusive) + if test >= low and test <= high then + return true + else + return false + end +end + +local function CompTime(first, second) --compares the timestamps and returns true if first was taken before second + first_time = first.exif_datetime_taken + if string.match(first_time, '[0-9]') == nil then first_time = '9999:99:99 99:99:99' end + first_time = tonumber(string.gsub(first_time, '[^0-9]*','')) + second_time = second.exif_datetime_taken + if string.match(second_time, '[0-9]') == nil then second_time = '9999:99:99 99:99:99' end + second_time = tonumber(string.gsub(second_time, '[^0-9]*','')) + return first_time < second_time +end + +local function SeperateTime(str) --seperates the timestamp into individual components for used with OS.time operations + local cleaned = string.gsub(str, '[^%d]',':') + cleaned = string.gsub(cleaned, '::*',':') --YYYY:MM:DD:hh:mm:ss + local year = string.sub(cleaned,1,4) + local month = string.sub(cleaned,6,7) + local day = string.sub(cleaned,9,10) + local hour = string.sub(cleaned,12,13) + local min = string.sub(cleaned,15,16) + local sec = string.sub(cleaned,18,19) + return {year = year, month = month, day = day, hour = hour, min = min, sec = sec} +end + +local function GetTimeDiff(curr_image, prev_image) --returns the time difference (in sec.) from current image and the previous image + local curr_time = SeperateTime(curr_image.exif_datetime_taken) + local prev_time = SeperateTime(prev_image.exif_datetime_taken) + return os.time(curr_time)-os.time(prev_time) +end + +local function main(on_collection) + local images = {} + if on_collection then + local col_images = dt.collection + for i,image in ipairs(col_images) do --copy images to a standard table, table.sort barfs on type dt_lua_singleton_image_collection + table.insert(images,i,image) + end + else + images = dt.gui.selection() + end + dt.preferences.write(MOD, 'active_gap', 'integer', GUI.gap.value) + if #images < 2 then + dt.print('please select at least 2 images') + return + end + table.sort(images, function(first, second) return CompTime(first,second) end) --sort images by timestamp + + for i, image in ipairs(images) do + if i == 1 then + prev_image = image + elseif string.match(image.exif_datetime_taken, '[%d]') ~= nil then --make sure current image has a timestamp, if so check if it is within the user specified gap value and add to group + local curr_image = image + if GetTimeDiff(curr_image, prev_image) <= GUI.gap.value then + images[i]:group_with(images[i-1]) + end + prev_image = curr_image + end + end +end + +local function install_module() + if not Ag.module_installed then + dt.print_log("installing module") + dt.register_lib( + MOD, -- Module name + _('auto group'), -- name + true, -- expandable + true, -- resetable + {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 99}}, -- containers + dt.new_widget("box"){ + orientation = "vertical", + GUI.gap, + GUI.selected, + GUI.collection + } + ) + Ag.module_installed = true + dt.print_log("module installed") + dt.print_log("styles module visibility is " .. tostring(dt.gui.libs["styles"].visible)) + end +end + +local function destroy() + dt.gui.libs[MOD].visible = false +end + +local function restart() + dt.gui.libs[MOD].visible = true +end + +-- GUI -- +temp = dt.preferences.read(MOD, 'active_gap', 'integer') +if not InRange(temp, 1, 86400) then temp = 3 end +GUI.gap = dt.new_widget('slider'){ + label = _('group gap [sec.]'), + tooltip = _('minimum gap, in seconds, between groups'), + soft_min = 1, + soft_max = 60, + hard_min = 1, + hard_max = 86400, + step = 1, + digits = 0, + value = temp, + reset_callback = function(self) + self.value = 3 + end +} +GUI.selected = dt.new_widget("button"){ + label = _('auto group: selected'), + tooltip =_('auto group selected images'), + clicked_callback = function() main(false) end +} +GUI.collection = dt.new_widget("button"){ + label = _('auto group: collection'), + tooltip =_('auto group the entire collection'), + clicked_callback = function() main(true) end +} + +if dt.gui.current_view().id == "lighttable" then + install_module() +else + if not Ag.event_registered then + dt.register_event( + "AutoGrouper", "view-changed", + function(event, old_view, new_view) + if new_view.name == "lighttable" and old_view.name == "darkroom" then + install_module() + end + end + ) + Ag.event_registered = true + end +end + +script_data.destroy = destroy +script_data.destroy_method = "hide" +script_data.restart = restart +script_data.show = restart + +return script_data diff --git a/contrib/CollectHelper.lua b/contrib/CollectHelper.lua index 4e37f06f..ca76d857 100644 --- a/contrib/CollectHelper.lua +++ b/contrib/CollectHelper.lua @@ -1,253 +1,260 @@ ---[[Collect Helper plugin for darktable - - copyright (c) 2019 Kevin Ertel - - darktable is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - darktable is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with darktable. If not, see . -]] - ---[[About this plugin -This plugin adds the button(s) to the "Selected Images" module: -1) Return to Previous Collection -2) Collect on image's Folder -3) Collect on image's Color Label(s) -4) Collect on All (AND) - -It also adds 3 preferences to the lua options dialog box which allow the user to activate/deactivate the 3 "Collect on" buttons. - -Button Behavior: -1) Return to Previous Collection - Will reset the collect parameters to the previously active settings -2) Collect on image's Folder - Will change the collect parameters to be "Folder" with a value of the selected image's folder location -3) Collect on image's Color Label(s) - Will change the collect parameter to be "Color" with a value of the selected images color labels, will apply multiple parameters with AND logic if multiple exist -4) Collect on All (AND) - Will collect on all parameters activated by the preferences dialog, as such this button is redundant if you only have one of the two other options enabled - -----REQUIRED SOFTWARE---- -NA - -----USAGE---- -Install: (see here for more detail: https://github.com/darktable-org/lua-scripts ) - 1) Copy this file in to your "lua/contrib" folder where all other scripts reside. - 2) Require this file in your luarc file, as with any other dt plug-in - -Select the photo you wish to change you collection based on. -In the "Selected Images" module click on "Collect on this Image" - -----KNOWN ISSUES---- -]] - -local dt = require "darktable" -local du = require "lib/dtutils" -local gettext = dt.gettext.gettext -local previous = nil -local all_active = false - -du.check_min_api_version("7.0.0", "CollectHelper") - --- return data structure for script_manager - -local script_data = {} - -script_data.destroy = nil -- function to destory the script -script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil -script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again -script_data.show = nil -- only required for libs since the destroy_method only hides them - -gettext.bindtextdomain("CollectHelper", dt.configuration.config_dir .."/lua/locale/") - -local function _(msgid) - return gettext(msgid) -end - --- FUNCTION -- -local function CheckSingleImage(selection) - if #selection ~= 1 then - dt.print(_("please select a single image")) - return true - end - return false -end - -local function CheckHasColorLabel(selection) - local ret = false - for _,image in pairs(selection) do - if image.red then ret = true end - if image.blue then ret = true end - if image.green then ret = true end - if image.yellow then ret = true end - if image.purple then ret = true end - end - return ret -end -local function PreviousCollection() - if previous ~= nil then - previous = dt.gui.libs.collect.filter(previous) - end -end - -local function CollectOnFolder(all_rules, all_active) - local images = dt.gui.selection() - if CheckSingleImage(images) then - return - end - local rules = {} - local rule = dt.gui.libs.collect.new_rule() - rule.mode = "DT_LIB_COLLECT_MODE_AND" - rule.data = images[1].path - rule.item = "DT_COLLECTION_PROP_FOLDERS" - table.insert(rules, rule) - if all_active then - for _,active_rule in pairs(rules) do - table.insert(all_rules, active_rule) - end - return all_rules - else - previous = dt.gui.libs.collect.filter(rules) - end -end - -local function CollectOnColors(all_rules, all_active) - local images = dt.gui.selection() - if CheckSingleImage(images) then - return - end - if not CheckHasColorLabel(images) then - dt.print(_('select an image with an active color label')) - return - end - for _,image in pairs(images) do - local rules = {} - if image.red then - local red_rule = dt.gui.libs.collect.new_rule() - red_rule.mode = "DT_LIB_COLLECT_MODE_AND" - red_rule.data = "red" - red_rule.item = "DT_COLLECTION_PROP_COLORLABEL" - table.insert(rules, red_rule) - end - if image.blue then - local blue_rule = dt.gui.libs.collect.new_rule() - blue_rule.mode = "DT_LIB_COLLECT_MODE_AND" - blue_rule.data = "blue" - blue_rule.item = "DT_COLLECTION_PROP_COLORLABEL" - table.insert(rules, blue_rule) - end - if image.green then - local green_rule = dt.gui.libs.collect.new_rule() - green_rule.mode = "DT_LIB_COLLECT_MODE_AND" - green_rule.data = "green" - green_rule.item = "DT_COLLECTION_PROP_COLORLABEL" - table.insert(rules, green_rule) - end - if image.yellow then - local yellow_rule = dt.gui.libs.collect.new_rule() - yellow_rule.mode = "DT_LIB_COLLECT_MODE_AND" - yellow_rule.data = "yellow" - yellow_rule.item = "DT_COLLECTION_PROP_COLORLABEL" - table.insert(rules, yellow_rule) - end - if image.purple then - local purple_rule = dt.gui.libs.collect.new_rule() - purple_rule.mode = "DT_LIB_COLLECT_MODE_AND" - purple_rule.data = "purple" - purple_rule.item = "DT_COLLECTION_PROP_COLORLABEL" - table.insert(rules, purple_rule) - end - if all_active then - for _,active_rule in pairs(rules) do - table.insert(all_rules, active_rule) - end - return all_rules - else - previous = dt.gui.libs.collect.filter(rules) - end - end -end - -local function CollectOnAll_AND() - local images = dt.gui.selection() - if CheckSingleImage(images) then - return - end - local rules = {} - if dt.preferences.read('module_CollectHelper','folder','bool') then - rules = CollectOnFolder(rules, true) - end - if dt.preferences.read('module_CollectHelper','colors','bool') then - rules = CollectOnColors(rules, true) - end - previous = dt.gui.libs.collect.filter(rules) -end - -local function destroy() - dt.gui.libs.image.destroy_action("CollectHelper_prev") - if dt.preferences.read('module_CollectHelper','folder','bool') then - dt.gui.libs.image.destroy_action("CollectHelper_folder") - end - if dt.preferences.read('module_CollectHelper','colors','bool') then - dt.gui.libs.image.destroy_action("CollectHelper_labels") - end - if dt.preferences.read('module_CollectHelper','all_and','bool') then - dt.gui.libs.image.destroy_action("CollectHelper_and") - end -end - --- GUI -- -dt.gui.libs.image.register_action( - "CollectHelper_prev", _("collect: previous"), - function() PreviousCollection() end, - _("sets the collect parameters to be the previously active parameters") -) -if dt.preferences.read('module_CollectHelper','folder','bool') then - dt.gui.libs.image.register_action( - "CollectHelper_folder", _("collect: folder"), - function() CollectOnFolder(_ , false) end, - _("sets the collect parameters to be the selected images's folder") - ) -end -if dt.preferences.read('module_CollectHelper','colors','bool') then - dt.gui.libs.image.register_action( - "CollectHelper_labels", _("collect: color label(s)"), - function() CollectOnColors(_ , false) end, - _("sets the collect parameters to be the selected images's color label(s)") - ) -end -if dt.preferences.read('module_CollectHelper','all_and','bool') then - dt.gui.libs.image.register_action( - "CollectHelper_and", _("collect: all (AND)"), - function() CollectOnAll_AND() end, - _("sets the collect parameters based on all activated CollectHelper options") - ) -end - --- PREFERENCES -- -dt.preferences.register("module_CollectHelper", "all_and", -- name - "bool", -- type - _('CollectHelper: all'), -- label - _('will create a collect parameter set that utilizes all enabled CollectHelper types (and)'), -- tooltip - true -- default -) -dt.preferences.register("module_CollectHelper", "colors", -- name - "bool", -- type - _('CollectHelper: color label(s)'), -- label - _('enable the button that allows you to swap to a collection based on selected image\'s color label(s)'), -- tooltip - true -- default -) -dt.preferences.register("module_CollectHelper", "folder", -- name - "bool", -- type - _('CollectHelper: folder'), -- label - _('enable the button that allows you to swap to a collection based on selected image\'s folder location'), -- tooltip - true -- default -) - -script_data.destroy = destroy - -return script_data +--[[Collect Helper plugin for darktable + + copyright (c) 2019 Kevin Ertel + + darktable is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + darktable is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with darktable. If not, see . +]] + +--[[About this plugin +This plugin adds the button(s) to the "Selected Images" module: +1) Return to Previous Collection +2) Collect on image's Folder +3) Collect on image's Color Label(s) +4) Collect on All (AND) + +It also adds 3 preferences to the lua options dialog box which allow the user to activate/deactivate the 3 "Collect on" buttons. + +Button Behavior: +1) Return to Previous Collection - Will reset the collect parameters to the previously active settings +2) Collect on image's Folder - Will change the collect parameters to be "Folder" with a value of the selected image's folder location +3) Collect on image's Color Label(s) - Will change the collect parameter to be "Color" with a value of the selected images color labels, will apply multiple parameters with AND logic if multiple exist +4) Collect on All (AND) - Will collect on all parameters activated by the preferences dialog, as such this button is redundant if you only have one of the two other options enabled + +----REQUIRED SOFTWARE---- +NA + +----USAGE---- +Install: (see here for more detail: https://github.com/darktable-org/lua-scripts ) + 1) Copy this file in to your "lua/contrib" folder where all other scripts reside. + 2) Require this file in your luarc file, as with any other dt plug-in + +Select the photo you wish to change you collection based on. +In the "Selected Images" module click on "Collect on this Image" + +----KNOWN ISSUES---- +]] + +local dt = require "darktable" +local du = require "lib/dtutils" +local gettext = dt.gettext.gettext +local previous = nil +local all_active = false + +du.check_min_api_version("7.0.0", "CollectHelper") + +dt.gettext.bindtextdomain("CollectHelper", dt.configuration.config_dir .."/lua/locale/") + +local function _(msgid) + return gettext(msgid) +end + +-- return data structure for script_manager + +local script_data = {} + +script_data.metadata = { + name = "CollectHelper", + purpose = _("add collection helper buttons"), + author = "Kevin Ertel", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/CollectHelper/" +} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them + +-- FUNCTION -- +local function CheckSingleImage(selection) + if #selection ~= 1 then + dt.print(_("please select a single image")) + return true + end + return false +end + +local function CheckHasColorLabel(selection) + local ret = false + for _,image in pairs(selection) do + if image.red then ret = true end + if image.blue then ret = true end + if image.green then ret = true end + if image.yellow then ret = true end + if image.purple then ret = true end + end + return ret +end +local function PreviousCollection() + if previous ~= nil then + previous = dt.gui.libs.collect.filter(previous) + end +end + +local function CollectOnFolder(all_rules, all_active) + local images = dt.gui.selection() + if CheckSingleImage(images) then + return + end + local rules = {} + local rule = dt.gui.libs.collect.new_rule() + rule.mode = "DT_LIB_COLLECT_MODE_AND" + rule.data = images[1].path + rule.item = "DT_COLLECTION_PROP_FOLDERS" + table.insert(rules, rule) + if all_active then + for _,active_rule in pairs(rules) do + table.insert(all_rules, active_rule) + end + return all_rules + else + previous = dt.gui.libs.collect.filter(rules) + end +end + +local function CollectOnColors(all_rules, all_active) + local images = dt.gui.selection() + if CheckSingleImage(images) then + return + end + if not CheckHasColorLabel(images) then + dt.print(_('select an image with an active color label')) + return + end + for _,image in pairs(images) do + local rules = {} + if image.red then + local red_rule = dt.gui.libs.collect.new_rule() + red_rule.mode = "DT_LIB_COLLECT_MODE_AND" + red_rule.data = "red" + red_rule.item = "DT_COLLECTION_PROP_COLORLABEL" + table.insert(rules, red_rule) + end + if image.blue then + local blue_rule = dt.gui.libs.collect.new_rule() + blue_rule.mode = "DT_LIB_COLLECT_MODE_AND" + blue_rule.data = "blue" + blue_rule.item = "DT_COLLECTION_PROP_COLORLABEL" + table.insert(rules, blue_rule) + end + if image.green then + local green_rule = dt.gui.libs.collect.new_rule() + green_rule.mode = "DT_LIB_COLLECT_MODE_AND" + green_rule.data = "green" + green_rule.item = "DT_COLLECTION_PROP_COLORLABEL" + table.insert(rules, green_rule) + end + if image.yellow then + local yellow_rule = dt.gui.libs.collect.new_rule() + yellow_rule.mode = "DT_LIB_COLLECT_MODE_AND" + yellow_rule.data = "yellow" + yellow_rule.item = "DT_COLLECTION_PROP_COLORLABEL" + table.insert(rules, yellow_rule) + end + if image.purple then + local purple_rule = dt.gui.libs.collect.new_rule() + purple_rule.mode = "DT_LIB_COLLECT_MODE_AND" + purple_rule.data = "purple" + purple_rule.item = "DT_COLLECTION_PROP_COLORLABEL" + table.insert(rules, purple_rule) + end + if all_active then + for _,active_rule in pairs(rules) do + table.insert(all_rules, active_rule) + end + return all_rules + else + previous = dt.gui.libs.collect.filter(rules) + end + end +end + +local function CollectOnAll_AND() + local images = dt.gui.selection() + if CheckSingleImage(images) then + return + end + local rules = {} + if dt.preferences.read('module_CollectHelper','folder','bool') then + rules = CollectOnFolder(rules, true) + end + if dt.preferences.read('module_CollectHelper','colors','bool') then + rules = CollectOnColors(rules, true) + end + previous = dt.gui.libs.collect.filter(rules) +end + +local function destroy() + dt.gui.libs.image.destroy_action("CollectHelper_prev") + if dt.preferences.read('module_CollectHelper','folder','bool') then + dt.gui.libs.image.destroy_action("CollectHelper_folder") + end + if dt.preferences.read('module_CollectHelper','colors','bool') then + dt.gui.libs.image.destroy_action("CollectHelper_labels") + end + if dt.preferences.read('module_CollectHelper','all_and','bool') then + dt.gui.libs.image.destroy_action("CollectHelper_and") + end +end + +-- GUI -- +dt.gui.libs.image.register_action( + "CollectHelper_prev", _("collect: previous"), + function() PreviousCollection() end, + _("sets the collect parameters to be the previously active parameters") +) +if dt.preferences.read('module_CollectHelper','folder','bool') then + dt.gui.libs.image.register_action( + "CollectHelper_folder", _("collect: folder"), + function() CollectOnFolder(_ , false) end, + _("sets the collect parameters to be the selected images's folder") + ) +end +if dt.preferences.read('module_CollectHelper','colors','bool') then + dt.gui.libs.image.register_action( + "CollectHelper_labels", _("collect: color label(s)"), + function() CollectOnColors(_ , false) end, + _("sets the collect parameters to be the selected images's color label(s)") + ) +end +if dt.preferences.read('module_CollectHelper','all_and','bool') then + dt.gui.libs.image.register_action( + "CollectHelper_and", _("collect: all (AND)"), + function() CollectOnAll_AND() end, + _("sets the collect parameters based on all activated CollectHelper options") + ) +end + +-- PREFERENCES -- +dt.preferences.register("module_CollectHelper", "all_and", -- name + "bool", -- type + _('CollectHelper: all'), -- label + _('will create a collect parameter set that utilizes all enabled CollectHelper types (and)'), -- tooltip + true -- default +) +dt.preferences.register("module_CollectHelper", "colors", -- name + "bool", -- type + _('CollectHelper: color label(s)'), -- label + _('enable the button that allows you to swap to a collection based on selected image\'s color label(s)'), -- tooltip + true -- default +) +dt.preferences.register("module_CollectHelper", "folder", -- name + "bool", -- type + _('CollectHelper: folder'), -- label + _('enable the button that allows you to swap to a collection based on selected image\'s folder location'), -- tooltip + true -- default +) + +script_data.destroy = destroy + +return script_data diff --git a/contrib/HDRMerge.lua b/contrib/HDRMerge.lua index f365ec42..5ab1bee2 100644 --- a/contrib/HDRMerge.lua +++ b/contrib/HDRMerge.lua @@ -1,481 +1,488 @@ ---[[HDRMerge plugin for darktable - - copyright (c) 2018 Kevin Ertel - - darktable is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - darktable is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with darktable. If not, see . -]] - ---[[About this Plugin -This plugin adds the module 'HDRMerge' to darktable's lighttable view - -----REQUIRED SOFTWARE---- -HDRMerge ver. 4.5 or greater - -----USAGE---- -Install: (see here for more detail: https://github.com/darktable-org/lua-scripts ) - 1) Copy this file in to your 'lua/contrib' folder where all other scripts reside. - 2) Require this file in your luarc file, as with any other dt plug-in -On the initial startup go to darktable settings > lua options and set your executable paths and other preferences, then restart darktable - -Select bracketed images and press the Run HDRMerge button. The resulting DNG will be auto-imported into darktable. -Additional tags or style can be applied on auto import as well, if you desire. - -Base Options: -Select your desired BPS (bits per sample and Embedded Preview Size. - -Batch Options: -Select if you want to run in batch mode or not -Select the gap, in seconds, between images for auto grouping in batch mode - -See HDRMerge manual for further detail: http://jcelaya.github.io/hdrmerge/documentation/2014/07/11/user-manual.html - -Auto-import Options: -Select a style, whether you want tags to be copied from the original, and any additional tags you desire added when the new image is auto-imported -]] - -local dt = require 'darktable' -local du = require "lib/dtutils" -local df = require 'lib/dtutils.file' -local dsys = require 'lib/dtutils.system' - -du.check_min_api_version("7.0.0", "HDRmerge") - --- return data structure for script_manager - -local script_data = {} - -script_data.destroy = nil -- function to destory the script -script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil -script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again -script_data.show = nil -- only required for libs since the destroy_method only hides them - - -local mod = 'module_HDRMerge' -local os_path_seperator = '/' -if dt.configuration.running_os == 'windows' then os_path_seperator = '\\' end -local CURR_API_STRING = dt.configuration.api_version_string - --- Tell gettext where to find the .mo file translating messages for a particular domain -local gettext = dt.gettext.gettext - -gettext.bindtextdomain("HDRMerge", dt.configuration.config_dir .."/lua/locale/") - -local function _(msgid) - return gettext(msgid) -end - -local temp -local HDRM = { --HDRMerge Program Table - name = 'HDRMerge', - bin = '', - first_run = true, - install_error = false, - arg_string = '', - images_string = '', - args = { - bps = {text = '-b ', style = 'integer'}, - size = {text = '-p ', style = 'string'}, - batch = {text = '-B ', style = 'bool'}, - gap = {text = '-g ', style = 'integer'} - } -} -local GUI = { --GUI Elements Table - HDR = { - bps ={}, - size ={}, - batch ={}, - gap ={} - }, - Target = { - style ={}, - copy_tags ={}, - add_tags ={} - }, - run = {}, - stack = {}, - options = {}, - exes = { - HDRMerge = {}, - update = {}, - } -} - -HDRM.module_installed = false -HDRM.event_registered = false - - ---Detect User Styles-- -local styles = dt.styles -local styles_count = 1 -- 'none' = 1 -for _,i in pairs(dt.styles) do - if type(i) == 'userdata' then styles_count = styles_count + 1 end -end - -local function InRange(test, low, high) --tests if test value is within range of low and high (inclusive) - if test >= low and test <= high then - return true - else - return false - end -end - -local function GetFileName(full_path) --Parses a full path (path/filename_identifier.extension) into individual parts ---[[Input: Folder1/Folder2/Folder3/Img_0001.CR2 - - Returns: - path: Folder1/Folder2/Folder3/ - filename: Img_0001 - identifier: 0001 - extension: .CR2 - - EX: - path_1, file_1, id_1, ext_1 = GetFileName(full_path_1) - ]] - local path = string.match(full_path, '.*[\\/]') - local filename = string.gsub(string.match(full_path, '[%w-_]*%.') , '%.' , '' ) - local identifier = string.match(filename, '%d*$') - local extension = string.match(full_path, '%.%w*') - return path, filename, identifier, extension -end - -local function CleanSpaces(text) --removes spaces from the front and back of passed in text - text = string.gsub(text,'^%s*','') - text = string.gsub(text,'%s*$','') - return text -end - -local function BuildExecuteCmd(prog_table) --creates a program command using elements of the passed in program table - local result = CleanSpaces(prog_table.bin)..' '..CleanSpaces(prog_table.arg_string)..' '..CleanSpaces(prog_table.images_string) - return result -end - -local function PreCall(prog_tbl) --looks to see if this is the first call, if so checks to see if program is installed properly - for _,prog in pairs(prog_tbl) do - if prog.first_run then - prog.bin = df.check_if_bin_exists(prog.name) - if not prog.bin then - prog.install_error = true - dt.preferences.write(mod, 'bin_exists', 'bool', false) - else - prog.bin = CleanSpaces(prog.bin) - end - prog.first_run = false - end - end - if not dt.preferences.read(mod, 'bin_exists', 'bool') then - GUI.stack.active = 2 - dt.print(_('please update you binary location')) - end -end - -local function ExeUpdate(prog_tbl) - dt.preferences.write(mod, 'bin_exists', 'bool', true) - for _,prog in pairs(prog_tbl) do - dt.preferences.write('executable_paths', prog.name, 'string', GUI.exes[prog.name].value) - prog.bin = df.check_if_bin_exists(prog.name) - if not prog.bin then - prog.install_error = true - dt.preferences.write(mod, 'bin_exists', 'bool', false) - else - prog.bin = CleanSpaces(prog.bin) - end - prog.first_run = false - end - if dt.preferences.read(mod, 'bin_exists', 'bool') then - GUI.stack.active = 1 - dt.print(_('update successful')) - else - dt.print(_('update unsuccessful, please try again')) - end -end - -local function UpdateActivePreference() --sliders & entry boxes do not have a click/changed callback, so their values must be saved to the active preference - temp = GUI.HDR.gap.value - dt.preferences.write(mod, 'active_gap', 'integer', temp) - temp = GUI.Target.add_tags.text - dt.preferences.write(mod, 'active_add_tags', 'string', temp) -end - -local function main() - PreCall({HDRM}) --check if furst run then check if install OK - if HDRM.install_error then - dt.print_error('HDRMerge install issue') - dt.print(_('HDRMerge install issue, please ensure the binary path is proper')) - return - end - images = dt.gui.selection() --get selected images - if #images < 2 then --ensure enough images selected - dt.print(_('not enough images selected, select at least 2 images to merge')) - return - end - - UpdateActivePreference() --save current gui elements to active preference so those values will be pre-loaded at next startup - - --create image string and output path - HDRM.images_string = '' - local out_path = '' - local smallest_id = math.huge - local smallest_name = '' - local largest_id = 0 - local source_raw = {} - for _,image in pairs(images) do --loop to concat the images string, also track the image indexes for use in creating the final image name (eg; IMG_1034-1037.dng) - local curr_image = image.path..os_path_seperator..image.filename - HDRM.images_string = HDRM.images_string..df.sanitize_filename(curr_image)..' ' - out_path = image.path - _unused, source_name, source_id = GetFileName(image.filename) - source_id = tonumber(source_id) or 0 - if source_id < smallest_id then - smallest_id = source_id - smallest_name = source_name - source_raw = image - end - if source_id > largest_id then largest_id = source_id end - end - out_path = out_path..os_path_seperator..smallest_name..'-'..largest_id..'.dng' - out_path = df.create_unique_filename(out_path) - - --create argument string - HDRM.arg_string = HDRM.args.bps.text..GUI.HDR.bps.value..' '..HDRM.args.size.text..GUI.HDR.size.value..' ' - if GUI.HDR.batch.value then - HDRM.arg_string = HDRM.arg_string..HDRM.args.batch.text..HDRM.args.gap.text..math.floor(GUI.HDR.gap.value)..' -a' - else - HDRM.arg_string = HDRM.arg_string..'-o '..df.sanitize_filename(out_path) - end - - -- create run command and execute - local run_cmd = BuildExecuteCmd(HDRM) - resp = dsys.external_command(run_cmd) - - if resp == 0 and not GUI.HDR.batch.value then - local imported = dt.database.import(out_path) -- import the new file - if GUI.Target.style.selected > 1 then -- apply selected style - local set_style = styles[GUI.Target.style.selected - 1] - dt.styles.apply(set_style , imported) - end - if GUI.Target.copy_tags.value then -- copy tags from the original file (ignore 'darktable' generated tags) - local all_tags = dt.tags.get_tags(source_raw) - for _,tag in pairs(all_tags) do - if string.match(tag.name, 'darktable|') == nil then dt.tags.attach(tag, imported) end - end - end - local set_tag = GUI.Target.add_tags.text - if set_tag ~= nil then -- add additional user-specified tags - for tag in string.gmatch(set_tag, '[^,]+') do - tag = CleanSpaces(tag) - tag = dt.tags.create(tag) - dt.tags.attach(tag, imported) - end - end - dt.print(_('HDRMerge completed successfully')) - else - dt.print_error('HDRMerge failed') - dt.print(_('HDRMerge failed')) - end - -end - -local function install_module() - if not HDRM.module_installed then - dt.register_lib( -- register HDRMerge module - 'HDRMerge_Lib', -- Module name - _('HDRMerge'), -- name - true, -- expandable - true, -- resetable - {[dt.gui.views.lighttable] = {'DT_UI_CONTAINER_PANEL_RIGHT_CENTER', 99}}, -- containers - dt.new_widget('box'){ - orientation = 'vertical', - GUI.stack - } - ) - HDRM.module_installed = true - end -end - -local function destroy() - dt.gui.libs["HDRMerge_Lib"].visible = false -end - -local function restart() - dt.gui.libs["HDRMerge_Lib"].visible = true -end - --- GUI Elements -- -local lbl_hdr = dt.new_widget('section_label'){ - label = _('HDRMerge options') -} -temp = dt.preferences.read(mod, 'active_bps_ind', 'integer') -if not InRange(temp, 1, 3) then temp = 3 end -GUI.HDR.bps = dt.new_widget('combobox'){ - label = _('bits per sample'), - tooltip =_('number of bits per sample in the output image'), - selected = temp, - '16','24','32', - changed_callback = function(self) - dt.preferences.write(mod, 'active_bps', 'integer', self.value) - dt.preferences.write(mod, 'active_bps_ind', 'integer', self.selected) - end, - reset_callback = function(self) - self.selected = 3 - dt.preferences.write(mod, 'active_bps', 'integer', self.value) - dt.preferences.write(mod, 'active_bps_ind', 'integer', self.selected) - end -} -temp = dt.preferences.read(mod, 'active_size_ind', 'integer') -if not InRange(temp, 1, 3) then temp = 2 end -GUI.HDR.size = dt.new_widget('combobox'){ - label = _('embedded preview size'), - tooltip =_('size of the embedded preview in output image'), - selected = temp, - _('none'),_('half'),_('full'), - changed_callback = function(self) - dt.preferences.write(mod, 'active_size', 'string', self.value) - dt.preferences.write(mod, 'active_size_ind', 'integer', self.selected) - end, - reset_callback = function(self) - self.selected = 2 - dt.preferences.write(mod, 'active_size', 'string', self.value) - dt.preferences.write(mod, 'active_size_ind', 'integer', self.selected) - end -} -GUI.HDR.batch = dt.new_widget('check_button'){ - label = _('batch mode'), - value = dt.preferences.read(mod, 'active_batch', 'bool'), - tooltip = _('enable batch mode operation \nNOTE: resultant files will NOT be auto-imported'), - clicked_callback = function(self) - dt.preferences.write(mod, 'active_batch', 'bool', self.value) - GUI.HDR.gap.sensitive = self.value - end, - reset_callback = function(self) self.value = false end -} -temp = dt.preferences.read(mod, 'active_gap', 'integer') -if not InRange(temp, 1, 3600) then temp = 3 end -GUI.HDR.gap = dt.new_widget('slider'){ - label = _('batch gap [sec.]'), - tooltip = _('gap, in seconds, between batch mode groups'), - soft_min = 1, - soft_max = 30, - hard_min = 1, - hard_max = 3600, - step = 1, - digits = 0, - value = temp, - sensitive = GUI.HDR.batch.value, - reset_callback = function(self) - self.value = 3 - end -} -local lbl_import = dt.new_widget('section_label'){ - label = _('import options') -} -GUI.Target.style = dt.new_widget('combobox'){ - label = _('apply style on import'), - tooltip = _('apply selected style on auto-import to newly created image'), - selected = 1, - _('none'), - changed_callback = function(self) - dt.preferences.write(mod, 'active_style', 'string', self.value) - dt.preferences.write(mod, 'active_style_ind', 'integer', self.selected) - end, - reset_callback = function(self) - self.selected = 1 - dt.preferences.write(mod, 'active_style', 'string', self.value) - dt.preferences.write(mod, 'active_style_ind', 'integer', self.selected) - end -} -for k=1, (styles_count-1) do - GUI.Target.style[k+1] = styles[k].name -end -temp = dt.preferences.read(mod, 'active_style_ind', 'integer') -if not InRange(temp, 1, styles_count) then temp = 1 end -GUI.Target.style.selected = temp -GUI.Target.copy_tags = dt.new_widget('check_button'){ - label = _('copy tags'), - value = dt.preferences.read(mod, 'active_copy_tags', 'bool'), - tooltip = _('copy tags from first source image'), - clicked_callback = function(self) dt.preferences.write(mod, 'active_copy_tags', 'bool', self.value) end, - reset_callback = function(self) self.value = true end -} -temp = dt.preferences.read(mod, 'active_add_tags', 'string') -if temp == '' then temp = nil end -GUI.Target.add_tags = dt.new_widget('entry'){ - tooltip = _('additional tags to be added on import, seperate with commas, all spaces will be removed'), - text = temp, - placeholder = _('enter tags, seperated by commas'), - editable = true -} -GUI.run = dt.new_widget('button'){ - label = _('merge'), - tooltip =_('run HDRMerge with the above specified settings'), - clicked_callback = function() main() end -} -GUI.exes.HDRMerge = dt.new_widget('file_chooser_button'){ - title = _('select HDRmerge executable'), - value = df.get_executable_path_preference(HDRM.name), - is_directory = false -} -GUI.exes.update = dt.new_widget('button'){ - label = _('update'), - tooltip =_('update the binary path with current value'), - clicked_callback = function() ExeUpdate({HDRM}) end -} -GUI.options = dt.new_widget('box'){ - orientation = 'vertical', - lbl_hdr, - GUI.HDR.bps, - GUI.HDR.size, - GUI.HDR.batch, - GUI.HDR.gap, - lbl_import, - GUI.Target.style, - GUI.Target.copy_tags, - GUI.Target.add_tags, - GUI.run -} -local exes_box = dt.new_widget('box'){ - orientation = 'vertical', - GUI.exes.HDRMerge, - GUI.exes.update -} -GUI.stack = dt.new_widget('stack'){ - GUI.options, - exes_box -} -if dt.preferences.read(mod, 'bin_exists', 'bool') then - GUI.stack.active = 1 -else - GUI.stack.active = 2 -end - -if dt.gui.current_view().id == "lighttable" then - install_module() -else - if not HDRM.event_registered then - dt.register_event( - "HDRmerge", "view-changed", - function(event, old_view, new_view) - if new_view.name == "lighttable" and old_view.name == "darkroom" then - install_module() - end - end - ) - HDRM.event_registered = true - end -end - -script_data.destroy = destroy -script_data.restart = restart -script_data.destroy_method = "hide" -script_data.show = restart - +--[[HDRMerge plugin for darktable + + copyright (c) 2018 Kevin Ertel + + darktable is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + darktable is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with darktable. If not, see . +]] + +--[[About this Plugin +This plugin adds the module 'HDRMerge' to darktable's lighttable view + +----REQUIRED SOFTWARE---- +HDRMerge ver. 4.5 or greater + +----USAGE---- +Install: (see here for more detail: https://github.com/darktable-org/lua-scripts ) + 1) Copy this file in to your 'lua/contrib' folder where all other scripts reside. + 2) Require this file in your luarc file, as with any other dt plug-in +On the initial startup go to darktable settings > lua options and set your executable paths and other preferences, then restart darktable + +Select bracketed images and press the Run HDRMerge button. The resulting DNG will be auto-imported into darktable. +Additional tags or style can be applied on auto import as well, if you desire. + +Base Options: +Select your desired BPS (bits per sample and Embedded Preview Size. + +Batch Options: +Select if you want to run in batch mode or not +Select the gap, in seconds, between images for auto grouping in batch mode + +See HDRMerge manual for further detail: http://jcelaya.github.io/hdrmerge/documentation/2014/07/11/user-manual.html + +Auto-import Options: +Select a style, whether you want tags to be copied from the original, and any additional tags you desire added when the new image is auto-imported +]] + +local dt = require 'darktable' +local du = require "lib/dtutils" +local df = require 'lib/dtutils.file' +local dsys = require 'lib/dtutils.system' + +du.check_min_api_version("7.0.0", "HDRmerge") + +-- Tell gettext where to find the .mo file translating messages for a particular domain +local gettext = dt.gettext.gettext + +dt.gettext.bindtextdomain("HDRMerge", dt.configuration.config_dir .."/lua/locale/") + +local function _(msgid) + return gettext(msgid) +end + +-- return data structure for script_manager + +local script_data = {} + +script_data.metadata = { + name = "HDRmerge", + purpose = _("merge bracketed images into an HDR DNG image"), + author = "Kevin Ertel", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/HDRmerge" +} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them + + +local mod = 'module_HDRMerge' +local os_path_seperator = '/' +if dt.configuration.running_os == 'windows' then os_path_seperator = '\\' end +local CURR_API_STRING = dt.configuration.api_version_string + +local temp +local HDRM = { --HDRMerge Program Table + name = 'HDRMerge', + bin = '', + first_run = true, + install_error = false, + arg_string = '', + images_string = '', + args = { + bps = {text = '-b ', style = 'integer'}, + size = {text = '-p ', style = 'string'}, + batch = {text = '-B ', style = 'bool'}, + gap = {text = '-g ', style = 'integer'} + } +} +local GUI = { --GUI Elements Table + HDR = { + bps ={}, + size ={}, + batch ={}, + gap ={} + }, + Target = { + style ={}, + copy_tags ={}, + add_tags ={} + }, + run = {}, + stack = {}, + options = {}, + exes = { + HDRMerge = {}, + update = {}, + } +} + +HDRM.module_installed = false +HDRM.event_registered = false + + +--Detect User Styles-- +local styles = dt.styles +local styles_count = 1 -- 'none' = 1 +for _,i in pairs(dt.styles) do + if type(i) == 'userdata' then styles_count = styles_count + 1 end +end + +local function InRange(test, low, high) --tests if test value is within range of low and high (inclusive) + if test >= low and test <= high then + return true + else + return false + end +end + +local function GetFileName(full_path) --Parses a full path (path/filename_identifier.extension) into individual parts +--[[Input: Folder1/Folder2/Folder3/Img_0001.CR2 + + Returns: + path: Folder1/Folder2/Folder3/ + filename: Img_0001 + identifier: 0001 + extension: .CR2 + + EX: + path_1, file_1, id_1, ext_1 = GetFileName(full_path_1) + ]] + local path = string.match(full_path, '.*[\\/]') + local filename = string.gsub(string.match(full_path, '[%w-_]*%.') , '%.' , '' ) + local identifier = string.match(filename, '%d*$') + local extension = string.match(full_path, '%.%w*') + return path, filename, identifier, extension +end + +local function CleanSpaces(text) --removes spaces from the front and back of passed in text + text = string.gsub(text,'^%s*','') + text = string.gsub(text,'%s*$','') + return text +end + +local function BuildExecuteCmd(prog_table) --creates a program command using elements of the passed in program table + local result = CleanSpaces(prog_table.bin)..' '..CleanSpaces(prog_table.arg_string)..' '..CleanSpaces(prog_table.images_string) + return result +end + +local function PreCall(prog_tbl) --looks to see if this is the first call, if so checks to see if program is installed properly + for _,prog in pairs(prog_tbl) do + if prog.first_run then + prog.bin = df.check_if_bin_exists(prog.name) + if not prog.bin then + prog.install_error = true + dt.preferences.write(mod, 'bin_exists', 'bool', false) + else + prog.bin = CleanSpaces(prog.bin) + end + prog.first_run = false + end + end + if not dt.preferences.read(mod, 'bin_exists', 'bool') then + GUI.stack.active = 2 + dt.print(_('please update you binary location')) + end +end + +local function ExeUpdate(prog_tbl) + dt.preferences.write(mod, 'bin_exists', 'bool', true) + for _,prog in pairs(prog_tbl) do + dt.preferences.write('executable_paths', prog.name, 'string', GUI.exes[prog.name].value) + prog.bin = df.check_if_bin_exists(prog.name) + if not prog.bin then + prog.install_error = true + dt.preferences.write(mod, 'bin_exists', 'bool', false) + else + prog.bin = CleanSpaces(prog.bin) + end + prog.first_run = false + end + if dt.preferences.read(mod, 'bin_exists', 'bool') then + GUI.stack.active = 1 + dt.print(_('update successful')) + else + dt.print(_('update unsuccessful, please try again')) + end +end + +local function UpdateActivePreference() --sliders & entry boxes do not have a click/changed callback, so their values must be saved to the active preference + temp = GUI.HDR.gap.value + dt.preferences.write(mod, 'active_gap', 'integer', temp) + temp = GUI.Target.add_tags.text + dt.preferences.write(mod, 'active_add_tags', 'string', temp) +end + +local function main() + PreCall({HDRM}) --check if furst run then check if install OK + if HDRM.install_error then + dt.print_error('HDRMerge install issue') + dt.print(_('HDRMerge install issue, please ensure the binary path is proper')) + return + end + images = dt.gui.selection() --get selected images + if #images < 2 then --ensure enough images selected + dt.print(_('not enough images selected, select at least 2 images to merge')) + return + end + + UpdateActivePreference() --save current gui elements to active preference so those values will be pre-loaded at next startup + + --create image string and output path + HDRM.images_string = '' + local out_path = '' + local smallest_id = math.huge + local smallest_name = '' + local largest_id = 0 + local source_raw = {} + for _,image in pairs(images) do --loop to concat the images string, also track the image indexes for use in creating the final image name (eg; IMG_1034-1037.dng) + local curr_image = image.path..os_path_seperator..image.filename + HDRM.images_string = HDRM.images_string..df.sanitize_filename(curr_image)..' ' + out_path = image.path + _unused, source_name, source_id = GetFileName(image.filename) + source_id = tonumber(source_id) or 0 + if source_id < smallest_id then + smallest_id = source_id + smallest_name = source_name + source_raw = image + end + if source_id > largest_id then largest_id = source_id end + end + out_path = out_path..os_path_seperator..smallest_name..'-'..largest_id..'.dng' + out_path = df.create_unique_filename(out_path) + + --create argument string + HDRM.arg_string = HDRM.args.bps.text..GUI.HDR.bps.value..' '..HDRM.args.size.text..GUI.HDR.size.value..' ' + if GUI.HDR.batch.value then + HDRM.arg_string = HDRM.arg_string..HDRM.args.batch.text..HDRM.args.gap.text..math.floor(GUI.HDR.gap.value)..' -a' + else + HDRM.arg_string = HDRM.arg_string..'-o '..df.sanitize_filename(out_path) + end + + -- create run command and execute + local run_cmd = BuildExecuteCmd(HDRM) + resp = dsys.external_command(run_cmd) + + if resp == 0 and not GUI.HDR.batch.value then + local imported = dt.database.import(out_path) -- import the new file + if GUI.Target.style.selected > 1 then -- apply selected style + local set_style = styles[GUI.Target.style.selected - 1] + dt.styles.apply(set_style , imported) + end + if GUI.Target.copy_tags.value then -- copy tags from the original file (ignore 'darktable' generated tags) + local all_tags = dt.tags.get_tags(source_raw) + for _,tag in pairs(all_tags) do + if string.match(tag.name, 'darktable|') == nil then dt.tags.attach(tag, imported) end + end + end + local set_tag = GUI.Target.add_tags.text + if set_tag ~= nil then -- add additional user-specified tags + for tag in string.gmatch(set_tag, '[^,]+') do + tag = CleanSpaces(tag) + tag = dt.tags.create(tag) + dt.tags.attach(tag, imported) + end + end + dt.print(_('HDRMerge completed successfully')) + else + dt.print_error('HDRMerge failed') + dt.print(_('HDRMerge failed')) + end + +end + +local function install_module() + if not HDRM.module_installed then + dt.register_lib( -- register HDRMerge module + 'HDRMerge_Lib', -- Module name + _('HDRMerge'), -- name + true, -- expandable + true, -- resetable + {[dt.gui.views.lighttable] = {'DT_UI_CONTAINER_PANEL_RIGHT_CENTER', 99}}, -- containers + dt.new_widget('box'){ + orientation = 'vertical', + GUI.stack + } + ) + HDRM.module_installed = true + end +end + +local function destroy() + dt.gui.libs["HDRMerge_Lib"].visible = false +end + +local function restart() + dt.gui.libs["HDRMerge_Lib"].visible = true +end + +-- GUI Elements -- +local lbl_hdr = dt.new_widget('section_label'){ + label = _('HDRMerge options') +} +temp = dt.preferences.read(mod, 'active_bps_ind', 'integer') +if not InRange(temp, 1, 3) then temp = 3 end +GUI.HDR.bps = dt.new_widget('combobox'){ + label = _('bits per sample'), + tooltip =_('number of bits per sample in the output image'), + selected = temp, + '16','24','32', + changed_callback = function(self) + dt.preferences.write(mod, 'active_bps', 'integer', self.value) + dt.preferences.write(mod, 'active_bps_ind', 'integer', self.selected) + end, + reset_callback = function(self) + self.selected = 3 + dt.preferences.write(mod, 'active_bps', 'integer', self.value) + dt.preferences.write(mod, 'active_bps_ind', 'integer', self.selected) + end +} +temp = dt.preferences.read(mod, 'active_size_ind', 'integer') +if not InRange(temp, 1, 3) then temp = 2 end +GUI.HDR.size = dt.new_widget('combobox'){ + label = _('embedded preview size'), + tooltip =_('size of the embedded preview in output image'), + selected = temp, + _('none'),_('half'),_('full'), + changed_callback = function(self) + dt.preferences.write(mod, 'active_size', 'string', self.value) + dt.preferences.write(mod, 'active_size_ind', 'integer', self.selected) + end, + reset_callback = function(self) + self.selected = 2 + dt.preferences.write(mod, 'active_size', 'string', self.value) + dt.preferences.write(mod, 'active_size_ind', 'integer', self.selected) + end +} +GUI.HDR.batch = dt.new_widget('check_button'){ + label = _('batch mode'), + value = dt.preferences.read(mod, 'active_batch', 'bool'), + tooltip = _('enable batch mode operation \nNOTE: resultant files will NOT be auto-imported'), + clicked_callback = function(self) + dt.preferences.write(mod, 'active_batch', 'bool', self.value) + GUI.HDR.gap.sensitive = self.value + end, + reset_callback = function(self) self.value = false end +} +temp = dt.preferences.read(mod, 'active_gap', 'integer') +if not InRange(temp, 1, 3600) then temp = 3 end +GUI.HDR.gap = dt.new_widget('slider'){ + label = _('batch gap [sec.]'), + tooltip = _('gap, in seconds, between batch mode groups'), + soft_min = 1, + soft_max = 30, + hard_min = 1, + hard_max = 3600, + step = 1, + digits = 0, + value = temp, + sensitive = GUI.HDR.batch.value, + reset_callback = function(self) + self.value = 3 + end +} +local lbl_import = dt.new_widget('section_label'){ + label = _('import options') +} +GUI.Target.style = dt.new_widget('combobox'){ + label = _('apply style on import'), + tooltip = _('apply selected style on auto-import to newly created image'), + selected = 1, + _('none'), + changed_callback = function(self) + dt.preferences.write(mod, 'active_style', 'string', self.value) + dt.preferences.write(mod, 'active_style_ind', 'integer', self.selected) + end, + reset_callback = function(self) + self.selected = 1 + dt.preferences.write(mod, 'active_style', 'string', self.value) + dt.preferences.write(mod, 'active_style_ind', 'integer', self.selected) + end +} +for k=1, (styles_count-1) do + GUI.Target.style[k+1] = styles[k].name +end +temp = dt.preferences.read(mod, 'active_style_ind', 'integer') +if not InRange(temp, 1, styles_count) then temp = 1 end +GUI.Target.style.selected = temp +GUI.Target.copy_tags = dt.new_widget('check_button'){ + label = _('copy tags'), + value = dt.preferences.read(mod, 'active_copy_tags', 'bool'), + tooltip = _('copy tags from first source image'), + clicked_callback = function(self) dt.preferences.write(mod, 'active_copy_tags', 'bool', self.value) end, + reset_callback = function(self) self.value = true end +} +temp = dt.preferences.read(mod, 'active_add_tags', 'string') +if temp == '' then temp = nil end +GUI.Target.add_tags = dt.new_widget('entry'){ + tooltip = _('additional tags to be added on import, seperate with commas, all spaces will be removed'), + text = temp, + placeholder = _('enter tags, seperated by commas'), + editable = true +} +GUI.run = dt.new_widget('button'){ + label = _('merge'), + tooltip =_('run HDRMerge with the above specified settings'), + clicked_callback = function() main() end +} +GUI.exes.HDRMerge = dt.new_widget('file_chooser_button'){ + title = _('select HDRmerge executable'), + value = df.get_executable_path_preference(HDRM.name), + is_directory = false +} +GUI.exes.update = dt.new_widget('button'){ + label = _('update'), + tooltip =_('update the binary path with current value'), + clicked_callback = function() ExeUpdate({HDRM}) end +} +GUI.options = dt.new_widget('box'){ + orientation = 'vertical', + lbl_hdr, + GUI.HDR.bps, + GUI.HDR.size, + GUI.HDR.batch, + GUI.HDR.gap, + lbl_import, + GUI.Target.style, + GUI.Target.copy_tags, + GUI.Target.add_tags, + GUI.run +} +local exes_box = dt.new_widget('box'){ + orientation = 'vertical', + GUI.exes.HDRMerge, + GUI.exes.update +} +GUI.stack = dt.new_widget('stack'){ + GUI.options, + exes_box +} +if dt.preferences.read(mod, 'bin_exists', 'bool') then + GUI.stack.active = 1 +else + GUI.stack.active = 2 +end + +if dt.gui.current_view().id == "lighttable" then + install_module() +else + if not HDRM.event_registered then + dt.register_event( + "HDRmerge", "view-changed", + function(event, old_view, new_view) + if new_view.name == "lighttable" and old_view.name == "darkroom" then + install_module() + end + end + ) + HDRM.event_registered = true + end +end + +script_data.destroy = destroy +script_data.restart = restart +script_data.destroy_method = "hide" +script_data.show = restart + return script_data \ No newline at end of file diff --git a/contrib/LabelsToTags.lua b/contrib/LabelsToTags.lua index c41c6ad6..6046f9c3 100644 --- a/contrib/LabelsToTags.lua +++ b/contrib/LabelsToTags.lua @@ -52,9 +52,9 @@ local du = require "lib/dtutils" du.check_min_api_version("7.0.0", "LabelsToTags") -local gettext = dt.gettext.gettext +local gettext = darktable.gettext.gettext -gettext.bindtextdomain("LabelsToTags", dt.configuration.config_dir .."/lua/locale/") +darktable.gettext.bindtextdomain("LabelsToTags", darktable.configuration.config_dir .."/lua/locale/") local function _(msgid) return gettext(msgid) @@ -64,6 +64,13 @@ end local script_data = {} +script_data.metadata = { + name = "LabelsToTags", + purpose = _("allows the mass-application of tags using color labels and ratings as a guide"), + author = "August Schwerdfeger (august@schwerdfeger.name)", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/LabelsToTags" +} + script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again diff --git a/contrib/OpenInExplorer.lua b/contrib/OpenInExplorer.lua index d375af75..dba04d02 100644 --- a/contrib/OpenInExplorer.lua +++ b/contrib/OpenInExplorer.lua @@ -1,237 +1,244 @@ ---[[ -OpenInExplorer plugin for darktable - - copyright (c) 2018 Kevin Ertel - Update 2020 and macOS support by Volker Lenhardt - Linux support 2020 by Bill Ferguson - - darktable is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - darktable is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with darktable. If not, see . -]] - ---[[About this plugin -This plugin adds the module "OpenInExplorer" to darktable's lighttable view. - -----REQUIRED SOFTWARE---- -Apple macOS, Microsoft Windows or Linux - -----USAGE---- -Install: (see here for more detail: https://github.com/darktable-org/lua-scripts ) - 1) Copy this file into your "lua/contrib" folder where all other scripts reside. - 2) Require this file in your luarc file, as with any other dt plug-in - -Select the photo(s) you wish to find in your operating system's file manager and press "show in file explorer" in the "selected images" section. - -- Nautilus (Linux), Explorer (Windows), and Finder (macOS prior to Mojave) will open one window for each selected image at the file's location. The file name will be highlighted. - -- On macOS Mojave and Catalina the Finder will open one window for each different directory. In these windows only the last one of the corresponding files will be highlighted (bug or feature?). - -- Dolphin (Linux) will open one window with tabs for the different directories. All the selected images' file names are highlighted in their respective directories. - -As an alternative option you can choose to show the image file names as symbolic links in an arbitrary directory. Go to preferences|Lua options. This option is not available for Windows users as on Windows solely admins are allowed to create links. - -- Pros: You do not clutter up your display with multiple windows. So there is no need to limit the number of selections. - -- Cons: If you want to work with the files you are one step behind the original data. - -----KNOWN ISSUES---- -]] - -local dt = require "darktable" -local du = require "lib/dtutils" -local df = require "lib/dtutils.file" -local dsys = require "lib/dtutils.system" -local gettext = dt.gettext.gettext - ---Check API version -du.check_min_api_version("7.0.0", "OpenInExplorer") - --- return data structure for script_manager - -local script_data = {} - -script_data.destroy = nil -- function to destory the script -script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil -script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again -script_data.show = nil -- only required for libs since the destroy_method only hides them - -gettext.bindtextdomain("OpenInExplorer", dt.configuration.config_dir .."/lua/locale/") - -local function _(msgid) - return gettext(msgid) -end - -local act_os = dt.configuration.running_os -local PS = act_os == "windows" and "\\" or "/" - ---Detect OS and quit if it is not supported. -if act_os ~= "macos" and act_os ~= "windows" and act_os ~= "linux" then - dt.print(_("OpenInExplorer plug-in only supports linux, macos, and windows at this time")) - dt.print_error("OpenInExplorer plug-in only supports Linux, macOS, and Windows at this time") - return -end - -local use_links, links_dir = false, "" -if act_os ~= "windows" then - use_links = dt.preferences.read("OpenInExplorer", "use_links", "bool") - links_dir = dt.preferences.read("OpenInExplorer", "linked_image_files_dir", "string") -end - ---Check if the directory exists that was chosen for the file links. Return boolean. -local function check_if_links_dir_exists() - local dir_exists = true - if not links_dir then - --Just for paranoic reasons. I tried, but I couldn't devise a setting for a nil value. - dt.print(_("no links directory selected\nplease check the dt preferences (lua options)")) - dt.print_error("OpenInExplorer: No links directory selected") - dir_exists = false - elseif not df.check_if_file_exists(links_dir) then - dt.print(string.format(_("links directory '%s' not found\nplease check the dt preferences (lua options)"), links_dir)) - dt.print_error(string.format("OpenInExplorer: Links directory '%s' not found", links_dir)) - dir_exists = false - end - return dir_exists -end - ---Format strings for the commands to open the corresponding OS's file manager. -local open_dir = {} -open_dir.windows = "explorer.exe /n, %s" -open_dir.macos = "open %s" -open_dir.linux = [[busctl --user call org.freedesktop.FileManager1 /org/freedesktop/FileManager1 org.freedesktop.FileManager1 ShowFolders ass 1 %s ""]] - -local open_files = {} -open_files.windows = "explorer.exe /select, %s" -open_files.macos = "open -Rn %s" -open_files.linux = [[busctl --user call org.freedesktop.FileManager1 /org/freedesktop/FileManager1 org.freedesktop.FileManager1 ShowItems ass %d %s ""]] - ---Call the file mangager for each selected image on Linux. ---There is one call to busctl containing a list of all the image file names. -local function call_list_of_files(selected_images) - local current_image, file_uris, run_cmd = "", "", "" - for _, image in pairs(selected_images) do - current_image = image.path..PS..image.filename - file_uris = file_uris .. df.sanitize_filename("file://" .. current_image) .. " " - dt.print_log("file_uris is " .. file_uris) - end - run_cmd = string.format(open_files.linux, #selected_images, file_uris) - dt.print_log("OpenInExplorer run_cmd = "..run_cmd) - dsys.external_command(run_cmd) -end - ---Call the file manager for each selected image on Windows and macOS. -local function call_file_by_file(selected_images) - local current_image, run_cmd = "", "" - for _, image in pairs(selected_images) do - current_image = image.path..PS..image.filename - run_cmd = string.format(open_files[act_os], df.sanitize_filename(current_image)) - dt.print_log("OpenInExplorer run_cmd = "..run_cmd) - dsys.external_command(run_cmd) - end -end - ---Create a link for each selected image, and finally call the file manager. -local function set_links(selected_images) - local current_image, link_target, run_cmd, k = "", "", "", nil - for k, image in pairs(selected_images) do - current_image = image.path..PS..image.filename - link_target = df.create_unique_filename(links_dir .. PS .. image.filename) - run_cmd = string.format("ln -s %s %s", df.sanitize_filename(current_image), df.sanitize_filename(link_target)) - --[[ - In case Windows will allow normal users to create soft links: - if act_os == "windows" then - run_cmd = string.format("mklink %s %s", df.sanitize_filename(link_target), df.sanitize_filename(current_image)) - end - ]] - if dsys.external_command(run_cmd) ~= 0 then - dt.print(_("failed to create links, missing rights?")) - dt.print_error("OpenInExplorer: Failed to create links") - return - end - end - --The URI format is necessary only for the Linux busctl command. - --But it is accepted by the Windows Explorer and macOS's Finder all the same. - run_cmd = string.format(open_dir[act_os], df.sanitize_filename("file://"..links_dir)) - dt.print_log("OpenInExplorer run_cmd = "..run_cmd) - dsys.external_command(run_cmd) -end - ---The working function that starts the particular task. -local function open_in_fmanager() - local images = dt.gui.selection() - if #images == 0 then - dt.print(_("please select an image")) - else - if use_links and not check_if_links_dir_exists() then - return - end - if #images > 15 and not use_links then - dt.print(_("please select fewer images (max. 15)")) - elseif use_links then - set_links(images) - else - if act_os == "linux" then - call_list_of_files(images) - else - call_file_by_file(images) - end - end - end -end - -local function destroy() - dt.gui.libs.image.destroy_action("OpenInExplorer") - dt.destroy_event("OpenInExplorer", "shortcut") - if act_os ~= "windows" then - dt.preferences.destroy("OpenInExplorer", "linked_image_files_dir") - end - dt.preferences.destroy("OpenInExplorer", "use_links") -end - - --- GUI -- -dt.gui.libs.image.register_action( - "OpenInExplorer", _("show in file explorer"), - function() open_in_fmanager() end, - _("open the file manager at the selected image's location") -) - - -if act_os ~= "windows" then - dt.preferences.register("OpenInExplorer", "linked_image_files_dir", -- name - "directory", -- type - _("OpenInExplorer: linked files directory"), -- label - _("directory to store the links to the file names, requires restart to take effect"), -- tooltip - "Links to image files", -- default - dt.new_widget("file_chooser_button"){ - title = _("select directory"), - is_directory = true, - } - ) - dt.preferences.register("OpenInExplorer", "use_links", -- name - "bool", -- type - _("OpenInExplorer: use links"), -- label - _("use links instead of multiple windows, requires restart to take effect"), -- tooltip - false, -- default - "" - ) -end - -dt.register_event( - "OpenInExplorer", "shortcut", - function(event, shortcut) open_in_fmanager() end, - "OpenInExplorer" -) - -script_data.destroy = destroy - -return script_data +--[[ +OpenInExplorer plugin for darktable + + copyright (c) 2018 Kevin Ertel + Update 2020 and macOS support by Volker Lenhardt + Linux support 2020 by Bill Ferguson + + darktable is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + darktable is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with darktable. If not, see . +]] + +--[[About this plugin +This plugin adds the module "OpenInExplorer" to darktable's lighttable view. + +----REQUIRED SOFTWARE---- +Apple macOS, Microsoft Windows or Linux + +----USAGE---- +Install: (see here for more detail: https://github.com/darktable-org/lua-scripts ) + 1) Copy this file into your "lua/contrib" folder where all other scripts reside. + 2) Require this file in your luarc file, as with any other dt plug-in + +Select the photo(s) you wish to find in your operating system's file manager and press "show in file explorer" in the "selected images" section. + +- Nautilus (Linux), Explorer (Windows), and Finder (macOS prior to Mojave) will open one window for each selected image at the file's location. The file name will be highlighted. + +- On macOS Mojave and Catalina the Finder will open one window for each different directory. In these windows only the last one of the corresponding files will be highlighted (bug or feature?). + +- Dolphin (Linux) will open one window with tabs for the different directories. All the selected images' file names are highlighted in their respective directories. + +As an alternative option you can choose to show the image file names as symbolic links in an arbitrary directory. Go to preferences|Lua options. This option is not available for Windows users as on Windows solely admins are allowed to create links. + +- Pros: You do not clutter up your display with multiple windows. So there is no need to limit the number of selections. + +- Cons: If you want to work with the files you are one step behind the original data. + +----KNOWN ISSUES---- +]] + +local dt = require "darktable" +local du = require "lib/dtutils" +local df = require "lib/dtutils.file" +local dsys = require "lib/dtutils.system" +local gettext = dt.gettext.gettext + +--Check API version +du.check_min_api_version("7.0.0", "OpenInExplorer") + +dt.gettext.bindtextdomain("OpenInExplorer", dt.configuration.config_dir .."/lua/locale/") + +local function _(msgid) + return gettext(msgid) +end + +-- return data structure for script_manager + +local script_data = {} + +script_data.metadata = { + name = "OpenInExplorer", + purpose = _("open a selected file in the system file manager"), + author = "Kevin Ertel", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/OpenInExplorer" +} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them + +local act_os = dt.configuration.running_os +local PS = act_os == "windows" and "\\" or "/" + +--Detect OS and quit if it is not supported. +if act_os ~= "macos" and act_os ~= "windows" and act_os ~= "linux" then + dt.print(_("OpenInExplorer plug-in only supports linux, macos, and windows at this time")) + dt.print_error("OpenInExplorer plug-in only supports Linux, macOS, and Windows at this time") + return +end + +local use_links, links_dir = false, "" +if act_os ~= "windows" then + use_links = dt.preferences.read("OpenInExplorer", "use_links", "bool") + links_dir = dt.preferences.read("OpenInExplorer", "linked_image_files_dir", "string") +end + +--Check if the directory exists that was chosen for the file links. Return boolean. +local function check_if_links_dir_exists() + local dir_exists = true + if not links_dir then + --Just for paranoic reasons. I tried, but I couldn't devise a setting for a nil value. + dt.print(_("no links directory selected\nplease check the dt preferences (lua options)")) + dt.print_error("OpenInExplorer: No links directory selected") + dir_exists = false + elseif not df.check_if_file_exists(links_dir) then + dt.print(string.format(_("links directory '%s' not found\nplease check the dt preferences (lua options)"), links_dir)) + dt.print_error(string.format("OpenInExplorer: Links directory '%s' not found", links_dir)) + dir_exists = false + end + return dir_exists +end + +--Format strings for the commands to open the corresponding OS's file manager. +local open_dir = {} +open_dir.windows = "explorer.exe /n, %s" +open_dir.macos = "open %s" +open_dir.linux = [[busctl --user call org.freedesktop.FileManager1 /org/freedesktop/FileManager1 org.freedesktop.FileManager1 ShowFolders ass 1 %s ""]] + +local open_files = {} +open_files.windows = "explorer.exe /select, %s" +open_files.macos = "open -Rn %s" +open_files.linux = [[busctl --user call org.freedesktop.FileManager1 /org/freedesktop/FileManager1 org.freedesktop.FileManager1 ShowItems ass %d %s ""]] + +--Call the file mangager for each selected image on Linux. +--There is one call to busctl containing a list of all the image file names. +local function call_list_of_files(selected_images) + local current_image, file_uris, run_cmd = "", "", "" + for _, image in pairs(selected_images) do + current_image = image.path..PS..image.filename + file_uris = file_uris .. df.sanitize_filename("file://" .. current_image) .. " " + dt.print_log("file_uris is " .. file_uris) + end + run_cmd = string.format(open_files.linux, #selected_images, file_uris) + dt.print_log("OpenInExplorer run_cmd = "..run_cmd) + dsys.external_command(run_cmd) +end + +--Call the file manager for each selected image on Windows and macOS. +local function call_file_by_file(selected_images) + local current_image, run_cmd = "", "" + for _, image in pairs(selected_images) do + current_image = image.path..PS..image.filename + run_cmd = string.format(open_files[act_os], df.sanitize_filename(current_image)) + dt.print_log("OpenInExplorer run_cmd = "..run_cmd) + dsys.external_command(run_cmd) + end +end + +--Create a link for each selected image, and finally call the file manager. +local function set_links(selected_images) + local current_image, link_target, run_cmd, k = "", "", "", nil + for k, image in pairs(selected_images) do + current_image = image.path..PS..image.filename + link_target = df.create_unique_filename(links_dir .. PS .. image.filename) + run_cmd = string.format("ln -s %s %s", df.sanitize_filename(current_image), df.sanitize_filename(link_target)) + --[[ + In case Windows will allow normal users to create soft links: + if act_os == "windows" then + run_cmd = string.format("mklink %s %s", df.sanitize_filename(link_target), df.sanitize_filename(current_image)) + end + ]] + if dsys.external_command(run_cmd) ~= 0 then + dt.print(_("failed to create links, missing rights?")) + dt.print_error("OpenInExplorer: Failed to create links") + return + end + end + --The URI format is necessary only for the Linux busctl command. + --But it is accepted by the Windows Explorer and macOS's Finder all the same. + run_cmd = string.format(open_dir[act_os], df.sanitize_filename("file://"..links_dir)) + dt.print_log("OpenInExplorer run_cmd = "..run_cmd) + dsys.external_command(run_cmd) +end + +--The working function that starts the particular task. +local function open_in_fmanager() + local images = dt.gui.selection() + if #images == 0 then + dt.print(_("please select an image")) + else + if use_links and not check_if_links_dir_exists() then + return + end + if #images > 15 and not use_links then + dt.print(_("please select fewer images (max. 15)")) + elseif use_links then + set_links(images) + else + if act_os == "linux" then + call_list_of_files(images) + else + call_file_by_file(images) + end + end + end +end + +local function destroy() + dt.gui.libs.image.destroy_action("OpenInExplorer") + dt.destroy_event("OpenInExplorer", "shortcut") + if act_os ~= "windows" then + dt.preferences.destroy("OpenInExplorer", "linked_image_files_dir") + end + dt.preferences.destroy("OpenInExplorer", "use_links") +end + + +-- GUI -- +dt.gui.libs.image.register_action( + "OpenInExplorer", _("show in file explorer"), + function() open_in_fmanager() end, + _("open the file manager at the selected image's location") +) + + +if act_os ~= "windows" then + dt.preferences.register("OpenInExplorer", "linked_image_files_dir", -- name + "directory", -- type + _("OpenInExplorer: linked files directory"), -- label + _("directory to store the links to the file names, requires restart to take effect"), -- tooltip + "Links to image files", -- default + dt.new_widget("file_chooser_button"){ + title = _("select directory"), + is_directory = true, + } + ) + dt.preferences.register("OpenInExplorer", "use_links", -- name + "bool", -- type + _("OpenInExplorer: use links"), -- label + _("use links instead of multiple windows, requires restart to take effect"), -- tooltip + false, -- default + "" + ) +end + +dt.register_event( + "OpenInExplorer", "shortcut", + function(event, shortcut) open_in_fmanager() end, + "OpenInExplorer" +) + +script_data.destroy = destroy + +return script_data diff --git a/contrib/RL_out_sharp.lua b/contrib/RL_out_sharp.lua index fcbfb5c0..aa64b3f8 100644 --- a/contrib/RL_out_sharp.lua +++ b/contrib/RL_out_sharp.lua @@ -65,10 +65,26 @@ local MODULE_NAME = "RL_out_sharp" -- check API version du.check_min_api_version("7.0.0", MODULE_NAME) +-- translation +local gettext = dt.gettext.gettext + +dt.gettext.bindtextdomain("RL_out_sharp", dt.configuration.config_dir .."/lua/locale/") + +local function _(msgid) + return gettext(msgid) + end + -- return data structure for script_manager local script_data = {} +script_data.metadata = { + name = "RL_out_sharp", + purpose = _("Richardson-Lucy output sharpening using GMic"), + author = "Marco Carrarini ", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/RL_out_sharp" +} + script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again @@ -77,15 +93,6 @@ script_data.show = nil -- only required for libs since the destroy_method only h -- OS compatibility local PS = dt.configuration.running_os == "windows" and "\\" or "/" --- translation -local gettext = dt.gettext.gettext - -gettext.bindtextdomain("RL_out_sharp", dt.configuration.config_dir .."/lua/locale/") - -local function _(msgid) - return gettext(msgid) - end - -- initialize module preferences if not dt.preferences.read(MODULE_NAME, "initialized", "bool") then dt.preferences.write(MODULE_NAME, "sigma", "string", "0.7") diff --git a/contrib/autostyle.lua b/contrib/autostyle.lua index 426b76fd..a12cd0ac 100644 --- a/contrib/autostyle.lua +++ b/contrib/autostyle.lua @@ -43,7 +43,7 @@ local filelib = require "lib/dtutils.file" du.check_min_api_version("7.0.0", "autostyle") local gettext = darktable.gettext.gettext -gettext.bindtextdomain("autostyle", dt.configuration.config_dir .."/lua/locale/") +darktable.gettext.bindtextdomain("autostyle", darktable.configuration.config_dir .."/lua/locale/") local function _(msgid) return gettext(msgid) @@ -53,6 +53,13 @@ end local script_data = {} +script_data.metadata = { + name = "autostyle", + purpose = _("automatically apply a style based on image EXIF tag"), + author = "Marc Cousin ", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/autostyle/" +} + script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again diff --git a/contrib/change_group_leader.lua b/contrib/change_group_leader.lua index b70310df..202f3f6e 100644 --- a/contrib/change_group_leader.lua +++ b/contrib/change_group_leader.lua @@ -40,23 +40,30 @@ local gettext = dt.gettext.gettext local MODULE = "change_group_leader" -gettext.bindtextdomain(MODULE, dt.configuration.config_dir .."/lua/locale/") +dt.gettext.bindtextdomain(MODULE, dt.configuration.config_dir .."/lua/locale/") du.check_min_api_version("3.0.0", MODULE) +local function _(msgid) + return gettext(msgid) +end + -- return data structure for script_manager local script_data = {} +script_data.metadata = { + name = "change_group_leader", + purpose = _("automatically change the leader of raw+jpg paired image groups"), + author = "Bill Ferguson ", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/change_group_leader" +} + script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again script_data.show = nil -- only required for libs since the destroy_method only hides them -local function _(msgid) - return gettext(msgid) -end - -- create a namespace to contain persistent data and widgets chg_grp_ldr = {} diff --git a/contrib/clear_GPS.lua b/contrib/clear_GPS.lua index da915027..f90d8b8f 100644 --- a/contrib/clear_GPS.lua +++ b/contrib/clear_GPS.lua @@ -39,28 +39,34 @@ local dt = require "darktable" local du = require "lib/dtutils" +local gettext = dt.gettext.gettext +dt.gettext.bindtextdomain("clear_GPS", dt.configuration.config_dir .."/lua/locale/") + +local function _(msgid) + return gettext(msgid) +end + -- return data structure for script_manager local script_data = {} +script_data.metadata = { + name = "clear_GPS", + purpose = _("remove GPS data from selected image(s)"), + author = "Bill Ferguson ", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/clear_gps/" +} + script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again script_data.show = nil -- only required for libs since the destroy_method only hides them -local gettext = dt.gettext.gettext -gettext.bindtextdomain("clear_GPS", dt.configuration.config_dir .."/lua/locale/") - -- not a number local NaN = 0/0 du.check_min_api_version("7.0.0", "clear_GPS") - -local function _(msgid) - return gettext(msgid) -end - local function clear_GPS(images) for _, image in ipairs(images) do -- set the location information to Not a Number (NaN) so it displays correctly diff --git a/contrib/color_profile_manager.lua b/contrib/color_profile_manager.lua index 61b40284..ed083178 100644 --- a/contrib/color_profile_manager.lua +++ b/contrib/color_profile_manager.lua @@ -54,7 +54,7 @@ du.check_min_api_version("7.0.0", "color_profile_manager") local gettext = dt.gettext.gettext -gettext.bindtextdomain("color_profile_manager", dt.configuration.config_dir .."/lua/locale/") +dt.gettext.bindtextdomain("color_profile_manager", dt.configuration.config_dir .."/lua/locale/") local function _(msgid) return gettext(msgid) @@ -363,6 +363,13 @@ end local script_data = {} +script_data.metadata = { + name = "color_profile_manager", + purpose = _("manage external darktable color profiles"), + author = "Bill Ferguson ", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/color_profile_manager" +} + script_data.destroy = destroy script_data.restart = restart script_data.destroy_method = "hide" diff --git a/contrib/copy_attach_detach_tags.lua b/contrib/copy_attach_detach_tags.lua index fb9f4870..6d6c470c 100644 --- a/contrib/copy_attach_detach_tags.lua +++ b/contrib/copy_attach_detach_tags.lua @@ -44,21 +44,28 @@ local gettext = dt.gettext.gettext du.check_min_api_version("7.0.0", "copy_attach_detach_tags") +dt.gettext.bindtextdomain("copy_attach_detach_tags", dt.configuration.config_dir .."/lua/locale/") + +local function _(msgid) + return gettext(msgid) +end + -- return data structure for script_manager local script_data = {} +script_data.metadata = { + name = "copy_attach_detach_tags", + purpose = _("shortcuts to copy, paste, replace, or remove tags from images"), + author = "Christian Kanzian", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/copy_attach_detach_tags" +} + script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again script_data.show = nil -- only required for libs since the destroy_method only hides them -gettext.bindtextdomain("copy_attach_detach_tags", dt.configuration.config_dir .."/lua/locale/") - -local function _(msgid) - return gettext(msgid) -end - local cadt = {} cadt.module_installed = false cadt.event_registered = false diff --git a/contrib/cr2hdr.lua b/contrib/cr2hdr.lua index 04232c27..a091a8f1 100644 --- a/contrib/cr2hdr.lua +++ b/contrib/cr2hdr.lua @@ -37,9 +37,9 @@ local du = require "lib/dtutils" du.check_min_api_version("7.0.0", "cr2hdr") -local gettext = dt.gettext.gettext +local gettext = darktable.gettext.gettext -gettext.bindtextdomain("cr2hdr", dt.configuration.config_dir .."/lua/locale/") +darktable.gettext.bindtextdomain("cr2hdr", darktable.configuration.config_dir .."/lua/locale/") local function _(msgid) return gettext(msgid) @@ -49,6 +49,13 @@ end local script_data = {} +script_data.metadata = { + name = "cr2hdr", + purpose = _("process Magic Lantern dual ISO images"), + author = "Till Theato ", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/cr2hdr" +} + script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again diff --git a/contrib/cycle_group_leader.lua b/contrib/cycle_group_leader.lua index 1b8d6841..30ed0b8e 100644 --- a/contrib/cycle_group_leader.lua +++ b/contrib/cycle_group_leader.lua @@ -1,6 +1,6 @@ --[[ - cycle_group_leader.lua - change image grouip leader + cycle_group_leader.lua - change image group leader Copyright (C) 2024 Bill Ferguson @@ -54,29 +54,36 @@ local MODULE = "cycle_group_leader" du.check_min_api_version("7.0.0", MODULE) --- - - - - - - - - - - - - - - - - - - - - - - - - - --- S C R I P T M A N A G E R I N T E G R A T I O N --- - - - - - - - - - - - - - - - - - - - - - - - - - - -local script_data = {} - -script_data.destroy = nil -- function to destory the script -script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet -script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again -script_data.show = nil -- only required for libs since the destroy_method only hides them - -- - - - - - - - - - - - - - - - - - - - - - - - - - -- I 1 8 N -- - - - - - - - - - - - - - - - - - - - - - - - - - local gettext = dt.gettext.gettext -gettext.bindtextdomain("cycle_group_leader", dt.configuration.config_dir .."/lua/locale/") +dt.gettext.bindtextdomain("cycle_group_leader", dt.configuration.config_dir .."/lua/locale/") local function _(msgid) return gettext(msgid) end +-- - - - - - - - - - - - - - - - - - - - - - - - - - +-- S C R I P T M A N A G E R I N T E G R A T I O N +-- - - - - - - - - - - - - - - - - - - - - - - - - - + +local script_data = {} + +script_data.metadata = { + name = "cycle_group_leader", + purpose = _("change image group leader"), + author = "Bill Ferguson ", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/cycle_group_leader" +} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them + -- - - - - - - - - - - - - - - - - - - - - - - - -- F U N C T I O N S -- - - - - - - - - - - - - - - - - - - - - - - - diff --git a/contrib/enfuseAdvanced.lua b/contrib/enfuseAdvanced.lua index 42b62b15..b5ec586e 100644 --- a/contrib/enfuseAdvanced.lua +++ b/contrib/enfuseAdvanced.lua @@ -67,24 +67,31 @@ if dt.configuration.running_os == 'windows' then os_path_seperator = '\\' end du.check_min_api_version("7.0.0", "enfuseAdvanced") +-- Tell gettext where to find the .mo file translating messages for a particular domain +local gettext = dt.gettext.gettext + +dt.gettext.bindtextdomain("enfuseAdvanced", dt.configuration.config_dir .."/lua/locale/") + +local function _(msgid) + return gettext(msgid) +end + -- return data structure for script_manager local script_data = {} +script_data.metadata = { + name = "enfuseAdvanced", + purpose = _("focus stack or exposure blend images"), + author = "Kevin Ertel", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/enfuseAdvanced" +} + script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again script_data.show = nil -- only required for libs since the destroy_method only hides them --- Tell gettext where to find the .mo file translating messages for a particular domain -local gettext = dt.gettext.gettext - -gettext.bindtextdomain("enfuseAdvanced", dt.configuration.config_dir .."/lua/locale/") - -local function _(msgid) - return gettext(msgid) -end - -- INITS -- local AIS = { name = 'align_image_stack', diff --git a/contrib/exportLUT.lua b/contrib/exportLUT.lua index 4b044558..0a578a24 100644 --- a/contrib/exportLUT.lua +++ b/contrib/exportLUT.lua @@ -33,23 +33,30 @@ local ds = require("lib/dtutils.system") du.check_min_api_version("7.0.0", "exportLUT") +local gettext = dt.gettext.gettext + +dt.gettext.bindtextdomain("exportLUT", dt.configuration.config_dir .."/lua/locale/") + +local function _(msgid) + return gettext(msgid) +end + -- return data structure for script_manager local script_data = {} +script_data.metadata = { + name = "exportLUT", + purpose = _("export a style as a LUT"), + author = "Noah Clarke", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/exportLUT" +} + script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again script_data.show = nil -- only required for libs since the destroy_method only hides them -local gettext = dt.gettext.gettext - -gettext.bindtextdomain("exportLUT", dt.configuration.config_dir .."/lua/locale/") - -local function _(msgid) - return gettext(msgid) -end - du.check_min_api_version("5.0.0", "exportLUT") local eL = {} diff --git a/contrib/ext_editor.lua b/contrib/ext_editor.lua index 0650cd70..592550bc 100644 --- a/contrib/ext_editor.lua +++ b/contrib/ext_editor.lua @@ -75,10 +75,26 @@ local dtsys = require "lib/dtutils.system" local MODULE_NAME = "ext_editor" du.check_min_api_version("7.0.0", MODULE_NAME) +-- translation +local gettext = dt.gettext.gettext + +dt.gettext.bindtextdomain("ext_editor", dt.configuration.config_dir .."/lua/locale/") + +local function _(msgid) + return gettext(msgid) +end + -- return data structure for script_manager local script_data = {} +script_data.metadata = { + name = "ext_editor", + purpose = _("edit images with external editors"), + author = "Marco Carrarini, marco.carrarini@gmail.com", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/ext_editor" +} + script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again @@ -94,15 +110,6 @@ ee.event_registered = false ee.widgets = {} --- translation -local gettext = dt.gettext.gettext - -gettext.bindtextdomain("ext_editor", dt.configuration.config_dir .."/lua/locale/") - -local function _(msgid) - return gettext(msgid) -end - -- maximum number of external programs, can be increased to necessity local MAX_EDITORS = 9 diff --git a/contrib/face_recognition.lua b/contrib/face_recognition.lua index 233b4b7b..0f6183bd 100644 --- a/contrib/face_recognition.lua +++ b/contrib/face_recognition.lua @@ -54,10 +54,23 @@ local OUTPUT = dt.configuration.tmp_dir .. PS .. "facerecognition.txt" du.check_min_api_version("7.0.0", MODULE) +dt.gettext.bindtextdomain("face_recognition", dt.configuration.config_dir .."/lua/locale/") + +local function _(msgid) + return gettext(msgid) +end + -- return data structure for script_manager local script_data = {} +script_data.metadata = { + name = "face_recognition", + purpose = _("use facial recognition to tag images"), + author = "Sebastian Witt", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/face_recognition" +} + script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again @@ -69,12 +82,6 @@ local fc = {} fc.module_installed = false fc.event_registered = false -gettext.bindtextdomain("face_recognition", dt.configuration.config_dir .."/lua/locale/") - -local function _(msgid) - return gettext(msgid) -end - local function build_image_table(images) local image_table = {} local file_extension = "" diff --git a/contrib/fujifilm_dynamic_range.lua b/contrib/fujifilm_dynamic_range.lua index a6d80875..d373d130 100644 --- a/contrib/fujifilm_dynamic_range.lua +++ b/contrib/fujifilm_dynamic_range.lua @@ -60,13 +60,27 @@ cameras may behave in other ways. local dt = require "darktable" local du = require "lib/dtutils" local df = require "lib/dtutils.file" +local gettext = dt.gettext.gettext du.check_min_api_version("7.0.0", "fujifilm_dynamic_range") +dt.gettext.bindtextdomain("fujifilm_dynamic_range", dt.configuration.config_dir .."/lua/locale/") + +local function _(msgid) + return gettext(msgid) +end + -- return data structure for script_manager local script_data = {} +script_data.metadata = { + name = "fujifilm_dynamic_range", + purpose = _("compensate for Fujifilm raw files made using \"dynamic range\""), + author = "Dan Torop ", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/fujifilm_dynamic_range" +} + script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again diff --git a/contrib/fujifilm_ratings.lua b/contrib/fujifilm_ratings.lua index df73b464..f9bb1c86 100644 --- a/contrib/fujifilm_ratings.lua +++ b/contrib/fujifilm_ratings.lua @@ -30,21 +30,28 @@ local gettext = dt.gettext.gettext du.check_min_api_version("7.0.0", "fujifilm_ratings") +dt.gettext.bindtextdomain("fujifilm_ratings", dt.configuration.config_dir .."/lua/locale/") + +local function _(msgid) + return gettext(msgid) +end + -- return data structure for script_manager local script_data = {} +script_data.metadata = { + name = "fujifilm_ratings", + purpose = _("import Fujifilm in-camera ratings"), + author = "Ben Mendis ", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/fujifilm_ratings" +} + script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again script_data.show = nil -- only required for libs since the destroy_method only hides them -gettext.bindtextdomain("fujifilm_ratings", dt.configuration.config_dir .."/lua/locale/") - -local function _(msgid) - return gettext(msgid) -end - local function detect_rating(event, image) if not df.check_if_bin_exists("exiftool") then dt.print_error(_("exiftool not found")) diff --git a/contrib/geoJSON_export.lua b/contrib/geoJSON_export.lua index 18247ee5..695976a6 100644 --- a/contrib/geoJSON_export.lua +++ b/contrib/geoJSON_export.lua @@ -39,21 +39,28 @@ local gettext = dt.gettext.gettext du.check_min_api_version("7.0.0", "geoJSON_export") +dt.gettext.bindtextdomain("geoJSON_export", dt.configuration.config_dir .."/lua/locale/") + +local function _(msgid) + return gettext(msgid) +end + -- return data structure for script_manager local script_data = {} +script_data.metadata = { + name = "geoJSON_export", + purpose = _("export a geoJSON file from geo data"), + author = "Tobias Jakobs", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/geoJSON_export" +} + script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again script_data.show = nil -- only required for libs since the destroy_method only hides them -gettext.bindtextdomain("geoJSON_export", dt.configuration.config_dir .."/lua/locale/") - -local function _(msgid) - return gettext(msgid) -end - -- Sort a table local function spairs(_table, order) -- Code copied from http://stackoverflow.com/questions/15706270/sort-a-table-in-lua -- collect the keys diff --git a/contrib/geoToolbox.lua b/contrib/geoToolbox.lua index 33a67368..83caa130 100644 --- a/contrib/geoToolbox.lua +++ b/contrib/geoToolbox.lua @@ -32,21 +32,28 @@ local gettext = dt.gettext.gettext du.check_min_api_version("7.0.0", "geoToolbox") +dt.gettext.bindtextdomain("geoToolbox", dt.configuration.config_dir .."/lua/locale/") + +local function _(msgid) + return gettext(msgid) +end + -- return data structure for script_manager local script_data = {} +script_data.metadata = { + name = "geoToolbox", + purpose = _("geodata tools"), + author = "Tobias Jakobs", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/geoToolbox" +} + script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again script_data.show = nil -- only required for libs since the destroy_method only hides them -gettext.bindtextdomain("geoToolbox", dt.configuration.config_dir .."/lua/locale/") - -local function _(msgid) - return gettext(msgid) -end - local gT = {} gT.module_installed = false diff --git a/contrib/gimp.lua b/contrib/gimp.lua index e8d2a4e8..9a60cada 100644 --- a/contrib/gimp.lua +++ b/contrib/gimp.lua @@ -74,21 +74,28 @@ local gimp_widget = nil du.check_min_api_version("7.0.0", "gimp") +dt.gettext.bindtextdomain("gimp", dt.configuration.config_dir .."/lua/locale/") + +local function _(msgid) + return gettext(msgid) +end + -- return data structure for script_manager local script_data = {} +script_data.metadata = { + name = "gimp", + purpose = _("export and edit with GIMP"), + author = "Bill Ferguson ", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/gimp" +} + script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again script_data.show = nil -- only required for libs since the destroy_method only hides them -gettext.bindtextdomain("gimp", dt.configuration.config_dir .."/lua/locale/") - -local function _(msgid) - return gettext(msgid) -end - local function group_if_not_member(img, new_img) local image_table = img:get_group_members() local is_member = false diff --git a/contrib/gpx_export.lua b/contrib/gpx_export.lua index 39bb5193..b3d93015 100644 --- a/contrib/gpx_export.lua +++ b/contrib/gpx_export.lua @@ -25,25 +25,32 @@ For each source folder, a separate is generated in the gpx file. local dt = require "darktable" local df = require "lib/dtutils.file" local dl = require "lib/dtutils" -local gettext = dt.gettext.gettext +local gettext = dt.gettext dl.check_min_api_version("7.0.0", "gpx_export") +gettext.bindtextdomain("gpx_export", dt.configuration.config_dir .."/lua/locale/") + +local function _(msgid) + return gettext.dgettext("gpx_export", msgid) +end + -- return data structure for script_manager local script_data = {} +script_data.metadata = { + name = "gpx_export", + purpose = _("export gpx information to a file"), + author = "Jannis_V", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/gpx_export" +} + script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again script_data.show = nil -- only required for libs since the destroy_method only hides them -gettext.bindtextdomain("gpx_export", dt.configuration.config_dir .."/lua/locale/") - -local function _(msgid) - return gettext.dgettext("gpx_export", msgid) -end - local gpx = {} gpx.module_installed = false gpx.event_registered = false diff --git a/contrib/harmonic_armature_guide.lua b/contrib/harmonic_armature_guide.lua index 2e8afd8d..fd16f2b6 100644 --- a/contrib/harmonic_armature_guide.lua +++ b/contrib/harmonic_armature_guide.lua @@ -36,12 +36,26 @@ local gettext = dt.gettext.gettext du.check_min_api_version("2.0.0", "harmonic_armature_guide") -gettext.bindtextdomain("harmonic_armature_guide", dt.configuration.config_dir .."/lua/locale/") +dt.gettext.bindtextdomain("harmonic_armature_guide", dt.configuration.config_dir .."/lua/locale/") local function _(msgid) return gettext(msgid) end +local script_data = {} + +script_data.metadata = { + name = "harmonic_armature_guide", + purpose = _("harmonic artmature guide"), + author = "Hubert Kowalski", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/harmonic_armature_guide" +} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them + dt.guides.register_guide("harmonic armature", -- draw function(cairo, x, y, width, height, zoom_scale) @@ -74,4 +88,12 @@ end, function() return dt.new_widget("label"){label = _("harmonic armature"), halign = "start"} end -) \ No newline at end of file +) + +local function destroy() + -- nothing to destroy +end + +script_data.destroy = destroy + +return script_data diff --git a/contrib/hif_group_leader.lua b/contrib/hif_group_leader.lua index 4c7fb61e..26eaf48d 100644 --- a/contrib/hif_group_leader.lua +++ b/contrib/hif_group_leader.lua @@ -58,29 +58,36 @@ local MODULE = "hif_group_leader" du.check_min_api_version("7.0.0", MODULE) --- - - - - - - - - - - - - - - - - - - - - - - - - - --- S C R I P T M A N A G E R I N T E G R A T I O N --- - - - - - - - - - - - - - - - - - - - - - - - - - - -local script_data = {} - -script_data.destroy = nil -- function to destory the script -script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet -script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again -script_data.show = nil -- only required for libs since the destroy_method only hides them - -- - - - - - - - - - - - - - - - - - - - - - - - - - -- I 1 8 N -- - - - - - - - - - - - - - - - - - - - - - - - - - local gettext = dt.gettext.gettext -gettext.bindtextdomain("hif_group_leader", dt.configuration.config_dir .."/lua/locale/") +dt.gettext.bindtextdomain("hif_group_leader", dt.configuration.config_dir .."/lua/locale/") local function _(msgid) return gettext(msgid) end +-- - - - - - - - - - - - - - - - - - - - - - - - - - +-- S C R I P T M A N A G E R I N T E G R A T I O N +-- - - - - - - - - - - - - - - - - - - - - - - - - - + +local script_data = {} + +script_data.metadata = { + name = "hif_group_leader", + purpose = _("make hif image group leader"), + author = "Bill Ferguson ", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/hif_group_leader" +} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them + -- - - - - - - - - - - - - - - - - - - - - - - - -- P R E F E R E N C E S diff --git a/contrib/hugin.lua b/contrib/hugin.lua index 451eb956..f209c0c5 100644 --- a/contrib/hugin.lua +++ b/contrib/hugin.lua @@ -56,21 +56,28 @@ local PQ = dt.configuration.running_os == "windows" and '"' or "'" -- works with darktable API version from 5.0.0 on du.check_min_api_version("7.0.0", "hugin") +dt.gettext.bindtextdomain("hugin", dt.configuration.config_dir .."/lua/locale/") + +local function _(msgid) + return gettext(msgid) +end + -- return data structure for script_manager local script_data = {} +script_data.metadata = { + name = "hugin", + purpose = _("stitch images into a panorama"), + author = "Wolfgang Goetz", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/hugin" +} + script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again script_data.show = nil -- only required for libs since the destroy_method only hides them -gettext.bindtextdomain("hugin", dt.configuration.config_dir .."/lua/locale/") - -local function _(msgid) - return gettext(msgid) -end - local function user_preference_changed(widget) user_prefer_gui = widget.value dt.preferences.write(namespace, user_pref_str, "bool", user_prefer_gui) diff --git a/contrib/image_stack.lua b/contrib/image_stack.lua index 424b2fc4..c63ff166 100644 --- a/contrib/image_stack.lua +++ b/contrib/image_stack.lua @@ -73,21 +73,28 @@ local PS = dt.configuration.running_os == "windows" and "\\" or "/" -- works with LUA API version 5.0.0 du.check_min_api_version("7.0.0", "image_stack") +dt.gettext.bindtextdomain("image_stack", dt.configuration.config_dir .."/lua/locale/") + +local function _(msgid) + return gettext(msgid) +end + -- return data structure for script_manager local script_data = {} +script_data.metadata = { + name = "image_stack", + purpose = _("process a stack of images"), + author = "Bill Ferguson ", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/image_stack" +} + script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again script_data.show = nil -- only required for libs since the destroy_method only hides them -gettext.bindtextdomain("image_stack", dt.configuration.config_dir .."/lua/locale/") - -local function _(msgid) - return gettext(msgid) -end - -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -- GUI definitions -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/contrib/image_time.lua b/contrib/image_time.lua index 81bce253..f20e5000 100644 --- a/contrib/image_time.lua +++ b/contrib/image_time.lua @@ -115,10 +115,23 @@ img_time.event_registered = false du.check_min_api_version("7.0.0", "image_time") +dt.gettext.bindtextdomain("image_time", dt.configuration.config_dir .."/lua/locale/") + +local function _(msgid) + return gettext(msgid) +end + -- return data structure for script_manager local script_data = {} +script_data.metadata = { + name = "image_time", + purpose = _("synchronize image time for images shot with different cameras or adjust or set image time"), + author = "Bill Ferguson ", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/image_time" +} + script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again @@ -126,12 +139,6 @@ script_data.show = nil -- only required for libs since the destroy_method only h -gettext.bindtextdomain("image_time", dt.configuration.config_dir .."/lua/locale/") - -local function _(msgid) - return gettext(msgid) -end - local PS = dt.configuration.runnin_os == "windows" and "\\" or "/" local ERROR = -1 diff --git a/contrib/jpg_group_leader.lua b/contrib/jpg_group_leader.lua index d8fd7283..6201b398 100644 --- a/contrib/jpg_group_leader.lua +++ b/contrib/jpg_group_leader.lua @@ -58,29 +58,36 @@ local MODULE = "jpg_group_leader" du.check_min_api_version("7.0.0", MODULE) --- - - - - - - - - - - - - - - - - - - - - - - - - - --- S C R I P T M A N A G E R I N T E G R A T I O N --- - - - - - - - - - - - - - - - - - - - - - - - - - - -local script_data = {} - -script_data.destroy = nil -- function to destory the script -script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet -script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again -script_data.show = nil -- only required for libs since the destroy_method only hides them - -- - - - - - - - - - - - - - - - - - - - - - - - - - -- I 1 8 N -- - - - - - - - - - - - - - - - - - - - - - - - - - local gettext = dt.gettext.gettext -gettext.bindtextdomain("jpg_group_leader", dt.configuration.config_dir .."/lua/locale/") +dt.gettext.bindtextdomain("jpg_group_leader", dt.configuration.config_dir .."/lua/locale/") local function _(msgid) return gettext(msgid) end +-- - - - - - - - - - - - - - - - - - - - - - - - - - +-- S C R I P T M A N A G E R I N T E G R A T I O N +-- - - - - - - - - - - - - - - - - - - - - - - - - - + +local script_data = {} + +script_data.metadata = { + name = "jpg_group_leader", + purpose = _("make jpg image group leader"), + author = "Bill Ferguson ", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/jpg_group_leader" +} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them + -- - - - - - - - - - - - - - - - - - - - - - - - -- P R E F E R E N C E S diff --git a/contrib/kml_export.lua b/contrib/kml_export.lua index 25eb5d2e..ec1aa04a 100644 --- a/contrib/kml_export.lua +++ b/contrib/kml_export.lua @@ -45,21 +45,28 @@ local PS = dt.configuration.running_os == "windows" and "\\" or "/" du.check_min_api_version("7.0.0", "kml_export") +dt.gettext.bindtextdomain("kml_export", dt.configuration.config_dir .."/lua/locale/") + +local function _(msgid) + return gettext(msgid) +end + -- return data structure for script_manager local script_data = {} +script_data.metadata = { + name = "kml_export", + purpose = _("export KML/KMZ data to a file"), + author = "Tobias Jakobs", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/kml_export" +} + script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again script_data.show = nil -- only required for libs since the destroy_method only hides them -gettext.bindtextdomain("kml_export", dt.configuration.config_dir .."/lua/locale/") - -local function _(msgid) - return gettext(msgid) -end - local function show_status(storage, image, format, filename, number, total, high_quality, extra_data) dt.print(string.format(_("export image %i/%i"), number, total)) end diff --git a/contrib/passport_guide.lua b/contrib/passport_guide.lua index 0b233c64..246e7378 100644 --- a/contrib/passport_guide.lua +++ b/contrib/passport_guide.lua @@ -41,12 +41,26 @@ local gettext = dt.gettext.gettext du.check_min_api_version("2.0.0", "passport_guide") -gettext.bindtextdomain("passport_guide", dt.configuration.config_dir .."/lua/locale/") +dt.gettext.bindtextdomain("passport_guide", dt.configuration.config_dir .."/lua/locale/") local function _(msgid) return gettext(msgid) end +local script_data = {} + +script_data.metadata = { + name = "passport_guide", + purpose = _("guides for cropping passport photos"), + author = "Kåre Hampf", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/passport_guide" +} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them + dt.guides.register_guide("passport", -- draw function(cairo, x, y, width, height, zoom_scale) @@ -90,5 +104,13 @@ function() end ) +local function destroy() + -- nothing to destroy +end + +script_data.destroy = destroy + +return script_data + -- kate: tab-indents: off; indent-width 2; replace-tabs on; remove-trailing-space on; hl Lua; -- vim: shiftwidth=2 expandtab tabstop=2 cindent syntax=lua diff --git a/contrib/passport_guide_germany.lua b/contrib/passport_guide_germany.lua index f020ae7d..735c092a 100644 --- a/contrib/passport_guide_germany.lua +++ b/contrib/passport_guide_germany.lua @@ -45,12 +45,26 @@ local gettext = dt.gettext du.check_min_api_version("2.0.0", "passport_guide_germany") -- Tell gettext where to find the .mo file translating messages for a particular domain -gettext.bindtextdomain("passport_guide_germany",dt.configuration.config_dir.."/lua/locale/") +dt.gettext.bindtextdomain("passport_guide_germany",dt.configuration.config_dir.."/lua/locale/") local function _(msgid) return gettext.dgettext("passport_guide_germany", msgid) end +local script_data = {} + +script_data.metadata = { + name = "passport_guide_germany", + purpose = _("guides for cropping passport and ID card (\"Personalausweis\") photos based on the \"Passbild-Schablone\" from the German Federal Ministry of the Interior and Community"), + author = "menschmachine", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/passport_guide_germany" +} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them + dt.guides.register_guide("Passport Photo Germany", -- draw function(cairo, x, y, width, height, zoom_scale) @@ -101,5 +115,13 @@ function() end ) +local function destroy() + -- noting to destroy +end + +script_data.destroy = destroy + +return script_data + -- kate: tab-indents: off; indent-width 2; replace-tabs on; remove-trailing-space on; hl Lua; -- vim: shiftwidth=2 expandtab tabstop=2 cindent syntax=lua diff --git a/contrib/pdf_slideshow.lua b/contrib/pdf_slideshow.lua index b6fb1803..911493f8 100644 --- a/contrib/pdf_slideshow.lua +++ b/contrib/pdf_slideshow.lua @@ -44,7 +44,7 @@ local df = require "lib/dtutils.file" local gettext = dt.gettext.gettext -gettext.bindtextdomain("pdf_slideshow", dt.configuration.config_dir .."/lua/locale/") +dt.gettext.bindtextdomain("pdf_slideshow", dt.configuration.config_dir .."/lua/locale/") local function _(msgid) return gettext(msgid) @@ -61,6 +61,13 @@ du.check_min_api_version("7.0.0", "pdf_slideshow") local script_data = {} +script_data.metadata = { + name = "pdf_slideshow", + purpose = _("generates a PDF slideshow (via Latex) containing all selected images one per slide"), + author = "Pascal Obry", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/pdf_slideshow" +} + script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again @@ -230,7 +237,7 @@ dt.register_storage("pdf_slideshow",_("pdf slideshow"), local result = dt.control.execute(command) if result ~= 0 then dt.print(_("problem running pdflatex")) -- this one is probably usefull to the user - error("problem running ")..command) + error("problem running "..command) end -- open the PDF diff --git a/contrib/photils.lua b/contrib/photils.lua index 250915ef..b06dc6ef 100644 --- a/contrib/photils.lua +++ b/contrib/photils.lua @@ -44,10 +44,24 @@ local dtsys = require "lib/dtutils.system" local MODULE_NAME = "photils" du.check_min_api_version("7.0.0", MODULE_NAME) +local gettext = dt.gettext.gettext +dt.gettext.bindtextdomain("photils", dt.configuration.config_dir .."/lua/locale/") + +local function _(msgid) + return gettext(msgid) +end + -- return data structure for script_manager local script_data = {} +script_data.metadata = { + name = "photils", + purpose = _("suggest tags based on image classification"), + author = "Tobias Scheck", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/photils" +} + script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again @@ -55,7 +69,6 @@ script_data.show = nil -- only required for libs since the destroy_method only h local PS = dt.configuration.running_os == "windows" and "\\" or "/" -local gettext = dt.gettext.gettext local exporter = dt.new_format("jpeg") exporter.quality = 80 @@ -64,12 +77,6 @@ exporter.max_width = 224 -- helper functions -gettext.bindtextdomain("photils", dt.configuration.config_dir .."/lua/locale/") - -local function _(msgid) - return gettext(msgid) -end - local function num_keys(tbl) local num = 0 for _ in pairs(tbl) do num = num + 1 end diff --git a/contrib/quicktag.lua b/contrib/quicktag.lua index 1ab5f3f0..7a17fa1b 100644 --- a/contrib/quicktag.lua +++ b/contrib/quicktag.lua @@ -49,10 +49,25 @@ local debug = require "darktable.debug" du.check_min_api_version("7.0.0", "quicktag") +local gettext = dt.gettext.gettext + +dt.gettext.bindtextdomain("quicktag", dt.configuration.config_dir .."/lua/locale/") + +local function _(msgid) + return gettext(msgid) +end + -- return data structure for script_manager local script_data = {} +script_data.metadata = { + name = "quicktag", + purpose = _("use buttons to quickly apply tags assigned to them"), + author = "Christian Kanzian", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/quicktag" +} + script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again @@ -62,14 +77,6 @@ qt.module_installed = false qt.event_registered = false qt.widget_table = {} -local gettext = dt.gettext.gettext - -gettext.bindtextdomain("quicktag", dt.configuration.config_dir .."/lua/locale/") - -local function _(msgid) - return gettext(msgid) -end - -- maximum length of button labels dt.preferences.register("quickTag", "labellength", diff --git a/contrib/rate_group.lua b/contrib/rate_group.lua index d8e7130b..6455f6d3 100644 --- a/contrib/rate_group.lua +++ b/contrib/rate_group.lua @@ -46,7 +46,7 @@ du.check_min_api_version("7.0.0", "rate_group") local gettext = dt.gettext.gettext -gettext.bindtextdomain("rate_group", dt.configuration.config_dir .."/lua/locale/") +dt.gettext.bindtextdomain("rate_group", dt.configuration.config_dir .."/lua/locale/") local function _(msgid) return gettext(msgid) @@ -56,6 +56,13 @@ end local script_data = {} +script_data.metadata = { + name = "rate_group", + purpose = _("rate all images in a group"), + author = "Dom H (dom@hxy.io)", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/rate_group" +} + script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again diff --git a/contrib/rename-tags.lua b/contrib/rename-tags.lua index 90597bb3..3b84eba6 100644 --- a/contrib/rename-tags.lua +++ b/contrib/rename-tags.lua @@ -36,9 +36,9 @@ local debug = require "darktable.debug" du.check_min_api_version("7.0.0", "rename-tags") du.deprecated("contrib/rename-tags.lua","darktable release 4.0") -local gettext = dt.gettext.gettext +local gettext = darktable.gettext.gettext -gettext.bindtextdomain("rename-tags", dt.configuration.config_dir .."/lua/locale/") +darktable.gettext.bindtextdomain("rename-tags", darktable.configuration.config_dir .."/lua/locale/") local function _(msgid) return gettext(msgid) @@ -48,6 +48,13 @@ end local script_data = {} +script_data.metadata = { + name = "rename-tags", + purpose = _("rename an existing tag"), + author = "Sebastian Witt (se.witt@gmx.net)", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/rename-tags" +} + script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again diff --git a/contrib/rename_images.lua b/contrib/rename_images.lua index e63a1ab1..d3ed9824 100644 --- a/contrib/rename_images.lua +++ b/contrib/rename_images.lua @@ -48,7 +48,7 @@ du.check_min_api_version("7.0.0", "rename_images") local gettext = dt.gettext.gettext -gettext.bindtextdomain("rename_images", dt.configuration.config_dir .."/lua/locale/") +dt.gettext.bindtextdomain("rename_images", dt.configuration.config_dir .."/lua/locale/") local function _(msgid) return gettext(msgid) @@ -71,6 +71,13 @@ rename.event_registered = false -- script_manager integration local script_data = {} +script_data.metadata = { + name = "rename_images", + purpose = _("rename an image file or files"), + author = "Bill Ferguson ", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/rename_images" +} + script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again diff --git a/contrib/select_non_existing.lua b/contrib/select_non_existing.lua index a8225b17..f691589a 100644 --- a/contrib/select_non_existing.lua +++ b/contrib/select_non_existing.lua @@ -31,7 +31,7 @@ local PS = dt.configuration.running_os == "windows" and "\\" or "/" local gettext = dt.gettext.gettext -gettext.bindtextdomain("select_non_existing", dt.configuration.config_dir .."/lua/locale/") +dt.gettext.bindtextdomain("select_non_existing", dt.configuration.config_dir .."/lua/locale/") local function _(msgid) return gettext(msgid) @@ -74,5 +74,13 @@ dt.gui.libs.select.register_selection( _("select all non-existing images in the current images")) local script_data = {} + +script_data.metadata = { + name = "select_non_existing", + purpose = _("enable selection of non-existing images"), + author = "Dirk Dittmar", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/select_non_existing" +} + script_data.destroy = destroy return script_data \ No newline at end of file diff --git a/contrib/select_untagged.lua b/contrib/select_untagged.lua index 97bf3382..2aef97e8 100644 --- a/contrib/select_untagged.lua +++ b/contrib/select_untagged.lua @@ -24,21 +24,28 @@ local gettext = dt.gettext.gettext du.check_min_api_version("7.0.0", "select_untagged") +dt.gettext.bindtextdomain("select_untagged", dt.configuration.config_dir .."/lua/locale/") + +local function _(msgid) + return gettext(msgid) +end + -- return data structure for script_manager local script_data = {} +script_data.metadata = { + name = "select_untagged", + purpose = _("enable selection of untagged images"), + author = "Jannis_V", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/select_untagged" +} + script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again script_data.show = nil -- only required for libs since the destroy_method only hides them -gettext.bindtextdomain("select_untagged", dt.configuration.config_dir .."/lua/locale/") - -local function _(msgid) - return gettext(msgid) -end - local function stop_job(job) job.valid = false end diff --git a/contrib/slideshowMusic.lua b/contrib/slideshowMusic.lua index 666402e3..c5b9d8ce 100644 --- a/contrib/slideshowMusic.lua +++ b/contrib/slideshowMusic.lua @@ -31,21 +31,28 @@ local gettext = dt.gettext.gettext du.check_min_api_version("7.0.0", "slideshowMusic") +dt.gettext.bindtextdomain("slideshowMusic", dt.configuration.config_dir .."/lua/locale/") + +local function _(msgid) + return gettext(msgid) +end + -- return data structure for script_manager local script_data = {} +script_data.metadata = { + name = "slideshowMusic", + purpose = _("play music during a slideshow"), + author = "Tobias Jakobs", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/slideshowMusic" +} + script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again script_data.show = nil -- only required for libs since the destroy_method only hides them -gettext.bindtextdomain("slideshowMusic", dt.configuration.config_dir .."/lua/locale/") - -local function _(msgid) - return gettext(msgid) -end - local function playSlideshowMusic(_, old_view, new_view) local filename, playMusic diff --git a/contrib/transfer_hierarchy.lua b/contrib/transfer_hierarchy.lua index 574ef4b9..96b18e44 100755 --- a/contrib/transfer_hierarchy.lua +++ b/contrib/transfer_hierarchy.lua @@ -80,10 +80,23 @@ local dtutils_system = require("lib/dtutils.system") local LIB_ID = "transfer_hierarchy" dtutils.check_min_api_version("7.0.0", LIB_ID) +darktable.gettext.bindtextdomain("transfer_hierarchy", darktable.configuration.config_dir .."/lua/locale/") + +local function _(msgid) + return darktable.gettext.gettext(msgid) +end + -- return data structure for script_manager local script_data = {} +script_data.metadata = { + name = "transfer_hierarchy", + purpose = _("allows the moving or copying of images from one directory tree to another, while preserving the existing hierarchy"), + author = "August Schwerdfeger (august@schwerdfeger.name)", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/transfer_hierarchy" +} + script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again @@ -96,12 +109,6 @@ local PATH_SEGMENT_REGEX = "(" .. PATH_SEPARATOR .. "?)([^" .. PATH_SEPARATOR .. unpack = unpack or table.unpack gmatch = string.gfind or string.gmatch -gettext.bindtextdomain("transfer_hierarchy", dt.configuration.config_dir .."/lua/locale/") - -local function _(msgid) - return darktable.gettext.gettext(msgid) -end - -- Header material: END diff --git a/contrib/video_ffmpeg.lua b/contrib/video_ffmpeg.lua index 5c4369c6..4203188e 100644 --- a/contrib/video_ffmpeg.lua +++ b/contrib/video_ffmpeg.lua @@ -41,10 +41,23 @@ local gettext = dt.gettext.gettext du.check_min_api_version("7.0.0", "video_ffmpeg") +dt.gettext.bindtextdomain("video_ffmpeg", dt.configuration.config_dir .."/lua/locale/") + +local function _(msgid) + return gettext(msgid) +end + -- return data structure for script_manager local script_data = {} +script_data.metadata = { + name = "video_ffmpeg", + purpose = _("timelapse video plugin based on ffmpeg"), + author = "Dominik Markiewicz", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contib/video_ffmpeg" +} + script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again @@ -54,13 +67,6 @@ local MODULE_NAME = "video_ffmpeg" local PS = dt.configuration.running_os == "windows" and "\\" or "/" -gettext.bindtextdomain("video_ffmpeg", dt.configuration.config_dir .."/lua/locale/") - -local function _(msgid) - return gettext(msgid) -end - - ---- DECLARATIONS local resolutions = { @@ -376,7 +382,7 @@ local module_widget = dt.new_widget("box") { ---- EXPORT & REGISTRATION local function show_status(enf_storage, image, format, filename, number, total, high_quality, extra_data) - dt.print(string.format(_("export %d / %d"), number), total)) + dt.print(string.format(_("export %d / %d", number), total)) end local function init_export(storage, img_format, images, high_quality, extra_data) diff --git a/examples/api_version.lua b/examples/api_version.lua index d89416cf..d54b7883 100644 --- a/examples/api_version.lua +++ b/examples/api_version.lua @@ -27,7 +27,7 @@ local dt = require "darktable" local gettext = dt.gettext.gettext -gettext.bindtextdomain("api_version", dt.configuration.config_dir .."/lua/locale/") +dt.gettext.bindtextdomain("api_version", dt.configuration.config_dir .."/lua/locale/") local function _(msg) return gettext(msg) @@ -47,6 +47,14 @@ dt.print(string.format(_("API version: %s"), result)) -- it's time to destroy the script and then return the data to -- script_manager local script_data = {} + +script_data.metadata = { + name = "api_version", + purpose = _("display api_version example"), + author = "Tobias Jakobs", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/examples/api_version" +} + script_data.destroy = destroy return script_data diff --git a/examples/darkroom_demo.lua b/examples/darkroom_demo.lua index 2a528883..802df749 100644 --- a/examples/darkroom_demo.lua +++ b/examples/darkroom_demo.lua @@ -60,7 +60,7 @@ local PS = dt.configuration.running_os == "windows" and "\\" or "/" -- - - - - - - - - - - - - - - - - - - - - - - - local gettext = dt.gettext.gettext -gettext.bindtextdomain("darkroom_demo", dt.configuration.config_dir .."/lua/locale/") +dt.gettext.bindtextdomain("darkroom_demo", dt.configuration.config_dir .."/lua/locale/") local function _(msgid) return gettext(msgid) @@ -117,6 +117,14 @@ dt.gui.current_view(current_view) -- it's time to destroy the script and then return the data to -- script_manager local script_data = {} + +script_data.metadata = { + name = "darkroom_demo", + purpose = _("example demonstrating how to control image display in darkroom mode"), + author = "Bill Ferguson ", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/examples/darkroom_demo" +} + script_data.destroy = destroy return script_data diff --git a/examples/gettextExample.lua b/examples/gettextExample.lua index 7c1e241f..20d5db43 100644 --- a/examples/gettextExample.lua +++ b/examples/gettextExample.lua @@ -69,7 +69,7 @@ dt.print_error("Hello World!") local gettext = dt.gettext.gettext -gettext.bindtextdomain("gettextExample", dt.configuration.config_dir .."/lua/locale/") +dt.gettext.bindtextdomain("gettextExample", dt.configuration.config_dir .."/lua/locale/") -- Translate a string using the darktable textdomain dt.print_error(gettext("image")) @@ -86,6 +86,14 @@ dt.print_error(_("hello world!")) -- it's time to destroy the script and then return the data to -- script_manager local script_data = {} + +script_data.metadata = { + name = "gettextExample", + purpose = _("example of how translations works"), + author = "Tobias Jakobs", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/examples/gettextExample" +} + script_data.destroy = destroy return script_data diff --git a/examples/gui_action.lua b/examples/gui_action.lua index 205366ee..3bff94b6 100644 --- a/examples/gui_action.lua +++ b/examples/gui_action.lua @@ -4,6 +4,29 @@ local NaN = 0/0 local wg = {} +local gettext = dt.gettext.gettext +dt.gettext.bindtextdomain("gui_action", dt.configuration.config_dir .."/lua/locale/") + +local function _(msgid) + return gettext(msgid) +end + +-- return data structure for script_manager + +local script_data = {} + +script_data.metadata = { + name = "gui_action", + purpose = _("example of how to use darktable.gui.action() calls"), + author = "Diederik ter Rahe", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/examples/gui_action" +} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them + wg.action = dt.new_widget("entry"){ text = "lib/filter/view", placeholder = "action path", @@ -103,3 +126,18 @@ dt.register_lib( }, } ) + +local function restart() + dt.gui.libs["execute_action"].visible = true +end + +local function destroy() + dt.gui.libs["execute_action"].visible = false +end + +script_data.destroy = destroy +script_data.destroy_method = "hide" +script_data.restart = restart +script_data.show = restart + +return script_data diff --git a/examples/hello_world.lua b/examples/hello_world.lua index 75e52ca8..e64c4f9a 100644 --- a/examples/hello_world.lua +++ b/examples/hello_world.lua @@ -35,7 +35,7 @@ du.check_min_api_version("2.0.0", "hello_world") local gettext = dt.gettext.gettext -gettext.bindtextdomain("hello_world", dt.configuration.config_dir .."/lua/locale/") +dt.gettext.bindtextdomain("hello_world", dt.configuration.config_dir .."/lua/locale/") local function _(msg) return gettext(msg) @@ -53,6 +53,14 @@ dt.print(_("hello, world")) -- it's time to destroy the script and then return the data to -- script_manager local script_data = {} + +script_data.metadata = { + name = "hello_world", + purpose = _("example of how to print a message to the screen"), + author = "Tobias Ellinghaus", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/examples/hello_world" +} + script_data.destroy = destroy return script_data diff --git a/examples/lighttable_demo.lua b/examples/lighttable_demo.lua index 6047e889..d897ff8a 100644 --- a/examples/lighttable_demo.lua +++ b/examples/lighttable_demo.lua @@ -61,7 +61,7 @@ end -- - - - - - - - - - - - - - - - - - - - - - - - local gettext = dt.gettext.gettext -gettext.bindtextdomain("lighttable_demo", dt.configuration.config_dir .."/lua/locale/") +dt.gettext.bindtextdomain("lighttable_demo", dt.configuration.config_dir .."/lua/locale/") local function _(msgid) return gettext(msgid) @@ -216,6 +216,14 @@ current_sort_order = dt.gui.libs.filter.sort_order(current_sort_order) -- it's time to destroy the script and then return the data to -- script_manager local script_data = {} + +script_data.metadata = { + name = "lighttable_demo", + purpose = _("example demonstrating how to control lighttable display modes"), + author = "Bill Ferguson ", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/examples/lighttable_demo" +} + script_data.destroy = destroy return script_data diff --git a/examples/moduleExample.lua b/examples/moduleExample.lua index 06ba003e..edf4815a 100644 --- a/examples/moduleExample.lua +++ b/examples/moduleExample.lua @@ -35,10 +35,26 @@ local du = require "lib/dtutils" du.check_min_api_version("7.0.0", "moduleExample") +-- https://www.darktable.org/lua-api/index.html#darktable_gettext +local gettext = dt.gettext.gettext + +dt.gettext.bindtextdomain("moduleExample", dt.configuration.config_dir .."/lua/locale/") + +local function _(msgid) + return gettext(msgid) +end + -- return data structure for script_manager local script_data = {} +script_data.metadata = { + name = "moduleExample", + purpose = _("example of how to create a lighttable module"), + author = "Tobias Jakobs", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/examples/moduleExample" +} + script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again @@ -46,15 +62,6 @@ script_data.show = nil -- only required for libs since the destroy_method only h -- translation --- https://www.darktable.org/lua-api/index.html#darktable_gettext -local gettext = dt.gettext.gettext - -gettext.bindtextdomain("moduleExample", dt.configuration.config_dir .."/lua/locale/") - -local function _(msgid) - return gettext(msgid) -end - -- declare a local namespace and a couple of variables we'll need to install the module local mE = {} mE.widgets = {} diff --git a/examples/multi_os.lua b/examples/multi_os.lua index 8d8758a8..f27cc9ea 100644 --- a/examples/multi_os.lua +++ b/examples/multi_os.lua @@ -72,7 +72,7 @@ local dtsys = require "lib/dtutils.system" -- system utilities local gettext = dt.gettext.gettext -gettext.bindtextdomain("multi_os", dt.configuration.config_dir .."/lua/locale/") +dt.gettext.bindtextdomain("multi_os", dt.configuration.config_dir .."/lua/locale/") local function _(msgid) return gettext(msgid) @@ -260,6 +260,14 @@ dt.register_event( ]] local script_data = {} + +script_data.metadata = { + name = "multi_os", + purpose = _("example module thet runs on different operating systems"), + author = "Bill Ferguson ", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/examples/multi_os" +} + script_data.destroy = destroy return script_data diff --git a/examples/panels_demo.lua b/examples/panels_demo.lua index ad7c924e..36e31e3c 100644 --- a/examples/panels_demo.lua +++ b/examples/panels_demo.lua @@ -61,7 +61,7 @@ local PS = dt.configuration.running_os == "windows" and "\\" or "/" -- - - - - - - - - - - - - - - - - - - - - - - - local gettext = dt.gettext.gettext -gettext.bindtextdomain("panels_demo", dt.configuration.config_dir .."/lua/locale/") +dt.gettext.bindtextdomain("panels_demo", dt.configuration.config_dir .."/lua/locale/") local function _(msgid) return gettext(msgid) @@ -146,6 +146,14 @@ end -- it's time to destroy the script and then return the data to -- script_manager local script_data = {} + +script_data.metadata = { + name = "panels_demo", + purpose = _("example demonstrating how to contol panel visibility"), + author = "Bill Ferguson ", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/examples/panels_demo" +} + script_data.destroy = destroy return script_data diff --git a/examples/preferenceExamples.lua b/examples/preferenceExamples.lua index c9040d85..e3721ca6 100644 --- a/examples/preferenceExamples.lua +++ b/examples/preferenceExamples.lua @@ -28,12 +28,21 @@ local du = require "lib/dtutils" local gettext = dt.gettext.gettext -gettext.bindtextdomain("preferenceExamples", dt.configuration.config_dir .."/lua/locale/") +dt.gettext.bindtextdomain("preferenceExamples", dt.configuration.config_dir .."/lua/locale/") local function _(msg) return gettext(msg) end +local script_data = {} + +script_data.metadata = { + name = "preferenceExamples", + purpose = _("example to show the different preference types that are possible"), + author = "Tobias Jakobs", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/examples/preferenceExamples" +} + du.check_min_api_version("2.0.1", "preferenceExamples") @@ -92,3 +101,11 @@ dt.preferences.register("preferenceExamples", -- script: This is a string "Enum 1", -- default "Enum 1", "Enum 2") -- values + +local function destroy() + -- nothing to destroy +end + +script_data.destroy = destroy + +return script_data diff --git a/examples/printExamples.lua b/examples/printExamples.lua index c68ddd59..23614c5b 100644 --- a/examples/printExamples.lua +++ b/examples/printExamples.lua @@ -28,7 +28,7 @@ du.check_min_api_version("5.0.0", "printExamples") local gettext = dt.gettext.gettext -gettext.bindtextdomain("printExamples", dt.configuration.config_dir .."/lua/locale/") +dt.gettext.bindtextdomain("printExamples", dt.configuration.config_dir .."/lua/locale/") local function _(msg) return gettext(msg) @@ -58,6 +58,14 @@ dt.print_log("print log") -- it's time to destroy the script and then return the data to -- script_manager local script_data = {} + +script_data.metadata = { + name = "printExamples", + purpose = _("example showing the different types of printing messages"), + author = "Tobias Jakobs", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/examples/printExamples" +} + script_data.destroy = destroy return script_data diff --git a/examples/running_os.lua b/examples/running_os.lua index 6a710958..1e61cb84 100644 --- a/examples/running_os.lua +++ b/examples/running_os.lua @@ -34,7 +34,7 @@ du.check_min_api_version("5.0.0", "running_os") local gettext = dt.gettext.gettext -gettext.bindtextdomain("running_os", dt.configuration.config_dir .."/lua/locale/") +dt.gettext.bindtextdomain("running_os", dt.configuration.config_dir .."/lua/locale/") local function _(msg) return gettext(msg) @@ -52,6 +52,14 @@ dt.print(string.format(_("you are running: %s"), dt.configuration.running_os)) -- it's time to destroy the script and then return the data to -- script_manager local script_data = {} + +script_data.metadata = { + name = "running_os", + purpose = _("example of how to determine the operating system being used"), + author = "Tobias Jakobs", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/examples/running_os" +} + script_data.destroy = destroy return script_data diff --git a/examples/x-touch.lua b/examples/x-touch.lua index 73ed112b..dd8dd2e9 100644 --- a/examples/x-touch.lua +++ b/examples/x-touch.lua @@ -1,163 +1,194 @@ ---[[ - This file is part of darktable, - copyright (c) 2023 Diederik ter Rahe - - darktable is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - darktable is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with darktable. If not, see . -]] ---[[ -X-Touch Mini flexible encoder shortcuts - -This script will create virtual sliders that are mapped dynamically to -the most relevant sliders for the currently focused processing module. -Tailored modules are color zones, tone equalizer, color calibration and -mask manager properties. The script can easily be amended for other -devices or personal preferences. Virtual "toggle" buttons can be created -as well, that dynamically change meaning depending on current status. - -USAGE -* require this script from your main lua file -* restart darktable -* create shortcuts for each of the encoders on the x-touch mini - to a virtual slider under lua/x-touch - or import the following shortcutsrc file in the shortcuts dialog/preferences tab: - -None;midi:CC1=lua/x-touch/knob 1 -None;midi:CC2=lua/x-touch/knob 2 -None;midi:CC3=lua/x-touch/knob 3 -None;midi:CC4=lua/x-touch/knob 4 -None;midi:CC5=lua/x-touch/knob 5 -None;midi:CC6=lua/x-touch/knob 6 -None;midi:CC7=lua/x-touch/knob 7 -None;midi:CC8=lua/x-touch/knob 8 -midi:E0=global/modifiers -midi:F0=global/modifiers;ctrl -midi:F#0=global/modifiers;alt -midi:G#-1=iop/blend/tools/show and edit mask elements -midi:A-1=iop/colorzones;focus -midi:A#-1=iop/toneequal;focus -midi:B-1=iop/colorbalancergb;focus -midi:C0=iop/channelmixerrgb;focus -]] - -local dt = require "darktable" -local du = require "lib/dtutils" - -du.check_min_api_version("9.2.0", "x-touch") - --- set up 8 mimic sliders with the same function -for k = 1,8 do - dt.gui.mimic("slider", "knob ".. k, - function(action, element, effect, size) - -- take the number from the mimic name - local k = tonumber(action:sub(-1)) - - -- only operate in darkroom; return NAN otherwise - if dt.gui.current_view() ~= dt.gui.views.darkroom then - return 0/0 - end - - local maskval = 0/0 - if k < 8 then - -- first try if the mask slider at that position is active - local s = { "opacity", - "size", - "feather", - "hardness", - "rotation", - "curvature", - "compression" } - maskval = dt.gui.action("lib/masks/properties/" .. s[k], - element, effect, size) - end - -- if a value different from NAN is returned, the slider was active - if maskval == maskval then - return maskval - - -- try if colorzones module is focused; if so select element of graph - elseif dt.gui.action("iop/colorzones", "focus") ~= 0 then - which = "iop/colorzones/graph" - local e = { "red", - "orange", - "yellow", - "green", - "aqua", - "blue", - "purple", - "magenta" } - element = e[k] - - - -- if the sigmoid rgb primaries is focused, - -- check sliders - elseif dt.gui.action("iop/sigmoid", "focus") ~= 0 and k <8 then - local e = { "red attenuation", "red rotation", "green attenuation", "green rotation", "blue attenuation", "blue rotation", "recover purity" } - which = "iop/sigmoid/primaries/"..e[k] - - -- if the rgb primaries is focused, - -- check sliders - elseif dt.gui.action("iop/primaries", "focus") ~= 0 and k >=1 then - local e = { "red hue", "red purity", "green hue", "green purity", "blue hue", "blue purity", "tint hue", "tint purity" } - which = "iop/primaries/" ..e[k] - - -- if the tone equalizer is focused, - -- select one of the sliders in the "simple" tab - elseif dt.gui.action("iop/toneequal", "focus") ~= 0 then - which ="iop/toneequal/simple/"..(k-9).." EV" - - -- if color calibration is focused, - -- the last 4 knobs are sent there - elseif dt.gui.action("iop/channelmixerrgb", "focus") ~= 0 - and k >= 5 then - -- knob 5 selects the active tab; pressing it resets to CAT - if k == 5 then - which = "iop/channelmixerrgb/page" - element = "CAT" - -- since the tab action is not a slider, - -- the effects need to be translated - if effect == "up" then effect = "next" - elseif effect == "down" then effect = "previous" - else effect = "activate" - end - else - -- knobs 6, 7 and 8 are for the three color sliders on each tab - which = "iop/focus/sliders" - local e = { "1st", - "2nd", - "3rd" } - element = e[k - 5] - end - - -- the 4th knob is contrast; - -- either colorbalance if it is focused, or filmic - elseif dt.gui.action("iop/colorbalancergb", "focus") ~= 0 - and k == 4 then - which = "iop/colorbalancergb/contrast" - - -- in all other cases use a default selection - else - local s = { "iop/exposure/exposure", - "iop/filmicrgb/white relative exposure", - "iop/filmicrgb/black relative exposure", - "iop/filmicrgb/contrast", - "iop/crop/left", - "iop/crop/right", - "iop/crop/top", - "iop/crop/bottom" } - which = s[k] - end - - -- now pass the element/effect/size to the selected slider - return dt.gui.action(which, element, effect, size) - end) -end +--[[ + This file is part of darktable, + copyright (c) 2023 Diederik ter Rahe + + darktable is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + darktable is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with darktable. If not, see . +]] +--[[ +X-Touch Mini flexible encoder shortcuts + +This script will create virtual sliders that are mapped dynamically to +the most relevant sliders for the currently focused processing module. +Tailored modules are color zones, tone equalizer, color calibration and +mask manager properties. The script can easily be amended for other +devices or personal preferences. Virtual "toggle" buttons can be created +as well, that dynamically change meaning depending on current status. + +USAGE +* require this script from your main lua file +* restart darktable +* create shortcuts for each of the encoders on the x-touch mini + to a virtual slider under lua/x-touch + or import the following shortcutsrc file in the shortcuts dialog/preferences tab: + +None;midi:CC1=lua/x-touch/knob 1 +None;midi:CC2=lua/x-touch/knob 2 +None;midi:CC3=lua/x-touch/knob 3 +None;midi:CC4=lua/x-touch/knob 4 +None;midi:CC5=lua/x-touch/knob 5 +None;midi:CC6=lua/x-touch/knob 6 +None;midi:CC7=lua/x-touch/knob 7 +None;midi:CC8=lua/x-touch/knob 8 +midi:E0=global/modifiers +midi:F0=global/modifiers;ctrl +midi:F#0=global/modifiers;alt +midi:G#-1=iop/blend/tools/show and edit mask elements +midi:A-1=iop/colorzones;focus +midi:A#-1=iop/toneequal;focus +midi:B-1=iop/colorbalancergb;focus +midi:C0=iop/channelmixerrgb;focus +]] + +local dt = require "darktable" +local du = require "lib/dtutils" + +du.check_min_api_version("9.2.0", "x-touch") + +local gettext = dt.gettext.gettext +dt.gettext.bindtextdomain("gui_action", dt.configuration.config_dir .."/lua/locale/") + +local function _(msgid) + return gettext(msgid) +end + +-- return data structure for script_manager + +local script_data = {} + +script_data.metadata = { + name = "x-touch", + purpose = _("example of how to control an x-touch midi device"), + author = "Diederik ter Rahe", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/examples/x-touch" +} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them + +-- set up 8 mimic sliders with the same function +for k = 1,8 do + dt.gui.mimic("slider", "knob ".. k, + function(action, element, effect, size) + -- take the number from the mimic name + local k = tonumber(action:sub(-1)) + + -- only operate in darkroom; return NAN otherwise + if dt.gui.current_view() ~= dt.gui.views.darkroom then + return 0/0 + end + + local maskval = 0/0 + if k < 8 then + -- first try if the mask slider at that position is active + local s = { "opacity", + "size", + "feather", + "hardness", + "rotation", + "curvature", + "compression" } + maskval = dt.gui.action("lib/masks/properties/" .. s[k], + element, effect, size) + end + -- if a value different from NAN is returned, the slider was active + if maskval == maskval then + return maskval + + -- try if colorzones module is focused; if so select element of graph + elseif dt.gui.action("iop/colorzones", "focus") ~= 0 then + which = "iop/colorzones/graph" + local e = { "red", + "orange", + "yellow", + "green", + "aqua", + "blue", + "purple", + "magenta" } + element = e[k] + + + -- if the sigmoid rgb primaries is focused, + -- check sliders + elseif dt.gui.action("iop/sigmoid", "focus") ~= 0 and k <8 then + local e = { "red attenuation", "red rotation", "green attenuation", "green rotation", "blue attenuation", "blue rotation", "recover purity" } + which = "iop/sigmoid/primaries/"..e[k] + + -- if the rgb primaries is focused, + -- check sliders + elseif dt.gui.action("iop/primaries", "focus") ~= 0 and k >=1 then + local e = { "red hue", "red purity", "green hue", "green purity", "blue hue", "blue purity", "tint hue", "tint purity" } + which = "iop/primaries/" ..e[k] + + -- if the tone equalizer is focused, + -- select one of the sliders in the "simple" tab + elseif dt.gui.action("iop/toneequal", "focus") ~= 0 then + which ="iop/toneequal/simple/"..(k-9).." EV" + + -- if color calibration is focused, + -- the last 4 knobs are sent there + elseif dt.gui.action("iop/channelmixerrgb", "focus") ~= 0 + and k >= 5 then + -- knob 5 selects the active tab; pressing it resets to CAT + if k == 5 then + which = "iop/channelmixerrgb/page" + element = "CAT" + -- since the tab action is not a slider, + -- the effects need to be translated + if effect == "up" then effect = "next" + elseif effect == "down" then effect = "previous" + else effect = "activate" + end + else + -- knobs 6, 7 and 8 are for the three color sliders on each tab + which = "iop/focus/sliders" + local e = { "1st", + "2nd", + "3rd" } + element = e[k - 5] + end + + -- the 4th knob is contrast; + -- either colorbalance if it is focused, or filmic + elseif dt.gui.action("iop/colorbalancergb", "focus") ~= 0 + and k == 4 then + which = "iop/colorbalancergb/contrast" + + -- in all other cases use a default selection + else + local s = { "iop/exposure/exposure", + "iop/filmicrgb/white relative exposure", + "iop/filmicrgb/black relative exposure", + "iop/filmicrgb/contrast", + "iop/crop/left", + "iop/crop/right", + "iop/crop/top", + "iop/crop/bottom" } + which = s[k] + end + + -- now pass the element/effect/size to the selected slider + return dt.gui.action(which, element, effect, size) + end) +end + +local function destroy() + -- nothing to destroy +end + +script_data.destroy = destroy + +return script_data diff --git a/official/check_for_updates.lua b/official/check_for_updates.lua index db184350..de92c7c9 100644 --- a/official/check_for_updates.lua +++ b/official/check_for_updates.lua @@ -34,10 +34,25 @@ local cjson = require "cjson" du.check_min_api_version("2.0.0", "check_for_updates") +local gettext = dt.gettext.gettext + +dt.gettext.bindtextdomain("check_for_updates", dt.configuration.config_dir .."/lua/locale/") + +local function _(msg) + return gettext(msg) +end + -- return data structure for script_manager local script_data = {} +script_data.metadata = { + name = "check_for_updates", + purpose = _("check for newer darktable releases"), + author = "Tobias Ellinghaus", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/official/check_for_updates" +} + script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again diff --git a/official/copy_paste_metadata.lua b/official/copy_paste_metadata.lua index a44270ef..0c765ec1 100644 --- a/official/copy_paste_metadata.lua +++ b/official/copy_paste_metadata.lua @@ -31,10 +31,23 @@ local gettext = dt.gettext.gettext du.check_min_api_version("7.0.0", "copy_paste_metadata") +dt.gettext.bindtextdomain("copy_paste_metadata", dt.configuration.config_dir .."/lua/locale/") + +local function _(msgid) + return gettext(msgid) +end + -- return data structure for script_manager local script_data = {} +script_data.metadata = { + name = "copy_paste_metadata", + purpose = _("adds keyboard shortcuts and buttons to copy/paste metadata between images"), + author = "Tobias Ellinghaus", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/official/copy_paste_metadata" +} + script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again @@ -58,12 +71,6 @@ local publisher = "" local rights = "" local tags = {} -gettext.bindtextdomain("copy_paste_metadata", dt.configuration.config_dir .."/lua/locale/") - -local function _(msgid) - return gettext(msgid) -end - local function copy(image) if not image then have_data = false diff --git a/official/delete_long_tags.lua b/official/delete_long_tags.lua index 2c5d0e6e..2c807e15 100644 --- a/official/delete_long_tags.lua +++ b/official/delete_long_tags.lua @@ -33,10 +33,25 @@ local du = require "lib/dtutils" du.check_min_api_version("2.0.0", "delete_long_tags") +local gettext = dt.gettext.gettext + +dt.gettext.bindtextdomain("delete_long_tags", dt.configuration.config_dir .."/lua/locale/") + +local function _(msgid) + return gettext(msgid) +end + -- return data structure for script_manager local script_data = {} +script_data.metadata = { + name = "delete_long_tags", + purpose = _("delete all tags longer than a set length"), + author = "Tobias Ellinghaus", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/official/delete_long_tags" +} + script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again diff --git a/official/delete_unused_tags.lua b/official/delete_unused_tags.lua index e169068e..bcdceaf1 100644 --- a/official/delete_unused_tags.lua +++ b/official/delete_unused_tags.lua @@ -37,10 +37,25 @@ local function destroy() -- noting to destroy end +local gettext = dt.gettext.gettext + +dt.gettext.bindtextdomain("delete_unused_tags", dt.configuration.config_dir .."/lua/locale/") + +local function _(msgid) + return gettext(msgid) +end + -- return data structure for script_manager local script_data = {} +script_data.metadata = { + name = "delete_unused_tags", + purpose = _("delete unused tags"), + author = "Tobias Ellinghaus", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/official/delete_unused_tags" +} + script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again diff --git a/official/enfuse.lua b/official/enfuse.lua index 9aa5815a..c8df51b1 100644 --- a/official/enfuse.lua +++ b/official/enfuse.lua @@ -43,10 +43,23 @@ local gettext = dt.gettext.gettext du.check_min_api_version("7.0.0", "enfuse") +dt.gettext.bindtextdomain("enfuse", dt.configuration.config_dir .."/lua/locale/") + +local function _(msgid) + return gettext(msgid) +end + -- return data structure for script_manager local script_data = {} +script_data.metadata = { + name = "enfuse", + purpose = _("exposure blend images"), + author = "Tobias Ellinghaus", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/official/enfuse" +} + script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again @@ -57,12 +70,6 @@ enf.event_registered = false enf.module_installed = false enf.lib_widgets = {} -gettext.bindtextdomain("enfuse", dt.configuration.config_dir .."/lua/locale/") - -local function _(msgid) - return gettext(msgid) -end - local function install_module() if not enf.module_installed then dt.register_lib( diff --git a/official/generate_image_txt.lua b/official/generate_image_txt.lua index c9559887..deacefaf 100644 --- a/official/generate_image_txt.lua +++ b/official/generate_image_txt.lua @@ -40,7 +40,7 @@ require "darktable.debug" local gettext = dt.gettext.gettext -gettext.bindtextdomain("generate_image_txt", dt.configuration.config_dir .."/lua/locale/") +dt.gettext.bindtextdomain("generate_image_txt", dt.configuration.config_dir .."/lua/locale/") local function _(msg) return gettext(msg) @@ -52,6 +52,13 @@ du.check_min_api_version("7.0.0", "generate_image_txt") local script_data = {} +script_data.metadata = { + name = "generate_image_txt", + purpose = _("overlay metadata on the selected image(s)"), + author = "Tobias Ellinghaus", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/official/generate_image_txt" +} + script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again diff --git a/official/image_path_in_ui.lua b/official/image_path_in_ui.lua index e81a6cb8..fd9e3fbc 100644 --- a/official/image_path_in_ui.lua +++ b/official/image_path_in_ui.lua @@ -33,10 +33,25 @@ local du = require "lib/dtutils" du.check_min_api_version("7.0.0", "image_path_in_ui") +local gettext = dt.gettext.gettext + +dt.gettext.bindtextdomain("image_path_in_ui", dt.configuration.config_dir .."/lua/locale/") + +local function _(msgid) + return gettext(msgid) +end + -- return data structure for script_manager local script_data = {} +script_data.metadata = { + name = "image_path_in_ui", + purpose = _("print the image path in the UI"), + author = "Jérémy Rosen", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/official/image_path_in_ui" +} + script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again diff --git a/official/import_filter_manager.lua b/official/import_filter_manager.lua index 05bc45dd..9b16ee3e 100644 --- a/official/import_filter_manager.lua +++ b/official/import_filter_manager.lua @@ -32,14 +32,28 @@ USAGE local dt = require "darktable" -local gettext = dt.gettext.gettext +local gettext = dt.gettext.gettext -gettext.bindtextdomain("import_filter_manager", dt.configuration.config_dir .."/lua/locale/") +dt.gettext.bindtextdomain("import_filter_manager", dt.configuration.config_dir .."/lua/locale/") local function _(msg) return gettext(msg) end +local script_data = {} + +script_data.metadata = { + name = "import_filter_manager", + purpose = _("manage import filters"), + author = "Tobias Ellinghaus", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/official/import_filter_manager" +} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them + local import_filter_list = {} local n_import_filters = 1 @@ -83,6 +97,12 @@ dt.register_import_filter = function(name, callback) if name == active_filter then filter_dropdown.value = n_import_filters end end +local function destroy() + --noting to destroy +end + +script_data.destroy = destroy +return script_data -- vim: shiftwidth=2 expandtab tabstop=2 cindent -- kate: tab-indents: off; indent-width 2; replace-tabs on; remove-trailing-space on; diff --git a/official/import_filters.lua b/official/import_filters.lua index 807dec61..165ec3fd 100644 --- a/official/import_filters.lua +++ b/official/import_filters.lua @@ -30,6 +30,28 @@ USAGE local dt = require "darktable" +local gettext = dt.gettext.gettext + +dt.gettext.bindtextdomain("import_filters", dt.configuration.config_dir .."/lua/locale/") + +local function _(msg) + return gettext(msg) +end + +local script_data = {} + +script_data.metadata = { + name = "import_filters", + purpose = _("import filtering"), + author = "Tobias Ellinghaus & Christian Mandel", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/official/import_filters" +} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them + -- we get fed a sorted list of filenames. just setting images to ignore to nil is enough -- ignore jpeg @@ -88,5 +110,13 @@ dt.register_import_filter("prefer raw over jpeg", function(event, images) end) +local function destroy() + -- nothing to destroy +end + +script_data.destroy = destroy + +return script_data + -- vim: shiftwidth=2 expandtab tabstop=2 cindent -- kate: tab-indents: off; indent-width 2; replace-tabs on; remove-trailing-space on; diff --git a/official/save_selection.lua b/official/save_selection.lua index f37ad0be..865ca265 100644 --- a/official/save_selection.lua +++ b/official/save_selection.lua @@ -38,9 +38,9 @@ local du = require "lib/dtutils" du.check_min_api_version("7.0.0", "save_selection") -local gettext = dt.gettext.gettext +local gettext = dt.gettext.gettext -gettext.bindtextdomain("save_selection", dt.configuration.config_dir .."/lua/locale/") +dt.gettext.bindtextdomain("save_selection", dt.configuration.config_dir .."/lua/locale/") local function _(msg) return gettext(msg) @@ -50,6 +50,13 @@ end local script_data = {} +script_data.metadata = { + name = "save_selection", + purpose = _("shortcuts providing multiple selection buffers"), + author = "Jérémy Rosen", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/official/save_selection" +} + script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again diff --git a/official/selection_to_pdf.lua b/official/selection_to_pdf.lua index 116f0d75..18a7be57 100644 --- a/official/selection_to_pdf.lua +++ b/official/selection_to_pdf.lua @@ -38,9 +38,9 @@ local du = require "lib/dtutils" du.check_min_api_version("7.0.0", "selection_to_pdf") -local gettext = dt.gettext.gettext +local gettext = dt.gettext.gettext -gettext.bindtextdomain("selection_to_pdf", dt.configuration.config_dir .."/lua/locale/") +dt.gettext.bindtextdomain("selection_to_pdf", dt.configuration.config_dir .."/lua/locale/") local function _(msg) return gettext(msg) @@ -50,6 +50,13 @@ end local script_data = {} +script_data.metadata = { + name = "selection_to_pdf", + purpose = _("generate a pdf file of selected images"), + author = "Jérémy Rosen & Pascal Obry", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/official/selection_to_pdf" +} + script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again diff --git a/tools/executable_manager.lua b/tools/executable_manager.lua index 48659746..58a055ab 100644 --- a/tools/executable_manager.lua +++ b/tools/executable_manager.lua @@ -34,10 +34,25 @@ local df = require "lib/dtutils.file" du.check_min_api_version("7.0.0", "executable_manager") +local gettext = dt.gettext.gettext + +dt.gettext.bindtextdomain("executable_manager", dt.configuration.config_dir .."/lua/locale/") + +local function _(msg) + return gettext(msg) +end + -- return data structure for script_manager local script_data = {} +script_data.metadata = { + name = "executable_manager", + purpose = _("manage the list of external executables used by the lua scripts"), + author = "Bill Ferguson ", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/tools/executable_manager" +} + script_data.destroy = nil -- function to destory the script script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again @@ -45,8 +60,6 @@ script_data.show = nil -- only required for libs since the destroy_method only h local PS = dt.configuration.running_os == "windows" and "\\" or "/" -local gettext = dt.gettext.gettext - local exec_man = {} -- our own namespace exec_man.module_installed = false exec_man.event_registered = false @@ -55,12 +68,6 @@ exec_man.event_registered = false -- F U N C T I O N S -- - - - - - - - - - - - - - - - - - - - - - - - - - - - -gettext.bindtextdomain("executable_manager", dt.configuration.config_dir .."/lua/locale/") - -local function _(msg) - return gettext(msg) -end - local function grep(file, pattern) local result = {} diff --git a/tools/get_lib_manpages.lua b/tools/get_lib_manpages.lua index 2e599181..a3c39157 100644 --- a/tools/get_lib_manpages.lua +++ b/tools/get_lib_manpages.lua @@ -12,6 +12,14 @@ local libname = nil du.check_min_api_version("3.0.0", "get_lib_manpages") +local gettext = dt.gettext.gettext + +dt.gettext.bindtextdomain("get_lib_manpages", dt.configuration.config_dir .."/lua/locale/") + +local function _(msg) + return gettext(msg) +end + local function destroy() -- nothing to destroy end @@ -79,6 +87,14 @@ for line in output:lines() do end local script_data = {} + +script_data.metadata = { + name = "get_lib_manpages", + purpose = _("output the internal library documentation as man pages"), + author = "Bill Ferguson ", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/tools/get_lib_manpages" +} + script_data.destroy = destroy return script_data diff --git a/tools/get_libdoc.lua b/tools/get_libdoc.lua index d22516fc..5cb08122 100644 --- a/tools/get_libdoc.lua +++ b/tools/get_libdoc.lua @@ -9,6 +9,14 @@ local du = require "lib/dtutils" du.check_min_api_version("3.0.0", "get_libdoc") +local gettext = dt.gettext.gettext + +dt.gettext.bindtextdomain("get_libdoc", dt.configuration.config_dir .."/lua/locale/") + +local function _(msg) + return gettext(msg) +end + local function destroy() -- nothing to destroy end @@ -53,6 +61,14 @@ for line in output:lines() do end local script_data = {} + +script_data.metadata = { + name = "get_libdoc", + purpose = _("retrieve and print the documentation to the console"), + author = "Bill Ferguson ", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/tools/get_libdoc" +} + script_data.destroy = destroy return script_data From 284c0f971484a367a1ed22bc69587deea4eafcef Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Wed, 15 May 2024 21:33:29 -0400 Subject: [PATCH 287/445] tools/script_manager - fixed metadata decoding to get rid of spurious commas --- tools/script_manager.lua | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tools/script_manager.lua b/tools/script_manager.lua index 28bd1d98..b79dbe30 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -60,7 +60,7 @@ local gettext = dt.gettext -- Tell gettext where to find the .mo file translating messages for a particular domain -gettext.bindtextdomain("script_manager",dt.configuration.config_dir.."/lua/locale/") +dt.gettext.bindtextdomain("script_manager",dt.configuration.config_dir.."/lua/locale/") local function _(msgid) return gettext.dgettext("script_manager", msgid) @@ -380,6 +380,10 @@ local function string_dei18n(str) return string.match(str, "%_%((.+)%)") end +local function string_chop(str) + return str:sub(1, -2) +end + ------------------ -- script handling ------------------ @@ -431,6 +435,9 @@ local function get_script_metadata(script) else parts[2] = string_dequote(parts[2]) end + if string.match(parts[2], ",$") then + parts[2] = string_chop(parts[2]) + end metadata = metadata .. string.format("%s%-10s\t%s", first and "" or "\n", parts[1], parts[2]) first = nil end @@ -438,6 +445,7 @@ local function get_script_metadata(script) end restore_log_level(old_log_level) + dt.print_log(metadata) return metadata end From bf138abeb2d21e52839f7c7aa1ef459c3898e46d Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Wed, 15 May 2024 21:36:15 -0400 Subject: [PATCH 288/445] tools/script_manager - removed debugging statement --- tools/script_manager.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/script_manager.lua b/tools/script_manager.lua index b79dbe30..daaa824e 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -445,7 +445,6 @@ local function get_script_metadata(script) end restore_log_level(old_log_level) - dt.print_log(metadata) return metadata end From 5c3b2777f077b03820876a2eb45aa33f8b7a6e19 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Thu, 16 May 2024 11:44:35 -0400 Subject: [PATCH 289/445] tools/script_manager - fixed gettext.bindtextdomain --- tools/script_manager.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/script_manager.lua b/tools/script_manager.lua index 3938d94f..71609321 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -60,7 +60,7 @@ local debug = require "darktable.debug" local gettext = dt.gettext.gettext -gettext.bindtextdomain("script_manager", dt.configuration.config_dir .."/lua/locale/") +dt.gettext.bindtextdomain("script_manager", dt.configuration.config_dir .."/lua/locale/") local function _(msgid) return gettext(msgid) From 3e2afffed82ff9488c0805bcfd389d8361269c7c Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sat, 18 May 2024 21:59:11 -0400 Subject: [PATCH 290/445] lib/dtutils/string - Added categories to substitution functionality. This makes it feature complete. Some substitutions aren't implemented since the current use case for this is creating export directories. The results from the not implemented substitutions wouldn't work well in path/file names (such as comma separated lists or newlines). --- lib/dtutils/string.lua | 291 +++++++++++++++++++++++++++-------------- 1 file changed, 195 insertions(+), 96 deletions(-) diff --git a/lib/dtutils/string.lua b/lib/dtutils/string.lua index e315edaa..1cece46a 100644 --- a/lib/dtutils/string.lua +++ b/lib/dtutils/string.lua @@ -477,6 +477,7 @@ function dtutils_string.get_filetype(str) end local substitutes = {} +local category_substitutes = {} -- - - - - - - - - - - - - - - - - - - - - - - - -- C O N S T A N T S @@ -488,7 +489,7 @@ local PLACEHOLDERS = {"ROLL.NAME", "FILE.EXTENSION", "ID", "VERSION", - "VERSION.IF.MULTI", -- Not Implemented + "VERSION.IF.MULTI", "VERSION.NAME", "DARKTABLE.VERSION", "DARKTABLE.NAME", -- Not Implemented @@ -504,14 +505,20 @@ local PLACEHOLDERS = {"ROLL.NAME", "WIDTH.MAX", -- Not Implemented "HEIGHT.MAX", -- Not Implemented "YEAR", + "YEAR.SHORT", "MONTH", + "MONTH.LONG", + "MONTH.SHORT", "DAY", "HOUR", "MINUTE", "SECOND", "MSEC", "EXIF.YEAR", + "EXIF.YEAR.SHORT", "EXIF.MONTH", + "EXIF.MONTH.LONG", + "EXIF.MONTH.SHORT", "EXIF.DAY", "EXIF.HOUR", "EXIF.MINUTE", @@ -523,17 +530,22 @@ local PLACEHOLDERS = {"ROLL.NAME", "EXIF.EXPOSURE", "EXIF.EXPOSURE.BIAS", "EXIF.APERTURE", + "EXIF.CROP.FACTOR", "EXIF.FOCAL.LENGTH", + "EXIF.FOCAL.LENGTH.EQUIV", -- Not Implemented "EXIF.FOCUS.DISTANCE", + "IMAGE.EXIF", -- Not Implemented "LONGITUDE", "LATITUDE", - "ALTITUDE", + "ELEVATION", + "GPS.LOCATION", -- Not Implemented "STARS", "RATING.ICONS", -- Not Implemented "LABELS", "LABELS.ICONS", -- Not Implemented "MAKER", "MODEL", + "LENS", "TITLE", "DESCRIPTION", "CREATOR", @@ -547,7 +559,7 @@ local PLACEHOLDERS = {"ROLL.NAME", "FOLDER.DESKTOP", "OPENCL.ACTIVATED", -- Not Implemented "USERNAME", - "NL", + "NL", -- Not Implemented "JOBCODE" -- Not Implemented } @@ -560,14 +572,19 @@ local DESKTOP = HOME .. PS .. "Desktop" local function get_colorlabels(image) local old_log_level = log.log_level() log.log_level(dtutils_string.log_level) + local colorlabels = {} + if image.red then table.insert(colorlabels, "red") end if image.yellow then table.insert(colorlabels, "yellow") end if image.green then table.insert(colorlabels, "green") end if image.blue then table.insert(colorlabels, "blue") end if image.purple then table.insert(colorlabels, "purple") end - local labels = #colorlabels == 1 and colorlabels[1] or du.join(colorlabels, ",") + + local labels = #colorlabels == 1 and colorlabels[1] or du.join(colorlabels, "_") + log.log_level(old_log_level) + return labels end @@ -575,9 +592,10 @@ dtutils_string.libdoc.functions["build_substitution_list"] = { Name = [[build_substitution_list]], Synopsis = [[build a list of variable substitutions]], Usage = [[local ds = require "lib/dtutils.string" - ds.build_substitution_list(image, sequence, [username], [pic_folder], [home], [desktop]) + ds.build_substitution_list(image, sequence, variable_string, [username], [pic_folder], [home], [desktop]) image - dt_lua_image_t - the image being processed sequence - integer - the sequence number of the image + variable_string - string - the substitution variable string [username] - string - optional - user name. Will be determined if not supplied [pic_folder] - string - optional - pictures folder name. Will be determined if not supplied [home] - string - optional - home directory. Will be determined if not supplied @@ -594,7 +612,46 @@ dtutils_string.libdoc.functions["build_substitution_list"] = { Copyright = [[]], } -function dtutils_string.build_substition_list(image, sequence, username, pic_folder, home, desktop) +local function build_category_substitution_list(image, variable_string) + -- scan the variable string for CATEGORYn(tag name) entries and build the substitutions + local old_log_level = log.log_level() + -- log.log_level(dtutils_string.log_level) + --log.log_level(log.debug) + + for match in string.gmatch(variable_string, "%$%(.-%)?%)") do + log.msg(log.info, "match is " .. match) + local var = string.match(match, "%$%((.-%)?)%)") + log.msg(log.info, "var is " .. var) + if string.match(var, "CATEGORY%d") then + local element, tag = string.match(var, "CATEGORY(%d)%((.-)%)") + element = element + 1 + log.msg(log.debug, "element is " .. element .. " and tag is " .. tag) + local tags = image:get_tags() + log.msg(log.debug, "got " .. #tags .. " from image " .. image.filename) + for _, image_tag in ipairs(tags) do + log.msg(log.debug, "checking tag " .. image_tag.name) + if string.match(image_tag.name, tag) then + parts = du.split(image_tag.name, "|") + substitutes[var] = parts[element] + log.msg(log.info, "set substitute for " .. var .. " to " .. parts[element]) + log.msg(log.info, "double check substitutes[" .. var .. "] is " .. substitutes[var]) + end + end + end + end + -- scan the variable string looking for CATEGORYn + -- retrieve the tag and compute the replacement string + -- add the found string as a PLACEHOLDER + -- add the replacement to the corresponding spot in the replacement table + log.log_level(old_log_level) +end + +local function exiftime2systime(exiftime) + local yr,mo,dy,h,m,s = string.match(exiftime, "(%d-):(%d-):(%d-) (%d-):(%d-):(%d+)") + return(os.time{year=yr, month=mo, day=dy, hour=h, min=m, sec=s}) +end + +function dtutils_string.build_substition_list(image, sequence, variable_string, username, pic_folder, home, desktop) -- build the argument substitution list from each image local old_log_level = log.log_level() @@ -606,6 +663,8 @@ function dtutils_string.build_substition_list(image, sequence, username, pic_fol end local datetime = os.date("*t") + local long_month = os.date("%B") + local short_month = os.date("%b") local user_name = username or USER local pictures_folder = pic_folder or PICTURES local home_folder = home or HOME @@ -629,7 +688,8 @@ function dtutils_string.build_substition_list(image, sequence, username, pic_fol dtutils_string.get_filetype(image.filename),-- FILE.EXTENSION image.id, -- ID image.duplicate_index, -- VERSION - "", -- VERSION.IF_MULTI + -- #image:get_group_members() > 1 and image.duplicate_index or "", -- VERSION.IF_MULTI + "", -- VERSION.IF_MULTI image.version_name, -- VERSION.NAME dt.configuration.version, -- DARKTABLE.VERSION "", -- DARKTABLE.NAME @@ -645,57 +705,71 @@ function dtutils_string.build_substition_list(image, sequence, username, pic_fol "", -- WIDTH.MAX "", -- HEIGHT.MAX string.format("%4d", datetime.year), -- YEAR + string.sub(datetime.year, 3), -- YEAR.SHORT string.format("%02d", datetime.month), -- MONTH + long_month, -- MONTH.LONG + short_month, -- MONTH.SHORT string.format("%02d", datetime.day), -- DAY string.format("%02d", datetime.hour), -- HOUR string.format("%02d", datetime.min), -- MINUTE string.format("%02d", datetime.sec), -- SECOND - "", -- MSEC + 0, -- MSEC eyear, -- EXIF.YEAR + string.sub(eyear, 3), -- EXIF.YEAR.SHORT emon, -- EXIF.MONTH + os.date("%B", exiftime2systime(image.exif_datetime_taken)), -- EXIF.MONTH.LONG + os.date("%b", exiftime2systime(image.exif_datetime_taken)), -- EXIF.MONTH.SHORT eday, -- EXIF.DAY ehour, -- EXIF.HOUR emin, -- EXIF.MINUTE esec, -- EXIF.SECOND emsec, -- EXIF.MSEC - "", -- EXIF.DATE.REGIONAL - "", -- EXIF.TIME.REGIONAL + "", -- EXIF.DATE.REGIONAL - wont be implemented + "", -- EXIF.TIME.REGIONAL - wont be implemented string.format("%d", image.exif_iso), -- EXIF.ISO - string.format("1/%.0f", 1./image.exif_exposure), -- EXIF.EXPOSURE + string.format("%.0f", 1./image.exif_exposure), -- EXIF.EXPOSURE image.exif_exposure_bias, -- EXIF.EXPOSURE.BIAS string.format("%.01f", image.exif_aperture), -- EXIF.APERTURE + string.format("%.01f", image.exif_crop),-- EXIF.CROP_FACTOR string.format("%.0f", image.exif_focal_length), -- EXIF.FOCAL.LENGTH + string.format("%.0f", image.exif_focal_length * image.exif_crop), -- EXIF.FOCAL.LENGTH.EQUIV image.exif_focus_distance, -- EXIF.FOCUS.DISTANCE + "", -- IMAGE.EXIF image.longitude or "", -- LONGITUDE image.latitude or "", -- LATITUDE - image.elevation or "", -- ALTITUDE + image.elevation or "", -- ELEVATION + "", -- GPS.LOCATION - wont be implemented image.rating, -- STARS - "", -- RATING.ICONS + "", -- RATING.ICONS - wont be implemented labels, -- LABELS - "", -- LABELS.ICONS + "", -- LABELS.ICONS - wont be implemented image.exif_maker, -- MAKER image.exif_model, -- MODEL + image.exif_lens, -- LENS image.title, -- TITLE image.description, -- DESCRIPTION image.creator, -- CREATOR image.publisher, -- PUBLISHER image.rights, -- RIGHTS - "", -- TAGS - "", -- CATEGORYn - "", -- SIDECAR.TXT + "", -- TAGS - wont be implemented + "", -- CATEGORY + "", -- SIDECAR.TXT - wont be implemented pictures_folder, -- FOLDER.PICTURES home_folder, -- FOLDER.HOME desktop_folder, -- FOLDER.DESKTOP - "", -- OPENCL.ACTIVATED + "", -- OPENCL.ACTIVATED - wont be implemented user_name, -- USERNAME - "\n", -- NL - "" -- JOBCODE + "", -- NL - wont be implemented + "" -- JOBCODE - wont be implemented } for i = 1, #PLACEHOLDERS, 1 do substitutes[PLACEHOLDERS[i]] = replacements[i] log.msg(log.info, "setting " .. PLACEHOLDERS[i] .. " to " .. tostring(replacements[i])) end + + build_category_substitution_list(image, variable_string) + log.log_level(old_log_level) end @@ -712,86 +786,105 @@ end local function treat(var_string) local old_log_level = log.log_level() - log.log_level(dtutils_string.log_level) + --log.log_level(dtutils_string.log_level) + --log.log_level(log.info) local ret_val = "" -- remove the var from the string local var = string.match(var_string, "[%a%._]+") var = check_legacy_vars(var) log.msg(log.info, "var_string is " .. tostring(var_string) .. " and var is " .. tostring(var)) - ret_val = substitutes[var] - if not ret_val then + if string.match(var_string, "CATEGORY%d") then + log.msg(log.info, "substituting for " .. var_string) + ret_val = substitutes[var_string] + log.msg(log.info, "ret_val is " .. ret_val) + else + ret_val = substitutes[var] + end + local valid_var = false + + if ret_val then + valid_var = true + --elseif string.match(var, "CATEGORY%d") then + --valid_var = true + end + + if not valid_var then log.msg(log.error, "variable " .. var .. " is not an allowed variable, returning empty value") log.log_level(old_log_level) return "" end - local args = string.gsub(var_string, var, "") - log.msg(log.info, "args is " .. tostring(args)) - if string.len(args) > 0 then - if string.match(args, '^%^%^') then - ret_val = string.upper(ret_val) - elseif string.match(args, "^%^") then - ret_val = string.gsub(ret_val, "^%a", string.upper, 1) - elseif string.match(args, "^,,") then - ret_val = string.lower(ret_val) - elseif string.match(args, "^,") then - ret_val = string.gsub(ret_val, "^%a", string.lower, 1) - elseif string.match(args, "^:%-?%d+:%-?%d+") then - local soffset, slen = string.match(args, ":(%-?%d+):(%-?%d+)") - log.msg(log.info, "soffset is " .. soffset .. " and slen is " .. slen) - if tonumber(soffset) >= 0 then - soffset = soffset + 1 - end - log.msg(log.info, "soffset is " .. soffset .. " and slen is " .. slen) - if tonumber(soffset) < 0 and tonumber(slen) < 0 then - local temp = soffset - soffset = slen - slen = temp - end - log.msg(log.info, "soffset is " .. soffset .. " and slen is " .. slen) - ret_val = string.sub(ret_val, soffset, slen) - log.msg(log.info, "ret_val is " .. ret_val) - elseif string.match(args, "^:%-?%d+") then - local soffset= string.match(args, ":(%-?%d+)") - if tonumber(soffset) >= 0 then - soffset = soffset + 1 - end - ret_val = string.sub(ret_val, soffset, -1) - elseif string.match(args, "^-%$%(.-%)") then - local replacement = string.match(args, "-%$%(([%a%._]+)%)") - replacement = check_legacy_vars(replacement) - if string.len(ret_val) == 0 then - ret_val = substitutes[replacement] - end - elseif string.match(args, "^-.+$") then - local replacement = string.match(args, "-(.+)$") - if string.len(ret_val) == 0 then - ret_val = replacement - end - elseif string.match(args, "^+.+") then - local replacement = string.match(args, "+(.+)") - if string.len(ret_val) > 0 then - ret_val = replacement + if string.match(var, "CATEGORY%d") then + ret_val = process_category(image, var, var_string) + else + local args = string.gsub(var_string, var, "") + log.msg(log.info, "args is " .. tostring(args)) + if string.len(args) > 0 then + if string.match(args, '^%^%^') then + ret_val = string.upper(ret_val) + elseif string.match(args, "^%^") then + ret_val = string.gsub(ret_val, "^%a", string.upper, 1) + elseif string.match(args, "^,,") then + ret_val = string.lower(ret_val) + elseif string.match(args, "^,") then + ret_val = string.gsub(ret_val, "^%a", string.lower, 1) + elseif string.match(args, "^:%-?%d+:%-?%d+") then + local soffset, slen = string.match(args, ":(%-?%d+):(%-?%d+)") + log.msg(log.info, "soffset is " .. soffset .. " and slen is " .. slen) + if tonumber(soffset) >= 0 then + soffset = soffset + 1 + end + log.msg(log.info, "soffset is " .. soffset .. " and slen is " .. slen) + if tonumber(soffset) < 0 and tonumber(slen) < 0 then + local temp = soffset + soffset = slen + slen = temp + end + log.msg(log.info, "soffset is " .. soffset .. " and slen is " .. slen) + ret_val = string.sub(ret_val, soffset, slen) + log.msg(log.info, "ret_val is " .. ret_val) + elseif string.match(args, "^:%-?%d+") then + local soffset= string.match(args, ":(%-?%d+)") + if tonumber(soffset) >= 0 then + soffset = soffset + 1 + end + ret_val = string.sub(ret_val, soffset, -1) + elseif string.match(args, "^-%$%(.-%)") then + local replacement = string.match(args, "-%$%(([%a%._]+)%)") + replacement = check_legacy_vars(replacement) + if string.len(ret_val) == 0 then + ret_val = substitutes[replacement] + end + elseif string.match(args, "^-.+$") then + local replacement = string.match(args, "-(.+)$") + if string.len(ret_val) == 0 then + ret_val = replacement + end + elseif string.match(args, "^+.+") then + local replacement = string.match(args, "+(.+)") + if string.len(ret_val) > 0 then + ret_val = replacement + end + elseif string.match(args, "^#.+") then + local pattern = string.match(args, "#(.+)") + log.msg(log.info, "pattern to remove is " .. tostring(pattern)) + ret_val = string.gsub(ret_val, "^" .. dtutils_string.sanitize_lua(pattern), "") + elseif string.match(args, "^%%.+") then + local pattern = string.match(args, "%%(.+)") + ret_val = string.gsub(ret_val, pattern .. "$", "") + elseif string.match(args, "^//.-/.+") then + local pattern, replacement = string.match(args, "//(.-)/(.+)") + ret_val = string.gsub(ret_val, pattern, replacement) + elseif string.match(args, "^/#.+/.+") then + local pattern, replacement = string.match(args, "/#(.+)/(.+)") + ret_val = string.gsub(ret_val, "^" .. pattern, replacement, 1) + elseif string.match(args, "^/%%.-/.+") then + local pattern, replacement = string.match(args, "/%%(.-)/(.+)") + ret_val = string.gsub(ret_val, pattern .. "$", replacement) + elseif string.match(args, "^/.-/.+") then + log.msg(log.info, "took replacement branch") + local pattern, replacement = string.match(args, "/(.-)/(.+)") + ret_val = string.gsub(ret_val, pattern, replacement, 1) end - elseif string.match(args, "^#.+") then - local pattern = string.match(args, "#(.+)") - log.msg(log.info, "pattern to remove is " .. tostring(pattern)) - ret_val = string.gsub(ret_val, "^" .. dtutils_string.sanitize_lua(pattern), "") - elseif string.match(args, "^%%.+") then - local pattern = string.match(args, "%%(.+)") - ret_val = string.gsub(ret_val, pattern .. "$", "") - elseif string.match(args, "^//.-/.+") then - local pattern, replacement = string.match(args, "//(.-)/(.+)") - ret_val = string.gsub(ret_val, pattern, replacement) - elseif string.match(args, "^/#.+/.+") then - local pattern, replacement = string.match(args, "/#(.+)/(.+)") - ret_val = string.gsub(ret_val, "^" .. pattern, replacement, 1) - elseif string.match(args, "^/%%.-/.+") then - local pattern, replacement = string.match(args, "/%%(.-)/(.+)") - ret_val = string.gsub(ret_val, pattern .. "$", replacement) - elseif string.match(args, "^/.-/.+") then - log.msg(log.info, "took replacement branch") - local pattern, replacement = string.match(args, "/(.-)/(.+)") - ret_val = string.gsub(ret_val, pattern, replacement, 1) end end log.log_level(old_log_level) @@ -848,9 +941,10 @@ dtutils_string.libdoc.functions["clear_substitute_list"] = { function dtutils_string.clear_substitute_list() local old_log_level = log.log_level() log.log_level(dtutils_string.log_level) - for i = 1, #PLACEHOLDERS, 1 do - substitutes[PLACEHOLDERS[i]] = nil - end + + substitutes = {} + category_substitutes = {} + log.log_level(old_log_level) end @@ -858,9 +952,10 @@ dtutils_string.libdoc.functions["substitute"] = { Name = [[substitute]], Synopsis = [[Check if a string has been sanitized]], Usage = [[local ds = require "lib/dtutils.string" - ds.substitute(image, sequence, [username], [pic_folder], [home], [desktop]) + ds.substitute(image, sequence, variable_string, [username], [pic_folder], [home], [desktop]) image - dt_lua_image_t - the image being processed sequence - integer - the sequence number of the image + variable_string - string - the substitution variable string [username] - string - optional - user name. Will be determined if not supplied [pic_folder] - string - optional - pictures folder name. Will be determined if not supplied [home] - string - optional - home directory. Will be determined if not supplied @@ -880,13 +975,17 @@ dtutils_string.libdoc.functions["substitute"] = { function dtutils_string.substitute(image, sequence, variable_string, username, pic_folder, home, desktop) local old_log_level = log.log_level() log.log_level(dtutils_string.log_level) + dtutils_string.clear_substitute_list() - dtutils_string.build_substition_list(image, sequence, username, pic_folder, home, desktop) + + dtutils_string.build_substition_list(image, sequence, variable_string, username, pic_folder, home, desktop) + local str = dtutils_string.substitute_list(variable_string) + log.log_level(old_log_level) + return str end - return dtutils_string From 7b2018412a7180c09ab502062dac2d8939c8dec0 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sat, 18 May 2024 22:01:10 -0400 Subject: [PATCH 291/445] lib/dtutils/string - Cleaned up code to make it more readable. Fixed VERSION_IF_MULTI. Added safety check in category to make sure we don't try and read a tag field that doesn't exist. --- lib/dtutils/string.lua | 353 ++++++++++++++++++++++++----------------- 1 file changed, 208 insertions(+), 145 deletions(-) diff --git a/lib/dtutils/string.lua b/lib/dtutils/string.lua index 1cece46a..dad0d558 100644 --- a/lib/dtutils/string.lua +++ b/lib/dtutils/string.lua @@ -476,6 +476,30 @@ function dtutils_string.get_filetype(str) return parts["filetype"] end +dtutils_string.libdoc.functions["build_substitution_list"] = { + Name = [[build_substitution_list]], + Synopsis = [[build a list of variable substitutions]], + Usage = [[local ds = require "lib/dtutils.string" + ds.build_substitution_list(image, sequence, variable_string, [username], [pic_folder], [home], [desktop]) + image - dt_lua_image_t - the image being processed + sequence - integer - the sequence number of the image + variable_string - string - the substitution variable string + [username] - string - optional - user name. Will be determined if not supplied + [pic_folder] - string - optional - pictures folder name. Will be determined if not supplied + [home] - string - optional - home directory. Will be determined if not supplied + [desktop] - string - optional - desktop directory. Will be determined if not supplied]], + Description = [[build_substitution_list populates variables with values from the arguments + and determined from the system and darktable.]], + Return_Value = [[]], + Limitations = [[If the value for a variable can not be determined, or if it is not supported, + then an empty string is used for the value.]], + Example = [[]], + See_Also = [[https://docs.darktable.org/usermanual/4.2/en/special-topics/variables/]], + Reference = [[]], + License = [[]], + Copyright = [[]], +} + local substitutes = {} local category_substitutes = {} @@ -492,7 +516,7 @@ local PLACEHOLDERS = {"ROLL.NAME", "VERSION.IF.MULTI", "VERSION.NAME", "DARKTABLE.VERSION", - "DARKTABLE.NAME", -- Not Implemented + "DARKTABLE.NAME", -- Not Implemented "SEQUENCE", "WIDTH.SENSOR", "HEIGHT.SENSOR", @@ -502,8 +526,8 @@ local PLACEHOLDERS = {"ROLL.NAME", "HEIGHT.CROP", "WIDTH.EXPORT", "HEIGHT.EXPORT", - "WIDTH.MAX", -- Not Implemented - "HEIGHT.MAX", -- Not Implemented + "WIDTH.MAX", -- Not Implemented + "HEIGHT.MAX", -- Not Implemented "YEAR", "YEAR.SHORT", "MONTH", @@ -524,8 +548,8 @@ local PLACEHOLDERS = {"ROLL.NAME", "EXIF.MINUTE", "EXIF.SECOND", "EXIF.MSEC", - "EXIF.DATE.REGIONAL", -- Not Implemented - "EXIF.TIME.REGIONAL", -- Not Implemented + "EXIF.DATE.REGIONAL", -- Not Implemented + "EXIF.TIME.REGIONAL", -- Not Implemented "EXIF.ISO", "EXIF.EXPOSURE", "EXIF.EXPOSURE.BIAS", @@ -534,15 +558,15 @@ local PLACEHOLDERS = {"ROLL.NAME", "EXIF.FOCAL.LENGTH", "EXIF.FOCAL.LENGTH.EQUIV", -- Not Implemented "EXIF.FOCUS.DISTANCE", - "IMAGE.EXIF", -- Not Implemented + "IMAGE.EXIF", -- Not Implemented "LONGITUDE", "LATITUDE", "ELEVATION", - "GPS.LOCATION", -- Not Implemented + "GPS.LOCATION", -- Not Implemented "STARS", - "RATING.ICONS", -- Not Implemented + "RATING.ICONS", -- Not Implemented "LABELS", - "LABELS.ICONS", -- Not Implemented + "LABELS.ICONS", -- Not Implemented "MAKER", "MODEL", "LENS", @@ -551,23 +575,22 @@ local PLACEHOLDERS = {"ROLL.NAME", "CREATOR", "PUBLISHER", "RIGHTS", - "TAGS", -- Not Implemented - "CATEGORY", -- Not Implemented - "SIDECAR.TXT", -- Not Implemented + "TAGS", -- Not Implemented + "SIDECAR.TXT", -- Not Implemented "FOLDER.PICTURES", "FOLDER.HOME", "FOLDER.DESKTOP", - "OPENCL.ACTIVATED", -- Not Implemented + "OPENCL.ACTIVATED", -- Not Implemented "USERNAME", - "NL", -- Not Implemented - "JOBCODE" -- Not Implemented + "NL", -- Not Implemented + "JOBCODE" -- Not Implemented } -local PS = dt.configuration.running_os == "windows" and "\\" or "/" -local USER = os.getenv("USERNAME") -local HOME = dt.configuration.running_os == "windows" and os.getenv("HOMEPATH") or os.getenv("HOME") -local PICTURES = HOME .. PS .. (dt.configuration.running_os == "windows" and "My Pictures" or "Pictures") -local DESKTOP = HOME .. PS .. "Desktop" +local PS = dt.configuration.running_os == "windows" and "\\" or "/" +local USER = os.getenv("USERNAME") +local HOME = dt.configuration.running_os == "windows" and os.getenv("HOMEPATH") or os.getenv("HOME") +local PICTURES = HOME .. PS .. (dt.configuration.running_os == "windows" and "My Pictures" or "Pictures") +local DESKTOP = HOME .. PS .. "Desktop" local function get_colorlabels(image) local old_log_level = log.log_level() @@ -588,75 +611,64 @@ local function get_colorlabels(image) return labels end -dtutils_string.libdoc.functions["build_substitution_list"] = { - Name = [[build_substitution_list]], - Synopsis = [[build a list of variable substitutions]], - Usage = [[local ds = require "lib/dtutils.string" - ds.build_substitution_list(image, sequence, variable_string, [username], [pic_folder], [home], [desktop]) - image - dt_lua_image_t - the image being processed - sequence - integer - the sequence number of the image - variable_string - string - the substitution variable string - [username] - string - optional - user name. Will be determined if not supplied - [pic_folder] - string - optional - pictures folder name. Will be determined if not supplied - [home] - string - optional - home directory. Will be determined if not supplied - [desktop] - string - optional - desktop directory. Will be determined if not supplied]], - Description = [[build_substitution_list populates variables with values from the arguments - and determined from the system and darktable.]], - Return_Value = [[]], - Limitations = [[If the value for a variable can not be determined, or if it is not supported, - then an empty string is used for the value.]], - Example = [[]], - See_Also = [[https://docs.darktable.org/usermanual/4.2/en/special-topics/variables/]], - Reference = [[]], - License = [[]], - Copyright = [[]], -} +-- find the $CATEGORYn requests and add them to the substitute list local function build_category_substitution_list(image, variable_string) - -- scan the variable string for CATEGORYn(tag name) entries and build the substitutions local old_log_level = log.log_level() - -- log.log_level(dtutils_string.log_level) - --log.log_level(log.debug) + log.log_level(dtutils_string.log_level) - for match in string.gmatch(variable_string, "%$%(.-%)?%)") do + for match in string.gmatch(variable_string, "%$%(.-%)?%)") do -- grab each complete variable log.msg(log.info, "match is " .. match) - local var = string.match(match, "%$%((.-%)?)%)") + + local var = string.match(match, "%$%((.-%)?)%)") -- strip of the leading $( and trailing ) log.msg(log.info, "var is " .. var) + if string.match(var, "CATEGORY%d") then - local element, tag = string.match(var, "CATEGORY(%d)%((.-)%)") - element = element + 1 + local element, tag = string.match(var, "CATEGORY(%d)%((.-)%)") -- get the element number and the tag to match + + element = element + 1 -- add one to element since lua arrays are 1 based log.msg(log.debug, "element is " .. element .. " and tag is " .. tag) + local tags = image:get_tags() log.msg(log.debug, "got " .. #tags .. " from image " .. image.filename) + for _, image_tag in ipairs(tags) do log.msg(log.debug, "checking tag " .. image_tag.name) + if string.match(image_tag.name, tag) then - parts = du.split(image_tag.name, "|") - substitutes[var] = parts[element] - log.msg(log.info, "set substitute for " .. var .. " to " .. parts[element]) - log.msg(log.info, "double check substitutes[" .. var .. "] is " .. substitutes[var]) + fields = du.split(image_tag.name, "|") + + if element <= #fields then + substitutes[var] = fields[element] + else + substitutes[var] = "" + log.msg(log.warn, "requested field for tag " .. tag .. " doesn't exist") + end + + log.msg(log.info, "set substitute for " .. var .. " to " .. fields[element]) + end end end end - -- scan the variable string looking for CATEGORYn - -- retrieve the tag and compute the replacement string - -- add the found string as a PLACEHOLDER - -- add the replacement to the corresponding spot in the replacement table log.log_level(old_log_level) end +-- convert image.exif_datetime_taken to system time + local function exiftime2systime(exiftime) local yr,mo,dy,h,m,s = string.match(exiftime, "(%d-):(%d-):(%d-) (%d-):(%d-):(%d+)") return(os.time{year=yr, month=mo, day=dy, hour=h, min=m, sec=s}) end -function dtutils_string.build_substition_list(image, sequence, variable_string, username, pic_folder, home, desktop) - -- build the argument substitution list from each image +-- build the argument substitution list from each image +function dtutils_string.build_substition_list(image, sequence, variable_string, username, pic_folder, home, desktop) local old_log_level = log.log_level() log.log_level(dtutils_string.log_level) + -- is time millisecond aware? Implemented in API 9.1.0 + local is_api_9_1 = true if dt.configuration.api_version_string < "9.1.0" then is_api_9_1 = false @@ -668,11 +680,10 @@ function dtutils_string.build_substition_list(image, sequence, variable_string, local user_name = username or USER local pictures_folder = pic_folder or PICTURES local home_folder = home or HOME - log.msg(log.info, "home is " .. tostring(home) .. " and HOME is " .. tostring(HOME) .. " and home_folder is " .. tostring(home_folder)) local desktop_folder = desktop or DESKTOP local labels = get_colorlabels(image) - log.msg(log.info, "image date time taken is " .. image.exif_datetime_taken) + local eyear, emon, eday, ehour, emin, esec, emsec if dt.preferences.read("darktable", "lighttable/ui/milliseconds", "bool") and is_api_9_1 then eyear, emon, eday, ehour, emin, esec, emsec = @@ -682,14 +693,16 @@ function dtutils_string.build_substition_list(image, sequence, variable_string, eyear, emon, eday, ehour, emin, esec = string.match(image.exif_datetime_taken, "(%d+):(%d+):(%d+) (%d+):(%d+):(%d+)$") end + + local version_multi = #image:get_group_members() > 1 and image.version or "" + local replacements = {image.film, -- ROLL.NAME image.path, -- FILE.FOLDER image.filename, -- FILE.NAME dtutils_string.get_filetype(image.filename),-- FILE.EXTENSION image.id, -- ID image.duplicate_index, -- VERSION - -- #image:get_group_members() > 1 and image.duplicate_index or "", -- VERSION.IF_MULTI - "", -- VERSION.IF_MULTI + version_multi, -- VERSION.IF_MULTI image.version_name, -- VERSION.NAME dt.configuration.version, -- DARKTABLE.VERSION "", -- DARKTABLE.NAME @@ -698,12 +711,12 @@ function dtutils_string.build_substition_list(image, sequence, variable_string, image.height, -- HEIGHT.SENSOR is_api_9_1 and image.p_width or "", -- WIDTH.RAW is_api_9_1 and image.p_height or "", -- HEIGHT.RAW - is_api_9_1 and image.final_width or "", -- WIDTH.CROP + is_api_9_1 and image.final_width or "", -- WIDTH.CROP is_api_9_1 and image.final_height or "", -- HEIGHT.CROP is_api_9_1 and image.final_width or "", -- WIDTH.EXPORT is_api_9_1 and image.final_height or "", -- HEIGHT.EXPORT - "", -- WIDTH.MAX - "", -- HEIGHT.MAX + "", -- WIDTH.MAX -- from export module + "", -- HEIGHT.MAX -- from export module string.format("%4d", datetime.year), -- YEAR string.sub(datetime.year, 3), -- YEAR.SHORT string.format("%02d", datetime.month), -- MONTH @@ -717,8 +730,8 @@ function dtutils_string.build_substition_list(image, sequence, variable_string, eyear, -- EXIF.YEAR string.sub(eyear, 3), -- EXIF.YEAR.SHORT emon, -- EXIF.MONTH - os.date("%B", exiftime2systime(image.exif_datetime_taken)), -- EXIF.MONTH.LONG - os.date("%b", exiftime2systime(image.exif_datetime_taken)), -- EXIF.MONTH.SHORT + os.date("%B", exiftime2systime(image.exif_datetime_taken)), -- EXIF.MONTH.LONG + os.date("%b", exiftime2systime(image.exif_datetime_taken)), -- EXIF.MONTH.SHORT eday, -- EXIF.DAY ehour, -- EXIF.HOUR emin, -- EXIF.MINUTE @@ -752,7 +765,6 @@ function dtutils_string.build_substition_list(image, sequence, variable_string, image.publisher, -- PUBLISHER image.rights, -- RIGHTS "", -- TAGS - wont be implemented - "", -- CATEGORY "", -- SIDECAR.TXT - wont be implemented pictures_folder, -- FOLDER.PICTURES home_folder, -- FOLDER.HOME @@ -763,36 +775,50 @@ function dtutils_string.build_substition_list(image, sequence, variable_string, "" -- JOBCODE - wont be implemented } + -- populate the substitution list + for i = 1, #PLACEHOLDERS, 1 do substitutes[PLACEHOLDERS[i]] = replacements[i] log.msg(log.info, "setting " .. PLACEHOLDERS[i] .. " to " .. tostring(replacements[i])) end + -- do category substitutions separately + build_category_substitution_list(image, variable_string) log.log_level(old_log_level) end +-- handle different versions of names + local function check_legacy_vars(var_name) local var = var_name + if string.match(var, "_") then var = string.gsub(var, "_", ".") end + if string.match(var, "^HOME$") then var = "FOLDER.HOME" end if string.match(var, "^PICTURES.FOLDER$") then var = "FOLDER.PICTURES" end if string.match(var, "^DESKTOP$") then var = "FOLDER.DESKTOP" end + return var end +-- get the substitution and do any string manipulations requested + local function treat(var_string) local old_log_level = log.log_level() - --log.log_level(dtutils_string.log_level) - --log.log_level(log.info) + log.log_level(dtutils_string.log_level) + local ret_val = "" + -- remove the var from the string local var = string.match(var_string, "[%a%._]+") + var = check_legacy_vars(var) log.msg(log.info, "var_string is " .. tostring(var_string) .. " and var is " .. tostring(var)) + if string.match(var_string, "CATEGORY%d") then log.msg(log.info, "substituting for " .. var_string) ret_val = substitutes[var_string] @@ -800,12 +826,11 @@ local function treat(var_string) else ret_val = substitutes[var] end + local valid_var = false if ret_val then valid_var = true - --elseif string.match(var, "CATEGORY%d") then - --valid_var = true end if not valid_var then @@ -813,79 +838,109 @@ local function treat(var_string) log.log_level(old_log_level) return "" end - if string.match(var, "CATEGORY%d") then - ret_val = process_category(image, var, var_string) - else - local args = string.gsub(var_string, var, "") - log.msg(log.info, "args is " .. tostring(args)) - if string.len(args) > 0 then - if string.match(args, '^%^%^') then - ret_val = string.upper(ret_val) - elseif string.match(args, "^%^") then - ret_val = string.gsub(ret_val, "^%a", string.upper, 1) - elseif string.match(args, "^,,") then - ret_val = string.lower(ret_val) - elseif string.match(args, "^,") then - ret_val = string.gsub(ret_val, "^%a", string.lower, 1) - elseif string.match(args, "^:%-?%d+:%-?%d+") then - local soffset, slen = string.match(args, ":(%-?%d+):(%-?%d+)") - log.msg(log.info, "soffset is " .. soffset .. " and slen is " .. slen) - if tonumber(soffset) >= 0 then - soffset = soffset + 1 - end - log.msg(log.info, "soffset is " .. soffset .. " and slen is " .. slen) - if tonumber(soffset) < 0 and tonumber(slen) < 0 then - local temp = soffset - soffset = slen - slen = temp - end - log.msg(log.info, "soffset is " .. soffset .. " and slen is " .. slen) - ret_val = string.sub(ret_val, soffset, slen) - log.msg(log.info, "ret_val is " .. ret_val) - elseif string.match(args, "^:%-?%d+") then - local soffset= string.match(args, ":(%-?%d+)") - if tonumber(soffset) >= 0 then - soffset = soffset + 1 - end - ret_val = string.sub(ret_val, soffset, -1) - elseif string.match(args, "^-%$%(.-%)") then - local replacement = string.match(args, "-%$%(([%a%._]+)%)") - replacement = check_legacy_vars(replacement) - if string.len(ret_val) == 0 then - ret_val = substitutes[replacement] - end - elseif string.match(args, "^-.+$") then - local replacement = string.match(args, "-(.+)$") - if string.len(ret_val) == 0 then - ret_val = replacement - end - elseif string.match(args, "^+.+") then - local replacement = string.match(args, "+(.+)") - if string.len(ret_val) > 0 then - ret_val = replacement - end - elseif string.match(args, "^#.+") then - local pattern = string.match(args, "#(.+)") - log.msg(log.info, "pattern to remove is " .. tostring(pattern)) - ret_val = string.gsub(ret_val, "^" .. dtutils_string.sanitize_lua(pattern), "") - elseif string.match(args, "^%%.+") then - local pattern = string.match(args, "%%(.+)") - ret_val = string.gsub(ret_val, pattern .. "$", "") - elseif string.match(args, "^//.-/.+") then - local pattern, replacement = string.match(args, "//(.-)/(.+)") - ret_val = string.gsub(ret_val, pattern, replacement) - elseif string.match(args, "^/#.+/.+") then - local pattern, replacement = string.match(args, "/#(.+)/(.+)") - ret_val = string.gsub(ret_val, "^" .. pattern, replacement, 1) - elseif string.match(args, "^/%%.-/.+") then - local pattern, replacement = string.match(args, "/%%(.-)/(.+)") - ret_val = string.gsub(ret_val, pattern .. "$", replacement) - elseif string.match(args, "^/.-/.+") then - log.msg(log.info, "took replacement branch") - local pattern, replacement = string.match(args, "/(.-)/(.+)") - ret_val = string.gsub(ret_val, pattern, replacement, 1) + + -- string modifications + + local args = string.gsub(var_string, var, "") + log.msg(log.info, "args is " .. tostring(args)) + + if string.len(args) > 0 then + + if string.match(args, '^%^%^') then + ret_val = string.upper(ret_val) + + elseif string.match(args, "^%^") then + ret_val = string.gsub(ret_val, "^%a", string.upper, 1) + + elseif string.match(args, "^,,") then + ret_val = string.lower(ret_val) + + elseif string.match(args, "^,") then + ret_val = string.gsub(ret_val, "^%a", string.lower, 1) + + elseif string.match(args, "^:%-?%d+:%-?%d+") then + + local soffset, slen = string.match(args, ":(%-?%d+):(%-?%d+)") + log.msg(log.info, "soffset is " .. soffset .. " and slen is " .. slen) + + if tonumber(soffset) >= 0 then + soffset = soffset + 1 end + log.msg(log.info, "soffset is " .. soffset .. " and slen is " .. slen) + + if tonumber(soffset) < 0 and tonumber(slen) < 0 then + local temp = soffset + soffset = slen + slen = temp + end + log.msg(log.info, "soffset is " .. soffset .. " and slen is " .. slen) + + ret_val = string.sub(ret_val, soffset, slen) + log.msg(log.info, "ret_val is " .. ret_val) + + elseif string.match(args, "^:%-?%d+") then + + local soffset= string.match(args, ":(%-?%d+)") + if tonumber(soffset) >= 0 then + soffset = soffset + 1 + end + ret_val = string.sub(ret_val, soffset, -1) + + elseif string.match(args, "^-%$%(.-%)") then + + local replacement = string.match(args, "-%$%(([%a%._]+)%)") + replacement = check_legacy_vars(replacement) + if string.len(ret_val) == 0 then + ret_val = substitutes[replacement] + end + + elseif string.match(args, "^-.+$") then + + local replacement = string.match(args, "-(.+)$") + if string.len(ret_val) == 0 then + ret_val = replacement + end + + elseif string.match(args, "^+.+") then + + local replacement = string.match(args, "+(.+)") + if string.len(ret_val) > 0 then + ret_val = replacement + end + + elseif string.match(args, "^#.+") then + + local pattern = string.match(args, "#(.+)") + log.msg(log.info, "pattern to remove is " .. tostring(pattern)) + ret_val = string.gsub(ret_val, "^" .. dtutils_string.sanitize_lua(pattern), "") + + elseif string.match(args, "^%%.+") then + + local pattern = string.match(args, "%%(.+)") + ret_val = string.gsub(ret_val, pattern .. "$", "") + + elseif string.match(args, "^//.-/.+") then + + local pattern, replacement = string.match(args, "//(.-)/(.+)") + ret_val = string.gsub(ret_val, pattern, replacement) + + elseif string.match(args, "^/#.+/.+") then + + local pattern, replacement = string.match(args, "/#(.+)/(.+)") + ret_val = string.gsub(ret_val, "^" .. pattern, replacement, 1) + + elseif string.match(args, "^/%%.-/.+") then + + local pattern, replacement = string.match(args, "/%%(.-)/(.+)") + ret_val = string.gsub(ret_val, pattern .. "$", replacement) + + elseif string.match(args, "^/.-/.+") then + + log.msg(log.info, "took replacement branch") + local pattern, replacement = string.match(args, "/(.-)/(.+)") + ret_val = string.gsub(ret_val, pattern, replacement, 1) end + end log.log_level(old_log_level) return ret_val @@ -911,15 +966,22 @@ dtutils_string.libdoc.functions["substitute_list"] = { function dtutils_string.substitute_list(str) local old_log_level = log.log_level() log.log_level(dtutils_string.log_level) + -- replace the substitution variables in a string for match in string.gmatch(str, "%$%(.-%)?%)") do + local var = string.match(match, "%$%((.-%)?)%)") + local treated_var = treat(var) log.msg(log.info, "var is " .. var .. " and treated var is " .. tostring(treated_var)) + str = string.gsub(str, "%$%(".. dtutils_string.sanitize_lua(var) .."%)", tostring(treated_var)) log.msg(log.info, "str after replacement is " .. str) + end + log.log_level(old_log_level) + return str end @@ -988,4 +1050,5 @@ function dtutils_string.substitute(image, sequence, variable_string, username, p end + return dtutils_string From 97e33672ea79d29073aef37364c6c523bd6d5bad Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sun, 19 May 2024 23:04:01 -0400 Subject: [PATCH 292/445] lib/dtutils/string - fixed default formatting of sequence --- lib/dtutils/string.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/dtutils/string.lua b/lib/dtutils/string.lua index dad0d558..c172ff66 100644 --- a/lib/dtutils/string.lua +++ b/lib/dtutils/string.lua @@ -706,7 +706,7 @@ function dtutils_string.build_substition_list(image, sequence, variable_string, image.version_name, -- VERSION.NAME dt.configuration.version, -- DARKTABLE.VERSION "", -- DARKTABLE.NAME - sequence, -- SEQUENCE + string.format("%04d", sequence), -- SEQUENCE image.width, -- WIDTH.SENSOR image.height, -- HEIGHT.SENSOR is_api_9_1 and image.p_width or "", -- WIDTH.RAW From 3ed4219e6c2f92cdc01eabb9d88227b972c83948 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Mon, 20 May 2024 00:56:01 -0400 Subject: [PATCH 293/445] lib/dtutils/string - added [] to sanitize_lua(). added 4.8 syntax to CATEGORY added 4.8 SEQUENCE changes (syntax, start, width) --- lib/dtutils/string.lua | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/lib/dtutils/string.lua b/lib/dtutils/string.lua index c172ff66..2e4b7d86 100644 --- a/lib/dtutils/string.lua +++ b/lib/dtutils/string.lua @@ -335,6 +335,8 @@ function dtutils_string.sanitize_lua(str) str = string.gsub(str, "%-", "%%-") str = string.gsub(str, "%(", "%%(") str = string.gsub(str, "%)", "%%)") + str = string.gsub(str, "%[", "%%[") + str = string.gsub(str, "%]", "%%]") str = string.gsub(str, "+", "%%+") log.log_level(old_log_level) return str @@ -623,8 +625,15 @@ local function build_category_substitution_list(image, variable_string) local var = string.match(match, "%$%((.-%)?)%)") -- strip of the leading $( and trailing ) log.msg(log.info, "var is " .. var) - if string.match(var, "CATEGORY%d") then - local element, tag = string.match(var, "CATEGORY(%d)%((.-)%)") -- get the element number and the tag to match + if string.match(var, "CATEGORY%d") or string.match(var, "CATEGORY%[") then + local element + local tag + + if string.match(var, "CATEGORY%d") then + element, tag = string.match(var, "CATEGORY(%d)%((.-)%)") -- get the element number and the tag to match + else + element, tag = string.match(var, "%[(%d),(.-)%]") -- new syntax + end element = element + 1 -- add one to element since lua arrays are 1 based log.msg(log.debug, "element is " .. element .. " and tag is " .. tag) @@ -696,7 +705,7 @@ function dtutils_string.build_substition_list(image, sequence, variable_string, local version_multi = #image:get_group_members() > 1 and image.version or "" - local replacements = {image.film, -- ROLL.NAME + local replacements = {image.film.path, -- ROLL.NAME image.path, -- FILE.FOLDER image.filename, -- FILE.NAME dtutils_string.get_filetype(image.filename),-- FILE.EXTENSION @@ -819,10 +828,18 @@ local function treat(var_string) var = check_legacy_vars(var) log.msg(log.info, "var_string is " .. tostring(var_string) .. " and var is " .. tostring(var)) - if string.match(var_string, "CATEGORY%d") then + if string.match(var_string, "CATEGORY%d") or string.match(var_string, "CATEGORY%[") then log.msg(log.info, "substituting for " .. var_string) ret_val = substitutes[var_string] log.msg(log.info, "ret_val is " .. ret_val) + + elseif string.match(var_string, "SEQUENCE%[") then + local start, width = string.match(var_string, "(%d+),(%d)") + local seq_val = tonumber(substitutes[var]) + local pat = "%0" .. width .. "d" + substitutes[var_string] = string.format(pat, start + (seq_val - 1)) + ret_val = substitutes[var_string] + else ret_val = substitutes[var] end @@ -943,6 +960,7 @@ local function treat(var_string) end log.log_level(old_log_level) + dt.print_log("returning ret_val of " .. ret_val) return ret_val end @@ -965,7 +983,8 @@ dtutils_string.libdoc.functions["substitute_list"] = { function dtutils_string.substitute_list(str) local old_log_level = log.log_level() - log.log_level(dtutils_string.log_level) + -- log.log_level(dtutils_string.log_level) + log.log_level(log.info) -- replace the substitution variables in a string for match in string.gmatch(str, "%$%(.-%)?%)") do @@ -975,6 +994,8 @@ function dtutils_string.substitute_list(str) local treated_var = treat(var) log.msg(log.info, "var is " .. var .. " and treated var is " .. tostring(treated_var)) + dt.print_log("str is " .. str) + str = string.gsub(str, "%$%(".. dtutils_string.sanitize_lua(var) .."%)", tostring(treated_var)) log.msg(log.info, "str after replacement is " .. str) From 232baab86bd559684d97aab3c154da6c240d5deb Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Mon, 20 May 2024 10:07:13 -0400 Subject: [PATCH 294/445] lib/dtutils/string - removed debugging statements --- lib/dtutils/string.lua | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/lib/dtutils/string.lua b/lib/dtutils/string.lua index 2e4b7d86..7690d59c 100644 --- a/lib/dtutils/string.lua +++ b/lib/dtutils/string.lua @@ -960,7 +960,6 @@ local function treat(var_string) end log.log_level(old_log_level) - dt.print_log("returning ret_val of " .. ret_val) return ret_val end @@ -983,8 +982,7 @@ dtutils_string.libdoc.functions["substitute_list"] = { function dtutils_string.substitute_list(str) local old_log_level = log.log_level() - -- log.log_level(dtutils_string.log_level) - log.log_level(log.info) + log.log_level(dtutils_string.log_level) -- replace the substitution variables in a string for match in string.gmatch(str, "%$%(.-%)?%)") do @@ -994,8 +992,6 @@ function dtutils_string.substitute_list(str) local treated_var = treat(var) log.msg(log.info, "var is " .. var .. " and treated var is " .. tostring(treated_var)) - dt.print_log("str is " .. str) - str = string.gsub(str, "%$%(".. dtutils_string.sanitize_lua(var) .."%)", tostring(treated_var)) log.msg(log.info, "str after replacement is " .. str) From 417c165d16dc7d65ccfd2be5906ab05e0bb12c85 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Mon, 20 May 2024 18:18:46 -0400 Subject: [PATCH 295/445] lib/dtutils/string - updated documentation --- lib/dtutils/string.lua | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/dtutils/string.lua b/lib/dtutils/string.lua index 7690d59c..f3236fc8 100644 --- a/lib/dtutils/string.lua +++ b/lib/dtutils/string.lua @@ -484,7 +484,7 @@ dtutils_string.libdoc.functions["build_substitution_list"] = { Usage = [[local ds = require "lib/dtutils.string" ds.build_substitution_list(image, sequence, variable_string, [username], [pic_folder], [home], [desktop]) image - dt_lua_image_t - the image being processed - sequence - integer - the sequence number of the image + sequence - integer - the sequence number of the image being processed (exported) variable_string - string - the substitution variable string [username] - string - optional - user name. Will be determined if not supplied [pic_folder] - string - optional - pictures folder name. Will be determined if not supplied @@ -496,7 +496,7 @@ dtutils_string.libdoc.functions["build_substitution_list"] = { Limitations = [[If the value for a variable can not be determined, or if it is not supported, then an empty string is used for the value.]], Example = [[]], - See_Also = [[https://docs.darktable.org/usermanual/4.2/en/special-topics/variables/]], + See_Also = [[https://docs.darktable.org/usermanual/4.6/en/special-topics/variables/]], Reference = [[]], License = [[]], Copyright = [[]], @@ -613,7 +613,7 @@ local function get_colorlabels(image) return labels end --- find the $CATEGORYn requests and add them to the substitute list +-- find the $CATEGORYn and $CATEGORY[n,m] requests and add them to the substitute list local function build_category_substitution_list(image, variable_string) local old_log_level = log.log_level() @@ -974,7 +974,7 @@ dtutils_string.libdoc.functions["substitute_list"] = { Return_Value = [[result - string - the input string with values substituted for the variables]], Limitations = [[]], Example = [[]], - See_Also = [[]], + See_Also = [[https://docs.darktable.org/usermanual/4.6/en/special-topics/variables/]], Reference = [[]], License = [[]], Copyright = [[]], @@ -1033,7 +1033,7 @@ dtutils_string.libdoc.functions["substitute"] = { Usage = [[local ds = require "lib/dtutils.string" ds.substitute(image, sequence, variable_string, [username], [pic_folder], [home], [desktop]) image - dt_lua_image_t - the image being processed - sequence - integer - the sequence number of the image + sequence - integer - the number of the image being processed (exported) variable_string - string - the substitution variable string [username] - string - optional - user name. Will be determined if not supplied [pic_folder] - string - optional - pictures folder name. Will be determined if not supplied @@ -1045,7 +1045,7 @@ dtutils_string.libdoc.functions["substitute"] = { Return_Value = [[result - string - the input string with values substituted for the variables]], Limitations = [[]], Example = [[]], - See_Also = [[]], + See_Also = [[https://docs.darktable.org/usermanual/4.6/en/special-topics/variables/]], Reference = [[]], License = [[]], Copyright = [[]], From dcbe575e9c50665209c429842edbe309a8191192 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Mon, 20 May 2024 22:13:29 -0400 Subject: [PATCH 296/445] lib/dtutils/string - updated embedded documentation --- lib/dtutils/string.lua | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/dtutils/string.lua b/lib/dtutils/string.lua index f3236fc8..342a5763 100644 --- a/lib/dtutils/string.lua +++ b/lib/dtutils/string.lua @@ -478,11 +478,11 @@ function dtutils_string.get_filetype(str) return parts["filetype"] end -dtutils_string.libdoc.functions["build_substitution_list"] = { - Name = [[build_substitution_list]], +dtutils_string.libdoc.functions["build_substitute_list"] = { + Name = [[build_substitute_list]], Synopsis = [[build a list of variable substitutions]], Usage = [[local ds = require "lib/dtutils.string" - ds.build_substitution_list(image, sequence, variable_string, [username], [pic_folder], [home], [desktop]) + ds.build_substitute_list(image, sequence, variable_string, [username], [pic_folder], [home], [desktop]) image - dt_lua_image_t - the image being processed sequence - integer - the sequence number of the image being processed (exported) variable_string - string - the substitution variable string @@ -490,7 +490,7 @@ dtutils_string.libdoc.functions["build_substitution_list"] = { [pic_folder] - string - optional - pictures folder name. Will be determined if not supplied [home] - string - optional - home directory. Will be determined if not supplied [desktop] - string - optional - desktop directory. Will be determined if not supplied]], - Description = [[build_substitution_list populates variables with values from the arguments + Description = [[build_substitute_list populates variables with values from the arguments and determined from the system and darktable.]], Return_Value = [[]], Limitations = [[If the value for a variable can not be determined, or if it is not supported, @@ -1057,7 +1057,7 @@ function dtutils_string.substitute(image, sequence, variable_string, username, p dtutils_string.clear_substitute_list() - dtutils_string.build_substition_list(image, sequence, variable_string, username, pic_folder, home, desktop) + dtutils_string.build_substitute_list(image, sequence, variable_string, username, pic_folder, home, desktop) local str = dtutils_string.substitute_list(variable_string) From fecbb39347eb315d61f8532ecc3b741a44d58935 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Mon, 20 May 2024 23:43:47 -0400 Subject: [PATCH 297/445] lib/dtutils/string - more embedded doc updates --- lib/dtutils/string.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/dtutils/string.lua b/lib/dtutils/string.lua index 342a5763..926c6673 100644 --- a/lib/dtutils/string.lua +++ b/lib/dtutils/string.lua @@ -1029,7 +1029,7 @@ end dtutils_string.libdoc.functions["substitute"] = { Name = [[substitute]], - Synopsis = [[Check if a string has been sanitized]], + Synopsis = [[Perform all the variable substitution steps with one function call]], Usage = [[local ds = require "lib/dtutils.string" ds.substitute(image, sequence, variable_string, [username], [pic_folder], [home], [desktop]) image - dt_lua_image_t - the image being processed @@ -1040,7 +1040,7 @@ dtutils_string.libdoc.functions["substitute"] = { [home] - string - optional - home directory. Will be determined if not supplied [desktop] - string - optional - desktop directory. Will be determined if not supplied]], Description = [[substitute initializes the substitution list by calling clear_substitute_list(), - then builds the substitutions by calling build_substitution_list() and finally does the + then builds the substitutions by calling build_substitute_list() and finally does the substitution by calling substitute_list(), then returns the result string.]], Return_Value = [[result - string - the input string with values substituted for the variables]], Limitations = [[]], From a3b295112f1ac8afe9f2454ec865cac81a8dcd07 Mon Sep 17 00:00:00 2001 From: Krzysztof Kotowicz Date: Mon, 27 May 2024 13:03:00 +0200 Subject: [PATCH 298/445] Update OpenInExplorer.lua In OpenInExplorer, use AppleScript instead of `open -R` for OSX. That way multiple files can be selected. --- contrib/OpenInExplorer.lua | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/contrib/OpenInExplorer.lua b/contrib/OpenInExplorer.lua index dba04d02..64d478ac 100644 --- a/contrib/OpenInExplorer.lua +++ b/contrib/OpenInExplorer.lua @@ -118,9 +118,26 @@ open_dir.linux = [[busctl --user call org.freedesktop.FileManager1 /org/freedesk local open_files = {} open_files.windows = "explorer.exe /select, %s" -open_files.macos = "open -Rn %s" +open_files.macos = "osascript -e 'tell application \"Finder\" to (reveal {%s}) activate'" open_files.linux = [[busctl --user call org.freedesktop.FileManager1 /org/freedesktop/FileManager1 org.freedesktop.FileManager1 ShowItems ass %d %s ""]] +reveal_file_osx_cmd = "\"%s\" as POSIX file" + +--Call the osx Finder with each selected image selected. +--For images in multiple folders, Finder will open a separate window for each +local function call_list_of_files_osx(selected_images) + local cmds = {} + for _, image in pairs(selected_images) do + current_image = image.path..PS..image.filename + -- AppleScript needs double quoted strings, and the whole command is wrapped in single quotes. + table.insert(cmds, string.format(reveal_file_osx_cmd, string.gsub(string.gsub(current_image, "'", "'\\''"), "\"", "\\\"") )) + end + reveal_cmd = table.concat(cmds, ",") + run_cmd = string.format(open_files.macos, reveal_cmd) + dt.print_log("OSX run_cmd = "..run_cmd) + dsys.external_command(run_cmd) +end + --Call the file mangager for each selected image on Linux. --There is one call to busctl containing a list of all the image file names. local function call_list_of_files(selected_images) @@ -188,6 +205,8 @@ local function open_in_fmanager() else if act_os == "linux" then call_list_of_files(images) + elseif act_os == "macos" then + call_list_of_files_osx(images) else call_file_by_file(images) end From f1d8ad7fce66aa04a539ef6eab4e1daae531ea4a Mon Sep 17 00:00:00 2001 From: Krzysztof Kotowicz Date: Mon, 27 May 2024 18:26:35 +0200 Subject: [PATCH 299/445] Fix quoting. --- contrib/OpenInExplorer.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/OpenInExplorer.lua b/contrib/OpenInExplorer.lua index 64d478ac..1633a1a5 100644 --- a/contrib/OpenInExplorer.lua +++ b/contrib/OpenInExplorer.lua @@ -130,7 +130,7 @@ local function call_list_of_files_osx(selected_images) for _, image in pairs(selected_images) do current_image = image.path..PS..image.filename -- AppleScript needs double quoted strings, and the whole command is wrapped in single quotes. - table.insert(cmds, string.format(reveal_file_osx_cmd, string.gsub(string.gsub(current_image, "'", "'\\''"), "\"", "\\\"") )) + table.insert(cmds, string.format(reveal_file_osx_cmd, string.gsub(string.gsub(current_image, "\"", "\\\""), "'", "'\"'\"'"))) end reveal_cmd = table.concat(cmds, ",") run_cmd = string.format(open_files.macos, reveal_cmd) From 9088bc91441ae4c1a65bd7a4b8a76793fac95465 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Mon, 3 Jun 2024 14:48:44 -0400 Subject: [PATCH 300/445] tools/script_manager - make the constants to ensure they stay that way --- tools/script_manager.lua | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/tools/script_manager.lua b/tools/script_manager.lua index daaa824e..ed93b963 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -75,27 +75,27 @@ du.check_min_api_version("9.3.0", "script_manager") -- - - - - - - - - - - - - - - - - - - - - - - - -- path separator -local PS = dt.configuration.running_os == "windows" and "\\" or "/" +local PS = dt.configuration.running_os == "windows" and "\\" or "/" -- command separator -local CS = dt.configuration.running_os == "windows" and "&" or ";" +local CS = dt.configuration.running_os == "windows" and "&" or ";" -local MODULE = "script_manager" +local MODULE = "script_manager" -local MIN_BUTTONS_PER_PAGE = 5 -local MAX_BUTTONS_PER_PAGE = 20 -local DEFAULT_BUTTONS_PER_PAGE = 10 +local MIN_BUTTONS_PER_PAGE = 5 +local MAX_BUTTONS_PER_PAGE = 20 +local DEFAULT_BUTTONS_PER_PAGE = 10 -local DEFAULT_LOG_LEVEL = log.error +local DEFAULT_LOG_LEVEL = log.error -local LUA_DIR = dt.configuration.config_dir .. PS .. "lua" -local LUA_SCRIPT_REPO = "https://github.com/darktable-org/lua-scripts.git" +local LUA_DIR = dt.configuration.config_dir .. PS .. "lua" +local LUA_SCRIPT_REPO = "https://github.com/darktable-org/lua-scripts.git" -local LUA_API_VER = "API-" .. dt.configuration.api_version_string +local LUA_API_VER = "API-" .. dt.configuration.api_version_string -- local POWER_ICON = dt.configuration.config_dir .. "/lua/data/data/icons/power.png" -local POWER_ICON = dt.configuration.config_dir .. "/lua/data/icons/path20.png" -local BLANK_ICON = dt.configuration.config_dir .. "/lua/data/icons/blank20.png" +local POWER_ICON = dt.configuration.config_dir .. "/lua/data/icons/path20.png" +local BLANK_ICON = dt.configuration.config_dir .. "/lua/data/icons/blank20.png" -- - - - - - - - - - - - - - - - - - - - - - - - -- P R E F E R E N C E S From 81b0f1fb484a9c293663191b99393eb9f322fc1c Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Mon, 3 Jun 2024 18:08:30 -0400 Subject: [PATCH 301/445] contrib/dbmaint - remove database records for missing film rolls and images. --- contrib/dbmaint.lua | 314 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 314 insertions(+) create mode 100644 contrib/dbmaint.lua diff --git a/contrib/dbmaint.lua b/contrib/dbmaint.lua new file mode 100644 index 00000000..7f2f21e0 --- /dev/null +++ b/contrib/dbmaint.lua @@ -0,0 +1,314 @@ +--[[ + + dbmaint.lua - perform database maintenance + + Copyright (C) 2024 Bill Ferguson . + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +]] +--[[ + dbmaint - perform database maintenance + + Perform database maintenance to clean up missing images and filmstrips. + + ADDITIONAL SOFTWARE NEEDED FOR THIS SCRIPT + None + + USAGE + * start dbmaint from script_manager + * scan for missing film rolls or missing images + * look at the results and choose to delete or not + + BUGS, COMMENTS, SUGGESTIONS + Bill Ferguson + + CHANGES +]] + +local dt = require "darktable" +local du = require "lib/dtutils" +local df = require "lib/dtutils.file" +local log = require "lib/dtutils.log" + + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- C O N S T A N T S +-- - - - - - - - - - - - - - - - - - - - - - - - + +local MODULE = "dbmaint" +local DEFAULT_LOG_LEVEL = log.error +local PS = dt.configuration.running_os == "windows" and "\\" or "/" + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- A P I C H E C K +-- - - - - - - - - - - - - - - - - - - - - - - - + +du.check_min_api_version("7.0.0", MODULE) -- choose the minimum version that contains the features you need + + +-- - - - - - - - - - - - - - - - - - - - - - - - - - +-- I 1 8 N +-- - - - - - - - - - - - - - - - - - - - - - - - - - + +local gettext = dt.gettext.gettext + +dt.gettext.bindtextdomain(MODULE , dt.configuration.config_dir .. "/lua/locale/") + +local function _(msgid) + return gettext(MODULE, msgid) +end + + +-- - - - - - - - - - - - - - - - - - - - - - - - - - +-- S C R I P T M A N A G E R I N T E G R A T I O N +-- - - - - - - - - - - - - - - - - - - - - - - - - - + +local script_data = {} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them + +script_data.metadata = { + name = "dbmaint", + purpose = _("perform database maintenance"), + author = "Bill Ferguson ", + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/dbmaint/" +} + + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- L O G L E V E L +-- - - - - - - - - - - - - - - - - - - - - - - - + +log.log_level(DEFAULT_LOG_LEVEL) + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- N A M E S P A C E +-- - - - - - - - - - - - - - - - - - - - - - - - + +local dbmaint = {} + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- G L O B A L V A R I A B L E S +-- - - - - - - - - - - - - - - - - - - - - - - - + +dbmaint.main_widget = nil + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- A L I A S E S +-- - - - - - - - - - - - - - - - - - - - - - - - + +local namespace = dbmaint + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- F U N C T I O N S +-- - - - - - - - - - - - - - - - - - - - - - - - + +local function scan_film_rolls() + local missing_films = {} + + for _, filmroll in ipairs(dt.films) do + if not df.check_if_file_exists(filmroll.path) then + table.insert(missing_films, filmroll) + end + end + + return missing_films +end + +local function scan_images(film) + local missing_images = {} + + if film then + for i = 1, #film do + local image = film[i] + log.log_msg(log.debug, "checking " .. image.filename) + if not df.check_if_file_exists(image.path .. PS .. image.filename) then + log.log_msg(log.info, image.filename .. " not found") + table.insert(missing_images, image) + end + end + end + + return missing_images +end + +local function remove_missing_film_rolls(list) + for _, filmroll in ipairs(list) do + filmroll:delete(true) + end +end + +-- force the lighttable to reload + +local function refresh_lighttable(film) + local rules = dt.gui.libs.collect.filter() + dt.gui.libs.collect.filter(rules) +end + +local function remove_missing_images(list) + local film = list[1].film + for _, image in ipairs(list) do + image:delete() + end + refresh_lighttable(film) +end + +local function install_module() + if not namespace.module_installed then + dt.register_lib( + MODULE, -- Module name + _("DB maintenance"), -- Visible name + true, -- expandable + true, -- resetable + {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_LEFT_CENTER", 0}}, -- containers + namespace.main_widget, + nil,-- view_enter + nil -- view_leave + ) + namespace.module_installed = true + end +end + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- U S E R I N T E R F A C E +-- - - - - - - - - - - - - - - - - - - - - - - - + +dbmaint.list_widget = dt.new_widget("text_view"){ + editable = false, + reset_callback = function(this) + this.text = "" + end +} + +dbmaint.chooser = dt.new_widget("combobox"){ + label = "scan for", + selected = 1, + "film rolls", "images", + reset_callback = function(this) + this.selected = 1 + end +} + +dbmaint.scan_button = dt.new_widget("button"){ + label = "scan", + tooltip = "click to scan for missing film rolls/files", + clicked_callback = function(this) + local found = nil + local found_text = "" + if dbmaint.chooser.value == "film rolls" then + found = scan_film_rolls() + if #found > 0 then + for _, film in ipairs(found) do + local dir_name = du.split(film.path, PS) + found_text = found_text .. dir_name[#dir_name] .. "\n" + end + end + else + log.log_msg(log.debug, "checking path " .. dt.collection[1].path .. " for missing files") + found = scan_images(dt.collection[1].film) + if #found > 0 then + for _, image in ipairs(found) do + found_text = found_text .. image.filename .. "\n" + end + end + end + if #found > 0 then + dbmaint.list_widget.text = found_text + dbmaint.found = found + dbmaint.remove_button.sensitive = true + end + end, + reset_callback = function(this) + dbmaint.found = nil + end +} + +dbmaint.remove_button = dt.new_widget("button"){ + label = "remove", + tooltip = "remove missing film rolls/images", + sensitive = false, + clicked_callback = function(this) + if dbmaint.chooser.value == "film rolls" then + remove_missing_film_rolls(dbmaint.found) + else + remove_missing_images(dbmaint.found) + end + dbmaint.found = nil + dbmaint.list_widget.text = "" + this.sensitive = false + end, + reset_callback = function(this) + this.sensitive = false + end +} + +dbmaint.main_widget = dt.new_widget("box"){ + orientation = "vertical", + dt.new_widget("section_label"){label = "missing items"}, + dbmaint.list_widget, + dt.new_widget("label"){label = ""}, + dbmaint.chooser, + dt.new_widget("label"){label = ""}, + dbmaint.scan_button, + dbmaint.remove_button +} + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- D A R K T A B L E I N T E G R A T I O N +-- - - - - - - - - - - - - - - - - - - - - - - - + +local function destroy() + dt.gui.libs[MODULE].visible = false + + if namespace.event_registered then + dt.destroy_event(MODULE, "view-changed") + end + + return +end + +local function restart() + dt.gui.libs[MODULE].visible = true + + return +end + +script_data.destroy = destroy +script_data.restart = restart +script_data.destroy_method = "hide" +script_data.show = restart + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- E V E N T S +-- - - - - - - - - - - - - - - - - - - - - - - - + +if dt.gui.current_view().id == "lighttable" then + install_module() +else + if not namespace.event_registered then + dt.register_event(MODULE, "view-changed", + function(event, old_view, new_view) + if new_view.name == "lighttable" and old_view.name == "darkroom" then + install_module() + end + end + ) + namespace.event_registered = true + end +end + +return script_data \ No newline at end of file From 2f330ea9cc6afe8795bd290697637d4c68f8662a Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Tue, 4 Jun 2024 23:16:19 -0400 Subject: [PATCH 302/445] lib/dtutils/system - added wrapper functions io_popen and os_execute to wrap io.popen and os.execute system calls respectively. These wrapper functions provide the necessary quoting on windows to get handle strings with spaces and special characters. --- lib/dtutils/system.lua | 51 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/lib/dtutils/system.lua b/lib/dtutils/system.lua index f41f821c..8f794f45 100644 --- a/lib/dtutils/system.lua +++ b/lib/dtutils/system.lua @@ -129,4 +129,55 @@ function dtutils_system.launch_default_app(path) end +dtutils_system.libdoc.functions["os_execute"] = { + Name = [[os_execute]], + Synopsis = [[wrapper around the lua os.execute function]], + Usage = [[local dsys = require "lib/dtutils.file" + + result = dsys.os_execute(cmd) + cmd - string - a command to execute on the operating system]], + Description = [[os_execute wraps the lua os.execute system call to provide + correct sanitization of windows commands]], + Return_Value = [[see the lua os.execute documentation]], + Limitations = [[]], + Example = [[]], + See_Also = [[]], + Reference = [[]], + License = [[]], + Copyright = [[]], +} + +function dtutils_system.os_execute(cmd) + if _scripts_install.dt.configuration.running_os == "windows" then + cmd = "\"" .. cmd .. "\"" + end + return os.execute(cmd) +end + +dtutils_system.libdoc.functions["io_popen"] = { + Name = [[io_popen]], + Synopsis = [[wrapper around the lua io.popen function]], + Usage = [[local dsys = require "lib/dtutils.file" + + result = dsys.io_popen(cmd) + cmd - string - a command to execute and attach to]], + Description = [[io_popen wraps the lua io.popen system call to provide + correct sanitization of windows commands]], + Return_Value = [[see the lua io.popen documentation]], + Limitations = [[]], + Example = [[]], + See_Also = [[]], + Reference = [[]], + License = [[]], + Copyright = [[]], +} + +function dtutils_system.io_popen(cmd) + if _scripts_install.dt.configuration.running_os == "windows" then + cmd = "\"" .. cmd .. "\"" + end + return io.popen(cmd) +end + + return dtutils_system From fe48d7498c8d40bd222c62104e454aa1f92dd39b Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Tue, 4 Jun 2024 23:41:07 -0400 Subject: [PATCH 303/445] lib/dtutils/file - replaced os.execute and io.popen with wrapper functions to sanitize windows calls --- lib/dtutils/file.lua | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/dtutils/file.lua b/lib/dtutils/file.lua index cd898e71..b8717116 100644 --- a/lib/dtutils/file.lua +++ b/lib/dtutils/file.lua @@ -42,7 +42,7 @@ end local function _win_os_execute(cmd) local result = nil - local p = io.popen(cmd) + local p = dsys.io_popen(cmd) local output = p:read("*a") p:close() if string.match(output, "true") then @@ -94,7 +94,7 @@ dtutils_file.libdoc.functions["test_file"] = { function dtutils_file.test_file(path, test) local cmd = "test -" - local engine = os.execute + local engine = dsys.os_execute local cmdstring = "" if dt.configuration.running_os == "windows" then @@ -167,7 +167,7 @@ local function _search_for_bin_windows(bin) for _,arg in ipairs(args) do local cmd = "where " .. arg .. " " .. ds.sanitize(bin) - local p = io.popen(cmd) + local p = dsys.io_popen(cmd) local output = p:read("*a") p:close() local lines = du.split(output, "\n") @@ -191,7 +191,7 @@ end local function _search_for_bin_nix(bin) local result = false - local p = io.popen("command -v " .. bin) + local p = dsys.io_popen("command -v " .. bin) local output = p:read("*a") p:close() if string.len(output) > 0 then @@ -220,7 +220,7 @@ local function _search_for_bin_macos(bin) search_start = "/Applications/" .. bin .. ".app" end - local p = io.popen("find " .. search_start .. " -type f -name " .. bin .. " -print") + local p = dsys.io_popen("find " .. search_start .. " -type f -name " .. bin .. " -print") local output = p:read("*a") p:close() local lines = du.split(output, "\n") @@ -445,7 +445,7 @@ function dtutils_file.check_if_file_exists(filepath) local result = false if (dt.configuration.running_os == 'windows') then filepath = string.gsub(filepath, '[\\/]+', '\\') - local p = io.popen("if exist " .. dtutils_file.sanitize_filename(filepath) .. " (echo 'yes') else (echo 'no')") + local p = dsys.io_popen("if exist " .. dtutils_file.sanitize_filename(filepath) .. " (echo 'yes') else (echo 'no')") local ans = p:read("*all") p:close() if string.match(ans, "yes") then @@ -456,7 +456,7 @@ function dtutils_file.check_if_file_exists(filepath) -- result = false -- end elseif (dt.configuration.running_os == "linux") then - result = os.execute('test -e ' .. dtutils_file.sanitize_filename(filepath)) + result = dsys.os_execute('test -e ' .. dtutils_file.sanitize_filename(filepath)) if not result then result = false end @@ -522,9 +522,9 @@ function dtutils_file.file_copy(fromFile, toFile) local result = nil -- if cp exists, use it if dt.configuration.running_os == "windows" then - result = os.execute('copy "' .. fromFile .. '" "' .. toFile .. '"') + result = dsys.os_execute('copy "' .. fromFile .. '" "' .. toFile .. '"') elseif dtutils_file.check_if_bin_exists("cp") then - result = os.execute("cp '" .. fromFile .. "' '" .. toFile .. "'") + result = dsys.os_execute("cp '" .. fromFile .. "' '" .. toFile .. "'") end -- if cp was not present, or if cp failed, then a pure lua solution @@ -575,7 +575,7 @@ function dtutils_file.file_move(fromFile, toFile) if not success then -- an error occurred, so let's try using the operating system function if dtutils_file.check_if_bin_exists("mv") then - success = os.execute("mv '" .. fromFile .. "' '" .. toFile .. "'") + success = dsys.os_execute("mv '" .. fromFile .. "' '" .. toFile .. "'") end -- if the mv didn't exist or succeed, then... if not success then From 038418b89fac9e99a309a536eee6aa4f13c19428 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Tue, 4 Jun 2024 23:43:21 -0400 Subject: [PATCH 304/445] contrib/autostyle replaced io.popen functions with wrapper contrib/color_profile_manager to properly quote windows commands so contrib/fujifilm_dynamic_range that they are sanitized for special contrib/fujifilm_ratings characters and spaces contrib/geoJSON_export contrib/geoToolbox contrib/image_stack contrib/image_time contrib/kml_export official/enfuse tools/executable_manager tools/get_lib_manpages tools/get_libdoc --- contrib/autostyle.lua | 3 ++- contrib/color_profile_manager.lua | 3 ++- contrib/fujifilm_dynamic_range.lua | 3 ++- contrib/fujifilm_ratings.lua | 5 +++-- contrib/geoJSON_export.lua | 3 ++- contrib/geoToolbox.lua | 3 ++- contrib/image_stack.lua | 2 +- contrib/image_time.lua | 7 ++++--- contrib/kml_export.lua | 2 +- official/enfuse.lua | 2 +- tools/executable_manager.lua | 5 +++-- tools/get_lib_manpages.lua | 5 +++-- tools/get_libdoc.lua | 3 ++- 13 files changed, 28 insertions(+), 18 deletions(-) diff --git a/contrib/autostyle.lua b/contrib/autostyle.lua index a12cd0ac..319b8f3a 100644 --- a/contrib/autostyle.lua +++ b/contrib/autostyle.lua @@ -39,6 +39,7 @@ GPLv2 local darktable = require "darktable" local du = require "lib/dtutils" local filelib = require "lib/dtutils.file" +local syslib = require "lib/dtutils.system" du.check_min_api_version("7.0.0", "autostyle") @@ -68,7 +69,7 @@ script_data.show = nil -- only required for libs since the destroy_method only h -- run command and retrieve stdout local function get_stdout(cmd) -- Open the command, for reading - local fd = assert(io.popen(cmd, 'r')) + local fd = assert(syslib.io_popen(cmd, 'r')) darktable.control.read(fd) -- slurp the whole file local data = assert(fd:read('*a')) diff --git a/contrib/color_profile_manager.lua b/contrib/color_profile_manager.lua index ed083178..d87d9a6a 100644 --- a/contrib/color_profile_manager.lua +++ b/contrib/color_profile_manager.lua @@ -45,6 +45,7 @@ local dt = require "darktable" local du = require "lib/dtutils" local df = require "lib/dtutils.file" +local dtsys = require "lib/dtutils.system" du.check_min_api_version("7.0.0", "color_profile_manager") @@ -106,7 +107,7 @@ end local function list_profiles(dir) local files = {} - local p = io.popen(DIR_CMD .. " " .. dir) + local p = dtsys.io_popen(DIR_CMD .. " " .. dir) if p then for line in p:lines() do table.insert(files, line) diff --git a/contrib/fujifilm_dynamic_range.lua b/contrib/fujifilm_dynamic_range.lua index d373d130..1034411d 100644 --- a/contrib/fujifilm_dynamic_range.lua +++ b/contrib/fujifilm_dynamic_range.lua @@ -60,6 +60,7 @@ cameras may behave in other ways. local dt = require "darktable" local du = require "lib/dtutils" local df = require "lib/dtutils.file" +local dtsys = require "lib/dtutils.system" local gettext = dt.gettext.gettext du.check_min_api_version("7.0.0", "fujifilm_dynamic_range") @@ -105,7 +106,7 @@ local function detect_dynamic_range(event, image) -- without -n flag, exiftool will round to the nearest tenth command = command .. " -RawExposureBias -n -t " .. RAF_filename dt.print_log(command) - output = io.popen(command) + output = dtsys.io_popen(command) local raf_result = output:read("*all") output:close() if #raf_result == 0 then diff --git a/contrib/fujifilm_ratings.lua b/contrib/fujifilm_ratings.lua index f9bb1c86..ef935139 100644 --- a/contrib/fujifilm_ratings.lua +++ b/contrib/fujifilm_ratings.lua @@ -26,6 +26,7 @@ Dependencies: local dt = require "darktable" local du = require "lib/dtutils" local df = require "lib/dtutils.file" +local dtsys = require "lib/dtutils.system" local gettext = dt.gettext.gettext du.check_min_api_version("7.0.0", "fujifilm_ratings") @@ -61,7 +62,7 @@ local function detect_rating(event, image) local JPEG_filename = string.gsub(RAF_filename, "%.RAF$", ".JPG") local command = "exiftool -Rating " .. JPEG_filename dt.print_error(command) - local output = io.popen(command) + local output = dtsys.io_popen(command) local jpeg_result = output:read("*all") output:close() if string.len(jpeg_result) > 0 then @@ -72,7 +73,7 @@ local function detect_rating(event, image) end command = "exiftool -Rating " .. RAF_filename dt.print_error(command) - output = io.popen(command) + output = dtsys.io_popen(command) local raf_result = output:read("*all") output:close() if string.len(raf_result) > 0 then diff --git a/contrib/geoJSON_export.lua b/contrib/geoJSON_export.lua index 695976a6..406c37c2 100644 --- a/contrib/geoJSON_export.lua +++ b/contrib/geoJSON_export.lua @@ -35,6 +35,7 @@ USAGE local dt = require "darktable" local du = require "lib/dtutils" local df = require "lib/dtutils.file" +local dtsys = require "lib/dtutils.system" local gettext = dt.gettext.gettext du.check_min_api_version("7.0.0", "geoJSON_export") @@ -330,7 +331,7 @@ dt.preferences.register("geoJSON_export", _("opens the geoJSON file after the export with the standard program for geoJSON files"), false ) -local handle = io.popen("xdg-user-dir DESKTOP") +local handle = dtsys.io_popen("xdg-user-dir DESKTOP") local result = handle:read() handle:close() if (result == nil) then diff --git a/contrib/geoToolbox.lua b/contrib/geoToolbox.lua index 83caa130..d654eeba 100644 --- a/contrib/geoToolbox.lua +++ b/contrib/geoToolbox.lua @@ -28,6 +28,7 @@ require "geoToolbox" local dt = require "darktable" local du = require "lib/dtutils" local df = require "lib/dtutils.file" +local dtsys = require "lib/dtutils.system" local gettext = dt.gettext.gettext du.check_min_api_version("7.0.0", "geoToolbox") @@ -411,7 +412,7 @@ local function reverse_geocode() -- jq could be replaced with a Lua JSON parser startCommand = string.format("curl --silent \"https://api.mapbox.com/geocoding/v5/mapbox.places/%s,%s.json?types=%s&access_token=%s\" | jq '.features | .[0] | '.text''", lon1, lat1, types, tokan) - local handle = io.popen(startCommand) + local handle = dtsys.io_popen(startCommand) local result = trim12(handle:read("*a")) handle:close() diff --git a/contrib/image_stack.lua b/contrib/image_stack.lua index c63ff166..ba0909b1 100644 --- a/contrib/image_stack.lua +++ b/contrib/image_stack.lua @@ -348,7 +348,7 @@ local function list_files(search_string) search_string = string.gsub(search_string, "/", "\\\\") end - local f = io.popen(ls .. search_string) + local f = dtsys.io_popen(ls .. search_string) if f then local found_file = f:read() while found_file do diff --git a/contrib/image_time.lua b/contrib/image_time.lua index f20e5000..fa00b576 100644 --- a/contrib/image_time.lua +++ b/contrib/image_time.lua @@ -107,6 +107,7 @@ local dt = require "darktable" local du = require "lib/dtutils" local df = require "lib/dtutils.file" local ds = require "lib/dtutils.string" +local dtsys = require "lib/dtutils.system" local gettext = dt.gettext.gettext local img_time = {} @@ -225,7 +226,7 @@ local function get_image_taken_time(image) local exiv2 = df.check_if_bin_exists("exiv2") if exiv2 then - p = io.popen(exiv2 .. " -K Exif.Image.DateTime " .. image.path .. PS .. image.filename) + p = dtsys.io_popen(exiv2 .. " -K Exif.Image.DateTime " .. image.path .. PS .. image.filename) if p then for line in p:lines() do if string.match(line, "Exif.Image.DateTime") then @@ -243,7 +244,7 @@ end local function _get_windows_image_file_creation_time(image) local datetime = nil - local p = io.popen("dir " .. image.path .. PS .. image.filename) + local p = dtsys.io_popen("dir " .. image.path .. PS .. image.filename) if p then for line in p:lines() do if string.match(line, ds.sanitize_lua(image.filename)) then @@ -264,7 +265,7 @@ end local function _get_nix_image_file_creation_time(image) local datetime = nil - local p = io.popen("ls -lL --time-style=full-iso " .. image.path .. PS .. image.filename) + local p = dtsys.io_popen("ls -lL --time-style=full-iso " .. image.path .. PS .. image.filename) if p then for line in p:lines() do if string.match(line, ds.sanitize_lua(image.filename)) then diff --git a/contrib/kml_export.lua b/contrib/kml_export.lua index ec1aa04a..ec7218ca 100644 --- a/contrib/kml_export.lua +++ b/contrib/kml_export.lua @@ -343,7 +343,7 @@ if dt.configuration.running_os == "windows" then elseif dt.configuration.running_os == "macos" then defaultDir = os.getenv("HOME") else - local handle = io.popen("xdg-user-dir DESKTOP") + local handle = dsys.io_popen("xdg-user-dir DESKTOP") defaultDir = handle:read() handle:close() end diff --git a/official/enfuse.lua b/official/enfuse.lua index c8df51b1..c193c35e 100644 --- a/official/enfuse.lua +++ b/official/enfuse.lua @@ -116,7 +116,7 @@ if enfuse_installed then local version = nil - local p = io.popen(enfuse_installed .. " --version") + local p = dtsys.io_popen(enfuse_installed .. " --version") local f = p:read("all") p:close() version = string.match(f, "enfuse (%d.%d)") diff --git a/tools/executable_manager.lua b/tools/executable_manager.lua index 58a055ab..0ac35ad4 100644 --- a/tools/executable_manager.lua +++ b/tools/executable_manager.lua @@ -31,6 +31,7 @@ local dt = require "darktable" local du = require "lib/dtutils" local df = require "lib/dtutils.file" +local dtsys = require "lib/dtutils.system" du.check_min_api_version("7.0.0", "executable_manager") @@ -75,7 +76,7 @@ local function grep(file, pattern) if dt.configuration.running_os == "windows" then -- use find to get the matches local command = "\\windows\\system32\\find.exe " .. "\"" .. pattern .. "\"" .. " " .. file - local f = io.popen(command) + local f = dtsys.io_popen(command) local output = f:read("all") f:close() -- strip out the first line @@ -84,7 +85,7 @@ local function grep(file, pattern) else -- use grep and just return the answers local command = "grep " .. pattern .. " " .. file - local f = io.popen(command) + local f = dtsys.io_popen(command) local output = f:read("all") f:close() result = du.split(output, "\n") diff --git a/tools/get_lib_manpages.lua b/tools/get_lib_manpages.lua index a3c39157..33d2d031 100644 --- a/tools/get_lib_manpages.lua +++ b/tools/get_lib_manpages.lua @@ -7,6 +7,7 @@ local dt = require "darktable" local du = require "lib/dtutils" local df = require "lib/dtutils.file" +local dtsys = require "lib/dtutils.system" local log = require "lib/dtutils.log" local libname = nil @@ -33,7 +34,7 @@ local function output_man(d) libname = name end local fname = "/tmp/" .. name .. ".3" - local mf = io.open(fname, "w") + local mf = dtsys.io_open(fname, "w") if mf then mf:write(".TH " .. string.upper(name) .. " 3 \"\" \"\" \"Darktable " .. libname .. " functions\"\n") for _,section in ipairs(keys) do @@ -59,7 +60,7 @@ end -- find the libraries -local output = io.popen("cd "..dt.configuration.config_dir.."/lua/lib ;find . -name \\*.lua -print | sort") +local output = dtsys.io_popen("cd "..dt.configuration.config_dir.."/lua/lib ;find . -name \\*.lua -print | sort") -- loop through the libraries diff --git a/tools/get_libdoc.lua b/tools/get_libdoc.lua index 5cb08122..2328014a 100644 --- a/tools/get_libdoc.lua +++ b/tools/get_libdoc.lua @@ -6,6 +6,7 @@ local dt = require "darktable" local du = require "lib/dtutils" +local dtsys = require "lib/dtutils.system" du.check_min_api_version("3.0.0", "get_libdoc") @@ -36,7 +37,7 @@ end -- find the libraries -local output = io.popen("cd "..dt.configuration.config_dir.."/lua/lib ;find . -name \\*.lua -print | sort") +local output = dtsys.io_popen("cd "..dt.configuration.config_dir.."/lua/lib ;find . -name \\*.lua -print | sort") -- loop through the libraries From 96471ae7e77e9146989f40ce3f7a670b04b3225b Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Wed, 5 Jun 2024 00:00:43 -0400 Subject: [PATCH 305/445] lib/dtutils - fixed documentation error --- lib/dtutils.lua | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/dtutils.lua b/lib/dtutils.lua index c17ce334..c8331cbd 100644 --- a/lib/dtutils.lua +++ b/lib/dtutils.lua @@ -82,8 +82,7 @@ dtutils.libdoc.functions["check_max_api_version"] = { run against the current api version. This function is used when a part of the Lua API that the script relies on is removed. If the maximum api version is not met, then an error message is printed saying the script_name failed to load, then an error is thrown causing the - program to stop executing. - + program to stop executing.]], Return_Value = [[result - true if the maximum api version is available, false if not.]], Limitations = [[When using the default handler on a script being executed from the luarc file, the error thrown will stop the luarc file from executing any remaining statements. This limitation does not apply to script_manger.]], From 67538a4de2efb78b9c96134e963166f55ed23848 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Wed, 5 Jun 2024 00:01:17 -0400 Subject: [PATCH 306/445] lib/dtutils/system code cleanup --- lib/dtutils/system.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/dtutils/system.lua b/lib/dtutils/system.lua index 8f794f45..87a1f230 100644 --- a/lib/dtutils/system.lua +++ b/lib/dtutils/system.lua @@ -148,7 +148,7 @@ dtutils_system.libdoc.functions["os_execute"] = { } function dtutils_system.os_execute(cmd) - if _scripts_install.dt.configuration.running_os == "windows" then + if dt.configuration.running_os == "windows" then cmd = "\"" .. cmd .. "\"" end return os.execute(cmd) @@ -173,7 +173,7 @@ dtutils_system.libdoc.functions["io_popen"] = { } function dtutils_system.io_popen(cmd) - if _scripts_install.dt.configuration.running_os == "windows" then + if dt.configuration.running_os == "windows" then cmd = "\"" .. cmd .. "\"" end return io.popen(cmd) From 32e966f8d9b8135fcabc5bab26e1b1a80708b2de Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Wed, 5 Jun 2024 00:01:47 -0400 Subject: [PATCH 307/445] tools/git_lib_manpages code cleanup --- tools/get_lib_manpages.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/get_lib_manpages.lua b/tools/get_lib_manpages.lua index 33d2d031..fbc38b86 100644 --- a/tools/get_lib_manpages.lua +++ b/tools/get_lib_manpages.lua @@ -34,7 +34,7 @@ local function output_man(d) libname = name end local fname = "/tmp/" .. name .. ".3" - local mf = dtsys.io_open(fname, "w") + local mf = dtsys.io_popen(fname, "w") if mf then mf:write(".TH " .. string.upper(name) .. " 3 \"\" \"\" \"Darktable " .. libname .. " functions\"\n") for _,section in ipairs(keys) do @@ -46,7 +46,7 @@ local function output_man(d) mf:close() if df.check_if_bin_exists("groff") then if df.check_if_bin_exists("ps2pdf") then - os.execute("groff -man " .. fname .. " | ps2pdf - " .. fname .. ".pdf") + dtsys.os_execute("groff -man " .. fname .. " | ps2pdf - " .. fname .. ".pdf") else log.msg(log.error, "Missing ps2pdf. Can't generate pdf man pages.") end From 2abb83b485922892ec1f7318481dd11c38d83fda Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Wed, 5 Jun 2024 00:09:18 -0400 Subject: [PATCH 308/445] tools/get_lib_manpages - more code cleanup --- tools/get_lib_manpages.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/get_lib_manpages.lua b/tools/get_lib_manpages.lua index fbc38b86..91d5dbb3 100644 --- a/tools/get_lib_manpages.lua +++ b/tools/get_lib_manpages.lua @@ -34,7 +34,7 @@ local function output_man(d) libname = name end local fname = "/tmp/" .. name .. ".3" - local mf = dtsys.io_popen(fname, "w") + local mf = io.open(fname, "w") if mf then mf:write(".TH " .. string.upper(name) .. " 3 \"\" \"\" \"Darktable " .. libname .. " functions\"\n") for _,section in ipairs(keys) do From 9f2dbef4f09f00c7043eba5fc16d26180805ccfe Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Wed, 5 Jun 2024 12:15:01 -0400 Subject: [PATCH 309/445] lib/dtutils/system added local helper function quote_windows_command() to wrap a windows command in quotes. Added a sanitize step to windows_external_command() plus quote_windows_command() to deal with all the windows username possibilities --- lib/dtutils/system.lua | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/lib/dtutils/system.lua b/lib/dtutils/system.lua index 87a1f230..e8ce9af0 100644 --- a/lib/dtutils/system.lua +++ b/lib/dtutils/system.lua @@ -1,6 +1,7 @@ local dtutils_system = {} local dt = require "darktable" +local ds = require "lib/dtutils.string" dtutils_system.libdoc = { Name = [[dtutils.system]], @@ -50,9 +51,9 @@ function dtutils_system.external_command(command) local result = nil if dt.configuration.running_os == "windows" then - result = dtutils_system.windows_command(command) + result = dtutils_system.windows_command(ds.sanitize(command)) else - result = dt.control.execute(command) + result = dt.control.execute(ds.sanitize(command)) end return result @@ -77,15 +78,20 @@ dtutils_system.libdoc.functions["windows_command"] = { Copyright = [[]], } +local function quote_windows_command(command) + return "\"" .. command .. "\"" +end + function dtutils_system.windows_command(command) local result = 1 - local fname = dt.configuration.tmp_dir .. "/run_command.bat" + local fname = ds.sanitize(dt.configuration.tmp_dir .. "/run_command.bat") local file = io.open(fname, "w") if file then dt.print_log("opened file") command = string.gsub(command, "%%", "%%%%") -- escape % from windows shell + command = quote_windows-command(command) file:write(command) file:close() @@ -149,7 +155,7 @@ dtutils_system.libdoc.functions["os_execute"] = { function dtutils_system.os_execute(cmd) if dt.configuration.running_os == "windows" then - cmd = "\"" .. cmd .. "\"" + cmd = quote_windows_command(cmd) end return os.execute(cmd) end @@ -174,7 +180,7 @@ dtutils_system.libdoc.functions["io_popen"] = { function dtutils_system.io_popen(cmd) if dt.configuration.running_os == "windows" then - cmd = "\"" .. cmd .. "\"" + cmd = quote_windows_command(cmd) end return io.popen(cmd) end From 3e032616a038cb4317c6ed897aadb5976dfac5cc Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Wed, 5 Jun 2024 14:49:06 -0400 Subject: [PATCH 310/445] tools/executable_manager - fix position not visible on windows --- tools/executable_manager.lua | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tools/executable_manager.lua b/tools/executable_manager.lua index 58a055ab..cc98cd9b 100644 --- a/tools/executable_manager.lua +++ b/tools/executable_manager.lua @@ -107,13 +107,19 @@ local function update_combobox_choices(combobox, choice_table, selected) end local function install_module() + local panel = "DT_UI_CONTAINER_PANEL_LEFT_BOTTOM" + local panel_pos = 600 + if dt.configuration.running_os == "windows" then + panel = "DT_UI_CONTAINER_PANEL_LEFT_CENTER" + panel_pos = 100 + end if not exec_man.module_installed then dt.register_lib( "executable_manager", -- Module name "executable manager", -- Visible name true, -- expandable false, -- resetable - {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_LEFT_BOTTOM", 600}}, -- containers + {[dt.gui.views.lighttable] = {panel, panel_pos}}, -- containers dt.new_widget("box") -- widget { orientation = "vertical", From 539f25517bbf0a4fcc58a3408d13d9eafe3ef1b4 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Wed, 5 Jun 2024 22:16:40 -0400 Subject: [PATCH 311/445] contrib/fujifilm_ratings - added check to ensure the image is a fujifilm file. --- contrib/fujifilm_ratings.lua | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/contrib/fujifilm_ratings.lua b/contrib/fujifilm_ratings.lua index ef935139..b2f11fe3 100644 --- a/contrib/fujifilm_ratings.lua +++ b/contrib/fujifilm_ratings.lua @@ -54,6 +54,9 @@ script_data.restart = nil -- how to restart the (lib) script after it's been hid script_data.show = nil -- only required for libs since the destroy_method only hides them local function detect_rating(event, image) + if not string.match(image.filename, "%.RAF$") and not string.match(image.filename, "%.raf$") then + return + end if not df.check_if_bin_exists("exiftool") then dt.print_error(_("exiftool not found")) return @@ -61,25 +64,25 @@ local function detect_rating(event, image) local RAF_filename = df.sanitize_filename(tostring(image)) local JPEG_filename = string.gsub(RAF_filename, "%.RAF$", ".JPG") local command = "exiftool -Rating " .. JPEG_filename - dt.print_error(command) + dt.print_log(command) local output = dtsys.io_popen(command) local jpeg_result = output:read("*all") output:close() if string.len(jpeg_result) > 0 then jpeg_result = string.gsub(jpeg_result, "^Rating.*(%d)", "%1") image.rating = tonumber(jpeg_result) - dt.print_error(string.format(_("using JPEG rating: %d"), jpeg_result)) + dt.print_log("using JPEG rating: " .. jpeg_result) return end command = "exiftool -Rating " .. RAF_filename - dt.print_error(command) + dt.print_log(command) output = dtsys.io_popen(command) local raf_result = output:read("*all") output:close() if string.len(raf_result) > 0 then raf_result = string.gsub(raf_result, "^Rating.*(%d)", "%1") image.rating = tonumber(raf_result) - dt.print_error(string.format(_("using RAF rating: %d"), raf_result)) + dt.print_log("using RAF rating: " .. raf_result) end end From 4ff111134141cbdd0adfdacee4643695847465d0 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Fri, 7 Jun 2024 15:23:06 -0400 Subject: [PATCH 312/445] tools/script_manaager added sanitized io.popen and os.execute functions for windows character and space issues. Cleaned up translatable strings to make future translation easier. --- tools/script_manager.lua | 69 +++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 40 deletions(-) diff --git a/tools/script_manager.lua b/tools/script_manager.lua index ed93b963..955f4839 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -1,6 +1,6 @@ --[[ This file is part of darktable, - copyright (c) 2018, 2020, 2023 Bill Ferguson + copyright (c) 2018, 2020, 2023, 2024 Bill Ferguson darktable is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -60,7 +60,7 @@ local gettext = dt.gettext -- Tell gettext where to find the .mo file translating messages for a particular domain -dt.gettext.bindtextdomain("script_manager",dt.configuration.config_dir.."/lua/locale/") +dt.gettext.bindtextdomain("script_manager", dt.configuration.config_dir .. "/lua/locale/") local function _(msgid) return gettext.dgettext("script_manager", msgid) @@ -241,7 +241,7 @@ end local function get_repo_status(repo) local old_log_level = set_log_level(sm.log_level) - local p = io.popen("cd " .. repo .. CS .. "git status") + local p = dtsys.io_popen("cd " .. repo .. CS .. "git status") if p then local data = p:read("*a") @@ -259,7 +259,7 @@ local function get_current_repo_branch(repo) local branch = nil - local p = io.popen("cd " .. repo .. CS .. "git branch --all") + local p = dtsys.io_popen("cd " .. repo .. CS .. "git branch --all") if p then local data = p:read("*a") @@ -289,7 +289,7 @@ local function get_repo_branches(repo) local old_log_level = set_log_level(sm.log_level) local branches = {} - local p = io.popen("cd " .. repo .. CS .. "git pull --all" .. CS .. "git branch --all") + local p = dtsys.io_popen("cd " .. repo .. CS .. "git pull --all" .. CS .. "git branch --all") if p then local data = p:read("*a") @@ -329,7 +329,7 @@ local function checkout_repo_branch(repo, branch) log.msg(log.info, "checkout out branch " .. branch .. " from repository " .. repo) - os.execute("cd " .. repo .. CS .. "git checkout " .. branch) + dtsys.os_execute("cd " .. repo .. CS .. "git checkout " .. branch) restore_log_level(old_log_level) end @@ -417,7 +417,7 @@ local function get_script_metadata(script) -- grab the script_data.metadata table description = string.match(content, "script_data%.metadata = %{\r?\n(.-)\r?\n%}") else - log.msg(log.error, _("Cant read from " .. script)) + log.msg(log.error, "cant read from " .. script) end if description then @@ -459,7 +459,7 @@ local function get_script_doc(script) -- assume that the second block comment is the documentation description = string.match(content, "%-%-%[%[.-%]%].-%-%-%[%[(.-)%]%]") else - log.msg(log.error, _("Cant read from " .. script)) + log.msg(log.error, "can't read from " .. script) end if description then restore_log_level(old_log_level) @@ -489,7 +489,7 @@ local function activate(script) if status then pref_write(script.script_name, "bool", true) - log.msg(log.screen, _("Loaded ") .. script.script_name) + log.msg(log.screen, _(string.format("loaded %s", script.script_name))) script.running = true if err ~= true then @@ -503,9 +503,9 @@ local function activate(script) end else - log.msg(log.screen, script.script_name .. _(" failed to load")) - log.msg(log.error, "Error loading " .. script.script_name) - log.msg(log.error, "Error message: " .. err) + log.msg(log.screen, _(string.format("%s failed to load", script.script_name))) + log.msg(log.error, "error loading " .. script.script_name) + log.msg(log.error, "error message: " .. err) end else -- script is a lib and loaded but hidden and the user wants to reload @@ -549,13 +549,13 @@ local function deactivate(script) end log.msg(log.info, "turned off " .. script.script_name) - log.msg(log.screen, script.name .. _(" stopped")) + log.msg(log.screen, _(string.format("%s stopped", script.name))) else script.running = false log.msg(log.info, "setting " .. script.script_name .. " to not start") - log.msg(log.screen, script.name .. _(" will not start when darktable is restarted")) + log.msg(log.screen, _(string.format("%s will not start when darktable is restarted", script.name))) end restore_log_level(old_log_level) @@ -665,7 +665,7 @@ local function scan_scripts(script_dir) log.msg(log.debug, "find command is " .. find_cmd) -- scan the scripts - local output = io.popen(find_cmd) + local output = dtsys.io_popen(find_cmd) for line in output:lines() do log.msg(log.debug, "line is " .. line) local l = string.gsub(line, ds.sanitize_lua(LUA_DIR) .. PS, "") -- strip the lua dir off @@ -695,7 +695,7 @@ local function update_scripts() local git = sm.executables.git if not git then - dt.print(_("ERROR: git not found. Install or specify the location of the git executable.")) + log.msg(log.screen, _("ERROR: git not found. Install or specify the location of the git executable.")) return end @@ -709,7 +709,7 @@ local function update_scripts() end if result == 0 then - dt.print(_("lua scripts successfully updated")) + log.msg(log.screen, _("lua scripts successfully updated")) end restore_log_level(old_log_level) @@ -749,9 +749,9 @@ local function scan_repositories() find_cmd = "dir /b/s /a:d " .. LUA_DIR .. PS .. "*.git | sort" end - log.msg(log.debug, _("find command is ") .. find_cmd) + log.msg(log.debug, "find command is " .. find_cmd) - local output = io.popen(find_cmd) + local output = dtsys.io_popen(find_cmd) for line in output:lines() do local l = string.gsub(line, ds.sanitize_lua(LUA_DIR) .. PS, "") -- strip the lua dir off @@ -799,7 +799,7 @@ local function install_scripts() local folder = sm.widgets.new_folder.text if string.match(du.join(sm.folders, " "), ds.sanitize_lua(folder)) then - log.msg(log.screen, _("folder ") .. folder .. _(" is already in use. Please specify a different folder name.")) + log.msg(log.screen, _(string.format("folder %s is already in use. Please specify a different folder name.", folder))) log.msg(log.error, "folder " .. folder .. " already exists, returning...") restore_log_level(old_log_level) return @@ -810,7 +810,7 @@ local function install_scripts() local git = sm.executables.git if not git then - dt.print(_("ERROR: git not found. Install or specify the location of the git executable.")) + log.msg(log.screen, _("ERROR: git not found. Install or specify the location of the git executable.")) restore_log_level(old_log_level) return end @@ -849,12 +849,12 @@ local function install_scripts() sm.widgets.new_folder.text = "" sm.widgets.main_menu.selected = 3 else - dt.print(_("No scripts found to install")) + log.msg(log.screen, _("No scripts found to install")) log.msg(log.error, "scan_scripts returned " .. count .. " scripts found. Not adding to folder_selector") end else - dt.print(_("failed to download scripts")) + log.msg(log.screen, _("failed to download scripts")) end restore_log_level(old_log_level) @@ -1006,7 +1006,7 @@ local function paginate(direction) last = first + sm.page_status.num_buttons - 1 end - sm.widgets.page_status.label = _("Page ") .. cur_page .. _(" of ") .. max_pages + sm.widgets.page_status.label = _(string.format("page %d of %d", cur_page, max_pages)) populate_buttons(folder, first, last) @@ -1177,17 +1177,6 @@ local function install_module() log.msg(log.debug, "set run to true, loading preferences") load_preferences() scan_repositories() - --[[dt.print_log("\n\nsetting sm visible false\n\n") - dt.gui.libs["script_manager"].visible = false - dt.control.sleep(5000) - dt.print_log("setting sm visible true") - dt.gui.libs["script_manager"].visible = true - --[[dt.control.sleep(5000) - dt.print_log("setting sm expanded false") - dt.gui.libs["script_manager"].expanded = false - dt.control.sleep(5000) - dt.print_log("setting sm expanded true") - dt.gui.libs["script_manager"].expanded = true]] restore_log_level(old_log_level) end @@ -1217,7 +1206,7 @@ if check_for_updates then -- probably upgraded from an earlier api version so get back to master -- to use the latest version of script_manager to get the proper API checkout_repo_branch(repo, "master") - log.msg(log.screen, "lua API version reset, please restart darktable") + log.msg(log.screen, _("lua API version reset, please restart darktable")) elseif LUA_API_VER == current_branch then -- do nothing, we are fine @@ -1353,7 +1342,7 @@ sm.widgets.disable_scripts = dt.new_widget("button"){ local LUARC = dt.configuration.config_dir .. PS .. "luarc" df.file_move(LUARC, LUARC .. ".disabled") log.msg(log.info, "lua scripts disabled") - dt.print(_("lua scripts will not run the next time darktable is started")) + log.msg(log.screen, _("lua scripts will not run the next time darktable is started")) end } @@ -1414,7 +1403,7 @@ end local page_back = "<" local page_forward = ">" -sm.widgets.page_status = dt.new_widget("label"){label = _("Page:")} +sm.widgets.page_status = dt.new_widget("label"){label = _("page:")} sm.widgets.page_back = dt.new_widget("button"){ label = page_back, @@ -1445,7 +1434,7 @@ sm.widgets.scripts = dt.new_widget("box"){ orientation = vertical, dt.new_widget("section_label"){label = _(" ")}, dt.new_widget("label"){label = " "}, - dt.new_widget("label"){label = _("Scripts")}, + dt.new_widget("label"){label = _("scripts")}, sm.widgets.folder_selector, sm.widgets.page_control, table.unpack(sm.widgets.boxes), @@ -1529,7 +1518,7 @@ else function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() - end + end end ) sm.event_registered = true From 5571e2f2dc3e9a709aef3cee20e58e787ba67d78 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sat, 8 Jun 2024 21:51:37 -0400 Subject: [PATCH 313/445] ChangeLog - Updated with the latest repository changes README - Updated the script additions --- ChangeLog.md | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 9 +++++++ 2 files changed, 82 insertions(+) diff --git a/ChangeLog.md b/ChangeLog.md index d935ab16..33b27bd2 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,5 +1,78 @@ ## Changes from most recent to oldest +**06 Jun 2024 - wpferguson** +* fix fujifilm_ratings running on all images +* added string library functions to sanitize windows io.popen and os.execute functions +* added database maintenance script + +**05 Jun 2024 - wpferguson** +* added fix for executable_manager not being visible on windows + +**30 May 2024 - kkotowicz** +* open in explorer now uses applescript on macos to open multiple files + +**20 May 2024 - wpferguson** +* added string variable substitution to the string library + +**16 May 2024 - wpferguson** +* fix crash in script_manager + +**15 May 2024 - wpferguson** +* added metadata to scripts (name, author, purpose, help url) + +**06 May 2024 - christian.sueltrop** +* added passport_guide_germany script + +**08 Apr 2024 - wpferguson** +* made script_manager aware of library modules in other directories besides lib + +**29 Mar 2024 - wpferguson** +* updated examples/gui_action to use NaN instead of nan + +**29 Mar 2024 - dterrahe** +* add lua action script example + +**28 Jan 2024 - wpferguson** +* fix script_manager crash when script existed in top level lua directory + +**24 Jan 2024 - wpferguson** +* don't set lib visibility unless we are in lighttable mode + +**15 Jan 2024 - MStraeten** +* update x-touch.lua with support for primaries slider + +**14 Jan 2024 - wpferguson** +* added cycle_group_leader script +* added hif_group_leader script +* added jpg_group_leader script + +**28 Oct 2023 - ddittmar** +* Added select non existing image script + +**17 Oct 2023 - wpferguson** +* script_manager wrap username in quotes to handle spaces in username + +**20 Sep 2023 - wpferguson** +* script_manager explicitly set stopped scripts to false + +**18 Aug 2023 - wpferguson** +* swap the position of executable_manager and script_manager due to windows gtk bug + +**17 Jul 2023 - wpferguson** +* update check for update instructions +* update flatpak readme + +**16 Jul 2023 - wpferguson** +* added script_data.show function to contrib/gpx_export + +**15 Jul 2023 - wpferguson** +* script_manager updates +* added check_max_api_version for the case where the API no longer supports the required + functions + +**14 Jul 2023 - spaceChRis** +* add tooltip to filter manager + **25 Mar 2023 - wpferguson** * Added script_manager darktable shortcut integration * Moved filename/path/extension string functions to string library diff --git a/README.md b/README.md index f371e8d5..80ead1b9 100644 --- a/README.md +++ b/README.md @@ -39,8 +39,11 @@ Name|Standalone|OS |Purpose change_group_leader|Yes|LMW|Change which image leads group [clear_GPS](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/clear_gps)|Yes|LMW|Reset GPS information for selected images [CollectHelper](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/collecthelper)|Yes|LMW|Add buttons to selected images module to manipulate the collection +color_profile_manager|Yes|LMW|Manage darktable input and output color profiles [copy_attach_detach_tags](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/copy_attach_detach_tags)|Yes|LMW|Copy and paste tags from/to images [cr2hdr](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/cr2hdr)|Yes|L|Process image created with Magic Lantern Dual ISO +cycle_group_leader|Yes|LMW|cycle through images of a group making each the group leader in turn +dbmaint|Yes|LMW|find and remove database entries for missing film rolls and images [enfuseAdvanced](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/enfuseadvanced)|No|LMW|Merge multiple images into Dynamic Range Increase (DRI) or Depth From Focus (DFF) images [exportLUT](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/exportlut)|Yes|LMW|Create a LUT from a style and export it [ext_editor](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/ext_editor)|No|LW|Export pictures to collection and edit them with up to nine user-defined external editors @@ -51,14 +54,18 @@ change_group_leader|Yes|LMW|Change which image leads group [geoToolbox](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/geotoolbox)|No|LMW|A toolbox of geo functions [gimp](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/gimp)|No|LMW|Open an image in GIMP for editing and return the result [gpx_export](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/gpx_export)|No|LMW|Export a GPX track file from selected images GPS data +harmonic_armature|Yes|LMW|provide a harmonic armature guide +hif_group_leader|Yes|LMW|change the group leader in a raw+heif image pair to the heif image [HDRMerge](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/hdrmerge)|No|LMW|Combine the selected images into an HDR DNG and return the result [hugin](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/hugin)|No|LMW|Combine selected images into a panorama and return the result [image_stack](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/image_stack)|No|LMW|Combine a stack of images to remove noise or transient objects [image_time](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/image_time)|Yes|LMW|Adjust the EXIF image time +jpg_group_leader|Yes|LMW|change the group leader for a raw+jpg pair to the jpg image [kml_export](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/kml_export)|No|L|Export photos with a KML file for usage in Google Earth [LabelsToTags](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/labelstotags)|Yes|LMW|Apply tags based on color labels and ratings [OpenInExplorer](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/openinexplorer)|No|LMW|Open the selected images in the system file manager [passport_guide](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/passport_guide)|Yes|LMW|Add passport cropping guide to darkroom crop tool +passport_guide_germany|Yes|LMW|Add passport cropping guide for German passports to darkroom crop tool [pdf_slideshow](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/pdf_slideshow)|No|LM|Export images to a PDF slideshow [photils](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/photils)|No|LM|Automatic tag suggestions for your images [quicktag](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/quicktag)|Yes|LMW|Create shortcuts for quickly applying tags @@ -81,6 +88,7 @@ Name|Standalone|OS |Purpose [api_version](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/api_version)|Yes|LMW|Print the current API version [darkroom_demo](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/darkroom_demo)|Yes|LMW|Demonstrate changing images in darkoom [gettextExample](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/gettextexample)|Yes|LM|How to use translation +gui_actions|Yes|LMW|demonstrate controlling the GUI using darktable.gui.action calls [hello_world](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/hello_world)|Yes|LMW|Prints hello world when darktable starts [lighttable_demo](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/lighttable_demo)|Yes|LMW|Demonstrate controlling lighttable mode, zoom, sorting and filtering [moduleExample](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/moduleexample)|Yes|LMW|How to create a lighttable module @@ -89,6 +97,7 @@ Name|Standalone|OS |Purpose [preferenceExamples](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/preferenceexamples)|Yes|LMW|How to use preferences in a script [printExamples](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/printexamples)|Yes|LMW|How to use various print functions from a script [running_os](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/running_os)|Yes|LMW|Print out the running operating system +x-touch|Yes|LMW|demonstrate how to use an x-touch mini MIDI controller to control the darktable GUI ### Tools From 28622e620e676e98b3f01f45b6e08e709080c982 Mon Sep 17 00:00:00 2001 From: wpferguson Date: Sun, 9 Jun 2024 16:42:05 -0400 Subject: [PATCH 314/445] Revert "script_manager new UI" --- contrib/micharambou | 1 - data/icons/blank20.png | Bin 5678 -> 0 bytes data/icons/path20.png | Bin 6265 -> 0 bytes data/icons/power.png | Bin 426 -> 0 bytes data/icons/poweroff.png | Bin 599 -> 0 bytes development | 1 - tools/script_manager.lua | 652 ++++++++++++--------------------------- 7 files changed, 194 insertions(+), 460 deletions(-) delete mode 120000 contrib/micharambou delete mode 100644 data/icons/blank20.png delete mode 100644 data/icons/path20.png delete mode 100644 data/icons/power.png delete mode 100644 data/icons/poweroff.png delete mode 120000 development diff --git a/contrib/micharambou b/contrib/micharambou deleted file mode 120000 index bbe4f2d2..00000000 --- a/contrib/micharambou +++ /dev/null @@ -1 +0,0 @@ -/home/bill/src/dtluadev/gitannex/micharambou/ \ No newline at end of file diff --git a/data/icons/blank20.png b/data/icons/blank20.png deleted file mode 100644 index 81ed51574807dde06248d05f94fe17aad24b193a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5678 zcmeHKd010d7Eff8SY$^*g%A|$60$=Q2*bWqK$g^iqLAdhK!7YHfh4SoUw6r(JBzi;}VN#4u5=brOB=lt%u_uZT6 z@8_w5Fhjs#Fdc6%w?OFM2)c~tYeILA?(3B>nC627daxvrDMboJ0uDC@L`vjB5DCh- z92iV?_i6B^eGjd_c^6?EGSAB^ZD`zKrG5JgamHraEfOi$Z)Mm4(f(Mti3`Jvv8*R7 zb!=SAkzSj=c0=t6k0ep&UNiIWnjD|r3%WL(@~(X{IHBJn|DIa9jYr3?T}LLTJyR15 zg(RKzFZPz=$F|L+l=iI&k{d`cZKw4InSE)0pm#ntlU4Se=DAm0ZtimlVQ7`o?McUi@UT6Mc^jjkx>L~$$P z?(Wf~U#p#GYQ9r*;KlV;kG-0D>l6lzyFjR11V8dXQF5S9;vI3v%#(c5_>_ZTd0^Vv zbcSP6MsD-jdW($0`@E#{8WSiH+f~Q&`m-WUw_lobR$o!%j=p(t9vUY;sS1LiNM}z(onbsZ!Gm;Az`--*8O6X(;k>+xd0aBzf5ZI;M&Z~+H0ID;irl=%}*)aHYhjvxmANR!jZ`5tVTzG9e z;Ao|5N{uND@cbuHj!N-4WZQA7rmA+}yET}QpJVoZ&-hJP*U214Z>oQKZj>*mEPLDQ z7-r#w{=M?1^VOAimqd+_5_fu;`?cZJ!i_}p?myB~9R4>hd&Q8??qasdnnC(}XYbf+ z98ufW@GY4@g;xAF8@FW*>jzENwp_}YStYu7_$^Y@fB!Y2?lCuVY1`?b5s#c*w|;p3 zz1b^Md0EsYT`cNgVdnm*aSJcAM4i+>Zk~AJ8_l{vlTIqs-UU|)xGBB$9WNS|++V#V zrl`R)GJzUrn_@SwE@^(%&-syI3uH|ej%x;kJy~*C`qL*V+?#y=NDZ-Jf2eZay<~T`xwisXyIyKG(zi zxy8=&%hS8Eq1z8T$=ixsJ)$4#%qq4?CcI^)yABr|`_(sD+P5g2d}M*`eZ1nr){RlJ zGn9~+Dc8it{tLFd?L*mqvR(1dfeEvl7YI8W zgFL*RA+3)`TIZ}WDKUrrEQT-dBuf{Y!u6jY-hN81pD)j{gS^K z<1%J<`efz&=CSuOqsZ{(pDv7N?LBLgMHY9=tmx9J7)u_S*3Co4)b4nsZLVhilRsXc zLGOLo(=M=lXV06ula8S<^{+M;EcWPZDp=&wwC#4mT`e+nX_os)N4o=dX!UWs_Tt9SGS?7-TrRC7pn6UX3T$S|!xN@7 z-oRk+bgrwbzqhOFhu0nSk}FQ$L-V@iZwLlV2 z`qa2+JKf?D3ckx~m_E__HcKxV{tap^p`)na7%^#dw1j$m?7l-s%d@UO7z<3)=AmNK zOv`VoONu8mkDgk4vTeA{(0W?d3Mc)s+!l7H#$}t$>4#}T8}-gsC`K1^fc<~%2to!8R{w%eC>}D z&vVbGWQHOdR);?fcG58ee$}1PY>9|AuCTsv%*$Xz9$TD?E0r#aBrP3&+Z(%arPH|S z`Csg3HX0VaTYll@O_rxZVJnRN{bnI;K%})e1rG$pmm$%IgVp=GMh?7C+(7GXdHJZP z@5*Dfyt0ro!Pf1r;Z1ILMja=|MoWHcp*?-`4)#h{Bzd%q*8*)z%(&3@BiPr6$`J^U^Qnbc;vNryybtJqT8Qb;E)Ek2iUn~ZHs~G?@+DTELICWK_QE((j4B;~ zjR9jo9;7OUyy8A{>FMq3|ItE8K?Ij4R9Qh}f2Jwna{eOgv)Gh9s&qaL1Tz1K`O~8&*hUe`@Ln-}J0Rfu}P*smO4iT^=67A4LTNa2WQa~n}$!25G910c$ zNH`pc$YFm1<;@pMn0z*LC#En9y)?dCUk9BjiV@I+TP{o&CLOD7+2!FNuE)Q^J7^Xeb{pKTh^n2c63UgCtBP zn>afh9!DV%30OSIj)0wuS%tR&6p5iqRAS<=HiS7`<*-npWFTUh$~uJrRIpGkR96wm zln6w0fgpy4QbHh=ma6hbI?N4<7gr2v$dwiUzUG6#*tyo+6o}!fx{yd!*+MMOIT17C zK|tjQvYYE-M>6>lAT+<<7t{wi_kRo)heM%Y32a+58^?sk8(?4{yOl0d}tRWg^n|0uSeRTqmU+Rou?aY zR{1TxP*DI$w1r+FVi;`UCFKRbBB%r)p_atk*IjEwT^+8En0a<&5E7YqyE)Uz9qjPM j8b`y8cBKVi5t^$Yz%m%T)O4pCqyh7G_j5b#5}x)S(L1|$ diff --git a/data/icons/path20.png b/data/icons/path20.png deleted file mode 100644 index 1021d86405b81bbfa10a78e4ea7e8de8651462dd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6265 zcmeH~c|26@`^Se0i3}x0dZrh=5n)9dy7{@2W$nK}1;UGMw4KKFI*bDsofCmVTLRapoG zB5!AF=?eZX2M=W#De&9+aZ@e?BGnh>?#*{431A#9o5lzPVEj-H00V>!8U!MII^w;x zL_=F{ny&04X=@wZKW?nOq2aAt*0YT3YnpYF!-39rM>W5-?&dmOS7yKP;!Vdhv(`}y zvpn#<$pHneJ`tCL9 zFZEGjmmT`89^8bMS;xkQE)kW&&Ii263@a;9E?zMezGTn#k(pUQDm>=-ZQ@nR4X@oZ zXXM*XM>}cx9%6N#VlV2bG~(1+Y!rME>qfeDQ?}<2g7c)cG9pIWite?%Pz_btE`ZC+K`}m%ZhqnK730>TM zI?Q(@P|$p2UHEIIvuW0~Ua*=bk052?he+K{_DfRiOI7ESP=~$r z&g5yvjz;cXs1I9fxKk=n#~?Dbs47BFWzu=saXq+>mX!zx+}9EL51AFN+PYNhJk9fx zukJRkVx6OIPU|Bb594@n{fYdmL;h+7B}Q+`f#H(vAzdR0zBdv_hCeLJ%~8V> zZ9iM?&f2%5D1QIT9?RAG5bL$tFxFCu)oH7Xyj`1KHW<+gm7L6i%rI3|>B8aVH(WIO-jl*pt@l{($a^}z z;Lv_8pf^W#+J^irVA3to6JYx;8y>k{CcS2`-hYq%yV{EF$D6yLUK8ZnMicXvmb{{g zc*Wd)3%|#ymQy>b`ew#2O0F4;XUlYSL2rpZxpW(^Jl)oDL)h%Fi7^qXapYm*;aK^% zoabc=(wB})6fm!O7iQFJss-?N#uRJ4_S|hyN?L!%Vb#QieVNyI)}Bs2;{&+f4f%lw z2+ODPJA$_^ZOC~jGIn?&)p9qAAI(dbmvi0m&s5rj74&Gq7D!oQ#X#iFCo7>@<5O2Q zBuRaZ6ty*W8Y|Csz3^c*X2~YV?~Zb7-FvC!gYT$Z^>I41`s<-7zn6+%qxRdIPX;TV zh#iM2YA3mM_#H0q`O7fr$i~H}7!3c|`x|*WIMl77x)=I(tOOM;H`_%2lzIsnTh(<=rmDWWy~I9qX=T)?jKskE z&PuW$-M;%%zzEx{a?#9+_s^F|CR)T=20mZ(q2{E|2~e3+4NopQevsVuZZt*l(T4qY zI%#%&2jVVBM~-fT*y%T^TU&3k3?GCA?1-gikZo197*rFkke`BX(is}e&t8A)_?>BJ zQq5`Gb!XS{g16}0GThpg<)+%u*m1X^?zA0kRYRQ=aV!VAR^4Tv2paV!jk>+Z6rN1( zD{%oPlwZ}AS3G#U;VRz#?@pVN+cJ;0>u$B(YQH5|O-3z0Gc>wBG9HoQP^YX+xQ>6T zpB<4S|NQj$dTl-PCjzC~+*5+LS@|;j&J6(ywsL2kV=xPfVLC@@NF#l^psV?ij{s8y+H1ZY-FZ% zI7BWd&AG{J*`$5*^<>%H-N=&}k(`osD4B@r%}75brPp^eZ}&fGzkd7z8U1y!)>{7~ zri?QOg_4^%ni8LHrEw$wIu|LMT=2yCu4>%Ax6HE@$flzNThaX@r$+VRU8j1D<>T%Z z%iRe*fcW&x)EMJ6THREIzOh=9E`S!)n_>4a8-%Sy$kIP0W=~3(yZ2!14`{n2nR8bt zy;bP@Izp&>9zClNU6pb3iyz0pWaG)c^oJCJs8`nzhK$iE7!1DZNFP$1exI`QY~p@b z8LsdIG)%ERLCtT-+R>=ZHSX-9S36e-O?$#uKP`367T!xgGrfi&DsY&(QPK0f@PW3O z^V)~z_Yf+)Zl#PO&0t}v8+`t)IZKs-C@TU zX-Cy#%T;Wui(kBGCO@ve<>MvoWd@y=2nyl2@{cNw*~=ox4uZkd*P(&W+M1NH25d*l*heSez%yE+$gVe75UDn(cG6t^s^ zcXzxHzILGSZs@@x&-|i~MxW(17VQB}4gX_(v<7}0W)>Sw)XA-}PM;;NUxEGS@Angl z*Y+lClfAC9>!tT5c~xq=!mLy!JwW+_*3E2NrNPjk^hC^Afr=k~^}tj|kgxWp@m1Fz zZJ704c5+7Z=EH|%o2n`TC#dUTipdME^vboVD|KcixGhm-fZGpmM+YK>%|w!@ zY%+ipGCAP(1OhQO6>>yK$=ML`TP_6)v9n7TwRv`e3ukka2O8Mc>3FZdQr9-8l zfIxr=n)1L=F~1CHW9R7n!$T|qox$YHd4Xd8V##OF{uS$&*u*_^>HHiB=>CKIi}m;1 z=ZrxsM@OP1n-VMz&(6{WE*_sqWm6bb;{0C#N5&W$8Y1vm8VP~J7@!d(l0F7OGs55~ zcnk?o!5jR9vSac1Bo+k_qd+*40dmNO1^|^r!XS){NFV}FAs~zl0StmdBVcg)hGd*R z4fhjb3zq>_B`NUdsKh8Lh|)I#a0Ubt9)ZSE&|oxF0>Y3+Fhl@o10zEM8K4o!ggF$I zLbPUcnIv#J8B7u#Kyg^~xel@5L^EeQ6F3%${us95EKIS=|C&1-_l_+Ln&`AAxu6SCAU^1YvBypXBfH^Ff3(=LQ1(=DR3P*}(p1PRjMaS_}LDu})|#4uJ+g`tDc^5kny2 zvEV5YjfSJXC5#eZ)!#EVM*Sa6jOPq~S_VMB`8IHQ0aq*3kLBu{W?~uti?45U@n0MP zME@D&xAgrZ*B`llOM%}q{!?9lA{5yC7?L1)FVqE5J{4q zrJ1|oz0}rw7d?UHQsd9dD!c9k_`0vT;$VJNiUiY)J9oqrhC7yPmz?%q1_jPq{liOhS5q)pEPGKbjdP_!P_dBr=6E z23K4?>ThJfH(sha9+Msxy1C1_Kc_DIfV-N=cm^obM~gJ_@IT^*eYlEg#jmmeyOynJ!{do)8eGidEWAN3)SPXYZklWq)3{VUBUHS6Vb&?OZ;D_z;!%DI>+7Hr9y>-(&z{uGP{Y+J zb=Rz&?ksH+iJE#jDe857E)$lwJN{nVxpF~>;x<-Vnx;r(zj$P`@9uLUz0+~IY0bgmF+l+%ZJpCpF8FWQhbW?9;ba!ELWdL_~cP?peYja~^aAhuUa%Y?FJQ@H10XIoR zK~yM_jgmhvL{SjM&%9Oo7YTMLGz%ws)~H1CJIeN?*DO=dPQvs*J86J2)w%92d49tXMh`uaSc>rGa1kT+Q2jL<*^NH0T%jy08L>r U|26I@$^ZZW07*qoM6N<$g6#{bzW@LL diff --git a/data/icons/poweroff.png b/data/icons/poweroff.png deleted file mode 100644 index 1fb1e75c828d38f907b7ff7556dc73de0455ff10..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 599 zcmV-d0;v6oP)pF8FWQhbW?9;ba!ELWdL_~cP?peYja~^aAhuUa%Y?FJQ@H10pv+U zK~yM_jgY--lTjGOf6sm2bnzpxR7tEc5sm0#Qi^uaKR~1y-av7%Aa!zZut@(0QOV+0 zce_YYQ$HZ6xL7QeYLh__ba_pn6&(~EY~SWS4sTLZNs4E=mwV57&N+`m7o>9eQ_=Y0 zg;?TH^~dsuPn|fXn^=)!z;;!Jx^djUPTqu~7c9=ndgcDde~JBB@1P@E7WB4XnYq61 zoXqCO6uk7yg@&HC=i4)?1t4xlh) z>hB(w5ncj)HVB?{8;}|-B#gL^fnMN6ty+5K0vI=Pwh;vL0)sXP-Y0Wj(LtXQi7e~t zN&;hswPDAB9f0qw+0k&BO(X|S?-n)pfD>JF3$MhOGydBLOB=+k?^M?FtS~C*5YPvF lQ)J$#z3W$JN@3j)e*jLFrNd8l&ny4{002ovPDHLkV1h8c408Yg diff --git a/development b/development deleted file mode 120000 index 1c69f2fb..00000000 --- a/development +++ /dev/null @@ -1 +0,0 @@ -/home/bill/src/lua-scripts.local/development/ \ No newline at end of file diff --git a/tools/script_manager.lua b/tools/script_manager.lua index 8beed26a..71609321 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -1,6 +1,6 @@ --[[ This file is part of darktable, - copyright (c) 2018, 2020, 2023, 2024 Bill Ferguson + copyright (c) 2018, 2020, 2023 Bill Ferguson darktable is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -22,9 +22,9 @@ manage the lua scripts. On startup script_manager scans the lua scripts directory to see what scripts are present. - Scripts are sorted by 'folder' based on what sub-directory they are in. With no - additional script repositories iinstalled, the folders are contrib, examples, official - and tools. When a folder is selected the buttons show the script name and whether the + Scripts are sorted by 'category' based on what sub-directory they are in. With no + additional script repositories iinstalled, the categories are contrib, examples, official + and tools. When a category is selected the buttons show the script name and whether the script is started or stopped. The button is a toggle, so if the script is stopped click the button to start it and vice versa. @@ -60,9 +60,7 @@ local debug = require "darktable.debug" local gettext = dt.gettext.gettext --- Tell gettext where to find the .mo file translating messages for a particular domain -dt.gettext.bindtextdomain("script_manager", dt.configuration.config_dir .. "/lua/locale/") - +dt.gettext.bindtextdomain("script_manager", dt.configuration.config_dir .."/lua/locale/") local function _(msgid) return gettext(msgid) @@ -70,34 +68,30 @@ end -- api check -du.check_min_api_version("9.3.0", "script_manager") +du.check_min_api_version("5.0.0", "script_manager") -- - - - - - - - - - - - - - - - - - - - - - - - -- C O N S T A N T S -- - - - - - - - - - - - - - - - - - - - - - - - -- path separator -local PS = dt.configuration.running_os == "windows" and "\\" or "/" +local PS = dt.configuration.running_os == "windows" and "\\" or "/" -- command separator -local CS = dt.configuration.running_os == "windows" and "&" or ";" - -local MODULE = "script_manager" +local CS = dt.configuration.running_os == "windows" and "&" or ";" -local MIN_BUTTONS_PER_PAGE = 5 -local MAX_BUTTONS_PER_PAGE = 20 -local DEFAULT_BUTTONS_PER_PAGE = 10 +local MODULE = "script_manager" -local DEFAULT_LOG_LEVEL = log.error +local MIN_BUTTONS_PER_PAGE = 5 +local MAX_BUTTONS_PER_PAGE = 20 +local DEFAULT_BUTTONS_PER_PAGE = 10 -local LUA_DIR = dt.configuration.config_dir .. PS .. "lua" -local LUA_SCRIPT_REPO = "https://github.com/darktable-org/lua-scripts.git" +local DEFAULT_LOG_LEVEL = log.error -local LUA_API_VER = "API-" .. dt.configuration.api_version_string +local LUA_DIR = dt.configuration.config_dir .. PS .. "lua" +local LUA_SCRIPT_REPO = "https://github.com/darktable-org/lua-scripts.git" --- local POWER_ICON = dt.configuration.config_dir .. "/lua/data/data/icons/power.png" -local POWER_ICON = dt.configuration.config_dir .. "/lua/data/icons/path20.png" -local BLANK_ICON = dt.configuration.config_dir .. "/lua/data/icons/blank20.png" +local LUA_API_VER = "API-" .. dt.configuration.api_version_string -- - - - - - - - - - - - - - - - - - - - - - - - -- P R E F E R E N C E S @@ -134,7 +128,7 @@ sm.event_registered = false -- set up tables to contain all the widgets and choices sm.widgets = {} -sm.folders = {} +sm.categories = {} -- set log level for functions @@ -143,14 +137,14 @@ sm.log_level = DEFAULT_LOG_LEVEL --[[ sm.scripts is a table of tables for containing the scripts - It is organized as into folder (folder) subtables containing + It is organized as into category (folder) subtables containing each script definition, which is a table sm.scripts- | - - folder------------| + - category------------| | - script - - folder----| | + - category----| | - script| | - script - script| @@ -158,7 +152,7 @@ sm.log_level = DEFAULT_LOG_LEVEL and a script table looks like name the name of the script file without the lua extension - path folder (folder), path separator, path, name without the lua extension + path category (folder), path separator, path, name without the lua extension doc the header comments from the script to be used as a tooltip script_name the folder, path separator, and name without the lua extension running true if running, false if not, hidden if running but the @@ -184,7 +178,10 @@ sm.page_status = {} sm.page_status.num_buttons = DEFAULT_BUTTONS_PER_PAGE sm.page_status.buttons_created = 0 sm.page_status.current_page = 0 -sm.page_status.folder = "" +sm.page_status.category = "" + +-- use color in the interface? +sm.use_color = false -- installed script repositories sm.installed_repositories = { @@ -215,24 +212,17 @@ end local function pref_read(name, pref_type) local old_log_level = set_log_level(sm.log_level) - log.msg(log.debug, "name is " .. name .. " and type is " .. pref_type) - local val = dt.preferences.read(MODULE, name, pref_type) - log.msg(log.debug, "read value " .. tostring(val)) - restore_log_level(old_log_level) return val end local function pref_write(name, pref_type, value) local old_log_level = set_log_level(sm.log_level) - log.msg(log.debug, "writing value " .. tostring(value) .. " for name " .. name) - dt.preferences.write(MODULE, name, pref_type, value) - restore_log_level(old_log_level) end @@ -242,15 +232,12 @@ end local function get_repo_status(repo) local old_log_level = set_log_level(sm.log_level) - - local p = dtsys.io_popen("cd " .. repo .. CS .. "git status") - + local p = io.popen("cd " .. repo .. CS .. "git status") if p then local data = p:read("*a") p:close() return data end - log.msg(log.error, "unable to get status of " .. repo) restore_log_level(old_log_level) return nil @@ -258,11 +245,8 @@ end local function get_current_repo_branch(repo) local old_log_level = set_log_level(sm.log_level) - local branch = nil - - local p = dtsys.io_popen("cd " .. repo .. CS .. "git branch --all") - + local p = io.popen("cd " .. repo .. CS .. "git branch --all") if p then local data = p:read("*a") p:close() @@ -270,29 +254,23 @@ local function get_current_repo_branch(repo) for _, b in ipairs(branches) do log.msg(log.debug, "branch for testing is " .. b) branch = string.match(b, "^%* (.-)$") - if branch then log.msg(log.info, "current repo branch is " .. branch) return branch end - end end - if not branch then log.msg(log.error, "no current branch detected in repo_data") end - restore_log_level(old_log_level) return nil end local function get_repo_branches(repo) local old_log_level = set_log_level(sm.log_level) - local branches = {} - local p = dtsys.io_popen("cd " .. repo .. CS .. "git pull --all" .. CS .. "git branch --all") - + local p = io.popen("cd " .. repo .. CS .. "git pull --all" .. CS .. "git branch --all") if p then local data = p:read("*a") p:close() @@ -307,14 +285,12 @@ local function get_repo_branches(repo) end end end - restore_log_level(old_log_level) return branches end local function is_repo_clean(repo_data) local old_log_level = set_log_level(sm.log_level) - if string.match(repo_data, "\n%s-%a.-%a:%s-%a%g-\n") then log.msg(log.info, "repo is dirty") return false @@ -322,17 +298,13 @@ local function is_repo_clean(repo_data) log.msg(log.info, "repo is clean") return true end - restore_log_level(old_log_level) end local function checkout_repo_branch(repo, branch) local old_log_level = set_log_level(sm.log_level) - log.msg(log.info, "checkout out branch " .. branch .. " from repository " .. repo) - - dtsys.os_execute("cd " .. repo .. CS .. "git checkout " .. branch) - + os.execute("cd " .. repo .. CS .. "git checkout " .. branch) restore_log_level(old_log_level) end @@ -342,20 +314,16 @@ end local function update_combobox_choices(combobox, choice_table, selected) local old_log_level = set_log_level(sm.log_level) - local items = #combobox local choices = #choice_table - for i, name in ipairs(choice_table) do combobox[i] = name end - if choices < items then for j = items, choices + 1, -1 do combobox[j] = nil end end - if not selected then selected = 1 end @@ -366,10 +334,8 @@ end local function string_trim(str) local old_log_level = set_log_level(sm.log_level) - local result = string.gsub(str, "^%s+", "") result = string.gsub(result, "%s+$", "") - restore_log_level(old_log_level) return result end @@ -378,76 +344,18 @@ local function string_dequote(str) return string.gsub(str, "['\"]", "") end -local function string_dei18n(str) - return string.match(str, "%_%((.+)%)") -end - -local function string_chop(str) - return str:sub(1, -2) -end - ------------------ -- script handling ------------------ -local function add_script_folder(folder) - local old_log_level = set_log_level(sm.log_level) - - if #sm.folders == 0 or not string.match(du.join(sm.folders, " "), ds.sanitize_lua(folder)) then - table.insert(sm.folders, folder) - sm.scripts[folder] = {} - log.msg(log.debug, "created folder " .. folder) - end - - restore_log_level(old_log_level) -end - -local function get_script_metadata(script) +local function add_script_category(category) local old_log_level = set_log_level(sm.log_level) - -- set_log_level(log.debug) - - log.msg(log.debug, "processing metatdata for " .. script) - - local description = nil - local metadata = nil - - f = io.open(LUA_DIR .. PS .. script .. ".lua") - if f then - -- slurp the file - local content = f:read("*all") - f:close() - -- grab the script_data.metadata table - description = string.match(content, "script_data%.metadata = %{\r?\n(.-)\r?\n%}") - else - log.msg(log.error, "cant read from " .. script) - end - - if description then - metadata = "" - -- format it into a string block for display - local lines = du.split(description, "\n") - log.msg(log.debug, "got " .. #lines .. " lines") - local first = 1 - for i = 1, #lines do - log.msg(log.debug, "splitting line " .. lines[i]) - local parts = du.split(lines[i], " = ") - log.msg(log.debug, "got value " .. parts[1] .. " and data " .. parts[2]) - if string.match(parts[2], "%_%(") then - parts[2] = _(string_dequote(string_dei18n(parts[2]))) - else - parts[2] = string_dequote(parts[2]) - end - if string.match(parts[2], ",$") then - parts[2] = string_chop(parts[2]) - end - metadata = metadata .. string.format("%s%-10s\t%s", first and "" or "\n", parts[1], parts[2]) - first = nil - end - log.msg(log.debug, "script data is \n" .. metadata) + if #sm.categories == 0 or not string.match(du.join(sm.categories, " "), ds.sanitize_lua(category)) then + table.insert(sm.categories, category) + sm.scripts[category] = {} + log.msg(log.debug, "created category " .. category) end - restore_log_level(old_log_level) - return metadata end local function get_script_doc(script) @@ -461,9 +369,7 @@ local function get_script_doc(script) -- assume that the second block comment is the documentation description = string.match(content, "%-%-%[%[.-%]%].-%-%-%[%[(.-)%]%]") else - - log.msg(log.error, "can't read from " .. script) - + log.msg(log.error, "Cant read from " .. script) end if description then restore_log_level(old_log_level) @@ -476,28 +382,18 @@ end local function activate(script) local old_log_level = set_log_level(sm.log_level) - local status = nil -- status of start function local err = nil -- error message returned if module doesn't start - log.msg(log.info, "activating " .. script.name) - if script.running == false then - script_manager_running_script = script.name - status, err = du.prequire(script.path) log.msg(log.debug, "prequire returned " .. tostring(status) .. " and for err " .. tostring(err)) - script_manager_running_script = nil - if status then pref_write(script.script_name, "bool", true) - - log.msg(log.screen, _(string.format("loaded %s", script.script_name))) - + log.msg(log.screen, string.format(_("loaded %s"), script.script_name)) script.running = true - if err ~= true then log.msg(log.debug, "got lib data") script.data = err @@ -507,20 +403,17 @@ local function activate(script) else script.data = nil end - else - - log.msg(log.screen, _(string.format("%s failed to load", script.script_name))) - log.msg(log.error, "error loading " .. script.script_name) - log.msg(log.error, "error message: " .. err) - + log.msg(log.screen, string.format(_("%s failed to load"), script.script_name)) + log.msg(log.error, "Error loading " .. script.script_name) + log.msg(log.error, "Error message: " .. err) + end else -- script is a lib and loaded but hidden and the user wants to reload script.data.restart() script.running = true status = true pref_write(script.script_name, "bool", true) end - restore_log_level(old_log_level) return status end @@ -535,13 +428,9 @@ local function deactivate(script) -- deactivate it.... local old_log_level = set_log_level(sm.log_level) - pref_write(script.script_name, "bool", false) - if script.data then - script.data.destroy() - if script.data.destroy_method then if string.match(script.data.destroy_method, "hide") then script.running = "hidden" @@ -553,57 +442,44 @@ local function deactivate(script) package.loaded[script.script_name] = nil script.running = false end - log.msg(log.info, "turned off " .. script.script_name) - - log.msg(log.screen, _(string.format("%s stopped", script.name))) - + log.msg(log.screen, string.format(_("%s stopped"), script.name)) else script.running = false - log.msg(log.info, "setting " .. script.script_name .. " to not start") - - log.msg(log.screen, _(string.format("%s will not start when darktable is restarted", script.name))) - + log.msg(log.screen, string.format(_("%s will not start when darktable is restarted"), script.name)) end - restore_log_level(old_log_level) end -local function add_script_name(name, path, folder) +local function add_script_name(name, path, category) local old_log_level = set_log_level(sm.log_level) - - log.msg(log.debug, "folder is " .. folder) + log.msg(log.debug, "category is " .. category) log.msg(log.debug, "name is " .. name) - local script = { name = name, - path = folder .. "/" .. path .. name, + path = category .. "/" .. path .. name, running = false, - doc = get_script_doc(folder .. "/" .. path .. name), - metadata = get_script_metadata(folder .. "/" .. path .. name), - script_name = folder .. "/" .. name, + doc = get_script_doc(category .. "/" .. path .. name), + script_name = category .. "/" .. name, data = nil } - - table.insert(sm.scripts[folder], script) - + table.insert(sm.scripts[category], script) if pref_read(script.script_name, "bool") then activate(script) else pref_write(script.script_name, "bool", false) end - restore_log_level(old_log_level) end local function process_script_data(script_file) local old_log_level = set_log_level(sm.log_level) - -- the script file supplied is folder/filename.filetype - -- the following pattern splits the string into folder, path, name, fileename, and filetype + -- the script file supplied is category/filename.filetype + -- the following pattern splits the string into category, path, name, fileename, and filetype -- for example contrib/gimp.lua becomes - -- folder - contrib + -- category - contrib -- path - -- name - gimp.lua -- filename - gimp @@ -620,42 +496,14 @@ local function process_script_data(script_file) log.msg(log.info, "processing " .. script_file) -- add the script data - local folder,path,name,filename,filetype = string.match(script_file, pattern) + local category,path,name,filename,filetype = string.match(script_file, pattern) - if folder and name and path then - log.msg(log.debug, "folder is " .. folder) + if category and name and path then + log.msg(log.debug, "category is " .. category) log.msg(log.debug, "name is " .. name) - add_script_folder(folder) - add_script_name(name, path, folder) - end - - restore_log_level(old_log_level) -end - -local function ensure_lib_in_search_path(line) - local old_log_level = set_log_level(sm.log_level) - - log.msg(log.debug, "line is " .. line) - - if string.match(line, ds.sanitize_lua(dt.configuration.config_dir .. PS .. "lua/lib")) then - log.msg(log.debug, line .. " is already in search path, returning...") - return - end - - local pattern = dt.configuration.running_os == "windows" and "(.+)\\lib\\.+lua" or "(.+)/lib/.+lua" - local path = string.match(line, pattern) - - log.msg(log.debug, "extracted path is " .. path) - log.msg(log.debug, "package.path is " .. package.path) - - if not string.match(package.path, ds.sanitize_lua(path)) then - - log.msg(log.debug, "path isn't in package.path, adding...") - - package.path = package.path .. ";" .. path .. "/?.lua" - - log.msg(log.debug, "new package.path is " .. package.path) + add_script_category(category) + add_script_name(name, path, category) end restore_log_level(old_log_level) @@ -692,20 +540,15 @@ end local function scan_scripts(script_dir) local old_log_level = set_log_level(sm.log_level) - local script_count = 0 local find_cmd = "find -L " .. script_dir .. " -name \\*.lua -print | sort" - if dt.configuration.running_os == "windows" then find_cmd = "dir /b/s \"" .. script_dir .. "\\*.lua\" | sort" end - log.msg(log.debug, "find command is " .. find_cmd) - -- scan the scripts - local output = dtsys.io_popen(find_cmd) + local output = io.popen(find_cmd) for line in output:lines() do - log.msg(log.debug, "line is " .. line) local l = string.gsub(line, ds.sanitize_lua(LUA_DIR) .. PS, "") -- strip the lua dir off local script_file = l:sub(1,-5) -- strip off .lua\n if not string.match(script_file, "script_manager") then -- let's not include ourself @@ -721,7 +564,6 @@ local function scan_scripts(script_dir) end end end - restore_log_level(old_log_level) return script_count end @@ -733,9 +575,7 @@ local function update_scripts() local git = sm.executables.git if not git then - - log.msg(log.screen, _("ERROR: git not found. Install or specify the location of the git executable.")) - + dt.print(_("ERROR: git not found, install or specify the location of the git executable.")) return end @@ -749,7 +589,7 @@ local function update_scripts() end if result == 0 then - log.msg(log.screen, _("lua scripts successfully updated")) + dt.print(_("lua scripts successfully updated")) end restore_log_level(old_log_level) @@ -762,85 +602,65 @@ end local function update_script_update_choices() local old_log_level = set_log_level(sm.log_level) - local installs = {} local pref_string = "" - for i, repo in ipairs(sm.installed_repositories) do table.insert(installs, repo.name) pref_string = pref_string .. i .. "," .. repo.name .. "," .. repo.directory .. "," end - update_combobox_choices(sm.widgets.update_script_choices, installs, 1) - log.msg(log.debug, "repo pref string is " .. pref_string) pref_write("installed_repos", "string", pref_string) - restore_log_level(old_log_level) end local function scan_repositories() local old_log_level = set_log_level(sm.log_level) - local script_count = 0 local find_cmd = "find -L " .. LUA_DIR .. " -name \\*.git -print | sort" - if dt.configuration.running_os == "windows" then find_cmd = "dir /b/s /a:d " .. LUA_DIR .. PS .. "*.git | sort" end - log.msg(log.debug, "find command is " .. find_cmd) - - local output = dtsys.io_popen(find_cmd) - + local output = io.popen(find_cmd) for line in output:lines() do local l = string.gsub(line, ds.sanitize_lua(LUA_DIR) .. PS, "") -- strip the lua dir off - local folder = string.match(l, "(.-)" .. PS) -- get everything to the first / - - if folder then -- if we have a folder (.git doesn't) - - log.msg(log.debug, "found folder " .. folder) - - if not string.match(folder, "plugins") and not string.match(folder, "%.git") then -- skip plugins - + local category = string.match(l, "(.-)" .. PS) -- get everything to teh first / + if category then -- if we have a category (.git doesn't) + log.msg(log.debug, "found category " .. category) + if not string.match(category, "plugins") and not string.match(category, "%.git") then -- skip plugins if #sm.installed_repositories == 1 then - log.msg(log.debug, "only 1 repo, adding " .. folder) - table.insert(sm.installed_repositories, {name = folder, directory = LUA_DIR .. PS .. folder}) + log.msg(log.debug, "only 1 repo, adding " .. category) + table.insert(sm.installed_repositories, {name = category, directory = LUA_DIR .. PS .. category}) else log.msg(log.debug, "more than 1 repo, we have to search the repos to make sure it's not there") local found = nil - for _, repo in ipairs(sm.installed_repositories) do - if string.match(repo.name, ds.sanitize_lua(folder)) then + if string.match(repo.name, ds.sanitize_lua(category)) then log.msg(log.debug, "matched " .. repo.name) found = true break end end - if not found then - table.insert(sm.installed_repositories, {name = folder, directory = LUA_DIR .. PS .. folder}) + table.insert(sm.installed_repositories, {name = category, directory = LUA_DIR .. PS .. category}) end - end end end end - update_script_update_choices() - restore_log_level(old_log_level) end local function install_scripts() local old_log_level = set_log_level(sm.log_level) - local url = sm.widgets.script_url.text - local folder = sm.widgets.new_folder.text + local category = sm.widgets.new_category.text - if string.match(du.join(sm.folders, " "), ds.sanitize_lua(folder)) then - log.msg(log.screen, _(string.format("folder %s is already in use. Please specify a different folder name.", folder))) - log.msg(log.error, "folder " .. folder .. " already exists, returning...") + if string.match(du.join(sm.categories, " "), ds.sanitize_lua(category)) then + log.msg(log.screen, string.format(_("category %s is already in use, please specify a different category name."), category)) + log.msg(log.error, "category " .. category .. " already exists, returning...") restore_log_level(old_log_level) return end @@ -850,12 +670,12 @@ local function install_scripts() local git = sm.executables.git if not git then - log.msg(log.screen, _("ERROR: git not found. Install or specify the location of the git executable.")) + dt.print(_("ERROR: git not found, install or specify the location of the git executable.")) restore_log_level(old_log_level) return end - local git_command = "cd " .. LUA_DIR .. " " .. CS .. " " .. git .. " clone " .. url .. " " .. folder + local git_command = "cd " .. LUA_DIR .. " " .. CS .. " " .. git .. " clone " .. url .. " " .. category log.msg(log.debug, "update git command is " .. git_command) if dt.configuration.running_os == "windows" then @@ -867,34 +687,30 @@ local function install_scripts() log.msg(log.info, "result from import is " .. result) if result == 0 then - local count = scan_scripts(LUA_DIR .. PS .. folder) - + local count = scan_scripts(LUA_DIR .. PS .. category) if count > 0 then - update_combobox_choices(sm.widgets.folder_selector, sm.folders, sm.widgets.folder_selector.selected) - dt.print(_("scripts successfully installed into folder ") .. folder) - table.insert(sm.installed_repositories, {name = folder, directory = LUA_DIR .. PS .. folder}) + update_combobox_choices(sm.widgets.category_selector, sm.categories, sm.widgets.category_selector.selected) + dt.print(string.format(_("scripts successfully installed into category "), category)) + table.insert(sm.installed_repositories, {name = category, directory = LUA_DIR .. PS .. category}) update_script_update_choices() - - for i = 1, #sm.widgets.folder_selector do - if string.match(sm.widgets.folder_selector[i], ds.sanitize_lua(folder)) then - log.msg(log.debug, "setting folder selector to " .. i) - sm.widgets.folder_selector.selected = i + for i = 1, #sm.widgets.category_selector do + if string.match(sm.widgets.category_selector[i], ds.sanitize_lua(category)) then + log.msg(log.debug, "setting category selector to " .. i) + sm.widgets.category_selector.selected = i break end i = i + 1 end - log.msg(log.debug, "clearing text fields") sm.widgets.script_url.text = "" - sm.widgets.new_folder.text = "" + sm.widgets.new_category.text = "" sm.widgets.main_menu.selected = 3 else - log.msg(log.screen, _("No scripts found to install")) - log.msg(log.error, "scan_scripts returned " .. count .. " scripts found. Not adding to folder_selector") + dt.print(_("no scripts found to install")) + log.msg(log.error, "scan_scripts returned " .. count .. " scripts found. Not adding to category_selector") end - else - log.msg(log.screen, _("failed to download scripts")) + dt.print(_("failed to download scripts")) end restore_log_level(old_log_level) @@ -903,101 +719,102 @@ end local function clear_button(number) local old_log_level = set_log_level(sm.log_level) - local button = sm.widgets.buttons[number] - local label = sm.widgets.labels[number] - - button.image = BLANK_ICON + button.label = "" button.tooltip = "" button.sensitive = false - label.label = "" - button.name = "" - + --button.name = "" restore_log_level(old_log_level) end -local function find_script(folder, name) +local function find_script(category, name) local old_log_level = set_log_level(sm.log_level) - - log.msg(log.debug, "looking for script " .. name .. " in folder " .. folder) - - for _, script in ipairs(sm.scripts[folder]) do + log.msg(log.debug, "looking for script " .. name .. " in category " .. category) + for _, script in ipairs(sm.scripts[category]) do if string.match(script.name, "^" .. ds.sanitize_lua(name) .. "$") then return script end end - restore_log_level(old_log_level) return nil end -local function populate_buttons(folder, first, last) +local function populate_buttons(category, first, last) local old_log_level = set_log_level(sm.log_level) - - log.msg(log.debug, "folder is " .. folder .. " and first is " .. first .. " and last is " .. last) - + log.msg(log.debug, "category is " .. category .. " and first is " .. first .. " and last is " .. last) local button_num = 1 - for i = first, last do - local script = sm.scripts[folder][i] - local button = sm.widgets.buttons[button_num] - local label = sm.widgets.labels[button_num] - + script = sm.scripts[category][i] + button = sm.widgets.buttons[button_num] if script.running == true then - button.name = "pb_on" + if sm.use_color then + button.label = script.name + button.name = "sm_started" + else + button.label = string.format(_("%s started"), script.name) + end else - button.name = "pb_off" + if sm.use_color then + button.label = script.name + button.name = "sm_stopped" + else + button.label = string.format(_("%s stopped"), script.name) + end end - - button.image = POWER_ICON - label.label = script.name - label.name = "pb_label" - button.ellipsize = "end" + button.ellipsize = "middle" button.sensitive = true - label.tooltip = script.metadata and script.metadata or script.doc - + button.tooltip = script.doc button.clicked_callback = function (this) - local cb_script = script + local script_name = nil local state = nil - if cb_script then - log.msg(log.debug, "found script " .. cb_script.name .. " with path " .. cb_script.path) - if cb_script.running == true then - log.msg(log.debug, "deactivating " .. cb_script.name .. " on " .. cb_script.path) - deactivate(cb_script) - this.name = "pb_off" + if sm.use_color then + script_name = string.match(this.label, "(.+)") + else + script_name, state = string.match(this.label, "(.-) (.+)") + end + local script = find_script(sm.widgets.category_selector.value, script_name) + if script then + log.msg(log.debug, "found script " .. script.name .. " with path " .. script.path) + if script.running == true then + log.msg(log.debug, "deactivating " .. script.name .. " on " .. script.path .. " for button " .. this.label) + deactivate(script) + if sm.use_color then + this.name = "sm_stopped" + else + this.label = string.format(_("%s stopped"), script.name) + end else - log.msg(log.debug, "activating " .. cb_script.name .. " on " .. script.path) - local result = activate(cb_script) + log.msg(log.debug, "activating " .. script.name .. " on " .. script.path .. " for button " .. this.label) + local result = activate(script) if result then - this.name = "pb_on" + if sm.use_color then + this.name = "sm_started" + else + this.label = string.format(_("%s started"), script.name) + end end end + else + log.msg(log.error, "script " .. script_name .. " not found") end end - button_num = button_num + 1 end - if button_num <= sm.page_status.num_buttons then for i = button_num, sm.page_status.num_buttons do clear_button(i) end end - restore_log_level(old_log_level) end local function paginate(direction) local old_log_level = set_log_level(sm.log_level) - - local folder = sm.page_status.folder - log.msg(log.debug, "folder is " .. folder) - - local num_scripts = #sm.scripts[folder] + local category = sm.page_status.category + log.msg(log.debug, "category is " .. category) + local num_scripts = #sm.scripts[category] log.msg(log.debug, "num_scripts is " .. num_scripts) - local max_pages = math.ceil(num_scripts / sm.page_status.num_buttons) - local cur_page = sm.page_status.current_page log.msg(log.debug, "max pages is " .. max_pages) @@ -1019,9 +836,7 @@ local function paginate(direction) log.msg(log.debug, "took path 2") cur_page = 1 end - log.msg(log.debug, "cur_page is " .. cur_page .. " and max_pages is " .. max_pages) - if cur_page == max_pages and cur_page == 1 then sm.widgets.page_forward.sensitive = false sm.widgets.page_back.sensitive = false @@ -1037,167 +852,115 @@ local function paginate(direction) end sm.page_status.current_page = cur_page - first = (cur_page * sm.page_status.num_buttons) - (sm.page_status.num_buttons - 1) - if first + sm.page_status.num_buttons > num_scripts then last = num_scripts else last = first + sm.page_status.num_buttons - 1 end + sm.widgets.page_status.label = string.format(_("page %d of %d"), cur_page, max_pages) - sm.widgets.page_status.label = _(string.format("page %d of %d", cur_page, max_pages)) - - populate_buttons(folder, first, last) - + populate_buttons(category, first, last) restore_log_level(old_log_level) end -local function change_folder(folder) +local function change_category(category) local old_log_level = set_log_level(sm.log_level) - - if not folder then - log.msg(log.debug "setting folder to selector value " .. sm.widgets.folder_selector.value) - sm.page_status.folder = sm.widgets.folder_selector.value + if not category then + log.msg(log.debug "setting category to selector value " .. sm.widgets.category_selector.value) + sm.page_status.category = sm.widgets.category_selector.value else - log.msg(log.debug, "setting catgory to argument " .. folder) - sm.page_status.folder = folder + log.msg(log.debug, "setting catgory to argument " .. category) + sm.page_status.category = category end paginate(2) - restore_log_level(old_log_level) end local function change_num_buttons() local old_log_level = set_log_level(sm.log_level) - cur_buttons = sm.page_status.num_buttons new_buttons = sm.widgets.num_buttons.value - pref_write("num_buttons", "integer", new_buttons) - if new_buttons < cur_buttons then - log.msg(log.debug, "took new is less than current branch") - for i = 1, cur_buttons - new_buttons do table.remove(sm.widgets.scripts) end - log.msg(log.debug, "finished removing widgets, now there are " .. #sm.widgets.buttons) elseif new_buttons > cur_buttons then - log.msg(log.debug, "took new is greater than current branch") - log.msg(log.debug, "number of scripts is " .. #sm.widgets.scripts) - log.msg(log.debug, "number of buttons is " .. #sm.widgets.buttons) - log.msg(log.debug, "number of labels is " .. #sm.widgets.labels) - log.msg(log.debug, "number of boxes is " .. #sm.widgets.boxes) - if new_buttons > sm.page_status.buttons_created then - for i = sm.page_status.buttons_created + 1, new_buttons do - log.msg(log.debug, "i is " .. i) table.insert(sm.widgets.buttons, dt.new_widget("button"){}) - log.msg(log.debug, "inserted new button") - log.msg(log.debug, "number of buttons is " .. #sm.widgets.buttons) - table.insert(sm.widgets.labels, dt.new_widget("label"){}) - log.msg(log.debug, "inserted new label") - log.msg(log.debug, "number of labels is " .. #sm.widgets.labels) - table.insert(sm.widgets.boxes, dt.new_widget("box"){ orientation = "horizontal", expand = false, fill = false, - sm.widgets.buttons[i], sm.widgets.labels[i]}) - log.msg(log.debug, "inserted new box") sm.page_status.buttons_created = sm.page_status.buttons_created + 1 end - end - log.msg(log.debug, "cur_buttons is " .. cur_buttons .. " and new_buttons is " .. new_buttons) log.msg(log.debug, #sm.widgets.buttons .. " buttons are available") - for i = cur_buttons + 1, new_buttons do log.msg(log.debug, "inserting button " .. i .. " into scripts widget") - table.insert(sm.widgets.scripts, sm.widgets.boxes[i]) + table.insert(sm.widgets.scripts, sm.widgets.buttons[i]) end - log.msg(log.debug, "finished adding widgets, now there are " .. #sm.widgets.buttons) else -- no change log.msg(log.debug, "no change, just returning") return end - sm.page_status.num_buttons = new_buttons log.msg(log.debug, "num_buttons set to " .. sm.page_status.num_buttons) paginate(2) -- force the buttons to repopulate sm.widgets.main_menu.selected = 3 -- jump back to start/stop scripts - restore_log_level(old_log_level) end local function load_preferences() local old_log_level = set_log_level(sm.log_level) - -- load the prefs and update settings -- update_script_choices - local pref_string = pref_read("installed_repos", "string") local entries = du.split(pref_string, ",") - while #entries > 2 do local num = table.remove(entries, 1) local name = table.remove(entries, 1) local directory = table.remove(entries, 1) - if not string.match(sm.installed_repositories[1].name, "^" .. ds.sanitize_lua(name) .. "$") then table.insert(sm.installed_repositories, {name = name, directory = directory}) end - end - update_script_update_choices() log.msg(log.debug, "updated installed scripts") - - -- folder selector - local val = pref_read("folder_selector", "integer") - + -- category selector + local val = pref_read("category_selector", "integer") if val == 0 then val = 1 end - - sm.widgets.folder_selector.selected = val - sm.page_status.folder = sm.widgets.folder_selector.value - log.msg(log.debug, "updated folder selector and set it to " .. sm.widgets.folder_selector.value) - + sm.widgets.category_selector.selected = val + sm.page_status.category = sm.widgets.category_selector.value + log.msg(log.debug, "updated category selector and set it to " .. sm.widgets.category_selector.value) -- num_buttons local val = pref_read("num_buttons", "integer") - if val == 0 then val = DEFAULT_BUTTONS_PER_PAGE end - sm.widgets.num_buttons.value = val log.msg(log.debug, "set page buttons to " .. val) - change_num_buttons() log.msg(log.debug, "paginated") - -- main menu local val = pref_read("main_menu_action", "integer") log.msg(log.debug, "read " .. val .. " for main menu") - if val == 0 then val = 3 end - sm.widgets.main_menu.selected = val log.msg(log.debug, "set main menu to val " .. val .. " which is " .. sm.widgets.main_menu.value) log.msg(log.debug, "set main menu to " .. sm.widgets.main_menu.value) - restore_log_level(old_log_level) end local function install_module() local old_log_level = set_log_level(sm.log_level) - if not sm.module_installed then dt.register_lib( "script_manager", -- Module name @@ -1211,13 +974,22 @@ local function install_module() ) sm.module_installed = true end - sm.run = true sm.use_color = pref_read("use_color", "bool") log.msg(log.debug, "set run to true, loading preferences") load_preferences() scan_repositories() - + --[[dt.print_log("\n\nsetting sm visible false\n\n") + dt.gui.libs["script_manager"].visible = false + dt.control.sleep(5000) + dt.print_log("setting sm visible true") + dt.gui.libs["script_manager"].visible = true + --[[dt.control.sleep(5000) + dt.print_log("setting sm expanded false") + dt.gui.libs["script_manager"].expanded = false + dt.control.sleep(5000) + dt.print_log("setting sm expanded true") + dt.gui.libs["script_manager"].expanded = true]] restore_log_level(old_log_level) end @@ -1236,28 +1008,22 @@ if check_for_updates then local repo = LUA_DIR if current_branch then - if sm.executables.git and clean and - (current_branch == "master" or string.match(current_branch, "^API%-")) then -- only make changes to clean branches local branches = get_repo_branches(LUA_DIR) - if current_branch ~= LUA_API_VER and current_branch ~= "master" then -- probably upgraded from an earlier api version so get back to master -- to use the latest version of script_manager to get the proper API checkout_repo_branch(repo, "master") - log.msg(log.screen, _("lua API version reset, please restart darktable")) - + log.msg(log.screen, "lua API version reset, please restart darktable") elseif LUA_API_VER == current_branch then -- do nothing, we are fine log.msg(log.debug, "took equal branch, doing nothing") - elseif string.match(LUA_API_VER, "dev") then -- we are on a dev API version, so checkout the dev -- api version or checkout/stay on master log.msg(log.debug, "took the dev branch") local match = false - for _, branch in ipairs(branches) do log.msg(log.debug, "checking branch " .. branch .. " against API " .. LUA_API_VER) if LUA_API_VER == branch then @@ -1266,7 +1032,6 @@ if check_for_updates then checkout_repo_branch(repo, branch) end end - if not match then if current_branch == "master" then log.msg(log.info, "staying on master, no dev branch yet") @@ -1275,33 +1040,25 @@ if check_for_updates then checkout_repo_branch(repo, "master") end end - elseif #branches > 0 and LUA_API_VER > branches[#branches] then log.msg(log.info, "no newer branches, staying on master") -- stay on master - else -- checkout the appropriate branch for API version if it exists log.msg(log.info, "checking out the appropriate API branch") - local match = false - for _, branch in ipairs(branches) do log.msg(log.debug, "checking branch " .. branch .. " against API " .. LUA_API_VER) - if LUA_API_VER == branch then match = true log.msg(log.info, "checking out repo branch " .. branch) checkout_repo_branch(repo, branch) log.msg(log.screen, "you must restart darktable to use the correct version of the lua") end - end - if not match then log.msg(log.warn, "no matching branch found for " .. LUA_API_VER) end - end end end @@ -1343,18 +1100,18 @@ sm.widgets.script_url = dt.new_widget("entry"){ tooltip = _("enter the URL of the git repository containing the scripts you wish to add") } -sm.widgets.new_folder = dt.new_widget("entry"){ +sm.widgets.new_category = dt.new_widget("entry"){ text = "", - placeholder = _("name of new folder"), - tooltip = _("enter a folder name for the additional scripts") + placeholder = _("name of new category"), + tooltip = _("enter a category name for the additional scripts") } sm.widgets.add_scripts = dt.new_widget("box"){ orientation = vertical, dt.new_widget("label"){label = _("URL to download additional scripts from")}, sm.widgets.script_url, - dt.new_widget("label"){label = _("new folder to place scripts in")}, - sm.widgets.new_folder, + dt.new_widget("label"){label = _("new category to place scripts in")}, + sm.widgets.new_category, dt.new_widget("button"){ label = _("install additional scripts"), clicked_callback = function(this) @@ -1369,8 +1126,6 @@ sm.widgets.allow_disable = dt.new_widget("check_button"){ clicked_callback = function(this) if this.value == true then sm.widgets.disable_scripts.sensitive = true - else - sm.widgets.disable_scripts.sensitive = false end end, } @@ -1382,62 +1137,41 @@ sm.widgets.disable_scripts = dt.new_widget("button"){ local LUARC = dt.configuration.config_dir .. PS .. "luarc" df.file_move(LUARC, LUARC .. ".disabled") log.msg(log.info, "lua scripts disabled") - log.msg(log.screen, _("lua scripts will not run the next time darktable is started")) + dt.print(_("lua scripts will not run the next time darktable is started")) end } sm.widgets.install_update = dt.new_widget("box"){ orientation = "vertical", - dt.new_widget("section_label"){label = _(" ")}, - dt.new_widget("label"){label = " "}, - dt.new_widget("label"){label = _("update scripts")}, - dt.new_widget("label"){label = " "}, + dt.new_widget("section_label"){label = _("update scripts")}, sm.widgets.update_script_choices, sm.widgets.update, - dt.new_widget("section_label"){label = " "}, - dt.new_widget("label"){label = " "}, - dt.new_widget("label"){label = _("add more scripts")}, - dt.new_widget("label"){label = " "}, + dt.new_widget("section_label"){label = _("add more scripts")}, sm.widgets.add_scripts, - dt.new_widget("section_label"){label = " "}, - dt.new_widget("label"){label = " "}, - dt.new_widget("label"){label = _("disable scripts")}, - dt.new_widget("label"){label = " "}, + dt.new_widget("section_label"){label = _("disable scripts")}, sm.widgets.allow_disable, - sm.widgets.disable_scripts, - dt.new_widget("label"){label = " "}, + sm.widgets.disable_scripts } -- manage the scripts -sm.widgets.folder_selector = dt.new_widget("combobox"){ - label = _("folder"), - tooltip = _( "select the script folder"), +sm.widgets.category_selector = dt.new_widget("combobox"){ + label = _("category"), + tooltip = _("select the script category"), selected = 1, changed_callback = function(self) if sm.run then - pref_write("folder_selector", "integer", self.selected) - change_folder(self.value) + pref_write("category_selector", "integer", self.selected) + change_category(self.value) end end, - table.unpack(sm.folders), + table.unpack(sm.categories), } --- a script "button" consists of: --- a button to start and stop the script --- a label that contains the name of the script --- a horizontal box that contains the button and the label - sm.widgets.buttons ={} -sm.widgets.labels = {} -sm.widgets.boxes = {} - for i =1, DEFAULT_BUTTONS_PER_PAGE do table.insert(sm.widgets.buttons, dt.new_widget("button"){}) - table.insert(sm.widgets.labels, dt.new_widget("label"){}) - table.insert(sm.widgets.boxes, dt.new_widget("box"){ orientation = "horizontal", expand = false, fill = false, - sm.widgets.buttons[i], sm.widgets.labels[i]}) - sm.page_status.buttons_created = sm.page_status.buttons_created + 1 + sm.page_status.buttons_create = sm.page_status.buttons_created + 1 end local page_back = "<" @@ -1471,13 +1205,10 @@ sm.widgets.page_control = dt.new_widget("box"){ sm.widgets.scripts = dt.new_widget("box"){ orientation = vertical, - - dt.new_widget("section_label"){label = _(" ")}, - dt.new_widget("label"){label = " "}, dt.new_widget("label"){label = _("scripts")}, - sm.widgets.folder_selector, + sm.widgets.category_selector, sm.widgets.page_control, - table.unpack(sm.widgets.boxes), + table.unpack(sm.widgets.buttons) } -- configure options @@ -1503,16 +1234,21 @@ sm.widgets.change_buttons = dt.new_widget("button"){ sm.widgets.configure = dt.new_widget("box"){ orientation = "vertical", - dt.new_widget("section_label"){label = " "}, - dt.new_widget("label"){label = " "}, dt.new_widget("label"){label = _("configuration")}, - dt.new_widget("label"){label = " "}, sm.widgets.num_buttons, - dt.new_widget("label"){label = " "}, sm.widgets.change_buttons, - dt.new_widget("label"){label = " "}, } +sm.widgets.color = dt.new_widget("check_button"){ + label = _("use color interface?"), + value = pref_read("use_color", "bool"), + clicked_callback = function(this) + pref_write("use_color", "bool", this.value) + sm.use_color = this.value + end +} +table.insert(sm.widgets.configure, sm.widgets.color) + -- stack for the options sm.widgets.main_stack = dt.new_widget("stack"){ @@ -1558,7 +1294,7 @@ else function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() - end + end end ) sm.event_registered = true From 3efc1805ca6637aca3094ed4825234ac9c58b91c Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sun, 9 Jun 2024 17:33:06 -0400 Subject: [PATCH 315/445] tools/script_manager - new user interface for darktable 4.8 wrappers added for io.popen and os.execute to handle windows special characters and spaces --- data/icons/blank20.png | Bin 0 -> 5678 bytes data/icons/path20.png | Bin 0 -> 6265 bytes tools/script_manager.lua | 620 ++++++++++++++++++++++++++------------- 3 files changed, 422 insertions(+), 198 deletions(-) create mode 100644 data/icons/blank20.png create mode 100644 data/icons/path20.png diff --git a/data/icons/blank20.png b/data/icons/blank20.png new file mode 100644 index 0000000000000000000000000000000000000000..81ed51574807dde06248d05f94fe17aad24b193a GIT binary patch literal 5678 zcmeHKd010d7Eff8SY$^*g%A|$60$=Q2*bWqK$g^iqLAdhK!7YHfh4SoUw6r(JBzi;}VN#4u5=brOB=lt%u_uZT6 z@8_w5Fhjs#Fdc6%w?OFM2)c~tYeILA?(3B>nC627daxvrDMboJ0uDC@L`vjB5DCh- z92iV?_i6B^eGjd_c^6?EGSAB^ZD`zKrG5JgamHraEfOi$Z)Mm4(f(Mti3`Jvv8*R7 zb!=SAkzSj=c0=t6k0ep&UNiIWnjD|r3%WL(@~(X{IHBJn|DIa9jYr3?T}LLTJyR15 zg(RKzFZPz=$F|L+l=iI&k{d`cZKw4InSE)0pm#ntlU4Se=DAm0ZtimlVQ7`o?McUi@UT6Mc^jjkx>L~$$P z?(Wf~U#p#GYQ9r*;KlV;kG-0D>l6lzyFjR11V8dXQF5S9;vI3v%#(c5_>_ZTd0^Vv zbcSP6MsD-jdW($0`@E#{8WSiH+f~Q&`m-WUw_lobR$o!%j=p(t9vUY;sS1LiNM}z(onbsZ!Gm;Az`--*8O6X(;k>+xd0aBzf5ZI;M&Z~+H0ID;irl=%}*)aHYhjvxmANR!jZ`5tVTzG9e z;Ao|5N{uND@cbuHj!N-4WZQA7rmA+}yET}QpJVoZ&-hJP*U214Z>oQKZj>*mEPLDQ z7-r#w{=M?1^VOAimqd+_5_fu;`?cZJ!i_}p?myB~9R4>hd&Q8??qasdnnC(}XYbf+ z98ufW@GY4@g;xAF8@FW*>jzENwp_}YStYu7_$^Y@fB!Y2?lCuVY1`?b5s#c*w|;p3 zz1b^Md0EsYT`cNgVdnm*aSJcAM4i+>Zk~AJ8_l{vlTIqs-UU|)xGBB$9WNS|++V#V zrl`R)GJzUrn_@SwE@^(%&-syI3uH|ej%x;kJy~*C`qL*V+?#y=NDZ-Jf2eZay<~T`xwisXyIyKG(zi zxy8=&%hS8Eq1z8T$=ixsJ)$4#%qq4?CcI^)yABr|`_(sD+P5g2d}M*`eZ1nr){RlJ zGn9~+Dc8it{tLFd?L*mqvR(1dfeEvl7YI8W zgFL*RA+3)`TIZ}WDKUrrEQT-dBuf{Y!u6jY-hN81pD)j{gS^K z<1%J<`efz&=CSuOqsZ{(pDv7N?LBLgMHY9=tmx9J7)u_S*3Co4)b4nsZLVhilRsXc zLGOLo(=M=lXV06ula8S<^{+M;EcWPZDp=&wwC#4mT`e+nX_os)N4o=dX!UWs_Tt9SGS?7-TrRC7pn6UX3T$S|!xN@7 z-oRk+bgrwbzqhOFhu0nSk}FQ$L-V@iZwLlV2 z`qa2+JKf?D3ckx~m_E__HcKxV{tap^p`)na7%^#dw1j$m?7l-s%d@UO7z<3)=AmNK zOv`VoONu8mkDgk4vTeA{(0W?d3Mc)s+!l7H#$}t$>4#}T8}-gsC`K1^fc<~%2to!8R{w%eC>}D z&vVbGWQHOdR);?fcG58ee$}1PY>9|AuCTsv%*$Xz9$TD?E0r#aBrP3&+Z(%arPH|S z`Csg3HX0VaTYll@O_rxZVJnRN{bnI;K%})e1rG$pmm$%IgVp=GMh?7C+(7GXdHJZP z@5*Dfyt0ro!Pf1r;Z1ILMja=|MoWHcp*?-`4)#h{Bzd%q*8*)z%(&3@BiPr6$`J^U^Qnbc;vNryybtJqT8Qb;E)Ek2iUn~ZHs~G?@+DTELICWK_QE((j4B;~ zjR9jo9;7OUyy8A{>FMq3|ItE8K?Ij4R9Qh}f2Jwna{eOgv)Gh9s&qaL1Tz1K`O~8&*hUe`@Ln-}J0Rfu}P*smO4iT^=67A4LTNa2WQa~n}$!25G910c$ zNH`pc$YFm1<;@pMn0z*LC#En9y)?dCUk9BjiV@I+TP{o&CLOD7+2!FNuE)Q^J7^Xeb{pKTh^n2c63UgCtBP zn>afh9!DV%30OSIj)0wuS%tR&6p5iqRAS<=HiS7`<*-npWFTUh$~uJrRIpGkR96wm zln6w0fgpy4QbHh=ma6hbI?N4<7gr2v$dwiUzUG6#*tyo+6o}!fx{yd!*+MMOIT17C zK|tjQvYYE-M>6>lAT+<<7t{wi_kRo)heM%Y32a+58^?sk8(?4{yOl0d}tRWg^n|0uSeRTqmU+Rou?aY zR{1TxP*DI$w1r+FVi;`UCFKRbBB%r)p_atk*IjEwT^+8En0a<&5E7YqyE)Uz9qjPM j8b`y8cBKVi5t^$Yz%m%T)O4pCqyh7G_j5b#5}x)S(L1|$ literal 0 HcmV?d00001 diff --git a/data/icons/path20.png b/data/icons/path20.png new file mode 100644 index 0000000000000000000000000000000000000000..1021d86405b81bbfa10a78e4ea7e8de8651462dd GIT binary patch literal 6265 zcmeH~c|26@`^Se0i3}x0dZrh=5n)9dy7{@2W$nK}1;UGMw4KKFI*bDsofCmVTLRapoG zB5!AF=?eZX2M=W#De&9+aZ@e?BGnh>?#*{431A#9o5lzPVEj-H00V>!8U!MII^w;x zL_=F{ny&04X=@wZKW?nOq2aAt*0YT3YnpYF!-39rM>W5-?&dmOS7yKP;!Vdhv(`}y zvpn#<$pHneJ`tCL9 zFZEGjmmT`89^8bMS;xkQE)kW&&Ii263@a;9E?zMezGTn#k(pUQDm>=-ZQ@nR4X@oZ zXXM*XM>}cx9%6N#VlV2bG~(1+Y!rME>qfeDQ?}<2g7c)cG9pIWite?%Pz_btE`ZC+K`}m%ZhqnK730>TM zI?Q(@P|$p2UHEIIvuW0~Ua*=bk052?he+K{_DfRiOI7ESP=~$r z&g5yvjz;cXs1I9fxKk=n#~?Dbs47BFWzu=saXq+>mX!zx+}9EL51AFN+PYNhJk9fx zukJRkVx6OIPU|Bb594@n{fYdmL;h+7B}Q+`f#H(vAzdR0zBdv_hCeLJ%~8V> zZ9iM?&f2%5D1QIT9?RAG5bL$tFxFCu)oH7Xyj`1KHW<+gm7L6i%rI3|>B8aVH(WIO-jl*pt@l{($a^}z z;Lv_8pf^W#+J^irVA3to6JYx;8y>k{CcS2`-hYq%yV{EF$D6yLUK8ZnMicXvmb{{g zc*Wd)3%|#ymQy>b`ew#2O0F4;XUlYSL2rpZxpW(^Jl)oDL)h%Fi7^qXapYm*;aK^% zoabc=(wB})6fm!O7iQFJss-?N#uRJ4_S|hyN?L!%Vb#QieVNyI)}Bs2;{&+f4f%lw z2+ODPJA$_^ZOC~jGIn?&)p9qAAI(dbmvi0m&s5rj74&Gq7D!oQ#X#iFCo7>@<5O2Q zBuRaZ6ty*W8Y|Csz3^c*X2~YV?~Zb7-FvC!gYT$Z^>I41`s<-7zn6+%qxRdIPX;TV zh#iM2YA3mM_#H0q`O7fr$i~H}7!3c|`x|*WIMl77x)=I(tOOM;H`_%2lzIsnTh(<=rmDWWy~I9qX=T)?jKskE z&PuW$-M;%%zzEx{a?#9+_s^F|CR)T=20mZ(q2{E|2~e3+4NopQevsVuZZt*l(T4qY zI%#%&2jVVBM~-fT*y%T^TU&3k3?GCA?1-gikZo197*rFkke`BX(is}e&t8A)_?>BJ zQq5`Gb!XS{g16}0GThpg<)+%u*m1X^?zA0kRYRQ=aV!VAR^4Tv2paV!jk>+Z6rN1( zD{%oPlwZ}AS3G#U;VRz#?@pVN+cJ;0>u$B(YQH5|O-3z0Gc>wBG9HoQP^YX+xQ>6T zpB<4S|NQj$dTl-PCjzC~+*5+LS@|;j&J6(ywsL2kV=xPfVLC@@NF#l^psV?ij{s8y+H1ZY-FZ% zI7BWd&AG{J*`$5*^<>%H-N=&}k(`osD4B@r%}75brPp^eZ}&fGzkd7z8U1y!)>{7~ zri?QOg_4^%ni8LHrEw$wIu|LMT=2yCu4>%Ax6HE@$flzNThaX@r$+VRU8j1D<>T%Z z%iRe*fcW&x)EMJ6THREIzOh=9E`S!)n_>4a8-%Sy$kIP0W=~3(yZ2!14`{n2nR8bt zy;bP@Izp&>9zClNU6pb3iyz0pWaG)c^oJCJs8`nzhK$iE7!1DZNFP$1exI`QY~p@b z8LsdIG)%ERLCtT-+R>=ZHSX-9S36e-O?$#uKP`367T!xgGrfi&DsY&(QPK0f@PW3O z^V)~z_Yf+)Zl#PO&0t}v8+`t)IZKs-C@TU zX-Cy#%T;Wui(kBGCO@ve<>MvoWd@y=2nyl2@{cNw*~=ox4uZkd*P(&W+M1NH25d*l*heSez%yE+$gVe75UDn(cG6t^s^ zcXzxHzILGSZs@@x&-|i~MxW(17VQB}4gX_(v<7}0W)>Sw)XA-}PM;;NUxEGS@Angl z*Y+lClfAC9>!tT5c~xq=!mLy!JwW+_*3E2NrNPjk^hC^Afr=k~^}tj|kgxWp@m1Fz zZJ704c5+7Z=EH|%o2n`TC#dUTipdME^vboVD|KcixGhm-fZGpmM+YK>%|w!@ zY%+ipGCAP(1OhQO6>>yK$=ML`TP_6)v9n7TwRv`e3ukka2O8Mc>3FZdQr9-8l zfIxr=n)1L=F~1CHW9R7n!$T|qox$YHd4Xd8V##OF{uS$&*u*_^>HHiB=>CKIi}m;1 z=ZrxsM@OP1n-VMz&(6{WE*_sqWm6bb;{0C#N5&W$8Y1vm8VP~J7@!d(l0F7OGs55~ zcnk?o!5jR9vSac1Bo+k_qd+*40dmNO1^|^r!XS){NFV}FAs~zl0StmdBVcg)hGd*R z4fhjb3zq>_B`NUdsKh8Lh|)I#a0Ubt9)ZSE&|oxF0>Y3+Fhl@o10zEM8K4o!ggF$I zLbPUcnIv#J8B7u#Kyg^~xel@5L^EeQ6F3%${us95EKIS=|C&1-_l_+Ln&`AAxu6SCAU^1YvBypXBfH^Ff3(=LQ1(=DR3P*}(p1PRjMaS_}LDu})|#4uJ+g`tDc^5kny2 zvEV5YjfSJXC5#eZ)!#EVM*Sa6jOPq~S_VMB`8IHQ0aq*3kLBu{W?~uti?45U@n0MP zME@D&xAgrZ*B`llOM%}q{!?9lA{5yC7?L1)FVqE5J{4q zrJ1|oz0}rw7d?UHQsd9dD!c9k_`0vT;$VJNiUiY)J9oqrhC7yPmz?%q1_jPq{liOhS5q)pEPGKbjdP_!P_dBr=6E z23K4?>ThJfH(sha9+Msxy1C1_Kc_DIfV-N=cm^obM~gJ_@IT^*eYlEg#jmmeyOynJ!{do)8eGidEWAN3)SPXYZklWq)3{VUBUHS6Vb&?OZ;D_z;!%DI>+7Hr9y>-(&z{uGP{Y+J zb=Rz&?ksH+iJE#jDe857E)$lwJN{nVxpF~>;x<-Vnx;r(zj$P`@9uLUz0+~IY0bgmF+l+%ZJpC + copyright (c) 2018, 2020, 2023, 2024 Bill Ferguson darktable is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -22,9 +22,9 @@ manage the lua scripts. On startup script_manager scans the lua scripts directory to see what scripts are present. - Scripts are sorted by 'category' based on what sub-directory they are in. With no - additional script repositories iinstalled, the categories are contrib, examples, official - and tools. When a category is selected the buttons show the script name and whether the + Scripts are sorted by 'folder' based on what sub-directory they are in. With no + additional script repositories iinstalled, the folders are contrib, examples, official + and tools. When a folder is selected the buttons show the script name and whether the script is started or stopped. The button is a toggle, so if the script is stopped click the button to start it and vice versa. @@ -56,42 +56,46 @@ local dtsys = require "lib/dtutils.system" local log = require "lib/dtutils.log" local debug = require "darktable.debug" --- set up translation +local gettext = dt.gettext -local gettext = dt.gettext.gettext -dt.gettext.bindtextdomain("script_manager", dt.configuration.config_dir .."/lua/locale/") +-- Tell gettext where to find the .mo file translating messages for a particular domain +dt.gettext.bindtextdomain("script_manager", dt.configuration.config_dir .. "/lua/locale/") local function _(msgid) - return gettext(msgid) + return gettext.dgettext("script_manager", msgid) end -- api check -du.check_min_api_version("5.0.0", "script_manager") +du.check_min_api_version("9.3.0", "script_manager") -- - - - - - - - - - - - - - - - - - - - - - - - -- C O N S T A N T S -- - - - - - - - - - - - - - - - - - - - - - - - -- path separator -local PS = dt.configuration.running_os == "windows" and "\\" or "/" +local PS = dt.configuration.running_os == "windows" and "\\" or "/" -- command separator -local CS = dt.configuration.running_os == "windows" and "&" or ";" +local CS = dt.configuration.running_os == "windows" and "&" or ";" -local MODULE = "script_manager" +local MODULE = "script_manager" -local MIN_BUTTONS_PER_PAGE = 5 -local MAX_BUTTONS_PER_PAGE = 20 -local DEFAULT_BUTTONS_PER_PAGE = 10 +local MIN_BUTTONS_PER_PAGE = 5 +local MAX_BUTTONS_PER_PAGE = 20 +local DEFAULT_BUTTONS_PER_PAGE = 10 -local DEFAULT_LOG_LEVEL = log.error +local DEFAULT_LOG_LEVEL = log.error -local LUA_DIR = dt.configuration.config_dir .. PS .. "lua" -local LUA_SCRIPT_REPO = "https://github.com/darktable-org/lua-scripts.git" +local LUA_DIR = dt.configuration.config_dir .. PS .. "lua" +local LUA_SCRIPT_REPO = "https://github.com/darktable-org/lua-scripts.git" -local LUA_API_VER = "API-" .. dt.configuration.api_version_string +local LUA_API_VER = "API-" .. dt.configuration.api_version_string + +-- local POWER_ICON = dt.configuration.config_dir .. "/lua/data/data/icons/power.png" +local POWER_ICON = dt.configuration.config_dir .. "/lua/data/icons/path20.png" +local BLANK_ICON = dt.configuration.config_dir .. "/lua/data/icons/blank20.png" -- - - - - - - - - - - - - - - - - - - - - - - - -- P R E F E R E N C E S @@ -128,7 +132,7 @@ sm.event_registered = false -- set up tables to contain all the widgets and choices sm.widgets = {} -sm.categories = {} +sm.folders = {} -- set log level for functions @@ -137,14 +141,14 @@ sm.log_level = DEFAULT_LOG_LEVEL --[[ sm.scripts is a table of tables for containing the scripts - It is organized as into category (folder) subtables containing + It is organized as into folder (folder) subtables containing each script definition, which is a table sm.scripts- | - - category------------| + - folder------------| | - script - - category----| | + - folder----| | - script| | - script - script| @@ -152,7 +156,7 @@ sm.log_level = DEFAULT_LOG_LEVEL and a script table looks like name the name of the script file without the lua extension - path category (folder), path separator, path, name without the lua extension + path folder (folder), path separator, path, name without the lua extension doc the header comments from the script to be used as a tooltip script_name the folder, path separator, and name without the lua extension running true if running, false if not, hidden if running but the @@ -178,10 +182,7 @@ sm.page_status = {} sm.page_status.num_buttons = DEFAULT_BUTTONS_PER_PAGE sm.page_status.buttons_created = 0 sm.page_status.current_page = 0 -sm.page_status.category = "" - --- use color in the interface? -sm.use_color = false +sm.page_status.folder = "" -- installed script repositories sm.installed_repositories = { @@ -212,17 +213,24 @@ end local function pref_read(name, pref_type) local old_log_level = set_log_level(sm.log_level) + log.msg(log.debug, "name is " .. name .. " and type is " .. pref_type) + local val = dt.preferences.read(MODULE, name, pref_type) + log.msg(log.debug, "read value " .. tostring(val)) + restore_log_level(old_log_level) return val end local function pref_write(name, pref_type, value) local old_log_level = set_log_level(sm.log_level) + log.msg(log.debug, "writing value " .. tostring(value) .. " for name " .. name) + dt.preferences.write(MODULE, name, pref_type, value) + restore_log_level(old_log_level) end @@ -232,12 +240,15 @@ end local function get_repo_status(repo) local old_log_level = set_log_level(sm.log_level) - local p = io.popen("cd " .. repo .. CS .. "git status") + + local p = dtsys.io_popen("cd " .. repo .. CS .. "git status") + if p then local data = p:read("*a") p:close() return data end + log.msg(log.error, "unable to get status of " .. repo) restore_log_level(old_log_level) return nil @@ -245,8 +256,11 @@ end local function get_current_repo_branch(repo) local old_log_level = set_log_level(sm.log_level) + local branch = nil - local p = io.popen("cd " .. repo .. CS .. "git branch --all") + + local p = dtsys.io_popen("cd " .. repo .. CS .. "git branch --all") + if p then local data = p:read("*a") p:close() @@ -254,23 +268,29 @@ local function get_current_repo_branch(repo) for _, b in ipairs(branches) do log.msg(log.debug, "branch for testing is " .. b) branch = string.match(b, "^%* (.-)$") + if branch then log.msg(log.info, "current repo branch is " .. branch) return branch end + end end + if not branch then log.msg(log.error, "no current branch detected in repo_data") end + restore_log_level(old_log_level) return nil end local function get_repo_branches(repo) local old_log_level = set_log_level(sm.log_level) + local branches = {} - local p = io.popen("cd " .. repo .. CS .. "git pull --all" .. CS .. "git branch --all") + local p = dtsys.io_popen("cd " .. repo .. CS .. "git pull --all" .. CS .. "git branch --all") + if p then local data = p:read("*a") p:close() @@ -285,12 +305,14 @@ local function get_repo_branches(repo) end end end + restore_log_level(old_log_level) return branches end local function is_repo_clean(repo_data) local old_log_level = set_log_level(sm.log_level) + if string.match(repo_data, "\n%s-%a.-%a:%s-%a%g-\n") then log.msg(log.info, "repo is dirty") return false @@ -298,13 +320,17 @@ local function is_repo_clean(repo_data) log.msg(log.info, "repo is clean") return true end + restore_log_level(old_log_level) end local function checkout_repo_branch(repo, branch) local old_log_level = set_log_level(sm.log_level) + log.msg(log.info, "checkout out branch " .. branch .. " from repository " .. repo) - os.execute("cd " .. repo .. CS .. "git checkout " .. branch) + + dtsys.os_execute("cd " .. repo .. CS .. "git checkout " .. branch) + restore_log_level(old_log_level) end @@ -314,16 +340,20 @@ end local function update_combobox_choices(combobox, choice_table, selected) local old_log_level = set_log_level(sm.log_level) + local items = #combobox local choices = #choice_table + for i, name in ipairs(choice_table) do combobox[i] = name end + if choices < items then for j = items, choices + 1, -1 do combobox[j] = nil end end + if not selected then selected = 1 end @@ -334,8 +364,10 @@ end local function string_trim(str) local old_log_level = set_log_level(sm.log_level) + local result = string.gsub(str, "^%s+", "") result = string.gsub(result, "%s+$", "") + restore_log_level(old_log_level) return result end @@ -344,20 +376,78 @@ local function string_dequote(str) return string.gsub(str, "['\"]", "") end +local function string_dei18n(str) + return string.match(str, "%_%((.+)%)") +end + +local function string_chop(str) + return str:sub(1, -2) +end + ------------------ -- script handling ------------------ -local function add_script_category(category) +local function add_script_folder(folder) local old_log_level = set_log_level(sm.log_level) - if #sm.categories == 0 or not string.match(du.join(sm.categories, " "), ds.sanitize_lua(category)) then - table.insert(sm.categories, category) - sm.scripts[category] = {} - log.msg(log.debug, "created category " .. category) + + if #sm.folders == 0 or not string.match(du.join(sm.folders, " "), ds.sanitize_lua(folder)) then + table.insert(sm.folders, folder) + sm.scripts[folder] = {} + log.msg(log.debug, "created folder " .. folder) end + restore_log_level(old_log_level) end +local function get_script_metadata(script) + local old_log_level = set_log_level(sm.log_level) + -- set_log_level(log.debug) + + log.msg(log.debug, "processing metatdata for " .. script) + + local description = nil + local metadata = nil + + f = io.open(LUA_DIR .. PS .. script .. ".lua") + if f then + -- slurp the file + local content = f:read("*all") + f:close() + -- grab the script_data.metadata table + description = string.match(content, "script_data%.metadata = %{\r?\n(.-)\r?\n%}") + else + log.msg(log.error, "cant read from " .. script) + end + + if description then + metadata = "" + -- format it into a string block for display + local lines = du.split(description, "\n") + log.msg(log.debug, "got " .. #lines .. " lines") + local first = 1 + for i = 1, #lines do + log.msg(log.debug, "splitting line " .. lines[i]) + local parts = du.split(lines[i], " = ") + log.msg(log.debug, "got value " .. parts[1] .. " and data " .. parts[2]) + if string.match(parts[2], "%_%(") then + parts[2] = _(string_dequote(string_dei18n(parts[2]))) + else + parts[2] = string_dequote(parts[2]) + end + if string.match(parts[2], ",$") then + parts[2] = string_chop(parts[2]) + end + metadata = metadata .. string.format("%s%-10s\t%s", first and "" or "\n", parts[1], parts[2]) + first = nil + end + log.msg(log.debug, "script data is \n" .. metadata) + end + + restore_log_level(old_log_level) + return metadata +end + local function get_script_doc(script) local old_log_level = set_log_level(sm.log_level) local description = nil @@ -369,7 +459,7 @@ local function get_script_doc(script) -- assume that the second block comment is the documentation description = string.match(content, "%-%-%[%[.-%]%].-%-%-%[%[(.-)%]%]") else - log.msg(log.error, "Cant read from " .. script) + log.msg(log.error, "can't read from " .. script) end if description then restore_log_level(old_log_level) @@ -382,18 +472,26 @@ end local function activate(script) local old_log_level = set_log_level(sm.log_level) + local status = nil -- status of start function local err = nil -- error message returned if module doesn't start + log.msg(log.info, "activating " .. script.name) + if script.running == false then + script_manager_running_script = script.name + status, err = du.prequire(script.path) log.msg(log.debug, "prequire returned " .. tostring(status) .. " and for err " .. tostring(err)) + script_manager_running_script = nil + if status then pref_write(script.script_name, "bool", true) - log.msg(log.screen, string.format(_("loaded %s"), script.script_name)) + log.msg(log.screen, _(string.format("loaded %s", script.script_name))) script.running = true + if err ~= true then log.msg(log.debug, "got lib data") script.data = err @@ -403,17 +501,20 @@ local function activate(script) else script.data = nil end + else - log.msg(log.screen, string.format(_("%s failed to load"), script.script_name)) - log.msg(log.error, "Error loading " .. script.script_name) - log.msg(log.error, "Error message: " .. err) + log.msg(log.screen, _(string.format("%s failed to load", script.script_name))) + log.msg(log.error, "error loading " .. script.script_name) + log.msg(log.error, "error message: " .. err) end + else -- script is a lib and loaded but hidden and the user wants to reload script.data.restart() script.running = true status = true pref_write(script.script_name, "bool", true) end + restore_log_level(old_log_level) return status end @@ -428,9 +529,13 @@ local function deactivate(script) -- deactivate it.... local old_log_level = set_log_level(sm.log_level) + pref_write(script.script_name, "bool", false) + if script.data then + script.data.destroy() + if script.data.destroy_method then if string.match(script.data.destroy_method, "hide") then script.running = "hidden" @@ -442,44 +547,54 @@ local function deactivate(script) package.loaded[script.script_name] = nil script.running = false end + log.msg(log.info, "turned off " .. script.script_name) - log.msg(log.screen, string.format(_("%s stopped"), script.name)) + log.msg(log.screen, _(string.format("%s stopped", script.name))) + else script.running = false + log.msg(log.info, "setting " .. script.script_name .. " to not start") - log.msg(log.screen, string.format(_("%s will not start when darktable is restarted"), script.name)) + log.msg(log.screen, _(string.format("%s will not start when darktable is restarted", script.name))) end + restore_log_level(old_log_level) end -local function add_script_name(name, path, category) +local function add_script_name(name, path, folder) local old_log_level = set_log_level(sm.log_level) - log.msg(log.debug, "category is " .. category) + + log.msg(log.debug, "folder is " .. folder) log.msg(log.debug, "name is " .. name) + local script = { name = name, - path = category .. "/" .. path .. name, + path = folder .. "/" .. path .. name, running = false, - doc = get_script_doc(category .. "/" .. path .. name), - script_name = category .. "/" .. name, + doc = get_script_doc(folder .. "/" .. path .. name), + metadata = get_script_metadata(folder .. "/" .. path .. name), + script_name = folder .. "/" .. name, data = nil } - table.insert(sm.scripts[category], script) + + table.insert(sm.scripts[folder], script) + if pref_read(script.script_name, "bool") then activate(script) else pref_write(script.script_name, "bool", false) end + restore_log_level(old_log_level) end local function process_script_data(script_file) local old_log_level = set_log_level(sm.log_level) - -- the script file supplied is category/filename.filetype - -- the following pattern splits the string into category, path, name, fileename, and filetype + -- the script file supplied is folder/filename.filetype + -- the following pattern splits the string into folder, path, name, fileename, and filetype -- for example contrib/gimp.lua becomes - -- category - contrib + -- folder - contrib -- path - -- name - gimp.lua -- filename - gimp @@ -496,14 +611,14 @@ local function process_script_data(script_file) log.msg(log.info, "processing " .. script_file) -- add the script data - local category,path,name,filename,filetype = string.match(script_file, pattern) + local folder,path,name,filename,filetype = string.match(script_file, pattern) - if category and name and path then - log.msg(log.debug, "category is " .. category) + if folder and name and path then + log.msg(log.debug, "folder is " .. folder) log.msg(log.debug, "name is " .. name) - add_script_category(category) - add_script_name(name, path, category) + add_script_folder(folder) + add_script_name(name, path, folder) end restore_log_level(old_log_level) @@ -511,11 +626,10 @@ end local function ensure_lib_in_search_path(line) local old_log_level = set_log_level(sm.log_level) - set_log_level(log.debug) log.msg(log.debug, "line is " .. line) - if string.match(line, ds.sanitize_lua(dt.configuration.config_dir .. PS .. "lua" .. PS .. "lib")) then + if string.match(line, ds.sanitize_lua(dt.configuration.config_dir .. PS .. "lua/lib")) then log.msg(log.debug, line .. " is already in search path, returning...") return end @@ -540,15 +654,20 @@ end local function scan_scripts(script_dir) local old_log_level = set_log_level(sm.log_level) + local script_count = 0 local find_cmd = "find -L " .. script_dir .. " -name \\*.lua -print | sort" + if dt.configuration.running_os == "windows" then find_cmd = "dir /b/s \"" .. script_dir .. "\\*.lua\" | sort" end + log.msg(log.debug, "find command is " .. find_cmd) + -- scan the scripts - local output = io.popen(find_cmd) + local output = dtsys.io_popen(find_cmd) for line in output:lines() do + log.msg(log.debug, "line is " .. line) local l = string.gsub(line, ds.sanitize_lua(LUA_DIR) .. PS, "") -- strip the lua dir off local script_file = l:sub(1,-5) -- strip off .lua\n if not string.match(script_file, "script_manager") then -- let's not include ourself @@ -564,6 +683,7 @@ local function scan_scripts(script_dir) end end end + restore_log_level(old_log_level) return script_count end @@ -575,7 +695,7 @@ local function update_scripts() local git = sm.executables.git if not git then - dt.print(_("ERROR: git not found, install or specify the location of the git executable.")) + log.msg(log.screen, _("ERROR: git not found. Install or specify the location of the git executable.")) return end @@ -589,7 +709,7 @@ local function update_scripts() end if result == 0 then - dt.print(_("lua scripts successfully updated")) + log.msg(log.screen, _("lua scripts successfully updated")) end restore_log_level(old_log_level) @@ -602,65 +722,85 @@ end local function update_script_update_choices() local old_log_level = set_log_level(sm.log_level) + local installs = {} local pref_string = "" + for i, repo in ipairs(sm.installed_repositories) do table.insert(installs, repo.name) pref_string = pref_string .. i .. "," .. repo.name .. "," .. repo.directory .. "," end + update_combobox_choices(sm.widgets.update_script_choices, installs, 1) + log.msg(log.debug, "repo pref string is " .. pref_string) pref_write("installed_repos", "string", pref_string) + restore_log_level(old_log_level) end local function scan_repositories() local old_log_level = set_log_level(sm.log_level) + local script_count = 0 local find_cmd = "find -L " .. LUA_DIR .. " -name \\*.git -print | sort" + if dt.configuration.running_os == "windows" then find_cmd = "dir /b/s /a:d " .. LUA_DIR .. PS .. "*.git | sort" end + log.msg(log.debug, "find command is " .. find_cmd) - local output = io.popen(find_cmd) + + local output = dtsys.io_popen(find_cmd) + for line in output:lines() do local l = string.gsub(line, ds.sanitize_lua(LUA_DIR) .. PS, "") -- strip the lua dir off - local category = string.match(l, "(.-)" .. PS) -- get everything to teh first / - if category then -- if we have a category (.git doesn't) - log.msg(log.debug, "found category " .. category) - if not string.match(category, "plugins") and not string.match(category, "%.git") then -- skip plugins + local folder = string.match(l, "(.-)" .. PS) -- get everything to the first / + + if folder then -- if we have a folder (.git doesn't) + + log.msg(log.debug, "found folder " .. folder) + + if not string.match(folder, "plugins") and not string.match(folder, "%.git") then -- skip plugins + if #sm.installed_repositories == 1 then - log.msg(log.debug, "only 1 repo, adding " .. category) - table.insert(sm.installed_repositories, {name = category, directory = LUA_DIR .. PS .. category}) + log.msg(log.debug, "only 1 repo, adding " .. folder) + table.insert(sm.installed_repositories, {name = folder, directory = LUA_DIR .. PS .. folder}) else log.msg(log.debug, "more than 1 repo, we have to search the repos to make sure it's not there") local found = nil + for _, repo in ipairs(sm.installed_repositories) do - if string.match(repo.name, ds.sanitize_lua(category)) then + if string.match(repo.name, ds.sanitize_lua(folder)) then log.msg(log.debug, "matched " .. repo.name) found = true break end end + if not found then - table.insert(sm.installed_repositories, {name = category, directory = LUA_DIR .. PS .. category}) + table.insert(sm.installed_repositories, {name = folder, directory = LUA_DIR .. PS .. folder}) end + end end end end + update_script_update_choices() + restore_log_level(old_log_level) end local function install_scripts() local old_log_level = set_log_level(sm.log_level) + local url = sm.widgets.script_url.text - local category = sm.widgets.new_category.text + local folder = sm.widgets.new_folder.text - if string.match(du.join(sm.categories, " "), ds.sanitize_lua(category)) then - log.msg(log.screen, string.format(_("category %s is already in use, please specify a different category name."), category)) - log.msg(log.error, "category " .. category .. " already exists, returning...") + if string.match(du.join(sm.folders, " "), ds.sanitize_lua(folder)) then + log.msg(log.screen, _(string.format("folder %s is already in use. Please specify a different folder name.", folder))) + log.msg(log.error, "folder " .. folder .. " already exists, returning...") restore_log_level(old_log_level) return end @@ -670,12 +810,12 @@ local function install_scripts() local git = sm.executables.git if not git then - dt.print(_("ERROR: git not found, install or specify the location of the git executable.")) + log.msg(log.screen, _("ERROR: git not found. Install or specify the location of the git executable.")) restore_log_level(old_log_level) return end - local git_command = "cd " .. LUA_DIR .. " " .. CS .. " " .. git .. " clone " .. url .. " " .. category + local git_command = "cd " .. LUA_DIR .. " " .. CS .. " " .. git .. " clone " .. url .. " " .. folder log.msg(log.debug, "update git command is " .. git_command) if dt.configuration.running_os == "windows" then @@ -687,30 +827,34 @@ local function install_scripts() log.msg(log.info, "result from import is " .. result) if result == 0 then - local count = scan_scripts(LUA_DIR .. PS .. category) + local count = scan_scripts(LUA_DIR .. PS .. folder) + if count > 0 then - update_combobox_choices(sm.widgets.category_selector, sm.categories, sm.widgets.category_selector.selected) - dt.print(string.format(_("scripts successfully installed into category "), category)) - table.insert(sm.installed_repositories, {name = category, directory = LUA_DIR .. PS .. category}) + update_combobox_choices(sm.widgets.folder_selector, sm.folders, sm.widgets.folder_selector.selected) + dt.print(_("scripts successfully installed into folder ") .. folder) + table.insert(sm.installed_repositories, {name = folder, directory = LUA_DIR .. PS .. folder}) update_script_update_choices() - for i = 1, #sm.widgets.category_selector do - if string.match(sm.widgets.category_selector[i], ds.sanitize_lua(category)) then - log.msg(log.debug, "setting category selector to " .. i) - sm.widgets.category_selector.selected = i + + for i = 1, #sm.widgets.folder_selector do + if string.match(sm.widgets.folder_selector[i], ds.sanitize_lua(folder)) then + log.msg(log.debug, "setting folder selector to " .. i) + sm.widgets.folder_selector.selected = i break end i = i + 1 end + log.msg(log.debug, "clearing text fields") sm.widgets.script_url.text = "" - sm.widgets.new_category.text = "" + sm.widgets.new_folder.text = "" sm.widgets.main_menu.selected = 3 else - dt.print(_("no scripts found to install")) - log.msg(log.error, "scan_scripts returned " .. count .. " scripts found. Not adding to category_selector") + log.msg(log.screen, _("No scripts found to install")) + log.msg(log.error, "scan_scripts returned " .. count .. " scripts found. Not adding to folder_selector") end + else - dt.print(_("failed to download scripts")) + log.msg(log.screen, _("failed to download scripts")) end restore_log_level(old_log_level) @@ -719,102 +863,101 @@ end local function clear_button(number) local old_log_level = set_log_level(sm.log_level) + local button = sm.widgets.buttons[number] - button.label = "" + local label = sm.widgets.labels[number] + + button.image = BLANK_ICON button.tooltip = "" button.sensitive = false - --button.name = "" + label.label = "" + button.name = "" + restore_log_level(old_log_level) end -local function find_script(category, name) +local function find_script(folder, name) local old_log_level = set_log_level(sm.log_level) - log.msg(log.debug, "looking for script " .. name .. " in category " .. category) - for _, script in ipairs(sm.scripts[category]) do + + log.msg(log.debug, "looking for script " .. name .. " in folder " .. folder) + + for _, script in ipairs(sm.scripts[folder]) do if string.match(script.name, "^" .. ds.sanitize_lua(name) .. "$") then return script end end + restore_log_level(old_log_level) return nil end -local function populate_buttons(category, first, last) +local function populate_buttons(folder, first, last) local old_log_level = set_log_level(sm.log_level) - log.msg(log.debug, "category is " .. category .. " and first is " .. first .. " and last is " .. last) + + log.msg(log.debug, "folder is " .. folder .. " and first is " .. first .. " and last is " .. last) + local button_num = 1 + for i = first, last do - script = sm.scripts[category][i] - button = sm.widgets.buttons[button_num] + local script = sm.scripts[folder][i] + local button = sm.widgets.buttons[button_num] + local label = sm.widgets.labels[button_num] + if script.running == true then - if sm.use_color then - button.label = script.name - button.name = "sm_started" - else - button.label = string.format(_("%s started"), script.name) - end + button.name = "pb_on" else - if sm.use_color then - button.label = script.name - button.name = "sm_stopped" - else - button.label = string.format(_("%s stopped"), script.name) - end + button.name = "pb_off" end - button.ellipsize = "middle" + + button.image = POWER_ICON + label.label = script.name + label.name = "pb_label" + button.ellipsize = "end" button.sensitive = true - button.tooltip = script.doc + label.tooltip = script.metadata and script.metadata or script.doc + button.clicked_callback = function (this) - local script_name = nil + local cb_script = script local state = nil - if sm.use_color then - script_name = string.match(this.label, "(.+)") - else - script_name, state = string.match(this.label, "(.-) (.+)") - end - local script = find_script(sm.widgets.category_selector.value, script_name) - if script then - log.msg(log.debug, "found script " .. script.name .. " with path " .. script.path) - if script.running == true then - log.msg(log.debug, "deactivating " .. script.name .. " on " .. script.path .. " for button " .. this.label) - deactivate(script) - if sm.use_color then - this.name = "sm_stopped" - else - this.label = string.format(_("%s stopped"), script.name) - end + if cb_script then + log.msg(log.debug, "found script " .. cb_script.name .. " with path " .. cb_script.path) + if cb_script.running == true then + log.msg(log.debug, "deactivating " .. cb_script.name .. " on " .. cb_script.path) + deactivate(cb_script) + this.name = "pb_off" else - log.msg(log.debug, "activating " .. script.name .. " on " .. script.path .. " for button " .. this.label) - local result = activate(script) + log.msg(log.debug, "activating " .. cb_script.name .. " on " .. script.path) + local result = activate(cb_script) if result then - if sm.use_color then - this.name = "sm_started" - else - this.label = string.format(_("%s started"), script.name) - end + this.name = "pb_on" end end - else - log.msg(log.error, "script " .. script_name .. " not found") end end + button_num = button_num + 1 end + if button_num <= sm.page_status.num_buttons then for i = button_num, sm.page_status.num_buttons do clear_button(i) end end + restore_log_level(old_log_level) end local function paginate(direction) local old_log_level = set_log_level(sm.log_level) - local category = sm.page_status.category - log.msg(log.debug, "category is " .. category) - local num_scripts = #sm.scripts[category] + + local folder = sm.page_status.folder + log.msg(log.debug, "folder is " .. folder) + + local num_scripts = #sm.scripts[folder] log.msg(log.debug, "num_scripts is " .. num_scripts) + local max_pages = math.ceil(num_scripts / sm.page_status.num_buttons) + local cur_page = sm.page_status.current_page log.msg(log.debug, "max pages is " .. max_pages) @@ -836,7 +979,9 @@ local function paginate(direction) log.msg(log.debug, "took path 2") cur_page = 1 end + log.msg(log.debug, "cur_page is " .. cur_page .. " and max_pages is " .. max_pages) + if cur_page == max_pages and cur_page == 1 then sm.widgets.page_forward.sensitive = false sm.widgets.page_back.sensitive = false @@ -852,115 +997,167 @@ local function paginate(direction) end sm.page_status.current_page = cur_page + first = (cur_page * sm.page_status.num_buttons) - (sm.page_status.num_buttons - 1) + if first + sm.page_status.num_buttons > num_scripts then last = num_scripts else last = first + sm.page_status.num_buttons - 1 end - sm.widgets.page_status.label = string.format(_("page %d of %d"), cur_page, max_pages) - populate_buttons(category, first, last) + sm.widgets.page_status.label = _(string.format("page %d of %d", cur_page, max_pages)) + + populate_buttons(folder, first, last) + restore_log_level(old_log_level) end -local function change_category(category) +local function change_folder(folder) local old_log_level = set_log_level(sm.log_level) - if not category then - log.msg(log.debug "setting category to selector value " .. sm.widgets.category_selector.value) - sm.page_status.category = sm.widgets.category_selector.value + + if not folder then + log.msg(log.debug "setting folder to selector value " .. sm.widgets.folder_selector.value) + sm.page_status.folder = sm.widgets.folder_selector.value else - log.msg(log.debug, "setting catgory to argument " .. category) - sm.page_status.category = category + log.msg(log.debug, "setting catgory to argument " .. folder) + sm.page_status.folder = folder end paginate(2) + restore_log_level(old_log_level) end local function change_num_buttons() local old_log_level = set_log_level(sm.log_level) + cur_buttons = sm.page_status.num_buttons new_buttons = sm.widgets.num_buttons.value + pref_write("num_buttons", "integer", new_buttons) + if new_buttons < cur_buttons then + log.msg(log.debug, "took new is less than current branch") + for i = 1, cur_buttons - new_buttons do table.remove(sm.widgets.scripts) end + log.msg(log.debug, "finished removing widgets, now there are " .. #sm.widgets.buttons) elseif new_buttons > cur_buttons then + log.msg(log.debug, "took new is greater than current branch") + log.msg(log.debug, "number of scripts is " .. #sm.widgets.scripts) + log.msg(log.debug, "number of buttons is " .. #sm.widgets.buttons) + log.msg(log.debug, "number of labels is " .. #sm.widgets.labels) + log.msg(log.debug, "number of boxes is " .. #sm.widgets.boxes) + if new_buttons > sm.page_status.buttons_created then + for i = sm.page_status.buttons_created + 1, new_buttons do + log.msg(log.debug, "i is " .. i) table.insert(sm.widgets.buttons, dt.new_widget("button"){}) + log.msg(log.debug, "inserted new button") + log.msg(log.debug, "number of buttons is " .. #sm.widgets.buttons) + table.insert(sm.widgets.labels, dt.new_widget("label"){}) + log.msg(log.debug, "inserted new label") + log.msg(log.debug, "number of labels is " .. #sm.widgets.labels) + table.insert(sm.widgets.boxes, dt.new_widget("box"){ orientation = "horizontal", expand = false, fill = false, + sm.widgets.buttons[i], sm.widgets.labels[i]}) + log.msg(log.debug, "inserted new box") sm.page_status.buttons_created = sm.page_status.buttons_created + 1 end + end + log.msg(log.debug, "cur_buttons is " .. cur_buttons .. " and new_buttons is " .. new_buttons) log.msg(log.debug, #sm.widgets.buttons .. " buttons are available") + for i = cur_buttons + 1, new_buttons do log.msg(log.debug, "inserting button " .. i .. " into scripts widget") - table.insert(sm.widgets.scripts, sm.widgets.buttons[i]) + table.insert(sm.widgets.scripts, sm.widgets.boxes[i]) end + log.msg(log.debug, "finished adding widgets, now there are " .. #sm.widgets.buttons) else -- no change log.msg(log.debug, "no change, just returning") return end + sm.page_status.num_buttons = new_buttons log.msg(log.debug, "num_buttons set to " .. sm.page_status.num_buttons) paginate(2) -- force the buttons to repopulate sm.widgets.main_menu.selected = 3 -- jump back to start/stop scripts + restore_log_level(old_log_level) end local function load_preferences() local old_log_level = set_log_level(sm.log_level) + -- load the prefs and update settings -- update_script_choices + local pref_string = pref_read("installed_repos", "string") local entries = du.split(pref_string, ",") + while #entries > 2 do local num = table.remove(entries, 1) local name = table.remove(entries, 1) local directory = table.remove(entries, 1) + if not string.match(sm.installed_repositories[1].name, "^" .. ds.sanitize_lua(name) .. "$") then table.insert(sm.installed_repositories, {name = name, directory = directory}) end + end + update_script_update_choices() log.msg(log.debug, "updated installed scripts") - -- category selector - local val = pref_read("category_selector", "integer") + + -- folder selector + local val = pref_read("folder_selector", "integer") + if val == 0 then val = 1 end - sm.widgets.category_selector.selected = val - sm.page_status.category = sm.widgets.category_selector.value - log.msg(log.debug, "updated category selector and set it to " .. sm.widgets.category_selector.value) + + sm.widgets.folder_selector.selected = val + sm.page_status.folder = sm.widgets.folder_selector.value + log.msg(log.debug, "updated folder selector and set it to " .. sm.widgets.folder_selector.value) + -- num_buttons local val = pref_read("num_buttons", "integer") + if val == 0 then val = DEFAULT_BUTTONS_PER_PAGE end + sm.widgets.num_buttons.value = val log.msg(log.debug, "set page buttons to " .. val) + change_num_buttons() log.msg(log.debug, "paginated") + -- main menu local val = pref_read("main_menu_action", "integer") log.msg(log.debug, "read " .. val .. " for main menu") + if val == 0 then val = 3 end + sm.widgets.main_menu.selected = val log.msg(log.debug, "set main menu to val " .. val .. " which is " .. sm.widgets.main_menu.value) log.msg(log.debug, "set main menu to " .. sm.widgets.main_menu.value) + restore_log_level(old_log_level) end local function install_module() local old_log_level = set_log_level(sm.log_level) + if not sm.module_installed then dt.register_lib( "script_manager", -- Module name @@ -974,22 +1171,13 @@ local function install_module() ) sm.module_installed = true end + sm.run = true sm.use_color = pref_read("use_color", "bool") log.msg(log.debug, "set run to true, loading preferences") load_preferences() scan_repositories() - --[[dt.print_log("\n\nsetting sm visible false\n\n") - dt.gui.libs["script_manager"].visible = false - dt.control.sleep(5000) - dt.print_log("setting sm visible true") - dt.gui.libs["script_manager"].visible = true - --[[dt.control.sleep(5000) - dt.print_log("setting sm expanded false") - dt.gui.libs["script_manager"].expanded = false - dt.control.sleep(5000) - dt.print_log("setting sm expanded true") - dt.gui.libs["script_manager"].expanded = true]] + restore_log_level(old_log_level) end @@ -1008,22 +1196,28 @@ if check_for_updates then local repo = LUA_DIR if current_branch then + if sm.executables.git and clean and + (current_branch == "master" or string.match(current_branch, "^API%-")) then -- only make changes to clean branches local branches = get_repo_branches(LUA_DIR) + if current_branch ~= LUA_API_VER and current_branch ~= "master" then -- probably upgraded from an earlier api version so get back to master -- to use the latest version of script_manager to get the proper API checkout_repo_branch(repo, "master") - log.msg(log.screen, "lua API version reset, please restart darktable") + log.msg(log.screen, _("lua API version reset, please restart darktable")) + elseif LUA_API_VER == current_branch then -- do nothing, we are fine log.msg(log.debug, "took equal branch, doing nothing") + elseif string.match(LUA_API_VER, "dev") then -- we are on a dev API version, so checkout the dev -- api version or checkout/stay on master log.msg(log.debug, "took the dev branch") local match = false + for _, branch in ipairs(branches) do log.msg(log.debug, "checking branch " .. branch .. " against API " .. LUA_API_VER) if LUA_API_VER == branch then @@ -1032,6 +1226,7 @@ if check_for_updates then checkout_repo_branch(repo, branch) end end + if not match then if current_branch == "master" then log.msg(log.info, "staying on master, no dev branch yet") @@ -1040,25 +1235,33 @@ if check_for_updates then checkout_repo_branch(repo, "master") end end + elseif #branches > 0 and LUA_API_VER > branches[#branches] then log.msg(log.info, "no newer branches, staying on master") -- stay on master + else -- checkout the appropriate branch for API version if it exists log.msg(log.info, "checking out the appropriate API branch") + local match = false + for _, branch in ipairs(branches) do log.msg(log.debug, "checking branch " .. branch .. " against API " .. LUA_API_VER) + if LUA_API_VER == branch then match = true log.msg(log.info, "checking out repo branch " .. branch) checkout_repo_branch(repo, branch) log.msg(log.screen, "you must restart darktable to use the correct version of the lua") end + end + if not match then log.msg(log.warn, "no matching branch found for " .. LUA_API_VER) end + end end end @@ -1100,18 +1303,18 @@ sm.widgets.script_url = dt.new_widget("entry"){ tooltip = _("enter the URL of the git repository containing the scripts you wish to add") } -sm.widgets.new_category = dt.new_widget("entry"){ +sm.widgets.new_folder = dt.new_widget("entry"){ text = "", - placeholder = _("name of new category"), - tooltip = _("enter a category name for the additional scripts") + placeholder = _("name of new folder"), + tooltip = _("enter a folder name for the additional scripts") } sm.widgets.add_scripts = dt.new_widget("box"){ orientation = vertical, dt.new_widget("label"){label = _("URL to download additional scripts from")}, sm.widgets.script_url, - dt.new_widget("label"){label = _("new category to place scripts in")}, - sm.widgets.new_category, + dt.new_widget("label"){label = _("new folder to place scripts in")}, + sm.widgets.new_folder, dt.new_widget("button"){ label = _("install additional scripts"), clicked_callback = function(this) @@ -1126,6 +1329,8 @@ sm.widgets.allow_disable = dt.new_widget("check_button"){ clicked_callback = function(this) if this.value == true then sm.widgets.disable_scripts.sensitive = true + else + sm.widgets.disable_scripts.sensitive = false end end, } @@ -1137,47 +1342,69 @@ sm.widgets.disable_scripts = dt.new_widget("button"){ local LUARC = dt.configuration.config_dir .. PS .. "luarc" df.file_move(LUARC, LUARC .. ".disabled") log.msg(log.info, "lua scripts disabled") - dt.print(_("lua scripts will not run the next time darktable is started")) + log.msg(log.screen, _("lua scripts will not run the next time darktable is started")) end } sm.widgets.install_update = dt.new_widget("box"){ orientation = "vertical", - dt.new_widget("section_label"){label = _("update scripts")}, + dt.new_widget("section_label"){label = _(" ")}, + dt.new_widget("label"){label = " "}, + dt.new_widget("label"){label = _("update scripts")}, + dt.new_widget("label"){label = " "}, sm.widgets.update_script_choices, sm.widgets.update, - dt.new_widget("section_label"){label = _("add more scripts")}, + dt.new_widget("section_label"){label = " "}, + dt.new_widget("label"){label = " "}, + dt.new_widget("label"){label = _("add more scripts")}, + dt.new_widget("label"){label = " "}, sm.widgets.add_scripts, - dt.new_widget("section_label"){label = _("disable scripts")}, + dt.new_widget("section_label"){label = " "}, + dt.new_widget("label"){label = " "}, + dt.new_widget("label"){label = _("disable scripts")}, + dt.new_widget("label"){label = " "}, sm.widgets.allow_disable, - sm.widgets.disable_scripts + sm.widgets.disable_scripts, + dt.new_widget("label"){label = " "}, } -- manage the scripts -sm.widgets.category_selector = dt.new_widget("combobox"){ - label = _("category"), - tooltip = _("select the script category"), +sm.widgets.folder_selector = dt.new_widget("combobox"){ + label = _("folder"), + tooltip = _( "select the script folder"), selected = 1, changed_callback = function(self) if sm.run then - pref_write("category_selector", "integer", self.selected) - change_category(self.value) + pref_write("folder_selector", "integer", self.selected) + change_folder(self.value) end end, - table.unpack(sm.categories), + table.unpack(sm.folders), } +-- a script "button" consists of: +-- a button to start and stop the script +-- a label that contains the name of the script +-- a horizontal box that contains the button and the label + sm.widgets.buttons ={} +sm.widgets.labels = {} +sm.widgets.boxes = {} + for i =1, DEFAULT_BUTTONS_PER_PAGE do table.insert(sm.widgets.buttons, dt.new_widget("button"){}) - sm.page_status.buttons_create = sm.page_status.buttons_created + 1 + table.insert(sm.widgets.labels, dt.new_widget("label"){}) + table.insert(sm.widgets.boxes, dt.new_widget("box"){ orientation = "horizontal", expand = false, fill = false, + sm.widgets.buttons[i], sm.widgets.labels[i]}) + sm.page_status.buttons_created = sm.page_status.buttons_created + 1 end local page_back = "<" local page_forward = ">" sm.widgets.page_status = dt.new_widget("label"){label = _("page:")} + sm.widgets.page_back = dt.new_widget("button"){ label = page_back, clicked_callback = function(this) @@ -1205,10 +1432,12 @@ sm.widgets.page_control = dt.new_widget("box"){ sm.widgets.scripts = dt.new_widget("box"){ orientation = vertical, + dt.new_widget("section_label"){label = _(" ")}, + dt.new_widget("label"){label = " "}, dt.new_widget("label"){label = _("scripts")}, - sm.widgets.category_selector, + sm.widgets.folder_selector, sm.widgets.page_control, - table.unpack(sm.widgets.buttons) + table.unpack(sm.widgets.boxes), } -- configure options @@ -1234,21 +1463,16 @@ sm.widgets.change_buttons = dt.new_widget("button"){ sm.widgets.configure = dt.new_widget("box"){ orientation = "vertical", + dt.new_widget("section_label"){label = " "}, + dt.new_widget("label"){label = " "}, dt.new_widget("label"){label = _("configuration")}, + dt.new_widget("label"){label = " "}, sm.widgets.num_buttons, + dt.new_widget("label"){label = " "}, sm.widgets.change_buttons, + dt.new_widget("label"){label = " "}, } -sm.widgets.color = dt.new_widget("check_button"){ - label = _("use color interface?"), - value = pref_read("use_color", "bool"), - clicked_callback = function(this) - pref_write("use_color", "bool", this.value) - sm.use_color = this.value - end -} -table.insert(sm.widgets.configure, sm.widgets.color) - -- stack for the options sm.widgets.main_stack = dt.new_widget("stack"){ @@ -1294,7 +1518,7 @@ else function(event, old_view, new_view) if new_view.name == "lighttable" and old_view.name == "darkroom" then install_module() - end + end end ) sm.event_registered = true From ff20098175d99588ee414d2f38fbf4fbb08f5ce3 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Fri, 14 Jun 2024 12:33:35 -0400 Subject: [PATCH 316/445] lib/dtuils/system - removed ds.sanitize wrapped around non windows command. --- lib/dtutils/system.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/dtutils/system.lua b/lib/dtutils/system.lua index e8ce9af0..894ff6ea 100644 --- a/lib/dtutils/system.lua +++ b/lib/dtutils/system.lua @@ -53,7 +53,7 @@ function dtutils_system.external_command(command) if dt.configuration.running_os == "windows" then result = dtutils_system.windows_command(ds.sanitize(command)) else - result = dt.control.execute(ds.sanitize(command)) + result = dt.control.execute(command) end return result From 88e4ac1a64fdb974763a24522490847d268dd516 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Tue, 18 Jun 2024 00:29:27 -0400 Subject: [PATCH 317/445] tools/script_manager - changed API check from hard (crash) to soft which allows script_manager to fix tthe problem by checking out the correct version of the scripts for the API version. --- tools/script_manager.lua | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/tools/script_manager.lua b/tools/script_manager.lua index 955f4839..40a69628 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -68,12 +68,15 @@ end -- api check -du.check_min_api_version("9.3.0", "script_manager") +-- du.check_min_api_version("9.3.0", "script_manager") -- - - - - - - - - - - - - - - - - - - - - - - - -- C O N S T A N T S -- - - - - - - - - - - - - - - - - - - - - - - - +-- script_manager required API version +local SM_API_VER_REQD = "9.3.0" + -- path separator local PS = dt.configuration.running_os == "windows" and "\\" or "/" @@ -1189,7 +1192,7 @@ end script_manager_running_script = "script_manager" -if check_for_updates then +if check_for_updates or SM_API_VER_REQD > dt.configuration.api_version_string then local repo_data = get_repo_status(LUA_DIR) local current_branch = get_current_repo_branch(LUA_DIR) local clean = is_repo_clean(repo_data) @@ -1246,14 +1249,15 @@ if check_for_updates then local match = false - for _, branch in ipairs(branches) do + for _x, branch in ipairs(branches) do log.msg(log.debug, "checking branch " .. branch .. " against API " .. LUA_API_VER) if LUA_API_VER == branch then match = true log.msg(log.info, "checking out repo branch " .. branch) checkout_repo_branch(repo, branch) - log.msg(log.screen, "you must restart darktable to use the correct version of the lua") + log.msg(log.screen, _("you must restart darktable to use the correct version of the lua scripts")) + return end end From c95f8a23b2e371c69727ca2dc9a08ffa8b6919aa Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Tue, 18 Jun 2024 00:30:34 -0400 Subject: [PATCH 318/445] lib/dtutils/log - fix screen print check --- lib/dtutils/log.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/dtutils/log.lua b/lib/dtutils/log.lua index 6910c8eb..28dce69f 100644 --- a/lib/dtutils/log.lua +++ b/lib/dtutils/log.lua @@ -199,7 +199,7 @@ function dtutils_log.msg(level, ...) table.remove(args, 1) end local log_msg = level.label - if level.engine ~= dt_screen and call_level ~= 0 then + if level.engine ~= dt_print and call_level ~= 0 then log_msg = log_msg .. dtutils_log.caller(call_level, level.caller_info) .. " " elseif log_msg:len() > 2 then log_msg = log_msg .. " " From 94f41db6fceca0246c92ad5757782a5567d2bb19 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Wed, 19 Jun 2024 11:41:54 -0400 Subject: [PATCH 319/445] contrib/rename_images - make sure the renamed image, or first renamed image of a group is visible after renaming. --- contrib/rename_images.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/contrib/rename_images.lua b/contrib/rename_images.lua index d3ed9824..769adfac 100644 --- a/contrib/rename_images.lua +++ b/contrib/rename_images.lua @@ -214,6 +214,7 @@ end local function do_rename(images) if #images > 0 then + local first_image = images[1] local pattern = rename.widgets.pattern.text dt.preferences.write(MODULE_NAME, "pattern", "string", pattern) dt.print_log("pattern is " .. pattern) @@ -256,6 +257,7 @@ local function do_rename(images) stop_job(job) local collect_rules = dt.gui.libs.collect.filter() dt.gui.libs.collect.filter(collect_rules) + dt.gui.views.lighttable.set_image_visible(first_image) dt.print(string.format(_("renamed %d images"), #images)) else -- pattern length dt.print_error("no pattern supplied, returning...") From f8c076f3082c6305db28aea9fd32b8a7ac4fded6 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Wed, 19 Jun 2024 20:50:54 -0400 Subject: [PATCH 320/445] contrib/fujifilm_dynamic_range - added check for duplicates after an image is processed. If duplicates are found the exposure bias is applied to them. --- contrib/fujifilm_dynamic_range.lua | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/contrib/fujifilm_dynamic_range.lua b/contrib/fujifilm_dynamic_range.lua index 1034411d..ad7b2bb5 100644 --- a/contrib/fujifilm_dynamic_range.lua +++ b/contrib/fujifilm_dynamic_range.lua @@ -126,6 +126,17 @@ local function detect_dynamic_range(event, image) -- note that scene-referred workflow exposure preset also pushes exposure up by 0.5 EV image.exif_exposure_bias = image.exif_exposure_bias + tonumber(raf_result) dt.print_log("[fujifilm_dynamic_range] raw exposure bias " .. tostring(raf_result)) + -- handle any duplicates + if #image:get_group_members() > 1 then + local basename = df.get_basename(image.filename) + local grouped_images = image:get_group_members() + for _, img in ipairs(grouped_images) do + if string.match(img.filename, basename) and img.duplicate_index > 0 then + -- its a duplicate + img.exif_exposure_bias = img.exif_exposure_bias + tonumber(raf_result) + end + end + end end local function destroy() From 3bb4e9c59a422f17eb1850dff4d5bc0c2075fcef Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Thu, 20 Jun 2024 17:46:54 -0400 Subject: [PATCH 321/445] contrib/auto_snapshot - take a snapshot automatically when opening an image in darkroom --- contrib/auto_snapshot.lua | 123 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 contrib/auto_snapshot.lua diff --git a/contrib/auto_snapshot.lua b/contrib/auto_snapshot.lua new file mode 100644 index 00000000..e7d39867 --- /dev/null +++ b/contrib/auto_snapshot.lua @@ -0,0 +1,123 @@ +--[[ + + auto_snapshot.lua - automatically take a snapshot when an image is loaded in darkroom + + Copyright (C) 2024 Bill Ferguson . + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +]] +--[[ + auto_snapshot - + + automatically take a snapshot when an image is loaded in darkroom + + ADDITIONAL SOFTWARE NEEDED FOR THIS SCRIPT + None + + USAGE + * start the script from script_manager + * open an image in darkroom + + BUGS, COMMENTS, SUGGESTIONS + Bill Ferguson + + CHANGES +]] + +local dt = require "darktable" +local du = require "lib/dtutils" + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- C O N S T A N T S +-- - - - - - - - - - - - - - - - - - - - - - - - + +local MODULE = "auto_snapshot" +local DEFAULT_LOG_LEVEL = log.error + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- A P I C H E C K +-- - - - - - - - - - - - - - - - - - - - - - - - + +du.check_min_api_version("7.0.0", MODULE) -- choose the minimum version that contains the features you need + + +-- - - - - - - - - - - - - - - - - - - - - - - - - - +-- I 1 8 N +-- - - - - - - - - - - - - - - - - - - - - - - - - - + +local gettext = dt.gettext.gettext + +dt.gettext.bindtextdomain(MODULE , dt.configuration.config_dir .. "/lua/locale/") + +local function _(msgid) + return gettext(MODULE, msgid) +end + + +-- - - - - - - - - - - - - - - - - - - - - - - - - - +-- S C R I P T M A N A G E R I N T E G R A T I O N +-- - - - - - - - - - - - - - - - - - - - - - - - - - + +local script_data = {} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them + +script_data.metadata = { + name = "auto_snapshot", -- name of script + purpose = _("automatically take a snapshot when an image is loaded in darkroom"), -- purpose of script + author = "Bill Ferguson ", -- your name and optionally e-mail address + help = "" -- URL to help/documentation +} + + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- L O G L E V E L +-- - - - - - - - - - - - - - - - - - - - - - - - + +log.log_level(DEFAULT_LOG_LEVEL) + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- N A M E S P A C E +-- - - - - - - - - - - - - - - - - - - - - - - - + +local auto_snapshot = {} + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- D A R K T A B L E I N T E G R A T I O N +-- - - - - - - - - - - - - - - - - - - - - - - - + +local function destroy() + dt.destroy_event(MODULE, "darkroom-image-loaded") +end + +script_data.destroy = destroy + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- E V E N T S +-- - - - - - - - - - - - - - - - - - - - - - - - + +dt.register_event(MODULE, "darkroom-image-loaded", + function(event, clean, image) + if clean then + dt.gui.libs.snapshots.take_snapshot() + end + + end +) + + +return script_data \ No newline at end of file From ba94914c0e256aae2d09f2c6fc8877da1c70edfb Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Thu, 20 Jun 2024 18:09:10 -0400 Subject: [PATCH 322/445] contrib/auto_snapshot - added Lua option to create always create a snapshot when opening an image in darkroom, even if it is altered --- contrib/auto_snapshot.lua | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/contrib/auto_snapshot.lua b/contrib/auto_snapshot.lua index e7d39867..a5eca61a 100644 --- a/contrib/auto_snapshot.lua +++ b/contrib/auto_snapshot.lua @@ -37,6 +37,7 @@ local dt = require "darktable" local du = require "lib/dtutils" +local log = require "lib/dtutils.log" -- - - - - - - - - - - - - - - - - - - - - - - - -- C O N S T A N T S @@ -96,6 +97,13 @@ log.log_level(DEFAULT_LOG_LEVEL) local auto_snapshot = {} +-- - - - - - - - - - - - - - - - - - - - - - - - +-- P R E F E R E N C E S +-- - - - - - - - - - - - - - - - - - - - - - - - + +dt.preferences.register(MODULE, "always_create_snapshot", "bool", "always automatically create_snapshot", + "auto_snapshot - create a snapshot even if the image is altered", false) + -- - - - - - - - - - - - - - - - - - - - - - - - -- D A R K T A B L E I N T E G R A T I O N -- - - - - - - - - - - - - - - - - - - - - - - - @@ -112,7 +120,10 @@ script_data.destroy = destroy dt.register_event(MODULE, "darkroom-image-loaded", function(event, clean, image) - if clean then + local always = dt.preferences.read(MODULE, "always_create_snapshot", "bool") + if clean and always then + dt.gui.libs.snapshots.take_snapshot() + elseif clean and not image.is_altered then dt.gui.libs.snapshots.take_snapshot() end From 316a89d6a83fc11ddc25c1868c11608c27fd0ec7 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sun, 30 Jun 2024 12:44:02 -0400 Subject: [PATCH 323/445] contrib/auto_snapshot - fixed email address contrib/dbmain --- contrib/auto_snapshot.lua | 6 +++--- contrib/dbmaint.lua | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/contrib/auto_snapshot.lua b/contrib/auto_snapshot.lua index a5eca61a..f42631f4 100644 --- a/contrib/auto_snapshot.lua +++ b/contrib/auto_snapshot.lua @@ -2,7 +2,7 @@ auto_snapshot.lua - automatically take a snapshot when an image is loaded in darkroom - Copyright (C) 2024 Bill Ferguson . + Copyright (C) 2024 Bill Ferguson . This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -30,7 +30,7 @@ * open an image in darkroom BUGS, COMMENTS, SUGGESTIONS - Bill Ferguson + Bill Ferguson CHANGES ]] @@ -80,7 +80,7 @@ script_data.show = nil -- only required for libs since the destroy_ script_data.metadata = { name = "auto_snapshot", -- name of script purpose = _("automatically take a snapshot when an image is loaded in darkroom"), -- purpose of script - author = "Bill Ferguson ", -- your name and optionally e-mail address + author = "Bill Ferguson ", -- your name and optionally e-mail address help = "" -- URL to help/documentation } diff --git a/contrib/dbmaint.lua b/contrib/dbmaint.lua index 7f2f21e0..70454ff6 100644 --- a/contrib/dbmaint.lua +++ b/contrib/dbmaint.lua @@ -2,7 +2,7 @@ dbmaint.lua - perform database maintenance - Copyright (C) 2024 Bill Ferguson . + Copyright (C) 2024 Bill Ferguson . This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -31,7 +31,7 @@ * look at the results and choose to delete or not BUGS, COMMENTS, SUGGESTIONS - Bill Ferguson + Bill Ferguson CHANGES ]] @@ -84,7 +84,7 @@ script_data.show = nil -- only required for libs since the destroy_ script_data.metadata = { name = "dbmaint", purpose = _("perform database maintenance"), - author = "Bill Ferguson ", + author = "Bill Ferguson ", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/dbmaint/" } From 36023d8d4f5e83bde5d96b249dca6ccaf81e26f0 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Mon, 8 Jul 2024 11:43:42 -0400 Subject: [PATCH 324/445] lib/dtutils/system - fixed typo in quote_windows_command call --- lib/dtutils/system.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/dtutils/system.lua b/lib/dtutils/system.lua index 894ff6ea..5326018b 100644 --- a/lib/dtutils/system.lua +++ b/lib/dtutils/system.lua @@ -91,7 +91,7 @@ function dtutils_system.windows_command(command) if file then dt.print_log("opened file") command = string.gsub(command, "%%", "%%%%") -- escape % from windows shell - command = quote_windows-command(command) + command = quote_windows_command(command) file:write(command) file:close() From e8a99c83968c49ec8d849c2d074a015e2ddaa893 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Wed, 10 Jul 2024 15:17:35 -0400 Subject: [PATCH 325/445] contrib/RL_out_sharp - add function to preserve the exported images metadata in the sharpened image using exiftool --- contrib/RL_out_sharp.lua | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/contrib/RL_out_sharp.lua b/contrib/RL_out_sharp.lua index aa64b3f8..9e0a1fb0 100644 --- a/contrib/RL_out_sharp.lua +++ b/contrib/RL_out_sharp.lua @@ -99,7 +99,18 @@ if not dt.preferences.read(MODULE_NAME, "initialized", "bool") then dt.preferences.write(MODULE_NAME, "iterations", "string", "10") dt.preferences.write(MODULE_NAME, "jpg_quality", "string", "95") dt.preferences.write(MODULE_NAME, "initialized", "bool", true) - end +end + +-- preserve original image metadata in the output image ----------------------- +local function preserve_metadata(original, sharpened) + local exiftool = df.check_if_bin_exists("exiftool") + + if exiftool then + dtsys.external_command("exiftool -overwrite_original_in_place -tagsFromFile " .. original .. " " .. sharpened) + else + dt.print_log(MODULE .. " exiftool not found, metadata not preserved") + end +end -- setup export --------------------------------------------------------------- @@ -163,7 +174,10 @@ local function export2RL(storage, image_table, extra_data) if result ~= 0 then dt.print(_("sharpening error")) return - end + end + + -- copy metadata from input_file to output_file + preserve_metadata(input_file, output_file) -- delete temp image os.remove(temp_name) From 9f423eeef39db6e26a0123179377648b34e3e2fa Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sat, 13 Jul 2024 12:46:34 -0400 Subject: [PATCH 326/445] lib/dtutils/file - reverted io_popen and os_execute wrappers as lib/dtutils/system they don't work in this situation (no control over the input strings) --- lib/dtutils/file.lua | 20 +++++++------- lib/dtutils/system.lua | 61 ++++-------------------------------------- 2 files changed, 15 insertions(+), 66 deletions(-) diff --git a/lib/dtutils/file.lua b/lib/dtutils/file.lua index b8717116..cd898e71 100644 --- a/lib/dtutils/file.lua +++ b/lib/dtutils/file.lua @@ -42,7 +42,7 @@ end local function _win_os_execute(cmd) local result = nil - local p = dsys.io_popen(cmd) + local p = io.popen(cmd) local output = p:read("*a") p:close() if string.match(output, "true") then @@ -94,7 +94,7 @@ dtutils_file.libdoc.functions["test_file"] = { function dtutils_file.test_file(path, test) local cmd = "test -" - local engine = dsys.os_execute + local engine = os.execute local cmdstring = "" if dt.configuration.running_os == "windows" then @@ -167,7 +167,7 @@ local function _search_for_bin_windows(bin) for _,arg in ipairs(args) do local cmd = "where " .. arg .. " " .. ds.sanitize(bin) - local p = dsys.io_popen(cmd) + local p = io.popen(cmd) local output = p:read("*a") p:close() local lines = du.split(output, "\n") @@ -191,7 +191,7 @@ end local function _search_for_bin_nix(bin) local result = false - local p = dsys.io_popen("command -v " .. bin) + local p = io.popen("command -v " .. bin) local output = p:read("*a") p:close() if string.len(output) > 0 then @@ -220,7 +220,7 @@ local function _search_for_bin_macos(bin) search_start = "/Applications/" .. bin .. ".app" end - local p = dsys.io_popen("find " .. search_start .. " -type f -name " .. bin .. " -print") + local p = io.popen("find " .. search_start .. " -type f -name " .. bin .. " -print") local output = p:read("*a") p:close() local lines = du.split(output, "\n") @@ -445,7 +445,7 @@ function dtutils_file.check_if_file_exists(filepath) local result = false if (dt.configuration.running_os == 'windows') then filepath = string.gsub(filepath, '[\\/]+', '\\') - local p = dsys.io_popen("if exist " .. dtutils_file.sanitize_filename(filepath) .. " (echo 'yes') else (echo 'no')") + local p = io.popen("if exist " .. dtutils_file.sanitize_filename(filepath) .. " (echo 'yes') else (echo 'no')") local ans = p:read("*all") p:close() if string.match(ans, "yes") then @@ -456,7 +456,7 @@ function dtutils_file.check_if_file_exists(filepath) -- result = false -- end elseif (dt.configuration.running_os == "linux") then - result = dsys.os_execute('test -e ' .. dtutils_file.sanitize_filename(filepath)) + result = os.execute('test -e ' .. dtutils_file.sanitize_filename(filepath)) if not result then result = false end @@ -522,9 +522,9 @@ function dtutils_file.file_copy(fromFile, toFile) local result = nil -- if cp exists, use it if dt.configuration.running_os == "windows" then - result = dsys.os_execute('copy "' .. fromFile .. '" "' .. toFile .. '"') + result = os.execute('copy "' .. fromFile .. '" "' .. toFile .. '"') elseif dtutils_file.check_if_bin_exists("cp") then - result = dsys.os_execute("cp '" .. fromFile .. "' '" .. toFile .. "'") + result = os.execute("cp '" .. fromFile .. "' '" .. toFile .. "'") end -- if cp was not present, or if cp failed, then a pure lua solution @@ -575,7 +575,7 @@ function dtutils_file.file_move(fromFile, toFile) if not success then -- an error occurred, so let's try using the operating system function if dtutils_file.check_if_bin_exists("mv") then - success = dsys.os_execute("mv '" .. fromFile .. "' '" .. toFile .. "'") + success = os.execute("mv '" .. fromFile .. "' '" .. toFile .. "'") end -- if the mv didn't exist or succeed, then... if not success then diff --git a/lib/dtutils/system.lua b/lib/dtutils/system.lua index 5326018b..2ec2c313 100644 --- a/lib/dtutils/system.lua +++ b/lib/dtutils/system.lua @@ -51,7 +51,7 @@ function dtutils_system.external_command(command) local result = nil if dt.configuration.running_os == "windows" then - result = dtutils_system.windows_command(ds.sanitize(command)) + result = dtutils_system.windows_command(command) else result = dt.control.execute(command) end @@ -78,20 +78,20 @@ dtutils_system.libdoc.functions["windows_command"] = { Copyright = [[]], } -local function quote_windows_command(command) +local function _quote_windows_command(command) return "\"" .. command .. "\"" end function dtutils_system.windows_command(command) local result = 1 - local fname = ds.sanitize(dt.configuration.tmp_dir .. "/run_command.bat") + local fname = dt.configuration.tmp_dir .. "/run_command.bat" local file = io.open(fname, "w") if file then dt.print_log("opened file") command = string.gsub(command, "%%", "%%%%") -- escape % from windows shell - command = quote_windows_command(command) + command = _quote_windows_command(command) file:write(command) file:close() @@ -124,6 +124,7 @@ dtutils_system.libdoc.functions["launch_default_app"] = { License = [[]], Copyright = [[]], } + function dtutils_system.launch_default_app(path) local open_cmd = "xdg-open " if (dt.configuration.running_os == "windows") then @@ -134,56 +135,4 @@ function dtutils_system.launch_default_app(path) return dtutils_system.external_command(open_cmd .. path) end - -dtutils_system.libdoc.functions["os_execute"] = { - Name = [[os_execute]], - Synopsis = [[wrapper around the lua os.execute function]], - Usage = [[local dsys = require "lib/dtutils.file" - - result = dsys.os_execute(cmd) - cmd - string - a command to execute on the operating system]], - Description = [[os_execute wraps the lua os.execute system call to provide - correct sanitization of windows commands]], - Return_Value = [[see the lua os.execute documentation]], - Limitations = [[]], - Example = [[]], - See_Also = [[]], - Reference = [[]], - License = [[]], - Copyright = [[]], -} - -function dtutils_system.os_execute(cmd) - if dt.configuration.running_os == "windows" then - cmd = quote_windows_command(cmd) - end - return os.execute(cmd) -end - -dtutils_system.libdoc.functions["io_popen"] = { - Name = [[io_popen]], - Synopsis = [[wrapper around the lua io.popen function]], - Usage = [[local dsys = require "lib/dtutils.file" - - result = dsys.io_popen(cmd) - cmd - string - a command to execute and attach to]], - Description = [[io_popen wraps the lua io.popen system call to provide - correct sanitization of windows commands]], - Return_Value = [[see the lua io.popen documentation]], - Limitations = [[]], - Example = [[]], - See_Also = [[]], - Reference = [[]], - License = [[]], - Copyright = [[]], -} - -function dtutils_system.io_popen(cmd) - if dt.configuration.running_os == "windows" then - cmd = quote_windows_command(cmd) - end - return io.popen(cmd) -end - - return dtutils_system From 1b272be5f560ba9d4239d2f47c687a630f6453df Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sat, 13 Jul 2024 12:48:37 -0400 Subject: [PATCH 327/445] various scripts - reverted the calls to io_popen and os_execute back to the respective lua calls. --- contrib/autostyle.lua | 4 ++-- contrib/color_profile_manager.lua | 2 +- contrib/fujifilm_dynamic_range.lua | 2 +- contrib/fujifilm_ratings.lua | 4 ++-- contrib/geoJSON_export.lua | 2 +- contrib/geoToolbox.lua | 2 +- contrib/image_stack.lua | 2 +- contrib/image_time.lua | 6 +++--- contrib/kml_export.lua | 2 +- official/enfuse.lua | 2 +- tools/executable_manager.lua | 4 ++-- tools/get_lib_manpages.lua | 4 ++-- tools/get_libdoc.lua | 2 +- tools/script_manager.lua | 14 +++++++------- 14 files changed, 26 insertions(+), 26 deletions(-) diff --git a/contrib/autostyle.lua b/contrib/autostyle.lua index 319b8f3a..336e6f78 100644 --- a/contrib/autostyle.lua +++ b/contrib/autostyle.lua @@ -69,7 +69,7 @@ script_data.show = nil -- only required for libs since the destroy_method only h -- run command and retrieve stdout local function get_stdout(cmd) -- Open the command, for reading - local fd = assert(syslib.io_popen(cmd, 'r')) + local fd = assert(io.popen(cmd, 'r')) darktable.control.read(fd) -- slurp the whole file local data = assert(fd:read('*a')) @@ -188,4 +188,4 @@ darktable.register_event("autostyle", "post-import-image", script_data.destroy = destroy -return script_data \ No newline at end of file +return script_data diff --git a/contrib/color_profile_manager.lua b/contrib/color_profile_manager.lua index d87d9a6a..52fc38ce 100644 --- a/contrib/color_profile_manager.lua +++ b/contrib/color_profile_manager.lua @@ -107,7 +107,7 @@ end local function list_profiles(dir) local files = {} - local p = dtsys.io_popen(DIR_CMD .. " " .. dir) + local p = io.popen(DIR_CMD .. " " .. dir) if p then for line in p:lines() do table.insert(files, line) diff --git a/contrib/fujifilm_dynamic_range.lua b/contrib/fujifilm_dynamic_range.lua index ad7b2bb5..6116d352 100644 --- a/contrib/fujifilm_dynamic_range.lua +++ b/contrib/fujifilm_dynamic_range.lua @@ -106,7 +106,7 @@ local function detect_dynamic_range(event, image) -- without -n flag, exiftool will round to the nearest tenth command = command .. " -RawExposureBias -n -t " .. RAF_filename dt.print_log(command) - output = dtsys.io_popen(command) + output = io.popen(command) local raf_result = output:read("*all") output:close() if #raf_result == 0 then diff --git a/contrib/fujifilm_ratings.lua b/contrib/fujifilm_ratings.lua index b2f11fe3..049e3c20 100644 --- a/contrib/fujifilm_ratings.lua +++ b/contrib/fujifilm_ratings.lua @@ -65,7 +65,7 @@ local function detect_rating(event, image) local JPEG_filename = string.gsub(RAF_filename, "%.RAF$", ".JPG") local command = "exiftool -Rating " .. JPEG_filename dt.print_log(command) - local output = dtsys.io_popen(command) + local output = io.popen(command) local jpeg_result = output:read("*all") output:close() if string.len(jpeg_result) > 0 then @@ -76,7 +76,7 @@ local function detect_rating(event, image) end command = "exiftool -Rating " .. RAF_filename dt.print_log(command) - output = dtsys.io_popen(command) + output = io.popen(command) local raf_result = output:read("*all") output:close() if string.len(raf_result) > 0 then diff --git a/contrib/geoJSON_export.lua b/contrib/geoJSON_export.lua index 406c37c2..2ff30807 100644 --- a/contrib/geoJSON_export.lua +++ b/contrib/geoJSON_export.lua @@ -331,7 +331,7 @@ dt.preferences.register("geoJSON_export", _("opens the geoJSON file after the export with the standard program for geoJSON files"), false ) -local handle = dtsys.io_popen("xdg-user-dir DESKTOP") +local handle = io.popen("xdg-user-dir DESKTOP") local result = handle:read() handle:close() if (result == nil) then diff --git a/contrib/geoToolbox.lua b/contrib/geoToolbox.lua index d654eeba..68fdc3c6 100644 --- a/contrib/geoToolbox.lua +++ b/contrib/geoToolbox.lua @@ -412,7 +412,7 @@ local function reverse_geocode() -- jq could be replaced with a Lua JSON parser startCommand = string.format("curl --silent \"https://api.mapbox.com/geocoding/v5/mapbox.places/%s,%s.json?types=%s&access_token=%s\" | jq '.features | .[0] | '.text''", lon1, lat1, types, tokan) - local handle = dtsys.io_popen(startCommand) + local handle = io.popen(startCommand) local result = trim12(handle:read("*a")) handle:close() diff --git a/contrib/image_stack.lua b/contrib/image_stack.lua index ba0909b1..c63ff166 100644 --- a/contrib/image_stack.lua +++ b/contrib/image_stack.lua @@ -348,7 +348,7 @@ local function list_files(search_string) search_string = string.gsub(search_string, "/", "\\\\") end - local f = dtsys.io_popen(ls .. search_string) + local f = io.popen(ls .. search_string) if f then local found_file = f:read() while found_file do diff --git a/contrib/image_time.lua b/contrib/image_time.lua index fa00b576..a35f751f 100644 --- a/contrib/image_time.lua +++ b/contrib/image_time.lua @@ -226,7 +226,7 @@ local function get_image_taken_time(image) local exiv2 = df.check_if_bin_exists("exiv2") if exiv2 then - p = dtsys.io_popen(exiv2 .. " -K Exif.Image.DateTime " .. image.path .. PS .. image.filename) + p = io.popen(exiv2 .. " -K Exif.Image.DateTime " .. image.path .. PS .. image.filename) if p then for line in p:lines() do if string.match(line, "Exif.Image.DateTime") then @@ -244,7 +244,7 @@ end local function _get_windows_image_file_creation_time(image) local datetime = nil - local p = dtsys.io_popen("dir " .. image.path .. PS .. image.filename) + local p = io.popen("dir " .. image.path .. PS .. image.filename) if p then for line in p:lines() do if string.match(line, ds.sanitize_lua(image.filename)) then @@ -265,7 +265,7 @@ end local function _get_nix_image_file_creation_time(image) local datetime = nil - local p = dtsys.io_popen("ls -lL --time-style=full-iso " .. image.path .. PS .. image.filename) + local p = io.popen("ls -lL --time-style=full-iso " .. image.path .. PS .. image.filename) if p then for line in p:lines() do if string.match(line, ds.sanitize_lua(image.filename)) then diff --git a/contrib/kml_export.lua b/contrib/kml_export.lua index ec7218ca..ec1aa04a 100644 --- a/contrib/kml_export.lua +++ b/contrib/kml_export.lua @@ -343,7 +343,7 @@ if dt.configuration.running_os == "windows" then elseif dt.configuration.running_os == "macos" then defaultDir = os.getenv("HOME") else - local handle = dsys.io_popen("xdg-user-dir DESKTOP") + local handle = io.popen("xdg-user-dir DESKTOP") defaultDir = handle:read() handle:close() end diff --git a/official/enfuse.lua b/official/enfuse.lua index c193c35e..c8df51b1 100644 --- a/official/enfuse.lua +++ b/official/enfuse.lua @@ -116,7 +116,7 @@ if enfuse_installed then local version = nil - local p = dtsys.io_popen(enfuse_installed .. " --version") + local p = io.popen(enfuse_installed .. " --version") local f = p:read("all") p:close() version = string.match(f, "enfuse (%d.%d)") diff --git a/tools/executable_manager.lua b/tools/executable_manager.lua index 0e286680..ffdf532d 100644 --- a/tools/executable_manager.lua +++ b/tools/executable_manager.lua @@ -76,7 +76,7 @@ local function grep(file, pattern) if dt.configuration.running_os == "windows" then -- use find to get the matches local command = "\\windows\\system32\\find.exe " .. "\"" .. pattern .. "\"" .. " " .. file - local f = dtsys.io_popen(command) + local f = io.popen(command) local output = f:read("all") f:close() -- strip out the first line @@ -85,7 +85,7 @@ local function grep(file, pattern) else -- use grep and just return the answers local command = "grep " .. pattern .. " " .. file - local f = dtsys.io_popen(command) + local f = io.popen(command) local output = f:read("all") f:close() result = du.split(output, "\n") diff --git a/tools/get_lib_manpages.lua b/tools/get_lib_manpages.lua index 91d5dbb3..a5a7ab97 100644 --- a/tools/get_lib_manpages.lua +++ b/tools/get_lib_manpages.lua @@ -46,7 +46,7 @@ local function output_man(d) mf:close() if df.check_if_bin_exists("groff") then if df.check_if_bin_exists("ps2pdf") then - dtsys.os_execute("groff -man " .. fname .. " | ps2pdf - " .. fname .. ".pdf") + os.execute("groff -man " .. fname .. " | ps2pdf - " .. fname .. ".pdf") else log.msg(log.error, "Missing ps2pdf. Can't generate pdf man pages.") end @@ -60,7 +60,7 @@ end -- find the libraries -local output = dtsys.io_popen("cd "..dt.configuration.config_dir.."/lua/lib ;find . -name \\*.lua -print | sort") +local output = io.popen("cd "..dt.configuration.config_dir.."/lua/lib ;find . -name \\*.lua -print | sort") -- loop through the libraries diff --git a/tools/get_libdoc.lua b/tools/get_libdoc.lua index 2328014a..3749a683 100644 --- a/tools/get_libdoc.lua +++ b/tools/get_libdoc.lua @@ -37,7 +37,7 @@ end -- find the libraries -local output = dtsys.io_popen("cd "..dt.configuration.config_dir.."/lua/lib ;find . -name \\*.lua -print | sort") +local output = io.popen("cd "..dt.configuration.config_dir.."/lua/lib ;find . -name \\*.lua -print | sort") -- loop through the libraries diff --git a/tools/script_manager.lua b/tools/script_manager.lua index 40a69628..b39f9e42 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -89,7 +89,7 @@ local MIN_BUTTONS_PER_PAGE = 5 local MAX_BUTTONS_PER_PAGE = 20 local DEFAULT_BUTTONS_PER_PAGE = 10 -local DEFAULT_LOG_LEVEL = log.error +local DEFAULT_LOG_LEVEL = log.debug local LUA_DIR = dt.configuration.config_dir .. PS .. "lua" local LUA_SCRIPT_REPO = "https://github.com/darktable-org/lua-scripts.git" @@ -244,7 +244,7 @@ end local function get_repo_status(repo) local old_log_level = set_log_level(sm.log_level) - local p = dtsys.io_popen("cd " .. repo .. CS .. "git status") + local p = io.popen("cd " .. repo .. CS .. "git status") if p then local data = p:read("*a") @@ -262,7 +262,7 @@ local function get_current_repo_branch(repo) local branch = nil - local p = dtsys.io_popen("cd " .. repo .. CS .. "git branch --all") + local p = io.popen("cd " .. repo .. CS .. "git branch --all") if p then local data = p:read("*a") @@ -292,7 +292,7 @@ local function get_repo_branches(repo) local old_log_level = set_log_level(sm.log_level) local branches = {} - local p = dtsys.io_popen("cd " .. repo .. CS .. "git pull --all" .. CS .. "git branch --all") + local p = io.popen("cd " .. repo .. CS .. "git pull --all" .. CS .. "git branch --all") if p then local data = p:read("*a") @@ -332,7 +332,7 @@ local function checkout_repo_branch(repo, branch) log.msg(log.info, "checkout out branch " .. branch .. " from repository " .. repo) - dtsys.os_execute("cd " .. repo .. CS .. "git checkout " .. branch) + os.execute("cd " .. repo .. CS .. "git checkout " .. branch) restore_log_level(old_log_level) end @@ -668,7 +668,7 @@ local function scan_scripts(script_dir) log.msg(log.debug, "find command is " .. find_cmd) -- scan the scripts - local output = dtsys.io_popen(find_cmd) + local output = io.popen(find_cmd) for line in output:lines() do log.msg(log.debug, "line is " .. line) local l = string.gsub(line, ds.sanitize_lua(LUA_DIR) .. PS, "") -- strip the lua dir off @@ -754,7 +754,7 @@ local function scan_repositories() log.msg(log.debug, "find command is " .. find_cmd) - local output = dtsys.io_popen(find_cmd) + local output = io.popen(find_cmd) for line in output:lines() do local l = string.gsub(line, ds.sanitize_lua(LUA_DIR) .. PS, "") -- strip the lua dir off From 3e37c06b84e9f07a0f5586af352cefa4ce2ee8f3 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sat, 13 Jul 2024 14:44:01 -0400 Subject: [PATCH 328/445] lib/dtutils/string - Added check to determine if string needs to be sanitized. Check looks for unprintable characters and spaces. --- lib/dtutils/string.lua | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/lib/dtutils/string.lua b/lib/dtutils/string.lua index 926c6673..d64a95a2 100644 --- a/lib/dtutils/string.lua +++ b/lib/dtutils/string.lua @@ -298,16 +298,32 @@ local function _sanitize_windows(str) end end +local function _should_be_sanitized(str) + local old_log_level = log.log_level() + local result = false + log.log_level(dtutils_string.log_level) + if string.match(str, "[^%g]") then + result = true + end + log.log_level(old_log_level) + return result +end + function dtutils_string.sanitize(str) local old_log_level = log.log_level() + local sanitized_str = nil log.log_level(dtutils_string.log_level) - if dt.configuration.running_os == "windows" then - log.log_level(old_log_level) - return _sanitize_windows(str) + if _should_be_sanitized(str) then + if dt.configuration.running_os == "windows" then + sanitized_str = _sanitize_windows(str) + else + sanitized_str = _sanitize_posix(str) + end else - log.log_level(old_log_level) - return _sanitize_posix(str) + sanitized_str = str end + log.log_level(old_log_level) + return sanitized_str end dtutils_string.libdoc.functions["sanitize_lua"] = { From cc11c1c3b89b0b834c6652759a4eaad53a86881e Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Thu, 18 Jul 2024 12:42:12 -0400 Subject: [PATCH 329/445] tools/script_manager - set log level to warn instead of debug --- tools/script_manager.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/script_manager.lua b/tools/script_manager.lua index b39f9e42..b62e0e2c 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -89,7 +89,7 @@ local MIN_BUTTONS_PER_PAGE = 5 local MAX_BUTTONS_PER_PAGE = 20 local DEFAULT_BUTTONS_PER_PAGE = 10 -local DEFAULT_LOG_LEVEL = log.debug +local DEFAULT_LOG_LEVEL = log.warn local LUA_DIR = dt.configuration.config_dir .. PS .. "lua" local LUA_SCRIPT_REPO = "https://github.com/darktable-org/lua-scripts.git" From 535ba78a06380c6d29e7a307e3b5a4613ebbec58 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sun, 21 Jul 2024 22:43:59 -0400 Subject: [PATCH 330/445] lib/dtutils/system - remove _quote_windows_command --- lib/dtutils/system.lua | 5 ----- 1 file changed, 5 deletions(-) diff --git a/lib/dtutils/system.lua b/lib/dtutils/system.lua index 2ec2c313..0df0dee9 100644 --- a/lib/dtutils/system.lua +++ b/lib/dtutils/system.lua @@ -78,10 +78,6 @@ dtutils_system.libdoc.functions["windows_command"] = { Copyright = [[]], } -local function _quote_windows_command(command) - return "\"" .. command .. "\"" -end - function dtutils_system.windows_command(command) local result = 1 @@ -91,7 +87,6 @@ function dtutils_system.windows_command(command) if file then dt.print_log("opened file") command = string.gsub(command, "%%", "%%%%") -- escape % from windows shell - command = _quote_windows_command(command) file:write(command) file:close() From 46e729b40e8e8fb0f9e4718679940a78a830bafb Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Thu, 8 Aug 2024 19:43:33 -0400 Subject: [PATCH 331/445] fixed translatable strings for inclusion into darktable --- contrib/LabelsToTags.lua | 8 ++++---- contrib/change_group_leader.lua | 4 ++-- contrib/geoJSON_export.lua | 2 +- contrib/geoToolbox.lua | 6 +++--- contrib/image_time.lua | 2 +- contrib/rate_group.lua | 14 ++++++++------ contrib/transfer_hierarchy.lua | 4 ++-- examples/multi_os.lua | 2 +- tools/script_manager.lua | 4 ++-- 9 files changed, 24 insertions(+), 22 deletions(-) diff --git a/contrib/LabelsToTags.lua b/contrib/LabelsToTags.lua index 6046f9c3..1054a8b9 100644 --- a/contrib/LabelsToTags.lua +++ b/contrib/LabelsToTags.lua @@ -130,10 +130,10 @@ local initialAvailableMappings = { ["***+**"] = { _("blue") }, ["****+*"] = { _("purple") } }, [_("single colors")] = { ["+----*"] = { _("red"), _("only red") }, - ["-+---*"] = { _("Yellow"), _("only yellow") }, - ["--+--*"] = { _("Green"), _("only green") }, - ["---+-*"] = { _("Blue"), _("only blue") }, - ["----+*"] = { _("Purple"), _("only purple") } }, + ["-+---*"] = { _("yellow"), _("only yellow") }, + ["--+--*"] = { _("green"), _("only green") }, + ["---+-*"] = { _("blue"), _("only blue") }, + ["----+*"] = { _("purple"), _("only purple") } }, [_("ratings")] = { ["*****0"] = { _("no stars"), _("not rejected") }, ["*****1"] = { _("one star"), _("not rejected") }, ["*****2"] = { _("two stars"), _("not rejected") }, diff --git a/contrib/change_group_leader.lua b/contrib/change_group_leader.lua index 202f3f6e..11522cbd 100644 --- a/contrib/change_group_leader.lua +++ b/contrib/change_group_leader.lua @@ -127,7 +127,7 @@ end local function process_image_groups(images) if #images < 1 then - dt.print(_("o images selected")) + dt.print(_("no images selected")) dt.print_log(MODULE .. "no images seletected, returning...") else local mode = cgl.widgets.mode.value @@ -204,4 +204,4 @@ script_data.restart = restart script_data.destroy_method = "hide" script_data.show = restart -return script_data \ No newline at end of file +return script_data diff --git a/contrib/geoJSON_export.lua b/contrib/geoJSON_export.lua index 2ff30807..74625120 100644 --- a/contrib/geoJSON_export.lua +++ b/contrib/geoJSON_export.lua @@ -322,7 +322,7 @@ dt.preferences.register("geoJSON_export", "mapBoxKey", "string", _("geoJSON export: MapBox key"), - _("https://www.mapbox.com/studio/account/tokens"), + "https://www.mapbox.com/studio/account/tokens", '' ) dt.preferences.register("geoJSON_export", "OpengeoJSONFile", diff --git a/contrib/geoToolbox.lua b/contrib/geoToolbox.lua index 68fdc3c6..13a7b5bd 100644 --- a/contrib/geoToolbox.lua +++ b/contrib/geoToolbox.lua @@ -495,9 +495,9 @@ local function calc_distance() if (distance < 1) then distance = distance * 1000 - distanceUnit = _("m") + distanceUnit = "m" else - distanceUnit = _("km") + distanceUnit = "km" end return string.format(_("distance: %.2f %s"), distance, distanceUnit) @@ -746,7 +746,7 @@ dt.preferences.register("geoToolbox", "mapBoxKey", "string", _("geoToolbox export: MapBox Key"), - _("https://www.mapbox.com/studio/account/tokens"), + "https://www.mapbox.com/studio/account/tokens", '' ) -- Register diff --git a/contrib/image_time.lua b/contrib/image_time.lua index a35f751f..ff5f8c28 100644 --- a/contrib/image_time.lua +++ b/contrib/image_time.lua @@ -257,7 +257,7 @@ local function _get_windows_image_file_creation_time(image) end p:close() else - dt.print(string.format(_("unable to get information for $s"), image.filename)) + dt.print(string.format(_("unable to get information for %s"), image.filename)) datetime = ERROR end return datetime diff --git a/contrib/rate_group.lua b/contrib/rate_group.lua index 6455f6d3..5c1659e7 100644 --- a/contrib/rate_group.lua +++ b/contrib/rate_group.lua @@ -93,6 +93,8 @@ local function destroy() dt.destroy_event("rg5", "shortcut") end +local rate_group = _("rate group") + dt.register_event("rg_reject", "shortcut", function(event, shortcut) apply_rating(-1) @@ -101,32 +103,32 @@ end, _("reject group")) dt.register_event("rg0", "shortcut", function(event, shortcut) apply_rating(0) -end, _("rate group 0")) +end, rate group .. " 0") dt.register_event("rg1", "shortcut", function(event, shortcut) apply_rating(1) -end, _("rate group 1")) +end, rate group .. " 1") dt.register_event("rg2", "shortcut", function(event, shortcut) apply_rating(2) -end, _("rate group 2")) +end, rate group .. " 2") dt.register_event("rg3", "shortcut", function(event, shortcut) apply_rating(3) -end, _("rate group 3")) +end, rate group .. " 3") dt.register_event("rg4", "shortcut", function(event, shortcut) apply_rating(4) -end, _("rate group 4")) +end, rate group .. " 4") dt.register_event("rg5", "shortcut", function(event, shortcut) apply_rating(5) -end, _("rate group 5")) +end, rate group .. " 5") script_data.destroy = destroy diff --git a/contrib/transfer_hierarchy.lua b/contrib/transfer_hierarchy.lua index 96b18e44..b73b38a9 100755 --- a/contrib/transfer_hierarchy.lua +++ b/contrib/transfer_hierarchy.lua @@ -352,7 +352,7 @@ th.transfer_widget = darktable.new_widget("box") { }, darktable.new_widget("button") { label = _("copy"), - tooltip = _("Copy all selected images"), + tooltip = _("copy all selected images"), clicked_callback = doCopy } } @@ -406,4 +406,4 @@ script_data.restart = restart script_data.destroy_method = "hide" script_data.show = restart -return script_data \ No newline at end of file +return script_data diff --git a/examples/multi_os.lua b/examples/multi_os.lua index f27cc9ea..a1eea24b 100644 --- a/examples/multi_os.lua +++ b/examples/multi_os.lua @@ -227,7 +227,7 @@ if dt.configuration.running_os ~= "linux" then dt.preferences.register("executable_paths", "ufraw-batch", -- name "file", -- type _('multi_os: ufraw-batch location'), -- label - _('Installed location of ufraw-batch, requires restart to take effect.'), -- tooltip + _('installed location of ufraw-batch, requires restart to take effect.'), -- tooltip "ufraw-batch", -- default ufraw_batch_path_widget ) diff --git a/tools/script_manager.lua b/tools/script_manager.lua index b62e0e2c..ada8579d 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -852,7 +852,7 @@ local function install_scripts() sm.widgets.new_folder.text = "" sm.widgets.main_menu.selected = 3 else - log.msg(log.screen, _("No scripts found to install")) + log.msg(log.screen, _("no scripts found to install")) log.msg(log.error, "scan_scripts returned " .. count .. " scripts found. Not adding to folder_selector") end @@ -1436,7 +1436,7 @@ sm.widgets.page_control = dt.new_widget("box"){ sm.widgets.scripts = dt.new_widget("box"){ orientation = vertical, - dt.new_widget("section_label"){label = _(" ")}, + dt.new_widget("section_label"){label = " "}, dt.new_widget("label"){label = " "}, dt.new_widget("label"){label = _("scripts")}, sm.widgets.folder_selector, From 200fc059c064c3e094321fc1f9a91eb940e0eccc Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sat, 10 Aug 2024 23:38:06 -0400 Subject: [PATCH 332/445] README.md - updated 3rd party scripts --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 80ead1b9..d57c8e68 100644 --- a/README.md +++ b/README.md @@ -127,6 +127,8 @@ The following third-party projects are listed for information only. Think of thi * [nbremond77/darktable](https://github.com/nbremond77/darktable/tree/master/scripts) * [s5k6/dtscripts](https://github.com/s5k6/dtscripts) * [ChristianBirzer/darktable_extra_scripts](https://github.com/ChristianBirzer/darktable_extra_scripts) +* [fjb2020/darktable-scripts](https://github.com//fjb2020/darktable-scripts) +* [bastibe/Darktable-Film-Simulation-Panel](https://github.com/bastibe/Darktable-Film-Simulation-Panel) ## Download and Install From a079860cd8f5074a1ecbd9b8632f24a3cf2950ad Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Tue, 13 Aug 2024 17:46:28 -0400 Subject: [PATCH 333/445] lib/dtutils/file - os.tmpname now works correctly on windows, removed check and fix --- lib/dtutils/file.lua | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/dtutils/file.lua b/lib/dtutils/file.lua index cd898e71..e33fa5aa 100644 --- a/lib/dtutils/file.lua +++ b/lib/dtutils/file.lua @@ -861,9 +861,6 @@ dtutils_file.libdoc.functions["create_tmp_file"] = { function dtutils_file.create_tmp_file() local tmp_file = os.tmpname() - if dt.configuration.running_os == "windows" then - tmp_file = dt.configuration.tmp_dir .. tmp_file -- windows os.tmpname() defaults to root directory - end local f = io.open(tmp_file, "w") if not f then From 6ca8f0034efebc875da46341c3cc13d57eda5541 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sat, 31 Aug 2024 15:53:38 -0400 Subject: [PATCH 334/445] official/apply_camera_style - apply a darktable camera style to an image based on maker and model. Styles may be applied to selections, collections, and on newly imported images. --- official/apply_camera_style.lua | 491 ++++++++++++++++++++++++++++++++ 1 file changed, 491 insertions(+) create mode 100644 official/apply_camera_style.lua diff --git a/official/apply_camera_style.lua b/official/apply_camera_style.lua new file mode 100644 index 00000000..ada2e45a --- /dev/null +++ b/official/apply_camera_style.lua @@ -0,0 +1,491 @@ +--[[ + + apply_camera_style.lua - apply camera style to matching images + + Copyright (C) 2024 Bill Ferguson . + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +]] +--[[ + apply_camera_style - apply camera style to matching images + + apply a camera style corresponding to the camera used to + take the image to provide a starting point for editing that + is similar to the SOOC jpeg. + + ADDITIONAL SOFTWARE NEEDED FOR THIS SCRIPT + none + + USAGE + start the script from script_manager + + BUGS, COMMENTS, SUGGESTIONS + Bill Ferguson + + CHANGES +]] + +local dt = require "darktable" +local du = require "lib/dtutils" +-- local df = require "lib/dtutils.file" +-- local ds = require "lib/dtutils.string" +-- local dtsys = require "lib/dtutils.system" +local log = require "lib/dtutils.log" +-- local debug = require "darktable.debug" + + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- C O N S T A N T S +-- - - - - - - - - - - - - - - - - - - - - - - - + +local MODULE = "apply_camera_style" +local DEFAULT_LOG_LEVEL = log.info +local TMP_DIR = dt.configuration.tmp_dir +local STYLE_PREFIX = "_l10n_darktable camera styles|" + +-- path separator +local PS = dt.configuration.running_os == "windows" and "\\" or "/" + +-- command separator +local CS = dt.configuration.running_os == "windows" and "&" or ";" + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- A P I C H E C K +-- - - - - - - - - - - - - - - - - - - - - - - - + +du.check_min_api_version("9.4.0", MODULE) -- styles use filmic V7 which appeared in darktable 4.4 + + +-- - - - - - - - - - - - - - - - - - - - - - - - - - +-- I 1 8 N +-- - - - - - - - - - - - - - - - - - - - - - - - - - + +local gettext = dt.gettext.gettext + +local function _(msgid) + return gettext(msgid) +end + +-- - - - - - - - - - - - - - - - - - - - - - - - - - +-- S C R I P T M A N A G E R I N T E G R A T I O N +-- - - - - - - - - - - - - - - - - - - - - - - - - - + +local script_data = {} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them + +script_data.metadata = { + name = "apply_camera_style", -- name of script + purpose = _("apply camera style to matching images"), -- purpose of script + author = "Bill Ferguson ", -- your name and optionally e-mail address + help = "https://docs.darktable.org/lua/development/lua.scripts.manual/scripts/official/apply_camera_style/" -- URL to help/documentation +} + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- L O G L E V E L +-- - - - - - - - - - - - - - - - - - - - - - - - + +log.log_level(DEFAULT_LOG_LEVEL) + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- N A M E S P A C E +-- - - - - - - - - - - - - - - - - - - - - - - - + +local apply_camera_style = {} + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- G L O B A L V A R I A B L E S +-- - - - - - - - - - - - - - - - - - - - - - - - + +apply_camera_style.imported_images = {} +apply_camera_style.styles = {} +apply_camera_style.log_level = DEFAULT_LOG_LEVEL + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- P R E F E R E N C E S +-- - - - - - - - - - - - - - - - - - - - - - - - + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- A L I A S E S +-- - - - - - - - - - - - - - - - - - - - - - - - + +local namespace = apply_camera_style +local acs = apply_camera_style + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- F U N C T I O N S +-- - - - - - - - - - - - - - - - - - - - - - - - + +------------------- +-- helper functions +------------------- + +local function set_log_level(level) + local old_log_level = log.log_level() + log.log_level(level) + return old_log_level +end + +local function restore_log_level(level) + log.log_level(level) +end + +------------------- +-- script functions +------------------- + +local function process_pattern(pattern) + + local log_level = set_log_level(acs.log_level) + + pattern = string.lower(pattern) + -- strip off series + pattern = string.gsub(pattern, " series$", "?") + -- match a character + if string.match(pattern, "?$") then + -- handle EOS R case + pattern = string.gsub(pattern, "?", ".?") + else + pattern = string.gsub(pattern, "?", ".") + end + -- escape dashes + pattern = string.gsub(pattern, "%-", "%%-") + -- until we end up with a set, I'll defer set processing, i.e. [...] + -- anchor the pattern to ensure we don't short match + pattern = "^" .. pattern .. "$" + + restore_log_level(log_level) + + return pattern +end + +local function process_set(pattern_set) + + local log_level = set_log_level(acs.log_level) + + local to_process = {} + local processed = {} + + local base, set, tail + + if string.match(pattern_set, "]$") then + base, set = string.match(pattern_set, "(.+)%[(.+)%]") + else + base, set, tail = string.match(pattern_set, "(.+)%[(.+)%](.+)") + end + + log.msg(log.debug, "base is " .. base .. " and set is " .. set) + + to_process = du.split(set, ",") + + for _, item in ipairs(to_process) do + local pat = base .. item + if tail then + pat = pat .. tail + end + table.insert(processed, process_pattern(pat)) + end + + restore_log_level(log_level) + + return processed +end + +local function get_camera_styles() + + local log_level = set_log_level(acs.log_level) + + -- separate the styles into + -- + -- acs.styles - + -- maker - + -- styles {} + -- patterns {} + + for _, style in ipairs(dt.styles) do + + if string.match(style.name, STYLE_PREFIX) then + log.msg(log.debug, "got " .. style.name) + + local parts = du.split(style.name, "|") + parts[2] = string.lower(parts[2]) + log.msg(log.debug, "maker is " .. parts[2]) + + if not acs.styles[parts[2]] then + acs.styles[parts[2]] = {} + acs.styles[parts[2]]["styles"] = {} + acs.styles[parts[2]]["patterns"] = {} + end + if parts[3] then + if not string.match(parts[3], "]") then + table.insert(acs.styles[parts[2]].styles, style) + local processed_pattern = process_pattern(parts[#parts]) + table.insert(acs.styles[parts[2]].patterns, processed_pattern) + log.msg(log.debug, "pattern for " .. style.name .. " is " .. processed_pattern) + else + local processed_patterns = process_set(parts[3]) + for _, pat in ipairs(processed_patterns) do + table.insert(acs.styles[parts[2]].styles, style) + table.insert(acs.styles[parts[2]].patterns, pat) + log.msg(log.debug, "pattern for " .. style.name .. " is " .. pat) + end + end + end + end + end + + restore_log_level(log_level) + +end + +local function normalize_model(maker, model) + + local log_level = set_log_level(acs.log_level) + + model = string.lower(model) + + -- strip off the maker name + if maker == "canon" then + model = string.gsub(model, "canon ", "") + elseif maker == "hasselblad" then + model = string.gsub(model, "hasselblad ", "") + elseif maker == "leica" then + model = string.gsub(model, "leica ", "") + elseif maker == "lg" then + model = string.gsub(model, "lg ", "") + elseif maker == "nikon" then + model = string.gsub(model, "nikon ", "") + elseif maker == "nokia" then + model = string.gsub(model, "nokia ", "") + elseif maker == "oneplus" then + model = string.gsub(model, "oneplus ", "") + elseif maker == "pentax" then + model = string.gsub(model, "pentax ", "") + model = string.gsub(model, "ricoh ", "") + end + + restore_log_level(log_level) + + return model +end + +local function normalize_maker(maker) + + local log_level = set_log_level(acs.log_level) + + maker = string.lower(maker) + + if string.match(maker, "^fujifilm") then + maker = "fujifilm" + elseif string.match(maker, "^hmd ") then + maker = "nokia" + elseif string.match(maker, "^leica") then + maker = "leica" + elseif string.match(maker, "^minolta") then + maker = "minolta" + elseif string.match(maker, "^nikon") then + maker = "nikon" + elseif string.match(maker, "^om ") then + maker = "om system" + elseif string.match(maker, "^olympus") then + maker = "olympus" + elseif string.match(maker, "^pentax") or string.match(maker, "^ricoh") then + maker = "pentax" + end + + restore_log_level(log_level) + + return maker +end + +local function has_style_tag(image, tag_name) + + local log_level = set_log_level(acs.log_level) + + local result = false + + log.msg(log.debug, "looking for tag " .. tag_name) + + for _, tag in ipairs(image:get_tags()) do + log.msg(log.debug, "checking against " .. tag.name) + if tag.name == tag_name then + log.msg(log.debug, "matched tag " .. tag_name) + result = true + end + end + + restore_log_level(log_level) + + return result +end + +local function mangle_model(model) + + local log_level = set_log_level(acs.log_level) + + if string.match(model, "eos") then + log.msg(log.debug, "mangle model got " .. model) + model = string.gsub(model, "r6m2", "r6 mark ii") + model = string.gsub(model, "eos 350d digital", "eos kiss digital n") + model = string.gsub(model, "eos 500d", "eos rebel t1") + model = string.gsub(model, "eos 550d", "eos rebel t2") + model = string.gsub(model, "eos 600d", "eos rebel t3i") + model = string.gsub(model, "eos 650d", "eos rebel t4i") + model = string.gsub(model, "eos 700d", "eos rebel t5") + model = string.gsub(model, "eos 750d", "eos rebel t6i") + model = string.gsub(model, "eos 760d", "eos rebel t6s") + model = string.gsub(model, "eos 100d", "eos rebel t6") + model = string.gsub(model, "eos 1100d", "eos rebel t3") + model = string.gsub(model, "eos 1200d", "eos rebel t5") + model = string.gsub(model, "eos 1300d", "eos rebel t6") + model = string.gsub(model, "eos 2000d", "eos rebel t7") + log.msg(log.debug, "mandle model returning " .. model) + end + + restore_log_level(log_level) + + return model +end + +local function stop_job() + if acs.job then + if acs.job.valid then + acs.job.valid = false + end + end +end + +local function apply_style_to_images(images) + + local log_level = set_log_level(acs.log_level) + + acs.job = dt.gui.create_job(_("applying camera styles to images"), true, stop_job) + + for count, image in ipairs(images) do + local maker = normalize_maker(image.exif_maker) + local model = normalize_model(maker, image.exif_model) + model = mangle_model(model) + log.msg(log.debug, "got maker " .. maker .. " and model " .. model .. " from image " .. image.filename) + + if acs.styles[maker] then + local no_match = true + for i, pattern in ipairs(acs.styles[maker].patterns) do + if string.match(model, pattern) or + (i == #acs.styles[maker].patterns and string.match(pattern, "generic")) then + local tag_name = "darktable|style|" .. acs.styles[maker].styles[i].name + if not has_style_tag(image, tag_name) then + image:apply_style(acs.styles[maker].styles[i]) + no_match = false + log.msg(log.info, "applied style " .. acs.styles[maker].styles[i].name .. " to " .. image.filename) + end + log.log_level(loglevel) + break + end + end + if no_match then + log.msg(log.info, "no style found for " .. maker .. " " .. model) + end + else + log.msg(log.info, "no maker found for " .. image.filename) + end + if count % 10 == 0 then + acs.job.percent = count / #images + end + if dt.control.ending then + stop_job() + end + end + + stop_job() + + restore_log_level(log_level) + +end + +local function apply_camera_style(collection) + + local log_level = set_log_level(acs.log_level) + + local images = nil + + if collection == true then + images = dt.collection + log.msg(log.info, "applying camera styles to collection") + elseif collection == false then + images = dt.gui.selection() + if #images == 0 then + images = dt.gui.action_images + end + log.msg(log.info, "applying camera styles to selection") + end + apply_style_to_images(images) + + restore_log_level(log_level) + +end + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- M A I N P R O G R A M +-- - - - - - - - - - - - - - - - - - - - - - - - + +get_camera_styles() + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- U S E R I N T E R F A C E +-- - - - - - - - - - - - - - - - - - - - - - - - + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- D A R K T A B L E I N T E G R A T I O N +-- - - - - - - - - - - - - - - - - - - - - - - - + +local function destroy() + dt.destroy_event(MODULE, "post-import-image") + dt.destroy_event(MODULE, "post-import-film") +end + +script_data.destroy = destroy + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- E V E N T S +-- - - - - - - - - - - - - - - - - - - - - - - - + +dt.register_event(MODULE, "shortcut", + function(event, shortcut) + apply_camera_style(true) + end, _("apply camera styles to collection") +) + +dt.register_event(MODULE, "shortcut", + function(event, shortcut) + apply_camera_style(false) + end, _("apply camera styles to selection") +) + +dt.register_event(MODULE, "post-import-image", + function(event, image) + table.insert(acs.imported_images, image) + end +) + +dt.register_event(MODULE, "post-import-film", + function(event, film) + apply_style_to_images(acs.imported_images) + acs.imported_images = {} + end +) + +return script_data \ No newline at end of file From 6c686128d2ea960496ebd298a8c441c84b938eee Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sat, 31 Aug 2024 16:48:36 -0400 Subject: [PATCH 335/445] official/*.lua - Removed bindtextdoamin so that darktable can handle the translation --- official/check_for_updates.lua | 2 -- official/copy_paste_metadata.lua | 2 -- official/delete_long_tags.lua | 2 -- official/delete_unused_tags.lua | 2 -- official/enfuse.lua | 2 -- official/generate_image_txt.lua | 2 -- official/image_path_in_ui.lua | 2 -- official/import_filter_manager.lua | 2 -- official/import_filters.lua | 2 -- official/save_selection.lua | 2 -- official/selection_to_pdf.lua | 2 -- 11 files changed, 22 deletions(-) diff --git a/official/check_for_updates.lua b/official/check_for_updates.lua index de92c7c9..45ec19b0 100644 --- a/official/check_for_updates.lua +++ b/official/check_for_updates.lua @@ -36,8 +36,6 @@ du.check_min_api_version("2.0.0", "check_for_updates") local gettext = dt.gettext.gettext -dt.gettext.bindtextdomain("check_for_updates", dt.configuration.config_dir .."/lua/locale/") - local function _(msg) return gettext(msg) end diff --git a/official/copy_paste_metadata.lua b/official/copy_paste_metadata.lua index 0c765ec1..37eb94f4 100644 --- a/official/copy_paste_metadata.lua +++ b/official/copy_paste_metadata.lua @@ -31,8 +31,6 @@ local gettext = dt.gettext.gettext du.check_min_api_version("7.0.0", "copy_paste_metadata") -dt.gettext.bindtextdomain("copy_paste_metadata", dt.configuration.config_dir .."/lua/locale/") - local function _(msgid) return gettext(msgid) end diff --git a/official/delete_long_tags.lua b/official/delete_long_tags.lua index 2c807e15..89b192f1 100644 --- a/official/delete_long_tags.lua +++ b/official/delete_long_tags.lua @@ -35,8 +35,6 @@ du.check_min_api_version("2.0.0", "delete_long_tags") local gettext = dt.gettext.gettext -dt.gettext.bindtextdomain("delete_long_tags", dt.configuration.config_dir .."/lua/locale/") - local function _(msgid) return gettext(msgid) end diff --git a/official/delete_unused_tags.lua b/official/delete_unused_tags.lua index bcdceaf1..62ebc95e 100644 --- a/official/delete_unused_tags.lua +++ b/official/delete_unused_tags.lua @@ -39,8 +39,6 @@ end local gettext = dt.gettext.gettext -dt.gettext.bindtextdomain("delete_unused_tags", dt.configuration.config_dir .."/lua/locale/") - local function _(msgid) return gettext(msgid) end diff --git a/official/enfuse.lua b/official/enfuse.lua index c8df51b1..317ab73d 100644 --- a/official/enfuse.lua +++ b/official/enfuse.lua @@ -43,8 +43,6 @@ local gettext = dt.gettext.gettext du.check_min_api_version("7.0.0", "enfuse") -dt.gettext.bindtextdomain("enfuse", dt.configuration.config_dir .."/lua/locale/") - local function _(msgid) return gettext(msgid) end diff --git a/official/generate_image_txt.lua b/official/generate_image_txt.lua index deacefaf..42f64987 100644 --- a/official/generate_image_txt.lua +++ b/official/generate_image_txt.lua @@ -40,8 +40,6 @@ require "darktable.debug" local gettext = dt.gettext.gettext -dt.gettext.bindtextdomain("generate_image_txt", dt.configuration.config_dir .."/lua/locale/") - local function _(msg) return gettext(msg) end diff --git a/official/image_path_in_ui.lua b/official/image_path_in_ui.lua index fd9e3fbc..b4440db9 100644 --- a/official/image_path_in_ui.lua +++ b/official/image_path_in_ui.lua @@ -35,8 +35,6 @@ du.check_min_api_version("7.0.0", "image_path_in_ui") local gettext = dt.gettext.gettext -dt.gettext.bindtextdomain("image_path_in_ui", dt.configuration.config_dir .."/lua/locale/") - local function _(msgid) return gettext(msgid) end diff --git a/official/import_filter_manager.lua b/official/import_filter_manager.lua index 9b16ee3e..11191504 100644 --- a/official/import_filter_manager.lua +++ b/official/import_filter_manager.lua @@ -34,8 +34,6 @@ local dt = require "darktable" local gettext = dt.gettext.gettext -dt.gettext.bindtextdomain("import_filter_manager", dt.configuration.config_dir .."/lua/locale/") - local function _(msg) return gettext(msg) end diff --git a/official/import_filters.lua b/official/import_filters.lua index 165ec3fd..44633062 100644 --- a/official/import_filters.lua +++ b/official/import_filters.lua @@ -32,8 +32,6 @@ local dt = require "darktable" local gettext = dt.gettext.gettext -dt.gettext.bindtextdomain("import_filters", dt.configuration.config_dir .."/lua/locale/") - local function _(msg) return gettext(msg) end diff --git a/official/save_selection.lua b/official/save_selection.lua index 865ca265..77e82eb4 100644 --- a/official/save_selection.lua +++ b/official/save_selection.lua @@ -40,8 +40,6 @@ du.check_min_api_version("7.0.0", "save_selection") local gettext = dt.gettext.gettext -dt.gettext.bindtextdomain("save_selection", dt.configuration.config_dir .."/lua/locale/") - local function _(msg) return gettext(msg) end diff --git a/official/selection_to_pdf.lua b/official/selection_to_pdf.lua index 18a7be57..1457a1b6 100644 --- a/official/selection_to_pdf.lua +++ b/official/selection_to_pdf.lua @@ -40,8 +40,6 @@ du.check_min_api_version("7.0.0", "selection_to_pdf") local gettext = dt.gettext.gettext -dt.gettext.bindtextdomain("selection_to_pdf", dt.configuration.config_dir .."/lua/locale/") - local function _(msg) return gettext(msg) end From 96fee48ef2afc242db08435e22d3b09d73bd2772 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sat, 31 Aug 2024 21:39:50 -0400 Subject: [PATCH 336/445] tools/script_manager - restore script_manager_running_script to "script_manager" after changing it to start a script --- tools/script_manager.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/script_manager.lua b/tools/script_manager.lua index ada8579d..0baba484 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -517,6 +517,7 @@ local function activate(script) status = true pref_write(script.script_name, "bool", true) end + script_manager_running_script = "script_manager" restore_log_level(old_log_level) return status From ee98f96a4fe67451e427ea0107c0ce8b4718def8 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Tue, 3 Sep 2024 19:14:31 -0400 Subject: [PATCH 337/445] contrib/rate_group - fixed formatting of tooltips --- contrib/rate_group.lua | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/contrib/rate_group.lua b/contrib/rate_group.lua index 5c1659e7..c75b504d 100644 --- a/contrib/rate_group.lua +++ b/contrib/rate_group.lua @@ -93,8 +93,6 @@ local function destroy() dt.destroy_event("rg5", "shortcut") end -local rate_group = _("rate group") - dt.register_event("rg_reject", "shortcut", function(event, shortcut) apply_rating(-1) @@ -103,32 +101,33 @@ end, _("reject group")) dt.register_event("rg0", "shortcut", function(event, shortcut) apply_rating(0) -end, rate group .. " 0") + end, string.format(_("rate group %d"), 0) +) dt.register_event("rg1", "shortcut", function(event, shortcut) apply_rating(1) -end, rate group .. " 1") +end, string.format(_("rate group %d"), 1)) dt.register_event("rg2", "shortcut", function(event, shortcut) apply_rating(2) -end, rate group .. " 2") +end, string.format(_("rate group %d"), 2)) dt.register_event("rg3", "shortcut", function(event, shortcut) apply_rating(3) -end, rate group .. " 3") +end, string.format(_("rate group %d"), 3)) dt.register_event("rg4", "shortcut", function(event, shortcut) apply_rating(4) -end, rate group .. " 4") +end, string.format(_("rate group %d"), 4)) dt.register_event("rg5", "shortcut", function(event, shortcut) apply_rating(5) -end, rate group .. " 5") +end, string.format(_("rate group %d"), 5)) script_data.destroy = destroy From ea08557a0e37511262240555ffcb79802f68fbdf Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sun, 8 Sep 2024 22:49:50 -0400 Subject: [PATCH 338/445] tools/script_manager - removed translation of empty string --- tools/script_manager.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/script_manager.lua b/tools/script_manager.lua index 0baba484..fe8fa6ab 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -1353,7 +1353,7 @@ sm.widgets.disable_scripts = dt.new_widget("button"){ sm.widgets.install_update = dt.new_widget("box"){ orientation = "vertical", - dt.new_widget("section_label"){label = _(" ")}, + dt.new_widget("section_label"){label = " "}, dt.new_widget("label"){label = " "}, dt.new_widget("label"){label = _("update scripts")}, dt.new_widget("label"){label = " "}, From f0e36278001c04c855898f8b82b4287a892b4ef6 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sun, 8 Sep 2024 22:54:42 -0400 Subject: [PATCH 339/445] contrib/exportLUT - fixed file chooser labels for translation --- contrib/exportLUT.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contrib/exportLUT.lua b/contrib/exportLUT.lua index 0a578a24..be904cdd 100644 --- a/contrib/exportLUT.lua +++ b/contrib/exportLUT.lua @@ -71,13 +71,13 @@ local mkdir_command = 'mkdir -p ' if dt.configuration.running_os == 'windows' then mkdir_command = 'mkdir ' end local file_chooser_button = dt.new_widget("file_chooser_button"){ - title = _("identity_file_chooser"), + title = _("choose the identity file"), value = "", is_directory = false } local export_chooser_button = dt.new_widget("file_chooser_button"){ - title = _("export_location_chooser"), + title = _("choose the export location"), value = "", is_directory = true } From 5be3d6986ef1da570908ac1a5f05ba7e55b5f8fb Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sun, 8 Sep 2024 23:24:33 -0400 Subject: [PATCH 340/445] official/selection_to_pdf - dont translate internal module name --- official/selection_to_pdf.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/official/selection_to_pdf.lua b/official/selection_to_pdf.lua index 1457a1b6..e4f22f5e 100644 --- a/official/selection_to_pdf.lua +++ b/official/selection_to_pdf.lua @@ -129,7 +129,7 @@ local function destroy() dt.print_log("done destroying") end -dt.register_storage(_("export_pdf"),_("export thumbnails to pdf"), +dt.register_storage("export_pdf", _("export thumbnails to pdf"), nil, function(storage,image_table) local my_title = title_widget.text From 05c57c02477a12d3682ce5d40f0a511d44ce0e75 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sun, 8 Sep 2024 23:42:45 -0400 Subject: [PATCH 341/445] contrib/geoTooxbox - fix latitude and longitude labels --- contrib/geoToolbox.lua | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/contrib/geoToolbox.lua b/contrib/geoToolbox.lua index 13a7b5bd..677af0a1 100644 --- a/contrib/geoToolbox.lua +++ b/contrib/geoToolbox.lua @@ -67,12 +67,12 @@ labelDistance.label = _("distance:") local label_copy_gps_lat = dt.new_widget("check_button") { - label = _("latitude:"), + label = _("latitude: "), value = true } local label_copy_gps_lon = dt.new_widget("check_button") { - label = _("longitude:"), + label = _("longitude: "), value = true } local label_copy_gps_ele = dt.new_widget("check_button") @@ -307,9 +307,9 @@ local function copy_gps() end end - label_copy_gps_lat.label = string.format(_("latitude: "), copy_gps_latitude) - label_copy_gps_lon.label = string.format(_("longitude: "),copy_gps_longitude) - label_copy_gps_ele.label = string.format(_("elevation: "), copy_gps_elevation) + label_copy_gps_lat.label = _("latitude: ") .. copy_gps_latitude + label_copy_gps_lon.label = _("longitude: ") .. copy_gps_longitude + label_copy_gps_ele.label = _("elevation: ") .. copy_gps_elevation return end From c65e070a761c4111bd35107181a0ce58dd26bd8a Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sun, 8 Sep 2024 23:43:39 -0400 Subject: [PATCH 342/445] contrib/geoJSON - don't translate the module name --- contrib/geoJSON_export.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contrib/geoJSON_export.lua b/contrib/geoJSON_export.lua index 74625120..dc336b2a 100644 --- a/contrib/geoJSON_export.lua +++ b/contrib/geoJSON_export.lua @@ -315,19 +315,19 @@ end dt.preferences.register("geoJSON_export", "CreateMapBoxHTMLFile", "bool", - _("geoJSON export: Create an additional HTML file"), + "geoJSON export: ".._("Create an additional HTML file"), _("creates an HTML file that loads the geoJSON file. (needs a MapBox key"), false ) dt.preferences.register("geoJSON_export", "mapBoxKey", "string", - _("geoJSON export: MapBox key"), + "geoJSON export: MapBox " .. _("key"), "https://www.mapbox.com/studio/account/tokens", '' ) dt.preferences.register("geoJSON_export", "OpengeoJSONFile", "bool", - _("geoJSON export: open geoJSON file after export"), + "geoJSON export: " .. _("open geoJSON file after export"), _("opens the geoJSON file after the export with the standard program for geoJSON files"), false ) From f0bdc890c1177008c175dd54101db30d54d7b3bb Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Mon, 9 Sep 2024 22:50:49 -0400 Subject: [PATCH 343/445] official/apply_camera_styles - updated message to specify the camera styles are darktable camera styles --- official/apply_camera_style.lua | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/official/apply_camera_style.lua b/official/apply_camera_style.lua index ada2e45a..963586af 100644 --- a/official/apply_camera_style.lua +++ b/official/apply_camera_style.lua @@ -18,7 +18,7 @@ along with this program. If not, see . ]] --[[ - apply_camera_style - apply camera style to matching images + apply_camera_style - apply darktable camera style to matching images apply a camera style corresponding to the camera used to take the image to provide a starting point for editing that @@ -90,7 +90,7 @@ script_data.show = nil -- only required for libs since the destroy_ script_data.metadata = { name = "apply_camera_style", -- name of script - purpose = _("apply camera style to matching images"), -- purpose of script + purpose = _("apply darktable camera style to matching images"), -- purpose of script author = "Bill Ferguson ", -- your name and optionally e-mail address help = "https://docs.darktable.org/lua/development/lua.scripts.manual/scripts/official/apply_camera_style/" -- URL to help/documentation } @@ -466,13 +466,13 @@ script_data.destroy = destroy dt.register_event(MODULE, "shortcut", function(event, shortcut) apply_camera_style(true) - end, _("apply camera styles to collection") + end, _("apply darktable camera styles to collection") ) dt.register_event(MODULE, "shortcut", function(event, shortcut) apply_camera_style(false) - end, _("apply camera styles to selection") + end, _("apply darktable camera styles to selection") ) dt.register_event(MODULE, "post-import-image", @@ -488,4 +488,4 @@ dt.register_event(MODULE, "post-import-film", end ) -return script_data \ No newline at end of file +return script_data From 167620fadf8b0baa137023ed6f4233c178e6d18d Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Tue, 10 Sep 2024 16:34:36 -0400 Subject: [PATCH 344/445] lib/dtutils/string - Added get_substitution_tooltip() function to return the substitution pattern tooltip so it only has to be translated in one place. Spelled substitution properly to that calls to build_substitution_list succeed. --- lib/dtutils/string.lua | 102 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 101 insertions(+), 1 deletion(-) diff --git a/lib/dtutils/string.lua b/lib/dtutils/string.lua index d64a95a2..b1718b39 100644 --- a/lib/dtutils/string.lua +++ b/lib/dtutils/string.lua @@ -6,6 +6,10 @@ local log = require "lib/dtutils.log" local DEFAULT_LOG_LEVEL = log.error +local function _(msg) + return dt.gettext.gettext(msg) +end + dtutils_string.log_level = DEFAULT_LOG_LEVEL dtutils_string.libdoc = { @@ -688,7 +692,7 @@ end -- build the argument substitution list from each image -function dtutils_string.build_substition_list(image, sequence, variable_string, username, pic_folder, home, desktop) +function dtutils_string.build_substitution_list(image, sequence, variable_string, username, pic_folder, home, desktop) local old_log_level = log.log_level() log.log_level(dtutils_string.log_level) @@ -814,6 +818,102 @@ function dtutils_string.build_substition_list(image, sequence, variable_string, log.log_level(old_log_level) end +dtutils_string.libdoc.functions["get_substitution_tooltip"] = { + Name = [[get_substitution_tooltip]], + Synopsis = [[get a tooltip that lists the substitution variables]], + Usage = [[local ds = require "lib/dtutils.string" + ds.get_substitution_tooltip() + Description = [[get_substitution_tooltip lists the variables with brief explanations]], + Return_Value = [[string - the tooltip]], + Limitations = [[]], + Example = [[]], + See_Also = [[https://docs.darktable.org/usermanual/4.6/en/special-topics/variables/]], + Reference = [[]], + License = [[]], + Copyright = [[]], +} + +function dtutils_string.get_substitution_tooltip() + return string.format("$(ROLL.NAME) - %s\n", _("film roll of the input image")) .. + string.format("$(FILE.FOLDER) - %s\n", _("folder containing the input image")) .. + string.format("$(FILE.NAME) - %s\n", _("basename of the input image")) .. + string.format("$(FILE.EXTENSION) - %s\n", _("extension of the input image")) .. + string.format("$(ID) - %s\n", _("the image id")) .. + string.format("$(VERSION) - %s\n", _("the duplicate version number")) .. + string.format("$(VERSION.IF.MULTI) - %s\n", _("same as $(VERSION) but null string if only one version exists")) .. + string.format("$(VERSION.NAME) - %s\n", _("version name from metadata")) .. + string.format("$(DARKTABLE.VERSION) - %s\n", _("the version of the running darktable instance")) .. + --string.format("$(DARKTABLE.NAME) - %s\n", _("")) .. -- Not Implemented + string.format("$(SEQUENCE[n,m]) - %s\n", _("a sequence number within an export job with n digits and starting with m\nparameters are optional, default is [4,1]")) .. + string.format("$(WIDTH.SENSOR) - %s\n", _("width of RAW data in pixels before RAW crop")) .. + string.format("$(HEIGHT.SENSOR) - %s\n", _("height of RAW data in pixels before RAW crop")) .. + string.format("$(WIDTH.RAW) - %s\n", _("width of RAW data in pixels after RAW crop")) .. + string.format("$(HEIGHT.RAW) - %s\n", _("height of RAW data in pixels after RAW crop")) .. + string.format("$(WIDTH.CROP) - %s\n", _("image width in pixels at the end of the pixelpipe, but before export resize")) .. + string.format("$(HEIGHT.CROP) - %s\n", _("image height in pixels at the end of the pixelpipe, but before export resize")) .. + string.format("$(WIDTH.EXPORT) - %s\n", _("image width in pixels at the end of the pixelpipe and after export resize")) .. + string.format("$(HEIGHT.EXPORT) - %s\n", _("image height in pixels at the end of the pixelpipe and after export resize")) .. + --string.format("$(WIDTH.MAX) - %s\n", _("")) .. -- Not Implemented + --string.format("$(HEIGHT.MAX) - %s\n", _("")) .. -- Not Implemented + string.format("$(YEAR) - %s\n", _("current year")) .. + string.format("$(YEAR.SHORT) - %s\n", _("current two digit year")) .. + string.format("$(MONTH) - %s\n", _("current numeric (1-12) month")) .. + string.format("$(MONTH.LONG) - %s\n", _("full current month name")) .. + string.format("$(MONTH.SHORT) - %s\n", _("abbreviated current month name")) .. + string.format("$(DAY) - %s\n", _("current day")) .. + string.format("$(HOUR) - %s\n", _("current hour")) .. + string.format("$(MINUTE) - %s\n", _("current minute")) .. + string.format("$(SECOND) - %s\n", _("current second")) .. + string.format("$(MSEC) - %s\n", _("current millisecond")) .. + string.format("$(EXIF.YEAR) - EXIF %s\n", _("year")) .. + string.format("$(EXIF.YEAR.SHORT) - EXIF %s\n", _("year, two-digit version")) .. + string.format("$(EXIF.MONTH) - EXIF %s\n", _("month, numeric")) .. + string.format("$(EXIF.MONTH.LONG) - EXIF %s\n", _("month, full name")) .. + string.format("$(EXIF.MONTH.SHORT) - EXIF %s\n", _("month, abbreviated name")) .. + string.format("$(EXIF.DAY) - EXIF %s\n", _("day")) .. + string.format("$(EXIF.HOUR) - EXIF %s\n", _("hour")) .. + string.format("$(EXIF.MINUTE) - EXIF %s\n", _("minute")) .. + string.format("$(EXIF.SECOND) - EXIF %s\n", _("second")) .. + string.format("$(EXIF.MSEC) - EXIF %s\n", _("millisecond")) .. + --string.format("$(EXIF.DATE.REGIONAL) - %s\n", _("")) .. -- Not Implemented + --string.format("$(EXIF.TIME.REGIONAL) - %s\n", _("")) .. -- Not Implemented + string.format("$(EXIF.ISO) - EXIF ISO %s\n", _("value")) .. + string.format("$(EXIF.EXPOSURE) - EXIF %s\n", _("exposure")) .. + string.format("$(EXIF.EXPOSURE.BIAS) - EXIF %s\n", _("exposure bias")) .. + string.format("$(EXIF.APERTURE) - EXIF %s\n", _("aperture")) .. + string.format("$(EXIF.CROP.FACTOR) - EXIF %s\n", _("crop factor")) .. + string.format("$(EXIF.FOCAL.LENGTH) - EXIF %s\n", _("focal length")) .. + string.format("$(EXIF.FOCAL.LENGTH.EQUIV) - EXIF 35mm %s\n", _("equivalent focal length")) .. -- Not Implemented + string.format("$(EXIF.FOCUS.DISTANCE) - EXIF %s\n", _("focus distance")) .. + --string.format("$(IMAGE.EXIF) - %s\n", _("")) .. -- Not Implemented + string.format("$(LONGITUDE) - %s\n", _("longitude")) .. + string.format("$(LATITUDE) - %s\n", _("latitude")) .. + string.format("$(ELEVATION) - %s\n", _("elevation")) .. + --string.format("$(GPS.LOCATION) - %s\n", _("")) .. -- Not Implemented + string.format("$(STARS) - %s\n", _("star rating")) .. + --string.format("$(RATING.ICONS) - %s\n", _("")) .. -- Not Implemented + string.format("$(LABELS) - %s\n", _("colorlabels")) .. + --string.format("$(LABELS.ICONS) - %s\n", _("")) .. -- Not Implemented + string.format("$(MAKER) - %s\n", _("camera maker")) .. + string.format("$(MODEL) - %s\n", _("camera model")) .. + string.format("$(LENS) - %s\n", _("lens")) .. + string.format("$(TITLE) - %s\n", _("title from metadata")) .. + string.format("$(DESCRIPTION) - %s\n", _("description from metadata")) .. + string.format("$(CREATOR) - %s\n", _("creator from metadata")) .. + string.format("$(PUBLISHER) - %s\n", _("publisher from metadata")) .. + string.format("$(RIGHTS) - %s\n", _("rights from metadata")) .. + --string.format("$(TAGS) - %s\n", _("")) .. -- Not Implemented + string.format("$(CATEGORY[n,category]) - %s\n", _("tag name of level n [0,9] of selected category (or tag)")) .. + --string.format("$(SIDECAR.TXT) - %s\n", _("")) .. -- Not Implemented + string.format("$(FOLDER.PICTURES) - %s\n", _("pictures folder")) .. + string.format("$(FOLDER.HOME) - %s\n", _("home folder")) .. + string.format("$(FOLDER.DESKTOP) - %s\n", _("desktop folder")) .. + --string.format("$(OPENCL.ACTIVATED) - %s\n", _("")) .. -- Not Implemented + string.format("$(USERNAME) - %s\n", _("user name defined by OS")) + --string.format("$(NL) - %s\n", _("")) .. -- Not Implemented + --string.format("$(JOBCODE) - %s", _("")) -- Not Implemented +end + -- handle different versions of names local function check_legacy_vars(var_name) From 3fb00586c39067b5d56e8ba06a9272586205c181 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Tue, 10 Sep 2024 16:36:54 -0400 Subject: [PATCH 345/445] contrib/rename_images - replaced pattern substitution code with the better implementation in the string library. --- contrib/rename_images.lua | 136 ++------------------------------------ 1 file changed, 6 insertions(+), 130 deletions(-) diff --git a/contrib/rename_images.lua b/contrib/rename_images.lua index 769adfac..c0132adb 100644 --- a/contrib/rename_images.lua +++ b/contrib/rename_images.lua @@ -43,6 +43,7 @@ local dt = require "darktable" local du = require "lib/dtutils" local df = require "lib/dtutils.file" +local ds = require "lib/dtutils.string" du.check_min_api_version("7.0.0", "rename_images") @@ -57,12 +58,6 @@ end -- namespace variable local rename = { presets = {}, - substitutes = {}, - placeholders = {"ROLL_NAME","FILE_FOLDER","FILE_NAME","FILE_EXTENSION","ID","VERSION","SEQUENCE","YEAR","MONTH","DAY", - "HOUR","MINUTE","SECOND","EXIF_YEAR","EXIF_MONTH","EXIF_DAY","EXIF_HOUR","EXIF_MINUTE","EXIF_SECOND", - "STARS","LABELS","MAKER","MODEL","TITLE","CREATOR","PUBLISHER","RIGHTS","USERNAME","PICTURES_FOLDER", - "HOME","DESKTOP","EXIF_ISO","EXIF_EXPOSURE","EXIF_EXPOSURE_BIAS","EXIF_APERTURE","EXIF_FOCUS_DISTANCE", - "EXIF_FOCAL_LENGTH","LONGITUDE","LATITUDE","ELEVATION","LENS","DESCRIPTION","EXIF_CROP"}, widgets = {}, } rename.module_installed = false @@ -99,83 +94,6 @@ local DESKTOP = HOME .. PS .. "Desktop" -- F U N C T I O N S -- - - - - - - - - - - - - - - - - - - - - - - - -local function build_substitution_list(image, sequence, datetime, username, pic_folder, home, desktop) - -- build the argument substitution list from each image - -- local datetime = os.date("*t") - local colorlabels = {} - if image.red then table.insert(colorlabels, "red") end - if image.yellow then table.insert(colorlabels, "yellow") end - if image.green then table.insert(colorlabels, "green") end - if image.blue then table.insert(colorlabels, "blue") end - if image.purple then table.insert(colorlabels, "purple") end - local labels = #colorlabels == 1 and colorlabels[1] or du.join(colorlabels, ",") - local eyear,emon,eday,ehour,emin,esec = string.match(image.exif_datetime_taken, "(%d-):(%d-):(%d-) (%d-):(%d-):(%d-)$") - local replacements = {image.film, - image.path, - df.get_filename(image.filename), - string.upper(df.get_filetype(image.filename)), - image.id,image.duplicate_index, - string.format("%04d", sequence), - datetime.year, - string.format("%02d", datetime.month), - string.format("%02d", datetime.day), - string.format("%02d", datetime.hour), - string.format("%02d", datetime.min), - string.format("%02d", datetime.sec), - eyear, - emon, - eday, - ehour, - emin, - esec, - image.rating, - labels, - image.exif_maker, - image.exif_model, - image.title, - image.creator, - image.publisher, - image.rights, - username, - pic_folder, - home, - desktop, - image.exif_iso, - image.exif_exposure, - image.exif_exposure_bias, - image.exif_aperture, - image.exif_focus_distance, - image.exif_focal_length, - image.longitude, - image.latitude, - image.elevation, - image.exif_lens, - image.description, - image.exif_crop - } - - for i=1,#rename.placeholders,1 do rename.substitutes[rename.placeholders[i]] = replacements[i] end -end - -local function substitute_list(str) - -- replace the substitution variables in a string - for match in string.gmatch(str, "%$%(.-%)") do - local var = string.match(match, "%$%((.-)%)") - if rename.substitutes[var] then - str = string.gsub(str, "%$%("..var.."%)", rename.substitutes[var]) - else - dt.print_error("unrecognized variable " .. var) - dt.print(string.format(_("unknown variable %s, aborting..."), var)) - return -1 - end - end - return str -end - -local function clear_substitute_list() - for i=1,#rename.placeholders,1 do rename.substitutes[rename.placeholders[i]] = nil end -end - local function stop_job(job) job.valid = false end @@ -225,14 +143,14 @@ local function do_rename(images) for i, image in ipairs(images) do if job.valid then job.percent = i / #images - build_substitution_list(image, i, datetime, USER, PICTURES, HOME, DESKTOP) - local new_name = substitute_list(pattern) + ds.build_substitution_list(image, i, pattern, USER, PICTURES, HOME, DESKTOP) + local new_name = ds.substitute_list(pattern) if new_name == -1 then dt.print(_("unable to do variable substitution, exiting...")) stop_job(job) return end - clear_substitute_list() + ds.clear_substitute_list() local args = {} local path = string.sub(df.get_path(new_name), 1, -2) if string.len(path) == 0 then @@ -278,50 +196,8 @@ end -- - - - - - - - - - - - - - - - - - - - - - - - rename.widgets.pattern = dt.new_widget("entry"){ - tooltip = _("$(ROLL_NAME) - film roll name\n") .. - _("$(FILE_FOLDER) - image file folder\n") .. - _("$(FILE_NAME) - image file name\n") .. - _("$(FILE_EXTENSION) - image file extension\n") .. - _("$(ID) - image id\n") .. - _("$(VERSION) - version number\n") .. - _("$(SEQUENCE) - sequence number of selection\n") .. - _("$(YEAR) - current year\n") .. - _("$(MONTH) - current month\n") .. - _("$(DAY) - current day\n") .. - _("$(HOUR) - current hour\n") .. - _("$(MINUTE) - current minute\n") .. - _("$(SECOND) - current second\n") .. - _("$(EXIF_YEAR) - EXIF year\n") .. - _("$(EXIF_MONTH) - EXIF month\n") .. - _("$(EXIF_DAY) - EXIF day\n") .. - _("$(EXIF_HOUR) - EXIF hour\n") .. - _("$(EXIF_MINUTE) - EXIF minute\n") .. - _("$(EXIF_SECOND) - EXIF seconds\n") .. - _("$(EXIF_ISO) - EXIF ISO\n") .. - _("$(EXIF_EXPOSURE) - EXIF exposure\n") .. - _("$(EXIF_EXPOSURE_BIAS) - EXIF exposure bias\n") .. - _("$(EXIF_APERTURE) - EXIF aperture\n") .. - _("$(EXIF_FOCAL_LENGTH) - EXIF focal length\n") .. - _("$(EXIF_FOCUS_DISTANCE) - EXIF focus distance\n") .. - _("$(EXIF_CROP) - EXIF crop\n") .. - _("$(LONGITUDE) - longitude\n") .. - _("$(LATITUDE) - latitude\n") .. - _("$(ELEVATION) - elevation\n") .. - _("$(STARS) - star rating\n") .. - _("$(LABELS) - color labels\n") .. - _("$(MAKER) - camera maker\n") .. - _("$(MODEL) - camera model\n") .. - _("$(LENS) - lens\n") .. - _("$(TITLE) - title from metadata\n") .. - _("$(DESCRIPTION) - description from metadata\n") .. - _("$(CREATOR) - creator from metadata\n") .. - _("$(PUBLISHER) - publisher from metadata\n") .. - _("$(RIGHTS) - rights from metadata\n") .. - _("$(USERNAME) - username\n") .. - _("$(PICTURES_FOLDER) - pictures folder\n") .. - _("$(HOME) - user's home directory\n") .. - _("$(DESKTOP) - desktop directory"), - placeholder = _("enter pattern $(FILE_FOLDER)/$(FILE_NAME)"), + tooltip = ds.get_substitution_tooltip(), + placeholder = _("enter pattern") .. "$(FILE_FOLDER)/$(FILE_NAME)", text = "" } From ce7ddfa4722d2ecd31aa561f75ed21bc32b81f25 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Tue, 10 Sep 2024 21:19:37 -0400 Subject: [PATCH 346/445] examples/*.lua - cleaned up translatable messages --- examples/api_version.lua | 4 +--- examples/darkroom_demo.lua | 4 +--- examples/gettextExample.lua | 2 -- examples/gui_action.lua | 39 ++++++++++++++++----------------- examples/hello_world.lua | 2 -- examples/moduleExample.lua | 14 +++++------- examples/multi_os.lua | 6 ++--- examples/panels_demo.lua | 8 +++---- examples/preferenceExamples.lua | 30 ++++++++++++------------- examples/printExamples.lua | 2 -- examples/running_os.lua | 2 -- examples/x-touch.lua | 1 - 12 files changed, 46 insertions(+), 68 deletions(-) diff --git a/examples/api_version.lua b/examples/api_version.lua index d54b7883..aaf341c7 100644 --- a/examples/api_version.lua +++ b/examples/api_version.lua @@ -27,8 +27,6 @@ local dt = require "darktable" local gettext = dt.gettext.gettext -dt.gettext.bindtextdomain("api_version", dt.configuration.config_dir .."/lua/locale/") - local function _(msg) return gettext(msg) end @@ -41,7 +39,7 @@ end local result = dt.configuration.api_version_string dt.print_log("API Version: " .. result) -dt.print(string.format(_("API version: %s"), result)) +dt.print("API " .. _("version") .. ": " .. result) -- set the destroy routine so that script_manager can call it when -- it's time to destroy the script and then return the data to diff --git a/examples/darkroom_demo.lua b/examples/darkroom_demo.lua index 802df749..72bf1324 100644 --- a/examples/darkroom_demo.lua +++ b/examples/darkroom_demo.lua @@ -60,8 +60,6 @@ local PS = dt.configuration.running_os == "windows" and "\\" or "/" -- - - - - - - - - - - - - - - - - - - - - - - - local gettext = dt.gettext.gettext -dt.gettext.bindtextdomain("darkroom_demo", dt.configuration.config_dir .."/lua/locale/") - local function _(msgid) return gettext(msgid) end @@ -93,7 +91,7 @@ dt.gui.current_view(dt.gui.views.darkroom) local max_images = 10 -dt.print(_("showing images, with a pause in between each")) +dt.print(_("showing images, with a pause between each")) sleep(1500) -- display first 10 images of collection pausing for a second between each diff --git a/examples/gettextExample.lua b/examples/gettextExample.lua index 20d5db43..acffdca2 100644 --- a/examples/gettextExample.lua +++ b/examples/gettextExample.lua @@ -69,8 +69,6 @@ dt.print_error("Hello World!") local gettext = dt.gettext.gettext -dt.gettext.bindtextdomain("gettextExample", dt.configuration.config_dir .."/lua/locale/") - -- Translate a string using the darktable textdomain dt.print_error(gettext("image")) diff --git a/examples/gui_action.lua b/examples/gui_action.lua index 3bff94b6..d0e707df 100644 --- a/examples/gui_action.lua +++ b/examples/gui_action.lua @@ -5,7 +5,6 @@ local NaN = 0/0 local wg = {} local gettext = dt.gettext.gettext -dt.gettext.bindtextdomain("gui_action", dt.configuration.config_dir .."/lua/locale/") local function _(msgid) return gettext(msgid) @@ -29,37 +28,37 @@ script_data.show = nil -- only required for libs since the destroy_method only h wg.action = dt.new_widget("entry"){ text = "lib/filter/view", - placeholder = "action path", - tooltip = "enter the full path of an action, for example 'lib/filter/view'" + placeholder = _("action path"), + tooltip = _("enter the full path of an action, for example 'lib/filter/view'") } wg.instance = dt.new_widget("combobox"){ - label = "instance", - tooltip = "the instance of an image processing module to execute action on", + label = _("instance"), + tooltip = _("the instance of an image processing module to execute action on"), "0", "+1", "-1", "+2", "-2", "+3", "-3", "+4", "-4", "+5", "-5", "+6", "-6", "+7", "-7", "+8", "-8", "+9", "-9" } wg.element = dt.new_widget("entry"){ text = "", - placeholder = "action element", - tooltip = "enter the element of an action, for example 'selection', or leave empty for default" + placeholder = _("action element"), + tooltip = _("enter the element of an action, for example 'selection', or leave empty for default") } wg.effect = dt.new_widget("entry"){ text = "next", - placeholder = "action effect", - tooltip = "enter the effect of an action, for example 'next', or leave empty for default" + placeholder = _("action effect"), + tooltip = _("enter the effect of an action, for example 'next', or leave empty for default") } wg.speed = dt.new_widget("entry"){ text = "1", - placeholder = "action speed", - tooltip = "enter the speed to use in action execution, or leave empty to only read state" + placeholder = _("action speed"), + tooltip = _("enter the speed to use in action execution, or leave empty to only read state") } wg.check = dt.new_widget("check_button"){ - label = 'perform action', - tooltip = 'perform action or only read return', + label = _('perform action'), + tooltip = _('perform action or only read return'), clicked_callback = function() wg.speed.sensitive = wg.check.value end, @@ -73,7 +72,7 @@ wg.return_value = dt.new_widget("entry"){ dt.register_lib( "execute_action", -- Module name - "execute gui actions", -- name + _("execute gui actions"), -- name true, -- expandable false, -- resetable {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_LEFT_CENTER", 100}, @@ -85,33 +84,33 @@ dt.register_lib( dt.new_widget("box") { orientation = "horizontal", - dt.new_widget("label"){label = "action path", halign = "start"}, + dt.new_widget("label"){label = _("action path"), halign = "start"}, wg.action }, wg.instance, dt.new_widget("box") { orientation = "horizontal", - dt.new_widget("label"){label = "element", halign = "start"}, + dt.new_widget("label"){label = _("element"), halign = "start"}, wg.element }, dt.new_widget("box") { orientation = "horizontal", - dt.new_widget("label"){label = "effect", halign = "start"}, + dt.new_widget("label"){label = _("effect"), halign = "start"}, wg.effect }, wg.check, dt.new_widget("box") { orientation = "horizontal", - dt.new_widget("label"){label = "speed", halign = "start"}, + dt.new_widget("label"){label = _("speed"), halign = "start"}, wg.speed }, dt.new_widget("button") { - label = "execute action", - tooltip = "execute the action specified in the fields above", + label = _("execute action"), + tooltip = _("execute the action specified in the fields above"), clicked_callback = function(_) local sp = NaN if wg.check.value then sp = wg.speed.text end diff --git a/examples/hello_world.lua b/examples/hello_world.lua index e64c4f9a..d29c99c7 100644 --- a/examples/hello_world.lua +++ b/examples/hello_world.lua @@ -35,8 +35,6 @@ du.check_min_api_version("2.0.0", "hello_world") local gettext = dt.gettext.gettext -dt.gettext.bindtextdomain("hello_world", dt.configuration.config_dir .."/lua/locale/") - local function _(msg) return gettext(msg) end diff --git a/examples/moduleExample.lua b/examples/moduleExample.lua index edf4815a..6996d2a9 100644 --- a/examples/moduleExample.lua +++ b/examples/moduleExample.lua @@ -38,8 +38,6 @@ du.check_min_api_version("7.0.0", "moduleExample") -- https://www.darktable.org/lua-api/index.html#darktable_gettext local gettext = dt.gettext.gettext -dt.gettext.bindtextdomain("moduleExample", dt.configuration.config_dir .."/lua/locale/") - local function _(msgid) return gettext(msgid) end @@ -87,7 +85,7 @@ local function install_module() orientation = "vertical", dt.new_widget("button") { - label = _("my button"), + label = _("my ") .. "button", clicked_callback = function (_) dt.print(_("button clicked")) end @@ -112,10 +110,10 @@ local function restart() end -- https://www.darktable.org/lua-api/types_lua_check_button.html -local check_button = dt.new_widget("check_button"){label = _("my check_button"), value = true} +local check_button = dt.new_widget("check_button"){label = _("my ") .. "check_button", value = true} -- https://www.darktable.org/lua-api/types_lua_combobox.html -local combobox = dt.new_widget("combobox"){label = _("my combobox"), value = 2, "8", "16", "32"} +local combobox = dt.new_widget("combobox"){label = _("my ") .. "combobox", value = 2, "8", "16", "32"} -- https://www.darktable.org/lua-api/types_lua_entry.html local entry = dt.new_widget("entry") @@ -131,14 +129,14 @@ local entry = dt.new_widget("entry") -- https://www.darktable.org/lua-api/types_lua_file_chooser_button.html local file_chooser_button = dt.new_widget("file_chooser_button") { - title = _("my file_chooser_button"), -- The title of the window when choosing a file + title = _("my ") .. "file_chooser_button", -- The title of the window when choosing a file value = "", -- The currently selected file is_directory = false -- True if the file chooser button only allows directories to be selecte } -- https://www.darktable.org/lua-api/types_lua_label.html local label = dt.new_widget("label") -label.label = _("my label") -- This is an alternative way to the "{}" syntax to set a property +label.label = _("my ") .. "label" -- This is an alternative way to the "{}" syntax to set a property -- https://www.darktable.org/lua-api/types_lua_separator.html local separator = dt.new_widget("separator"){} @@ -146,7 +144,7 @@ local separator = dt.new_widget("separator"){} -- https://www.darktable.org/lua-api/types_lua_slider.html local slider = dt.new_widget("slider") { - label = _("my slider"), + label = _("my ") .. "slider", soft_min = 10, -- The soft minimum value for the slider, the slider can't go beyond this point soft_max = 100, -- The soft maximum value for the slider, the slider can't go beyond this point hard_min = 0, -- The hard minimum value for the slider, the user can't manually enter a value beyond this point diff --git a/examples/multi_os.lua b/examples/multi_os.lua index a1eea24b..83bfee98 100644 --- a/examples/multi_os.lua +++ b/examples/multi_os.lua @@ -72,8 +72,6 @@ local dtsys = require "lib/dtutils.system" -- system utilities local gettext = dt.gettext.gettext -dt.gettext.bindtextdomain("multi_os", dt.configuration.config_dir .."/lua/locale/") - local function _(msgid) return gettext(msgid) end @@ -215,7 +213,7 @@ end if dt.configuration.running_os ~= "linux" then local executable = "ufraw-batch" local ufraw_batch_path_widget = dt.new_widget("file_chooser_button"){ - title = _("select ufraw-batch[.exe] executable"), + title = string.format(_("select %s executable"), "ufraw-batch[.exe]"), value = df.get_executable_path_preference(executable), is_directory = false, changed_callback = function(self) @@ -226,7 +224,7 @@ if dt.configuration.running_os ~= "linux" then } dt.preferences.register("executable_paths", "ufraw-batch", -- name "file", -- type - _('multi_os: ufraw-batch location'), -- label + 'multi_os: ufraw-batch ' .. _('location'), -- label _('installed location of ufraw-batch, requires restart to take effect.'), -- tooltip "ufraw-batch", -- default ufraw_batch_path_widget diff --git a/examples/panels_demo.lua b/examples/panels_demo.lua index 36e31e3c..6fa82607 100644 --- a/examples/panels_demo.lua +++ b/examples/panels_demo.lua @@ -61,8 +61,6 @@ local PS = dt.configuration.running_os == "windows" and "\\" or "/" -- - - - - - - - - - - - - - - - - - - - - - - - local gettext = dt.gettext.gettext -dt.gettext.bindtextdomain("panels_demo", dt.configuration.config_dir .."/lua/locale/") - local function _(msgid) return gettext(msgid) end @@ -95,11 +93,11 @@ dt.gui.panel_show_all() -- hide center_top, center_bottom, left, top, right, bottom in order -dt.print(_("hiding all panels, one at a tme")) +dt.print(_("hiding all panels, one at a time")) sleep(1500) for i = 1, #panels do - dt.print(_("hiding " .. panels[i])) + dt.print(string.format(_("hiding %s"), panels[i])) dt.gui.panel_hide(panels[i]) sleep(1500) end @@ -110,7 +108,7 @@ end sleep(1500) for i = #panels, 1, -1 do - dt.print(_("showing " .. panels[i])) + dt.print(string.format(_("showing %s"), panels[i])) dt.gui.panel_show(panels[i]) sleep(1500) end diff --git a/examples/preferenceExamples.lua b/examples/preferenceExamples.lua index e3721ca6..c53ce163 100644 --- a/examples/preferenceExamples.lua +++ b/examples/preferenceExamples.lua @@ -28,8 +28,6 @@ local du = require "lib/dtutils" local gettext = dt.gettext.gettext -dt.gettext.bindtextdomain("preferenceExamples", dt.configuration.config_dir .."/lua/locale/") - local function _(msg) return gettext(msg) end @@ -49,22 +47,22 @@ du.check_min_api_version("2.0.1", "preferenceExamples") dt.preferences.register("preferenceExamples", -- script: This is a string used to avoid name collision in preferences (i.e namespace). Set it to something unique, usually the name of the script handling the preference. "preferenceExamplesString", -- name "string", -- type - _("example string"), -- label - _("example string tooltip"), -- tooltip + _("example") .. " string", -- label + _("example") .. " string " .. _("tooltip"), -- tooltip "String") -- default dt.preferences.register("preferenceExamples", -- script: This is a string used to avoid name collision in preferences (i.e namespace). Set it to something unique, usually the name of the script handling the preference. "preferenceExamplesBool", -- name "bool", -- type - _("example boolean"), -- label - _("example boolean tooltip"), -- tooltip + _("example") .. " boolean", -- label + _("example") .. " boolean " .. _("tooltip"), -- tooltip true) -- default dt.preferences.register("preferenceExamples", -- script: This is a string used to avoid name collision in preferences (i.e namespace). Set it to something unique, usually the name of the script handling the preference. "preferenceExamplesInteger", -- name "integer", -- type - _("example integer"), -- label - _("example integer tooltip"), -- tooltip + _("example") .. " integer", -- label + _("example") .. " integer " .. _("tooltip"), -- tooltip 2, -- default 1, -- min 99) -- max @@ -72,8 +70,8 @@ dt.preferences.register("preferenceExamples", -- script: This is a string dt.preferences.register("preferenceExamples", -- script: This is a string used to avoid name collision in preferences (i.e namespace). Set it to something unique, usually the name of the script handling the preference. "preferenceExamplesFloat", -- name "float", -- type - _("example float"), -- label - _("example float tooltip"), -- tooltip + _("example") .. " float", -- label + _("example") .. " float " .. _("tooltip"), -- tooltip 1.3, -- default 1, -- min 99, -- max @@ -82,22 +80,22 @@ dt.preferences.register("preferenceExamples", -- script: This is a string dt.preferences.register("preferenceExamples", -- script: This is a string used to avoid name collision in preferences (i.e namespace). Set it to something unique, usually the name of the script handling the preference. "preferenceExamplesFile", -- name "file", -- type - _("example file"), -- label - _("example file tooltip"), -- tooltip + _("example") .. " file", -- label + _("example") .. " file " .. _("tooltip"), -- tooltip "") -- default dt.preferences.register("preferenceExamples", -- script: This is a string used to avoid name collision in preferences (i.e namespace). Set it to something unique, usually the name of the script handling the preference. "preferenceExamplesDirectory", -- name "directory", -- type - _("example directory"), -- label - _("example directory tooltip"), -- tooltip + _("example") .. " directory", -- label + _("example") .. " directory " .. _("tooltip"), -- tooltip "") -- default dt.preferences.register("preferenceExamples", -- script: This is a string used to avoid name collision in preferences (i.e namespace). Set it to something unique, usually the name of the script handling the preference. "preferenceExamplesEnum", -- name "enum", -- type - _("example enum"), -- label - _("example enum tooltip"), -- tooltip + _("example") .. " enum", -- label + _("example") .. " enum " .. _("tooltip"), -- tooltip "Enum 1", -- default "Enum 1", "Enum 2") -- values diff --git a/examples/printExamples.lua b/examples/printExamples.lua index 23614c5b..4bedaffa 100644 --- a/examples/printExamples.lua +++ b/examples/printExamples.lua @@ -28,8 +28,6 @@ du.check_min_api_version("5.0.0", "printExamples") local gettext = dt.gettext.gettext -dt.gettext.bindtextdomain("printExamples", dt.configuration.config_dir .."/lua/locale/") - local function _(msg) return gettext(msg) end diff --git a/examples/running_os.lua b/examples/running_os.lua index 1e61cb84..3c45cee8 100644 --- a/examples/running_os.lua +++ b/examples/running_os.lua @@ -34,8 +34,6 @@ du.check_min_api_version("5.0.0", "running_os") local gettext = dt.gettext.gettext -dt.gettext.bindtextdomain("running_os", dt.configuration.config_dir .."/lua/locale/") - local function _(msg) return gettext(msg) end diff --git a/examples/x-touch.lua b/examples/x-touch.lua index dd8dd2e9..969fd105 100644 --- a/examples/x-touch.lua +++ b/examples/x-touch.lua @@ -56,7 +56,6 @@ local du = require "lib/dtutils" du.check_min_api_version("9.2.0", "x-touch") local gettext = dt.gettext.gettext -dt.gettext.bindtextdomain("gui_action", dt.configuration.config_dir .."/lua/locale/") local function _(msgid) return gettext(msgid) From 8863f6ade740b97060da2846aa3979c92d7e8c77 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Fri, 13 Sep 2024 14:46:47 -0400 Subject: [PATCH 347/445] tools/get*.lua - updated translable stirngs --- tools/get_lib_manpages.lua | 2 -- tools/get_libdoc.lua | 2 -- 2 files changed, 4 deletions(-) diff --git a/tools/get_lib_manpages.lua b/tools/get_lib_manpages.lua index a5a7ab97..65c68046 100644 --- a/tools/get_lib_manpages.lua +++ b/tools/get_lib_manpages.lua @@ -15,8 +15,6 @@ du.check_min_api_version("3.0.0", "get_lib_manpages") local gettext = dt.gettext.gettext -dt.gettext.bindtextdomain("get_lib_manpages", dt.configuration.config_dir .."/lua/locale/") - local function _(msg) return gettext(msg) end diff --git a/tools/get_libdoc.lua b/tools/get_libdoc.lua index 3749a683..78bbf760 100644 --- a/tools/get_libdoc.lua +++ b/tools/get_libdoc.lua @@ -12,8 +12,6 @@ du.check_min_api_version("3.0.0", "get_libdoc") local gettext = dt.gettext.gettext -dt.gettext.bindtextdomain("get_libdoc", dt.configuration.config_dir .."/lua/locale/") - local function _(msg) return gettext(msg) end From a72abe0ad0a01f422e36bf6dadfd1fd2cf2f5a6f Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Fri, 13 Sep 2024 14:47:37 -0400 Subject: [PATCH 348/445] tools/executable_manager - cleaned up translatable strings. Changed displayed name to executables. --- tools/executable_manager.lua | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tools/executable_manager.lua b/tools/executable_manager.lua index ffdf532d..97421e4e 100644 --- a/tools/executable_manager.lua +++ b/tools/executable_manager.lua @@ -37,8 +37,6 @@ du.check_min_api_version("7.0.0", "executable_manager") local gettext = dt.gettext.gettext -dt.gettext.bindtextdomain("executable_manager", dt.configuration.config_dir .."/lua/locale/") - local function _(msg) return gettext(msg) end @@ -117,7 +115,7 @@ local function install_module() if not exec_man.module_installed then dt.register_lib( "executable_manager", -- Module name - "executable manager", -- Visible name + _("executables"), -- Visible name true, -- expandable false, -- resetable {[dt.gui.views.lighttable] = {panel, panel_pos}}, -- containers @@ -201,7 +199,7 @@ exec_man.stack = dt.new_widget("stack"){} -- create a combobox to for indexing into the stack of widgets exec_man.selector = dt.new_widget("combobox"){ - label = "executable", + label = _("executable"), tooltip = _("select executable to modify"), value = 1, "placeholder", changed_callback = function(self) From 684178b27e48dbacb82718650468e27eb25ec3ef Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Fri, 13 Sep 2024 14:48:30 -0400 Subject: [PATCH 349/445] tools/script_manager - cleaned up translatable strings. Changed displayed name to scripts. --- tools/script_manager.lua | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/tools/script_manager.lua b/tools/script_manager.lua index fe8fa6ab..52d20825 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -58,10 +58,6 @@ local debug = require "darktable.debug" local gettext = dt.gettext - --- Tell gettext where to find the .mo file translating messages for a particular domain -dt.gettext.bindtextdomain("script_manager", dt.configuration.config_dir .. "/lua/locale/") - local function _(msgid) return gettext.dgettext("script_manager", msgid) end @@ -469,7 +465,7 @@ local function get_script_doc(script) return description else restore_log_level(old_log_level) - return "No documentation available" + return _("No documentation available") end end @@ -835,7 +831,7 @@ local function install_scripts() if count > 0 then update_combobox_choices(sm.widgets.folder_selector, sm.folders, sm.widgets.folder_selector.selected) - dt.print(_("scripts successfully installed into folder ") .. folder) + dt.print(_(string.format("scripts successfully installed into folder %s"), folder)) table.insert(sm.installed_repositories, {name = folder, directory = LUA_DIR .. PS .. folder}) update_script_update_choices() @@ -1165,7 +1161,7 @@ local function install_module() if not sm.module_installed then dt.register_lib( "script_manager", -- Module name - "script manager", -- Visible name + _("scripts"), -- Visible name true, -- expandable false, -- resetable {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_LEFT_BOTTOM", 100}}, -- containers @@ -1408,7 +1404,7 @@ end local page_back = "<" local page_forward = ">" -sm.widgets.page_status = dt.new_widget("label"){label = _("page:")} +sm.widgets.page_status = dt.new_widget("label"){label = _("page") .. ":"} sm.widgets.page_back = dt.new_widget("button"){ label = page_back, From 5bed7c914c36a0faae49a5bb4f039dd4a7425ff7 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Fri, 13 Sep 2024 19:47:44 -0400 Subject: [PATCH 350/445] contrib/[a-f]*.lua - fixed translatable strings to prepare for darktable translation --- contrib/AutoGrouper.lua | 1 - contrib/CollectHelper.lua | 4 +--- contrib/auto_snapshot.lua | 8 +++----- contrib/autostyle.lua | 1 - contrib/change_group_leader.lua | 6 ++---- contrib/clear_GPS.lua | 3 +-- contrib/color_profile_manager.lua | 2 -- contrib/copy_attach_detach_tags.lua | 2 -- contrib/cr2hdr.lua | 2 -- contrib/cycle_group_leader.lua | 4 +--- contrib/dbmaint.lua | 20 +++++++++----------- contrib/enfuseAdvanced.lua | 12 +++++------- contrib/exportLUT.lua | 2 -- contrib/ext_editor.lua | 2 -- contrib/face_recognition.lua | 2 -- contrib/fujifilm_dynamic_range.lua | 2 -- contrib/fujifilm_ratings.lua | 4 +--- 17 files changed, 23 insertions(+), 54 deletions(-) diff --git a/contrib/AutoGrouper.lua b/contrib/AutoGrouper.lua index 90f65dbc..72654ae2 100644 --- a/contrib/AutoGrouper.lua +++ b/contrib/AutoGrouper.lua @@ -44,7 +44,6 @@ du.check_min_api_version("7.0.0", "AutoGrouper") local MOD = 'autogrouper' local gettext = dt.gettext -gettext.bindtextdomain(MOD, dt.configuration.config_dir .."/lua/locale/") local function _(msgid) return gettext.gettext(msgid) diff --git a/contrib/CollectHelper.lua b/contrib/CollectHelper.lua index ca76d857..f06b14e4 100644 --- a/contrib/CollectHelper.lua +++ b/contrib/CollectHelper.lua @@ -53,8 +53,6 @@ local all_active = false du.check_min_api_version("7.0.0", "CollectHelper") -dt.gettext.bindtextdomain("CollectHelper", dt.configuration.config_dir .."/lua/locale/") - local function _(msgid) return gettext(msgid) end @@ -239,7 +237,7 @@ end dt.preferences.register("module_CollectHelper", "all_and", -- name "bool", -- type _('CollectHelper: all'), -- label - _('will create a collect parameter set that utilizes all enabled CollectHelper types (and)'), -- tooltip + _('creates a collect parameter set that utilizes all enabled CollectHelper types (and)'), -- tooltip true -- default ) dt.preferences.register("module_CollectHelper", "colors", -- name diff --git a/contrib/auto_snapshot.lua b/contrib/auto_snapshot.lua index f42631f4..3b883412 100644 --- a/contrib/auto_snapshot.lua +++ b/contrib/auto_snapshot.lua @@ -59,8 +59,6 @@ du.check_min_api_version("7.0.0", MODULE) -- choose the minimum version that c local gettext = dt.gettext.gettext -dt.gettext.bindtextdomain(MODULE , dt.configuration.config_dir .. "/lua/locale/") - local function _(msgid) return gettext(MODULE, msgid) end @@ -81,7 +79,7 @@ script_data.metadata = { name = "auto_snapshot", -- name of script purpose = _("automatically take a snapshot when an image is loaded in darkroom"), -- purpose of script author = "Bill Ferguson ", -- your name and optionally e-mail address - help = "" -- URL to help/documentation + help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/auto_snapshot/" -- URL to help/documentation } @@ -101,8 +99,8 @@ local auto_snapshot = {} -- P R E F E R E N C E S -- - - - - - - - - - - - - - - - - - - - - - - - -dt.preferences.register(MODULE, "always_create_snapshot", "bool", "always automatically create_snapshot", - "auto_snapshot - create a snapshot even if the image is altered", false) +dt.preferences.register(MODULE, "always_create_snapshot", "bool", "auto_snapshot - " .. _("always automatically create_snapshot"), + _("create a snapshot even if the image is altered"), false) -- - - - - - - - - - - - - - - - - - - - - - - - -- D A R K T A B L E I N T E G R A T I O N diff --git a/contrib/autostyle.lua b/contrib/autostyle.lua index 336e6f78..46b14cac 100644 --- a/contrib/autostyle.lua +++ b/contrib/autostyle.lua @@ -44,7 +44,6 @@ local syslib = require "lib/dtutils.system" du.check_min_api_version("7.0.0", "autostyle") local gettext = darktable.gettext.gettext -darktable.gettext.bindtextdomain("autostyle", darktable.configuration.config_dir .."/lua/locale/") local function _(msgid) return gettext(msgid) diff --git a/contrib/change_group_leader.lua b/contrib/change_group_leader.lua index 11522cbd..e7f424b7 100644 --- a/contrib/change_group_leader.lua +++ b/contrib/change_group_leader.lua @@ -40,8 +40,6 @@ local gettext = dt.gettext.gettext local MODULE = "change_group_leader" -dt.gettext.bindtextdomain(MODULE, dt.configuration.config_dir .."/lua/locale/") - du.check_min_api_version("3.0.0", MODULE) local function _(msgid) @@ -65,7 +63,7 @@ script_data.restart = nil -- how to restart the (lib) script after it's been hid script_data.show = nil -- only required for libs since the destroy_method only hides them -- create a namespace to contain persistent data and widgets -chg_grp_ldr = {} +local chg_grp_ldr = {} local cgl = chg_grp_ldr @@ -82,7 +80,7 @@ local function install_module() if not cgl.module_installed then dt.register_lib( MODULE, -- Module name - _("change_group_leader"), -- Visible name + _("change group leader"), -- Visible name true, -- expandable false, -- resetable {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 700}}, -- containers diff --git a/contrib/clear_GPS.lua b/contrib/clear_GPS.lua index f90d8b8f..8c591661 100644 --- a/contrib/clear_GPS.lua +++ b/contrib/clear_GPS.lua @@ -40,7 +40,6 @@ local dt = require "darktable" local du = require "lib/dtutils" local gettext = dt.gettext.gettext -dt.gettext.bindtextdomain("clear_GPS", dt.configuration.config_dir .."/lua/locale/") local function _(msgid) return gettext(msgid) @@ -92,7 +91,7 @@ dt.gui.libs.image.register_action( dt.register_event( "clear_GPS", "shortcut", function(event, shortcut) clear_GPS(dt.gui.action_images) end, - _("clear GPS data") + _("clear GPS data from selected images") ) return script_data diff --git a/contrib/color_profile_manager.lua b/contrib/color_profile_manager.lua index 52fc38ce..6114992e 100644 --- a/contrib/color_profile_manager.lua +++ b/contrib/color_profile_manager.lua @@ -55,8 +55,6 @@ du.check_min_api_version("7.0.0", "color_profile_manager") local gettext = dt.gettext.gettext -dt.gettext.bindtextdomain("color_profile_manager", dt.configuration.config_dir .."/lua/locale/") - local function _(msgid) return gettext(msgid) end diff --git a/contrib/copy_attach_detach_tags.lua b/contrib/copy_attach_detach_tags.lua index 6d6c470c..2b66bc76 100644 --- a/contrib/copy_attach_detach_tags.lua +++ b/contrib/copy_attach_detach_tags.lua @@ -44,8 +44,6 @@ local gettext = dt.gettext.gettext du.check_min_api_version("7.0.0", "copy_attach_detach_tags") -dt.gettext.bindtextdomain("copy_attach_detach_tags", dt.configuration.config_dir .."/lua/locale/") - local function _(msgid) return gettext(msgid) end diff --git a/contrib/cr2hdr.lua b/contrib/cr2hdr.lua index a091a8f1..209287cc 100644 --- a/contrib/cr2hdr.lua +++ b/contrib/cr2hdr.lua @@ -39,8 +39,6 @@ du.check_min_api_version("7.0.0", "cr2hdr") local gettext = darktable.gettext.gettext -darktable.gettext.bindtextdomain("cr2hdr", darktable.configuration.config_dir .."/lua/locale/") - local function _(msgid) return gettext(msgid) end diff --git a/contrib/cycle_group_leader.lua b/contrib/cycle_group_leader.lua index 30ed0b8e..665f0c09 100644 --- a/contrib/cycle_group_leader.lua +++ b/contrib/cycle_group_leader.lua @@ -60,8 +60,6 @@ du.check_min_api_version("7.0.0", MODULE) local gettext = dt.gettext.gettext -dt.gettext.bindtextdomain("cycle_group_leader", dt.configuration.config_dir .."/lua/locale/") - local function _(msgid) return gettext(msgid) end @@ -106,7 +104,7 @@ end local function cycle_group_leader(image) local group_images = image:get_group_members() if #group_images < 2 then - hinter_msg(_("no images to cycle to in group")) + hinter_msg(_("no images to cycle through in group")) return else local position = nil diff --git a/contrib/dbmaint.lua b/contrib/dbmaint.lua index 70454ff6..8d24f1d2 100644 --- a/contrib/dbmaint.lua +++ b/contrib/dbmaint.lua @@ -63,8 +63,6 @@ du.check_min_api_version("7.0.0", MODULE) -- choose the minimum version that c local gettext = dt.gettext.gettext -dt.gettext.bindtextdomain(MODULE , dt.configuration.config_dir .. "/lua/locale/") - local function _(msgid) return gettext(MODULE, msgid) end @@ -195,21 +193,21 @@ dbmaint.list_widget = dt.new_widget("text_view"){ } dbmaint.chooser = dt.new_widget("combobox"){ - label = "scan for", + label = _("scan for"), selected = 1, - "film rolls", "images", + _("film rolls"), _("images"), reset_callback = function(this) this.selected = 1 end } dbmaint.scan_button = dt.new_widget("button"){ - label = "scan", - tooltip = "click to scan for missing film rolls/files", + label = _("scan"), + tooltip = _("click to scan for missing film rolls/files"), clicked_callback = function(this) local found = nil local found_text = "" - if dbmaint.chooser.value == "film rolls" then + if dbmaint.chooser.selected == 1 then -- film rolls found = scan_film_rolls() if #found > 0 then for _, film in ipairs(found) do @@ -238,11 +236,11 @@ dbmaint.scan_button = dt.new_widget("button"){ } dbmaint.remove_button = dt.new_widget("button"){ - label = "remove", - tooltip = "remove missing film rolls/images", + label = _("remove"), + tooltip = _("remove missing film rolls/images"), sensitive = false, clicked_callback = function(this) - if dbmaint.chooser.value == "film rolls" then + if dbmaint.chooser.selected == 1 then -- film rolls remove_missing_film_rolls(dbmaint.found) else remove_missing_images(dbmaint.found) @@ -258,7 +256,7 @@ dbmaint.remove_button = dt.new_widget("button"){ dbmaint.main_widget = dt.new_widget("box"){ orientation = "vertical", - dt.new_widget("section_label"){label = "missing items"}, + dt.new_widget("section_label"){label = _("missing items")}, dbmaint.list_widget, dt.new_widget("label"){label = ""}, dbmaint.chooser, diff --git a/contrib/enfuseAdvanced.lua b/contrib/enfuseAdvanced.lua index b5ec586e..b35cb490 100644 --- a/contrib/enfuseAdvanced.lua +++ b/contrib/enfuseAdvanced.lua @@ -70,8 +70,6 @@ du.check_min_api_version("7.0.0", "enfuseAdvanced") -- Tell gettext where to find the .mo file translating messages for a particular domain local gettext = dt.gettext.gettext -dt.gettext.bindtextdomain("enfuseAdvanced", dt.configuration.config_dir .."/lua/locale/") - local function _(msgid) return gettext(msgid) end @@ -445,7 +443,7 @@ local function main(storage, image_table, extra_data) dt.print(_('too few images selected, please select at least 2 images')) return elseif extra_data[1] == 2 then - dt.print(_('installation error, please verify binary paths are proper')) + dt.print(_('installation error, please verify binary paths are correct')) return end local images_to_remove = '' @@ -956,7 +954,7 @@ if temp == '' then temp = nil end GUI.Target.add_tags = dt.new_widget('entry'){ tooltip = _('additional tags to be added on import, seperate with commas, all spaces will be removed'), text = temp, - placeholder = _('enter tags, seperated by commas'), + placeholder = _('enter tags, separated by commas'), editable = true } temp = dt.preferences.read(mod, 'active_current_preset_ind', 'integer') @@ -1023,7 +1021,7 @@ GUI.Presets.variants_type = dt.new_widget('combobox'){ GUI.Presets.variants_type.sensitive = GUI.Presets.variants.value temp = df.get_executable_path_preference(AIS.name) GUI.exes.align_image_stack = dt.new_widget('file_chooser_button'){ - title = 'AIS binary path', + title = 'align_image_stack ' .. _('binary path'), value = temp, tooltip = temp, is_directory = false, @@ -1031,7 +1029,7 @@ GUI.exes.align_image_stack = dt.new_widget('file_chooser_button'){ } temp = df.get_executable_path_preference(ENF.name) GUI.exes.enfuse = dt.new_widget('file_chooser_button'){ - title = 'enfuse binary path', + title = 'enfuse ' .. _('binary path'), value = temp, tooltip = temp, is_directory = false, @@ -1039,7 +1037,7 @@ GUI.exes.enfuse = dt.new_widget('file_chooser_button'){ } temp = df.get_executable_path_preference(EXF.name) GUI.exes.exiftool = dt.new_widget('file_chooser_button'){ - title = 'Exiftool binary path', + title = 'exiftool ' .. _('binary path'), value = temp, tooltip = temp, is_directory = false, diff --git a/contrib/exportLUT.lua b/contrib/exportLUT.lua index be904cdd..80854567 100644 --- a/contrib/exportLUT.lua +++ b/contrib/exportLUT.lua @@ -35,8 +35,6 @@ du.check_min_api_version("7.0.0", "exportLUT") local gettext = dt.gettext.gettext -dt.gettext.bindtextdomain("exportLUT", dt.configuration.config_dir .."/lua/locale/") - local function _(msgid) return gettext(msgid) end diff --git a/contrib/ext_editor.lua b/contrib/ext_editor.lua index 592550bc..0cee9454 100644 --- a/contrib/ext_editor.lua +++ b/contrib/ext_editor.lua @@ -78,8 +78,6 @@ du.check_min_api_version("7.0.0", MODULE_NAME) -- translation local gettext = dt.gettext.gettext -dt.gettext.bindtextdomain("ext_editor", dt.configuration.config_dir .."/lua/locale/") - local function _(msgid) return gettext(msgid) end diff --git a/contrib/face_recognition.lua b/contrib/face_recognition.lua index 0f6183bd..74827f12 100644 --- a/contrib/face_recognition.lua +++ b/contrib/face_recognition.lua @@ -54,8 +54,6 @@ local OUTPUT = dt.configuration.tmp_dir .. PS .. "facerecognition.txt" du.check_min_api_version("7.0.0", MODULE) -dt.gettext.bindtextdomain("face_recognition", dt.configuration.config_dir .."/lua/locale/") - local function _(msgid) return gettext(msgid) end diff --git a/contrib/fujifilm_dynamic_range.lua b/contrib/fujifilm_dynamic_range.lua index 6116d352..7bb6ab53 100644 --- a/contrib/fujifilm_dynamic_range.lua +++ b/contrib/fujifilm_dynamic_range.lua @@ -65,8 +65,6 @@ local gettext = dt.gettext.gettext du.check_min_api_version("7.0.0", "fujifilm_dynamic_range") -dt.gettext.bindtextdomain("fujifilm_dynamic_range", dt.configuration.config_dir .."/lua/locale/") - local function _(msgid) return gettext(msgid) end diff --git a/contrib/fujifilm_ratings.lua b/contrib/fujifilm_ratings.lua index 049e3c20..c9a034d8 100644 --- a/contrib/fujifilm_ratings.lua +++ b/contrib/fujifilm_ratings.lua @@ -31,8 +31,6 @@ local gettext = dt.gettext.gettext du.check_min_api_version("7.0.0", "fujifilm_ratings") -dt.gettext.bindtextdomain("fujifilm_ratings", dt.configuration.config_dir .."/lua/locale/") - local function _(msgid) return gettext(msgid) end @@ -58,7 +56,7 @@ local function detect_rating(event, image) return end if not df.check_if_bin_exists("exiftool") then - dt.print_error(_("exiftool not found")) + dt.print_error("exiftool not found") return end local RAF_filename = df.sanitize_filename(tostring(image)) From 4165d46b33989f80eb5a3f44adaf730350ff653c Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Mon, 16 Sep 2024 20:04:29 -0400 Subject: [PATCH 351/445] tools/script_manager - fixed capitalization --- tools/script_manager.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/script_manager.lua b/tools/script_manager.lua index 52d20825..7991672e 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -465,7 +465,7 @@ local function get_script_doc(script) return description else restore_log_level(old_log_level) - return _("No documentation available") + return _("no documentation available") end end From 842f2fca66a1c6f9121454c60d51093a2fe6b163 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Mon, 16 Sep 2024 21:16:34 -0400 Subject: [PATCH 352/445] contrib/[g-o]*.lua - clean up translatable strings --- contrib/HDRMerge.lua | 10 ++++------ contrib/LabelsToTags.lua | 8 +++----- contrib/OpenInExplorer.lua | 2 -- contrib/geoJSON_export.lua | 12 +++++------- contrib/geoToolbox.lua | 10 ++++------ contrib/gimp.lua | 2 -- contrib/gpx_export.lua | 4 +--- contrib/harmonic_armature_guide.lua | 2 -- contrib/hif_group_leader.lua | 6 ++---- contrib/hugin.lua | 6 ++---- contrib/image_stack.lua | 10 ++++------ contrib/image_time.lua | 6 ++---- contrib/jpg_group_leader.lua | 6 ++---- contrib/kml_export.lua | 8 +++----- 14 files changed, 32 insertions(+), 60 deletions(-) diff --git a/contrib/HDRMerge.lua b/contrib/HDRMerge.lua index 5ab1bee2..76067d53 100644 --- a/contrib/HDRMerge.lua +++ b/contrib/HDRMerge.lua @@ -54,8 +54,6 @@ du.check_min_api_version("7.0.0", "HDRmerge") -- Tell gettext where to find the .mo file translating messages for a particular domain local gettext = dt.gettext.gettext -dt.gettext.bindtextdomain("HDRMerge", dt.configuration.config_dir .."/lua/locale/") - local function _(msgid) return gettext(msgid) end @@ -218,7 +216,7 @@ local function main() PreCall({HDRM}) --check if furst run then check if install OK if HDRM.install_error then dt.print_error('HDRMerge install issue') - dt.print(_('HDRMerge install issue, please ensure the binary path is proper')) + dt.print(_('HDRMerge install issue, please ensure the binary path is correct')) return end images = dt.gui.selection() --get selected images @@ -416,14 +414,14 @@ GUI.Target.copy_tags = dt.new_widget('check_button'){ temp = dt.preferences.read(mod, 'active_add_tags', 'string') if temp == '' then temp = nil end GUI.Target.add_tags = dt.new_widget('entry'){ - tooltip = _('additional tags to be added on import, seperate with commas, all spaces will be removed'), + tooltip = _('additional tags to be added on import, separate with commas, all spaces will be removed'), text = temp, - placeholder = _('enter tags, seperated by commas'), + placeholder = _('enter tags, separated by commas'), editable = true } GUI.run = dt.new_widget('button'){ label = _('merge'), - tooltip =_('run HDRMerge with the above specified settings'), + tooltip =_('run HDRMerge with the above settings'), clicked_callback = function() main() end } GUI.exes.HDRMerge = dt.new_widget('file_chooser_button'){ diff --git a/contrib/LabelsToTags.lua b/contrib/LabelsToTags.lua index 1054a8b9..0c00c123 100644 --- a/contrib/LabelsToTags.lua +++ b/contrib/LabelsToTags.lua @@ -54,8 +54,6 @@ du.check_min_api_version("7.0.0", "LabelsToTags") local gettext = darktable.gettext.gettext -darktable.gettext.bindtextdomain("LabelsToTags", darktable.configuration.config_dir .."/lua/locale/") - local function _(msgid) return gettext(msgid) end @@ -216,8 +214,8 @@ ltt.my_widget = darktable.new_widget("box") { orientation = "vertical", mappingComboBox, darktable.new_widget("button") { - label = "start", - tooltip = "Tag all selected images", + label = _("start"), + tooltip = _("tag all selected images"), clicked_callback = doTagging } } @@ -247,7 +245,7 @@ end local function install_module() if not ltt.module_installed then - darktable.register_lib(LIB_ID,"labels to tags",true,true,{ + darktable.register_lib(LIB_ID,_("labels to tags"),true,true,{ [darktable.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER",20}, },ltt.my_widget,nil,nil) ltt.module_installed = true diff --git a/contrib/OpenInExplorer.lua b/contrib/OpenInExplorer.lua index 1633a1a5..4ba59690 100644 --- a/contrib/OpenInExplorer.lua +++ b/contrib/OpenInExplorer.lua @@ -56,8 +56,6 @@ local gettext = dt.gettext.gettext --Check API version du.check_min_api_version("7.0.0", "OpenInExplorer") -dt.gettext.bindtextdomain("OpenInExplorer", dt.configuration.config_dir .."/lua/locale/") - local function _(msgid) return gettext(msgid) end diff --git a/contrib/geoJSON_export.lua b/contrib/geoJSON_export.lua index dc336b2a..aff04b22 100644 --- a/contrib/geoJSON_export.lua +++ b/contrib/geoJSON_export.lua @@ -40,8 +40,6 @@ local gettext = dt.gettext.gettext du.check_min_api_version("7.0.0", "geoJSON_export") -dt.gettext.bindtextdomain("geoJSON_export", dt.configuration.config_dir .."/lua/locale/") - local function _(msgid) return gettext(msgid) end @@ -92,19 +90,19 @@ end local function create_geoJSON_file(storage, image_table, extra_data) if not df.check_if_bin_exists("mkdir") then - dt.print_error(_("mkdir not found")) + dt.print_error("mkdir not found") return end if not df.check_if_bin_exists("convert") then - dt.print_error(_("convert not found")) + dt.print_error("convert not found") return end if not df.check_if_bin_exists("xdg-open") then - dt.print_error(_("xdg-open not found")) + dt.print_error("xdg-open not found") return end if not df.check_if_bin_exists("xdg-user-dir") then - dt.print_error(_("xdg-user-dir not found")) + dt.print_error("xdg-user-dir not found") return end @@ -295,7 +293,7 @@ local function create_geoJSON_file(storage, image_table, extra_data) file:write(geoJSON_file) file:close() - dt.print("geoJSON file created in "..exportDirectory) + dt.print(string.format(_("%s file created in %s", "geoJSON", exportDirectory))) -- Open the file with the standard programm if ( dt.preferences.read("geoJSON_export","OpengeoJSONFile","bool") == true ) then diff --git a/contrib/geoToolbox.lua b/contrib/geoToolbox.lua index 677af0a1..f2ab6957 100644 --- a/contrib/geoToolbox.lua +++ b/contrib/geoToolbox.lua @@ -33,8 +33,6 @@ local gettext = dt.gettext.gettext du.check_min_api_version("7.0.0", "geoToolbox") -dt.gettext.bindtextdomain("geoToolbox", dt.configuration.config_dir .."/lua/locale/") - local function _(msgid) return gettext(msgid) end @@ -77,7 +75,7 @@ local label_copy_gps_lon = dt.new_widget("check_button") } local label_copy_gps_ele = dt.new_widget("check_button") { - label = _("elevation:"), + label = _("elevation: "), value = true } -- @@ -372,12 +370,12 @@ end local function reverse_geocode() if not df.check_if_bin_exists("curl") then - dt.print_error(_("curl not found")) + dt.print_error("curl not found") return end if not df.check_if_bin_exists("jq") then - dt.print_error(_("jq not found")) + dt.print_error("jq not found") return end @@ -597,7 +595,7 @@ local function install_module() if not gT.module_installed then dt.register_lib( "geoToolbox", -- Module name - "geo toolbox", -- name + _("geo toolbox"), -- name true, -- expandable false, -- resetable {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, -- containers diff --git a/contrib/gimp.lua b/contrib/gimp.lua index 9a60cada..8e285517 100644 --- a/contrib/gimp.lua +++ b/contrib/gimp.lua @@ -74,8 +74,6 @@ local gimp_widget = nil du.check_min_api_version("7.0.0", "gimp") -dt.gettext.bindtextdomain("gimp", dt.configuration.config_dir .."/lua/locale/") - local function _(msgid) return gettext(msgid) end diff --git a/contrib/gpx_export.lua b/contrib/gpx_export.lua index b3d93015..84fc7bf9 100644 --- a/contrib/gpx_export.lua +++ b/contrib/gpx_export.lua @@ -29,8 +29,6 @@ local gettext = dt.gettext dl.check_min_api_version("7.0.0", "gpx_export") -gettext.bindtextdomain("gpx_export", dt.configuration.config_dir .."/lua/locale/") - local function _(msgid) return gettext.dgettext("gpx_export", msgid) end @@ -150,7 +148,7 @@ local function install_module() if not gpx.module_installed then dt.register_lib( "gpx_exporter", - "gpx export", + _("gpx export"), true, -- expandable true, -- resetable {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, -- containers diff --git a/contrib/harmonic_armature_guide.lua b/contrib/harmonic_armature_guide.lua index fd16f2b6..a85195cc 100644 --- a/contrib/harmonic_armature_guide.lua +++ b/contrib/harmonic_armature_guide.lua @@ -36,8 +36,6 @@ local gettext = dt.gettext.gettext du.check_min_api_version("2.0.0", "harmonic_armature_guide") -dt.gettext.bindtextdomain("harmonic_armature_guide", dt.configuration.config_dir .."/lua/locale/") - local function _(msgid) return gettext(msgid) end diff --git a/contrib/hif_group_leader.lua b/contrib/hif_group_leader.lua index 26eaf48d..2252f967 100644 --- a/contrib/hif_group_leader.lua +++ b/contrib/hif_group_leader.lua @@ -64,8 +64,6 @@ du.check_min_api_version("7.0.0", MODULE) local gettext = dt.gettext.gettext -dt.gettext.bindtextdomain("hif_group_leader", dt.configuration.config_dir .."/lua/locale/") - local function _(msgid) return gettext(msgid) end @@ -188,7 +186,7 @@ dt.register_event(MODULE .. "_collect", "shortcut", local images = dt.collection make_existing_hif_group_leader(images) end, - _("make hif group leader for collection") + string.format(_("make hif group leader for %s", "collection")) ) dt.register_event(MODULE .. "_select", "shortcut", @@ -196,7 +194,7 @@ dt.register_event(MODULE .. "_select", "shortcut", local images = dt.gui.selection() make_existing_hif_group_leader(images) end, - _("make hif group leader for selection") + string.format(_("make hif group leader for %s", "selection")) ) return script_data \ No newline at end of file diff --git a/contrib/hugin.lua b/contrib/hugin.lua index f209c0c5..12849168 100644 --- a/contrib/hugin.lua +++ b/contrib/hugin.lua @@ -56,8 +56,6 @@ local PQ = dt.configuration.running_os == "windows" and '"' or "'" -- works with darktable API version from 5.0.0 on du.check_min_api_version("7.0.0", "hugin") -dt.gettext.bindtextdomain("hugin", dt.configuration.config_dir .."/lua/locale/") - local function _(msgid) return gettext(msgid) end @@ -85,7 +83,7 @@ end local function show_status(storage, image, format, filename, number, total, high_quality, extra_data) - dt.print("exporting to hugin: "..tostring(number).."/"..tostring(total)) + dt.print(string.format(_("exporting to hugin: %d / $d", number, total))) end local function create_panorama(storage, image_table, extra_data) --finalize @@ -146,7 +144,7 @@ local function create_panorama(storage, image_table, extra_data) --finalize end if first_file == nil then - dt.print("no file selected") + dt.print(_("no file selected")) return end diff --git a/contrib/image_stack.lua b/contrib/image_stack.lua index c63ff166..817dc7a6 100644 --- a/contrib/image_stack.lua +++ b/contrib/image_stack.lua @@ -73,8 +73,6 @@ local PS = dt.configuration.running_os == "windows" and "\\" or "/" -- works with LUA API version 5.0.0 du.check_min_api_version("7.0.0", "image_stack") -dt.gettext.bindtextdomain("image_stack", dt.configuration.config_dir .."/lua/locale/") - local function _(msgid) return gettext(msgid) end @@ -141,19 +139,19 @@ local chkbtn_will_align = dt.new_widget("check_button"){ local chkbtn_radial_distortion = dt.new_widget("check_button"){ label = _('optimize radial distortion for all images'), value = dt.preferences.read("align_image_stack", "def_radial_distortion", "bool"), - tooltip = _('optimize radial distortion for all images, \nexcept for first'), + tooltip = _('optimize radial distortion for all images, \nexcept the first'), } local chkbtn_optimize_field = dt.new_widget("check_button"){ label = _('optimize field of view for all images'), value = dt.preferences.read("align_image_stack", "def_optimize_field", "bool"), - tooltip =_('optimize field of view for all images, except for first. \nUseful for aligning focus stacks (DFF) with slightly \ndifferent magnification.'), + tooltip =_('optimize field of view for all images, except the first. \nUseful for aligning focus stacks (DFF) with slightly \ndifferent magnification.'), } local chkbtn_optimize_image_center = dt.new_widget("check_button"){ label = _('optimize image center shift for all images'), value = dt.preferences.read("align_image_stack", "def_optimize_image_center", "bool"), - tooltip =_('optimize image center shift for all images, \nexcept for first.'), + tooltip =_('optimize image center shift for all images, \nexcept the first.'), } local chkbtn_auto_crop = dt.new_widget("check_button"){ @@ -506,7 +504,7 @@ local function image_stack(storage, image_table, extra_data) return end - job = dt.gui.create_job("image stack", true, stop_job) + job = dt.gui.create_job(_("image stack"), true, stop_job) job.percent = job.percent + percent_step -- align images if requested diff --git a/contrib/image_time.lua b/contrib/image_time.lua index ff5f8c28..4daf9c6b 100644 --- a/contrib/image_time.lua +++ b/contrib/image_time.lua @@ -116,8 +116,6 @@ img_time.event_registered = false du.check_min_api_version("7.0.0", "image_time") -dt.gettext.bindtextdomain("image_time", dt.configuration.config_dir .."/lua/locale/") - local function _(msgid) return gettext(msgid) end @@ -195,7 +193,7 @@ end local function synchronize_time(images) local sign = 1 - if img_time.sdir.value == "subtract" then + if img_time.sdir.value == _("subtract") then sign = -1 end synchronize_times(images, tonumber(img_time.diff_entry.text) * sign) @@ -511,7 +509,7 @@ img_time.stack = dt.new_widget("stack"){ dt.new_widget("box"){ orientation = "vertical", dt.new_widget("label"){label = _("set time")}, - dt.new_widget("section_label"){label = _("date: ")}, + dt.new_widget("section_label"){label = _("date:")}, img_time.sdy, img_time.smo, img_time.syr, diff --git a/contrib/jpg_group_leader.lua b/contrib/jpg_group_leader.lua index 6201b398..ef7cf910 100644 --- a/contrib/jpg_group_leader.lua +++ b/contrib/jpg_group_leader.lua @@ -64,8 +64,6 @@ du.check_min_api_version("7.0.0", MODULE) local gettext = dt.gettext.gettext -dt.gettext.bindtextdomain("jpg_group_leader", dt.configuration.config_dir .."/lua/locale/") - local function _(msgid) return gettext(msgid) end @@ -188,7 +186,7 @@ dt.register_event(MODULE .. "_collect", "shortcut", local images = dt.collection make_existing_jpg_group_leader(images) end, - _("make jpg group leader for collection") + string.format(_("make jpg group leader for %s", "collection")) ) dt.register_event(MODULE .. "_select", "shortcut", @@ -196,7 +194,7 @@ dt.register_event(MODULE .. "_select", "shortcut", local images = dt.gui.selection() make_existing_jpg_group_leader(images) end, - _("make jpg group leader for selection") + string.format(_("make jpg group leader for %s", "selection")) ) return script_data \ No newline at end of file diff --git a/contrib/kml_export.lua b/contrib/kml_export.lua index ec1aa04a..561e8ba8 100644 --- a/contrib/kml_export.lua +++ b/contrib/kml_export.lua @@ -45,8 +45,6 @@ local PS = dt.configuration.running_os == "windows" and "\\" or "/" du.check_min_api_version("7.0.0", "kml_export") -dt.gettext.bindtextdomain("kml_export", dt.configuration.config_dir .."/lua/locale/") - local function _(msgid) return gettext(msgid) end @@ -95,12 +93,12 @@ local function create_kml_file(storage, image_table, extra_data) end if not df.check_if_bin_exists(magickPath) then - dt.print_error(_("magick not found")) + dt.print_error("magick not found") return end if dt.configuration.running_os == "linux" then if not df.check_if_bin_exists("xdg-user-dir") then - dt.print_error(_("xdg-user-dir not found")) + dt.print_error("xdg-user-dir not found") return end end @@ -110,7 +108,7 @@ local function create_kml_file(storage, image_table, extra_data) if ( dt.preferences.read("kml_export","CreateKMZ","bool") == true and dt.configuration.running_os == "linux") then if not df.check_if_bin_exists("zip") then - dt.print_error(_("zip not found")) + dt.print_error("zip not found") return end exportDirectory = dt.configuration.tmp_dir From ecff9205375bf7218945d4483efa99fbf7650f27 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Tue, 17 Sep 2024 15:29:16 -0400 Subject: [PATCH 353/445] contrib/[p-z]*.lua - cleaned up translatable strings --- contrib/RL_out_sharp.lua | 2 -- contrib/passport_guide.lua | 2 -- contrib/passport_guide_germany.lua | 2 -- contrib/pdf_slideshow.lua | 2 -- contrib/photils.lua | 5 ++--- contrib/quicktag.lua | 6 ++---- contrib/rate_group.lua | 2 -- contrib/rename-tags.lua | 2 -- contrib/rename_images.lua | 2 -- contrib/select_non_existing.lua | 2 -- contrib/select_untagged.lua | 2 -- contrib/slideshowMusic.lua | 2 -- contrib/transfer_hierarchy.lua | 4 +--- contrib/video_ffmpeg.lua | 10 ++++------ 14 files changed, 9 insertions(+), 36 deletions(-) diff --git a/contrib/RL_out_sharp.lua b/contrib/RL_out_sharp.lua index 9e0a1fb0..9083277f 100644 --- a/contrib/RL_out_sharp.lua +++ b/contrib/RL_out_sharp.lua @@ -68,8 +68,6 @@ du.check_min_api_version("7.0.0", MODULE_NAME) -- translation local gettext = dt.gettext.gettext -dt.gettext.bindtextdomain("RL_out_sharp", dt.configuration.config_dir .."/lua/locale/") - local function _(msgid) return gettext(msgid) end diff --git a/contrib/passport_guide.lua b/contrib/passport_guide.lua index 246e7378..91e07052 100644 --- a/contrib/passport_guide.lua +++ b/contrib/passport_guide.lua @@ -41,8 +41,6 @@ local gettext = dt.gettext.gettext du.check_min_api_version("2.0.0", "passport_guide") -dt.gettext.bindtextdomain("passport_guide", dt.configuration.config_dir .."/lua/locale/") - local function _(msgid) return gettext(msgid) end diff --git a/contrib/passport_guide_germany.lua b/contrib/passport_guide_germany.lua index 735c092a..9b34d0b1 100644 --- a/contrib/passport_guide_germany.lua +++ b/contrib/passport_guide_germany.lua @@ -45,8 +45,6 @@ local gettext = dt.gettext du.check_min_api_version("2.0.0", "passport_guide_germany") -- Tell gettext where to find the .mo file translating messages for a particular domain -dt.gettext.bindtextdomain("passport_guide_germany",dt.configuration.config_dir.."/lua/locale/") - local function _(msgid) return gettext.dgettext("passport_guide_germany", msgid) end diff --git a/contrib/pdf_slideshow.lua b/contrib/pdf_slideshow.lua index 911493f8..36b0b1b8 100644 --- a/contrib/pdf_slideshow.lua +++ b/contrib/pdf_slideshow.lua @@ -44,8 +44,6 @@ local df = require "lib/dtutils.file" local gettext = dt.gettext.gettext -dt.gettext.bindtextdomain("pdf_slideshow", dt.configuration.config_dir .."/lua/locale/") - local function _(msgid) return gettext(msgid) end diff --git a/contrib/photils.lua b/contrib/photils.lua index b06dc6ef..35209401 100644 --- a/contrib/photils.lua +++ b/contrib/photils.lua @@ -45,7 +45,6 @@ local MODULE_NAME = "photils" du.check_min_api_version("7.0.0", MODULE_NAME) local gettext = dt.gettext.gettext -dt.gettext.bindtextdomain("photils", dt.configuration.config_dir .."/lua/locale/") local function _(msgid) return gettext(msgid) @@ -339,7 +338,7 @@ function PHOTILS.on_tags_clicked() end if #PHOTILS.tags == 0 then - local msg = string.format(_("no tags where found"), MODULE_NAME) + local msg = string.format(_("no tags were found"), MODULE_NAME) GUI.warning_label.label = msg GUI.stack.active = GUI.error_view return @@ -394,7 +393,7 @@ end local function install_module() if not PHOTILS.module_installed then dt.register_lib(MODULE_NAME, - "photils autotagger", + _("photils autotagger"), true, true, PHOTILS.plugin_display_views, diff --git a/contrib/quicktag.lua b/contrib/quicktag.lua index 7a17fa1b..7dd604da 100644 --- a/contrib/quicktag.lua +++ b/contrib/quicktag.lua @@ -51,8 +51,6 @@ du.check_min_api_version("7.0.0", "quicktag") local gettext = dt.gettext.gettext -dt.gettext.bindtextdomain("quicktag", dt.configuration.config_dir .."/lua/locale/") - local function _(msgid) return gettext(msgid) end @@ -199,7 +197,7 @@ local function install_module() if not qt.module_installed then dt.register_lib( "quicktag", -- Module name - "quicktag", -- name + _("quick tag"), -- name true, -- expandable false, -- resetable {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 490}}, @@ -306,7 +304,7 @@ end for i=1,qnr do dt.register_event("quicktag " .. tostring(i), "shortcut", function(event, shortcut) tagattach(tostring(quicktag_table[i])) end, - string.format(_("quicktag %i"),i)) + string.format(_("quick tag %i"),i)) end script_data.destroy = destroy diff --git a/contrib/rate_group.lua b/contrib/rate_group.lua index c75b504d..8c3a15d3 100644 --- a/contrib/rate_group.lua +++ b/contrib/rate_group.lua @@ -46,8 +46,6 @@ du.check_min_api_version("7.0.0", "rate_group") local gettext = dt.gettext.gettext -dt.gettext.bindtextdomain("rate_group", dt.configuration.config_dir .."/lua/locale/") - local function _(msgid) return gettext(msgid) end diff --git a/contrib/rename-tags.lua b/contrib/rename-tags.lua index 3b84eba6..69509a53 100644 --- a/contrib/rename-tags.lua +++ b/contrib/rename-tags.lua @@ -38,8 +38,6 @@ du.deprecated("contrib/rename-tags.lua","darktable release 4.0") local gettext = darktable.gettext.gettext -darktable.gettext.bindtextdomain("rename-tags", darktable.configuration.config_dir .."/lua/locale/") - local function _(msgid) return gettext(msgid) end diff --git a/contrib/rename_images.lua b/contrib/rename_images.lua index c0132adb..d50c8e18 100644 --- a/contrib/rename_images.lua +++ b/contrib/rename_images.lua @@ -49,8 +49,6 @@ du.check_min_api_version("7.0.0", "rename_images") local gettext = dt.gettext.gettext -dt.gettext.bindtextdomain("rename_images", dt.configuration.config_dir .."/lua/locale/") - local function _(msgid) return gettext(msgid) end diff --git a/contrib/select_non_existing.lua b/contrib/select_non_existing.lua index f691589a..d7bfa641 100644 --- a/contrib/select_non_existing.lua +++ b/contrib/select_non_existing.lua @@ -31,8 +31,6 @@ local PS = dt.configuration.running_os == "windows" and "\\" or "/" local gettext = dt.gettext.gettext -dt.gettext.bindtextdomain("select_non_existing", dt.configuration.config_dir .."/lua/locale/") - local function _(msgid) return gettext(msgid) end diff --git a/contrib/select_untagged.lua b/contrib/select_untagged.lua index 2aef97e8..c86cf831 100644 --- a/contrib/select_untagged.lua +++ b/contrib/select_untagged.lua @@ -24,8 +24,6 @@ local gettext = dt.gettext.gettext du.check_min_api_version("7.0.0", "select_untagged") -dt.gettext.bindtextdomain("select_untagged", dt.configuration.config_dir .."/lua/locale/") - local function _(msgid) return gettext(msgid) end diff --git a/contrib/slideshowMusic.lua b/contrib/slideshowMusic.lua index c5b9d8ce..d83dd248 100644 --- a/contrib/slideshowMusic.lua +++ b/contrib/slideshowMusic.lua @@ -31,8 +31,6 @@ local gettext = dt.gettext.gettext du.check_min_api_version("7.0.0", "slideshowMusic") -dt.gettext.bindtextdomain("slideshowMusic", dt.configuration.config_dir .."/lua/locale/") - local function _(msgid) return gettext(msgid) end diff --git a/contrib/transfer_hierarchy.lua b/contrib/transfer_hierarchy.lua index b73b38a9..465b4f7e 100755 --- a/contrib/transfer_hierarchy.lua +++ b/contrib/transfer_hierarchy.lua @@ -80,8 +80,6 @@ local dtutils_system = require("lib/dtutils.system") local LIB_ID = "transfer_hierarchy" dtutils.check_min_api_version("7.0.0", LIB_ID) -darktable.gettext.bindtextdomain("transfer_hierarchy", darktable.configuration.config_dir .."/lua/locale/") - local function _(msgid) return darktable.gettext.gettext(msgid) end @@ -145,7 +143,7 @@ end local function install_module() if not th.module_installed then darktable.register_lib(LIB_ID, - "transfer hierarchy", true, true, { + _("transfer hierarchy"), true, true, { [darktable.gui.views.lighttable] = { "DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 700 } }, th.transfer_widget, nil, nil) th.module_installed = true diff --git a/contrib/video_ffmpeg.lua b/contrib/video_ffmpeg.lua index 4203188e..68d0af30 100644 --- a/contrib/video_ffmpeg.lua +++ b/contrib/video_ffmpeg.lua @@ -41,8 +41,6 @@ local gettext = dt.gettext.gettext du.check_min_api_version("7.0.0", "video_ffmpeg") -dt.gettext.bindtextdomain("video_ffmpeg", dt.configuration.config_dir .."/lua/locale/") - local function _(msgid) return gettext(msgid) end @@ -248,8 +246,8 @@ local function string_pref_write(name, widget_attribute) end local framerates_selector = dt.new_widget("combobox"){ - label = _("framerate"), - tooltip = _("select framerate of output video"), + label = _("frame rate"), + tooltip = _("select frame rate of output video"), value = combobox_pref_read("framerate", framerates), changed_callback = combobox_pref_write("framerate"), table.unpack(framerates) @@ -418,7 +416,7 @@ local function export(extra_data) local ffmpeg_path = df.check_if_bin_exists("ffmpeg") if not ffmpeg_path then dt.print_error("ffmpeg not found") - dt.print("ERROR - ffmpeg not found") + dt.print(_("ERROR - ffmpeg not found")) return end local dir = extra_data["tmp_dir"] @@ -450,7 +448,7 @@ local function finalize_export(storage, images_table, extra_data) dt.print_error(filename, file.filename) df.file_move(filename, tmp_dir .. PS .. i .. extra_data["img_ext"]) end - dt.print("Start video building...") + dt.print(_("Start video building...")) local result, path = export(extra_data) if result ~= 0 then dt.print(_("ERROR: cannot build image, see console for more info")) From 36a6a54364fc96de015613795d471ccaa29e4d45 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Tue, 17 Sep 2024 18:29:05 -0400 Subject: [PATCH 354/445] official/apply_camera_string - clean up translatable strings --- official/apply_camera_style.lua | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/official/apply_camera_style.lua b/official/apply_camera_style.lua index 963586af..a72c8217 100644 --- a/official/apply_camera_style.lua +++ b/official/apply_camera_style.lua @@ -463,16 +463,18 @@ script_data.destroy = destroy -- E V E N T S -- - - - - - - - - - - - - - - - - - - - - - - - +local shortcut_string = _("apply darktable camera styles to %s") + dt.register_event(MODULE, "shortcut", function(event, shortcut) apply_camera_style(true) - end, _("apply darktable camera styles to collection") + end, string.format(shortcut_string, _("collection")) ) dt.register_event(MODULE, "shortcut", function(event, shortcut) apply_camera_style(false) - end, _("apply darktable camera styles to selection") + end, string.format(shortcut_string, _("selection")) ) dt.register_event(MODULE, "post-import-image", From f6cb8091e7d736a516192661dc577db81b2bc75b Mon Sep 17 00:00:00 2001 From: Krzysztof Kotowicz Date: Fri, 20 Sep 2024 15:07:37 +0200 Subject: [PATCH 355/445] Fix types in examples/gui_action script. --- examples/gui_action.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/gui_action.lua b/examples/gui_action.lua index 3bff94b6..66c5a811 100644 --- a/examples/gui_action.lua +++ b/examples/gui_action.lua @@ -115,7 +115,7 @@ dt.register_lib( clicked_callback = function(_) local sp = NaN if wg.check.value then sp = wg.speed.text end - wg.return_value.text = dt.gui.action(wg.action.text, wg.instance.value, wg.element.text, wg.effect.text, sp) + wg.return_value.text = dt.gui.action(wg.action.text, tonumber(wg.instance.value), wg.element.text, wg.effect.text, tonumber(sp)) end }, dt.new_widget("box") From d754e37cf43c569d9cd833ed8919168a945800be Mon Sep 17 00:00:00 2001 From: Krzysztof Kotowicz Date: Mon, 23 Sep 2024 10:42:31 +0200 Subject: [PATCH 356/445] Properly sanitize filenames in dtutils.file file_copy and file_move. --- lib/dtutils/file.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/dtutils/file.lua b/lib/dtutils/file.lua index e33fa5aa..a4599297 100644 --- a/lib/dtutils/file.lua +++ b/lib/dtutils/file.lua @@ -522,9 +522,9 @@ function dtutils_file.file_copy(fromFile, toFile) local result = nil -- if cp exists, use it if dt.configuration.running_os == "windows" then - result = os.execute('copy "' .. fromFile .. '" "' .. toFile .. '"') + result = os.execute('copy ' .. dtutils_file.sanitize_filename(fromFile) .. ' ' .. dtutils_file.sanitize_filename(toFile)) elseif dtutils_file.check_if_bin_exists("cp") then - result = os.execute("cp '" .. fromFile .. "' '" .. toFile .. "'") + result = os.execute("cp " .. dtutils_file.sanitize_filename(fromFile) .. ' ' .. dtutils_file.sanitize_filename(toFile)) end -- if cp was not present, or if cp failed, then a pure lua solution @@ -575,7 +575,7 @@ function dtutils_file.file_move(fromFile, toFile) if not success then -- an error occurred, so let's try using the operating system function if dtutils_file.check_if_bin_exists("mv") then - success = os.execute("mv '" .. fromFile .. "' '" .. toFile .. "'") + success = os.execute("mv " .. dtutils_file.sanitize_filename(fromFile) .. ' ' .. dtutils_file.sanitize_filename(toFile)) end -- if the mv didn't exist or succeed, then... if not success then From 64840089e97547a4dd1d9490efc696b9bcd92b52 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sat, 12 Oct 2024 20:28:01 -0400 Subject: [PATCH 357/445] clean up a few issues with parentheses and missed strings. --- contrib/geoJSON_export.lua | 2 +- contrib/hif_group_leader.lua | 4 ++-- contrib/hugin.lua | 2 +- contrib/jpg_group_leader.lua | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/contrib/geoJSON_export.lua b/contrib/geoJSON_export.lua index aff04b22..93ecd9ff 100644 --- a/contrib/geoJSON_export.lua +++ b/contrib/geoJSON_export.lua @@ -293,7 +293,7 @@ local function create_geoJSON_file(storage, image_table, extra_data) file:write(geoJSON_file) file:close() - dt.print(string.format(_("%s file created in %s", "geoJSON", exportDirectory))) + dt.print(string.format(_("%s file created in %s"), "geoJSON", exportDirectory)) -- Open the file with the standard programm if ( dt.preferences.read("geoJSON_export","OpengeoJSONFile","bool") == true ) then diff --git a/contrib/hif_group_leader.lua b/contrib/hif_group_leader.lua index 2252f967..9543becb 100644 --- a/contrib/hif_group_leader.lua +++ b/contrib/hif_group_leader.lua @@ -186,7 +186,7 @@ dt.register_event(MODULE .. "_collect", "shortcut", local images = dt.collection make_existing_hif_group_leader(images) end, - string.format(_("make hif group leader for %s", "collection")) + string.format(_("make hif group leader for %s", _("collection"))) ) dt.register_event(MODULE .. "_select", "shortcut", @@ -194,7 +194,7 @@ dt.register_event(MODULE .. "_select", "shortcut", local images = dt.gui.selection() make_existing_hif_group_leader(images) end, - string.format(_("make hif group leader for %s", "selection")) + string.format(_("make hif group leader for %s", _("selection"))) ) return script_data \ No newline at end of file diff --git a/contrib/hugin.lua b/contrib/hugin.lua index 12849168..49868424 100644 --- a/contrib/hugin.lua +++ b/contrib/hugin.lua @@ -83,7 +83,7 @@ end local function show_status(storage, image, format, filename, number, total, high_quality, extra_data) - dt.print(string.format(_("exporting to hugin: %d / $d", number, total))) + dt.print(string.format(_("exporting to hugin: %d / $d"), number, total)) end local function create_panorama(storage, image_table, extra_data) --finalize diff --git a/contrib/jpg_group_leader.lua b/contrib/jpg_group_leader.lua index ef7cf910..7ca1359b 100644 --- a/contrib/jpg_group_leader.lua +++ b/contrib/jpg_group_leader.lua @@ -186,7 +186,7 @@ dt.register_event(MODULE .. "_collect", "shortcut", local images = dt.collection make_existing_jpg_group_leader(images) end, - string.format(_("make jpg group leader for %s", "collection")) + string.format(_("make jpg group leader for %s", _("collection"))) ) dt.register_event(MODULE .. "_select", "shortcut", @@ -194,7 +194,7 @@ dt.register_event(MODULE .. "_select", "shortcut", local images = dt.gui.selection() make_existing_jpg_group_leader(images) end, - string.format(_("make jpg group leader for %s", "selection")) + string.format(_("make jpg group leader for %s", _("selection"))) ) return script_data \ No newline at end of file From 0e535b850c6c7423451f3e1535d4c87b45a0aef7 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sat, 12 Oct 2024 20:41:02 -0400 Subject: [PATCH 358/445] Incorporated TurboGit's suggestions --- contrib/photils.lua | 2 +- contrib/video_ffmpeg.lua | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/contrib/photils.lua b/contrib/photils.lua index 35209401..a5fe59be 100644 --- a/contrib/photils.lua +++ b/contrib/photils.lua @@ -393,7 +393,7 @@ end local function install_module() if not PHOTILS.module_installed then dt.register_lib(MODULE_NAME, - _("photils autotagger"), + _("photils auto-tagger"), true, true, PHOTILS.plugin_display_views, diff --git a/contrib/video_ffmpeg.lua b/contrib/video_ffmpeg.lua index 68d0af30..70af1efe 100644 --- a/contrib/video_ffmpeg.lua +++ b/contrib/video_ffmpeg.lua @@ -448,7 +448,7 @@ local function finalize_export(storage, images_table, extra_data) dt.print_error(filename, file.filename) df.file_move(filename, tmp_dir .. PS .. i .. extra_data["img_ext"]) end - dt.print(_("Start video building...")) + dt.print(_("start video building...")) local result, path = export(extra_data) if result ~= 0 then dt.print(_("ERROR: cannot build image, see console for more info")) From da7674ca5175ac1ac3f2e8c2a3a5992c38b5359f Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Mon, 14 Oct 2024 12:54:13 -0400 Subject: [PATCH 359/445] lib/dtutils/string - updated tooltip to use same translatable strings as gui/gtkentry.c for consistency and eas of translation --- lib/dtutils/string.lua | 172 ++++++++++++++++++++++------------------- 1 file changed, 91 insertions(+), 81 deletions(-) diff --git a/lib/dtutils/string.lua b/lib/dtutils/string.lua index b1718b39..8432dc35 100644 --- a/lib/dtutils/string.lua +++ b/lib/dtutils/string.lua @@ -589,9 +589,9 @@ local PLACEHOLDERS = {"ROLL.NAME", "RATING.ICONS", -- Not Implemented "LABELS", "LABELS.ICONS", -- Not Implemented - "MAKER", - "MODEL", - "LENS", + "EXIF.MAKER", + "EXIF.MODEL", + "EXIF.LENS", "TITLE", "DESCRIPTION", "CREATOR", @@ -834,84 +834,94 @@ dtutils_string.libdoc.functions["get_substitution_tooltip"] = { } function dtutils_string.get_substitution_tooltip() - return string.format("$(ROLL.NAME) - %s\n", _("film roll of the input image")) .. - string.format("$(FILE.FOLDER) - %s\n", _("folder containing the input image")) .. - string.format("$(FILE.NAME) - %s\n", _("basename of the input image")) .. - string.format("$(FILE.EXTENSION) - %s\n", _("extension of the input image")) .. - string.format("$(ID) - %s\n", _("the image id")) .. - string.format("$(VERSION) - %s\n", _("the duplicate version number")) .. - string.format("$(VERSION.IF.MULTI) - %s\n", _("same as $(VERSION) but null string if only one version exists")) .. - string.format("$(VERSION.NAME) - %s\n", _("version name from metadata")) .. - string.format("$(DARKTABLE.VERSION) - %s\n", _("the version of the running darktable instance")) .. - --string.format("$(DARKTABLE.NAME) - %s\n", _("")) .. -- Not Implemented - string.format("$(SEQUENCE[n,m]) - %s\n", _("a sequence number within an export job with n digits and starting with m\nparameters are optional, default is [4,1]")) .. - string.format("$(WIDTH.SENSOR) - %s\n", _("width of RAW data in pixels before RAW crop")) .. - string.format("$(HEIGHT.SENSOR) - %s\n", _("height of RAW data in pixels before RAW crop")) .. - string.format("$(WIDTH.RAW) - %s\n", _("width of RAW data in pixels after RAW crop")) .. - string.format("$(HEIGHT.RAW) - %s\n", _("height of RAW data in pixels after RAW crop")) .. - string.format("$(WIDTH.CROP) - %s\n", _("image width in pixels at the end of the pixelpipe, but before export resize")) .. - string.format("$(HEIGHT.CROP) - %s\n", _("image height in pixels at the end of the pixelpipe, but before export resize")) .. - string.format("$(WIDTH.EXPORT) - %s\n", _("image width in pixels at the end of the pixelpipe and after export resize")) .. - string.format("$(HEIGHT.EXPORT) - %s\n", _("image height in pixels at the end of the pixelpipe and after export resize")) .. - --string.format("$(WIDTH.MAX) - %s\n", _("")) .. -- Not Implemented - --string.format("$(HEIGHT.MAX) - %s\n", _("")) .. -- Not Implemented - string.format("$(YEAR) - %s\n", _("current year")) .. - string.format("$(YEAR.SHORT) - %s\n", _("current two digit year")) .. - string.format("$(MONTH) - %s\n", _("current numeric (1-12) month")) .. - string.format("$(MONTH.LONG) - %s\n", _("full current month name")) .. - string.format("$(MONTH.SHORT) - %s\n", _("abbreviated current month name")) .. - string.format("$(DAY) - %s\n", _("current day")) .. - string.format("$(HOUR) - %s\n", _("current hour")) .. - string.format("$(MINUTE) - %s\n", _("current minute")) .. - string.format("$(SECOND) - %s\n", _("current second")) .. - string.format("$(MSEC) - %s\n", _("current millisecond")) .. - string.format("$(EXIF.YEAR) - EXIF %s\n", _("year")) .. - string.format("$(EXIF.YEAR.SHORT) - EXIF %s\n", _("year, two-digit version")) .. - string.format("$(EXIF.MONTH) - EXIF %s\n", _("month, numeric")) .. - string.format("$(EXIF.MONTH.LONG) - EXIF %s\n", _("month, full name")) .. - string.format("$(EXIF.MONTH.SHORT) - EXIF %s\n", _("month, abbreviated name")) .. - string.format("$(EXIF.DAY) - EXIF %s\n", _("day")) .. - string.format("$(EXIF.HOUR) - EXIF %s\n", _("hour")) .. - string.format("$(EXIF.MINUTE) - EXIF %s\n", _("minute")) .. - string.format("$(EXIF.SECOND) - EXIF %s\n", _("second")) .. - string.format("$(EXIF.MSEC) - EXIF %s\n", _("millisecond")) .. - --string.format("$(EXIF.DATE.REGIONAL) - %s\n", _("")) .. -- Not Implemented - --string.format("$(EXIF.TIME.REGIONAL) - %s\n", _("")) .. -- Not Implemented - string.format("$(EXIF.ISO) - EXIF ISO %s\n", _("value")) .. - string.format("$(EXIF.EXPOSURE) - EXIF %s\n", _("exposure")) .. - string.format("$(EXIF.EXPOSURE.BIAS) - EXIF %s\n", _("exposure bias")) .. - string.format("$(EXIF.APERTURE) - EXIF %s\n", _("aperture")) .. - string.format("$(EXIF.CROP.FACTOR) - EXIF %s\n", _("crop factor")) .. - string.format("$(EXIF.FOCAL.LENGTH) - EXIF %s\n", _("focal length")) .. - string.format("$(EXIF.FOCAL.LENGTH.EQUIV) - EXIF 35mm %s\n", _("equivalent focal length")) .. -- Not Implemented - string.format("$(EXIF.FOCUS.DISTANCE) - EXIF %s\n", _("focus distance")) .. - --string.format("$(IMAGE.EXIF) - %s\n", _("")) .. -- Not Implemented - string.format("$(LONGITUDE) - %s\n", _("longitude")) .. - string.format("$(LATITUDE) - %s\n", _("latitude")) .. - string.format("$(ELEVATION) - %s\n", _("elevation")) .. - --string.format("$(GPS.LOCATION) - %s\n", _("")) .. -- Not Implemented - string.format("$(STARS) - %s\n", _("star rating")) .. - --string.format("$(RATING.ICONS) - %s\n", _("")) .. -- Not Implemented - string.format("$(LABELS) - %s\n", _("colorlabels")) .. - --string.format("$(LABELS.ICONS) - %s\n", _("")) .. -- Not Implemented - string.format("$(MAKER) - %s\n", _("camera maker")) .. - string.format("$(MODEL) - %s\n", _("camera model")) .. - string.format("$(LENS) - %s\n", _("lens")) .. - string.format("$(TITLE) - %s\n", _("title from metadata")) .. - string.format("$(DESCRIPTION) - %s\n", _("description from metadata")) .. - string.format("$(CREATOR) - %s\n", _("creator from metadata")) .. - string.format("$(PUBLISHER) - %s\n", _("publisher from metadata")) .. - string.format("$(RIGHTS) - %s\n", _("rights from metadata")) .. - --string.format("$(TAGS) - %s\n", _("")) .. -- Not Implemented - string.format("$(CATEGORY[n,category]) - %s\n", _("tag name of level n [0,9] of selected category (or tag)")) .. - --string.format("$(SIDECAR.TXT) - %s\n", _("")) .. -- Not Implemented - string.format("$(FOLDER.PICTURES) - %s\n", _("pictures folder")) .. - string.format("$(FOLDER.HOME) - %s\n", _("home folder")) .. - string.format("$(FOLDER.DESKTOP) - %s\n", _("desktop folder")) .. - --string.format("$(OPENCL.ACTIVATED) - %s\n", _("")) .. -- Not Implemented - string.format("$(USERNAME) - %s\n", _("user name defined by OS")) - --string.format("$(NL) - %s\n", _("")) .. -- Not Implemented - --string.format("$(JOBCODE) - %s", _("")) -- Not Implemented + return _("$(ROLL.NAME) - roll of the input image") .. "\n" .. + _("$(FILE.FOLDER) - folder containing the input image") .. "\n" .. + _("$(FILE.NAME) - basename of the input image") .. "\n" .. + _("$(FILE.EXTENSION) - extension of the input image") .. "\n" .. + _("$(ID) - image ID") .. "\n" .. + _("$(VERSION) - duplicate version") .. "\n" .. + _("$(VERSION.IF_MULTI) - same as $(VERSION) but null string if only one version exists") .. "\n" .. + _("$(VERSION.NAME) - version name from metadata") .. "\n" .. + _("$(DARKTABLE.VERSION) - current darktable version") .. "\n" .. + -- _("$(DARKTABLE.NAME) - darktable name") .. "\n" .. -- not implemented + _("$(SEQUENCE[n,m]) - sequence number, n: number of digits, m: start number") .. "\n" .. + _("$(WIDTH.SENSOR) - image sensor width") .. "\n" .. + _("$(HEIGHT.SENSOR) - image sensor height") .. "\n" .. + _("$(WIDTH.RAW) - RAW image width") .. "\n" .. + _("$(HEIGHT.RAW) - RAW image height") .. "\n" .. + _("$(WIDTH.CROP) - image width after crop") .. "\n" .. + _("$(HEIGHT.CROP) - image height after crop") .. "\n" .. + _("$(WIDTH.EXPORT) - exported image width") .. "\n" .. + _("$(HEIGHT.EXPORT) - exported image height") .. "\n" .. + -- _("$(WIDTH.MAX) - maximum image export width") .. "\n" .. -- not implemented + -- _("$(HEIGHT.MAX) - maximum image export height") .. "\n" .. -- not implemented + _("$(YEAR) - year") .. "\n" .. + _("$(YEAR.SHORT) - year without century") .. "\n" .. + _("$(MONTH) - month") .. "\n" .. + _("$(MONTH.LONG) - full month name according to the current locale") .. "\n" .. + _("$(MONTH.SHORT) - abbreviated month name according to the current locale") .. "\n" .. + _("$(DAY) - day") .. "\n" .. + _("$(HOUR) - hour") .. "\n" .. + -- _("$(HOUR.AMPM) - hour, 12-hour clock") .. "\n" .. -- not implemented + _("$(MINUTE) - minute") .. "\n" .. + _("$(SECOND) - second") .. "\n" .. + _("$(MSEC) - millisecond") .. "\n" .. + _("$(EXIF.YEAR) - EXIF year") .. "\n" .. + _("$(EXIF.YEAR.SHORT) - EXIF year without century") .. "\n" .. + _("$(EXIF.MONTH) - EXIF month") .. "\n" .. + _("$(EXIF.MONTH.LONG) - full EXIF month name according to the current locale") .. "\n" .. + _("$(EXIF.MONTH.SHORT) - abbreviated EXIF month name according to the current locale") .. "\n" .. + _("$(EXIF.DAY) - EXIF day") .. "\n" .. + _("$(EXIF.HOUR) - EXIF hour") .. "\n" .. + -- _("$(EXIF.HOUR.AMPM) - EXIF hour, 12-hour clock") .. "\n" .. -- not implemented + _("$(EXIF.MINUTE) - EXIF minute") .. "\n" .. + _("$(EXIF.SECOND) - EXIF second") .. "\n" .. + _("$(EXIF.MSEC) - EXIF millisecond") .. "\n" .. + -- _("$(EXIF.DATE.REGIONAL) - localized EXIF date") .. "\n" .. -- not implemented + -- _("$(EXIF.TIME.REGIONAL) - localized EXIF time") .. "\n" .. -- not implemented + _("$(EXIF.ISO) - ISO value") .. "\n" .. + _("$(EXIF.EXPOSURE) - EXIF exposure") .. "\n" .. + _("$(EXIF.EXPOSURE.BIAS) - EXIF exposure bias") .. "\n" .. + -- _("$(EXIF.EXPOSURE.PROGRAM) - EXIF exposure program") .. "\n" .. -- not implemented + _("$(EXIF.APERTURE) - EXIF aperture") .. "\n" .. + _("$(EXIF.CROP_FACTOR) - EXIF crop factor") .. "\n" .. + _("$(EXIF.FOCAL.LENGTH) - EXIF focal length") .. "\n" .. + _("$(EXIF.FOCAL.LENGTH.EQUIV) - EXIF 35 mm equivalent focal length") .. "\n" .. + _("$(EXIF.FOCUS.DISTANCE) - EXIF focal distance") .. "\n" .. + _("$(EXIF.MAKER) - camera maker") .. + _("$(EXIF.MODEL) - camera model") .. + -- _("$(EXIF.WHITEBALANCE) - EXIF selected white balance") .. -- not implemented + -- _("$(EXIF.METERING) - EXIF exposure metering mode") .. -- not implemented + _("$(EXIF.LENS) - lens") .. + -- _("$(EXIF.FLASH.ICON) - icon indicating whether flash was used") .. -- not implemented + -- _("$(EXIF.FLASH) - was flash used (yes/no/--)") .. -- not implemented + -- _("$(GPS.LONGITUDE) - longitude") .. "\n" ..-- not implemented + -- _("$(GPS.LATITUDE) - latitude") .. "\n" ..-- not implemented + -- _("$(GPS.ELEVATION) - elevation") .. "\n" ..-- not implemented + -- _("$(GPS.LOCATION.ICON) - icon indicating whether GPS location is known") .. "\n" ..-- not implemented + _("$(LONGITUDE) - longitude") .. "\n" .. + _("$(LATITUDE) - latitude") .. "\n" .. + _("$(ELEVATION) - elevation") .. "\n" .. + _("$(STARS) - star rating as number (-1 for rejected)") .. "\n" .. + -- _("$(RATING.ICONS) - star/reject rating in icon form") .. "\n" ..-- not implemented + _("$(LABELS) - color labels as text") .. "\n" .. + -- _("$(LABELS.ICONS) - color labels as icons") .. "\n" ..-- not implemented + _("$(TITLE) - title from metadata") .. "\n" .. + _("$(DESCRIPTION) - description from metadata") .. "\n" .. + _("$(CREATOR) - creator from metadata") .. "\n" .. + _("$(PUBLISHER) - publisher from metadata") .. "\n" .. + _("$(RIGHTS) - rights from metadata") .. "\n" .. + --_("$(TAGS) - tags as set in metadata settings") .. "\n" .. + _("$(CATEGORY[n,category]) - subtag of level n in hierarchical tags") .. "\n" .. + _("$(SIDECAR_TXT) - contents of .txt sidecar file, if present") .. "\n" .. + _("$(FOLDER.PICTURES) - pictures folder") .. "\n" .. + _("$(FOLDER.HOME) - home folder") .. "\n" .. + _("$(FOLDER.DESKTOP) - desktop folder") .. "\n" .. + -- _("$(OPENCL.ACTIVATED) - whether OpenCL is activated") .. "\n" .. + _("$(USERNAME) - login name") .. "\n" .. + -- _("$(NL) - newline") .. "\n" .. + -- _("$(JOBCODE) - job code for import") .. "\n" .. + "" end -- handle different versions of names From a835ab89bcaf25fc1e1078472a4cb6e3906195a6 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Wed, 16 Oct 2024 00:42:08 -0400 Subject: [PATCH 360/445] lib/dtutils/string - added new variable. Removed invalid variables. Fixed build_substitute list call. Fixed invalid category return. --- lib/dtutils/string.lua | 209 +++++++++++++++++++++++------------------ 1 file changed, 117 insertions(+), 92 deletions(-) diff --git a/lib/dtutils/string.lua b/lib/dtutils/string.lua index 8432dc35..e85d5866 100644 --- a/lib/dtutils/string.lua +++ b/lib/dtutils/string.lua @@ -557,6 +557,7 @@ local PLACEHOLDERS = {"ROLL.NAME", "MONTH.SHORT", "DAY", "HOUR", + "HOUR.AMPM", -- Not Implemented "MINUTE", "SECOND", "MSEC", @@ -567,6 +568,7 @@ local PLACEHOLDERS = {"ROLL.NAME", "EXIF.MONTH.SHORT", "EXIF.DAY", "EXIF.HOUR", + "EXIF.HOUR.AMPM", -- Not Implemented "EXIF.MINUTE", "EXIF.SECOND", "EXIF.MSEC", @@ -575,12 +577,23 @@ local PLACEHOLDERS = {"ROLL.NAME", "EXIF.ISO", "EXIF.EXPOSURE", "EXIF.EXPOSURE.BIAS", + "EXIF.EXPOSURE.PROGRAM", -- Not Implemented "EXIF.APERTURE", "EXIF.CROP.FACTOR", "EXIF.FOCAL.LENGTH", "EXIF.FOCAL.LENGTH.EQUIV", -- Not Implemented "EXIF.FOCUS.DISTANCE", - "IMAGE.EXIF", -- Not Implemented + "EXIF.MAKER", + "EXIF.MODEL", + "EXIF.WHTIEBALANCE", -- Not Implemented + "EXIF.METERING", -- Not Implemented + "EXIF.LENS", + "EXIF.FLASH.ICON", -- Not Implemented + "EXIF.FLASH", -- Not Implemented + "GPS.LONGITUDE", -- Not Implemented + "GPS.LATITUDE", -- Not Implemented + "GPS.ELEVATION", -- Not Implemented + "GPS.LOCATION.ICON", -- Not Implemented "LONGITUDE", "LATITUDE", "ELEVATION", @@ -589,9 +602,6 @@ local PLACEHOLDERS = {"ROLL.NAME", "RATING.ICONS", -- Not Implemented "LABELS", "LABELS.ICONS", -- Not Implemented - "EXIF.MAKER", - "EXIF.MODEL", - "EXIF.LENS", "TITLE", "DESCRIPTION", "CREATOR", @@ -692,7 +702,7 @@ end -- build the argument substitution list from each image -function dtutils_string.build_substitution_list(image, sequence, variable_string, username, pic_folder, home, desktop) +function dtutils_string.build_substitute_list(image, sequence, variable_string, username, pic_folder, home, desktop) local old_log_level = log.log_level() log.log_level(dtutils_string.log_level) @@ -703,6 +713,8 @@ function dtutils_string.build_substitution_list(image, sequence, variable_string is_api_9_1 = false end + local is_api_9_4 = dt.configuration.api_version_string >= "9.4.0" and true or false + local datetime = os.date("*t") local long_month = os.date("%B") local short_month = os.date("%b") @@ -753,6 +765,7 @@ function dtutils_string.build_substitution_list(image, sequence, variable_string short_month, -- MONTH.SHORT string.format("%02d", datetime.day), -- DAY string.format("%02d", datetime.hour), -- HOUR + "", -- HOUR.AMPM string.format("%02d", datetime.min), -- MINUTE string.format("%02d", datetime.sec), -- SECOND 0, -- MSEC @@ -763,6 +776,7 @@ function dtutils_string.build_substitution_list(image, sequence, variable_string os.date("%b", exiftime2systime(image.exif_datetime_taken)), -- EXIF.MONTH.SHORT eday, -- EXIF.DAY ehour, -- EXIF.HOUR + "", -- EXIF.HOUR.AMPM emin, -- EXIF.MINUTE esec, -- EXIF.SECOND emsec, -- EXIF.MSEC @@ -771,12 +785,23 @@ function dtutils_string.build_substitution_list(image, sequence, variable_string string.format("%d", image.exif_iso), -- EXIF.ISO string.format("%.0f", 1./image.exif_exposure), -- EXIF.EXPOSURE image.exif_exposure_bias, -- EXIF.EXPOSURE.BIAS + "", -- EXIF.EXPOSURE.PROGRAM string.format("%.01f", image.exif_aperture), -- EXIF.APERTURE string.format("%.01f", image.exif_crop),-- EXIF.CROP_FACTOR string.format("%.0f", image.exif_focal_length), -- EXIF.FOCAL.LENGTH string.format("%.0f", image.exif_focal_length * image.exif_crop), -- EXIF.FOCAL.LENGTH.EQUIV image.exif_focus_distance, -- EXIF.FOCUS.DISTANCE - "", -- IMAGE.EXIF + image.exif_maker, -- EXIF.MAKER + image.exif_model, -- EXIF.MODEL + is_api_9_4 and image.exif_whitebalance or "", -- EXIF.WHITEBALANCE + is_api_9_4 and image.exif_metering_mode or "", -- EXIF.METERING + image.exif_lens, -- LENS + "", -- EXIF.FLASH.ICON + is_api_9_4 and image.exif_flash or "", -- EXIF.FLASH + "", -- GPS.LONGITUDE + "", -- GPS.LATITUDE + "", -- GPS.ELEVATION + "", -- GPS.LOCATION.ICON image.longitude or "", -- LONGITUDE image.latitude or "", -- LATITUDE image.elevation or "", -- ELEVATION @@ -785,9 +810,6 @@ function dtutils_string.build_substitution_list(image, sequence, variable_string "", -- RATING.ICONS - wont be implemented labels, -- LABELS "", -- LABELS.ICONS - wont be implemented - image.exif_maker, -- MAKER - image.exif_model, -- MODEL - image.exif_lens, -- LENS image.title, -- TITLE image.description, -- DESCRIPTION image.creator, -- CREATOR @@ -834,94 +856,96 @@ dtutils_string.libdoc.functions["get_substitution_tooltip"] = { } function dtutils_string.get_substitution_tooltip() - return _("$(ROLL.NAME) - roll of the input image") .. "\n" .. - _("$(FILE.FOLDER) - folder containing the input image") .. "\n" .. - _("$(FILE.NAME) - basename of the input image") .. "\n" .. - _("$(FILE.EXTENSION) - extension of the input image") .. "\n" .. - _("$(ID) - image ID") .. "\n" .. - _("$(VERSION) - duplicate version") .. "\n" .. - _("$(VERSION.IF_MULTI) - same as $(VERSION) but null string if only one version exists") .. "\n" .. - _("$(VERSION.NAME) - version name from metadata") .. "\n" .. - _("$(DARKTABLE.VERSION) - current darktable version") .. "\n" .. - -- _("$(DARKTABLE.NAME) - darktable name") .. "\n" .. -- not implemented - _("$(SEQUENCE[n,m]) - sequence number, n: number of digits, m: start number") .. "\n" .. - _("$(WIDTH.SENSOR) - image sensor width") .. "\n" .. - _("$(HEIGHT.SENSOR) - image sensor height") .. "\n" .. - _("$(WIDTH.RAW) - RAW image width") .. "\n" .. - _("$(HEIGHT.RAW) - RAW image height") .. "\n" .. - _("$(WIDTH.CROP) - image width after crop") .. "\n" .. - _("$(HEIGHT.CROP) - image height after crop") .. "\n" .. - _("$(WIDTH.EXPORT) - exported image width") .. "\n" .. - _("$(HEIGHT.EXPORT) - exported image height") .. "\n" .. - -- _("$(WIDTH.MAX) - maximum image export width") .. "\n" .. -- not implemented - -- _("$(HEIGHT.MAX) - maximum image export height") .. "\n" .. -- not implemented - _("$(YEAR) - year") .. "\n" .. - _("$(YEAR.SHORT) - year without century") .. "\n" .. - _("$(MONTH) - month") .. "\n" .. - _("$(MONTH.LONG) - full month name according to the current locale") .. "\n" .. - _("$(MONTH.SHORT) - abbreviated month name according to the current locale") .. "\n" .. - _("$(DAY) - day") .. "\n" .. - _("$(HOUR) - hour") .. "\n" .. - -- _("$(HOUR.AMPM) - hour, 12-hour clock") .. "\n" .. -- not implemented - _("$(MINUTE) - minute") .. "\n" .. - _("$(SECOND) - second") .. "\n" .. - _("$(MSEC) - millisecond") .. "\n" .. - _("$(EXIF.YEAR) - EXIF year") .. "\n" .. - _("$(EXIF.YEAR.SHORT) - EXIF year without century") .. "\n" .. - _("$(EXIF.MONTH) - EXIF month") .. "\n" .. - _("$(EXIF.MONTH.LONG) - full EXIF month name according to the current locale") .. "\n" .. - _("$(EXIF.MONTH.SHORT) - abbreviated EXIF month name according to the current locale") .. "\n" .. - _("$(EXIF.DAY) - EXIF day") .. "\n" .. - _("$(EXIF.HOUR) - EXIF hour") .. "\n" .. + + return table.concat({ + _("$(ROLL.NAME) - roll of the input image"), + _("$(FILE.FOLDER) - folder containing the input image"), + _("$(FILE.NAME) - basename of the input image"), + _("$(FILE.EXTENSION) - extension of the input image"), + _("$(ID) - image ID"), + _("$(VERSION) - duplicate version"), + _("$(VERSION.IF_MULTI) - same as $(VERSION) but null string if only one version exists"), + _("$(VERSION.NAME) - version name from metadata"), + _("$(DARKTABLE.VERSION) - current darktable version"), + -- _("$(DARKTABLE.NAME) - darktable name"), -- not implemented + _("$(SEQUENCE[n,m]) - sequence number, n: number of digits, m: start number"), + _("$(WIDTH.SENSOR) - image sensor width"), + _("$(HEIGHT.SENSOR) - image sensor height"), + _("$(WIDTH.RAW) - RAW image width"), + _("$(HEIGHT.RAW) - RAW image height"), + _("$(WIDTH.CROP) - image width after crop"), + _("$(HEIGHT.CROP) - image height after crop"), + _("$(WIDTH.EXPORT) - exported image width"), + _("$(HEIGHT.EXPORT) - exported image height"), + -- _("$(WIDTH.MAX) - maximum image export width"), -- not implemented + -- _("$(HEIGHT.MAX) - maximum image export height"), -- not implemented + _("$(YEAR) - year"), + _("$(YEAR.SHORT) - year without century"), + _("$(MONTH) - month"), + _("$(MONTH.LONG) - full month name according to the current locale"), + _("$(MONTH.SHORT) - abbreviated month name according to the current locale"), + _("$(DAY) - day"), + _("$(HOUR) - hour"), + -- _("$(HOUR.AMPM) - hour, 12-hour clock"), -- not implemented + _("$(MINUTE) - minute"), + _("$(SECOND) - second"), + _("$(MSEC) - millisecond"), + _("$(EXIF.YEAR) - EXIF year"), + _("$(EXIF.YEAR.SHORT) - EXIF year without century"), + _("$(EXIF.MONTH) - EXIF month"), + _("$(EXIF.MONTH.LONG) - full EXIF month name according to the current locale"), + _("$(EXIF.MONTH.SHORT) - abbreviated EXIF month name according to the current locale"), + _("$(EXIF.DAY) - EXIF day"), + _("$(EXIF.HOUR) - EXIF hour"), -- _("$(EXIF.HOUR.AMPM) - EXIF hour, 12-hour clock") .. "\n" .. -- not implemented - _("$(EXIF.MINUTE) - EXIF minute") .. "\n" .. - _("$(EXIF.SECOND) - EXIF second") .. "\n" .. - _("$(EXIF.MSEC) - EXIF millisecond") .. "\n" .. - -- _("$(EXIF.DATE.REGIONAL) - localized EXIF date") .. "\n" .. -- not implemented - -- _("$(EXIF.TIME.REGIONAL) - localized EXIF time") .. "\n" .. -- not implemented - _("$(EXIF.ISO) - ISO value") .. "\n" .. - _("$(EXIF.EXPOSURE) - EXIF exposure") .. "\n" .. - _("$(EXIF.EXPOSURE.BIAS) - EXIF exposure bias") .. "\n" .. - -- _("$(EXIF.EXPOSURE.PROGRAM) - EXIF exposure program") .. "\n" .. -- not implemented - _("$(EXIF.APERTURE) - EXIF aperture") .. "\n" .. - _("$(EXIF.CROP_FACTOR) - EXIF crop factor") .. "\n" .. - _("$(EXIF.FOCAL.LENGTH) - EXIF focal length") .. "\n" .. - _("$(EXIF.FOCAL.LENGTH.EQUIV) - EXIF 35 mm equivalent focal length") .. "\n" .. - _("$(EXIF.FOCUS.DISTANCE) - EXIF focal distance") .. "\n" .. + _("$(EXIF.MINUTE) - EXIF minute"), + _("$(EXIF.SECOND) - EXIF second"), + _("$(EXIF.MSEC) - EXIF millisecond"), + -- _("$(EXIF.DATE.REGIONAL) - localized EXIF date"), -- not implemented + -- _("$(EXIF.TIME.REGIONAL) - localized EXIF time"), -- not implemented + _("$(EXIF.ISO) - ISO value"), + _("$(EXIF.EXPOSURE) - EXIF exposure"), + _("$(EXIF.EXPOSURE.BIAS) - EXIF exposure bias"), + -- _("$(EXIF.EXPOSURE.PROGRAM) - EXIF exposure program"), -- not implemented + _("$(EXIF.APERTURE) - EXIF aperture"), + _("$(EXIF.CROP_FACTOR) - EXIF crop factor"), + _("$(EXIF.FOCAL.LENGTH) - EXIF focal length"), + _("$(EXIF.FOCAL.LENGTH.EQUIV) - EXIF 35 mm equivalent focal length"), + _("$(EXIF.FOCUS.DISTANCE) - EXIF focal distance"), _("$(EXIF.MAKER) - camera maker") .. _("$(EXIF.MODEL) - camera model") .. - -- _("$(EXIF.WHITEBALANCE) - EXIF selected white balance") .. -- not implemented - -- _("$(EXIF.METERING) - EXIF exposure metering mode") .. -- not implemented + _("$(EXIF.WHITEBALANCE) - EXIF selected white balance") .. -- not implemented + _("$(EXIF.METERING) - EXIF exposure metering mode") .. -- not implemented _("$(EXIF.LENS) - lens") .. -- _("$(EXIF.FLASH.ICON) - icon indicating whether flash was used") .. -- not implemented - -- _("$(EXIF.FLASH) - was flash used (yes/no/--)") .. -- not implemented - -- _("$(GPS.LONGITUDE) - longitude") .. "\n" ..-- not implemented - -- _("$(GPS.LATITUDE) - latitude") .. "\n" ..-- not implemented - -- _("$(GPS.ELEVATION) - elevation") .. "\n" ..-- not implemented - -- _("$(GPS.LOCATION.ICON) - icon indicating whether GPS location is known") .. "\n" ..-- not implemented - _("$(LONGITUDE) - longitude") .. "\n" .. - _("$(LATITUDE) - latitude") .. "\n" .. - _("$(ELEVATION) - elevation") .. "\n" .. - _("$(STARS) - star rating as number (-1 for rejected)") .. "\n" .. - -- _("$(RATING.ICONS) - star/reject rating in icon form") .. "\n" ..-- not implemented - _("$(LABELS) - color labels as text") .. "\n" .. - -- _("$(LABELS.ICONS) - color labels as icons") .. "\n" ..-- not implemented - _("$(TITLE) - title from metadata") .. "\n" .. - _("$(DESCRIPTION) - description from metadata") .. "\n" .. - _("$(CREATOR) - creator from metadata") .. "\n" .. - _("$(PUBLISHER) - publisher from metadata") .. "\n" .. - _("$(RIGHTS) - rights from metadata") .. "\n" .. - --_("$(TAGS) - tags as set in metadata settings") .. "\n" .. - _("$(CATEGORY[n,category]) - subtag of level n in hierarchical tags") .. "\n" .. - _("$(SIDECAR_TXT) - contents of .txt sidecar file, if present") .. "\n" .. - _("$(FOLDER.PICTURES) - pictures folder") .. "\n" .. - _("$(FOLDER.HOME) - home folder") .. "\n" .. - _("$(FOLDER.DESKTOP) - desktop folder") .. "\n" .. - -- _("$(OPENCL.ACTIVATED) - whether OpenCL is activated") .. "\n" .. - _("$(USERNAME) - login name") .. "\n" .. - -- _("$(NL) - newline") .. "\n" .. - -- _("$(JOBCODE) - job code for import") .. "\n" .. - "" + _("$(EXIF.FLASH) - was flash used (yes/no/--)") .. -- not implemented + -- _("$(GPS.LONGITUDE) - longitude"),-- not implemented + -- _("$(GPS.LATITUDE) - latitude"),-- not implemented + -- _("$(GPS.ELEVATION) - elevation"),-- not implemented + -- _("$(GPS.LOCATION.ICON) - icon indicating whether GPS location is known"),-- not implemented + _("$(LONGITUDE) - longitude"), + _("$(LATITUDE) - latitude"), + _("$(ELEVATION) - elevation"), + _("$(STARS) - star rating as number (-1 for rejected)"), + -- _("$(RATING.ICONS) - star/reject rating in icon form"),-- not implemented + _("$(LABELS) - color labels as text"), + -- _("$(LABELS.ICONS) - color labels as icons"),-- not implemented + _("$(TITLE) - title from metadata"), + _("$(DESCRIPTION) - description from metadata"), + _("$(CREATOR) - creator from metadata"), + _("$(PUBLISHER) - publisher from metadata"), + _("$(RIGHTS) - rights from metadata"), + --_("$(TAGS) - tags as set in metadata settings"), + _("$(CATEGORY[n,category]) - subtag of level n in hierarchical tags"), + _("$(SIDECAR_TXT) - contents of .txt sidecar file, if present"), + _("$(FOLDER.PICTURES) - pictures folder"), + _("$(FOLDER.HOME) - home folder"), + _("$(FOLDER.DESKTOP) - desktop folder"), + -- _("$(OPENCL.ACTIVATED) - whether OpenCL is activated"), + _("$(USERNAME) - login name"), + -- _("$(NL) - newline"), + -- _("$(JOBCODE) - job code for import"), + ""}, "\n") end -- handle different versions of names @@ -957,6 +981,7 @@ local function treat(var_string) if string.match(var_string, "CATEGORY%d") or string.match(var_string, "CATEGORY%[") then log.msg(log.info, "substituting for " .. var_string) ret_val = substitutes[var_string] + if not ret_val then ret_val = "" log.msg(log.info, "ret_val is " .. ret_val) elseif string.match(var_string, "SEQUENCE%[") then From 99eb595f4c62330382ed2c2c04137d421b518da6 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Wed, 16 Oct 2024 21:00:27 -0400 Subject: [PATCH 361/445] lib/dtutils/string added end to if to ensure that ret_val has a value --- lib/dtutils/string.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/dtutils/string.lua b/lib/dtutils/string.lua index e85d5866..2310a496 100644 --- a/lib/dtutils/string.lua +++ b/lib/dtutils/string.lua @@ -981,7 +981,7 @@ local function treat(var_string) if string.match(var_string, "CATEGORY%d") or string.match(var_string, "CATEGORY%[") then log.msg(log.info, "substituting for " .. var_string) ret_val = substitutes[var_string] - if not ret_val then ret_val = "" + if not ret_val then ret_val = "" end log.msg(log.info, "ret_val is " .. ret_val) elseif string.match(var_string, "SEQUENCE%[") then From 44da339202747490a20fe6bb60c8c772c29eb94c Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Thu, 17 Oct 2024 22:17:38 -0400 Subject: [PATCH 362/445] alias gettext to darktable.gettext.gettext then change the call to gettext to only pass the message to be translated --- contrib/AutoGrouper.lua | 4 ++-- contrib/auto_snapshot.lua | 2 +- contrib/dbmaint.lua | 2 +- contrib/gpx_export.lua | 4 ++-- contrib/passport_guide_germany.lua | 4 ++-- contrib/transfer_hierarchy.lua | 3 ++- lib/dtutils/file.lua | 7 ++----- lib/dtutils/string.lua | 3 ++- tools/script_manager.lua | 4 ++-- 9 files changed, 16 insertions(+), 17 deletions(-) diff --git a/contrib/AutoGrouper.lua b/contrib/AutoGrouper.lua index 72654ae2..f8d8061b 100644 --- a/contrib/AutoGrouper.lua +++ b/contrib/AutoGrouper.lua @@ -43,10 +43,10 @@ du.check_min_api_version("7.0.0", "AutoGrouper") local MOD = 'autogrouper' -local gettext = dt.gettext +local gettext = dt.gettext.gettext local function _(msgid) - return gettext.gettext(msgid) + return gettext(msgid) end -- return data structure for script_manager diff --git a/contrib/auto_snapshot.lua b/contrib/auto_snapshot.lua index 3b883412..e3ede5b1 100644 --- a/contrib/auto_snapshot.lua +++ b/contrib/auto_snapshot.lua @@ -60,7 +60,7 @@ du.check_min_api_version("7.0.0", MODULE) -- choose the minimum version that c local gettext = dt.gettext.gettext local function _(msgid) - return gettext(MODULE, msgid) + return gettext(msgid) end diff --git a/contrib/dbmaint.lua b/contrib/dbmaint.lua index 8d24f1d2..044a9ac5 100644 --- a/contrib/dbmaint.lua +++ b/contrib/dbmaint.lua @@ -64,7 +64,7 @@ du.check_min_api_version("7.0.0", MODULE) -- choose the minimum version that c local gettext = dt.gettext.gettext local function _(msgid) - return gettext(MODULE, msgid) + return gettext(msgid) end diff --git a/contrib/gpx_export.lua b/contrib/gpx_export.lua index 84fc7bf9..1525aff8 100644 --- a/contrib/gpx_export.lua +++ b/contrib/gpx_export.lua @@ -25,12 +25,12 @@ For each source folder, a separate is generated in the gpx file. local dt = require "darktable" local df = require "lib/dtutils.file" local dl = require "lib/dtutils" -local gettext = dt.gettext +local gettext = dt.gettext.gettext dl.check_min_api_version("7.0.0", "gpx_export") local function _(msgid) - return gettext.dgettext("gpx_export", msgid) + return gettext(msgid) end -- return data structure for script_manager diff --git a/contrib/passport_guide_germany.lua b/contrib/passport_guide_germany.lua index 9b34d0b1..745f86df 100644 --- a/contrib/passport_guide_germany.lua +++ b/contrib/passport_guide_germany.lua @@ -40,13 +40,13 @@ USAGE local dt = require "darktable" local du = require "lib/dtutils" -local gettext = dt.gettext +local gettext = dt.gettext.gettext du.check_min_api_version("2.0.0", "passport_guide_germany") -- Tell gettext where to find the .mo file translating messages for a particular domain local function _(msgid) - return gettext.dgettext("passport_guide_germany", msgid) + return gettext(msgid) end local script_data = {} diff --git a/contrib/transfer_hierarchy.lua b/contrib/transfer_hierarchy.lua index 465b4f7e..16c23593 100755 --- a/contrib/transfer_hierarchy.lua +++ b/contrib/transfer_hierarchy.lua @@ -76,12 +76,13 @@ local darktable = require("darktable") local dtutils = require("lib/dtutils") local dtutils_file = require("lib/dtutils.file") local dtutils_system = require("lib/dtutils.system") +local gettext = darktable.gettext.gettext local LIB_ID = "transfer_hierarchy" dtutils.check_min_api_version("7.0.0", LIB_ID) local function _(msgid) - return darktable.gettext.gettext(msgid) + return gettext(msgid) end -- return data structure for script_manager diff --git a/lib/dtutils/file.lua b/lib/dtutils/file.lua index e33fa5aa..13197b97 100644 --- a/lib/dtutils/file.lua +++ b/lib/dtutils/file.lua @@ -24,15 +24,12 @@ dtutils_file.libdoc = { functions = {} } -local gettext = dt.gettext +local gettext = dt.gettext.gettext du.check_min_api_version("5.0.0", "dtutils.file") --- Tell gettext where to find the .mo file translating messages for a particular domain -gettext.bindtextdomain("dtutils.file",dt.configuration.config_dir.."/lua/locale/") - local function _(msgid) - return gettext.dgettext("dtutils.file", msgid) + return gettext(msgid) end --[[ diff --git a/lib/dtutils/string.lua b/lib/dtutils/string.lua index 2310a496..5cf49cd3 100644 --- a/lib/dtutils/string.lua +++ b/lib/dtutils/string.lua @@ -3,11 +3,12 @@ local dtutils_string = {} local dt = require "darktable" local du = require "lib/dtutils" local log = require "lib/dtutils.log" +local gettext = dt.gettext.gettext local DEFAULT_LOG_LEVEL = log.error local function _(msg) - return dt.gettext.gettext(msg) + return gettext(msg) end dtutils_string.log_level = DEFAULT_LOG_LEVEL diff --git a/tools/script_manager.lua b/tools/script_manager.lua index 7991672e..a925d847 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -56,10 +56,10 @@ local dtsys = require "lib/dtutils.system" local log = require "lib/dtutils.log" local debug = require "darktable.debug" -local gettext = dt.gettext +local gettext = dt.gettext.gettext local function _(msgid) - return gettext.dgettext("script_manager", msgid) + return gettext(msgid) end -- api check From 300bb9d44377244ba9ef962a8f60c4ea1b76edf8 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sat, 19 Oct 2024 22:04:56 -0400 Subject: [PATCH 363/445] lib/dtutils/string - fixed _should_be_sanitized with new patterns to detect non safe filename characters --- lib/dtutils/string.lua | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/dtutils/string.lua b/lib/dtutils/string.lua index 5cf49cd3..ff8f73ef 100644 --- a/lib/dtutils/string.lua +++ b/lib/dtutils/string.lua @@ -306,8 +306,16 @@ end local function _should_be_sanitized(str) local old_log_level = log.log_level() local result = false + local SAFE_POSIX_FILENAME_CHARS = "[^%w/._%-]+" + local SAFE_WIN_FILENAME_CHARS = "[^%w\\._%-:]+" + + local pattern = SAFE_POSIX_STRING_CHARS + if dt.configuration.running_os == "windows" then + pattern = SAFE_WIN_STRING_CHARS + end + log.log_level(dtutils_string.log_level) - if string.match(str, "[^%g]") then + if string.match(str, pattern) then result = true end log.log_level(old_log_level) From 8e4767c42a476c9423dbbfed53f00c3b58e4c2a9 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Mon, 21 Oct 2024 14:32:53 -0400 Subject: [PATCH 364/445] tools/script_manager - fixed translation of page %d of %d --- tools/script_manager.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/script_manager.lua b/tools/script_manager.lua index a925d847..bbefb1e7 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -1006,7 +1006,7 @@ local function paginate(direction) last = first + sm.page_status.num_buttons - 1 end - sm.widgets.page_status.label = _(string.format("page %d of %d", cur_page, max_pages)) + sm.widgets.page_status.label = string.format(_("page %d of %d"), cur_page, max_pages) populate_buttons(folder, first, last) From 13f210bec9566b805ffa7136be0b087b3cba6d99 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Mon, 21 Oct 2024 22:52:11 -0400 Subject: [PATCH 365/445] official/apply_camera_style - made name tranlatable and made it into name string instead of the filename tools/script_manager - change get_script_metadata to retreive a script metadata block and store it as a metadata block making the indiviual fields accessible. change the script buttons to use the translated name if available and just the purpose for the tooltip. --- official/apply_camera_style.lua | 2 +- tools/script_manager.lua | 28 ++++++++++++++-------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/official/apply_camera_style.lua b/official/apply_camera_style.lua index a72c8217..8c8aeae4 100644 --- a/official/apply_camera_style.lua +++ b/official/apply_camera_style.lua @@ -89,7 +89,7 @@ script_data.restart = nil -- how to restart the (lib) script after it' script_data.show = nil -- only required for libs since the destroy_method only hides them script_data.metadata = { - name = "apply_camera_style", -- name of script + name = _("apply camera style"), -- name of script purpose = _("apply darktable camera style to matching images"), -- purpose of script author = "Bill Ferguson ", -- your name and optionally e-mail address help = "https://docs.darktable.org/lua/development/lua.scripts.manual/scripts/official/apply_camera_style/" -- URL to help/documentation diff --git a/tools/script_manager.lua b/tools/script_manager.lua index bbefb1e7..59c23c43 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -405,8 +405,8 @@ local function get_script_metadata(script) log.msg(log.debug, "processing metatdata for " .. script) - local description = nil - local metadata = nil + local metadata_block = nil + local metadata = {} f = io.open(LUA_DIR .. PS .. script .. ".lua") if f then @@ -414,20 +414,19 @@ local function get_script_metadata(script) local content = f:read("*all") f:close() -- grab the script_data.metadata table - description = string.match(content, "script_data%.metadata = %{\r?\n(.-)\r?\n%}") + metadata_block = string.match(content, "script_data%.metadata = %{\r?\n(.-)\r?\n%}") else log.msg(log.error, "cant read from " .. script) end - if description then - metadata = "" - -- format it into a string block for display - local lines = du.split(description, "\n") + if metadata_block then + -- break up the lines into key value pairs + local lines = du.split(metadata_block, "\n") log.msg(log.debug, "got " .. #lines .. " lines") - local first = 1 for i = 1, #lines do log.msg(log.debug, "splitting line " .. lines[i]) local parts = du.split(lines[i], " = ") + parts[1] = string_trim(parts[1]) log.msg(log.debug, "got value " .. parts[1] .. " and data " .. parts[2]) if string.match(parts[2], "%_%(") then parts[2] = _(string_dequote(string_dei18n(parts[2]))) @@ -437,14 +436,15 @@ local function get_script_metadata(script) if string.match(parts[2], ",$") then parts[2] = string_chop(parts[2]) end - metadata = metadata .. string.format("%s%-10s\t%s", first and "" or "\n", parts[1], parts[2]) - first = nil + log.msg(log.debug, "parts 1 is " .. parts[1] .. " and parts 2 is " .. parts[2]) + metadata[parts[1]] = parts[2] + log.msg(log.debug, "metadata " .. parts[1] .. " is " .. metadata[parts[1]]) end - log.msg(log.debug, "script data is \n" .. metadata) + log.msg(log.debug, "script data found for " .. metadata["name"]) end restore_log_level(old_log_level) - return metadata + return metadata_block and metadata or nil end local function get_script_doc(script) @@ -910,11 +910,11 @@ local function populate_buttons(folder, first, last) end button.image = POWER_ICON - label.label = script.name + label.label = script.metadata and script.metadata.name or script.name label.name = "pb_label" button.ellipsize = "end" button.sensitive = true - label.tooltip = script.metadata and script.metadata or script.doc + label.tooltip = script.metadata and script.metadata.purpose or script.doc button.clicked_callback = function (this) local cb_script = script From d12363467933c99faec332253627b113a0c37dc8 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Tue, 22 Oct 2024 00:13:30 -0400 Subject: [PATCH 366/445] Changed script names in metadata from filenames to names by removing underscores, spelling out abbreviations, etc. --- contrib/AutoGrouper.lua | 2 +- contrib/CollectHelper.lua | 2 +- contrib/HDRMerge.lua | 2 +- contrib/LabelsToTags.lua | 2 +- contrib/OpenInExplorer.lua | 2 +- contrib/RL_out_sharp.lua | 2 +- contrib/auto_snapshot.lua | 2 +- contrib/autostyle.lua | 2 +- contrib/change_group_leader.lua | 2 +- contrib/clear_GPS.lua | 2 +- contrib/color_profile_manager.lua | 2 +- contrib/copy_attach_detach_tags.lua | 2 +- contrib/cr2hdr.lua | 2 +- contrib/cycle_group_leader.lua | 2 +- contrib/dbmaint.lua | 2 +- contrib/enfuseAdvanced.lua | 2 +- contrib/exportLUT.lua | 2 +- contrib/ext_editor.lua | 2 +- contrib/face_recognition.lua | 2 +- contrib/fujifilm_dynamic_range.lua | 2 +- contrib/fujifilm_ratings.lua | 2 +- contrib/geoJSON_export.lua | 2 +- contrib/geoToolbox.lua | 2 +- contrib/gimp.lua | 2 +- contrib/gpx_export.lua | 2 +- contrib/harmonic_armature_guide.lua | 2 +- contrib/hif_group_leader.lua | 2 +- contrib/hugin.lua | 2 +- contrib/image_stack.lua | 2 +- contrib/image_time.lua | 2 +- contrib/jpg_group_leader.lua | 2 +- contrib/kml_export.lua | 2 +- contrib/passport_guide.lua | 2 +- contrib/passport_guide_germany.lua | 2 +- contrib/pdf_slideshow.lua | 2 +- contrib/photils.lua | 2 +- contrib/quicktag.lua | 2 +- contrib/rate_group.lua | 2 +- contrib/rename-tags.lua | 2 +- contrib/rename_images.lua | 2 +- contrib/select_non_existing.lua | 2 +- contrib/select_untagged.lua | 2 +- contrib/slideshowMusic.lua | 2 +- contrib/transfer_hierarchy.lua | 2 +- contrib/video_ffmpeg.lua | 2 +- examples/api_version.lua | 2 +- examples/darkroom_demo.lua | 2 +- examples/gettextExample.lua | 2 +- examples/gui_action.lua | 2 +- examples/hello_world.lua | 2 +- examples/lighttable_demo.lua | 2 +- examples/moduleExample.lua | 2 +- examples/multi_os.lua | 2 +- examples/panels_demo.lua | 2 +- examples/preferenceExamples.lua | 2 +- examples/printExamples.lua | 2 +- examples/running_os.lua | 2 +- examples/x-touch.lua | 2 +- official/check_for_updates.lua | 2 +- official/copy_paste_metadata.lua | 2 +- official/delete_long_tags.lua | 2 +- official/delete_unused_tags.lua | 2 +- official/enfuse.lua | 2 +- official/generate_image_txt.lua | 2 +- official/image_path_in_ui.lua | 2 +- official/import_filter_manager.lua | 2 +- official/import_filters.lua | 2 +- official/save_selection.lua | 2 +- official/selection_to_pdf.lua | 2 +- tools/executable_manager.lua | 2 +- tools/get_lib_manpages.lua | 2 +- tools/get_libdoc.lua | 2 +- 72 files changed, 72 insertions(+), 72 deletions(-) diff --git a/contrib/AutoGrouper.lua b/contrib/AutoGrouper.lua index f8d8061b..67609374 100644 --- a/contrib/AutoGrouper.lua +++ b/contrib/AutoGrouper.lua @@ -54,7 +54,7 @@ end local script_data = {} script_data.metadata = { - name = "AutoGrouper", + name = _("auto group"), purpose = _("automatically group images by time interval"), author = "Kevin Ertel", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/AutoGrouper/" diff --git a/contrib/CollectHelper.lua b/contrib/CollectHelper.lua index f06b14e4..978aa309 100644 --- a/contrib/CollectHelper.lua +++ b/contrib/CollectHelper.lua @@ -62,7 +62,7 @@ end local script_data = {} script_data.metadata = { - name = "CollectHelper", + name = _("collection helper"), purpose = _("add collection helper buttons"), author = "Kevin Ertel", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/CollectHelper/" diff --git a/contrib/HDRMerge.lua b/contrib/HDRMerge.lua index 76067d53..9d7a951d 100644 --- a/contrib/HDRMerge.lua +++ b/contrib/HDRMerge.lua @@ -63,7 +63,7 @@ end local script_data = {} script_data.metadata = { - name = "HDRmerge", + name = _("HDR merge"), purpose = _("merge bracketed images into an HDR DNG image"), author = "Kevin Ertel", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/HDRmerge" diff --git a/contrib/LabelsToTags.lua b/contrib/LabelsToTags.lua index 0c00c123..32031a3b 100644 --- a/contrib/LabelsToTags.lua +++ b/contrib/LabelsToTags.lua @@ -63,7 +63,7 @@ end local script_data = {} script_data.metadata = { - name = "LabelsToTags", + name = _("labels to tags"), purpose = _("allows the mass-application of tags using color labels and ratings as a guide"), author = "August Schwerdfeger (august@schwerdfeger.name)", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/LabelsToTags" diff --git a/contrib/OpenInExplorer.lua b/contrib/OpenInExplorer.lua index 4ba59690..14f788d7 100644 --- a/contrib/OpenInExplorer.lua +++ b/contrib/OpenInExplorer.lua @@ -65,7 +65,7 @@ end local script_data = {} script_data.metadata = { - name = "OpenInExplorer", + name = _("open in explorer"), purpose = _("open a selected file in the system file manager"), author = "Kevin Ertel", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/OpenInExplorer" diff --git a/contrib/RL_out_sharp.lua b/contrib/RL_out_sharp.lua index 9083277f..b65581c9 100644 --- a/contrib/RL_out_sharp.lua +++ b/contrib/RL_out_sharp.lua @@ -77,7 +77,7 @@ local function _(msgid) local script_data = {} script_data.metadata = { - name = "RL_out_sharp", + name = _("RL output sharpening"), purpose = _("Richardson-Lucy output sharpening using GMic"), author = "Marco Carrarini ", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/RL_out_sharp" diff --git a/contrib/auto_snapshot.lua b/contrib/auto_snapshot.lua index e3ede5b1..48f99f5b 100644 --- a/contrib/auto_snapshot.lua +++ b/contrib/auto_snapshot.lua @@ -76,7 +76,7 @@ script_data.restart = nil -- how to restart the (lib) script after it' script_data.show = nil -- only required for libs since the destroy_method only hides them script_data.metadata = { - name = "auto_snapshot", -- name of script + name = _("auto snapshot"), -- name of script purpose = _("automatically take a snapshot when an image is loaded in darkroom"), -- purpose of script author = "Bill Ferguson ", -- your name and optionally e-mail address help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/auto_snapshot/" -- URL to help/documentation diff --git a/contrib/autostyle.lua b/contrib/autostyle.lua index 46b14cac..093c29a3 100644 --- a/contrib/autostyle.lua +++ b/contrib/autostyle.lua @@ -54,7 +54,7 @@ end local script_data = {} script_data.metadata = { - name = "autostyle", + name = _("auto style"), purpose = _("automatically apply a style based on image EXIF tag"), author = "Marc Cousin ", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/autostyle/" diff --git a/contrib/change_group_leader.lua b/contrib/change_group_leader.lua index e7f424b7..0e6f66e6 100644 --- a/contrib/change_group_leader.lua +++ b/contrib/change_group_leader.lua @@ -51,7 +51,7 @@ end local script_data = {} script_data.metadata = { - name = "change_group_leader", + name = _("change group leader"), purpose = _("automatically change the leader of raw+jpg paired image groups"), author = "Bill Ferguson ", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/change_group_leader" diff --git a/contrib/clear_GPS.lua b/contrib/clear_GPS.lua index 8c591661..2663ab4b 100644 --- a/contrib/clear_GPS.lua +++ b/contrib/clear_GPS.lua @@ -50,7 +50,7 @@ end local script_data = {} script_data.metadata = { - name = "clear_GPS", + name = _("clear GPS info"), purpose = _("remove GPS data from selected image(s)"), author = "Bill Ferguson ", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/clear_gps/" diff --git a/contrib/color_profile_manager.lua b/contrib/color_profile_manager.lua index 6114992e..683ae990 100644 --- a/contrib/color_profile_manager.lua +++ b/contrib/color_profile_manager.lua @@ -363,7 +363,7 @@ end local script_data = {} script_data.metadata = { - name = "color_profile_manager", + name = _("color profile manager"), purpose = _("manage external darktable color profiles"), author = "Bill Ferguson ", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/color_profile_manager" diff --git a/contrib/copy_attach_detach_tags.lua b/contrib/copy_attach_detach_tags.lua index 2b66bc76..3f1f6d34 100644 --- a/contrib/copy_attach_detach_tags.lua +++ b/contrib/copy_attach_detach_tags.lua @@ -53,7 +53,7 @@ end local script_data = {} script_data.metadata = { - name = "copy_attach_detach_tags", + name = _("copy attach detach tags"), purpose = _("shortcuts to copy, paste, replace, or remove tags from images"), author = "Christian Kanzian", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/copy_attach_detach_tags" diff --git a/contrib/cr2hdr.lua b/contrib/cr2hdr.lua index 209287cc..36f325f2 100644 --- a/contrib/cr2hdr.lua +++ b/contrib/cr2hdr.lua @@ -48,7 +48,7 @@ end local script_data = {} script_data.metadata = { - name = "cr2hdr", + name = _("cr2hdr"), purpose = _("process Magic Lantern dual ISO images"), author = "Till Theato ", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/cr2hdr" diff --git a/contrib/cycle_group_leader.lua b/contrib/cycle_group_leader.lua index 665f0c09..e168e93b 100644 --- a/contrib/cycle_group_leader.lua +++ b/contrib/cycle_group_leader.lua @@ -71,7 +71,7 @@ end local script_data = {} script_data.metadata = { - name = "cycle_group_leader", + name = _("cycle group leader"), purpose = _("change image group leader"), author = "Bill Ferguson ", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/cycle_group_leader" diff --git a/contrib/dbmaint.lua b/contrib/dbmaint.lua index 044a9ac5..16ca9b91 100644 --- a/contrib/dbmaint.lua +++ b/contrib/dbmaint.lua @@ -80,7 +80,7 @@ script_data.restart = nil -- how to restart the (lib) script after it' script_data.show = nil -- only required for libs since the destroy_method only hides them script_data.metadata = { - name = "dbmaint", + name = _("db maintenance"), purpose = _("perform database maintenance"), author = "Bill Ferguson ", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/dbmaint/" diff --git a/contrib/enfuseAdvanced.lua b/contrib/enfuseAdvanced.lua index b35cb490..5027c564 100644 --- a/contrib/enfuseAdvanced.lua +++ b/contrib/enfuseAdvanced.lua @@ -79,7 +79,7 @@ end local script_data = {} script_data.metadata = { - name = "enfuseAdvanced", + name = _("enfuse advanced"), purpose = _("focus stack or exposure blend images"), author = "Kevin Ertel", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/enfuseAdvanced" diff --git a/contrib/exportLUT.lua b/contrib/exportLUT.lua index 80854567..9ec29544 100644 --- a/contrib/exportLUT.lua +++ b/contrib/exportLUT.lua @@ -44,7 +44,7 @@ end local script_data = {} script_data.metadata = { - name = "exportLUT", + name = _("export LUT"), purpose = _("export a style as a LUT"), author = "Noah Clarke", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/exportLUT" diff --git a/contrib/ext_editor.lua b/contrib/ext_editor.lua index 0cee9454..be371e92 100644 --- a/contrib/ext_editor.lua +++ b/contrib/ext_editor.lua @@ -87,7 +87,7 @@ end local script_data = {} script_data.metadata = { - name = "ext_editor", + name = _("external editors"), purpose = _("edit images with external editors"), author = "Marco Carrarini, marco.carrarini@gmail.com", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/ext_editor" diff --git a/contrib/face_recognition.lua b/contrib/face_recognition.lua index 74827f12..0c60a5c1 100644 --- a/contrib/face_recognition.lua +++ b/contrib/face_recognition.lua @@ -63,7 +63,7 @@ end local script_data = {} script_data.metadata = { - name = "face_recognition", + name = _("face recognition"), purpose = _("use facial recognition to tag images"), author = "Sebastian Witt", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/face_recognition" diff --git a/contrib/fujifilm_dynamic_range.lua b/contrib/fujifilm_dynamic_range.lua index 7bb6ab53..37f79511 100644 --- a/contrib/fujifilm_dynamic_range.lua +++ b/contrib/fujifilm_dynamic_range.lua @@ -74,7 +74,7 @@ end local script_data = {} script_data.metadata = { - name = "fujifilm_dynamic_range", + name = _("fujifilm dynamic range"), purpose = _("compensate for Fujifilm raw files made using \"dynamic range\""), author = "Dan Torop ", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/fujifilm_dynamic_range" diff --git a/contrib/fujifilm_ratings.lua b/contrib/fujifilm_ratings.lua index c9a034d8..b29996d9 100644 --- a/contrib/fujifilm_ratings.lua +++ b/contrib/fujifilm_ratings.lua @@ -40,7 +40,7 @@ end local script_data = {} script_data.metadata = { - name = "fujifilm_ratings", + name = _("fujifilm ratings"), purpose = _("import Fujifilm in-camera ratings"), author = "Ben Mendis ", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/fujifilm_ratings" diff --git a/contrib/geoJSON_export.lua b/contrib/geoJSON_export.lua index 93ecd9ff..93e77289 100644 --- a/contrib/geoJSON_export.lua +++ b/contrib/geoJSON_export.lua @@ -49,7 +49,7 @@ end local script_data = {} script_data.metadata = { - name = "geoJSON_export", + name = _("geoJSON export"), purpose = _("export a geoJSON file from geo data"), author = "Tobias Jakobs", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/geoJSON_export" diff --git a/contrib/geoToolbox.lua b/contrib/geoToolbox.lua index f2ab6957..0fa07301 100644 --- a/contrib/geoToolbox.lua +++ b/contrib/geoToolbox.lua @@ -42,7 +42,7 @@ end local script_data = {} script_data.metadata = { - name = "geoToolbox", + name = _("geo toolbox"), purpose = _("geodata tools"), author = "Tobias Jakobs", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/geoToolbox" diff --git a/contrib/gimp.lua b/contrib/gimp.lua index 8e285517..92c6d0ce 100644 --- a/contrib/gimp.lua +++ b/contrib/gimp.lua @@ -83,7 +83,7 @@ end local script_data = {} script_data.metadata = { - name = "gimp", + name = _("edit with GIMP"), purpose = _("export and edit with GIMP"), author = "Bill Ferguson ", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/gimp" diff --git a/contrib/gpx_export.lua b/contrib/gpx_export.lua index 1525aff8..b310f3a9 100644 --- a/contrib/gpx_export.lua +++ b/contrib/gpx_export.lua @@ -38,7 +38,7 @@ end local script_data = {} script_data.metadata = { - name = "gpx_export", + name = _("gpx export"), purpose = _("export gpx information to a file"), author = "Jannis_V", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/gpx_export" diff --git a/contrib/harmonic_armature_guide.lua b/contrib/harmonic_armature_guide.lua index a85195cc..ffe03a29 100644 --- a/contrib/harmonic_armature_guide.lua +++ b/contrib/harmonic_armature_guide.lua @@ -43,7 +43,7 @@ end local script_data = {} script_data.metadata = { - name = "harmonic_armature_guide", + name = _("harmonic armature guide"), purpose = _("harmonic artmature guide"), author = "Hubert Kowalski", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/harmonic_armature_guide" diff --git a/contrib/hif_group_leader.lua b/contrib/hif_group_leader.lua index 9543becb..f39d3ff0 100644 --- a/contrib/hif_group_leader.lua +++ b/contrib/hif_group_leader.lua @@ -75,7 +75,7 @@ end local script_data = {} script_data.metadata = { - name = "hif_group_leader", + name = _("HIF group leader"), purpose = _("make hif image group leader"), author = "Bill Ferguson ", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/hif_group_leader" diff --git a/contrib/hugin.lua b/contrib/hugin.lua index 49868424..85fe5f85 100644 --- a/contrib/hugin.lua +++ b/contrib/hugin.lua @@ -65,7 +65,7 @@ end local script_data = {} script_data.metadata = { - name = "hugin", + name = _("hugin"), purpose = _("stitch images into a panorama"), author = "Wolfgang Goetz", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/hugin" diff --git a/contrib/image_stack.lua b/contrib/image_stack.lua index 817dc7a6..661b28d3 100644 --- a/contrib/image_stack.lua +++ b/contrib/image_stack.lua @@ -82,7 +82,7 @@ end local script_data = {} script_data.metadata = { - name = "image_stack", + name = _("image stack"), purpose = _("process a stack of images"), author = "Bill Ferguson ", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/image_stack" diff --git a/contrib/image_time.lua b/contrib/image_time.lua index 4daf9c6b..28570c1a 100644 --- a/contrib/image_time.lua +++ b/contrib/image_time.lua @@ -125,7 +125,7 @@ end local script_data = {} script_data.metadata = { - name = "image_time", + name = _("image time"), purpose = _("synchronize image time for images shot with different cameras or adjust or set image time"), author = "Bill Ferguson ", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/image_time" diff --git a/contrib/jpg_group_leader.lua b/contrib/jpg_group_leader.lua index 7ca1359b..8391a670 100644 --- a/contrib/jpg_group_leader.lua +++ b/contrib/jpg_group_leader.lua @@ -75,7 +75,7 @@ end local script_data = {} script_data.metadata = { - name = "jpg_group_leader", + name = _("JPG group leader"), purpose = _("make jpg image group leader"), author = "Bill Ferguson ", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/jpg_group_leader" diff --git a/contrib/kml_export.lua b/contrib/kml_export.lua index 561e8ba8..561724fa 100644 --- a/contrib/kml_export.lua +++ b/contrib/kml_export.lua @@ -54,7 +54,7 @@ end local script_data = {} script_data.metadata = { - name = "kml_export", + name = _("kml export"), purpose = _("export KML/KMZ data to a file"), author = "Tobias Jakobs", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/kml_export" diff --git a/contrib/passport_guide.lua b/contrib/passport_guide.lua index 91e07052..34e9fc79 100644 --- a/contrib/passport_guide.lua +++ b/contrib/passport_guide.lua @@ -48,7 +48,7 @@ end local script_data = {} script_data.metadata = { - name = "passport_guide", + name = _("passport guide"), purpose = _("guides for cropping passport photos"), author = "Kåre Hampf", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/passport_guide" diff --git a/contrib/passport_guide_germany.lua b/contrib/passport_guide_germany.lua index 745f86df..a1b9f618 100644 --- a/contrib/passport_guide_germany.lua +++ b/contrib/passport_guide_germany.lua @@ -52,7 +52,7 @@ end local script_data = {} script_data.metadata = { - name = "passport_guide_germany", + name = _("passport guide Germany"), purpose = _("guides for cropping passport and ID card (\"Personalausweis\") photos based on the \"Passbild-Schablone\" from the German Federal Ministry of the Interior and Community"), author = "menschmachine", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/passport_guide_germany" diff --git a/contrib/pdf_slideshow.lua b/contrib/pdf_slideshow.lua index 36b0b1b8..b93ae978 100644 --- a/contrib/pdf_slideshow.lua +++ b/contrib/pdf_slideshow.lua @@ -60,7 +60,7 @@ du.check_min_api_version("7.0.0", "pdf_slideshow") local script_data = {} script_data.metadata = { - name = "pdf_slideshow", + name = _("PDF slideshow"), purpose = _("generates a PDF slideshow (via Latex) containing all selected images one per slide"), author = "Pascal Obry", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/pdf_slideshow" diff --git a/contrib/photils.lua b/contrib/photils.lua index a5fe59be..7bb39c6f 100644 --- a/contrib/photils.lua +++ b/contrib/photils.lua @@ -55,7 +55,7 @@ end local script_data = {} script_data.metadata = { - name = "photils", + name = _("photils"), purpose = _("suggest tags based on image classification"), author = "Tobias Scheck", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/photils" diff --git a/contrib/quicktag.lua b/contrib/quicktag.lua index 7dd604da..c218f09c 100644 --- a/contrib/quicktag.lua +++ b/contrib/quicktag.lua @@ -60,7 +60,7 @@ end local script_data = {} script_data.metadata = { - name = "quicktag", + name = _("quick tag"), purpose = _("use buttons to quickly apply tags assigned to them"), author = "Christian Kanzian", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/quicktag" diff --git a/contrib/rate_group.lua b/contrib/rate_group.lua index 8c3a15d3..0e9ddb29 100644 --- a/contrib/rate_group.lua +++ b/contrib/rate_group.lua @@ -55,7 +55,7 @@ end local script_data = {} script_data.metadata = { - name = "rate_group", + name = _("rate group"), purpose = _("rate all images in a group"), author = "Dom H (dom@hxy.io)", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/rate_group" diff --git a/contrib/rename-tags.lua b/contrib/rename-tags.lua index 69509a53..ae77056a 100644 --- a/contrib/rename-tags.lua +++ b/contrib/rename-tags.lua @@ -47,7 +47,7 @@ end local script_data = {} script_data.metadata = { - name = "rename-tags", + name = _("rename tags"), purpose = _("rename an existing tag"), author = "Sebastian Witt (se.witt@gmx.net)", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/rename-tags" diff --git a/contrib/rename_images.lua b/contrib/rename_images.lua index d50c8e18..a0d37e99 100644 --- a/contrib/rename_images.lua +++ b/contrib/rename_images.lua @@ -65,7 +65,7 @@ rename.event_registered = false local script_data = {} script_data.metadata = { - name = "rename_images", + name = _("rename images"), purpose = _("rename an image file or files"), author = "Bill Ferguson ", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/rename_images" diff --git a/contrib/select_non_existing.lua b/contrib/select_non_existing.lua index d7bfa641..b47c7cf6 100644 --- a/contrib/select_non_existing.lua +++ b/contrib/select_non_existing.lua @@ -74,7 +74,7 @@ dt.gui.libs.select.register_selection( local script_data = {} script_data.metadata = { - name = "select_non_existing", + name = _("select non existing"), purpose = _("enable selection of non-existing images"), author = "Dirk Dittmar", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/select_non_existing" diff --git a/contrib/select_untagged.lua b/contrib/select_untagged.lua index c86cf831..0ca4b5d2 100644 --- a/contrib/select_untagged.lua +++ b/contrib/select_untagged.lua @@ -33,7 +33,7 @@ end local script_data = {} script_data.metadata = { - name = "select_untagged", + name = _("select untagged"), purpose = _("enable selection of untagged images"), author = "Jannis_V", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/select_untagged" diff --git a/contrib/slideshowMusic.lua b/contrib/slideshowMusic.lua index d83dd248..bed3da6f 100644 --- a/contrib/slideshowMusic.lua +++ b/contrib/slideshowMusic.lua @@ -40,7 +40,7 @@ end local script_data = {} script_data.metadata = { - name = "slideshowMusic", + name = _("slideshow music"), purpose = _("play music during a slideshow"), author = "Tobias Jakobs", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/slideshowMusic" diff --git a/contrib/transfer_hierarchy.lua b/contrib/transfer_hierarchy.lua index 16c23593..dd9c2708 100755 --- a/contrib/transfer_hierarchy.lua +++ b/contrib/transfer_hierarchy.lua @@ -90,7 +90,7 @@ end local script_data = {} script_data.metadata = { - name = "transfer_hierarchy", + name = _("transfer hierarchy"), purpose = _("allows the moving or copying of images from one directory tree to another, while preserving the existing hierarchy"), author = "August Schwerdfeger (august@schwerdfeger.name)", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/transfer_hierarchy" diff --git a/contrib/video_ffmpeg.lua b/contrib/video_ffmpeg.lua index 70af1efe..f0713fa6 100644 --- a/contrib/video_ffmpeg.lua +++ b/contrib/video_ffmpeg.lua @@ -50,7 +50,7 @@ end local script_data = {} script_data.metadata = { - name = "video_ffmpeg", + name = _("video ffmpeg"), purpose = _("timelapse video plugin based on ffmpeg"), author = "Dominik Markiewicz", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contib/video_ffmpeg" diff --git a/examples/api_version.lua b/examples/api_version.lua index aaf341c7..bf8a1c17 100644 --- a/examples/api_version.lua +++ b/examples/api_version.lua @@ -47,7 +47,7 @@ dt.print("API " .. _("version") .. ": " .. result) local script_data = {} script_data.metadata = { - name = "api_version", + name = _("APIversion"), purpose = _("display api_version example"), author = "Tobias Jakobs", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/examples/api_version" diff --git a/examples/darkroom_demo.lua b/examples/darkroom_demo.lua index 72bf1324..b76b552e 100644 --- a/examples/darkroom_demo.lua +++ b/examples/darkroom_demo.lua @@ -117,7 +117,7 @@ dt.gui.current_view(current_view) local script_data = {} script_data.metadata = { - name = "darkroom_demo", + name = _("darkroom demo"), purpose = _("example demonstrating how to control image display in darkroom mode"), author = "Bill Ferguson ", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/examples/darkroom_demo" diff --git a/examples/gettextExample.lua b/examples/gettextExample.lua index acffdca2..42e1a479 100644 --- a/examples/gettextExample.lua +++ b/examples/gettextExample.lua @@ -86,7 +86,7 @@ dt.print_error(_("hello world!")) local script_data = {} script_data.metadata = { - name = "gettextExample", + name = _("gettext example"), purpose = _("example of how translations works"), author = "Tobias Jakobs", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/examples/gettextExample" diff --git a/examples/gui_action.lua b/examples/gui_action.lua index b956e5a9..9fee3619 100644 --- a/examples/gui_action.lua +++ b/examples/gui_action.lua @@ -15,7 +15,7 @@ end local script_data = {} script_data.metadata = { - name = "gui_action", + name = _("gui action"), purpose = _("example of how to use darktable.gui.action() calls"), author = "Diederik ter Rahe", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/examples/gui_action" diff --git a/examples/hello_world.lua b/examples/hello_world.lua index d29c99c7..6e04efc4 100644 --- a/examples/hello_world.lua +++ b/examples/hello_world.lua @@ -53,7 +53,7 @@ dt.print(_("hello, world")) local script_data = {} script_data.metadata = { - name = "hello_world", + name = _("hello world"), purpose = _("example of how to print a message to the screen"), author = "Tobias Ellinghaus", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/examples/hello_world" diff --git a/examples/lighttable_demo.lua b/examples/lighttable_demo.lua index d897ff8a..e28454cd 100644 --- a/examples/lighttable_demo.lua +++ b/examples/lighttable_demo.lua @@ -218,7 +218,7 @@ current_sort_order = dt.gui.libs.filter.sort_order(current_sort_order) local script_data = {} script_data.metadata = { - name = "lighttable_demo", + name = _("lighttable demo"), purpose = _("example demonstrating how to control lighttable display modes"), author = "Bill Ferguson ", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/examples/lighttable_demo" diff --git a/examples/moduleExample.lua b/examples/moduleExample.lua index 6996d2a9..bc432677 100644 --- a/examples/moduleExample.lua +++ b/examples/moduleExample.lua @@ -47,7 +47,7 @@ end local script_data = {} script_data.metadata = { - name = "moduleExample", + name = ("module example"), purpose = _("example of how to create a lighttable module"), author = "Tobias Jakobs", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/examples/moduleExample" diff --git a/examples/multi_os.lua b/examples/multi_os.lua index 83bfee98..21dc0cb1 100644 --- a/examples/multi_os.lua +++ b/examples/multi_os.lua @@ -260,7 +260,7 @@ dt.register_event( local script_data = {} script_data.metadata = { - name = "multi_os", + name = _("multi OS"), purpose = _("example module thet runs on different operating systems"), author = "Bill Ferguson ", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/examples/multi_os" diff --git a/examples/panels_demo.lua b/examples/panels_demo.lua index 6fa82607..ac9e3de4 100644 --- a/examples/panels_demo.lua +++ b/examples/panels_demo.lua @@ -146,7 +146,7 @@ end local script_data = {} script_data.metadata = { - name = "panels_demo", + name = _("panels demo"), purpose = _("example demonstrating how to contol panel visibility"), author = "Bill Ferguson ", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/examples/panels_demo" diff --git a/examples/preferenceExamples.lua b/examples/preferenceExamples.lua index c53ce163..84425744 100644 --- a/examples/preferenceExamples.lua +++ b/examples/preferenceExamples.lua @@ -35,7 +35,7 @@ end local script_data = {} script_data.metadata = { - name = "preferenceExamples", + name = _("preference examples"), purpose = _("example to show the different preference types that are possible"), author = "Tobias Jakobs", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/examples/preferenceExamples" diff --git a/examples/printExamples.lua b/examples/printExamples.lua index 4bedaffa..721138cd 100644 --- a/examples/printExamples.lua +++ b/examples/printExamples.lua @@ -58,7 +58,7 @@ dt.print_log("print log") local script_data = {} script_data.metadata = { - name = "printExamples", + name = _("print examples"), purpose = _("example showing the different types of printing messages"), author = "Tobias Jakobs", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/examples/printExamples" diff --git a/examples/running_os.lua b/examples/running_os.lua index 3c45cee8..69741288 100644 --- a/examples/running_os.lua +++ b/examples/running_os.lua @@ -52,7 +52,7 @@ dt.print(string.format(_("you are running: %s"), dt.configuration.running_os)) local script_data = {} script_data.metadata = { - name = "running_os", + name = _("running OS"), purpose = _("example of how to determine the operating system being used"), author = "Tobias Jakobs", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/examples/running_os" diff --git a/examples/x-touch.lua b/examples/x-touch.lua index 969fd105..bbe9bbd6 100644 --- a/examples/x-touch.lua +++ b/examples/x-touch.lua @@ -66,7 +66,7 @@ end local script_data = {} script_data.metadata = { - name = "x-touch", + name = _("x-touch"), purpose = _("example of how to control an x-touch midi device"), author = "Diederik ter Rahe", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/examples/x-touch" diff --git a/official/check_for_updates.lua b/official/check_for_updates.lua index 45ec19b0..aeb45edb 100644 --- a/official/check_for_updates.lua +++ b/official/check_for_updates.lua @@ -45,7 +45,7 @@ end local script_data = {} script_data.metadata = { - name = "check_for_updates", + name = _("check for updates"), purpose = _("check for newer darktable releases"), author = "Tobias Ellinghaus", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/official/check_for_updates" diff --git a/official/copy_paste_metadata.lua b/official/copy_paste_metadata.lua index 37eb94f4..00040c9b 100644 --- a/official/copy_paste_metadata.lua +++ b/official/copy_paste_metadata.lua @@ -40,7 +40,7 @@ end local script_data = {} script_data.metadata = { - name = "copy_paste_metadata", + name = _("copy paste metadata"), purpose = _("adds keyboard shortcuts and buttons to copy/paste metadata between images"), author = "Tobias Ellinghaus", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/official/copy_paste_metadata" diff --git a/official/delete_long_tags.lua b/official/delete_long_tags.lua index 89b192f1..c770402b 100644 --- a/official/delete_long_tags.lua +++ b/official/delete_long_tags.lua @@ -44,7 +44,7 @@ end local script_data = {} script_data.metadata = { - name = "delete_long_tags", + name = _("delete long tags"), purpose = _("delete all tags longer than a set length"), author = "Tobias Ellinghaus", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/official/delete_long_tags" diff --git a/official/delete_unused_tags.lua b/official/delete_unused_tags.lua index 62ebc95e..3815aea0 100644 --- a/official/delete_unused_tags.lua +++ b/official/delete_unused_tags.lua @@ -48,7 +48,7 @@ end local script_data = {} script_data.metadata = { - name = "delete_unused_tags", + name = _("delete unused tags"), purpose = _("delete unused tags"), author = "Tobias Ellinghaus", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/official/delete_unused_tags" diff --git a/official/enfuse.lua b/official/enfuse.lua index 317ab73d..28d6da86 100644 --- a/official/enfuse.lua +++ b/official/enfuse.lua @@ -52,7 +52,7 @@ end local script_data = {} script_data.metadata = { - name = "enfuse", + name = _("enfuse"), purpose = _("exposure blend images"), author = "Tobias Ellinghaus", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/official/enfuse" diff --git a/official/generate_image_txt.lua b/official/generate_image_txt.lua index 42f64987..c786aabf 100644 --- a/official/generate_image_txt.lua +++ b/official/generate_image_txt.lua @@ -51,7 +51,7 @@ du.check_min_api_version("7.0.0", "generate_image_txt") local script_data = {} script_data.metadata = { - name = "generate_image_txt", + name = _("generate image text"), purpose = _("overlay metadata on the selected image(s)"), author = "Tobias Ellinghaus", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/official/generate_image_txt" diff --git a/official/image_path_in_ui.lua b/official/image_path_in_ui.lua index b4440db9..74671cd6 100644 --- a/official/image_path_in_ui.lua +++ b/official/image_path_in_ui.lua @@ -44,7 +44,7 @@ end local script_data = {} script_data.metadata = { - name = "image_path_in_ui", + name = _("image path in UI"), purpose = _("print the image path in the UI"), author = "Jérémy Rosen", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/official/image_path_in_ui" diff --git a/official/import_filter_manager.lua b/official/import_filter_manager.lua index 11191504..adf83620 100644 --- a/official/import_filter_manager.lua +++ b/official/import_filter_manager.lua @@ -41,7 +41,7 @@ end local script_data = {} script_data.metadata = { - name = "import_filter_manager", + name = _("import filter manager"), purpose = _("manage import filters"), author = "Tobias Ellinghaus", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/official/import_filter_manager" diff --git a/official/import_filters.lua b/official/import_filters.lua index 44633062..87d8b0ef 100644 --- a/official/import_filters.lua +++ b/official/import_filters.lua @@ -39,7 +39,7 @@ end local script_data = {} script_data.metadata = { - name = "import_filters", + name = _("import filters"), purpose = _("import filtering"), author = "Tobias Ellinghaus & Christian Mandel", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/official/import_filters" diff --git a/official/save_selection.lua b/official/save_selection.lua index 77e82eb4..64d33b4e 100644 --- a/official/save_selection.lua +++ b/official/save_selection.lua @@ -49,7 +49,7 @@ end local script_data = {} script_data.metadata = { - name = "save_selection", + name = _("save selection"), purpose = _("shortcuts providing multiple selection buffers"), author = "Jérémy Rosen", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/official/save_selection" diff --git a/official/selection_to_pdf.lua b/official/selection_to_pdf.lua index e4f22f5e..64b9c8be 100644 --- a/official/selection_to_pdf.lua +++ b/official/selection_to_pdf.lua @@ -49,7 +49,7 @@ end local script_data = {} script_data.metadata = { - name = "selection_to_pdf", + name = _("selection to PDF"), purpose = _("generate a pdf file of selected images"), author = "Jérémy Rosen & Pascal Obry", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/official/selection_to_pdf" diff --git a/tools/executable_manager.lua b/tools/executable_manager.lua index 97421e4e..4d03be28 100644 --- a/tools/executable_manager.lua +++ b/tools/executable_manager.lua @@ -46,7 +46,7 @@ end local script_data = {} script_data.metadata = { - name = "executable_manager", + name = _("executable manager"), purpose = _("manage the list of external executables used by the lua scripts"), author = "Bill Ferguson ", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/tools/executable_manager" diff --git a/tools/get_lib_manpages.lua b/tools/get_lib_manpages.lua index 65c68046..0e641104 100644 --- a/tools/get_lib_manpages.lua +++ b/tools/get_lib_manpages.lua @@ -88,7 +88,7 @@ end local script_data = {} script_data.metadata = { - name = "get_lib_manpages", + name = _("get library man pages"), purpose = _("output the internal library documentation as man pages"), author = "Bill Ferguson ", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/tools/get_lib_manpages" diff --git a/tools/get_libdoc.lua b/tools/get_libdoc.lua index 78bbf760..2c4458d0 100644 --- a/tools/get_libdoc.lua +++ b/tools/get_libdoc.lua @@ -62,7 +62,7 @@ end local script_data = {} script_data.metadata = { - name = "get_libdoc", + name = _("get library docs"), purpose = _("retrieve and print the documentation to the console"), author = "Bill Ferguson ", help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/tools/get_libdoc" From 8e129d3825c23ddf17cc8c57802d37891474470d Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Tue, 22 Oct 2024 16:38:03 -0400 Subject: [PATCH 367/445] tools/script_manager - added translated folder names. cleaned up metadata handling (trimmed whitespace and comments) fixed bug with folder names partially matching other folder names --- tools/script_manager.lua | 44 +++++++++++++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/tools/script_manager.lua b/tools/script_manager.lua index 59c23c43..573f1825 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -132,6 +132,7 @@ sm.event_registered = false sm.widgets = {} sm.folders = {} +sm.translated_folders = {} -- set log level for functions @@ -364,8 +365,9 @@ end local function string_trim(str) local old_log_level = set_log_level(sm.log_level) - local result = string.gsub(str, "^%s+", "") - result = string.gsub(result, "%s+$", "") + local result = string.gsub(str, "^%s+", "") -- trim leading spaces + result = string.gsub(result, "%s+$", "") -- trim trailing spaces + result = string.gsub(result, ",?%s+%-%-.+$", "") -- trim trailing comma and comments restore_log_level(old_log_level) return result @@ -387,11 +389,42 @@ end -- script handling ------------------ +local function is_folder_known(folder_table, name) + local match = false + + for _, folder_name in ipairs(folder_table) do + if name == folder_name then + match = true + end + end + + return match +end + +local function find_translated_name(folder) + local translated_name = nil + + if folder == "contrib" then + translated_name = _("contributed") + elseif folder == "examples" then + translated_name = _("examples") + elseif folder == "official" then + translated_name = _("official") + elseif folder == "tools" then + translated_name = _("tools") + else + translated_name = _(folder) -- in case we get lucky and the string got translated elsewhere + end + + return translated_name +end + local function add_script_folder(folder) local old_log_level = set_log_level(sm.log_level) - if #sm.folders == 0 or not string.match(du.join(sm.folders, " "), ds.sanitize_lua(folder)) then + if #sm.folders == 0 or not is_folder_known(sm.folders, folder) then table.insert(sm.folders, folder) + table.insert(sm.translated_folders, find_translated_name(folder)) sm.scripts[folder] = {} log.msg(log.debug, "created folder " .. folder) end @@ -427,6 +460,7 @@ local function get_script_metadata(script) log.msg(log.debug, "splitting line " .. lines[i]) local parts = du.split(lines[i], " = ") parts[1] = string_trim(parts[1]) + parts[2] = string_trim(parts[2]) log.msg(log.debug, "got value " .. parts[1] .. " and data " .. parts[2]) if string.match(parts[2], "%_%(") then parts[2] = _(string_dequote(string_dei18n(parts[2]))) @@ -1378,10 +1412,10 @@ sm.widgets.folder_selector = dt.new_widget("combobox"){ changed_callback = function(self) if sm.run then pref_write("folder_selector", "integer", self.selected) - change_folder(self.value) + change_folder(sm.folders[self.selected]) end end, - table.unpack(sm.folders), + table.unpack(sm.translated_folders), } -- a script "button" consists of: From a0af01884df3d83d5ee1b65394e584934634505c Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Wed, 23 Oct 2024 10:57:29 -0400 Subject: [PATCH 368/445] official/enfuse - fixed name and widget values to be translatable --- official/enfuse.lua | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/official/enfuse.lua b/official/enfuse.lua index 28d6da86..7bda2cf4 100644 --- a/official/enfuse.lua +++ b/official/enfuse.lua @@ -72,7 +72,7 @@ local function install_module() if not enf.module_installed then dt.register_lib( "enfuse", -- plugin name - "enfuse", -- name + _("enfuse"), -- name true, -- expandable false, -- resetable {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, -- containers @@ -135,7 +135,7 @@ if enfuse_installed then if version < "4.2" then exposure_mu = dt.new_widget("slider") { - label = "exposure mu", + label = _("exposure mu"), tooltip = _("center also known as mean of gaussian weighting function (0 <= mean <= 1); default: 0.5"), hard_min = 0, hard_max = 1, @@ -144,7 +144,7 @@ if enfuse_installed then else exposure_mu = dt.new_widget("slider") { - label = "exposure optimum", + label = _("exposure optimum"), tooltip = _("optimum exposure value, usually the maximum of the weighting function (0 <= optimum <=1); default 0.5"), hard_min = 0, hard_max = 1, @@ -154,7 +154,7 @@ if enfuse_installed then local depth = dt.new_widget("combobox") { - label = "depth", + label = _("depth"), tooltip = _("the number of bits per channel of the output image"), value = dt.preferences.read("enfuse", "depth", "integer"), changed_callback = function(w) dt.preferences.write("enfuse", "depth", "integer", w.selected) end, @@ -163,7 +163,7 @@ if enfuse_installed then local blend_colorspace = dt.new_widget("combobox") { - label = "blend colorspace", + label = _("blend colorspace"), tooltip = _("force blending in selected colorspace"), changed_callback = function(w) dt.preferences.write("enfuse", "blend_colorspace", "string", w.selected) end, "", "identity", "ciecam" From 21ec2883fe51e7bf8723ee6919b6e6bb04f300ea Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Wed, 23 Oct 2024 11:42:41 -0400 Subject: [PATCH 369/445] Added translation to module name --- examples/moduleExample.lua | 2 +- official/image_path_in_ui.lua | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/moduleExample.lua b/examples/moduleExample.lua index bc432677..89c56bc2 100644 --- a/examples/moduleExample.lua +++ b/examples/moduleExample.lua @@ -75,7 +75,7 @@ local function install_module() -- https://www.darktable.org/lua-api/index.html#darktable_register_lib dt.register_lib( "exampleModule", -- Module name - "exampleModule", -- name + _("example module"), -- name true, -- expandable false, -- resetable {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, -- containers diff --git a/official/image_path_in_ui.lua b/official/image_path_in_ui.lua index 74671cd6..2f23184a 100644 --- a/official/image_path_in_ui.lua +++ b/official/image_path_in_ui.lua @@ -63,7 +63,7 @@ local main_label = dt.new_widget("label"){selectable = true, ellipsize = "middle local function install_module() if not ipiu.module_installed then - dt.register_lib("image_path_no_ui","selected images path",true,false,{ + dt.register_lib("image_path_no_ui",_("selected images path"),true,false,{ [dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_LEFT_CENTER",300} }, main_label ) From 5e4ba9da5eb2f157ee7242f96870d687cebd03a5 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Mon, 28 Oct 2024 15:49:32 -0400 Subject: [PATCH 370/445] contrib/rename_images - fixed call to sting library for building the string substitution list --- contrib/rename_images.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/rename_images.lua b/contrib/rename_images.lua index a0d37e99..0093c540 100644 --- a/contrib/rename_images.lua +++ b/contrib/rename_images.lua @@ -141,7 +141,7 @@ local function do_rename(images) for i, image in ipairs(images) do if job.valid then job.percent = i / #images - ds.build_substitution_list(image, i, pattern, USER, PICTURES, HOME, DESKTOP) + ds.build_substitute_list(image, i, pattern, USER, PICTURES, HOME, DESKTOP) local new_name = ds.substitute_list(pattern) if new_name == -1 then dt.print(_("unable to do variable substitution, exiting...")) From 1b5cb1ae6ef64173872f556d86ba24f8303769d2 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Mon, 28 Oct 2024 20:18:22 -0400 Subject: [PATCH 371/445] lib/dtutils/string - corrected constrant names in assignment --- lib/dtutils/string.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/dtutils/string.lua b/lib/dtutils/string.lua index ff8f73ef..c142b1a1 100644 --- a/lib/dtutils/string.lua +++ b/lib/dtutils/string.lua @@ -309,9 +309,9 @@ local function _should_be_sanitized(str) local SAFE_POSIX_FILENAME_CHARS = "[^%w/._%-]+" local SAFE_WIN_FILENAME_CHARS = "[^%w\\._%-:]+" - local pattern = SAFE_POSIX_STRING_CHARS + local pattern = SAFE_POSIX_FILENAME_CHARS if dt.configuration.running_os == "windows" then - pattern = SAFE_WIN_STRING_CHARS + pattern = SAFE_WIN_FILENAME_CHARS end log.log_level(dtutils_string.log_level) From e7dbd6e369cb0e402f9f00894edfbbf1c38adcec Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Mon, 28 Oct 2024 20:41:02 -0400 Subject: [PATCH 372/445] lib/dtutils/string - fixed constant names to correctly define the patterns as the unsafe filename characters. --- lib/dtutils/string.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/dtutils/string.lua b/lib/dtutils/string.lua index c142b1a1..c8a1ce98 100644 --- a/lib/dtutils/string.lua +++ b/lib/dtutils/string.lua @@ -306,12 +306,12 @@ end local function _should_be_sanitized(str) local old_log_level = log.log_level() local result = false - local SAFE_POSIX_FILENAME_CHARS = "[^%w/._%-]+" - local SAFE_WIN_FILENAME_CHARS = "[^%w\\._%-:]+" + local UNSAFE_POSIX_FILENAME_CHARS = "[^%w/._%-]+" + local UNSAFE_WIN_FILENAME_CHARS = "[^%w\\._%-:]+" - local pattern = SAFE_POSIX_FILENAME_CHARS + local pattern = UNSAFE_POSIX_FILENAME_CHARS if dt.configuration.running_os == "windows" then - pattern = SAFE_WIN_FILENAME_CHARS + pattern = UNSAFE_WIN_FILENAME_CHARS end log.log_level(dtutils_string.log_level) From c5711880d3528c860e4721c302fd8b6206c0704d Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Tue, 29 Oct 2024 12:23:25 -0400 Subject: [PATCH 373/445] contrib/autostyle - added check to make sure autostyle has been configured so that it doesn't print out a confusing error message. Fixed preference to use translated script name, (script_data.metadata.name). --- contrib/autostyle.lua | 110 +++++++++++++++++++++++------------------- 1 file changed, 60 insertions(+), 50 deletions(-) diff --git a/contrib/autostyle.lua b/contrib/autostyle.lua index 093c29a3..a5feda3f 100644 --- a/contrib/autostyle.lua +++ b/contrib/autostyle.lua @@ -53,6 +53,8 @@ end local script_data = {} +local have_not_printed_config_message = true + script_data.metadata = { name = _("auto style"), purpose = _("automatically apply a style based on image EXIF tag"), @@ -101,56 +103,62 @@ end local function autostyle_apply_one_image (image) local pref = darktable.preferences.read("autostyle", "exif_tag", "string") - -- We need the tag, the value and the style_name provided from the configuration string - local tag, value, style_name = string.match(pref, "(%g+)%s*=%s*(%g+)%s*=>%s*(%g+)") - -- check they all exist (correct syntax) - if (not tag) then - darktable.print(string.format(_("EXIF tag not found in %s"), pref)) - return 0 - end - if (not value) then - darktable.print(string.format(_("value to match not found in %s"), pref)) - return 0 - end - if (not style_name) then - darktable.print(string.format(_("style name not found in %s"), pref)) - return 0 - end - if not filelib.check_if_bin_exists("exiftool") then - darktable.print(_("can't find exiftool")) - return 0 - end - - - -- First find the style (we have its name) - local styles = darktable.styles - local style - for _, s in ipairs(styles) do - if s.name == style_name then - style = s - end - end - if (not style) then - darktable.print(string.format(_("style not found for autostyle: %s"), style_name)) - return 0 - end - - -- Apply the style to image, if it is tagged - local ok, auto_dr_attr = pcall(exiftool_attribute, image.path .. '/' .. image.filename,tag) - --darktable.print_error("dr_attr:" .. auto_dr_attr) - -- If the lookup fails, stop here - if (not ok) then - darktable.print(string.format(_("couldn't get attribute %s from exiftool's output"), auto_dr_attr)) - return 0 - end - if auto_dr_attr == value then - darktable.print_log("Image " .. image.filename .. ": autostyle automatically applied " .. pref) - darktable.styles.apply(style,image) - return 1 - else - darktable.print_log("Image " .. image.filename .. ": autostyle not applied, exif tag " .. pref .. " not matched: " .. auto_dr_attr) - return 0 + if pref and string.len(pref) >= 6 then + -- We need the tag, the value and the style_name provided from the configuration string + local tag, value, style_name = string.match(pref, "(%g+)%s*=%s*(%g+)%s*=>%s*(%g+)") + + -- check they all exist (correct syntax) + if (not tag) then + darktable.print(string.format(_("EXIF tag not found in %s"), pref)) + return 0 + end + if (not value) then + darktable.print(string.format(_("value to match not found in %s"), pref)) + return 0 + end + if (not style_name) then + darktable.print(string.format(_("style name not found in %s"), pref)) + return 0 + end + if not filelib.check_if_bin_exists("exiftool") then + darktable.print(_("can't find exiftool")) + return 0 + end + + + -- First find the style (we have its name) + local styles = darktable.styles + local style + for _, s in ipairs(styles) do + if s.name == style_name then + style = s + end + end + if (not style) then + darktable.print(string.format(_("style not found for autostyle: %s"), style_name)) + return 0 + end + + -- Apply the style to image, if it is tagged + local ok, auto_dr_attr = pcall(exiftool_attribute, image.path .. '/' .. image.filename,tag) + --darktable.print_error("dr_attr:" .. auto_dr_attr) + -- If the lookup fails, stop here + if (not ok) then + darktable.print(string.format(_("couldn't get attribute %s from exiftool's output"), auto_dr_attr)) + return 0 + end + if auto_dr_attr == value then + darktable.print_log("Image " .. image.filename .. ": autostyle automatically applied " .. pref) + darktable.styles.apply(style,image) + return 1 + else + darktable.print_log("Image " .. image.filename .. ": autostyle not applied, exif tag " .. pref .. " not matched: " .. auto_dr_attr) + return 0 + end + elseif have_not_printed_config_message then + have_not_printed_config_message = false + darktable.print(string.format(_("%s is not configured, please configure the preference in Lua options"), script_data.metadata.name)) end end @@ -180,7 +188,9 @@ end darktable.register_event("autostyle", "shortcut", autostyle_apply, _("apply your chosen style from exiftool tags")) -darktable.preferences.register("autostyle", "exif_tag", "string", "Autostyle: EXIF_tag=value=>style", _("apply a style automatically if an EXIF tag matches value, find the tag with exiftool"), "") +darktable.preferences.register("autostyle", "exif_tag", "string", + string.format("%s: EXIF_tag=value=>style", script_data.metadata.name), + _("apply a style automatically if an EXIF tag matches value, find the tag with exiftool"), "") darktable.register_event("autostyle", "post-import-image", autostyle_apply_one_image_event) From b1e6bb8daa90787f1ec31b9750a38a5eeba7c3c0 Mon Sep 17 00:00:00 2001 From: Electro707 Date: Sat, 2 Nov 2024 21:29:53 -0400 Subject: [PATCH 374/445] Added sanitization around path for mkdir and rmdir --- lib/dtutils/file.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/dtutils/file.lua b/lib/dtutils/file.lua index 9a8eee90..fc2ee9ef 100644 --- a/lib/dtutils/file.lua +++ b/lib/dtutils/file.lua @@ -812,7 +812,7 @@ dtutils_file.libdoc.functions["mkdir"] = { function dtutils_file.mkdir(path) if not dtutils_file.check_if_file_exists(path) then local mkdir_cmd = dt.configuration.running_os == "windows" and "mkdir" or "mkdir -p" - return dsys.external_command(mkdir_cmd.." "..path) + return dsys.external_command(mkdir_cmd.." "..dtutils_file.sanitize_filename(path)) else return 0 end @@ -837,7 +837,7 @@ dtutils_file.libdoc.functions["rmdir"] = { function dtutils_file.rmdir(path) local rm_cmd = dt.configuration.running_os == "windows" and "rmdir /S /Q" or "rm -r" - return dsys.external_command(rm_cmd.." "..path) + return dsys.external_command(rm_cmd.." "..dtutils_file.sanitize_filename(path)) end dtutils_file.libdoc.functions["create_tmp_file"] = { From 8581af29d2baae17108d6ef5305eebd6f3bbedbc Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Wed, 13 Nov 2024 19:05:16 -0500 Subject: [PATCH 375/445] lib/dtutils - added a gen_uuid() function to generate a UUID string for use as a unique identifier. --- lib/dtutils.lua | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/lib/dtutils.lua b/lib/dtutils.lua index c8331cbd..6721eac9 100644 --- a/lib/dtutils.lua +++ b/lib/dtutils.lua @@ -374,7 +374,7 @@ dtutils.libdoc.functions["deprecated"] = { du.deprecated(script_name, removal_string) script_name - name of the script being deprecated - removal_strubg - a string explaining when the script will be removed]], + removal_string - a string explaining when the script will be removed]], Description = [[deprecated prints an error message saying the script is deprecated and when it will be removed]], Return_Value = [[]], Limitations = [[]], @@ -391,5 +391,40 @@ function dtutils.deprecated(script_name, removal_string) dt.print_error("WARNING: " .. script_name .. " is deprecated and will be removed in " .. removal_string) end +dtutils.libdoc.functions["gen_uuid"] = { + Name = [[gen_uuid]], + Synopsis = [[generate a UUID string]], + Usage = [[local du = require "lib/dtutils" + + uuid = du.gen_uuid(case) + case - "upper" or "lower" to specify the case of the UUID string]], + Description = [[gen_uuid prints an error message saying the script is gen_uuid and when it will be removed]], + Return_Value = [[uuid - string - a hexidecimal string representing the UUID in the requested case]], + Limitations = [[]], + Example = [[]], + See_Also = [[]], + Reference = [[https://gist.github.com/jrus/3197011]], + License = [[]], + Copyright = [[]], +} + +function dtutils.gen_uuid(case) + local template = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx' + + -- seed with os.time in seconds and add an extra degree of random for multiple calls in the same second + math.randomseed(os.time(), math.random(0, 65536)) + + local uuid = string.gsub(template, '[xy]', function (c) + local v = (c == 'x') and math.random(0, 0xf) or math.random(8, 0xb) + return string.format('%x', v) + end + ) + + if case and case == "upper" then + uuid = string.upper(uuid) + end + + return uuid +end return dtutils From 96b7ba24bc8c84c6ac4cda3da9b14182418148db Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Wed, 13 Nov 2024 23:09:14 -0500 Subject: [PATCH 376/445] official/apply_camera_style - make the translatable strings contrib/hif_group_leader translation safe contrib/jpg_group_leader --- contrib/hif_group_leader.lua | 4 ++-- contrib/jpg_group_leader.lua | 4 ++-- official/apply_camera_style.lua | 6 ++---- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/contrib/hif_group_leader.lua b/contrib/hif_group_leader.lua index f39d3ff0..412eea07 100644 --- a/contrib/hif_group_leader.lua +++ b/contrib/hif_group_leader.lua @@ -186,7 +186,7 @@ dt.register_event(MODULE .. "_collect", "shortcut", local images = dt.collection make_existing_hif_group_leader(images) end, - string.format(_("make hif group leader for %s", _("collection"))) + _("make hif group leader for collection") ) dt.register_event(MODULE .. "_select", "shortcut", @@ -194,7 +194,7 @@ dt.register_event(MODULE .. "_select", "shortcut", local images = dt.gui.selection() make_existing_hif_group_leader(images) end, - string.format(_("make hif group leader for %s", _("selection"))) + _("make hif group leader for selection") ) return script_data \ No newline at end of file diff --git a/contrib/jpg_group_leader.lua b/contrib/jpg_group_leader.lua index 8391a670..733071ed 100644 --- a/contrib/jpg_group_leader.lua +++ b/contrib/jpg_group_leader.lua @@ -186,7 +186,7 @@ dt.register_event(MODULE .. "_collect", "shortcut", local images = dt.collection make_existing_jpg_group_leader(images) end, - string.format(_("make jpg group leader for %s", _("collection"))) + _("make jpg group leader for collection") ) dt.register_event(MODULE .. "_select", "shortcut", @@ -194,7 +194,7 @@ dt.register_event(MODULE .. "_select", "shortcut", local images = dt.gui.selection() make_existing_jpg_group_leader(images) end, - string.format(_("make jpg group leader for %s", _("selection"))) + _("make jpg group leader for selection") ) return script_data \ No newline at end of file diff --git a/official/apply_camera_style.lua b/official/apply_camera_style.lua index 8c8aeae4..c75974bb 100644 --- a/official/apply_camera_style.lua +++ b/official/apply_camera_style.lua @@ -463,18 +463,16 @@ script_data.destroy = destroy -- E V E N T S -- - - - - - - - - - - - - - - - - - - - - - - - -local shortcut_string = _("apply darktable camera styles to %s") - dt.register_event(MODULE, "shortcut", function(event, shortcut) apply_camera_style(true) - end, string.format(shortcut_string, _("collection")) + end, _("apply darktable camera styles to collection") ) dt.register_event(MODULE, "shortcut", function(event, shortcut) apply_camera_style(false) - end, string.format(shortcut_string, _("selection")) + end, _("apply darktable camera styles to selection") ) dt.register_event(MODULE, "post-import-image", From 7e3c6471ff0ed65a3b2a8d516eda0879747d1325 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sun, 1 Dec 2024 12:27:16 -0500 Subject: [PATCH 377/445] official/apply_camera_sytle - ensure style is only applied to raw images. Fixed comment. --- official/apply_camera_style.lua | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/official/apply_camera_style.lua b/official/apply_camera_style.lua index c75974bb..aac49d16 100644 --- a/official/apply_camera_style.lua +++ b/official/apply_camera_style.lua @@ -64,7 +64,7 @@ local CS = dt.configuration.running_os == "windows" and "&" or ";" -- A P I C H E C K -- - - - - - - - - - - - - - - - - - - - - - - - -du.check_min_api_version("9.4.0", MODULE) -- styles use filmic V7 which appeared in darktable 4.4 +du.check_min_api_version("9.4.0", MODULE) -- camera styles added to darktable 5.0 -- - - - - - - - - - - - - - - - - - - - - - - - - - @@ -477,7 +477,9 @@ dt.register_event(MODULE, "shortcut", dt.register_event(MODULE, "post-import-image", function(event, image) - table.insert(acs.imported_images, image) + if image.is_raw then + table.insert(acs.imported_images, image) + end end ) From e4e194b0ec250991348d472f7531e724cb429250 Mon Sep 17 00:00:00 2001 From: Krzysztof Kotowicz Date: Mon, 2 Dec 2024 09:01:48 +0100 Subject: [PATCH 378/445] Fixed $(FILE.NAME) variable substitution According to comments and https://docs.darktable.org/usermanual/4.6/en/special-topics/variables/ it should be a basename. --- lib/dtutils/string.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/dtutils/string.lua b/lib/dtutils/string.lua index c8a1ce98..a710201b 100644 --- a/lib/dtutils/string.lua +++ b/lib/dtutils/string.lua @@ -748,7 +748,7 @@ function dtutils_string.build_substitute_list(image, sequence, variable_string, local replacements = {image.film.path, -- ROLL.NAME image.path, -- FILE.FOLDER - image.filename, -- FILE.NAME + dtutils_string.get_basename(image.filename),-- FILE.NAME dtutils_string.get_filetype(image.filename),-- FILE.EXTENSION image.id, -- ID image.duplicate_index, -- VERSION From 3fa913d68ad75ea3ce49d706c670a0bd557a4872 Mon Sep 17 00:00:00 2001 From: Krzysztof Kotowicz Date: Mon, 2 Dec 2024 09:56:45 +0100 Subject: [PATCH 379/445] Fixed $ROLL.NAME substitution Accd to https://github.com/darktable-org/darktable/blob/57d3ad4bd30372b1f7ae7368f6887d3292269b2a/src/common/variables.c#L660 it should be a basename of the file path. --- lib/dtutils/string.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/dtutils/string.lua b/lib/dtutils/string.lua index a710201b..2be4ef6b 100644 --- a/lib/dtutils/string.lua +++ b/lib/dtutils/string.lua @@ -746,7 +746,7 @@ function dtutils_string.build_substitute_list(image, sequence, variable_string, local version_multi = #image:get_group_members() > 1 and image.version or "" - local replacements = {image.film.path, -- ROLL.NAME + local replacements = {dtutils_string.get_basename(image.film.path),-- ROLL.NAME image.path, -- FILE.FOLDER dtutils_string.get_basename(image.filename),-- FILE.NAME dtutils_string.get_filetype(image.filename),-- FILE.EXTENSION From da275c2a662466ded7170c3aa6c4fb98bcc81673 Mon Sep 17 00:00:00 2001 From: Krzysztof Kotowicz Date: Mon, 2 Dec 2024 10:11:23 +0100 Subject: [PATCH 380/445] Fixed $(VERSION.IF_MULTI) Variable substitution actually errored out when duplicates were present. --- lib/dtutils/string.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/dtutils/string.lua b/lib/dtutils/string.lua index 2be4ef6b..7648f6f6 100644 --- a/lib/dtutils/string.lua +++ b/lib/dtutils/string.lua @@ -744,7 +744,7 @@ function dtutils_string.build_substitute_list(image, sequence, variable_string, string.match(image.exif_datetime_taken, "(%d+):(%d+):(%d+) (%d+):(%d+):(%d+)$") end - local version_multi = #image:get_group_members() > 1 and image.version or "" + local version_multi = #image:get_group_members() > 1 and image.duplicate_index or "" local replacements = {dtutils_string.get_basename(image.film.path),-- ROLL.NAME image.path, -- FILE.FOLDER From 9bfda93b510d16fb2b0d989626312f4449a4e367 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Wed, 13 Nov 2024 23:09:14 -0500 Subject: [PATCH 381/445] official/apply_camera_style - make the translatable strings contrib/hif_group_leader translation safe contrib/jpg_group_leader --- contrib/hif_group_leader.lua | 4 ++-- contrib/jpg_group_leader.lua | 4 ++-- official/apply_camera_style.lua | 6 ++---- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/contrib/hif_group_leader.lua b/contrib/hif_group_leader.lua index f39d3ff0..412eea07 100644 --- a/contrib/hif_group_leader.lua +++ b/contrib/hif_group_leader.lua @@ -186,7 +186,7 @@ dt.register_event(MODULE .. "_collect", "shortcut", local images = dt.collection make_existing_hif_group_leader(images) end, - string.format(_("make hif group leader for %s", _("collection"))) + _("make hif group leader for collection") ) dt.register_event(MODULE .. "_select", "shortcut", @@ -194,7 +194,7 @@ dt.register_event(MODULE .. "_select", "shortcut", local images = dt.gui.selection() make_existing_hif_group_leader(images) end, - string.format(_("make hif group leader for %s", _("selection"))) + _("make hif group leader for selection") ) return script_data \ No newline at end of file diff --git a/contrib/jpg_group_leader.lua b/contrib/jpg_group_leader.lua index 8391a670..733071ed 100644 --- a/contrib/jpg_group_leader.lua +++ b/contrib/jpg_group_leader.lua @@ -186,7 +186,7 @@ dt.register_event(MODULE .. "_collect", "shortcut", local images = dt.collection make_existing_jpg_group_leader(images) end, - string.format(_("make jpg group leader for %s", _("collection"))) + _("make jpg group leader for collection") ) dt.register_event(MODULE .. "_select", "shortcut", @@ -194,7 +194,7 @@ dt.register_event(MODULE .. "_select", "shortcut", local images = dt.gui.selection() make_existing_jpg_group_leader(images) end, - string.format(_("make jpg group leader for %s", _("selection"))) + _("make jpg group leader for selection") ) return script_data \ No newline at end of file diff --git a/official/apply_camera_style.lua b/official/apply_camera_style.lua index 8c8aeae4..c75974bb 100644 --- a/official/apply_camera_style.lua +++ b/official/apply_camera_style.lua @@ -463,18 +463,16 @@ script_data.destroy = destroy -- E V E N T S -- - - - - - - - - - - - - - - - - - - - - - - - -local shortcut_string = _("apply darktable camera styles to %s") - dt.register_event(MODULE, "shortcut", function(event, shortcut) apply_camera_style(true) - end, string.format(shortcut_string, _("collection")) + end, _("apply darktable camera styles to collection") ) dt.register_event(MODULE, "shortcut", function(event, shortcut) apply_camera_style(false) - end, string.format(shortcut_string, _("selection")) + end, _("apply darktable camera styles to selection") ) dt.register_event(MODULE, "post-import-image", From b5c93e55d16e52e3d3bdafe603dac85cdb3ac895 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Wed, 13 Nov 2024 19:05:16 -0500 Subject: [PATCH 382/445] lib/dtutils - added a gen_uuid() function to generate a UUID string for use as a unique identifier. --- lib/dtutils.lua | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/lib/dtutils.lua b/lib/dtutils.lua index c8331cbd..6721eac9 100644 --- a/lib/dtutils.lua +++ b/lib/dtutils.lua @@ -374,7 +374,7 @@ dtutils.libdoc.functions["deprecated"] = { du.deprecated(script_name, removal_string) script_name - name of the script being deprecated - removal_strubg - a string explaining when the script will be removed]], + removal_string - a string explaining when the script will be removed]], Description = [[deprecated prints an error message saying the script is deprecated and when it will be removed]], Return_Value = [[]], Limitations = [[]], @@ -391,5 +391,40 @@ function dtutils.deprecated(script_name, removal_string) dt.print_error("WARNING: " .. script_name .. " is deprecated and will be removed in " .. removal_string) end +dtutils.libdoc.functions["gen_uuid"] = { + Name = [[gen_uuid]], + Synopsis = [[generate a UUID string]], + Usage = [[local du = require "lib/dtutils" + + uuid = du.gen_uuid(case) + case - "upper" or "lower" to specify the case of the UUID string]], + Description = [[gen_uuid prints an error message saying the script is gen_uuid and when it will be removed]], + Return_Value = [[uuid - string - a hexidecimal string representing the UUID in the requested case]], + Limitations = [[]], + Example = [[]], + See_Also = [[]], + Reference = [[https://gist.github.com/jrus/3197011]], + License = [[]], + Copyright = [[]], +} + +function dtutils.gen_uuid(case) + local template = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx' + + -- seed with os.time in seconds and add an extra degree of random for multiple calls in the same second + math.randomseed(os.time(), math.random(0, 65536)) + + local uuid = string.gsub(template, '[xy]', function (c) + local v = (c == 'x') and math.random(0, 0xf) or math.random(8, 0xb) + return string.format('%x', v) + end + ) + + if case and case == "upper" then + uuid = string.upper(uuid) + end + + return uuid +end return dtutils From ed9f2bb0d055754c12058098af4d53336453f7cc Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sun, 1 Dec 2024 12:27:16 -0500 Subject: [PATCH 383/445] official/apply_camera_sytle - ensure style is only applied to raw images. Fixed comment. --- official/apply_camera_style.lua | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/official/apply_camera_style.lua b/official/apply_camera_style.lua index c75974bb..aac49d16 100644 --- a/official/apply_camera_style.lua +++ b/official/apply_camera_style.lua @@ -64,7 +64,7 @@ local CS = dt.configuration.running_os == "windows" and "&" or ";" -- A P I C H E C K -- - - - - - - - - - - - - - - - - - - - - - - - -du.check_min_api_version("9.4.0", MODULE) -- styles use filmic V7 which appeared in darktable 4.4 +du.check_min_api_version("9.4.0", MODULE) -- camera styles added to darktable 5.0 -- - - - - - - - - - - - - - - - - - - - - - - - - - @@ -477,7 +477,9 @@ dt.register_event(MODULE, "shortcut", dt.register_event(MODULE, "post-import-image", function(event, image) - table.insert(acs.imported_images, image) + if image.is_raw then + table.insert(acs.imported_images, image) + end end ) From 9bceb79a150c41f4aaa3e3546722ed03fc4ca57d Mon Sep 17 00:00:00 2001 From: Krzysztof Kotowicz Date: Mon, 2 Dec 2024 09:01:48 +0100 Subject: [PATCH 384/445] Fixed $(FILE.NAME) variable substitution According to comments and https://docs.darktable.org/usermanual/4.6/en/special-topics/variables/ it should be a basename. --- lib/dtutils/string.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/dtutils/string.lua b/lib/dtutils/string.lua index c8a1ce98..a710201b 100644 --- a/lib/dtutils/string.lua +++ b/lib/dtutils/string.lua @@ -748,7 +748,7 @@ function dtutils_string.build_substitute_list(image, sequence, variable_string, local replacements = {image.film.path, -- ROLL.NAME image.path, -- FILE.FOLDER - image.filename, -- FILE.NAME + dtutils_string.get_basename(image.filename),-- FILE.NAME dtutils_string.get_filetype(image.filename),-- FILE.EXTENSION image.id, -- ID image.duplicate_index, -- VERSION From d27df0c0ed31a26bd9b68eca5831e49751fce12a Mon Sep 17 00:00:00 2001 From: Krzysztof Kotowicz Date: Mon, 2 Dec 2024 09:56:45 +0100 Subject: [PATCH 385/445] Fixed $ROLL.NAME substitution Accd to https://github.com/darktable-org/darktable/blob/57d3ad4bd30372b1f7ae7368f6887d3292269b2a/src/common/variables.c#L660 it should be a basename of the file path. --- lib/dtutils/string.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/dtutils/string.lua b/lib/dtutils/string.lua index a710201b..2be4ef6b 100644 --- a/lib/dtutils/string.lua +++ b/lib/dtutils/string.lua @@ -746,7 +746,7 @@ function dtutils_string.build_substitute_list(image, sequence, variable_string, local version_multi = #image:get_group_members() > 1 and image.version or "" - local replacements = {image.film.path, -- ROLL.NAME + local replacements = {dtutils_string.get_basename(image.film.path),-- ROLL.NAME image.path, -- FILE.FOLDER dtutils_string.get_basename(image.filename),-- FILE.NAME dtutils_string.get_filetype(image.filename),-- FILE.EXTENSION From 87ca8bde27219034a6e250d19cea14f0be6f1ca6 Mon Sep 17 00:00:00 2001 From: Krzysztof Kotowicz Date: Mon, 2 Dec 2024 10:11:23 +0100 Subject: [PATCH 386/445] Fixed $(VERSION.IF_MULTI) Variable substitution actually errored out when duplicates were present. --- lib/dtutils/string.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/dtutils/string.lua b/lib/dtutils/string.lua index 2be4ef6b..7648f6f6 100644 --- a/lib/dtutils/string.lua +++ b/lib/dtutils/string.lua @@ -744,7 +744,7 @@ function dtutils_string.build_substitute_list(image, sequence, variable_string, string.match(image.exif_datetime_taken, "(%d+):(%d+):(%d+) (%d+):(%d+):(%d+)$") end - local version_multi = #image:get_group_members() > 1 and image.version or "" + local version_multi = #image:get_group_members() > 1 and image.duplicate_index or "" local replacements = {dtutils_string.get_basename(image.film.path),-- ROLL.NAME image.path, -- FILE.FOLDER From 3b520d62918dc21129bd0672ea0b90b1edbfd9aa Mon Sep 17 00:00:00 2001 From: Krzysztof Kotowicz Date: Fri, 23 Aug 2024 17:53:03 +0200 Subject: [PATCH 387/445] Added UltraHDR export plugin to generate UltraHDR JPEG images. --- contrib/ultrahdr.lua | 270 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 270 insertions(+) create mode 100644 contrib/ultrahdr.lua diff --git a/contrib/ultrahdr.lua b/contrib/ultrahdr.lua new file mode 100644 index 00000000..f3b4d193 --- /dev/null +++ b/contrib/ultrahdr.lua @@ -0,0 +1,270 @@ +--[[ + + UltraHDR storage for darktable + + copyright (c) 2024 Krzysztof Kotowicz + + darktable is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + darktable is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with darktable. If not, see . + +]] +--[[ + +ULTRAHDR +Add a new storage option to generate UltraHDR JPG images. + +https://developer.android.com/media/platform/hdr-image-format + +Of all exported files, the storage detects pairs of files generated from the same source image, +assuming the first one encountered is the base SDR image, and the second one is the gainmap +(alternatively, you can tag the gainmaps with a "gainmap" tag). + +The images are merged using libultrahdr example application (ultrahdr_app). + +ADDITIONAL SOFTWARE NEEDED FOR THIS SCRIPT +* ultrahdr_app (from https://github.com/google/libultrahdr example dir) +* exiftool + +USAGE +* require this file from your main luarc config file +* set exiftool and libultrahdr_app tool paths + +This plugin will add a new storage option. + +]] +local dt = require "darktable" +local du = require "lib/dtutils" +local df = require "lib/dtutils.file" +local log = require "lib/dtutils.log" +local dtsys = require "lib/dtutils.system" +local gettext = dt.gettext.gettext + +local namespace = 'module_ultrahdr' + +-- works with darktable API version from 5.0.0 on +du.check_min_api_version("7.0.0", "ultrahdr") + +dt.gettext.bindtextdomain("ultrahdr", dt.configuration.config_dir .. "/lua/locale/") + +local function _(msgid) + return gettext(msgid) +end + +-- return data structure for script_manager + +local script_data = {} + +script_data.metadata = { + name = "ultrahdr", + purpose = _("generate UltraHDR images"), + author = "Krzysztof Kotowicz" +} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them + +local function image_path(image) + return image.path .. "/" .. image.filename +end + +local function merge_ultrahdr(base, gainmap, ultrahdr_app, exiftool, metadata, output) + local base_tmp = df.chop_filetype(base) .. ".tmp" + local hdr = df.chop_filetype(base) .. "_hdr." .. df.get_filetype(base) + dtsys.external_command(exiftool .. " -all= " .. df.sanitize_filename(base) .. " -o " .. + df.sanitize_filename(base_tmp)) + dtsys.external_command(exiftool .. " -all= " .. df.sanitize_filename(gainmap) .. " -overwrite_original") + dtsys.external_command(ultrahdr_app .. " -m 0 -i " .. df.sanitize_filename(base_tmp) .. " -g " .. + df.sanitize_filename(gainmap) .. " -f " .. df.sanitize_filename(metadata) .. " -z " .. + df.sanitize_filename(hdr)) + dtsys.external_command(exiftool .. " -tagsfromfile " .. df.sanitize_filename(base) .. " -all>all " .. + df.sanitize_filename(hdr) .. " -overwrite_original") + df.file_move(hdr, df.create_unique_filename(output .. "/" .. df.get_filename(hdr))) + os.remove(base) + os.remove(base_tmp) + os.remove(gainmap) +end + +local function assert_settings_correct() + local ultrahdr_app = df.check_if_bin_exists("ultrahdr_app") + log.msg(log.debug, "ultrahdr_app set to ", ultrahdr_app) + local exiftool = df.check_if_bin_exists("exiftool") + log.msg(log.debug, "exiftool set to ", exiftool) + local metadata = dt.preferences.read("ultrahdr", "metadata path", "string") + log.msg(log.debug, "metadata set to ", metadata) + local output = dt.preferences.read("ultrahdr", "output dir", "string") + log.msg(log.debug, "output dir set to ", output) + + if not ultrahdr_app then + dt.print(_("ultrahdr_app is not found, did you set the path?")) + log.msg(log.error, "ultrahdr_app executable not found. Check if the executable is installed.") + log.msg(log.error, "If the executable is installed, check that the path is set correctly.") + return + end + + if not exiftool then + dt.print(_("exiftool is not found, did you set the path?")) + log.msg(log.error, "exiftool executable not found. Check if the executable is installed.") + log.msg(log.error, "If the executable is installed, check that the path is set correctly.") + return + end + + if not df.check_if_file_exists(metadata) then + dt.print(_("metadata file not found, did you set the path?")) + log.msg(log.error, "metadata file not found.") + return + end + + return ultrahdr_app, exiftool, metadata, output +end + +local function create_hdr(storage, image_table, extra_data) -- finalize + local saved_log_level = log.log_level() + log.log_level(log.info) + + local ultrahdr_app, exiftool, metadata, output = assert_settings_correct() + if not ultrahdr_app or not exiftool then + return + end + local merged = 0 + for ignore, v in pairs(extra_data) do + if not v then + goto continue + end + local msg = string.format(_("Merging %s and %s"), df.get_filename(image_table[v["base"]]), + df.get_filename(image_table[v["gainmap"]])) + log.msg(log.info, msg) + dt.print(msg) + merge_ultrahdr(image_table[v["base"]], image_table[v["gainmap"]], ultrahdr_app, exiftool, metadata, output) + merged = merged + 1 + ::continue:: + end + for ignore, v in pairs(image_table) do + if df.check_if_file_exists(v) then os.remove(v) end + end + dt.print(string.format(_("Created %d UltraHDR image(s) in %s"), merged, output)) + log.log_level(saved_log_level) +end + +local function destroy() + dt.destroy_storage(namespace) +end + +local function is_supported(storage, format) + if format.extension == "jpg" then + return true + end + return false +end + +local function initialize(storage, format, images, high_quality, extra_data) + local saved_log_level = log.log_level() + log.log_level(log.info) + local tags = nil + -- Group images into base, gainmap pairs based on their original filename. + -- Assume that the first encountered image from each filename is a base one, unless it has a "gainmap" tag. + for k, v in pairs(images) do + local has_gainmap_tag = false + tags = dt.tags.get_tags(v) + for ignore, tag in pairs(tags) do + if tag.name == "gainmap" then + has_gainmap_tag = true + end + end + local key = image_path(v) + if extra_data[key] == nil then + extra_data[key] = {} + end + if extra_data[key]["base"] or has_gainmap_tag then + extra_data[key]["gainmap"] = v + else + extra_data[key]["base"] = v + end + end + -- remove incomplete entries + for k, v in pairs(extra_data) do + if not v["base"] or not v["gainmap"] then + extra_data[k] = nil + end + end + log.log_level(saved_log_level) + return nil +end + +local function metadata_file_widget() + local box_widgets = {} + table.insert(box_widgets, dt.new_widget("label") { + label = "libultrahdr metadata file" + }) + local path = dt.preferences.read("ultrahdr", "metadata path", "string") + if not path then + path = "" + end + table.insert(box_widgets, dt.new_widget("file_chooser_button") { + title = "select libultrahdr metadata path", + value = path, + is_directory = false, + changed_callback = function(self) + if df.check_if_file_exists(self.value) then + dt.preferences.write("ultrahdr", "metadata path", "string", self.value) + end + end + }) + + local box = dt.new_widget("box") { + orientation = "vertical", + table.unpack(box_widgets) + } + return box +end + +local function output_directory_widget() + local box_widgets = {} + table.insert(box_widgets, dt.new_widget("label") { + label = "output directory" + }) + local path = dt.preferences.read("ultrahdr", "output dir", "string") + if not path then + path = "" + end + table.insert(box_widgets, dt.new_widget("file_chooser_button") { + title = "select libultrahdr metadata path", + value = path, + is_directory = true, + changed_callback = function(self) + dt.preferences.write("ultrahdr", "output dir", "string", self.value) + end + }) + + local box = dt.new_widget("box") { + orientation = "vertical", + table.unpack(box_widgets) + } + return box +end + +local ultrahdr_widget = dt.new_widget("box") { + orientation = "vertical", + metadata_file_widget(), + output_directory_widget(), + df.executable_path_widget({"ultrahdr_app", "exiftool"}) +} + +-- Register + +dt.register_storage(namespace, _("UltraHDR JPEG"), nil, create_hdr, is_supported, initialize, ultrahdr_widget) + +script_data.destroy = destroy + +return script_data From b963eaa38ccabf69dc47c9b6de4fb973c115cd7f Mon Sep 17 00:00:00 2001 From: Krzysztof Kotowicz Date: Mon, 26 Aug 2024 16:28:12 +0200 Subject: [PATCH 388/445] Added encoding variant as an explicit UI setting (though only API-4 is supported now). --- contrib/ultrahdr.lua | 102 +++++++++++++++++++++++++++++++------------ 1 file changed, 74 insertions(+), 28 deletions(-) diff --git a/contrib/ultrahdr.lua b/contrib/ultrahdr.lua index f3b4d193..381b013b 100644 --- a/contrib/ultrahdr.lua +++ b/contrib/ultrahdr.lua @@ -79,7 +79,23 @@ local function image_path(image) return image.path .. "/" .. image.filename end -local function merge_ultrahdr(base, gainmap, ultrahdr_app, exiftool, metadata, output) +local ENCODING_VARIANT_API_4 = 1 + +local function get_encoding_variant() + local encoding_variant = dt.preferences.read("ultrahdr", "encoding variant", "integer") + if not encoding_variant then + encoding_variant = ENCODING_VARIANT_API_4 + end + return encoding_variant +end + +local function merge_ultrahdr_api4(base, gainmap, ultrahdr_app, exiftool, output) + local metadata = dt.preferences.read("ultrahdr", "metadata path", "string") + if not df.check_if_file_exists(metadata) then + dt.print(_("metadata file not found, did you set the correct path?")) + log.msg(log.error, "metadata file not found.") + return + end local base_tmp = df.chop_filetype(base) .. ".tmp" local hdr = df.chop_filetype(base) .. "_hdr." .. df.get_filetype(base) dtsys.external_command(exiftool .. " -all= " .. df.sanitize_filename(base) .. " -o " .. @@ -101,8 +117,6 @@ local function assert_settings_correct() log.msg(log.debug, "ultrahdr_app set to ", ultrahdr_app) local exiftool = df.check_if_bin_exists("exiftool") log.msg(log.debug, "exiftool set to ", exiftool) - local metadata = dt.preferences.read("ultrahdr", "metadata path", "string") - log.msg(log.debug, "metadata set to ", metadata) local output = dt.preferences.read("ultrahdr", "output dir", "string") log.msg(log.debug, "output dir set to ", output) @@ -120,40 +134,42 @@ local function assert_settings_correct() return end - if not df.check_if_file_exists(metadata) then - dt.print(_("metadata file not found, did you set the path?")) - log.msg(log.error, "metadata file not found.") - return - end - - return ultrahdr_app, exiftool, metadata, output + return ultrahdr_app, exiftool, output end local function create_hdr(storage, image_table, extra_data) -- finalize local saved_log_level = log.log_level() log.log_level(log.info) - local ultrahdr_app, exiftool, metadata, output = assert_settings_correct() + local ultrahdr_app, exiftool, output = assert_settings_correct() if not ultrahdr_app or not exiftool then return end - local merged = 0 - for ignore, v in pairs(extra_data) do - if not v then - goto continue + local encoding_variant = get_encoding_variant() + log.msg(log.info, string.format("using encoding variant %d", encoding_variant)) + if encoding_variant == ENCODING_VARIANT_API_4 then + local merged = 0 + for ignore, v in pairs(extra_data) do + if not v then + goto continue + end + local msg = string.format(_("Merging %s and %s"), df.get_filename(image_table[v["base"]]), + df.get_filename(image_table[v["gainmap"]])) + log.msg(log.info, msg) + dt.print(msg) + merge_ultrahdr_api4(image_table[v["base"]], image_table[v["gainmap"]], ultrahdr_app, exiftool, output) + merged = merged + 1 + ::continue:: end - local msg = string.format(_("Merging %s and %s"), df.get_filename(image_table[v["base"]]), - df.get_filename(image_table[v["gainmap"]])) - log.msg(log.info, msg) + for ignore, v in pairs(image_table) do + if df.check_if_file_exists(v) then os.remove(v) end + end + dt.print(string.format(_("Created %d UltraHDR image(s) in %s"), merged, output)) + else + local msg = string.format(_("Unknown encoding variant: %d"), encoding_variant) + dt.print_error(msg) dt.print(msg) - merge_ultrahdr(image_table[v["base"]], image_table[v["gainmap"]], ultrahdr_app, exiftool, metadata, output) - merged = merged + 1 - ::continue:: - end - for ignore, v in pairs(image_table) do - if df.check_if_file_exists(v) then os.remove(v) end end - dt.print(string.format(_("Created %d UltraHDR image(s) in %s"), merged, output)) log.log_level(saved_log_level) end @@ -161,9 +177,14 @@ local function destroy() dt.destroy_storage(namespace) end + + local function is_supported(storage, format) - if format.extension == "jpg" then - return true + local encoding_variant = get_encoding_variant() + if encoding_variant == ENCODING_VARIANT_API_4 then + -- API-4 expects compressed base and gainmap + -- https://github.com/google/libultrahdr/tree/main?tab=readme-ov-file#encoding-api-outline + return format.extension == "jpg" end return false end @@ -254,10 +275,35 @@ local function output_directory_widget() return box end +local function encoding_variant_widget() + local metadata_widget = metadata_file_widget() + local encoding_variant = get_encoding_variant() + local combobox = dt.new_widget("combobox"){ + label = _("Generate HDR from"), + selected = encoding_variant, + changed_callback=function(self) + dt.preferences.write("ultrahdr", "encoding variant", "integer", self.selected) + if self.selected == ENCODING_VARIANT_API_4 then + metadata_widget.visible = true + else + metadata_widget.visible = false + end + end, + _("SDR + gainmap (API-4)") -- ENCODING_VARIANT_API_4, + } + + combobox.changed_callback(combobox) + return dt.new_widget("box") { + orientation = "vertical", + combobox, + metadata_widget + } +end + local ultrahdr_widget = dt.new_widget("box") { orientation = "vertical", - metadata_file_widget(), output_directory_widget(), + encoding_variant_widget(), df.executable_path_widget({"ultrahdr_app", "exiftool"}) } From 1986f4e14843453274f571b4f3a534beaf04b8d5 Mon Sep 17 00:00:00 2001 From: Krzysztof Kotowicz Date: Thu, 19 Sep 2024 12:49:04 +0200 Subject: [PATCH 389/445] Major overhaul of the plugin. Added SDR + HDR (JPEG-XL) support. --- contrib/ultrahdr.lua | 627 +++++++++++++++++++++++++++++-------------- 1 file changed, 426 insertions(+), 201 deletions(-) diff --git a/contrib/ultrahdr.lua b/contrib/ultrahdr.lua index 381b013b..d2540a3a 100644 --- a/contrib/ultrahdr.lua +++ b/contrib/ultrahdr.lua @@ -17,8 +17,7 @@ You should have received a copy of the GNU General Public License along with darktable. If not, see . -]] ---[[ +]] --[[ ULTRAHDR Add a new storage option to generate UltraHDR JPG images. @@ -32,35 +31,59 @@ assuming the first one encountered is the base SDR image, and the second one is The images are merged using libultrahdr example application (ultrahdr_app). ADDITIONAL SOFTWARE NEEDED FOR THIS SCRIPT -* ultrahdr_app (from https://github.com/google/libultrahdr example dir) +* ultrahdr_app (built using https://github.com/google/libultrahdr/blob/main/docs/building.md instructions) * exiftool +* ffmpeg USAGE * require this file from your main luarc config file -* set exiftool and libultrahdr_app tool paths - -This plugin will add a new storage option. +* set binary tool paths -]] -local dt = require "darktable" +]] local dt = require "darktable" local du = require "lib/dtutils" local df = require "lib/dtutils.file" local log = require "lib/dtutils.log" local dtsys = require "lib/dtutils.system" +local dd = require "lib/dtutils.debug" local gettext = dt.gettext.gettext -local namespace = 'module_ultrahdr' +local namespace = "module_ultrahdr" -- works with darktable API version from 5.0.0 on du.check_min_api_version("7.0.0", "ultrahdr") -dt.gettext.bindtextdomain("ultrahdr", dt.configuration.config_dir .. "/lua/locale/") +dt.gettext.bindtextdomain(namespace, dt.configuration.config_dir .. "/lua/locale/") local function _(msgid) return gettext(msgid) end --- return data structure for script_manager +local job + +local GUI = { + optionwidgets = { + settings_label = {}, + encoding_variant_combo = {}, + encoding_settings_box = {}, + output_settings_label = {}, + output_settings_box = {}, + use_original_directory = {}, + output_directory_widget = {}, + copy_exif = {}, + import_to_darktable = {}, + metadata_path_label = {}, + metadata_path_widget = {}, + metadata_path_box = {}, + edit_executables_button = {}, + executable_path_widget = {} + }, + options = {}, + run = {} +} + +local flags = {} +flags.event_registered = false -- keep track of whether we've added an event callback or not +flags.module_installed = false -- keep track of whether the module is module_installed local script_data = {} @@ -70,247 +93,449 @@ script_data.metadata = { author = "Krzysztof Kotowicz" } -script_data.destroy = nil -- function to destory the script -script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil -script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again -script_data.show = nil -- only required for libs since the destroy_method only hides them +local PS = dt.configuration.running_os == "windows" and "\\" or "/" +local ENCODING_VARIANT_SDR_AND_GAINMAP = 1 +local ENCODING_VARIANT_SDR_AND_HDR = 2 -local function image_path(image) - return image.path .. "/" .. image.filename +local function save_preferences() + dt.preferences.write(namespace, "encoding_variant", "integer", GUI.optionwidgets.encoding_variant_combo.selected) + if GUI.optionwidgets.metadata_path_widget.value then + dt.preferences.write(namespace, "metadata_path", "string", GUI.optionwidgets.metadata_path_widget.value) + end + dt.preferences.write(namespace, "use_original_directory", "bool", GUI.optionwidgets.use_original_directory.value) + dt.preferences.write(namespace, "output_directory", "string", GUI.optionwidgets.output_directory_widget.value) + dt.preferences.write(namespace, "import_to_darktable", "bool", GUI.optionwidgets.import_to_darktable.value) + dt.preferences.write(namespace, "copy_exif", "bool", GUI.optionwidgets.copy_exif.value) end -local ENCODING_VARIANT_API_4 = 1 +local function load_preferences() + GUI.optionwidgets.encoding_variant_combo.selected = dt.preferences.read(namespace, "encoding_variant", "integer") or + ENCODING_VARIANT_SDR_AND_GAINMAP + GUI.optionwidgets.metadata_path_widget.value = dt.preferences.read(namespace, "metadata_path", "string") + GUI.optionwidgets.use_original_directory.value = dt.preferences.read(namespace, "use_original_directory", "bool") + GUI.optionwidgets.output_directory_widget.value = dt.preferences.read(namespace, "output_directory", "string") + GUI.optionwidgets.import_to_darktable.value = dt.preferences.read(namespace, "import_to_darktable", "bool") + GUI.optionwidgets.copy_exif.value = dt.preferences.read(namespace, "copy_exif", "bool") +end local function get_encoding_variant() - local encoding_variant = dt.preferences.read("ultrahdr", "encoding variant", "integer") - if not encoding_variant then - encoding_variant = ENCODING_VARIANT_API_4 - end - return encoding_variant + return GUI.optionwidgets.encoding_variant_combo.selected end -local function merge_ultrahdr_api4(base, gainmap, ultrahdr_app, exiftool, output) - local metadata = dt.preferences.read("ultrahdr", "metadata path", "string") - if not df.check_if_file_exists(metadata) then - dt.print(_("metadata file not found, did you set the correct path?")) - log.msg(log.error, "metadata file not found.") - return - end - local base_tmp = df.chop_filetype(base) .. ".tmp" - local hdr = df.chop_filetype(base) .. "_hdr." .. df.get_filetype(base) - dtsys.external_command(exiftool .. " -all= " .. df.sanitize_filename(base) .. " -o " .. - df.sanitize_filename(base_tmp)) - dtsys.external_command(exiftool .. " -all= " .. df.sanitize_filename(gainmap) .. " -overwrite_original") - dtsys.external_command(ultrahdr_app .. " -m 0 -i " .. df.sanitize_filename(base_tmp) .. " -g " .. - df.sanitize_filename(gainmap) .. " -f " .. df.sanitize_filename(metadata) .. " -z " .. - df.sanitize_filename(hdr)) - dtsys.external_command(exiftool .. " -tagsfromfile " .. df.sanitize_filename(base) .. " -all>all " .. - df.sanitize_filename(hdr) .. " -overwrite_original") - df.file_move(hdr, df.create_unique_filename(output .. "/" .. df.get_filename(hdr))) - os.remove(base) - os.remove(base_tmp) - os.remove(gainmap) -end +local function assert_settings_correct(encoding_variant) + local settings = { + bin = { + ultrahdr_app = df.check_if_bin_exists("ultrahdr_app"), + exiftool = df.check_if_bin_exists("exiftool"), + ffmpeg = df.check_if_bin_exists("ffmpeg") + }, + output = GUI.optionwidgets.output_directory_widget.value, + use_original_dir = GUI.optionwidgets.use_original_directory.value, + import_to_darktable = GUI.optionwidgets.import_to_darktable.value, + copy_exif = GUI.optionwidgets.copy_exif.value, + metadata = GUI.optionwidgets.metadata_path_widget.value, + tmpdir = dt.configuration.tmp_dir + } -local function assert_settings_correct() - local ultrahdr_app = df.check_if_bin_exists("ultrahdr_app") - log.msg(log.debug, "ultrahdr_app set to ", ultrahdr_app) - local exiftool = df.check_if_bin_exists("exiftool") - log.msg(log.debug, "exiftool set to ", exiftool) - local output = dt.preferences.read("ultrahdr", "output dir", "string") - log.msg(log.debug, "output dir set to ", output) - - if not ultrahdr_app then - dt.print(_("ultrahdr_app is not found, did you set the path?")) - log.msg(log.error, "ultrahdr_app executable not found. Check if the executable is installed.") - log.msg(log.error, "If the executable is installed, check that the path is set correctly.") + if not settings.use_original_dir and not df.check_if_file_exists(settings.output) then + dt.print(string.format(_("output directory (%s) not found, did you set the correct path?"), settings.output)) return end - if not exiftool then - dt.print(_("exiftool is not found, did you set the path?")) - log.msg(log.error, "exiftool executable not found. Check if the executable is installed.") - log.msg(log.error, "If the executable is installed, check that the path is set correctly.") - return + for k, v in pairs(settings.bin) do + if not v then + dt.print(string.format(_("%s is not found, did you set the path?"), k)) + return + end end - return ultrahdr_app, exiftool, output -end - -local function create_hdr(storage, image_table, extra_data) -- finalize - local saved_log_level = log.log_level() - log.log_level(log.info) - - local ultrahdr_app, exiftool, output = assert_settings_correct() - if not ultrahdr_app or not exiftool then - return - end - local encoding_variant = get_encoding_variant() - log.msg(log.info, string.format("using encoding variant %d", encoding_variant)) - if encoding_variant == ENCODING_VARIANT_API_4 then - local merged = 0 - for ignore, v in pairs(extra_data) do - if not v then - goto continue - end - local msg = string.format(_("Merging %s and %s"), df.get_filename(image_table[v["base"]]), - df.get_filename(image_table[v["gainmap"]])) - log.msg(log.info, msg) - dt.print(msg) - merge_ultrahdr_api4(image_table[v["base"]], image_table[v["gainmap"]], ultrahdr_app, exiftool, output) - merged = merged + 1 - ::continue:: - end - for ignore, v in pairs(image_table) do - if df.check_if_file_exists(v) then os.remove(v) end + if encoding_variant == ENCODING_VARIANT_SDR_AND_GAINMAP then + if not df.check_if_file_exists(settings.metadata) then + dt.print(_("metadata file not found, did you set the correct path?")) + log.msg(log.error, "metadata file not found.") + return end - dt.print(string.format(_("Created %d UltraHDR image(s) in %s"), merged, output)) - else - local msg = string.format(_("Unknown encoding variant: %d"), encoding_variant) - dt.print_error(msg) - dt.print(msg) end - log.log_level(saved_log_level) -end -local function destroy() - dt.destroy_storage(namespace) + return settings end - - -local function is_supported(storage, format) - local encoding_variant = get_encoding_variant() - if encoding_variant == ENCODING_VARIANT_API_4 then - -- API-4 expects compressed base and gainmap - -- https://github.com/google/libultrahdr/tree/main?tab=readme-ov-file#encoding-api-outline - return format.extension == "jpg" +local function get_stacks(images, encoding_variant) + local stacks = {} + local extra_image_content_type, extra_image_extension + if encoding_variant == ENCODING_VARIANT_SDR_AND_GAINMAP then + extra_image_content_type = "gainmap" + elseif encoding_variant == ENCODING_VARIANT_SDR_AND_HDR then + extra_image_extension = "jxl" + extra_image_content_type = "hdr" end - return false -end -local function initialize(storage, format, images, high_quality, extra_data) - local saved_log_level = log.log_level() - log.log_level(log.info) local tags = nil - -- Group images into base, gainmap pairs based on their original filename. - -- Assume that the first encountered image from each filename is a base one, unless it has a "gainmap" tag. + -- Group images into sdr, extra pairs based on their original filename, ignoring the extension + -- 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 for k, v in pairs(images) do - local has_gainmap_tag = false + local is_extra = false tags = dt.tags.get_tags(v) for ignore, tag in pairs(tags) do - if tag.name == "gainmap" then - has_gainmap_tag = true + if tag.name == extra_image_content_type then + is_extra = true end end - local key = image_path(v) - if extra_data[key] == nil then - extra_data[key] = {} + if extra_image_extension and df.get_filetype(v.filename) == extra_image_extension then + is_extra = true end - if extra_data[key]["base"] or has_gainmap_tag then - extra_data[key]["gainmap"] = v + -- 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) + if stacks[key] == nil then + stacks[key] = {} + end + if stacks[key]["sdr"] or is_extra then + stacks[key][extra_image_content_type] = v else - extra_data[key]["base"] = v + stacks[key]["sdr"] = v end end - -- remove incomplete entries - for k, v in pairs(extra_data) do - if not v["base"] or not v["gainmap"] then - extra_data[k] = nil + -- remove invalid stacks + local count = 0 + for k, v in pairs(stacks) do + if not v["sdr"] or not v[extra_image_content_type] then + stacks[k] = nil + elseif (v["sdr"].final_width ~= v[extra_image_content_type].final_width) or + (v["sdr"].final_height ~= v[extra_image_content_type].final_height) then + stacks[k] = nil + elseif extra_image_extension and df.get_filetype(v[extra_image_content_type].filename) ~= extra_image_extension then + stacks[k] = nil + else + count = count + 1 end end - log.log_level(saved_log_level) - return nil + return stacks, count end -local function metadata_file_widget() - local box_widgets = {} - table.insert(box_widgets, dt.new_widget("label") { - label = "libultrahdr metadata file" - }) - local path = dt.preferences.read("ultrahdr", "metadata path", "string") - if not path then - path = "" - end - table.insert(box_widgets, dt.new_widget("file_chooser_button") { - title = "select libultrahdr metadata path", - value = path, - is_directory = false, - changed_callback = function(self) - if df.check_if_file_exists(self.value) then - dt.preferences.write("ultrahdr", "metadata path", "string", self.value) - end - end - }) +local function stop_job(job) + job.valid = false +end - local box = dt.new_widget("box") { - orientation = "vertical", - table.unpack(box_widgets) - } - return box +local function execute_cmd(cmd) + log.msg(log.debug, cmd) + return dtsys.external_command(cmd) end -local function output_directory_widget() - local box_widgets = {} - table.insert(box_widgets, dt.new_widget("label") { - label = "output directory" - }) - local path = dt.preferences.read("ultrahdr", "output dir", "string") - if not path then - path = "" +local function generate_ultrahdr(encoding_variant, images, settings, step, total_steps) + local total_substeps + local substep = 0 + local uhdr + + function update_job_progress() + substep = substep + 1 + if substep > total_substeps then + log.msg(log.debug, + string.format("total_substeps count is too low for encoding_variant %d", encoding_variant)) + end + job.percent = (total_substeps * step + substep) / (total_steps * total_substeps) end - table.insert(box_widgets, dt.new_widget("file_chooser_button") { - title = "select libultrahdr metadata path", - value = path, - is_directory = true, - changed_callback = function(self) - dt.preferences.write("ultrahdr", "output dir", "string", self.value) + + if encoding_variant == ENCODING_VARIANT_SDR_AND_GAINMAP then + total_substeps = 6 + local msg = string.format(_("Stacking %s"), images["sdr"].filename) + log.msg(log.info, msg) + dt.print(msg) + -- Export both SDR and gainmap to JPEGs + local exporter = dt.new_format("jpeg") + exporter.quality = 95 + local sdr = df.create_unique_filename(settings.tmpdir .. PS .. df.chop_filetype(images["sdr"].filename) .. + ".jpg") + exporter:write_image(images["sdr"], sdr) + local gainmap = df.create_unique_filename(settings.tmpdir .. PS .. images["gainmap"].filename .. "_gainmap.jpg") + exporter:write_image(images["gainmap"], gainmap) + + log.msg(log.debug, string.format(_("Exported files: %s, %s"), sdr, gainmap)) + update_job_progress() + -- Strip EXIFs + execute_cmd(settings.bin.exiftool .. " -all= " .. df.sanitize_filename(sdr) .. " -o " .. + df.sanitize_filename(sdr .. ".noexif")) + execute_cmd(settings.bin.exiftool .. " -all= " .. df.sanitize_filename(gainmap) .. " -overwrite_original") + update_job_progress() + -- Merge files + uhdr = df.chop_filetype(sdr) .. "_ultrahdr.jpg" + + execute_cmd(settings.bin.ultrahdr_app .. " -m 0 -M 0 -i " .. df.sanitize_filename(sdr .. ".noexif") .. " -g " .. + df.sanitize_filename(gainmap) .. " -f " .. df.sanitize_filename(settings.metadata) .. " -z " .. + df.sanitize_filename(uhdr)) + update_job_progress() + -- Copy SDR's EXIF to UltraHDR file + if settings.copy_exif then + execute_cmd(settings.bin.exiftool .. " -tagsfromfile " .. df.sanitize_filename(sdr) .. " -all>all " .. + df.sanitize_filename(uhdr) .. " -overwrite_original -preserve") + end + update_job_progress() + -- Cleanup + os.remove(sdr) + os.remove(sdr .. ".noexif") + os.remove(gainmap) + update_job_progress() + elseif encoding_variant == ENCODING_VARIANT_SDR_AND_HDR then + total_substeps = 5 + -- https://discuss.pixls.us/t/manual-creation-of-ultrahdr-images/45004/20 + -- Step 1: Export SDR to PNG (HDR is already a JPEG-XL) + local exporter = dt.new_format("png") + exporter.bpp = 8 + local sdr = df.create_unique_filename(settings.tmpdir .. PS .. df.chop_filetype(images["sdr"].filename) .. + ".png") + exporter:write_image(images["sdr"], sdr) + uhdr = df.chop_filetype(sdr) .. "_ultrahdr.jpg" + + update_job_progress() + local extra = df.create_unique_filename(settings.tmpdir .. PS .. images["hdr"].filename .. ".raw") + + -- Step 3: Generate libultrahdr RAW images + execute_cmd(settings.bin.ffmpeg .. " -i " .. df.sanitize_filename(sdr) .. " -pix_fmt rgba -f rawvideo " .. + df.sanitize_filename(sdr .. ".raw")) + execute_cmd(settings.bin.ffmpeg .. " -i " .. + df.sanitize_filename(images["hdr"].path .. PS .. images["hdr"].filename) .. + " -pix_fmt p010le -f rawvideo " .. df.sanitize_filename(extra)) + update_job_progress() + execute_cmd(settings.bin.ultrahdr_app .. " -m 0 -y " .. df.sanitize_filename(sdr .. ".raw") .. " -p " .. + df.sanitize_filename(extra) .. " -a 0 -b 3 -c 1 -C 1 -t 2 -M 1 -s 1 -q 100 -Q 100 -D 1 " .. + " -w " .. tostring(images["sdr"].final_width) .. " -h " .. tostring(images["sdr"].final_height) .. + " -z " .. df.sanitize_filename(uhdr)) + update_job_progress() + if settings.copy_exif then + execute_cmd(settings.bin.exiftool .. " -tagsfromfile " .. df.sanitize_filename(sdr) .. " -all>all " .. + df.sanitize_filename(uhdr) .. " -overwrite_original -preserve") end - }) + -- Cleanup + os.remove(sdr) + os.remove(sdr .. ".raw") + os.remove(extra) + update_job_progress() + end - local box = dt.new_widget("box") { - orientation = "vertical", - table.unpack(box_widgets) - } - return box + local output_dir = settings.use_original_dir and images["sdr"].path or settings.output + local output_file = df.create_unique_filename(output_dir .. PS .. df.get_filename(uhdr)) + df.file_move(uhdr, output_file) + if settings.import_to_darktable then + local img = dt.database.import(output_file) + -- Add "ultrahdr" tag to the imported image + local tagnr = dt.tags.find("ultrahdr") + if tagnr == nil then + dt.tags.create("ultrahdr") + tagnr = dt.tags.find("ultrahdr") + end + dt.tags.attach(tagnr, img) + end + update_job_progress() end -local function encoding_variant_widget() - local metadata_widget = metadata_file_widget() +local function main() + local saved_log_level = log.log_level() + log.log_level(log.info) + + save_preferences() + local encoding_variant = get_encoding_variant() - local combobox = dt.new_widget("combobox"){ - label = _("Generate HDR from"), - selected = encoding_variant, - changed_callback=function(self) - dt.preferences.write("ultrahdr", "encoding variant", "integer", self.selected) - if self.selected == ENCODING_VARIANT_API_4 then - metadata_widget.visible = true - else - metadata_widget.visible = false - end - end, - _("SDR + gainmap (API-4)") -- ENCODING_VARIANT_API_4, - } + log.msg(log.info, string.format("using encoding variant %d", encoding_variant)) - combobox.changed_callback(combobox) - return dt.new_widget("box") { - orientation = "vertical", - combobox, - metadata_widget - } + local settings = assert_settings_correct(encoding_variant) + if not settings then + dt.print(_("Export settings are incorrect, exiting...")) + log.log_level(saved_log_level) + return + end + + local images = dt.gui.selection() -- get selected images + if #images < 2 then + dt.print(_("Select at least 2 images to generate UltraHDR image")) + log.log_level(saved_log_level) + return + end + + local stacks, stack_count = get_stacks(images, encoding_variant) + dt.print(string.format(_("Detected %d image stack(s)"), stack_count)) + if stack_count == 0 then + log.log_level(saved_log_level) + return + end + job = dt.gui.create_job(_("Generating UltraHDR images"), true, stop_job) + local count = 0 + for i, v in pairs(stacks) do + generate_ultrahdr(encoding_variant, v, settings, count, stack_count) + count = count + 1 + -- sleep for a short moment to give stop_job callback function a chance to run + dt.control.sleep(10) + end + -- stop job and remove progress_bar from ui, but only if not alreay canceled + if (job.valid) then + job.valid = false + end + + log.log_level(saved_log_level) end -local ultrahdr_widget = dt.new_widget("box") { +GUI.optionwidgets.settings_label = dt.new_widget("section_label") { + label = _("UltraHDR settings") +} + +GUI.optionwidgets.output_settings_label = dt.new_widget("section_label") { + label = _("Output") +} + +GUI.optionwidgets.output_directory_widget = dt.new_widget("file_chooser_button") { + title = _("Select directory to write UltraHDR image files to"), + is_directory = true +} + +GUI.optionwidgets.use_original_directory = dt.new_widget("check_button") { + label = _("Export to original directory"), + tooltip = _("Write UltraHDR images to the same directory as their original images"), + clicked_callback = function(self) + GUI.optionwidgets.output_directory_widget.sensitive = not self.value + end +} + +GUI.optionwidgets.import_to_darktable = dt.new_widget("check_button") { + label = _("Import UltraHDRs to Darktable"), + tooltip = _("Import UltraHDR images to Darktable library after generating, with an 'ultrahdr' tag attached.") +} + +GUI.optionwidgets.copy_exif = dt.new_widget("check_button") { + label = _("Copy EXIF data from SDR file(s)"), + tooltip = _("Copy EXIF data into UltraHDR file(s) from their SDR sources.") +} + +GUI.optionwidgets.output_settings_box = dt.new_widget("box") { + orientation = "vertical", + GUI.optionwidgets.output_settings_label, + GUI.optionwidgets.use_original_directory, + GUI.optionwidgets.output_directory_widget, + GUI.optionwidgets.import_to_darktable, + GUI.optionwidgets.copy_exif +} + +GUI.optionwidgets.metadata_path_label = dt.new_widget("label") { + label = _("ultrahdr_app metadata.cfg file") +} + +GUI.optionwidgets.metadata_path_widget = dt.new_widget("file_chooser_button") { + title = "select libultrahdr metadata path", + is_directory = false +} + +GUI.optionwidgets.metadata_path_box = dt.new_widget("box") { orientation = "vertical", - output_directory_widget(), - encoding_variant_widget(), - df.executable_path_widget({"ultrahdr_app", "exiftool"}) + GUI.optionwidgets.metadata_path_label, + GUI.optionwidgets.metadata_path_widget } --- Register +GUI.optionwidgets.encoding_variant_combo = dt.new_widget("combobox") { + label = _("Source images"), + tooltip = string.format(_([[Select types of images in the selection. + +%s: SDR image paired with a monochromatic gain map image +%s: SDR image paired with a JPEG-XL HDR image (10-bit, 'PQ P3 RGB' profile recommended) + +UltraHDR image will be created for each pair of images that: + - have the same underlying image path + filename (ignoring file extension) + - have the same dimensions -dt.register_storage(namespace, _("UltraHDR JPEG"), nil, create_hdr, is_supported, initialize, ultrahdr_widget) + It is assumed that the first image in a pair is the SDR , unless it has a "hdr" / "gainmap" tag. +]]), _("SDR + monochrome gainmap"), _("SDR + JPEG-XL HDR")), + selected = 0, + changed_callback = function(self) + if self.selected == ENCODING_VARIANT_SDR_AND_GAINMAP then + GUI.optionwidgets.metadata_path_box.visible = true + else + GUI.optionwidgets.metadata_path_box.visible = false + end + end, + _("SDR + monochrome gainmap"), -- ENCODING_VARIANT_SDR_AND_GAINMAP, + _("SDR + JPEG-XL HDR") -- ENCODING_VARIANT_SDR_AND_HDR, +} + +GUI.optionwidgets.encoding_settings_box = dt.new_widget("box") { + orientation = "vertical", + GUI.optionwidgets.encoding_variant_combo, + GUI.optionwidgets.metadata_path_box +} + +GUI.optionwidgets.executable_path_widget = df.executable_path_widget({"ultrahdr_app", "exiftool", "ffmpeg"}) +GUI.optionwidgets.executable_path_widget.visible = false + +GUI.optionwidgets.edit_executables_button = dt.new_widget("button") { + label = _("Show / hide executables"), + tooltip = _("Show / hide settings for executable files required for the plugin functionality"), + clicked_callback = function() + GUI.optionwidgets.executable_path_widget.visible = not GUI.optionwidgets.executable_path_widget.visible + end +} + +GUI.options = dt.new_widget("box") { + orientation = "vertical", + GUI.optionwidgets.settings_label, + GUI.optionwidgets.encoding_settings_box, + GUI.optionwidgets.edit_executables_button, + GUI.optionwidgets.executable_path_widget, + GUI.optionwidgets.output_settings_box +} + +GUI.run = dt.new_widget("button") { + label = _("Generate UltraHDR"), + tooltip = _([[Generate UltraHDR image(s) from selection + +Global options in the export module apply to the SDR image. Make sure that a proper color 'profile' setting is used (e.g. Display P3) +]]), + clicked_callback = main +} + +load_preferences() + +local function install_module() + if flags.module_installed then + return + end + dt.register_lib( -- register module + namespace, -- Module name + _("UltraHDR"), -- name + true, -- expandable + true, -- resetable + { + [dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 99} + }, -- containers + dt.new_widget("box") { + orientation = "vertical", + GUI.options, + GUI.run + }, nil, -- view_enter + nil -- view_leave + ) +end + +local function destroy() + dt.gui.libs[namespace].visible = false +end + +local function restart() + dt.gui.libs[namespace].visible = true +end + +if dt.gui.current_view().id == "lighttable" then -- make sure we are in lighttable view + install_module() -- register the lib +else + if not flags.event_registered then -- if we are not in lighttable view then register an event to signal when we might be + -- https://www.darktable.org/lua-api/index.html#darktable_register_event + dt.register_event(namespace, "view-changed", -- we want to be informed when the view changes + function(event, old_view, new_view) + if new_view.name == "lighttable" and old_view.name == "darkroom" then -- if the view changes from darkroom to lighttable + install_module() -- register the lib + end + end) + flags.event_registered = true -- keep track of whether we have an event handler installed + end +end script_data.destroy = destroy +script_data.restart = restart +script_data.destroy_method = "hide" +script_data.show = restart return script_data From 865d29fb4084af6e1eef15d5b5f8fe33a27c3c15 Mon Sep 17 00:00:00 2001 From: Krzysztof Kotowicz Date: Thu, 19 Sep 2024 13:13:47 +0200 Subject: [PATCH 390/445] Changed the UltraHDR JPEG quality to 95. --- contrib/ultrahdr.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/ultrahdr.lua b/contrib/ultrahdr.lua index d2540a3a..0d0e34b9 100644 --- a/contrib/ultrahdr.lua +++ b/contrib/ultrahdr.lua @@ -296,7 +296,7 @@ local function generate_ultrahdr(encoding_variant, images, settings, step, total " -pix_fmt p010le -f rawvideo " .. df.sanitize_filename(extra)) update_job_progress() execute_cmd(settings.bin.ultrahdr_app .. " -m 0 -y " .. df.sanitize_filename(sdr .. ".raw") .. " -p " .. - df.sanitize_filename(extra) .. " -a 0 -b 3 -c 1 -C 1 -t 2 -M 1 -s 1 -q 100 -Q 100 -D 1 " .. + df.sanitize_filename(extra) .. " -a 0 -b 3 -c 1 -C 1 -t 2 -M 1 -s 1 -q 95 -Q 95 -D 1 " .. " -w " .. tostring(images["sdr"].final_width) .. " -h " .. tostring(images["sdr"].final_height) .. " -z " .. df.sanitize_filename(uhdr)) update_job_progress() From 28f87566e1522432856911bee9862136c095ed7c Mon Sep 17 00:00:00 2001 From: Krzysztof Kotowicz Date: Thu, 19 Sep 2024 15:11:52 +0200 Subject: [PATCH 391/445] Added better messaging. --- contrib/ultrahdr.lua | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/contrib/ultrahdr.lua b/contrib/ultrahdr.lua index 0d0e34b9..2efeb2c0 100644 --- a/contrib/ultrahdr.lua +++ b/contrib/ultrahdr.lua @@ -237,9 +237,6 @@ local function generate_ultrahdr(encoding_variant, images, settings, step, total if encoding_variant == ENCODING_VARIANT_SDR_AND_GAINMAP then total_substeps = 6 - local msg = string.format(_("Stacking %s"), images["sdr"].filename) - log.msg(log.info, msg) - dt.print(msg) -- Export both SDR and gainmap to JPEGs local exporter = dt.new_format("jpeg") exporter.quality = 95 @@ -324,6 +321,10 @@ local function generate_ultrahdr(encoding_variant, images, settings, step, total end dt.tags.attach(tagnr, img) end + + local msg = string.format(_("Generated %s."), df.get_filename(output_file)) + log.msg(log.info, msg) + dt.print(msg) update_job_progress() end @@ -369,6 +370,9 @@ local function main() job.valid = false end + local msg = string.format(_("Generated %d UltraHDR image(s)."), count) + log.msg(log.info, msg) + dt.print(msg) log.log_level(saved_log_level) end From 496f8e704dc22a9d9f01c1aa6090582152a72a65 Mon Sep 17 00:00:00 2001 From: Krzysztof Kotowicz Date: Thu, 19 Sep 2024 17:09:54 +0200 Subject: [PATCH 392/445] Fixed doc. --- contrib/ultrahdr.lua | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/contrib/ultrahdr.lua b/contrib/ultrahdr.lua index 2efeb2c0..628600ad 100644 --- a/contrib/ultrahdr.lua +++ b/contrib/ultrahdr.lua @@ -20,14 +20,10 @@ ]] --[[ ULTRAHDR -Add a new storage option to generate UltraHDR JPG images. +Generate UltraHDR JPG images from various combinations of source files (SDR, HDR, gainmap). https://developer.android.com/media/platform/hdr-image-format -Of all exported files, the storage detects pairs of files generated from the same source image, -assuming the first one encountered is the base SDR image, and the second one is the gainmap -(alternatively, you can tag the gainmaps with a "gainmap" tag). - The images are merged using libultrahdr example application (ultrahdr_app). ADDITIONAL SOFTWARE NEEDED FOR THIS SCRIPT From 1a3a7f17ff53a0e33b3958134e31fb093965c2bb Mon Sep 17 00:00:00 2001 From: Krzysztof Kotowicz Date: Thu, 19 Sep 2024 17:54:15 +0200 Subject: [PATCH 393/445] Added SDR + auto gainmap generation encoding variant. --- contrib/ultrahdr.lua | 82 +++++++++++++++++++++++++------------------- 1 file changed, 47 insertions(+), 35 deletions(-) diff --git a/contrib/ultrahdr.lua b/contrib/ultrahdr.lua index 628600ad..ee92c994 100644 --- a/contrib/ultrahdr.lua +++ b/contrib/ultrahdr.lua @@ -92,6 +92,7 @@ script_data.metadata = { local PS = dt.configuration.running_os == "windows" and "\\" or "/" local ENCODING_VARIANT_SDR_AND_GAINMAP = 1 local ENCODING_VARIANT_SDR_AND_HDR = 2 +local ENCODING_VARIANT_SDR_AUTO_GAINMAP = 3 local function save_preferences() dt.preferences.write(namespace, "encoding_variant", "integer", GUI.optionwidgets.encoding_variant_combo.selected) @@ -128,7 +129,7 @@ local function assert_settings_correct(encoding_variant) output = GUI.optionwidgets.output_directory_widget.value, use_original_dir = GUI.optionwidgets.use_original_directory.value, import_to_darktable = GUI.optionwidgets.import_to_darktable.value, - copy_exif = GUI.optionwidgets.copy_exif.value, + copy_exif = GUI.optionwidgets.copy_exif.value, metadata = GUI.optionwidgets.metadata_path_widget.value, tmpdir = dt.configuration.tmp_dir } @@ -164,6 +165,8 @@ local function get_stacks(images, encoding_variant) elseif encoding_variant == ENCODING_VARIANT_SDR_AND_HDR then extra_image_extension = "jxl" extra_image_content_type = "hdr" + elseif encoding_variant == ENCODING_VARIANT_SDR_AUTO_GAINMAP then + extra_image_content_type = nil end local tags = nil @@ -173,7 +176,7 @@ local function get_stacks(images, encoding_variant) local is_extra = false tags = dt.tags.get_tags(v) for ignore, tag in pairs(tags) do - if tag.name == extra_image_content_type then + if extra_image_content_type and tag.name == extra_image_content_type then is_extra = true end end @@ -185,23 +188,27 @@ local function get_stacks(images, encoding_variant) if stacks[key] == nil then stacks[key] = {} end - if stacks[key]["sdr"] or is_extra then + if extra_image_content_type and (stacks[key]["sdr"] or is_extra) then stacks[key][extra_image_content_type] = v - else + elseif not is_extra then stacks[key]["sdr"] = v end end -- remove invalid stacks local count = 0 for k, v in pairs(stacks) do - if not v["sdr"] or not v[extra_image_content_type] then - stacks[k] = nil - elseif (v["sdr"].final_width ~= v[extra_image_content_type].final_width) or - (v["sdr"].final_height ~= v[extra_image_content_type].final_height) then - stacks[k] = nil - elseif extra_image_extension and df.get_filetype(v[extra_image_content_type].filename) ~= extra_image_extension then - stacks[k] = nil - else + if extra_image_content_type then + if not v["sdr"] or not v[extra_image_content_type] then + stacks[k] = nil + elseif (v["sdr"].final_width ~= v[extra_image_content_type].final_width) or + (v["sdr"].final_height ~= v[extra_image_content_type].final_height) then + stacks[k] = nil + elseif extra_image_extension and df.get_filetype(v[extra_image_content_type].filename) ~= + extra_image_extension then + stacks[k] = nil + end + end + if stacks[k] then count = count + 1 end end @@ -231,7 +238,7 @@ local function generate_ultrahdr(encoding_variant, images, settings, step, total job.percent = (total_substeps * step + substep) / (total_steps * total_substeps) end - if encoding_variant == ENCODING_VARIANT_SDR_AND_GAINMAP then + if encoding_variant == ENCODING_VARIANT_SDR_AND_GAINMAP or encoding_variant == ENCODING_VARIANT_SDR_AUTO_GAINMAP then total_substeps = 6 -- Export both SDR and gainmap to JPEGs local exporter = dt.new_format("jpeg") @@ -239,20 +246,27 @@ local function generate_ultrahdr(encoding_variant, images, settings, step, total local sdr = df.create_unique_filename(settings.tmpdir .. PS .. df.chop_filetype(images["sdr"].filename) .. ".jpg") exporter:write_image(images["sdr"], sdr) - local gainmap = df.create_unique_filename(settings.tmpdir .. PS .. images["gainmap"].filename .. "_gainmap.jpg") - exporter:write_image(images["gainmap"], gainmap) - + local gainmap + if encoding_variant == ENCODING_VARIANT_SDR_AUTO_GAINMAP then -- SDR is also a gainmap + gainmap = sdr + else + gainmap = df.create_unique_filename(settings.tmpdir .. PS .. images["gainmap"].filename .. "_gainmap.jpg") + exporter:write_image(images["gainmap"], gainmap) + end + dd.dprint(images["gainmap"]) log.msg(log.debug, string.format(_("Exported files: %s, %s"), sdr, gainmap)) update_job_progress() -- Strip EXIFs execute_cmd(settings.bin.exiftool .. " -all= " .. df.sanitize_filename(sdr) .. " -o " .. df.sanitize_filename(sdr .. ".noexif")) - execute_cmd(settings.bin.exiftool .. " -all= " .. df.sanitize_filename(gainmap) .. " -overwrite_original") + if sdr ~= gainmap then + execute_cmd(settings.bin.exiftool .. " -all= " .. df.sanitize_filename(gainmap) .. " -overwrite_original") + end update_job_progress() -- Merge files uhdr = df.chop_filetype(sdr) .. "_ultrahdr.jpg" - execute_cmd(settings.bin.ultrahdr_app .. " -m 0 -M 0 -i " .. df.sanitize_filename(sdr .. ".noexif") .. " -g " .. + execute_cmd(settings.bin.ultrahdr_app .. " -m 0 -i " .. df.sanitize_filename(sdr .. ".noexif") .. " -g " .. df.sanitize_filename(gainmap) .. " -f " .. df.sanitize_filename(settings.metadata) .. " -z " .. df.sanitize_filename(uhdr)) update_job_progress() @@ -265,7 +279,9 @@ local function generate_ultrahdr(encoding_variant, images, settings, step, total -- Cleanup os.remove(sdr) os.remove(sdr .. ".noexif") - os.remove(gainmap) + if sdr ~= gainmap then + os.remove(gainmap) + end update_job_progress() elseif encoding_variant == ENCODING_VARIANT_SDR_AND_HDR then total_substeps = 5 @@ -289,9 +305,9 @@ local function generate_ultrahdr(encoding_variant, images, settings, step, total " -pix_fmt p010le -f rawvideo " .. df.sanitize_filename(extra)) update_job_progress() execute_cmd(settings.bin.ultrahdr_app .. " -m 0 -y " .. df.sanitize_filename(sdr .. ".raw") .. " -p " .. - df.sanitize_filename(extra) .. " -a 0 -b 3 -c 1 -C 1 -t 2 -M 1 -s 1 -q 95 -Q 95 -D 1 " .. - " -w " .. tostring(images["sdr"].final_width) .. " -h " .. tostring(images["sdr"].final_height) .. - " -z " .. df.sanitize_filename(uhdr)) + df.sanitize_filename(extra) .. " -a 0 -b 3 -c 1 -C 1 -t 2 -M 1 -s 1 -q 95 -Q 95 -D 1 " .. " -w " .. + tostring(images["sdr"].final_width) .. " -h " .. tostring(images["sdr"].final_height) .. " -z " .. + df.sanitize_filename(uhdr)) update_job_progress() if settings.copy_exif then execute_cmd(settings.bin.exiftool .. " -tagsfromfile " .. df.sanitize_filename(sdr) .. " -all>all " .. @@ -320,7 +336,7 @@ local function generate_ultrahdr(encoding_variant, images, settings, step, total local msg = string.format(_("Generated %s."), df.get_filename(output_file)) log.msg(log.info, msg) - dt.print(msg) + dt.print(msg) update_job_progress() end @@ -340,14 +356,7 @@ local function main() return end - local images = dt.gui.selection() -- get selected images - if #images < 2 then - dt.print(_("Select at least 2 images to generate UltraHDR image")) - log.log_level(saved_log_level) - return - end - - local stacks, stack_count = get_stacks(images, encoding_variant) + local stacks, stack_count = get_stacks(dt.gui.selection(), encoding_variant) dt.print(string.format(_("Detected %d image stack(s)"), stack_count)) if stack_count == 0 then log.log_level(saved_log_level) @@ -433,13 +442,15 @@ GUI.optionwidgets.encoding_variant_combo = dt.new_widget("combobox") { %s: SDR image paired with a monochromatic gain map image %s: SDR image paired with a JPEG-XL HDR image (10-bit, 'PQ P3 RGB' profile recommended) +%s: SDR image only. Gainmaps will be just copies of SDR images. UltraHDR image will be created for each pair of images that: - have the same underlying image path + filename (ignoring file extension) - have the same dimensions - It is assumed that the first image in a pair is the SDR , unless it has a "hdr" / "gainmap" tag. -]]), _("SDR + monochrome gainmap"), _("SDR + JPEG-XL HDR")), +By default, the first image in a pair is treated as SDR, and the next one store extra gainmap/HDR data. +You can force the image into a specific slot by attaching "hdr" / "gainmap" tags. +]]), _("SDR + monochrome gainmap"), _("SDR + JPEG-XL HDR"), _("SDR (auto gainmap)")), selected = 0, changed_callback = function(self) if self.selected == ENCODING_VARIANT_SDR_AND_GAINMAP then @@ -448,8 +459,9 @@ UltraHDR image will be created for each pair of images that: GUI.optionwidgets.metadata_path_box.visible = false end end, - _("SDR + monochrome gainmap"), -- ENCODING_VARIANT_SDR_AND_GAINMAP, - _("SDR + JPEG-XL HDR") -- ENCODING_VARIANT_SDR_AND_HDR, + _("SDR + monochrome gainmap"), -- ENCODING_VARIANT_SDR_AND_GAINMAP + _("SDR + JPEG-XL HDR"), -- ENCODING_VARIANT_SDR_AND_HDR + _("SDR (auto gainmap)") -- ENCODING_VARIANT_SDR_AUTO_GAINMAP } GUI.optionwidgets.encoding_settings_box = dt.new_widget("box") { From 794b12305c4173b0dfa796975c6a1cd5339335ae Mon Sep 17 00:00:00 2001 From: Krzysztof Kotowicz Date: Thu, 19 Sep 2024 18:07:25 +0200 Subject: [PATCH 394/445] Fixed tooltip language. --- contrib/ultrahdr.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/contrib/ultrahdr.lua b/contrib/ultrahdr.lua index ee92c994..3b3f5574 100644 --- a/contrib/ultrahdr.lua +++ b/contrib/ultrahdr.lua @@ -440,15 +440,15 @@ GUI.optionwidgets.encoding_variant_combo = dt.new_widget("combobox") { label = _("Source images"), tooltip = string.format(_([[Select types of images in the selection. -%s: SDR image paired with a monochromatic gain map image -%s: SDR image paired with a JPEG-XL HDR image (10-bit, 'PQ P3 RGB' profile recommended) -%s: SDR image only. Gainmaps will be just copies of SDR images. +- %s: SDR image paired with a monochromatic gain map image +- %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). UltraHDR image will be created for each pair of images that: - have the same underlying image path + filename (ignoring file extension) - have the same dimensions -By default, the first image in a pair is treated as SDR, and the next one store extra gainmap/HDR data. +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 + monochrome gainmap"), _("SDR + JPEG-XL HDR"), _("SDR (auto gainmap)")), selected = 0, From fe6d262d9b2e078394c5e11972532aa133799bd5 Mon Sep 17 00:00:00 2001 From: Krzysztof Kotowicz Date: Fri, 20 Sep 2024 09:29:49 +0200 Subject: [PATCH 395/445] Display all error messages when checking configuration. Changed config defaults to require less user input (use_original_directory=TRUE, import_to_darktable=TRUE). Account for nil values when checking for file existence. --- contrib/ultrahdr.lua | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/contrib/ultrahdr.lua b/contrib/ultrahdr.lua index 3b3f5574..4e55cfc3 100644 --- a/contrib/ultrahdr.lua +++ b/contrib/ultrahdr.lua @@ -100,7 +100,9 @@ local function save_preferences() dt.preferences.write(namespace, "metadata_path", "string", GUI.optionwidgets.metadata_path_widget.value) end dt.preferences.write(namespace, "use_original_directory", "bool", GUI.optionwidgets.use_original_directory.value) - dt.preferences.write(namespace, "output_directory", "string", GUI.optionwidgets.output_directory_widget.value) + if GUI.optionwidgets.output_directory_widget.value then + dt.preferences.write(namespace, "output_directory", "string", GUI.optionwidgets.output_directory_widget.value) + end dt.preferences.write(namespace, "import_to_darktable", "bool", GUI.optionwidgets.import_to_darktable.value) dt.preferences.write(namespace, "copy_exif", "bool", GUI.optionwidgets.copy_exif.value) end @@ -108,11 +110,11 @@ end local function load_preferences() GUI.optionwidgets.encoding_variant_combo.selected = dt.preferences.read(namespace, "encoding_variant", "integer") or ENCODING_VARIANT_SDR_AND_GAINMAP - GUI.optionwidgets.metadata_path_widget.value = dt.preferences.read(namespace, "metadata_path", "string") - GUI.optionwidgets.use_original_directory.value = dt.preferences.read(namespace, "use_original_directory", "bool") - GUI.optionwidgets.output_directory_widget.value = dt.preferences.read(namespace, "output_directory", "string") - GUI.optionwidgets.import_to_darktable.value = dt.preferences.read(namespace, "import_to_darktable", "bool") - GUI.optionwidgets.copy_exif.value = dt.preferences.read(namespace, "copy_exif", "bool") + GUI.optionwidgets.metadata_path_widget.value = dt.preferences.read(namespace, "metadata_path", "string") or "" + GUI.optionwidgets.use_original_directory.value = dt.preferences.read(namespace, "use_original_directory", "bool") or true + GUI.optionwidgets.output_directory_widget.value = dt.preferences.read(namespace, "output_directory", "string") or "" + GUI.optionwidgets.import_to_darktable.value = dt.preferences.read(namespace, "import_to_darktable", "bool") or true + GUI.optionwidgets.copy_exif.value = dt.preferences.read(namespace, "copy_exif", "bool") or false end local function get_encoding_variant() @@ -120,6 +122,7 @@ local function get_encoding_variant() end local function assert_settings_correct(encoding_variant) + local errors = {} local settings = { bin = { ultrahdr_app = df.check_if_bin_exists("ultrahdr_app"), @@ -134,27 +137,26 @@ local function assert_settings_correct(encoding_variant) tmpdir = dt.configuration.tmp_dir } - if not settings.use_original_dir and not df.check_if_file_exists(settings.output) then - dt.print(string.format(_("output directory (%s) not found, did you set the correct path?"), settings.output)) - return + if not settings.use_original_dir and (not settings.output or not df.check_if_file_exists(settings.output)) then + table.insert(errors, string.format(_("output directory (%s) not found"), settings.output)) end for k, v in pairs(settings.bin) do if not v then - dt.print(string.format(_("%s is not found, did you set the path?"), k)) - return + table.insert(errors, string.format(_("%s binary not found"), k)) end end if encoding_variant == ENCODING_VARIANT_SDR_AND_GAINMAP then - if not df.check_if_file_exists(settings.metadata) then - dt.print(_("metadata file not found, did you set the correct path?")) - log.msg(log.error, "metadata file not found.") - return + if not settings.metadata or not df.check_if_file_exists(settings.metadata) then + table.insert(errors, _("metadata.cfg file not found (select one from libultrahdr/examples directory)")) end end - return settings + if #errors > 0 then + return nil, errors + end + return settings, nil end local function get_stacks(images, encoding_variant) @@ -253,7 +255,6 @@ local function generate_ultrahdr(encoding_variant, images, settings, step, total gainmap = df.create_unique_filename(settings.tmpdir .. PS .. images["gainmap"].filename .. "_gainmap.jpg") exporter:write_image(images["gainmap"], gainmap) end - dd.dprint(images["gainmap"]) log.msg(log.debug, string.format(_("Exported files: %s, %s"), sdr, gainmap)) update_job_progress() -- Strip EXIFs @@ -349,9 +350,9 @@ local function main() local encoding_variant = get_encoding_variant() log.msg(log.info, string.format("using encoding variant %d", encoding_variant)) - local settings = assert_settings_correct(encoding_variant) + local settings, errors = assert_settings_correct(encoding_variant) if not settings then - dt.print(_("Export settings are incorrect, exiting...")) + dt.print(string.format(_("Export settings are incorrect, exiting:\n\n%s"), table.concat(errors, "\n"))) log.log_level(saved_log_level) return end @@ -453,6 +454,7 @@ You can force the image into a specific slot by attaching "hdr" / "gainmap" tags ]]), _("SDR + monochrome gainmap"), _("SDR + JPEG-XL HDR"), _("SDR (auto gainmap)")), selected = 0, changed_callback = function(self) + GUI.run.sensitive = self.selected and self.selected > 0 if self.selected == ENCODING_VARIANT_SDR_AND_GAINMAP then GUI.optionwidgets.metadata_path_box.visible = true else From 2e95c4837bc06fe27b04f63dd4d31ee20ca4caef Mon Sep 17 00:00:00 2001 From: Krzysztof Kotowicz Date: Fri, 20 Sep 2024 11:16:28 +0200 Subject: [PATCH 396/445] Added option to generate metadata file. Fixed pref load / saving code defaults. Metadata file is required in ENCODING_VARIANT_SDR_AUTO_GAINMAP mode. --- contrib/ultrahdr.lua | 78 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 62 insertions(+), 16 deletions(-) diff --git a/contrib/ultrahdr.lua b/contrib/ultrahdr.lua index 4e55cfc3..5f0ca6fb 100644 --- a/contrib/ultrahdr.lua +++ b/contrib/ultrahdr.lua @@ -67,9 +67,11 @@ local GUI = { output_directory_widget = {}, copy_exif = {}, import_to_darktable = {}, + metadata_file_generate = {}, metadata_path_label = {}, metadata_path_widget = {}, metadata_path_box = {}, + metadata_path_box2 = {}, edit_executables_button = {}, executable_path_widget = {} }, @@ -94,6 +96,26 @@ local ENCODING_VARIANT_SDR_AND_GAINMAP = 1 local ENCODING_VARIANT_SDR_AND_HDR = 2 local ENCODING_VARIANT_SDR_AUTO_GAINMAP = 3 +local function generate_metadata_file() + local default_metadata_file = [[--maxContentBoost 6.0 +--minContentBoost 1.0 +--gamma 1.0 +--offsetSdr 0.0 +--offsetHdr 0.0 +--hdrCapacityMin 1.0 +--hdrCapacityMax 6.0]] + + local filename = dt.configuration.config_dir .. PS .. "ultrahdr_metadata.cfg" + local f, err = io.open(filename, "w+") + if not f then + dt.print(err) + return nil + end + f:write(default_metadata_file) + f:close() + return filename +end + local function save_preferences() dt.preferences.write(namespace, "encoding_variant", "integer", GUI.optionwidgets.encoding_variant_combo.selected) if GUI.optionwidgets.metadata_path_widget.value then @@ -108,13 +130,22 @@ local function save_preferences() end local function load_preferences() - GUI.optionwidgets.encoding_variant_combo.selected = dt.preferences.read(namespace, "encoding_variant", "integer") or - ENCODING_VARIANT_SDR_AND_GAINMAP - GUI.optionwidgets.metadata_path_widget.value = dt.preferences.read(namespace, "metadata_path", "string") or "" - GUI.optionwidgets.use_original_directory.value = dt.preferences.read(namespace, "use_original_directory", "bool") or true - GUI.optionwidgets.output_directory_widget.value = dt.preferences.read(namespace, "output_directory", "string") or "" - GUI.optionwidgets.import_to_darktable.value = dt.preferences.read(namespace, "import_to_darktable", "bool") or true - GUI.optionwidgets.copy_exif.value = dt.preferences.read(namespace, "copy_exif", "bool") or false + -- 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( + dt.preferences.read(namespace, "encoding_variant", "integer"), ENCODING_VARIANT_SDR_AND_GAINMAP) + 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 + GUI.optionwidgets.metadata_path_widget.value = generate_metadata_file() + -- Avoid regenerating the file if the user only enables the plugin, but never clicks "Generate" + dt.preferences.write(namespace, "metadata_path", "string", GUI.optionwidgets.metadata_path_widget.value) + end + GUI.optionwidgets.output_directory_widget.value = dt.preferences.read(namespace, "output_directory", "string") + GUI.optionwidgets.use_original_directory.value = dt.preferences.read(namespace, "use_original_directory", "bool") + if not GUI.optionwidgets.output_directory_widget.value then + GUI.optionwidgets.use_original_directory.value = true + end + GUI.optionwidgets.import_to_darktable.value = dt.preferences.read(namespace, "import_to_darktable", "bool") + GUI.optionwidgets.copy_exif.value = dt.preferences.read(namespace, "copy_exif", "bool") end local function get_encoding_variant() @@ -147,9 +178,9 @@ local function assert_settings_correct(encoding_variant) end end - if encoding_variant == ENCODING_VARIANT_SDR_AND_GAINMAP then + if encoding_variant == ENCODING_VARIANT_SDR_AND_GAINMAP or encoding_variant == ENCODING_VARIANT_SDR_AUTO_GAINMAP then if not settings.metadata or not df.check_if_file_exists(settings.metadata) then - table.insert(errors, _("metadata.cfg file not found (select one from libultrahdr/examples directory)")) + table.insert(errors, _("metadata.cfg file not found (use 'Generate' button)")) end end @@ -423,25 +454,40 @@ GUI.optionwidgets.output_settings_box = dt.new_widget("box") { } GUI.optionwidgets.metadata_path_label = dt.new_widget("label") { - label = _("ultrahdr_app metadata.cfg file") + label = _("Gainmap metadata file") } GUI.optionwidgets.metadata_path_widget = dt.new_widget("file_chooser_button") { - title = "select libultrahdr metadata path", + title = _("Select libultrahdr metadata.cfg file"), is_directory = false } +GUI.optionwidgets.metadata_file_generate = dt.new_widget("button") { + label = _("Generate"), + tooltip = _("Generate new metadata file with default values"), + clicked_callback = function() + local metadata_file = generate_metadata_file() + GUI.optionwidgets.metadata_path_widget.value = metadata_file + end +} + +GUI.optionwidgets.metadata_path_box2 = dt.new_widget("box") { + orientation = "horizontal", + GUI.optionwidgets.metadata_path_widget, + GUI.optionwidgets.metadata_file_generate +} + GUI.optionwidgets.metadata_path_box = dt.new_widget("box") { orientation = "vertical", GUI.optionwidgets.metadata_path_label, - GUI.optionwidgets.metadata_path_widget + GUI.optionwidgets.metadata_path_box2 } GUI.optionwidgets.encoding_variant_combo = dt.new_widget("combobox") { label = _("Source images"), tooltip = string.format(_([[Select types of images in the selection. -- %s: SDR image paired with a monochromatic 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 images only. Gainmaps will be copies of SDR images (the simplest option). @@ -451,17 +497,17 @@ UltraHDR image will be created for each pair of images that: 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 + monochrome gainmap"), _("SDR + JPEG-XL HDR"), _("SDR (auto gainmap)")), +]]), _("SDR + gainmap"), _("SDR + JPEG-XL HDR"), _("SDR (auto gainmap)")), selected = 0, changed_callback = function(self) GUI.run.sensitive = self.selected and self.selected > 0 - if self.selected == ENCODING_VARIANT_SDR_AND_GAINMAP then + if self.selected == ENCODING_VARIANT_SDR_AND_GAINMAP or self.selected == ENCODING_VARIANT_SDR_AUTO_GAINMAP then GUI.optionwidgets.metadata_path_box.visible = true else GUI.optionwidgets.metadata_path_box.visible = false end end, - _("SDR + monochrome gainmap"), -- ENCODING_VARIANT_SDR_AND_GAINMAP + _("SDR + gainmap"), -- ENCODING_VARIANT_SDR_AND_GAINMAP _("SDR + JPEG-XL HDR"), -- ENCODING_VARIANT_SDR_AND_HDR _("SDR (auto gainmap)") -- ENCODING_VARIANT_SDR_AUTO_GAINMAP } From 7e8340c526a264a98efcd2917a9e5e1663fcc04a Mon Sep 17 00:00:00 2001 From: Krzysztof Kotowicz Date: Fri, 20 Sep 2024 11:38:24 +0200 Subject: [PATCH 397/445] Don't overwrite existing stack slots (that way the first matching image in a stack will be used, vs the last one). --- contrib/ultrahdr.lua | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/contrib/ultrahdr.lua b/contrib/ultrahdr.lua index 5f0ca6fb..cba1cc90 100644 --- a/contrib/ultrahdr.lua +++ b/contrib/ultrahdr.lua @@ -216,15 +216,21 @@ local function get_stacks(images, encoding_variant) if extra_image_extension and df.get_filetype(v.filename) == extra_image_extension then is_extra = true 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) if stacks[key] == nil then stacks[key] = {} end - if extra_image_content_type and (stacks[key]["sdr"] or is_extra) then - stacks[key][extra_image_content_type] = v + if extra_image_content_type and (is_extra or stacks[key]["sdr"]) then + -- Don't overwrite existing entries + if not stacks[key][extra_image_content_type] then + stacks[key][extra_image_content_type] = v + end elseif not is_extra then - stacks[key]["sdr"] = v + -- Don't overwrite existing entries + if not stacks[key]["sdr"] then + stacks[key]["sdr"] = v + end end end -- remove invalid stacks From 99c3548950533de135bbcd2cb5e67585341b0030 Mon Sep 17 00:00:00 2001 From: Krzysztof Kotowicz Date: Sat, 21 Sep 2024 07:54:45 +0200 Subject: [PATCH 398/445] Copy only EXIF tags to UltraHDR. --- contrib/ultrahdr.lua | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/contrib/ultrahdr.lua b/contrib/ultrahdr.lua index cba1cc90..326b0988 100644 --- a/contrib/ultrahdr.lua +++ b/contrib/ultrahdr.lua @@ -310,7 +310,9 @@ local function generate_ultrahdr(encoding_variant, images, settings, step, total update_job_progress() -- Copy SDR's EXIF to UltraHDR file if settings.copy_exif then - execute_cmd(settings.bin.exiftool .. " -tagsfromfile " .. df.sanitize_filename(sdr) .. " -all>all " .. + -- Restricting tags to EXIF only, to make sure we won't mess up XMP tags (-all>all). + -- This might hapen e.g. when the source files are Adobe gainmap HDRs. + execute_cmd(settings.bin.exiftool .. " -tagsfromfile " .. df.sanitize_filename(sdr) .. " -exif " .. df.sanitize_filename(uhdr) .. " -overwrite_original -preserve") end update_job_progress() @@ -348,7 +350,9 @@ local function generate_ultrahdr(encoding_variant, images, settings, step, total df.sanitize_filename(uhdr)) update_job_progress() if settings.copy_exif then - execute_cmd(settings.bin.exiftool .. " -tagsfromfile " .. df.sanitize_filename(sdr) .. " -all>all " .. + -- Restricting tags to EXIF only, to make sure we won't mess up XMP tags (-all>all). + -- This might hapen e.g. when the source files are Adobe gainmap HDRs. + execute_cmd(settings.bin.exiftool .. " -tagsfromfile " .. df.sanitize_filename(sdr) .. " -exif " .. df.sanitize_filename(uhdr) .. " -overwrite_original -preserve") end -- Cleanup From 39f63cc8c59441fe2557be469bbf9090c642bcd6 Mon Sep 17 00:00:00 2001 From: Krzysztof Kotowicz Date: Sat, 21 Sep 2024 09:44:56 +0200 Subject: [PATCH 399/445] Fallback to reading image's width/height, as sometimes final_width/height is 0. --- contrib/ultrahdr.lua | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/contrib/ultrahdr.lua b/contrib/ultrahdr.lua index 326b0988..2ccf2ebc 100644 --- a/contrib/ultrahdr.lua +++ b/contrib/ultrahdr.lua @@ -190,7 +190,14 @@ local function assert_settings_correct(encoding_variant) return settings, nil end -local function get_stacks(images, encoding_variant) +local function get_dimensions(image) + if image.final_width > 0 then + return image.final_width, image.final_height + end + return image.width, image.height +end + +local function get_stacks(images, encoding_variant, selection_type) local stacks = {} local extra_image_content_type, extra_image_extension if encoding_variant == ENCODING_VARIANT_SDR_AND_GAINMAP then @@ -239,12 +246,15 @@ local function get_stacks(images, encoding_variant) if extra_image_content_type then if not v["sdr"] or not v[extra_image_content_type] then stacks[k] = nil - elseif (v["sdr"].final_width ~= v[extra_image_content_type].final_width) or - (v["sdr"].final_height ~= v[extra_image_content_type].final_height) then - stacks[k] = nil elseif extra_image_extension and df.get_filetype(v[extra_image_content_type].filename) ~= extra_image_extension then stacks[k] = nil + else + local sdr_w, sdr_h = get_dimensions(v["sdr"]) + local extra_w, extra_h = get_dimensions(v[extra_image_content_type]) + if (sdr_w ~= extra_w) or (sdr_h ~= extra_h) then + stacks[k] = nil + end end end if stacks[k] then @@ -344,9 +354,10 @@ local function generate_ultrahdr(encoding_variant, images, settings, step, total df.sanitize_filename(images["hdr"].path .. PS .. images["hdr"].filename) .. " -pix_fmt p010le -f rawvideo " .. df.sanitize_filename(extra)) update_job_progress() + local sdr_w, sdr_h = get_dimensions(images["sdr"]) execute_cmd(settings.bin.ultrahdr_app .. " -m 0 -y " .. df.sanitize_filename(sdr .. ".raw") .. " -p " .. df.sanitize_filename(extra) .. " -a 0 -b 3 -c 1 -C 1 -t 2 -M 1 -s 1 -q 95 -Q 95 -D 1 " .. " -w " .. - tostring(images["sdr"].final_width) .. " -h " .. tostring(images["sdr"].final_height) .. " -z " .. + tostring(sdr_w) .. " -h " .. tostring(sdr_h) .. " -z " .. df.sanitize_filename(uhdr)) update_job_progress() if settings.copy_exif then From 08726427aab2afc80d34743d98b06de48eb8371b Mon Sep 17 00:00:00 2001 From: Krzysztof Kotowicz Date: Sat, 21 Sep 2024 09:47:08 +0200 Subject: [PATCH 400/445] Don't re-export JPEG files if their images are not altered. --- contrib/ultrahdr.lua | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/contrib/ultrahdr.lua b/contrib/ultrahdr.lua index 2ccf2ebc..c6cf9dc1 100644 --- a/contrib/ultrahdr.lua +++ b/contrib/ultrahdr.lua @@ -287,20 +287,28 @@ local function generate_ultrahdr(encoding_variant, images, settings, step, total job.percent = (total_substeps * step + substep) / (total_steps * total_substeps) end + function copy_or_export_jpg(src, dest) + if df.get_filetype(src.filename) == "jpg" and not src.is_altered then + df.file_copy(src.path .. PS .. src.filename, dest) + else + local exporter = dt.new_format("jpeg") + exporter.quality = 95 + exporter:write_image(src, dest) + end + end + if encoding_variant == ENCODING_VARIANT_SDR_AND_GAINMAP or encoding_variant == ENCODING_VARIANT_SDR_AUTO_GAINMAP then total_substeps = 6 - -- Export both SDR and gainmap to JPEGs - local exporter = dt.new_format("jpeg") - exporter.quality = 95 + -- Export/copy both SDR and gainmap to JPEGs local sdr = df.create_unique_filename(settings.tmpdir .. PS .. df.chop_filetype(images["sdr"].filename) .. ".jpg") - exporter:write_image(images["sdr"], sdr) + copy_or_export_jpg(images["sdr"], sdr) local gainmap if encoding_variant == ENCODING_VARIANT_SDR_AUTO_GAINMAP then -- SDR is also a gainmap gainmap = sdr else gainmap = df.create_unique_filename(settings.tmpdir .. PS .. images["gainmap"].filename .. "_gainmap.jpg") - exporter:write_image(images["gainmap"], gainmap) + copy_or_export_jpg(images["gainmap"], gainmap) end log.msg(log.debug, string.format(_("Exported files: %s, %s"), sdr, gainmap)) update_job_progress() From 44e442e7eb508f90c2a31c45cd5657fb7b487fa0 Mon Sep 17 00:00:00 2001 From: Krzysztof Kotowicz Date: Sat, 21 Sep 2024 09:49:06 +0200 Subject: [PATCH 401/445] Support grouping images into stacks by different criteria (or forcing the selection to be interpreted as a single UltraHDR stack). --- contrib/ultrahdr.lua | 68 ++++++++++++++++++++++++++++++-------------- 1 file changed, 46 insertions(+), 22 deletions(-) diff --git a/contrib/ultrahdr.lua b/contrib/ultrahdr.lua index c6cf9dc1..c4faddef 100644 --- a/contrib/ultrahdr.lua +++ b/contrib/ultrahdr.lua @@ -60,6 +60,7 @@ local GUI = { optionwidgets = { settings_label = {}, encoding_variant_combo = {}, + selection_type_combo = {}, encoding_settings_box = {}, output_settings_label = {}, 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_AUTO_GAINMAP = 3 +local SELECTION_TYPE_ONE_STACK = 1 +local SELECTION_TYPE_GROUP_BY_FNAME = 2 + local function generate_metadata_file() local default_metadata_file = [[--maxContentBoost 6.0 --minContentBoost 1.0 @@ -118,6 +122,7 @@ end local function save_preferences() 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 dt.preferences.write(namespace, "metadata_path", "string", GUI.optionwidgets.metadata_path_widget.value) 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 GUI.optionwidgets.encoding_variant_combo.selected = math.max( 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") if not GUI.optionwidgets.metadata_path_widget.value then -- file widgets reset "" value to nil 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") end -local function get_encoding_variant() - return GUI.optionwidgets.encoding_variant_combo.selected -end - local function assert_settings_correct(encoding_variant) local errors = {} local settings = { @@ -210,8 +214,8 @@ local function get_stacks(images, encoding_variant, selection_type) end local tags = nil - -- Group images into sdr, extra pairs based on their original filename, ignoring the extension - -- 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 + -- Group images into (sdr [,extra]) stacks + -- 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 local is_extra = false tags = dt.tags.get_tags(v) @@ -224,7 +228,12 @@ local function get_stacks(images, encoding_variant, selection_type) is_extra = true end -- 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 stacks[key] = {} end @@ -407,8 +416,9 @@ local function main() save_preferences() - local encoding_variant = get_encoding_variant() - log.msg(log.info, string.format("using encoding variant %d", encoding_variant)) + local selection_type = GUI.optionwidgets.selection_type_combo.selected + 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) if not settings then @@ -417,7 +427,7 @@ local function main() return 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)) if stack_count == 0 then 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") { - label = _("Source images"), - tooltip = string.format(_([[Select types of images in the selection. + label = _("Each stack contains"), + 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 JPEG-XL HDR image (10-bit, 'PQ P3 RGB' profile recommended) +- %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 images only. Gainmaps will be copies of SDR images (the simplest option). -UltraHDR image will be created for each pair of images that: - - have the same underlying image path + filename (ignoring file extension) - - have the same dimensions - -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)")), +By default, the first image in a stack is treated as SDR, and the second one is a gainmap/HDR. +You can force the image into a specific stack slot by attaching "hdr" / "gainmap" tags to them. +]]), _("SDR + gainmap"), _("SDR + JPEG-XL HDR"), _("SDR only")), selected = 0, changed_callback = function(self) 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, _("SDR + gainmap"), -- ENCODING_VARIANT_SDR_AND_GAINMAP _("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") { orientation = "vertical", + GUI.optionwidgets.selection_type_combo, GUI.optionwidgets.encoding_variant_combo, GUI.optionwidgets.metadata_path_box } From 118bbad5cbdb6970d58417f1b6c9cdd60a55c1af Mon Sep 17 00:00:00 2001 From: Krzysztof Kotowicz Date: Sun, 22 Sep 2024 17:02:24 +0200 Subject: [PATCH 402/445] Exposed sliders for crucial settings in a metadata file, removed file picker for metadata.cfg. Temporary metadata file will be created during UltraHDR generation, using the values from the UI. --- contrib/ultrahdr.lua | 171 +++++++++++++++++++++++++++++-------------- 1 file changed, 117 insertions(+), 54 deletions(-) diff --git a/contrib/ultrahdr.lua b/contrib/ultrahdr.lua index c4faddef..4ca4b2a5 100644 --- a/contrib/ultrahdr.lua +++ b/contrib/ultrahdr.lua @@ -68,11 +68,12 @@ local GUI = { output_directory_widget = {}, copy_exif = {}, import_to_darktable = {}, - metadata_file_generate = {}, - metadata_path_label = {}, - metadata_path_widget = {}, - metadata_path_box = {}, - metadata_path_box2 = {}, + min_content_boost = {}, + max_content_boost = {}, + hdr_capacity_min = {}, + hdr_capacity_max = {}, + metadata_label = {}, + metadata_box = {}, edit_executables_button = {}, executable_path_widget = {} }, @@ -100,22 +101,24 @@ 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 default_metadata_file = [[--maxContentBoost 6.0 ---minContentBoost 1.0 +local function generate_metadata_file(settings) + local metadata_file_fmt = [[--maxContentBoost %f +--minContentBoost %f --gamma 1.0 --offsetSdr 0.0 --offsetHdr 0.0 ---hdrCapacityMin 1.0 ---hdrCapacityMax 6.0]] +--hdrCapacityMin %f +--hdrCapacityMax %f]] - local filename = dt.configuration.config_dir .. PS .. "ultrahdr_metadata.cfg" + local filename = df.create_unique_filename(settings.tmpdir .. PS .. "metadata.cfg") local f, err = io.open(filename, "w+") if not f then dt.print(err) return nil end - f:write(default_metadata_file) + local content = string.format(metadata_file_fmt, settings.metadata.max_content_boost, + settings.metadata.min_content_boost, settings.metadata.hdr_capacity_min, settings.metadata.hdr_capacity_max) + f:write(content) f:close() return filename end @@ -123,15 +126,25 @@ end local function save_preferences() 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 - dt.preferences.write(namespace, "metadata_path", "string", GUI.optionwidgets.metadata_path_widget.value) - end dt.preferences.write(namespace, "use_original_directory", "bool", GUI.optionwidgets.use_original_directory.value) if GUI.optionwidgets.output_directory_widget.value then dt.preferences.write(namespace, "output_directory", "string", GUI.optionwidgets.output_directory_widget.value) end dt.preferences.write(namespace, "import_to_darktable", "bool", GUI.optionwidgets.import_to_darktable.value) dt.preferences.write(namespace, "copy_exif", "bool", GUI.optionwidgets.copy_exif.value) + if GUI.optionwidgets.min_content_boost.value then + dt.preferences.write(namespace, "min_content_boost", "float", GUI.optionwidgets.min_content_boost.value) + dt.preferences.write(namespace, "max_content_boost", "float", GUI.optionwidgets.max_content_boost.value) + dt.preferences.write(namespace, "hdr_capacity_min", "float", GUI.optionwidgets.hdr_capacity_min.value) + dt.preferences.write(namespace, "hdr_capacity_max", "float", GUI.optionwidgets.hdr_capacity_max.value) + end +end + +local function default_to(value, default) + if value == 0 then + return default + end + return value end local function load_preferences() @@ -141,12 +154,6 @@ local function load_preferences() 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") - if not GUI.optionwidgets.metadata_path_widget.value then -- file widgets reset "" value to nil - GUI.optionwidgets.metadata_path_widget.value = generate_metadata_file() - -- Avoid regenerating the file if the user only enables the plugin, but never clicks "Generate" - dt.preferences.write(namespace, "metadata_path", "string", GUI.optionwidgets.metadata_path_widget.value) - end GUI.optionwidgets.output_directory_widget.value = dt.preferences.read(namespace, "output_directory", "string") GUI.optionwidgets.use_original_directory.value = dt.preferences.read(namespace, "use_original_directory", "bool") if not GUI.optionwidgets.output_directory_widget.value then @@ -154,6 +161,14 @@ local function load_preferences() end GUI.optionwidgets.import_to_darktable.value = dt.preferences.read(namespace, "import_to_darktable", "bool") GUI.optionwidgets.copy_exif.value = dt.preferences.read(namespace, "copy_exif", "bool") + GUI.optionwidgets.min_content_boost.value = default_to(dt.preferences.read(namespace, "min_content_boost", "float"), + 1.0) + GUI.optionwidgets.max_content_boost.value = default_to(dt.preferences.read(namespace, "max_content_boost", "float"), + 6.0) + GUI.optionwidgets.hdr_capacity_min.value = default_to(dt.preferences.read(namespace, "hdr_capacity_min", "float"), + 1.0) + GUI.optionwidgets.hdr_capacity_max.value = default_to(dt.preferences.read(namespace, "hdr_capacity_max", "float"), + 6.0) end local function assert_settings_correct(encoding_variant) @@ -168,7 +183,12 @@ local function assert_settings_correct(encoding_variant) use_original_dir = GUI.optionwidgets.use_original_directory.value, import_to_darktable = GUI.optionwidgets.import_to_darktable.value, copy_exif = GUI.optionwidgets.copy_exif.value, - metadata = GUI.optionwidgets.metadata_path_widget.value, + metadata = { + min_content_boost = GUI.optionwidgets.min_content_boost.value, + max_content_boost = GUI.optionwidgets.max_content_boost.value, + hdr_capacity_min = GUI.optionwidgets.hdr_capacity_min.value, + hdr_capacity_max = GUI.optionwidgets.hdr_capacity_max.value + }, tmpdir = dt.configuration.tmp_dir } @@ -183,8 +203,11 @@ local function assert_settings_correct(encoding_variant) end if encoding_variant == ENCODING_VARIANT_SDR_AND_GAINMAP or encoding_variant == ENCODING_VARIANT_SDR_AUTO_GAINMAP then - if not settings.metadata or not df.check_if_file_exists(settings.metadata) then - table.insert(errors, _("metadata.cfg file not found (use 'Generate' button)")) + if settings.metadata.min_content_boost >= settings.metadata.max_content_boost then + table.insert(errors, _("min_content_boost should not be greater than max_content_boost")) + end + if settings.metadata.hdr_capacity_min >= settings.metadata.hdr_capacity_max then + table.insert(errors, _("hdr_capacity_min should not be greater than hdr_capacity_max")) end end @@ -233,7 +256,7 @@ local function get_stacks(images, encoding_variant, selection_type) key = df.chop_filetype(v.path .. PS .. v.filename) elseif selection_type == SELECTION_TYPE_ONE_STACK then key = "the_one_and_only" - end + end if stacks[key] == nil then stacks[key] = {} end @@ -299,11 +322,11 @@ local function generate_ultrahdr(encoding_variant, images, settings, step, total function copy_or_export_jpg(src, dest) if df.get_filetype(src.filename) == "jpg" and not src.is_altered then df.file_copy(src.path .. PS .. src.filename, dest) - else + else local exporter = dt.new_format("jpeg") - exporter.quality = 95 + exporter.quality = 95 exporter:write_image(src, dest) - end + end end if encoding_variant == ENCODING_VARIANT_SDR_AND_GAINMAP or encoding_variant == ENCODING_VARIANT_SDR_AUTO_GAINMAP then @@ -328,11 +351,13 @@ local function generate_ultrahdr(encoding_variant, images, settings, step, total execute_cmd(settings.bin.exiftool .. " -all= " .. df.sanitize_filename(gainmap) .. " -overwrite_original") end update_job_progress() + -- Generate metadata.cfg file + local metadata_file = generate_metadata_file(settings) -- Merge files uhdr = df.chop_filetype(sdr) .. "_ultrahdr.jpg" execute_cmd(settings.bin.ultrahdr_app .. " -m 0 -i " .. df.sanitize_filename(sdr .. ".noexif") .. " -g " .. - df.sanitize_filename(gainmap) .. " -f " .. df.sanitize_filename(settings.metadata) .. " -z " .. + df.sanitize_filename(gainmap) .. " -f " .. df.sanitize_filename(metadata_file) .. " -z " .. df.sanitize_filename(uhdr)) update_job_progress() -- Copy SDR's EXIF to UltraHDR file @@ -346,6 +371,7 @@ local function generate_ultrahdr(encoding_variant, images, settings, step, total -- Cleanup os.remove(sdr) os.remove(sdr .. ".noexif") + os.remove(metadata_file) if sdr ~= gainmap then os.remove(gainmap) end @@ -374,8 +400,7 @@ local function generate_ultrahdr(encoding_variant, images, settings, step, total local sdr_w, sdr_h = get_dimensions(images["sdr"]) execute_cmd(settings.bin.ultrahdr_app .. " -m 0 -y " .. df.sanitize_filename(sdr .. ".raw") .. " -p " .. df.sanitize_filename(extra) .. " -a 0 -b 3 -c 1 -C 1 -t 2 -M 1 -s 1 -q 95 -Q 95 -D 1 " .. " -w " .. - tostring(sdr_w) .. " -h " .. tostring(sdr_h) .. " -z " .. - df.sanitize_filename(uhdr)) + tostring(sdr_w) .. " -h " .. tostring(sdr_h) .. " -z " .. df.sanitize_filename(uhdr)) update_job_progress() if settings.copy_exif then -- Restricting tags to EXIF only, to make sure we won't mess up XMP tags (-all>all). @@ -492,34 +517,72 @@ GUI.optionwidgets.output_settings_box = dt.new_widget("box") { GUI.optionwidgets.copy_exif } -GUI.optionwidgets.metadata_path_label = dt.new_widget("label") { - label = _("Gainmap metadata file") +GUI.optionwidgets.metadata_label = dt.new_widget("label") { + label = _("Gainmap metadata") } -GUI.optionwidgets.metadata_path_widget = dt.new_widget("file_chooser_button") { - title = _("Select libultrahdr metadata.cfg file"), - is_directory = false +GUI.optionwidgets.min_content_boost = dt.new_widget("slider") { + label = _('Min content boost'), + tooltip = _( + 'How much darker an image can get, when shown on an HDR display, relative to the SDR rendition (linear, SDR = 1.0). Also called "GainMapMin". '), + hard_min = 0.9, + hard_max = 10, + soft_min = 0.9, + soft_max = 2, + step = 1, + digits = 1, + reset_callback = function(self) + self.value = 1.0 + end } - -GUI.optionwidgets.metadata_file_generate = dt.new_widget("button") { - label = _("Generate"), - tooltip = _("Generate new metadata file with default values"), - clicked_callback = function() - local metadata_file = generate_metadata_file() - GUI.optionwidgets.metadata_path_widget.value = metadata_file +GUI.optionwidgets.max_content_boost = dt.new_widget("slider") { + label = _('Max content boost'), + tooltip = _( + 'How much brighter an image can get, when shown on an HDR display, relative to the SDR rendition (linear, SDR = 1.0). Also called "GainMapMax". \n\nMust not be lower than Min content boost'), + hard_min = 1, + hard_max = 10, + soft_min = 2, + soft_max = 10, + step = 1, + digits = 1, + reset_callback = function(self) + self.value = 6.0 end } - -GUI.optionwidgets.metadata_path_box2 = dt.new_widget("box") { - orientation = "horizontal", - GUI.optionwidgets.metadata_path_widget, - GUI.optionwidgets.metadata_file_generate +GUI.optionwidgets.hdr_capacity_min = dt.new_widget("slider") { + label = _('Min HDR capacity'), + tooltip = _('Minimum display boost value for which the gain map is applied at all (linear, SDR = 1.0).'), + hard_min = 0.9, + hard_max = 10, + soft_min = 1, + soft_max = 2, + step = 1, + digits = 1, + reset_callback = function(self) + self.value = 1.0 + end +} +GUI.optionwidgets.hdr_capacity_max = dt.new_widget("slider") { + label = _('Max HDR capacity'), + tooltip = _('Maximum display boost value for which the gain map is applied completely (linear, SDR = 1.0).'), + hard_min = 1, + hard_max = 10, + soft_min = 2, + soft_max = 10, + digits = 1, + step = 1, + reset_callback = function(self) + self.value = 6.0 + end } -GUI.optionwidgets.metadata_path_box = dt.new_widget("box") { +GUI.optionwidgets.metadata_box = dt.new_widget("box") { orientation = "vertical", - GUI.optionwidgets.metadata_path_label, - GUI.optionwidgets.metadata_path_box2 + GUI.optionwidgets.metadata_label, + GUI.optionwidgets.min_content_boost, + GUI.optionwidgets.max_content_boost, + GUI.optionwidgets.hdr_capacity_min, + GUI.optionwidgets.hdr_capacity_max } GUI.optionwidgets.encoding_variant_combo = dt.new_widget("combobox") { @@ -538,9 +601,9 @@ You can force the image into a specific stack slot by attaching "hdr" / "gainmap changed_callback = function(self) GUI.run.sensitive = self.selected and self.selected > 0 if self.selected == ENCODING_VARIANT_SDR_AND_GAINMAP or self.selected == ENCODING_VARIANT_SDR_AUTO_GAINMAP then - GUI.optionwidgets.metadata_path_box.visible = true + GUI.optionwidgets.metadata_box.visible = true else - GUI.optionwidgets.metadata_path_box.visible = false + GUI.optionwidgets.metadata_box.visible = false end end, _("SDR + gainmap"), -- ENCODING_VARIANT_SDR_AND_GAINMAP @@ -568,7 +631,7 @@ GUI.optionwidgets.encoding_settings_box = dt.new_widget("box") { orientation = "vertical", GUI.optionwidgets.selection_type_combo, GUI.optionwidgets.encoding_variant_combo, - GUI.optionwidgets.metadata_path_box + GUI.optionwidgets.metadata_box } GUI.optionwidgets.executable_path_widget = df.executable_path_widget({"ultrahdr_app", "exiftool", "ffmpeg"}) From f6a1d1c20b7e162030fa75a00add12661e072e67 Mon Sep 17 00:00:00 2001 From: Krzysztof Kotowicz Date: Tue, 24 Sep 2024 14:57:35 +0200 Subject: [PATCH 403/445] Made the UltraHDR generation more robust. - Appropriate color profiles are used when generating UltraHDR files. DT_COLORSPACE_DISPLAY_P3 is used for SDR, and DT_COLORSPACE_PQ_P3 is used for HDR, regardless of what was selected in the export module UI. - Added correction for odd image dimensions in SDR + HDR mode. - Added quality setting for JPEG compression - SDR + HDR option can source from any DT image (JPEG-XL is generated on the fly). - generation can abort on errors and display error messages. --- contrib/ultrahdr.lua | 190 ++++++++++++++++++++++++++++++++----------- 1 file changed, 142 insertions(+), 48 deletions(-) diff --git a/contrib/ultrahdr.lua b/contrib/ultrahdr.lua index 4ca4b2a5..f013ff37 100644 --- a/contrib/ultrahdr.lua +++ b/contrib/ultrahdr.lua @@ -75,7 +75,8 @@ local GUI = { metadata_label = {}, metadata_box = {}, edit_executables_button = {}, - executable_path_widget = {} + executable_path_widget = {}, + quality_widget = {} }, options = {}, run = {} @@ -101,6 +102,10 @@ local ENCODING_VARIANT_SDR_AUTO_GAINMAP = 3 local SELECTION_TYPE_ONE_STACK = 1 local SELECTION_TYPE_GROUP_BY_FNAME = 2 +-- Values are defined in darktable/src/common/colorspaces.h +local DT_COLORSPACE_PQ_P3 = 24 +local DT_COLORSPACE_DISPLAY_P3 = 26 + local function generate_metadata_file(settings) local metadata_file_fmt = [[--maxContentBoost %f --minContentBoost %f @@ -138,6 +143,7 @@ local function save_preferences() dt.preferences.write(namespace, "hdr_capacity_min", "float", GUI.optionwidgets.hdr_capacity_min.value) dt.preferences.write(namespace, "hdr_capacity_max", "float", GUI.optionwidgets.hdr_capacity_max.value) end + dt.preferences.write(namespace, "quality", "integer", GUI.optionwidgets.quality_widget.value) end local function default_to(value, default) @@ -169,6 +175,30 @@ local function load_preferences() 1.0) GUI.optionwidgets.hdr_capacity_max.value = default_to(dt.preferences.read(namespace, "hdr_capacity_max", "float"), 6.0) + GUI.optionwidgets.quality_widget.value = default_to(dt.preferences.read(namespace, "quality", "integer"), 95) +end + +-- Changes the combobox selection blindly until a paired config value is set. +-- Workaround for https://github.com/darktable-org/lua-scripts/issues/522 +local function set_combobox(path, instance, config_name, new_config_value) + + local pref = dt.preferences.read("darktable", config_name, "integer") + if pref == new_config_value then + return new_config_value + end + + dt.gui.action(path, 0, "selection", "first", 1.0) + local limit, i = 30, 0 -- in case there is no matching config value in the first n entries of a combobox. + while i < limit do + i = i + 1 + dt.gui.action(path, 0, "selection", "next", 1.0) + dt.control.sleep(10) + if dt.preferences.read("darktable", config_name, "integer") == new_config_value then + log.msg(log.debug, string.format(_("Changed %s from %d to %d"), config_name, pref, new_config_value)) + return pref + end + end + log.msg(log.error, string.format(_("Could not change %s from %d to %d"), config_name, pref, new_config_value)) end local function assert_settings_correct(encoding_variant) @@ -189,6 +219,7 @@ local function assert_settings_correct(encoding_variant) hdr_capacity_min = GUI.optionwidgets.hdr_capacity_min.value, hdr_capacity_max = GUI.optionwidgets.hdr_capacity_max.value }, + quality = GUI.optionwidgets.quality_widget.value, tmpdir = dt.configuration.tmp_dir } @@ -226,11 +257,10 @@ end local function get_stacks(images, encoding_variant, selection_type) local stacks = {} - local extra_image_content_type, extra_image_extension + local extra_image_content_type if encoding_variant == ENCODING_VARIANT_SDR_AND_GAINMAP then extra_image_content_type = "gainmap" elseif encoding_variant == ENCODING_VARIANT_SDR_AND_HDR then - extra_image_extension = "jxl" extra_image_content_type = "hdr" elseif encoding_variant == ENCODING_VARIANT_SDR_AUTO_GAINMAP then extra_image_content_type = nil @@ -278,9 +308,6 @@ local function get_stacks(images, encoding_variant, selection_type) if extra_image_content_type then if not v["sdr"] or not v[extra_image_content_type] then stacks[k] = nil - elseif extra_image_extension and df.get_filetype(v[extra_image_content_type].filename) ~= - extra_image_extension then - stacks[k] = nil else local sdr_w, sdr_h = get_dimensions(v["sdr"]) local extra_w, extra_h = get_dimensions(v[extra_image_content_type]) @@ -309,6 +336,7 @@ local function generate_ultrahdr(encoding_variant, images, settings, step, total local total_substeps local substep = 0 local uhdr + local errors = {} function update_job_progress() substep = substep + 1 @@ -319,28 +347,56 @@ local function generate_ultrahdr(encoding_variant, images, settings, step, total job.percent = (total_substeps * step + substep) / (total_steps * total_substeps) end - function copy_or_export_jpg(src, dest) - if df.get_filetype(src.filename) == "jpg" and not src.is_altered then - df.file_copy(src.path .. PS .. src.filename, dest) + function copy_or_export(src_image, dest, format, colorspace, props) + if df.get_filetype(src_image.filename) == df.get_filetype(dest) and not src_image.is_altered then + return df.file_copy(src_image.path .. PS .. src_image.filename, dest) else - local exporter = dt.new_format("jpeg") - exporter.quality = 95 - exporter:write_image(src, dest) + local prev = set_combobox("lib/export/profile", 0, "plugins/lighttable/export/icctype", colorspace) + if not prev then + return false + end + local exporter = dt.new_format(format) + for k, v in pairs(props) do + exporter[k] = v + end + local ok = not exporter:write_image(src_image, dest) + if prev then + set_combobox("lib/export/profile", 0, "plugins/lighttable/export/icctype", prev) + end + return ok end + return true end if encoding_variant == ENCODING_VARIANT_SDR_AND_GAINMAP or encoding_variant == ENCODING_VARIANT_SDR_AUTO_GAINMAP then total_substeps = 6 + local ok -- Export/copy both SDR and gainmap to JPEGs local sdr = df.create_unique_filename(settings.tmpdir .. PS .. df.chop_filetype(images["sdr"].filename) .. ".jpg") - copy_or_export_jpg(images["sdr"], sdr) + ok = copy_or_export(images["sdr"], sdr, "jpeg", DT_COLORSPACE_DISPLAY_P3, { + quality = settings.quality + }) + if not ok then + os.remove(sdr) + table.insert(errors, string.format(_("Error exporting %s to %s"), images["sdr"].filename, "jpeg")) + return false, errors + end + local gainmap if encoding_variant == ENCODING_VARIANT_SDR_AUTO_GAINMAP then -- SDR is also a gainmap gainmap = sdr else gainmap = df.create_unique_filename(settings.tmpdir .. PS .. images["gainmap"].filename .. "_gainmap.jpg") - copy_or_export_jpg(images["gainmap"], gainmap) + ok = copy_or_export(images["gainmap"], gainmap, "jpeg", DT_COLORSPACE_DISPLAY_P3, { + quality = settings.quality + }) + if not ok then + os.remove(sdr) + os.remove(sdr) + table.insert(errors, string.format(_("Error exporting %s to %s"), images["gainmap"].filename, "jpeg")) + return false, errors + end end log.msg(log.debug, string.format(_("Exported files: %s, %s"), sdr, gainmap)) update_job_progress() @@ -377,30 +433,54 @@ local function generate_ultrahdr(encoding_variant, images, settings, step, total end update_job_progress() elseif encoding_variant == ENCODING_VARIANT_SDR_AND_HDR then - total_substeps = 5 + local ok + total_substeps = 6 -- https://discuss.pixls.us/t/manual-creation-of-ultrahdr-images/45004/20 - -- Step 1: Export SDR to PNG (HDR is already a JPEG-XL) - local exporter = dt.new_format("png") - exporter.bpp = 8 + -- Step 1: Export HDR to JPEG-XL with DT_COLORSPACE_PQ_P3 + local hdr = df.create_unique_filename(settings.tmpdir .. PS .. df.chop_filetype(images["hdr"].filename) .. + ".jxl") + ok = copy_or_export(images["hdr"], hdr, "jpegxl", DT_COLORSPACE_PQ_P3, { + bpp = 10, + quality = 100 -- lossless + }) + if not ok then + os.remove(hdr) + table.insert(errors, string.format(_("Error exporting %s to %s"), images["hdr"].filename, "jxl")) + return false, errors + end + update_job_progress() + -- Step 2: Export SDR to PNG local sdr = df.create_unique_filename(settings.tmpdir .. PS .. df.chop_filetype(images["sdr"].filename) .. ".png") - exporter:write_image(images["sdr"], sdr) + ok = copy_or_export(images["sdr"], sdr, "png", DT_COLORSPACE_DISPLAY_P3, { + bpp = 8 + }) + if not ok then + os.remove(hdr) + os.remove(sdr) + table.insert(errors, string.format(_("Error exporting %s to %s"), images["sdr"].filename, "png")) + return false, errors + end uhdr = df.chop_filetype(sdr) .. "_ultrahdr.jpg" update_job_progress() - local extra = df.create_unique_filename(settings.tmpdir .. PS .. images["hdr"].filename .. ".raw") - - -- Step 3: Generate libultrahdr RAW images - execute_cmd(settings.bin.ffmpeg .. " -i " .. df.sanitize_filename(sdr) .. " -pix_fmt rgba -f rawvideo " .. + -- Step 3: Generate libultrahdr RAW images + local sdr_w, sdr_h = get_dimensions(images["sdr"]) + local resize_cmd = "" + if sdr_h % 2 + sdr_w % 2 > 0 then -- needs resizing to even dimensions. + resize_cmd = string.format(" -vf 'crop=%d:%d:0:0' ", sdr_w - sdr_w % 2, sdr_h - sdr_h % 2) + end + + execute_cmd(settings.bin.ffmpeg .. " -i " .. df.sanitize_filename(sdr) .. resize_cmd .. " -pix_fmt rgba -f rawvideo " .. df.sanitize_filename(sdr .. ".raw")) - execute_cmd(settings.bin.ffmpeg .. " -i " .. - df.sanitize_filename(images["hdr"].path .. PS .. images["hdr"].filename) .. - " -pix_fmt p010le -f rawvideo " .. df.sanitize_filename(extra)) + execute_cmd(settings.bin.ffmpeg .. " -i " .. df.sanitize_filename(hdr) .. resize_cmd .. " -pix_fmt p010le -f rawvideo " .. + df.sanitize_filename(hdr .. ".raw")) update_job_progress() - local sdr_w, sdr_h = get_dimensions(images["sdr"]) execute_cmd(settings.bin.ultrahdr_app .. " -m 0 -y " .. df.sanitize_filename(sdr .. ".raw") .. " -p " .. - df.sanitize_filename(extra) .. " -a 0 -b 3 -c 1 -C 1 -t 2 -M 1 -s 1 -q 95 -Q 95 -D 1 " .. " -w " .. - tostring(sdr_w) .. " -h " .. tostring(sdr_h) .. " -z " .. df.sanitize_filename(uhdr)) + df.sanitize_filename(hdr .. ".raw") .. + string.format(" -a 0 -b 3 -c 1 -C 1 -t 2 -M 1 -s 1 -q %d -Q %d -D 1 ", settings.quality, + settings.quality) .. " -w " .. tostring(sdr_w - sdr_w % 2) .. " -h " .. tostring(sdr_h - sdr_h % 2) .. " -z " .. + df.sanitize_filename(uhdr)) update_job_progress() if settings.copy_exif then -- Restricting tags to EXIF only, to make sure we won't mess up XMP tags (-all>all). @@ -409,9 +489,10 @@ local function generate_ultrahdr(encoding_variant, images, settings, step, total df.sanitize_filename(uhdr) .. " -overwrite_original -preserve") end -- Cleanup + os.remove(hdr) os.remove(sdr) + os.remove(hdr .. ".raw") os.remove(sdr .. ".raw") - os.remove(extra) update_job_progress() end @@ -433,12 +514,10 @@ local function generate_ultrahdr(encoding_variant, images, settings, step, total log.msg(log.info, msg) dt.print(msg) update_job_progress() + return true, nil end local function main() - local saved_log_level = log.log_level() - log.log_level(log.info) - save_preferences() local selection_type = GUI.optionwidgets.selection_type_combo.selected @@ -447,21 +526,25 @@ local function main() local settings, errors = assert_settings_correct(encoding_variant) if not settings then - dt.print(string.format(_("Export settings are incorrect, exiting:\n\n%s"), table.concat(errors, "\n"))) - log.log_level(saved_log_level) + dt.print(string.format(_("Export settings are incorrect, exiting:\n\n- %s"), table.concat(errors, "\n- "))) return end local stacks, stack_count = get_stacks(dt.gui.selection(), encoding_variant, selection_type) dt.print(string.format(_("Detected %d image stack(s)"), stack_count)) if stack_count == 0 then - log.log_level(saved_log_level) return end job = dt.gui.create_job(_("Generating UltraHDR images"), true, stop_job) local count = 0 + local msg for i, v in pairs(stacks) do - generate_ultrahdr(encoding_variant, v, settings, count, stack_count) + local ok, errors = generate_ultrahdr(encoding_variant, v, settings, count, stack_count) + if not ok then + dt.print(string.format(_("Errors generating images:\n\n- %s"), table.concat(errors, "\n- "))) + job.valid = false + return + end count = count + 1 -- sleep for a short moment to give stop_job callback function a chance to run dt.control.sleep(10) @@ -471,10 +554,9 @@ local function main() job.valid = false end - local msg = string.format(_("Generated %d UltraHDR image(s)."), count) + msg = string.format(_("Generated %d UltraHDR image(s)."), count) log.msg(log.info, msg) dt.print(msg) - log.log_level(saved_log_level) end GUI.optionwidgets.settings_label = dt.new_widget("section_label") { @@ -591,12 +673,12 @@ GUI.optionwidgets.encoding_variant_combo = dt.new_widget("combobox") { This will determine the method used to generate UltraHDR. - %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 images only. Gainmaps will be copies of SDR images (the simplest option). +- %s: SDR image paired with an HDR image. +- %s: Each stack consists of a single SDR image. Gainmaps will be copies of SDR images. By default, the first image in a stack is treated as SDR, and the second one is a gainmap/HDR. -You can force the image into a specific stack slot by attaching "hdr" / "gainmap" tags to them. -]]), _("SDR + gainmap"), _("SDR + JPEG-XL HDR"), _("SDR only")), +You can force the image into a specific stack slot by attaching "hdr" / "gainmap" tags to it. +]]), _("SDR + gainmap"), _("SDR + HDR"), _("SDR only")), selected = 0, changed_callback = function(self) GUI.run.sensitive = self.selected and self.selected > 0 @@ -607,7 +689,7 @@ You can force the image into a specific stack slot by attaching "hdr" / "gainmap end end, _("SDR + gainmap"), -- ENCODING_VARIANT_SDR_AND_GAINMAP - _("SDR + JPEG-XL HDR"), -- ENCODING_VARIANT_SDR_AND_HDR + _("SDR + HDR"), -- ENCODING_VARIANT_SDR_AND_HDR _("SDR only") -- ENCODING_VARIANT_SDR_AUTO_GAINMAP } @@ -627,10 +709,25 @@ As an added precaution, each image in a stack needs to have the same dimensions. _("multiple stacks (use filename)") -- SELECTION_TYPE_GROUP_BY_FNAME } +GUI.optionwidgets.quality_widget = dt.new_widget("slider") { + label = _('Quality'), + tooltip = _('Quality of the output UltraHDR JPEG file'), + hard_min = 0, + hard_max = 100, + soft_min = 0, + soft_max = 100, + step = 1, + digits = 0, + reset_callback = function(self) + self.value = 95 + end +} + GUI.optionwidgets.encoding_settings_box = dt.new_widget("box") { orientation = "vertical", GUI.optionwidgets.selection_type_combo, GUI.optionwidgets.encoding_variant_combo, + GUI.optionwidgets.quality_widget, GUI.optionwidgets.metadata_box } @@ -656,10 +753,7 @@ GUI.options = dt.new_widget("box") { GUI.run = dt.new_widget("button") { label = _("Generate UltraHDR"), - tooltip = _([[Generate UltraHDR image(s) from selection - -Global options in the export module apply to the SDR image. Make sure that a proper color 'profile' setting is used (e.g. Display P3) -]]), + tooltip = _("Generate UltraHDR image(s) from selection"), clicked_callback = main } From 3791b47914bce99129fa3eed69f06d20772b5deb Mon Sep 17 00:00:00 2001 From: Krzysztof Kotowicz Date: Tue, 24 Sep 2024 15:03:52 +0200 Subject: [PATCH 404/445] Use lowercase labels to adjust to DT style. --- contrib/ultrahdr.lua | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/contrib/ultrahdr.lua b/contrib/ultrahdr.lua index f013ff37..4d37a6c3 100644 --- a/contrib/ultrahdr.lua +++ b/contrib/ultrahdr.lua @@ -1,6 +1,6 @@ --[[ - UltraHDR storage for darktable + UltraHDR image generation for darktable copyright (c) 2024 Krzysztof Kotowicz @@ -20,7 +20,7 @@ ]] --[[ ULTRAHDR -Generate UltraHDR JPG images from various combinations of source files (SDR, HDR, gainmap). +Generate UltraHDR JPEG images from various combinations of source files (SDR, HDR, gainmap). https://developer.android.com/media/platform/hdr-image-format @@ -34,6 +34,7 @@ ADDITIONAL SOFTWARE NEEDED FOR THIS SCRIPT USAGE * require this file from your main luarc config file * set binary tool paths +* Use UltraHDR module to generate UltraHDR images from selection ]] local dt = require "darktable" local du = require "lib/dtutils" @@ -564,16 +565,16 @@ GUI.optionwidgets.settings_label = dt.new_widget("section_label") { } GUI.optionwidgets.output_settings_label = dt.new_widget("section_label") { - label = _("Output") + label = _("output") } GUI.optionwidgets.output_directory_widget = dt.new_widget("file_chooser_button") { - title = _("Select directory to write UltraHDR image files to"), + title = _("select directory to write UltraHDR image files to"), is_directory = true } GUI.optionwidgets.use_original_directory = dt.new_widget("check_button") { - label = _("Export to original directory"), + label = _("export to original directory"), tooltip = _("Write UltraHDR images to the same directory as their original images"), clicked_callback = function(self) GUI.optionwidgets.output_directory_widget.sensitive = not self.value @@ -581,12 +582,12 @@ GUI.optionwidgets.use_original_directory = dt.new_widget("check_button") { } GUI.optionwidgets.import_to_darktable = dt.new_widget("check_button") { - label = _("Import UltraHDRs to Darktable"), + label = _("import UltraHDRs to library"), tooltip = _("Import UltraHDR images to Darktable library after generating, with an 'ultrahdr' tag attached.") } GUI.optionwidgets.copy_exif = dt.new_widget("check_button") { - label = _("Copy EXIF data from SDR file(s)"), + label = _("copy EXIF data"), tooltip = _("Copy EXIF data into UltraHDR file(s) from their SDR sources.") } @@ -600,11 +601,11 @@ GUI.optionwidgets.output_settings_box = dt.new_widget("box") { } GUI.optionwidgets.metadata_label = dt.new_widget("label") { - label = _("Gainmap metadata") + label = _("gainmap metadata") } GUI.optionwidgets.min_content_boost = dt.new_widget("slider") { - label = _('Min content boost'), + label = _('min content boost'), tooltip = _( 'How much darker an image can get, when shown on an HDR display, relative to the SDR rendition (linear, SDR = 1.0). Also called "GainMapMin". '), hard_min = 0.9, @@ -618,7 +619,7 @@ GUI.optionwidgets.min_content_boost = dt.new_widget("slider") { end } GUI.optionwidgets.max_content_boost = dt.new_widget("slider") { - label = _('Max content boost'), + label = _('max content boost'), tooltip = _( 'How much brighter an image can get, when shown on an HDR display, relative to the SDR rendition (linear, SDR = 1.0). Also called "GainMapMax". \n\nMust not be lower than Min content boost'), hard_min = 1, @@ -632,7 +633,7 @@ GUI.optionwidgets.max_content_boost = dt.new_widget("slider") { end } GUI.optionwidgets.hdr_capacity_min = dt.new_widget("slider") { - label = _('Min HDR capacity'), + label = _('min HDR capacity'), tooltip = _('Minimum display boost value for which the gain map is applied at all (linear, SDR = 1.0).'), hard_min = 0.9, hard_max = 10, @@ -645,7 +646,7 @@ GUI.optionwidgets.hdr_capacity_min = dt.new_widget("slider") { end } GUI.optionwidgets.hdr_capacity_max = dt.new_widget("slider") { - label = _('Max HDR capacity'), + label = _('max HDR capacity'), tooltip = _('Maximum display boost value for which the gain map is applied completely (linear, SDR = 1.0).'), hard_min = 1, hard_max = 10, @@ -668,7 +669,7 @@ GUI.optionwidgets.metadata_box = dt.new_widget("box") { } GUI.optionwidgets.encoding_variant_combo = dt.new_widget("combobox") { - label = _("Each stack contains"), + label = _("each stack contains"), tooltip = string.format(_([[Select the types of images in each stack. This will determine the method used to generate UltraHDR. @@ -694,7 +695,7 @@ You can force the image into a specific stack slot by attaching "hdr" / "gainmap } GUI.optionwidgets.selection_type_combo = dt.new_widget("combobox") { - label = _("Selection contains"), + 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). @@ -710,7 +711,7 @@ As an added precaution, each image in a stack needs to have the same dimensions. } GUI.optionwidgets.quality_widget = dt.new_widget("slider") { - label = _('Quality'), + label = _('quality'), tooltip = _('Quality of the output UltraHDR JPEG file'), hard_min = 0, hard_max = 100, @@ -735,7 +736,7 @@ GUI.optionwidgets.executable_path_widget = df.executable_path_widget({"ultrahdr_ GUI.optionwidgets.executable_path_widget.visible = false GUI.optionwidgets.edit_executables_button = dt.new_widget("button") { - label = _("Show / hide executables"), + label = _("show / hide executables"), tooltip = _("Show / hide settings for executable files required for the plugin functionality"), clicked_callback = function() GUI.optionwidgets.executable_path_widget.visible = not GUI.optionwidgets.executable_path_widget.visible @@ -752,7 +753,7 @@ GUI.options = dt.new_widget("box") { } GUI.run = dt.new_widget("button") { - label = _("Generate UltraHDR"), + label = _("generate UltraHDR"), tooltip = _("Generate UltraHDR image(s) from selection"), clicked_callback = main } From 84a1c1ddfe4ca43e919f95f11f40e58169f7727b Mon Sep 17 00:00:00 2001 From: Krzysztof Kotowicz Date: Wed, 25 Sep 2024 19:47:18 +0200 Subject: [PATCH 405/445] Use single channel gainmaps in SDR+HDR. --- contrib/ultrahdr.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/ultrahdr.lua b/contrib/ultrahdr.lua index 4d37a6c3..a3b30e0a 100644 --- a/contrib/ultrahdr.lua +++ b/contrib/ultrahdr.lua @@ -479,7 +479,7 @@ local function generate_ultrahdr(encoding_variant, images, settings, step, total update_job_progress() execute_cmd(settings.bin.ultrahdr_app .. " -m 0 -y " .. df.sanitize_filename(sdr .. ".raw") .. " -p " .. df.sanitize_filename(hdr .. ".raw") .. - string.format(" -a 0 -b 3 -c 1 -C 1 -t 2 -M 1 -s 1 -q %d -Q %d -D 1 ", settings.quality, + string.format(" -a 0 -b 3 -c 1 -C 1 -t 2 -M 0 -s 1 -q %d -Q %d -D 1 ", settings.quality, settings.quality) .. " -w " .. tostring(sdr_w - sdr_w % 2) .. " -h " .. tostring(sdr_h - sdr_h % 2) .. " -z " .. df.sanitize_filename(uhdr)) update_job_progress() From 749db97dd53fbf21b98042b759de7c61df006c7d Mon Sep 17 00:00:00 2001 From: Krzysztof Kotowicz Date: Wed, 25 Sep 2024 19:47:41 +0200 Subject: [PATCH 406/445] Speed up export in HDR+SDR. --- contrib/ultrahdr.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/contrib/ultrahdr.lua b/contrib/ultrahdr.lua index a3b30e0a..508ef8dd 100644 --- a/contrib/ultrahdr.lua +++ b/contrib/ultrahdr.lua @@ -442,7 +442,8 @@ local function generate_ultrahdr(encoding_variant, images, settings, step, total ".jxl") ok = copy_or_export(images["hdr"], hdr, "jpegxl", DT_COLORSPACE_PQ_P3, { bpp = 10, - quality = 100 -- lossless + quality = 100, -- lossless + effort = 1, -- we don't care about the size, the faile is temporary. }) if not ok then os.remove(hdr) From 2a4452cd20fcb7586556d2e8ad61264674ab1074 Mon Sep 17 00:00:00 2001 From: Krzysztof Kotowicz Date: Wed, 25 Sep 2024 21:30:09 +0200 Subject: [PATCH 407/445] Workaround https://github.com/darktable-org/darktable/pull/17529 for future DT versions. --- contrib/ultrahdr.lua | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/contrib/ultrahdr.lua b/contrib/ultrahdr.lua index 508ef8dd..f1f859cf 100644 --- a/contrib/ultrahdr.lua +++ b/contrib/ultrahdr.lua @@ -46,8 +46,8 @@ local gettext = dt.gettext.gettext local namespace = "module_ultrahdr" --- works with darktable API version from 5.0.0 on -du.check_min_api_version("7.0.0", "ultrahdr") +-- works with darktable API version from 4.8.0 on +du.check_min_api_version("9.3.0", "ultrahdr") dt.gettext.bindtextdomain(namespace, dt.configuration.config_dir .. "/lua/locale/") @@ -360,7 +360,12 @@ local function generate_ultrahdr(encoding_variant, images, settings, step, total for k, v in pairs(props) do exporter[k] = v end - local ok = not exporter:write_image(src_image, dest) + local ok = exporter:write_image(src_image, dest) + if dt.configuration.api_version_string == "9.3.0" then + -- Workaround for https://github.com/darktable-org/darktable/issues/17528 + ok = not ok + end + if prev then set_combobox("lib/export/profile", 0, "plugins/lighttable/export/icctype", prev) end From ea7ac8e474bd8a066f2ee034f1401f9cd360606a Mon Sep 17 00:00:00 2001 From: Krzysztof Kotowicz Date: Wed, 25 Sep 2024 21:38:35 +0200 Subject: [PATCH 408/445] Abort and cleanup early when any of the binaries fail. --- contrib/ultrahdr.lua | 142 ++++++++++++++++++++++++++----------------- 1 file changed, 85 insertions(+), 57 deletions(-) diff --git a/contrib/ultrahdr.lua b/contrib/ultrahdr.lua index f1f859cf..83568c8f 100644 --- a/contrib/ultrahdr.lua +++ b/contrib/ultrahdr.lua @@ -328,16 +328,23 @@ local function stop_job(job) job.valid = false end -local function execute_cmd(cmd) - log.msg(log.debug, cmd) - return dtsys.external_command(cmd) -end - local function generate_ultrahdr(encoding_variant, images, settings, step, total_steps) local total_substeps local substep = 0 local uhdr local errors = {} + local remove_files = {} + local ok + local cmd + + local function execute_cmd(cmd, errormsg) + log.msg(log.debug, cmd) + local code = dtsys.external_command(cmd) + if errormsg and code > 0 then + table.insert(errors, errormsg) + end + return code == 0 + end function update_job_progress() substep = substep + 1 @@ -374,19 +381,25 @@ local function generate_ultrahdr(encoding_variant, images, settings, step, total return true end + function cleanup() + for _, v in pairs(remove_files) do + os.remove(v) + end + return false + end + if encoding_variant == ENCODING_VARIANT_SDR_AND_GAINMAP or encoding_variant == ENCODING_VARIANT_SDR_AUTO_GAINMAP then - total_substeps = 6 - local ok + total_substeps = 5 -- Export/copy both SDR and gainmap to JPEGs local sdr = df.create_unique_filename(settings.tmpdir .. PS .. df.chop_filetype(images["sdr"].filename) .. ".jpg") + table.insert(remove_files, sdr) ok = copy_or_export(images["sdr"], sdr, "jpeg", DT_COLORSPACE_DISPLAY_P3, { quality = settings.quality }) if not ok then - os.remove(sdr) table.insert(errors, string.format(_("Error exporting %s to %s"), images["sdr"].filename, "jpeg")) - return false, errors + return cleanup(), errors end local gainmap @@ -394,52 +407,56 @@ local function generate_ultrahdr(encoding_variant, images, settings, step, total gainmap = sdr else gainmap = df.create_unique_filename(settings.tmpdir .. PS .. images["gainmap"].filename .. "_gainmap.jpg") + table.insert(remove_files, gainmap) ok = copy_or_export(images["gainmap"], gainmap, "jpeg", DT_COLORSPACE_DISPLAY_P3, { quality = settings.quality }) if not ok then - os.remove(sdr) - os.remove(sdr) table.insert(errors, string.format(_("Error exporting %s to %s"), images["gainmap"].filename, "jpeg")) - return false, errors + return cleanup(), errors end end log.msg(log.debug, string.format(_("Exported files: %s, %s"), sdr, gainmap)) update_job_progress() -- Strip EXIFs - execute_cmd(settings.bin.exiftool .. " -all= " .. df.sanitize_filename(sdr) .. " -o " .. - df.sanitize_filename(sdr .. ".noexif")) + table.insert(remove_files, sdr .. ".noexif") + cmd = settings.bin.exiftool .. " -all= " .. df.sanitize_filename(sdr) .. " -o " .. + df.sanitize_filename(sdr .. ".noexif") + if not execute_cmd(cmd, string.format(_("Error stripping EXIF from %s"), sdr)) then + return cleanup(), errors + end if sdr ~= gainmap then - execute_cmd(settings.bin.exiftool .. " -all= " .. df.sanitize_filename(gainmap) .. " -overwrite_original") + if not execute_cmd(settings.bin.exiftool .. " -all= " .. df.sanitize_filename(gainmap) .. + " -overwrite_original", string.format(_("Error stripping EXIF from %s"), gainmap)) then + return cleanup(), errors + end end update_job_progress() -- Generate metadata.cfg file local metadata_file = generate_metadata_file(settings) + table.insert(remove_files, metadata_file) -- Merge files uhdr = df.chop_filetype(sdr) .. "_ultrahdr.jpg" - - execute_cmd(settings.bin.ultrahdr_app .. " -m 0 -i " .. df.sanitize_filename(sdr .. ".noexif") .. " -g " .. - df.sanitize_filename(gainmap) .. " -f " .. df.sanitize_filename(metadata_file) .. " -z " .. - df.sanitize_filename(uhdr)) + table.insert(remove_files, uhdr) + cmd = settings.bin.ultrahdr_app .. " -m 0 -i " .. df.sanitize_filename(sdr .. ".noexif") .. " -g " .. + df.sanitize_filename(gainmap) .. " -f " .. df.sanitize_filename(metadata_file) .. " -z " .. + df.sanitize_filename(uhdr) + if not execute_cmd(cmd, string.format(_("Error merging UltraHDR to %s"), uhdr)) then + return cleanup(), errors + end update_job_progress() -- Copy SDR's EXIF to UltraHDR file if settings.copy_exif then -- Restricting tags to EXIF only, to make sure we won't mess up XMP tags (-all>all). -- This might hapen e.g. when the source files are Adobe gainmap HDRs. - execute_cmd(settings.bin.exiftool .. " -tagsfromfile " .. df.sanitize_filename(sdr) .. " -exif " .. - df.sanitize_filename(uhdr) .. " -overwrite_original -preserve") - end - update_job_progress() - -- Cleanup - os.remove(sdr) - os.remove(sdr .. ".noexif") - os.remove(metadata_file) - if sdr ~= gainmap then - os.remove(gainmap) + cmd = settings.bin.exiftool .. " -tagsfromfile " .. df.sanitize_filename(sdr) .. " -exif " .. + df.sanitize_filename(uhdr) .. " -overwrite_original -preserve" + if not execute_cmd(cmd, string.format(_("Error adding EXIF to %s"), uhdr)) then + return cleanup(), errors + end end update_job_progress() elseif encoding_variant == ENCODING_VARIANT_SDR_AND_HDR then - local ok total_substeps = 6 -- https://discuss.pixls.us/t/manual-creation-of-ultrahdr-images/45004/20 -- Step 1: Export HDR to JPEG-XL with DT_COLORSPACE_PQ_P3 @@ -448,28 +465,26 @@ local function generate_ultrahdr(encoding_variant, images, settings, step, total ok = copy_or_export(images["hdr"], hdr, "jpegxl", DT_COLORSPACE_PQ_P3, { bpp = 10, quality = 100, -- lossless - effort = 1, -- we don't care about the size, the faile is temporary. + effort = 1 -- we don't care about the size, the faile is temporary. }) if not ok then - os.remove(hdr) table.insert(errors, string.format(_("Error exporting %s to %s"), images["hdr"].filename, "jxl")) - return false, errors + return cleanup(), errors end update_job_progress() -- Step 2: Export SDR to PNG local sdr = df.create_unique_filename(settings.tmpdir .. PS .. df.chop_filetype(images["sdr"].filename) .. ".png") + table.insert(remove_files, sdr) ok = copy_or_export(images["sdr"], sdr, "png", DT_COLORSPACE_DISPLAY_P3, { bpp = 8 }) if not ok then - os.remove(hdr) - os.remove(sdr) table.insert(errors, string.format(_("Error exporting %s to %s"), images["sdr"].filename, "png")) - return false, errors + return cleanup(), errors end uhdr = df.chop_filetype(sdr) .. "_ultrahdr.jpg" - + table.insert(remove_files, uhdr) update_job_progress() -- Step 3: Generate libultrahdr RAW images local sdr_w, sdr_h = get_dimensions(images["sdr"]) @@ -477,35 +492,48 @@ local function generate_ultrahdr(encoding_variant, images, settings, step, total if sdr_h % 2 + sdr_w % 2 > 0 then -- needs resizing to even dimensions. resize_cmd = string.format(" -vf 'crop=%d:%d:0:0' ", sdr_w - sdr_w % 2, sdr_h - sdr_h % 2) end - - execute_cmd(settings.bin.ffmpeg .. " -i " .. df.sanitize_filename(sdr) .. resize_cmd .. " -pix_fmt rgba -f rawvideo " .. - df.sanitize_filename(sdr .. ".raw")) - execute_cmd(settings.bin.ffmpeg .. " -i " .. df.sanitize_filename(hdr) .. resize_cmd .. " -pix_fmt p010le -f rawvideo " .. - df.sanitize_filename(hdr .. ".raw")) + table.insert(remove_files, sdr .. ".raw") + table.insert(remove_files, hdr .. ".raw") + cmd = + settings.bin.ffmpeg .. " -i " .. df.sanitize_filename(sdr) .. resize_cmd .. " -pix_fmt rgba -f rawvideo " .. + df.sanitize_filename(sdr .. ".raw") + if not execute_cmd(cmd, string.format(_("Error generating %s"), sdr .. ".raw")) then + return cleanup(), errors + end + cmd = settings.bin.ffmpeg .. " -i " .. df.sanitize_filename(hdr) .. resize_cmd .. + " -pix_fmt p010le -f rawvideo " .. df.sanitize_filename(hdr .. ".raw") + if not execute_cmd(cmd, string.format(_("Error generating %s"), hdr .. ".raw")) then + return cleanup(), errors + end update_job_progress() - execute_cmd(settings.bin.ultrahdr_app .. " -m 0 -y " .. df.sanitize_filename(sdr .. ".raw") .. " -p " .. - df.sanitize_filename(hdr .. ".raw") .. - string.format(" -a 0 -b 3 -c 1 -C 1 -t 2 -M 0 -s 1 -q %d -Q %d -D 1 ", settings.quality, - settings.quality) .. " -w " .. tostring(sdr_w - sdr_w % 2) .. " -h " .. tostring(sdr_h - sdr_h % 2) .. " -z " .. - df.sanitize_filename(uhdr)) + cmd = settings.bin.ultrahdr_app .. " -m 0 -y " .. df.sanitize_filename(sdr .. ".raw") .. " -p " .. + df.sanitize_filename(hdr .. ".raw") .. + string.format(" -a 0 -b 3 -c 1 -C 1 -t 2 -M 0 -s 1 -q %d -Q %d -D 1 ", settings.quality, + settings.quality) .. " -w " .. tostring(sdr_w - sdr_w % 2) .. " -h " .. tostring(sdr_h - sdr_h % 2) .. + " -z " .. df.sanitize_filename(uhdr) + if not execute_cmd(cmd, string.format(_("Error merging %s"), uhdr)) then + return cleanup(), errors + end update_job_progress() if settings.copy_exif then -- Restricting tags to EXIF only, to make sure we won't mess up XMP tags (-all>all). -- This might hapen e.g. when the source files are Adobe gainmap HDRs. - execute_cmd(settings.bin.exiftool .. " -tagsfromfile " .. df.sanitize_filename(sdr) .. " -exif " .. - df.sanitize_filename(uhdr) .. " -overwrite_original -preserve") + cmd = settings.bin.exiftool .. " -tagsfromfile " .. df.sanitize_filename(sdr) .. " -exif " .. + df.sanitize_filename(uhdr) .. " -overwrite_original -preserve" + if not execute_cmd(cmd, string.format(_("Error adding EXIF to %s"), uhdr)) then + return cleanup(), errors + end end - -- Cleanup - os.remove(hdr) - os.remove(sdr) - os.remove(hdr .. ".raw") - os.remove(sdr .. ".raw") update_job_progress() end local output_dir = settings.use_original_dir and images["sdr"].path or settings.output local output_file = df.create_unique_filename(output_dir .. PS .. df.get_filename(uhdr)) - df.file_move(uhdr, output_file) + ok = df.file_move(uhdr, output_file) + if not ok then + table.insert(errors, string.format(_("Error generating UltraHDR for %s"), images["sdr"].filename)) + return cleanup(), errors + end if settings.import_to_darktable then local img = dt.database.import(output_file) -- Add "ultrahdr" tag to the imported image @@ -516,11 +544,11 @@ local function generate_ultrahdr(encoding_variant, images, settings, step, total end dt.tags.attach(tagnr, img) end - + cleanup() + update_job_progress() local msg = string.format(_("Generated %s."), df.get_filename(output_file)) log.msg(log.info, msg) dt.print(msg) - update_job_progress() return true, nil end From 268aa7df42dadb1770f078b2a7fffcb677b636e4 Mon Sep 17 00:00:00 2001 From: Krzysztof Kotowicz Date: Thu, 26 Sep 2024 09:05:31 +0200 Subject: [PATCH 409/445] Removed darktable capitalization. --- contrib/ultrahdr.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contrib/ultrahdr.lua b/contrib/ultrahdr.lua index 83568c8f..d26a72f9 100644 --- a/contrib/ultrahdr.lua +++ b/contrib/ultrahdr.lua @@ -617,7 +617,7 @@ GUI.optionwidgets.use_original_directory = dt.new_widget("check_button") { GUI.optionwidgets.import_to_darktable = dt.new_widget("check_button") { label = _("import UltraHDRs to library"), - tooltip = _("Import UltraHDR images to Darktable library after generating, with an 'ultrahdr' tag attached.") + tooltip = _("Import UltraHDR images to darktable library after generating, with an 'ultrahdr' tag attached.") } GUI.optionwidgets.copy_exif = dt.new_widget("check_button") { @@ -730,12 +730,12 @@ You can force the image into a specific stack slot by attaching "hdr" / "gainmap GUI.optionwidgets.selection_type_combo = dt.new_widget("combobox") { label = _("selection contains"), - tooltip = string.format(_([[Select types of images selected in Darktable. + 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. + 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)")), From 13ae486ab3abbebbb8c5f379748a9cf249573ca9 Mon Sep 17 00:00:00 2001 From: Krzysztof Kotowicz Date: Thu, 26 Sep 2024 10:02:47 +0200 Subject: [PATCH 410/445] Verify raw file size in pixels. Added option to keep temporary files around for analysis. --- contrib/ultrahdr.lua | 45 +++++++++++++++++++++++++++++++++----------- 1 file changed, 34 insertions(+), 11 deletions(-) diff --git a/contrib/ultrahdr.lua b/contrib/ultrahdr.lua index d26a72f9..74baab9e 100644 --- a/contrib/ultrahdr.lua +++ b/contrib/ultrahdr.lua @@ -221,7 +221,8 @@ local function assert_settings_correct(encoding_variant) hdr_capacity_max = GUI.optionwidgets.hdr_capacity_max.value }, quality = GUI.optionwidgets.quality_widget.value, - tmpdir = dt.configuration.tmp_dir + tmpdir = dt.configuration.tmp_dir, + skip_cleanup = false -- keep temporary files around, for debugging. } if not settings.use_original_dir and (not settings.output or not df.check_if_file_exists(settings.output)) then @@ -328,6 +329,16 @@ local function stop_job(job) job.valid = false end +local function file_size(path) + local f, err = io.open(path, "r") + if not f then + return 0 + end + local size = f:seek("end") + f:close() + return size +end + local function generate_ultrahdr(encoding_variant, images, settings, step, total_steps) local total_substeps local substep = 0 @@ -382,6 +393,9 @@ local function generate_ultrahdr(encoding_variant, images, settings, step, total end function cleanup() + if settings.skip_cleanup then + return false + end for _, v in pairs(remove_files) do os.remove(v) end @@ -462,6 +476,7 @@ local function generate_ultrahdr(encoding_variant, images, settings, step, total -- Step 1: Export HDR to JPEG-XL with DT_COLORSPACE_PQ_P3 local hdr = df.create_unique_filename(settings.tmpdir .. PS .. df.chop_filetype(images["hdr"].filename) .. ".jxl") + table.insert(remove_files, hdr) ok = copy_or_export(images["hdr"], hdr, "jpegxl", DT_COLORSPACE_PQ_P3, { bpp = 10, quality = 100, -- lossless @@ -487,27 +502,34 @@ local function generate_ultrahdr(encoding_variant, images, settings, step, total table.insert(remove_files, uhdr) update_job_progress() -- Step 3: Generate libultrahdr RAW images + local sdr_raw, hdr_raw = sdr .. ".raw", hdr .. ".raw" + table.insert(remove_files, sdr_raw) + table.insert(remove_files, hdr_raw) local sdr_w, sdr_h = get_dimensions(images["sdr"]) local resize_cmd = "" if sdr_h % 2 + sdr_w % 2 > 0 then -- needs resizing to even dimensions. resize_cmd = string.format(" -vf 'crop=%d:%d:0:0' ", sdr_w - sdr_w % 2, sdr_h - sdr_h % 2) end - table.insert(remove_files, sdr .. ".raw") - table.insert(remove_files, hdr .. ".raw") + local size_in_px = (sdr_w - sdr_w % 2) * (sdr_h - sdr_h % 2) cmd = settings.bin.ffmpeg .. " -i " .. df.sanitize_filename(sdr) .. resize_cmd .. " -pix_fmt rgba -f rawvideo " .. - df.sanitize_filename(sdr .. ".raw") - if not execute_cmd(cmd, string.format(_("Error generating %s"), sdr .. ".raw")) then + df.sanitize_filename(sdr_raw) + if not execute_cmd(cmd, string.format(_("Error generating %s"), sdr_raw)) then return cleanup(), errors end cmd = settings.bin.ffmpeg .. " -i " .. df.sanitize_filename(hdr) .. resize_cmd .. - " -pix_fmt p010le -f rawvideo " .. df.sanitize_filename(hdr .. ".raw") - if not execute_cmd(cmd, string.format(_("Error generating %s"), hdr .. ".raw")) then + " -pix_fmt p010le -f rawvideo " .. df.sanitize_filename(hdr_raw) + if not execute_cmd(cmd, string.format(_("Error generating %s"), hdr_raw)) then + return cleanup(), errors + end + -- sanity check for file sizes (sometimes dt exports different size images if the files were never opened in darktable view) + if file_size(sdr_raw) ~= size_in_px * 4 or file_size(hdr_raw) ~= size_in_px & 3 then + table.insert(errors, string.format(_("Wrong raw image dimensions: %s, expected %dx%d. Try opening the image in darktable mode first."), images["sdr"].filename, sdr_w, sdr_h)) return cleanup(), errors end update_job_progress() - cmd = settings.bin.ultrahdr_app .. " -m 0 -y " .. df.sanitize_filename(sdr .. ".raw") .. " -p " .. - df.sanitize_filename(hdr .. ".raw") .. + cmd = settings.bin.ultrahdr_app .. " -m 0 -y " .. df.sanitize_filename(sdr_raw) .. " -p " .. + df.sanitize_filename(hdr_raw) .. string.format(" -a 0 -b 3 -c 1 -C 1 -t 2 -M 0 -s 1 -q %d -Q %d -D 1 ", settings.quality, settings.quality) .. " -w " .. tostring(sdr_w - sdr_w % 2) .. " -h " .. tostring(sdr_h - sdr_h % 2) .. " -z " .. df.sanitize_filename(uhdr) @@ -566,17 +588,18 @@ local function main() end local stacks, stack_count = get_stacks(dt.gui.selection(), encoding_variant, selection_type) - dt.print(string.format(_("Detected %d image stack(s)"), stack_count)) if stack_count == 0 then + dt.print(string.format(_("No image stacks detected.\n\nMake sure that the image pairs have the same widths and heights."), stack_count)) return end + dt.print(string.format(_("Detected %d image stack(s)"), stack_count)) job = dt.gui.create_job(_("Generating UltraHDR images"), true, stop_job) local count = 0 local msg for i, v in pairs(stacks) do local ok, errors = generate_ultrahdr(encoding_variant, v, settings, count, stack_count) if not ok then - dt.print(string.format(_("Errors generating images:\n\n- %s"), table.concat(errors, "\n- "))) + dt.print(string.format(_("Generating UltraHDR images failed:\n\n- %s"), table.concat(errors, "\n- "))) job.valid = false return end From a3404b64deb80df6cf482d2aea8bebeb78686a54 Mon Sep 17 00:00:00 2001 From: Krzysztof Kotowicz Date: Thu, 26 Sep 2024 10:44:14 +0200 Subject: [PATCH 411/445] Renamed gainmap to "gain map" in UI. --- contrib/ultrahdr.lua | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/contrib/ultrahdr.lua b/contrib/ultrahdr.lua index 74baab9e..abe9da95 100644 --- a/contrib/ultrahdr.lua +++ b/contrib/ultrahdr.lua @@ -20,7 +20,7 @@ ]] --[[ ULTRAHDR -Generate UltraHDR JPEG images from various combinations of source files (SDR, HDR, gainmap). +Generate UltraHDR JPEG images from various combinations of source files (SDR, HDR, gain map). https://developer.android.com/media/platform/hdr-image-format @@ -658,7 +658,7 @@ GUI.optionwidgets.output_settings_box = dt.new_widget("box") { } GUI.optionwidgets.metadata_label = dt.new_widget("label") { - label = _("gainmap metadata") + label = _("gain map metadata") } GUI.optionwidgets.min_content_boost = dt.new_widget("slider") { @@ -732,11 +732,11 @@ This will determine the method used to generate UltraHDR. - %s: SDR image paired with a gain map image. - %s: SDR image paired with an HDR image. -- %s: Each stack consists of a single SDR image. Gainmaps will be copies of SDR images. +- %s: Each stack consists of a single SDR image. Gain maps will be copies of SDR images. -By default, the first image in a stack is treated as SDR, and the second one is a gainmap/HDR. +By default, the first image in a stack is treated as SDR, and the second one is a gain map/HDR. You can force the image into a specific stack slot by attaching "hdr" / "gainmap" tags to it. -]]), _("SDR + gainmap"), _("SDR + HDR"), _("SDR only")), +]]), _("SDR + gain map"), _("SDR + HDR"), _("SDR only")), selected = 0, changed_callback = function(self) GUI.run.sensitive = self.selected and self.selected > 0 @@ -746,7 +746,7 @@ You can force the image into a specific stack slot by attaching "hdr" / "gainmap GUI.optionwidgets.metadata_box.visible = false end end, - _("SDR + gainmap"), -- ENCODING_VARIANT_SDR_AND_GAINMAP + _("SDR + gain map"), -- ENCODING_VARIANT_SDR_AND_GAINMAP _("SDR + HDR"), -- ENCODING_VARIANT_SDR_AND_HDR _("SDR only") -- ENCODING_VARIANT_SDR_AUTO_GAINMAP } From e4da226661da5ac2c4a35867d351da8cbeef36f7 Mon Sep 17 00:00:00 2001 From: Krzysztof Kotowicz Date: Thu, 26 Sep 2024 10:45:03 +0200 Subject: [PATCH 412/445] Added gainmap downsampling. --- contrib/ultrahdr.lua | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/contrib/ultrahdr.lua b/contrib/ultrahdr.lua index abe9da95..261a8862 100644 --- a/contrib/ultrahdr.lua +++ b/contrib/ultrahdr.lua @@ -77,7 +77,8 @@ local GUI = { metadata_box = {}, edit_executables_button = {}, executable_path_widget = {}, - quality_widget = {} + quality_widget = {}, + gainmap_downsampling_widget = {}, }, options = {}, run = {} @@ -145,6 +146,7 @@ local function save_preferences() dt.preferences.write(namespace, "hdr_capacity_max", "float", GUI.optionwidgets.hdr_capacity_max.value) end dt.preferences.write(namespace, "quality", "integer", GUI.optionwidgets.quality_widget.value) + dt.preferences.write(namespace, "gainmap_downsampling", "integer", GUI.optionwidgets.gainmap_downsampling_widget.value) end local function default_to(value, default) @@ -177,6 +179,7 @@ local function load_preferences() GUI.optionwidgets.hdr_capacity_max.value = default_to(dt.preferences.read(namespace, "hdr_capacity_max", "float"), 6.0) GUI.optionwidgets.quality_widget.value = default_to(dt.preferences.read(namespace, "quality", "integer"), 95) + GUI.optionwidgets.gainmap_downsampling_widget.value = default_to(dt.preferences.read(namespace, "gainmap_downsampling", "integer"), 0) end -- Changes the combobox selection blindly until a paired config value is set. @@ -221,6 +224,7 @@ local function assert_settings_correct(encoding_variant) hdr_capacity_max = GUI.optionwidgets.hdr_capacity_max.value }, quality = GUI.optionwidgets.quality_widget.value, + downsample = 2^GUI.optionwidgets.gainmap_downsampling_widget.value, tmpdir = dt.configuration.tmp_dir, skip_cleanup = false -- keep temporary files around, for debugging. } @@ -531,7 +535,7 @@ local function generate_ultrahdr(encoding_variant, images, settings, step, total cmd = settings.bin.ultrahdr_app .. " -m 0 -y " .. df.sanitize_filename(sdr_raw) .. " -p " .. df.sanitize_filename(hdr_raw) .. string.format(" -a 0 -b 3 -c 1 -C 1 -t 2 -M 0 -s 1 -q %d -Q %d -D 1 ", settings.quality, - settings.quality) .. " -w " .. tostring(sdr_w - sdr_w % 2) .. " -h " .. tostring(sdr_h - sdr_h % 2) .. + settings.quality) .. string.format(" -s %d ", settings.downsample) .. " -w " .. tostring(sdr_w - sdr_w % 2) .. " -h " .. tostring(sdr_h - sdr_h % 2) .. " -z " .. df.sanitize_filename(uhdr) if not execute_cmd(cmd, string.format(_("Error merging %s"), uhdr)) then return cleanup(), errors @@ -742,8 +746,10 @@ You can force the image into a specific stack slot by attaching "hdr" / "gainmap GUI.run.sensitive = self.selected and self.selected > 0 if self.selected == ENCODING_VARIANT_SDR_AND_GAINMAP or self.selected == ENCODING_VARIANT_SDR_AUTO_GAINMAP then GUI.optionwidgets.metadata_box.visible = true + GUI.optionwidgets.gainmap_downsampling_widget.visible = false else GUI.optionwidgets.metadata_box.visible = false + GUI.optionwidgets.gainmap_downsampling_widget.visible = true end end, _("SDR + gain map"), -- ENCODING_VARIANT_SDR_AND_GAINMAP @@ -781,11 +787,26 @@ GUI.optionwidgets.quality_widget = dt.new_widget("slider") { end } +GUI.optionwidgets.gainmap_downsampling_widget = dt.new_widget("slider") { + label = _('gain map downsampling steps'), + tooltip = _('Exponent (2^x) of the gain map downsampling factor.\nDownsampling reduces the file size, at the expense of quality.\n\n0 = don\'t downsample the gain map, 7 = maximum downsampling (128x)'), + hard_min = 0, + hard_max = 7, + soft_min = 0, + soft_max = 7, + step = 1, + digits = 0, + reset_callback = function(self) + self.value = 0 + end +} + GUI.optionwidgets.encoding_settings_box = dt.new_widget("box") { orientation = "vertical", GUI.optionwidgets.selection_type_combo, GUI.optionwidgets.encoding_variant_combo, GUI.optionwidgets.quality_widget, + GUI.optionwidgets.gainmap_downsampling_widget, GUI.optionwidgets.metadata_box } From 72ce0b0f937d7d823a597e1a5c888ec61d4dba6c Mon Sep 17 00:00:00 2001 From: Krzysztof Kotowicz Date: Thu, 24 Oct 2024 08:13:49 +0200 Subject: [PATCH 413/445] Small fixes --- contrib/ultrahdr.lua | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/contrib/ultrahdr.lua b/contrib/ultrahdr.lua index 261a8862..e17c2a6c 100644 --- a/contrib/ultrahdr.lua +++ b/contrib/ultrahdr.lua @@ -484,7 +484,7 @@ local function generate_ultrahdr(encoding_variant, images, settings, step, total ok = copy_or_export(images["hdr"], hdr, "jpegxl", DT_COLORSPACE_PQ_P3, { bpp = 10, quality = 100, -- lossless - effort = 1 -- we don't care about the size, the faile is temporary. + effort = 1 -- we don't care about the size, the file is temporary. }) if not ok then table.insert(errors, string.format(_("Error exporting %s to %s"), images["hdr"].filename, "jxl")) @@ -527,8 +527,8 @@ local function generate_ultrahdr(encoding_variant, images, settings, step, total return cleanup(), errors end -- sanity check for file sizes (sometimes dt exports different size images if the files were never opened in darktable view) - if file_size(sdr_raw) ~= size_in_px * 4 or file_size(hdr_raw) ~= size_in_px & 3 then - table.insert(errors, string.format(_("Wrong raw image dimensions: %s, expected %dx%d. Try opening the image in darktable mode first."), images["sdr"].filename, sdr_w, sdr_h)) + if file_size(sdr_raw) ~= size_in_px * 4 or file_size(hdr_raw) ~= size_in_px * 3 then + table.insert(errors, string.format(_("Wrong raw image resolution: %s, expected %dx%d. Try opening the image in darktable mode first."), images["sdr"].filename, sdr_w, sdr_h)) return cleanup(), errors end update_job_progress() @@ -766,7 +766,7 @@ This determines how the plugin groups images into separate stacks (each stack wi - %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. +As an added precaution, each image in a stack needs to have the same resolution. ]]), _("one stack"), _("multiple stacks (use filename)")), selected = 0, _("one stack"), -- SELECTION_TYPE_ONE_STACK @@ -789,7 +789,7 @@ GUI.optionwidgets.quality_widget = dt.new_widget("slider") { GUI.optionwidgets.gainmap_downsampling_widget = dt.new_widget("slider") { label = _('gain map downsampling steps'), - tooltip = _('Exponent (2^x) of the gain map downsampling factor.\nDownsampling reduces the file size, at the expense of quality.\n\n0 = don\'t downsample the gain map, 7 = maximum downsampling (128x)'), + tooltip = _('Exponent (2^x) of the gain map downsampling factor.\nDownsampling reduces the gain map resolution.\n\n0 = don\'t downsample the gain map, 7 = maximum downsampling (128x)'), hard_min = 0, hard_max = 7, soft_min = 0, From 95e2e4924ef2942ad0421403c2f1e682b03a0897 Mon Sep 17 00:00:00 2001 From: Krzysztof Kotowicz Date: Mon, 25 Nov 2024 17:14:30 +0100 Subject: [PATCH 414/445] Added HDR only encoding variant. - Increase timeouts to improve stability of choosing export profiles. - Added peak nits setting. --- contrib/ultrahdr.lua | 192 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 157 insertions(+), 35 deletions(-) diff --git a/contrib/ultrahdr.lua b/contrib/ultrahdr.lua index e17c2a6c..35d02031 100644 --- a/contrib/ultrahdr.lua +++ b/contrib/ultrahdr.lua @@ -79,6 +79,7 @@ local GUI = { executable_path_widget = {}, quality_widget = {}, gainmap_downsampling_widget = {}, + target_display_peak_nits_widget = {} }, options = {}, run = {} @@ -100,6 +101,7 @@ local PS = dt.configuration.running_os == "windows" and "\\" or "/" local ENCODING_VARIANT_SDR_AND_GAINMAP = 1 local ENCODING_VARIANT_SDR_AND_HDR = 2 local ENCODING_VARIANT_SDR_AUTO_GAINMAP = 3 +local ENCODING_VARIANT_HDR_ONLY = 4 local SELECTION_TYPE_ONE_STACK = 1 local SELECTION_TYPE_GROUP_BY_FNAME = 2 @@ -146,7 +148,11 @@ local function save_preferences() dt.preferences.write(namespace, "hdr_capacity_max", "float", GUI.optionwidgets.hdr_capacity_max.value) end dt.preferences.write(namespace, "quality", "integer", GUI.optionwidgets.quality_widget.value) - dt.preferences.write(namespace, "gainmap_downsampling", "integer", GUI.optionwidgets.gainmap_downsampling_widget.value) + dt.preferences.write(namespace, "gainmap_downsampling", "integer", + GUI.optionwidgets.gainmap_downsampling_widget.value) + dt.preferences.write(namespace, "target_display_peak_nits", "integer", + (GUI.optionwidgets.target_display_peak_nits_widget.value+0.5)//1) + end local function default_to(value, default) @@ -179,7 +185,10 @@ local function load_preferences() GUI.optionwidgets.hdr_capacity_max.value = default_to(dt.preferences.read(namespace, "hdr_capacity_max", "float"), 6.0) GUI.optionwidgets.quality_widget.value = default_to(dt.preferences.read(namespace, "quality", "integer"), 95) - GUI.optionwidgets.gainmap_downsampling_widget.value = default_to(dt.preferences.read(namespace, "gainmap_downsampling", "integer"), 0) + GUI.optionwidgets.target_display_peak_nits_widget.value = default_to( + dt.preferences.read(namespace, "target_display_peak_nits", "integer"), 10000) + GUI.optionwidgets.gainmap_downsampling_widget.value = default_to( + dt.preferences.read(namespace, "gainmap_downsampling", "integer"), 0) end -- Changes the combobox selection blindly until a paired config value is set. @@ -192,11 +201,12 @@ local function set_combobox(path, instance, config_name, new_config_value) end dt.gui.action(path, 0, "selection", "first", 1.0) + dt.control.sleep(50) local limit, i = 30, 0 -- in case there is no matching config value in the first n entries of a combobox. while i < limit do i = i + 1 dt.gui.action(path, 0, "selection", "next", 1.0) - dt.control.sleep(10) + dt.control.sleep(50) if dt.preferences.read("darktable", config_name, "integer") == new_config_value then log.msg(log.debug, string.format(_("Changed %s from %d to %d"), config_name, pref, new_config_value)) return pref @@ -224,7 +234,8 @@ local function assert_settings_correct(encoding_variant) hdr_capacity_max = GUI.optionwidgets.hdr_capacity_max.value }, quality = GUI.optionwidgets.quality_widget.value, - downsample = 2^GUI.optionwidgets.gainmap_downsampling_widget.value, + target_display_peak_nits = (GUI.optionwidgets.target_display_peak_nits_widget.value+0.5)//1, + downsample = 2 ^ GUI.optionwidgets.gainmap_downsampling_widget.value, tmpdir = dt.configuration.tmp_dir, skip_cleanup = false -- keep temporary files around, for debugging. } @@ -263,23 +274,27 @@ end local function get_stacks(images, encoding_variant, selection_type) local stacks = {} - local extra_image_content_type + local primary = "sdr" + local extra if encoding_variant == ENCODING_VARIANT_SDR_AND_GAINMAP then - extra_image_content_type = "gainmap" + extra = "gainmap" elseif encoding_variant == ENCODING_VARIANT_SDR_AND_HDR then - extra_image_content_type = "hdr" + extra = "hdr" elseif encoding_variant == ENCODING_VARIANT_SDR_AUTO_GAINMAP then - extra_image_content_type = nil + extra = nil + elseif encoding_variant == ENCODING_VARIANT_HDR_ONLY then + extra = nil + primary = "hdr" end local tags = nil - -- Group images into (sdr [,extra]) stacks - -- 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 + -- Group images into (primary [,extra]) stacks + -- Assume that the first encountered image from each stack is a primary one, unless it has a tag matching the expected extra_image_type, or has the expected extension for k, v in pairs(images) do local is_extra = false tags = dt.tags.get_tags(v) for ignore, tag in pairs(tags) do - if extra_image_content_type and tag.name == extra_image_content_type then + if extra and tag.name == extra then is_extra = true end end @@ -296,27 +311,27 @@ local function get_stacks(images, encoding_variant, selection_type) if stacks[key] == nil then stacks[key] = {} end - if extra_image_content_type and (is_extra or stacks[key]["sdr"]) then + if extra and (is_extra or stacks[key][primary]) then -- Don't overwrite existing entries - if not stacks[key][extra_image_content_type] then - stacks[key][extra_image_content_type] = v + if not stacks[key][extra] then + stacks[key][extra] = v end elseif not is_extra then -- Don't overwrite existing entries - if not stacks[key]["sdr"] then - stacks[key]["sdr"] = v + if not stacks[key][primary] then + stacks[key][primary] = v end end end -- remove invalid stacks local count = 0 for k, v in pairs(stacks) do - if extra_image_content_type then - if not v["sdr"] or not v[extra_image_content_type] then + if extra then + if not v[primary] or not v[extra] then stacks[k] = nil else - local sdr_w, sdr_h = get_dimensions(v["sdr"]) - local extra_w, extra_h = get_dimensions(v[extra_image_content_type]) + local sdr_w, sdr_h = get_dimensions(v[primary]) + local extra_w, extra_h = get_dimensions(v[extra]) if (sdr_w ~= extra_w) or (sdr_h ~= extra_h) then stacks[k] = nil end @@ -346,6 +361,7 @@ end local function generate_ultrahdr(encoding_variant, images, settings, step, total_steps) local total_substeps local substep = 0 + local best_source_image local uhdr local errors = {} local remove_files = {} @@ -408,6 +424,7 @@ local function generate_ultrahdr(encoding_variant, images, settings, step, total if encoding_variant == ENCODING_VARIANT_SDR_AND_GAINMAP or encoding_variant == ENCODING_VARIANT_SDR_AUTO_GAINMAP then total_substeps = 5 + best_source_image = images["sdr"] -- Export/copy both SDR and gainmap to JPEGs local sdr = df.create_unique_filename(settings.tmpdir .. PS .. df.chop_filetype(images["sdr"].filename) .. ".jpg") @@ -456,9 +473,13 @@ local function generate_ultrahdr(encoding_variant, images, settings, step, total -- Merge files uhdr = df.chop_filetype(sdr) .. "_ultrahdr.jpg" table.insert(remove_files, uhdr) - cmd = settings.bin.ultrahdr_app .. " -m 0 -i " .. df.sanitize_filename(sdr .. ".noexif") .. " -g " .. - df.sanitize_filename(gainmap) .. " -f " .. df.sanitize_filename(metadata_file) .. " -z " .. - df.sanitize_filename(uhdr) + cmd = settings.bin.ultrahdr_app .. + string.format(" -m 0 -i %s -g %s -L %d -f %s -z %s", df.sanitize_filename(sdr .. ".noexif"), -- -i + df.sanitize_filename(gainmap), -- -g + settings.target_display_peak_nits, -- -L + df.sanitize_filename(metadata_file), -- -f + df.sanitize_filename(uhdr) -- -z + ) if not execute_cmd(cmd, string.format(_("Error merging UltraHDR to %s"), uhdr)) then return cleanup(), errors end @@ -476,6 +497,7 @@ local function generate_ultrahdr(encoding_variant, images, settings, step, total update_job_progress() elseif encoding_variant == ENCODING_VARIANT_SDR_AND_HDR then total_substeps = 6 + best_source_image = images["sdr"] -- https://discuss.pixls.us/t/manual-creation-of-ultrahdr-images/45004/20 -- Step 1: Export HDR to JPEG-XL with DT_COLORSPACE_PQ_P3 local hdr = df.create_unique_filename(settings.tmpdir .. PS .. df.chop_filetype(images["hdr"].filename) .. @@ -528,15 +550,26 @@ local function generate_ultrahdr(encoding_variant, images, settings, step, total end -- sanity check for file sizes (sometimes dt exports different size images if the files were never opened in darktable view) if file_size(sdr_raw) ~= size_in_px * 4 or file_size(hdr_raw) ~= size_in_px * 3 then - table.insert(errors, string.format(_("Wrong raw image resolution: %s, expected %dx%d. Try opening the image in darktable mode first."), images["sdr"].filename, sdr_w, sdr_h)) + table.insert(errors, + string.format( + _("Wrong raw image resolution: %s, expected %dx%d. Try opening the image in darktable mode first."), + images["sdr"].filename, sdr_w, sdr_h)) return cleanup(), errors end update_job_progress() - cmd = settings.bin.ultrahdr_app .. " -m 0 -y " .. df.sanitize_filename(sdr_raw) .. " -p " .. - df.sanitize_filename(hdr_raw) .. - string.format(" -a 0 -b 3 -c 1 -C 1 -t 2 -M 0 -s 1 -q %d -Q %d -D 1 ", settings.quality, - settings.quality) .. string.format(" -s %d ", settings.downsample) .. " -w " .. tostring(sdr_w - sdr_w % 2) .. " -h " .. tostring(sdr_h - sdr_h % 2) .. - " -z " .. df.sanitize_filename(uhdr) + cmd = settings.bin.ultrahdr_app .. + string.format( + " -m 0 -y %s -p %s -a 0 -b 3 -c 1 -C 1 -t 2 -M 0 -q %d -Q %d -L %d -D 1 -s %d -w %d -h %d -z %s", + df.sanitize_filename(sdr_raw), -- -y + df.sanitize_filename(hdr_raw), -- -p + settings.quality, -- -q + settings.quality, -- -Q + settings.target_display_peak_nits, -- -L + settings.downsample, -- -s + sdr_w - sdr_w % 2, -- w + sdr_h - sdr_h % 2, -- h + df.sanitize_filename(uhdr) -- z + ) if not execute_cmd(cmd, string.format(_("Error merging %s"), uhdr)) then return cleanup(), errors end @@ -551,13 +584,82 @@ local function generate_ultrahdr(encoding_variant, images, settings, step, total end end update_job_progress() + elseif encoding_variant == ENCODING_VARIANT_HDR_ONLY then + total_substeps = 5 + best_source_image = images["hdr"] + -- TODO: Check if exporting to JXL would be ok too. + -- Step 1: Export HDR to JPEG-XL with DT_COLORSPACE_PQ_P3 + local hdr = df.create_unique_filename(settings.tmpdir .. PS .. df.chop_filetype(images["hdr"].filename) .. + ".jxl") + table.insert(remove_files, hdr) + ok = copy_or_export(images["hdr"], hdr, "jpegxl", DT_COLORSPACE_PQ_P3, { + bpp = 10, + quality = 100, -- lossless + effort = 1 -- we don't care about the size, the file is temporary. + }) + if not ok then + table.insert(errors, string.format(_("Error exporting %s to %s"), images["hdr"].filename, "jxl")) + return cleanup(), errors + end + update_job_progress() + -- Step 1: Generate raw HDR image + local hdr_raw = df.create_unique_filename(settings.tmpdir .. PS .. df.chop_filetype(images["hdr"].filename) .. + ".raw") + table.insert(remove_files, hdr_raw) + local hdr_w, hdr_h = get_dimensions(images["hdr"]) + local resize_cmd = "" + if hdr_h % 2 + hdr_w % 2 > 0 then -- needs resizing to even dimensions. + resize_cmd = string.format(" -vf 'crop=%d:%d:0:0' ", hdr_w - hdr_w % 2, hdr_h - hdr_h % 2) + end + local size_in_px = (hdr_w - hdr_w % 2) * (hdr_h - hdr_h % 2) + cmd = settings.bin.ffmpeg .. " -i " .. df.sanitize_filename(hdr) .. resize_cmd .. + " -pix_fmt p010le -f rawvideo " .. df.sanitize_filename(hdr_raw) + if not execute_cmd(cmd, string.format(_("Error generating %s"), hdr_raw)) then + return cleanup(), errors + end + if file_size(hdr_raw) ~= size_in_px * 3 then + table.insert(errors, + string.format( + _("Wrong raw image resolution: %s, expected %dx%d. Try opening the image in darktable mode first."), + images["hdr"].filename, hdr_w, hdr_h)) + return cleanup(), errors + end + update_job_progress() + uhdr = df.chop_filetype(hdr_raw) .. "_ultrahdr.jpg" + table.insert(remove_files, uhdr) + cmd = settings.bin.ultrahdr_app .. + string.format( + " -m 0 -p %s -a 0 -b 3 -c 1 -C 1 -t 2 -M 0 -q %d -Q %d -D 1 -L %d -s %d -w %d -h %d -z %s", + df.sanitize_filename(hdr_raw), -- -p + settings.quality, -- -q + settings.quality, -- -Q + settings.target_display_peak_nits, -- -L + settings.downsample, -- s + hdr_w - hdr_w % 2, -- -w + hdr_h - hdr_h % 2, -- -h + df.sanitize_filename(uhdr) -- -z + ) + if not execute_cmd(cmd, string.format(_("Error merging %s"), uhdr)) then + return cleanup(), errors + end + update_job_progress() + if settings.copy_exif then + -- Restricting tags to EXIF only, to make sure we won't mess up XMP tags (-all>all). + -- This might hapen e.g. when the source files are Adobe gainmap HDRs. + cmd = settings.bin.exiftool .. " -tagsfromfile " .. df.sanitize_filename(hdr) .. " -exif " .. + df.sanitize_filename(uhdr) .. " -overwrite_original -preserve" + if not execute_cmd(cmd, string.format(_("Error adding EXIF to %s"), uhdr)) then + return cleanup(), errors + end + end + update_job_progress() end - local output_dir = settings.use_original_dir and images["sdr"].path or settings.output + local output_dir = settings.use_original_dir and best_source_image.path or settings.output local output_file = df.create_unique_filename(output_dir .. PS .. df.get_filename(uhdr)) ok = df.file_move(uhdr, output_file) if not ok then - table.insert(errors, string.format(_("Error generating UltraHDR for %s"), images["sdr"].filename)) + table.insert(errors, string.format(_("Error generating UltraHDR for %s"), best_source_image.filename)) return cleanup(), errors end if settings.import_to_darktable then @@ -593,7 +695,9 @@ local function main() local stacks, stack_count = get_stacks(dt.gui.selection(), encoding_variant, selection_type) if stack_count == 0 then - dt.print(string.format(_("No image stacks detected.\n\nMake sure that the image pairs have the same widths and heights."), stack_count)) + dt.print(string.format(_( + "No image stacks detected.\n\nMake sure that the image pairs have the same widths and heights."), + stack_count)) return end dt.print(string.format(_("Detected %d image stack(s)"), stack_count)) @@ -737,10 +841,11 @@ This will determine the method used to generate UltraHDR. - %s: SDR image paired with a gain map image. - %s: SDR image paired with an HDR image. - %s: Each stack consists of a single SDR image. Gain maps will be copies of SDR images. +- %s: Each stack consists of a single HDR image. HDR will be tone mapped to SDR. By default, the first image in a stack is treated as SDR, and the second one is a gain map/HDR. You can force the image into a specific stack slot by attaching "hdr" / "gainmap" tags to it. -]]), _("SDR + gain map"), _("SDR + HDR"), _("SDR only")), +]]), _("SDR + gain map"), _("SDR + HDR"), _("SDR only"), _("HDR only")), selected = 0, changed_callback = function(self) GUI.run.sensitive = self.selected and self.selected > 0 @@ -754,7 +859,8 @@ You can force the image into a specific stack slot by attaching "hdr" / "gainmap end, _("SDR + gain map"), -- ENCODING_VARIANT_SDR_AND_GAINMAP _("SDR + HDR"), -- ENCODING_VARIANT_SDR_AND_HDR - _("SDR only") -- ENCODING_VARIANT_SDR_AUTO_GAINMAP + _("SDR only"), -- ENCODING_VARIANT_SDR_AUTO_GAINMAP + _("HDR only") -- ENCODING_VARIANT_HDR_ONLY } GUI.optionwidgets.selection_type_combo = dt.new_widget("combobox") { @@ -787,9 +893,24 @@ GUI.optionwidgets.quality_widget = dt.new_widget("slider") { end } +GUI.optionwidgets.target_display_peak_nits_widget = dt.new_widget("slider") { + label = _('target display peak brightness (nits)'), + tooltip = _('Peak brightness of target display in nits (defaults to 10000)'), + hard_min = 203, + hard_max = 10000, + soft_min = 1000, + soft_max = 10000, + step = 10, + digits = 0, + reset_callback = function(self) + self.value = 10000 + end +} + GUI.optionwidgets.gainmap_downsampling_widget = dt.new_widget("slider") { label = _('gain map downsampling steps'), - tooltip = _('Exponent (2^x) of the gain map downsampling factor.\nDownsampling reduces the gain map resolution.\n\n0 = don\'t downsample the gain map, 7 = maximum downsampling (128x)'), + tooltip = _( + 'Exponent (2^x) of the gain map downsampling factor.\nDownsampling reduces the gain map resolution.\n\n0 = don\'t downsample the gain map, 7 = maximum downsampling (128x)'), hard_min = 0, hard_max = 7, soft_min = 0, @@ -807,6 +928,7 @@ GUI.optionwidgets.encoding_settings_box = dt.new_widget("box") { GUI.optionwidgets.encoding_variant_combo, GUI.optionwidgets.quality_widget, GUI.optionwidgets.gainmap_downsampling_widget, + GUI.optionwidgets.target_display_peak_nits_widget, GUI.optionwidgets.metadata_box } From a09140c03c475bd9d0deb51645574ddf5172550f Mon Sep 17 00:00:00 2001 From: Krzysztof Kotowicz Date: Mon, 2 Dec 2024 23:40:15 +0100 Subject: [PATCH 415/445] Variable substitution in output directory. Force exporting files, but left the code to reconfigure it. Added more robust way to set export profile. --- contrib/ultrahdr.lua | 100 +++++++++++++++++++++++++++---------------- 1 file changed, 62 insertions(+), 38 deletions(-) diff --git a/contrib/ultrahdr.lua b/contrib/ultrahdr.lua index 35d02031..111c521b 100644 --- a/contrib/ultrahdr.lua +++ b/contrib/ultrahdr.lua @@ -39,6 +39,7 @@ USAGE ]] local dt = require "darktable" local du = require "lib/dtutils" local df = require "lib/dtutils.file" +local ds = require "lib/dtutils.string" local log = require "lib/dtutils.log" local dtsys = require "lib/dtutils.system" local dd = require "lib/dtutils.debug" @@ -65,8 +66,9 @@ local GUI = { encoding_settings_box = {}, output_settings_label = {}, output_settings_box = {}, - use_original_directory = {}, - output_directory_widget = {}, + output_filepath_label = {}, + output_filepath_widget = {}, + overwrite_on_conflict = {}, copy_exif = {}, import_to_darktable = {}, min_content_boost = {}, @@ -110,6 +112,12 @@ local SELECTION_TYPE_GROUP_BY_FNAME = 2 local DT_COLORSPACE_PQ_P3 = 24 local DT_COLORSPACE_DISPLAY_P3 = 26 +-- 1-based position of a colorspace in export profile combobox. +local COLORSPACE_TO_GUI_ACTION = { + [DT_COLORSPACE_PQ_P3] = 9, + [DT_COLORSPACE_DISPLAY_P3] = 11 +} + local function generate_metadata_file(settings) local metadata_file_fmt = [[--maxContentBoost %f --minContentBoost %f @@ -135,10 +143,8 @@ end local function save_preferences() 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) - dt.preferences.write(namespace, "use_original_directory", "bool", GUI.optionwidgets.use_original_directory.value) - if GUI.optionwidgets.output_directory_widget.value then - dt.preferences.write(namespace, "output_directory", "string", GUI.optionwidgets.output_directory_widget.value) - end + dt.preferences.write(namespace, "output_filepath_pattern", "string", GUI.optionwidgets.output_filepath_widget.text) + dt.preferences.write(namespace, "overwrite_on_conflict", "bool", GUI.optionwidgets.overwrite_on_conflict.value) dt.preferences.write(namespace, "import_to_darktable", "bool", GUI.optionwidgets.import_to_darktable.value) dt.preferences.write(namespace, "copy_exif", "bool", GUI.optionwidgets.copy_exif.value) if GUI.optionwidgets.min_content_boost.value then @@ -151,7 +157,7 @@ local function save_preferences() dt.preferences.write(namespace, "gainmap_downsampling", "integer", GUI.optionwidgets.gainmap_downsampling_widget.value) dt.preferences.write(namespace, "target_display_peak_nits", "integer", - (GUI.optionwidgets.target_display_peak_nits_widget.value+0.5)//1) + (GUI.optionwidgets.target_display_peak_nits_widget.value + 0.5) // 1) end @@ -169,11 +175,8 @@ local function load_preferences() GUI.optionwidgets.selection_type_combo.selected = math.max( dt.preferences.read(namespace, "selection_type", "integer"), SELECTION_TYPE_ONE_STACK) - GUI.optionwidgets.output_directory_widget.value = dt.preferences.read(namespace, "output_directory", "string") - GUI.optionwidgets.use_original_directory.value = dt.preferences.read(namespace, "use_original_directory", "bool") - if not GUI.optionwidgets.output_directory_widget.value then - GUI.optionwidgets.use_original_directory.value = true - end + GUI.optionwidgets.output_filepath_widget.text = dt.preferences.read(namespace, "output_filepath_pattern", "string") + GUI.optionwidgets.overwrite_on_conflict.value = dt.preferences.read(namespace, "overwrite_on_conflict", "bool") GUI.optionwidgets.import_to_darktable.value = dt.preferences.read(namespace, "import_to_darktable", "bool") GUI.optionwidgets.copy_exif.value = dt.preferences.read(namespace, "copy_exif", "bool") GUI.optionwidgets.min_content_boost.value = default_to(dt.preferences.read(namespace, "min_content_boost", "float"), @@ -191,10 +194,25 @@ local function load_preferences() dt.preferences.read(namespace, "gainmap_downsampling", "integer"), 0) end +local function set_profile(colorspace) + local set_directly = true + + if set_directly then + -- New method, with hardcoded export profile values. + local old = dt.gui.action("lib/export/profile", 0, "selection", "", "") * -1 + local new = COLORSPACE_TO_GUI_ACTION[colorspace] or colorspace + log.msg(log.debug, string.format("%d %d %d %d", colorspace, new, old, new - old)) + dt.gui.action("lib/export/profile", 0, "selection", "next", new - old) + return old + else + -- Old method, timing-dependent + return set_combobox("lib/export/profile", 0, "plugins/lighttable/export/icctype", colorspace) + end +end + -- Changes the combobox selection blindly until a paired config value is set. -- Workaround for https://github.com/darktable-org/lua-scripts/issues/522 local function set_combobox(path, instance, config_name, new_config_value) - local pref = dt.preferences.read("darktable", config_name, "integer") if pref == new_config_value then return new_config_value @@ -223,8 +241,8 @@ local function assert_settings_correct(encoding_variant) exiftool = df.check_if_bin_exists("exiftool"), ffmpeg = df.check_if_bin_exists("ffmpeg") }, - output = GUI.optionwidgets.output_directory_widget.value, - use_original_dir = GUI.optionwidgets.use_original_directory.value, + overwrite_on_conflict = GUI.optionwidgets.overwrite_on_conflict.value, + output_filepath_pattern = GUI.optionwidgets.output_filepath_widget.text, import_to_darktable = GUI.optionwidgets.import_to_darktable.value, copy_exif = GUI.optionwidgets.copy_exif.value, metadata = { @@ -234,16 +252,13 @@ local function assert_settings_correct(encoding_variant) hdr_capacity_max = GUI.optionwidgets.hdr_capacity_max.value }, quality = GUI.optionwidgets.quality_widget.value, - target_display_peak_nits = (GUI.optionwidgets.target_display_peak_nits_widget.value+0.5)//1, + target_display_peak_nits = (GUI.optionwidgets.target_display_peak_nits_widget.value + 0.5) // 1, downsample = 2 ^ GUI.optionwidgets.gainmap_downsampling_widget.value, tmpdir = dt.configuration.tmp_dir, - skip_cleanup = false -- keep temporary files around, for debugging. + skip_cleanup = false, -- keep temporary files around, for debugging. + force_export = true -- if false, will copy source files instead of exporting if the file extension matches the format expectation. } - if not settings.use_original_dir and (not settings.output or not df.check_if_file_exists(settings.output)) then - table.insert(errors, string.format(_("output directory (%s) not found"), settings.output)) - end - for k, v in pairs(settings.bin) do if not v then table.insert(errors, string.format(_("%s binary not found"), k)) @@ -387,10 +402,11 @@ local function generate_ultrahdr(encoding_variant, images, settings, step, total end function copy_or_export(src_image, dest, format, colorspace, props) - if df.get_filetype(src_image.filename) == df.get_filetype(dest) and not src_image.is_altered then + if not settings.force_export and df.get_filetype(src_image.filename) == df.get_filetype(dest) and + not src_image.is_altered then return df.file_copy(src_image.path .. PS .. src_image.filename, dest) else - local prev = set_combobox("lib/export/profile", 0, "plugins/lighttable/export/icctype", colorspace) + local prev = set_profile(colorspace) if not prev then return false end @@ -405,7 +421,7 @@ local function generate_ultrahdr(encoding_variant, images, settings, step, total end if prev then - set_combobox("lib/export/profile", 0, "plugins/lighttable/export/icctype", prev) + set_profile(prev) end return ok end @@ -655,8 +671,10 @@ local function generate_ultrahdr(encoding_variant, images, settings, step, total update_job_progress() end - local output_dir = settings.use_original_dir and best_source_image.path or settings.output - local output_file = df.create_unique_filename(output_dir .. PS .. df.get_filename(uhdr)) + local output_file = ds.substitute(best_source_image, step + 1, settings.output_filepath_pattern) .. ".jpg" + if not settings.overwrite_on_conflict then + output_file = df.create_unique_filename(output_file) + end ok = df.file_move(uhdr, output_file) if not ok then table.insert(errors, string.format(_("Error generating UltraHDR for %s"), best_source_image.filename)) @@ -733,17 +751,20 @@ GUI.optionwidgets.output_settings_label = dt.new_widget("section_label") { label = _("output") } -GUI.optionwidgets.output_directory_widget = dt.new_widget("file_chooser_button") { - title = _("select directory to write UltraHDR image files to"), - is_directory = true +GUI.optionwidgets.output_filepath_label = dt.new_widget("label") { + label = _("file path pattern"), + tooltip = ds.get_substitution_tooltip() } -GUI.optionwidgets.use_original_directory = dt.new_widget("check_button") { - label = _("export to original directory"), - tooltip = _("Write UltraHDR images to the same directory as their original images"), - clicked_callback = function(self) - GUI.optionwidgets.output_directory_widget.sensitive = not self.value - end +GUI.optionwidgets.output_filepath_widget = dt.new_widget("entry") { + tooltip = ds.get_substitution_tooltip(), + placeholder = _("e.g. $(FILE_FOLDER)/$(FILE_NAME)_ultrahdr") +} + +GUI.optionwidgets.overwrite_on_conflict = dt.new_widget("check_button") { + label = _("overwrite if exists"), + tooltip = _( + "If the output file already exists, overwrite it. If unchecked, a unique filename will be created instead.") } GUI.optionwidgets.import_to_darktable = dt.new_widget("check_button") { @@ -759,8 +780,9 @@ GUI.optionwidgets.copy_exif = dt.new_widget("check_button") { GUI.optionwidgets.output_settings_box = dt.new_widget("box") { orientation = "vertical", GUI.optionwidgets.output_settings_label, - GUI.optionwidgets.use_original_directory, - GUI.optionwidgets.output_directory_widget, + GUI.optionwidgets.output_filepath_label, + GUI.optionwidgets.output_filepath_widget, + GUI.optionwidgets.overwrite_on_conflict, GUI.optionwidgets.import_to_darktable, GUI.optionwidgets.copy_exif } @@ -845,7 +867,9 @@ This will determine the method used to generate UltraHDR. By default, the first image in a stack is treated as SDR, and the second one is a gain map/HDR. You can force the image into a specific stack slot by attaching "hdr" / "gainmap" tags to it. -]]), _("SDR + gain map"), _("SDR + HDR"), _("SDR only"), _("HDR only")), + +For HDR source images, apply a log2(203 nits/10000 nits) = -5.62 EV exposure correction +before generating UltraHDR.]]), _("SDR + gain map"), _("SDR + HDR"), _("SDR only"), _("HDR only")), selected = 0, changed_callback = function(self) GUI.run.sensitive = self.selected and self.selected > 0 From 77c405882d9cca8f68163c67eca6b8ebad067922 Mon Sep 17 00:00:00 2001 From: Krzysztof Kotowicz Date: Tue, 3 Dec 2024 19:49:54 +0100 Subject: [PATCH 416/445] Added logging code and a workaround for https://github.com/darktable-org/darktable/issues/17528 in 9.4.0. --- .DS_Store | Bin 0 -> 6148 bytes contrib/ultrahdr.lua | 40 ++++++++++++++++++++++++++++++++++------ 2 files changed, 34 insertions(+), 6 deletions(-) create mode 100644 .DS_Store diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..c6f7696114afdb45c3563536fccffc402bfedec9 GIT binary patch literal 6148 zcmeHKJ8DBQ5S&d6F}QJ=Qdh_ggmF&b3k2H)48{-g>0gy|< z4@cjUNdYM!1*Cu!kOCK0pbG4Kap7}yoD`4(*ROzo9~#}U7mkVX>EIA80CC1}80XPT z5Ss^xy>Luqgl0)4Ce^CNu%t8IDz6ugiAjf5^I>(fRfl46JI`;C4(o{;rGOMTSKv06 zORxWr^k4e_bCOn4KnnaT1#Gt7tXF(e)z-=5yw*1Q6Wwz@>290{g+r8MVw7Vpyd2+0 cQsy 0 then return nil, errors end @@ -288,6 +309,7 @@ local function get_dimensions(image) end local function get_stacks(images, encoding_variant, selection_type) + local old_log_level = set_log_level(LOG_LEVEL) local stacks = {} local primary = "sdr" local extra @@ -356,6 +378,7 @@ local function get_stacks(images, encoding_variant, selection_type) count = count + 1 end end + restore_log_level(old_log_level) return stacks, count end @@ -374,6 +397,7 @@ local function file_size(path) end local function generate_ultrahdr(encoding_variant, images, settings, step, total_steps) + local old_log_level = set_log_level(LOG_LEVEL) local total_substeps local substep = 0 local best_source_image @@ -402,6 +426,8 @@ local function generate_ultrahdr(encoding_variant, images, settings, step, total end function copy_or_export(src_image, dest, format, colorspace, props) + -- Workaround for https://github.com/darktable-org/darktable/issues/17528 + local needs_workaround = dt.configuration.api_version_string == "9.3.0" or dt.configuration.api_version_string == "9.4.0" if not settings.force_export and df.get_filetype(src_image.filename) == df.get_filetype(dest) and not src_image.is_altered then return df.file_copy(src_image.path .. PS .. src_image.filename, dest) @@ -415,11 +441,10 @@ local function generate_ultrahdr(encoding_variant, images, settings, step, total exporter[k] = v end local ok = exporter:write_image(src_image, dest) - if dt.configuration.api_version_string == "9.3.0" then - -- Workaround for https://github.com/darktable-org/darktable/issues/17528 + if needs_workaround then ok = not ok end - + log.msg(log.info, string.format("Exporting %s to %s (format: %s): %s", src_image.filename, dest, format, ok)) if prev then set_profile(prev) end @@ -695,10 +720,12 @@ local function generate_ultrahdr(encoding_variant, images, settings, step, total local msg = string.format(_("Generated %s."), df.get_filename(output_file)) log.msg(log.info, msg) dt.print(msg) + restore_log_level(old_log_level) return true, nil end local function main() + local old_log_level = set_log_level(LOG_LEVEL) save_preferences() local selection_type = GUI.optionwidgets.selection_type_combo.selected @@ -741,6 +768,7 @@ local function main() msg = string.format(_("Generated %d UltraHDR image(s)."), count) log.msg(log.info, msg) dt.print(msg) + restore_log_level(old_log_level) end GUI.optionwidgets.settings_label = dt.new_widget("section_label") { From 3bdbfd12bf7f76e7de148ef3c2024cfe8de34cc0 Mon Sep 17 00:00:00 2001 From: Krzysztof Kotowicz Date: Thu, 5 Dec 2024 00:45:34 +0100 Subject: [PATCH 417/445] Apply write_image workaround only in 9.3.0 --- contrib/ultrahdr.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/ultrahdr.lua b/contrib/ultrahdr.lua index 29b30d9c..fc696ded 100644 --- a/contrib/ultrahdr.lua +++ b/contrib/ultrahdr.lua @@ -427,7 +427,7 @@ local function generate_ultrahdr(encoding_variant, images, settings, step, total function copy_or_export(src_image, dest, format, colorspace, props) -- Workaround for https://github.com/darktable-org/darktable/issues/17528 - local needs_workaround = dt.configuration.api_version_string == "9.3.0" or dt.configuration.api_version_string == "9.4.0" + local needs_workaround = dt.configuration.api_version_string == "9.3.0" if not settings.force_export and df.get_filetype(src_image.filename) == df.get_filetype(dest) and not src_image.is_altered then return df.file_copy(src_image.path .. PS .. src_image.filename, dest) From 1ba488d0735a778ec2f0f5c11ee79fc403001dfe Mon Sep 17 00:00:00 2001 From: Martin Straeten <39386816+MStraeten@users.noreply.github.com> Date: Sun, 15 Dec 2024 19:08:24 +0100 Subject: [PATCH 418/445] Enhanced x-touch.lua for colorequalizer just adapted the colorzone stuff for color equalizer. requires explicitly set the focus via a further switch --- examples/x-touch.lua | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/examples/x-touch.lua b/examples/x-touch.lua index bbe9bbd6..314135e4 100644 --- a/examples/x-touch.lua +++ b/examples/x-touch.lua @@ -48,6 +48,7 @@ midi:A-1=iop/colorzones;focus midi:A#-1=iop/toneequal;focus midi:B-1=iop/colorbalancergb;focus midi:C0=iop/channelmixerrgb;focus +midi:C#0=iop/colorequal;focus ]] local dt = require "darktable" @@ -119,6 +120,18 @@ for k = 1,8 do "magenta" } element = e[k] + -- try if colorequalizer module is focused; if so select element of graph + elseif dt.gui.action("iop/colorequal", "focus") ~= 0 then + local e = { "red", + "orange", + "yellow", + "green", + "cyan", + "blue", + "lavender", + "magenta" } + which = "iop/colorequal/graph" + element = e[k] -- if the sigmoid rgb primaries is focused, -- check sliders From 3c67c0c69304bbe229056ce01408750fb0818720 Mon Sep 17 00:00:00 2001 From: Krzysztof Kotowicz Date: Sat, 21 Dec 2024 10:20:02 +0100 Subject: [PATCH 419/445] Create output directory if it doesn't exist. --- contrib/ultrahdr.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/contrib/ultrahdr.lua b/contrib/ultrahdr.lua index fc696ded..ef7a61fd 100644 --- a/contrib/ultrahdr.lua +++ b/contrib/ultrahdr.lua @@ -700,6 +700,8 @@ local function generate_ultrahdr(encoding_variant, images, settings, step, total if not settings.overwrite_on_conflict then output_file = df.create_unique_filename(output_file) end + local output_path = ds.get_path(output_file) + df.mkdir(output_path) ok = df.file_move(uhdr, output_file) if not ok then table.insert(errors, string.format(_("Error generating UltraHDR for %s"), best_source_image.filename)) From 6d16a8778b61aea1196d78ab901a1aff04eb2ca1 Mon Sep 17 00:00:00 2001 From: Krzysztof Kotowicz Date: Sun, 22 Dec 2024 08:39:38 +0100 Subject: [PATCH 420/445] Removed .DS_Store --- .DS_Store | Bin 6148 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 .DS_Store diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index c6f7696114afdb45c3563536fccffc402bfedec9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHKJ8DBQ5S&d6F}QJ=Qdh_ggmF&b3k2H)48{-g>0gy|< z4@cjUNdYM!1*Cu!kOCK0pbG4Kap7}yoD`4(*ROzo9~#}U7mkVX>EIA80CC1}80XPT z5Ss^xy>Luqgl0)4Ce^CNu%t8IDz6ugiAjf5^I>(fRfl46JI`;C4(o{;rGOMTSKv06 zORxWr^k4e_bCOn4KnnaT1#Gt7tXF(e)z-=5yw*1Q6Wwz@>290{g+r8MVw7Vpyd2+0 cQsy Date: Wed, 1 Jan 2025 17:24:30 -0500 Subject: [PATCH 421/445] README.md - updated links to current documentation --- README.md | 132 +++++++++++++++++++++++++++--------------------------- 1 file changed, 66 insertions(+), 66 deletions(-) diff --git a/README.md b/README.md index d57c8e68..9a5521bb 100644 --- a/README.md +++ b/README.md @@ -15,17 +15,17 @@ These scripts are written primarily by the darktable developers and maintained b Name|Standalone|OS |Purpose ----|:--------:|:---:|------- -[check_for_updates](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/official/check_for_updates)|Yes|LMW|Check for updates to darktable -[copy_paste_metadata](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/official/copy_paste_metadata)|Yes|LMW|Copy and paste metadata, tags, ratings, and color labels between images -[delete_long_tags](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/official/delete_long_tags)|Yes|LMW|Delete all tags longer than a specified length -[delete_unused_tags](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/official/delete_unused_tags)|Yes|LMW|Delete tags that have no associated images -[enfuse](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/official/enfuse)|No|L|Exposure blend several images (HDR) -[generate_image_txt](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/official/generate_image_txt)|No|L|Generate txt sidecar files to be overlaid on zoomed images -[image_path_in_ui](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/official/image_path_in_ui)|Yes|LMW|Plugin to display selected image path -[import_filter_manager](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/official/import_filter_manager)|Yes|LMW|Manager for import filters -[import_filters](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/official/import_filters)|No|LMW|Two import filters for use with import_filter_manager -[save_selection](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/official/save_selection)|Yes|LMW|Provide save and restore from multiple selection buffers -[selection_to_pdf](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/official/selection_to_pdf)|No|L|Generate a PDF file from the selected images +[check_for_updates](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/official/check_for_updates)|Yes|LMW|Check for updates to darktable +[copy_paste_metadata](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/official/copy_paste_metadata)|Yes|LMW|Copy and paste metadata, tags, ratings, and color labels between images +[delete_long_tags](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/official/delete_long_tags)|Yes|LMW|Delete all tags longer than a specified length +[delete_unused_tags](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/official/delete_unused_tags)|Yes|LMW|Delete tags that have no associated images +[enfuse](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/official/enfuse)|No|L|Exposure blend several images (HDR) +[generate_image_txt](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/official/generate_image_txt)|No|L|Generate txt sidecar files to be overlaid on zoomed images +[image_path_in_ui](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/official/image_path_in_ui)|Yes|LMW|Plugin to display selected image path +[import_filter_manager](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/official/import_filter_manager)|Yes|LMW|Manager for import filters +[import_filters](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/official/import_filters)|No|LMW|Two import filters for use with import_filter_manager +[save_selection](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/official/save_selection)|Yes|LMW|Provide save and restore from multiple selection buffers +[selection_to_pdf](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/official/selection_to_pdf)|No|L|Generate a PDF file from the selected images ### Contributed Scripts @@ -34,50 +34,50 @@ These scripts are contributed by users. They are meant to have an "owner", i.e. Name|Standalone|OS |Purpose ----|:--------:|:---:|------- -[AutoGrouper](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/autogrouper)|Yes|LMW|Group images together by time -[autostyle](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/autostyle)|Yes|LMW|Automatically apply styles on import +[AutoGrouper](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/autogrouper)|Yes|LMW|Group images together by time +[autostyle](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/autostyle)|Yes|LMW|Automatically apply styles on import change_group_leader|Yes|LMW|Change which image leads group -[clear_GPS](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/clear_gps)|Yes|LMW|Reset GPS information for selected images -[CollectHelper](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/collecthelper)|Yes|LMW|Add buttons to selected images module to manipulate the collection +[clear_GPS](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/clear_gps)|Yes|LMW|Reset GPS information for selected images +[CollectHelper](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/collecthelper)|Yes|LMW|Add buttons to selected images module to manipulate the collection color_profile_manager|Yes|LMW|Manage darktable input and output color profiles -[copy_attach_detach_tags](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/copy_attach_detach_tags)|Yes|LMW|Copy and paste tags from/to images -[cr2hdr](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/cr2hdr)|Yes|L|Process image created with Magic Lantern Dual ISO +[copy_attach_detach_tags](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/copy_attach_detach_tags)|Yes|LMW|Copy and paste tags from/to images +[cr2hdr](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/cr2hdr)|Yes|L|Process image created with Magic Lantern Dual ISO cycle_group_leader|Yes|LMW|cycle through images of a group making each the group leader in turn dbmaint|Yes|LMW|find and remove database entries for missing film rolls and images -[enfuseAdvanced](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/enfuseadvanced)|No|LMW|Merge multiple images into Dynamic Range Increase (DRI) or Depth From Focus (DFF) images -[exportLUT](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/exportlut)|Yes|LMW|Create a LUT from a style and export it -[ext_editor](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/ext_editor)|No|LW|Export pictures to collection and edit them with up to nine user-defined external editors -[face_recognition](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/face_recognition)|No|LM|Identify and tag images using facial recognition -[fujifilm_dynamic_range](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/fujifilm_dynamic_range)|No|LMW|Correct fujifilm exposure based on exposure bias camera setting -[fujifilm_ratings](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/fujifilm_ratings)|No|LM|Support importing Fujifilm ratings -[geoJSON_export](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/geojson_export)|No|L|Create a geo JSON script with thumbnails for use in ... -[geoToolbox](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/geotoolbox)|No|LMW|A toolbox of geo functions -[gimp](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/gimp)|No|LMW|Open an image in GIMP for editing and return the result -[gpx_export](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/gpx_export)|No|LMW|Export a GPX track file from selected images GPS data +[enfuseAdvanced](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/enfuseadvanced)|No|LMW|Merge multiple images into Dynamic Range Increase (DRI) or Depth From Focus (DFF) images +[exportLUT](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/exportlut)|Yes|LMW|Create a LUT from a style and export it +[ext_editor](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/ext_editor)|No|LW|Export pictures to collection and edit them with up to nine user-defined external editors +[face_recognition](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/face_recognition)|No|LM|Identify and tag images using facial recognition +[fujifilm_dynamic_range](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/fujifilm_dynamic_range)|No|LMW|Correct fujifilm exposure based on exposure bias camera setting +[fujifilm_ratings](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/fujifilm_ratings)|No|LM|Support importing Fujifilm ratings +[geoJSON_export](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/geojson_export)|No|L|Create a geo JSON script with thumbnails for use in ... +[geoToolbox](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/geotoolbox)|No|LMW|A toolbox of geo functions +[gimp](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/gimp)|No|LMW|Open an image in GIMP for editing and return the result +[gpx_export](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/gpx_export)|No|LMW|Export a GPX track file from selected images GPS data harmonic_armature|Yes|LMW|provide a harmonic armature guide hif_group_leader|Yes|LMW|change the group leader in a raw+heif image pair to the heif image -[HDRMerge](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/hdrmerge)|No|LMW|Combine the selected images into an HDR DNG and return the result -[hugin](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/hugin)|No|LMW|Combine selected images into a panorama and return the result -[image_stack](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/image_stack)|No|LMW|Combine a stack of images to remove noise or transient objects -[image_time](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/image_time)|Yes|LMW|Adjust the EXIF image time +[HDRMerge](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/hdrmerge)|No|LMW|Combine the selected images into an HDR DNG and return the result +[hugin](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/hugin)|No|LMW|Combine selected images into a panorama and return the result +[image_stack](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/image_stack)|No|LMW|Combine a stack of images to remove noise or transient objects +[image_time](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/image_time)|Yes|LMW|Adjust the EXIF image time jpg_group_leader|Yes|LMW|change the group leader for a raw+jpg pair to the jpg image -[kml_export](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/kml_export)|No|L|Export photos with a KML file for usage in Google Earth -[LabelsToTags](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/labelstotags)|Yes|LMW|Apply tags based on color labels and ratings -[OpenInExplorer](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/openinexplorer)|No|LMW|Open the selected images in the system file manager -[passport_guide](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/passport_guide)|Yes|LMW|Add passport cropping guide to darkroom crop tool +[kml_export](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/kml_export)|No|L|Export photos with a KML file for usage in Google Earth +[LabelsToTags](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/labelstotags)|Yes|LMW|Apply tags based on color labels and ratings +[OpenInExplorer](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/openinexplorer)|No|LMW|Open the selected images in the system file manager +[passport_guide](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/passport_guide)|Yes|LMW|Add passport cropping guide to darkroom crop tool passport_guide_germany|Yes|LMW|Add passport cropping guide for German passports to darkroom crop tool -[pdf_slideshow](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/pdf_slideshow)|No|LM|Export images to a PDF slideshow -[photils](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/photils)|No|LM|Automatic tag suggestions for your images -[quicktag](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/quicktag)|Yes|LMW|Create shortcuts for quickly applying tags -[rate_group](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/rate_group)|Yes|LMW|Apply or remove a star rating from grouped images -[rename_images](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/rename_images)|Yes|LMW|Rename single or multiple images -[rename-tags](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/rename-tags)|Yes|LMW|Change a tag name -[RL_out_sharp](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/rl_out_sharp)|No|LW|Output sharpening using GMic (Richardson-Lucy algorithm) -[select_non_existing](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/select_non_existing)|Yes|LMW|Enable selection of non-existing images in the the currently worked on images -[select_untagged](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/select_untagged)|Yes|LMW|Enable selection of untagged images -[slideshowMusic](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/slideshowMusic)|No|L|Play music during a slideshow -[transfer_hierarchy](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/transfer_hierarchy)|Yes|LMW|Image move/copy preserving directory hierarchy -[video_ffmpeg](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/video_ffmpeg)|No|LMW|Export video from darktable +[pdf_slideshow](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/pdf_slideshow)|No|LM|Export images to a PDF slideshow +[photils](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/photils)|No|LM|Automatic tag suggestions for your images +[quicktag](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/quicktag)|Yes|LMW|Create shortcuts for quickly applying tags +[rate_group](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/rate_group)|Yes|LMW|Apply or remove a star rating from grouped images +[rename_images](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/rename_images)|Yes|LMW|Rename single or multiple images +[rename-tags](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/rename-tags)|Yes|LMW|Change a tag name +[RL_out_sharp](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/rl_out_sharp)|No|LW|Output sharpening using GMic (Richardson-Lucy algorithm) +[select_non_existing](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/select_non_existing)|Yes|LMW|Enable selection of non-existing images in the the currently worked on images +[select_untagged](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/select_untagged)|Yes|LMW|Enable selection of untagged images +[slideshowMusic](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/slideshowMusic)|No|L|Play music during a slideshow +[transfer_hierarchy](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/transfer_hierarchy)|Yes|LMW|Image move/copy preserving directory hierarchy +[video_ffmpeg](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/video_ffmpeg)|No|LMW|Export video from darktable ### Example Scripts @@ -85,18 +85,18 @@ These scripts provide examples of how to use specific portions of the API. They Name|Standalone|OS |Purpose ----|:--------:|:---:|------- -[api_version](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/api_version)|Yes|LMW|Print the current API version -[darkroom_demo](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/darkroom_demo)|Yes|LMW|Demonstrate changing images in darkoom -[gettextExample](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/gettextexample)|Yes|LM|How to use translation +[api_version](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/examples/api_version)|Yes|LMW|Print the current API version +[darkroom_demo](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/examples/darkroom_demo)|Yes|LMW|Demonstrate changing images in darkoom +[gettextExample](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/examples/gettextexample)|Yes|LM|How to use translation gui_actions|Yes|LMW|demonstrate controlling the GUI using darktable.gui.action calls -[hello_world](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/hello_world)|Yes|LMW|Prints hello world when darktable starts -[lighttable_demo](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/lighttable_demo)|Yes|LMW|Demonstrate controlling lighttable mode, zoom, sorting and filtering -[moduleExample](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/moduleexample)|Yes|LMW|How to create a lighttable module -[multi_os](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/multi_os)|No|LMW|How to create a cross platform script that calls an external executable -[panels_demo](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/panels_demo)|Yes|LMW|Demonstrate hiding and showing darktable panels -[preferenceExamples](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/preferenceexamples)|Yes|LMW|How to use preferences in a script -[printExamples](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/printexamples)|Yes|LMW|How to use various print functions from a script -[running_os](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/running_os)|Yes|LMW|Print out the running operating system +[hello_world](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/examples/hello_world)|Yes|LMW|Prints hello world when darktable starts +[lighttable_demo](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/examples/lighttable_demo)|Yes|LMW|Demonstrate controlling lighttable mode, zoom, sorting and filtering +[moduleExample](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/examples/moduleexample)|Yes|LMW|How to create a lighttable module +[multi_os](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/examples/multi_os)|No|LMW|How to create a cross platform script that calls an external executable +[panels_demo](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/examples/panels_demo)|Yes|LMW|Demonstrate hiding and showing darktable panels +[preferenceExamples](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/examples/preferenceexamples)|Yes|LMW|How to use preferences in a script +[printExamples](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/examples/printexamples)|Yes|LMW|How to use various print functions from a script +[running_os](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/examples/running_os)|Yes|LMW|Print out the running operating system x-touch|Yes|LMW|demonstrate how to use an x-touch mini MIDI controller to control the darktable GUI ### Tools @@ -105,11 +105,11 @@ Tool scripts perform functions relating to the repository, such as generating do Name|Standalone|OS |Purpose ----|:--------:|:---:|------- -[executable_manager](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/tools/executable_manager)|Yes|LMW|Manage the external executables used by the lua scripts -[gen_i18n_mo](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/tools/gen_i18n_mo)|No|LMW|Generate compiled translation files (.mo) from source files (.po) -[get_lib_manpages](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/tools/get_lib_manpages)|No|LM|Retrieve the library documentation and output it in man page and PDF format -[get_libdoc](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/tools/get_libdoc)|No|LMW|Retrieve the library documentation and output it as text -[script_manager](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/tools/script_manager)|No|LMW|Manage (install, update, enable, disable) the lua scripts +[executable_manager](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/tools/executable_manager)|Yes|LMW|Manage the external executables used by the lua scripts +[gen_i18n_mo](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/tools/gen_i18n_mo)|No|LMW|Generate compiled translation files (.mo) from source files (.po) +[get_lib_manpages](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/tools/get_lib_manpages)|No|LM|Retrieve the library documentation and output it in man page and PDF format +[get_libdoc](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/tools/get_libdoc)|No|LMW|Retrieve the library documentation and output it as text +[script_manager](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/tools/script_manager)|No|LMW|Manage (install, update, enable, disable) the lua scripts ### Related third-party projects @@ -237,18 +237,18 @@ To update the script repository, open a terminal or command prompt and do the fo ## Documentation -The [Lua Scripts Manual](https://darktable-org.github.io/luadocs/lua.scripts.manual/) provides documentation +The [Lua Scripts Manual](https://docs.darktable-org/lua/stable/lua.scripts.manual/) provides documentation for the scripts transcribed from the header comments. Each script also contains comments and usage instructions in the header comments. -The [Lua Scripts Library API Manual](https://darktable-org.github.io/luadocs/lua.scripts.api.manual/) provides +The [Lua Scripts Library API Manual](https://docs.darktable-org/lua/stable/lua.scripts.api.manual/) provides documentation of the libraries and functions. Lua-script libraries documentation may also be generated using the tools in the tools/ directory. More information about the scripting with Lua can be found in the darktable user manual: [Scripting with Lua](https://darktable-org.github.io/dtdocs/lua/) -The [Lua API Manual](https://darktable-org.github.io/luadocs/lua.api.manual/) provides docuemntation of the +The [Lua API Manual](https://docs.darktable-org/lua/stable/lua.api.manual/) provides docuemntation of the darktable Lua API. ## Troubleshooting From 7b2942ca293409f10d3e83f901749f2aff50648a Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Wed, 1 Jan 2025 17:28:03 -0500 Subject: [PATCH 422/445] README.md fixed darktable-org to darktable.org --- README.md | 142 +++++++++++++++++++++++++++--------------------------- 1 file changed, 71 insertions(+), 71 deletions(-) diff --git a/README.md b/README.md index 9a5521bb..7a7cf35b 100644 --- a/README.md +++ b/README.md @@ -15,17 +15,17 @@ These scripts are written primarily by the darktable developers and maintained b Name|Standalone|OS |Purpose ----|:--------:|:---:|------- -[check_for_updates](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/official/check_for_updates)|Yes|LMW|Check for updates to darktable -[copy_paste_metadata](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/official/copy_paste_metadata)|Yes|LMW|Copy and paste metadata, tags, ratings, and color labels between images -[delete_long_tags](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/official/delete_long_tags)|Yes|LMW|Delete all tags longer than a specified length -[delete_unused_tags](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/official/delete_unused_tags)|Yes|LMW|Delete tags that have no associated images -[enfuse](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/official/enfuse)|No|L|Exposure blend several images (HDR) -[generate_image_txt](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/official/generate_image_txt)|No|L|Generate txt sidecar files to be overlaid on zoomed images -[image_path_in_ui](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/official/image_path_in_ui)|Yes|LMW|Plugin to display selected image path -[import_filter_manager](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/official/import_filter_manager)|Yes|LMW|Manager for import filters -[import_filters](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/official/import_filters)|No|LMW|Two import filters for use with import_filter_manager -[save_selection](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/official/save_selection)|Yes|LMW|Provide save and restore from multiple selection buffers -[selection_to_pdf](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/official/selection_to_pdf)|No|L|Generate a PDF file from the selected images +[check_for_updates](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/official/check_for_updates)|Yes|LMW|Check for updates to darktable +[copy_paste_metadata](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/official/copy_paste_metadata)|Yes|LMW|Copy and paste metadata, tags, ratings, and color labels between images +[delete_long_tags](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/official/delete_long_tags)|Yes|LMW|Delete all tags longer than a specified length +[delete_unused_tags](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/official/delete_unused_tags)|Yes|LMW|Delete tags that have no associated images +[enfuse](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/official/enfuse)|No|L|Exposure blend several images (HDR) +[generate_image_txt](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/official/generate_image_txt)|No|L|Generate txt sidecar files to be overlaid on zoomed images +[image_path_in_ui](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/official/image_path_in_ui)|Yes|LMW|Plugin to display selected image path +[import_filter_manager](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/official/import_filter_manager)|Yes|LMW|Manager for import filters +[import_filters](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/official/import_filters)|No|LMW|Two import filters for use with import_filter_manager +[save_selection](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/official/save_selection)|Yes|LMW|Provide save and restore from multiple selection buffers +[selection_to_pdf](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/official/selection_to_pdf)|No|L|Generate a PDF file from the selected images ### Contributed Scripts @@ -34,50 +34,50 @@ These scripts are contributed by users. They are meant to have an "owner", i.e. Name|Standalone|OS |Purpose ----|:--------:|:---:|------- -[AutoGrouper](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/autogrouper)|Yes|LMW|Group images together by time -[autostyle](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/autostyle)|Yes|LMW|Automatically apply styles on import +[AutoGrouper](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/autogrouper)|Yes|LMW|Group images together by time +[autostyle](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/autostyle)|Yes|LMW|Automatically apply styles on import change_group_leader|Yes|LMW|Change which image leads group -[clear_GPS](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/clear_gps)|Yes|LMW|Reset GPS information for selected images -[CollectHelper](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/collecthelper)|Yes|LMW|Add buttons to selected images module to manipulate the collection +[clear_GPS](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/clear_gps)|Yes|LMW|Reset GPS information for selected images +[CollectHelper](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/collecthelper)|Yes|LMW|Add buttons to selected images module to manipulate the collection color_profile_manager|Yes|LMW|Manage darktable input and output color profiles -[copy_attach_detach_tags](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/copy_attach_detach_tags)|Yes|LMW|Copy and paste tags from/to images -[cr2hdr](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/cr2hdr)|Yes|L|Process image created with Magic Lantern Dual ISO +[copy_attach_detach_tags](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/copy_attach_detach_tags)|Yes|LMW|Copy and paste tags from/to images +[cr2hdr](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/cr2hdr)|Yes|L|Process image created with Magic Lantern Dual ISO cycle_group_leader|Yes|LMW|cycle through images of a group making each the group leader in turn dbmaint|Yes|LMW|find and remove database entries for missing film rolls and images -[enfuseAdvanced](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/enfuseadvanced)|No|LMW|Merge multiple images into Dynamic Range Increase (DRI) or Depth From Focus (DFF) images -[exportLUT](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/exportlut)|Yes|LMW|Create a LUT from a style and export it -[ext_editor](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/ext_editor)|No|LW|Export pictures to collection and edit them with up to nine user-defined external editors -[face_recognition](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/face_recognition)|No|LM|Identify and tag images using facial recognition -[fujifilm_dynamic_range](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/fujifilm_dynamic_range)|No|LMW|Correct fujifilm exposure based on exposure bias camera setting -[fujifilm_ratings](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/fujifilm_ratings)|No|LM|Support importing Fujifilm ratings -[geoJSON_export](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/geojson_export)|No|L|Create a geo JSON script with thumbnails for use in ... -[geoToolbox](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/geotoolbox)|No|LMW|A toolbox of geo functions -[gimp](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/gimp)|No|LMW|Open an image in GIMP for editing and return the result -[gpx_export](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/gpx_export)|No|LMW|Export a GPX track file from selected images GPS data +[enfuseAdvanced](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/enfuseadvanced)|No|LMW|Merge multiple images into Dynamic Range Increase (DRI) or Depth From Focus (DFF) images +[exportLUT](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/exportlut)|Yes|LMW|Create a LUT from a style and export it +[ext_editor](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/ext_editor)|No|LW|Export pictures to collection and edit them with up to nine user-defined external editors +[face_recognition](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/face_recognition)|No|LM|Identify and tag images using facial recognition +[fujifilm_dynamic_range](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/fujifilm_dynamic_range)|No|LMW|Correct fujifilm exposure based on exposure bias camera setting +[fujifilm_ratings](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/fujifilm_ratings)|No|LM|Support importing Fujifilm ratings +[geoJSON_export](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/geojson_export)|No|L|Create a geo JSON script with thumbnails for use in ... +[geoToolbox](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/geotoolbox)|No|LMW|A toolbox of geo functions +[gimp](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/gimp)|No|LMW|Open an image in GIMP for editing and return the result +[gpx_export](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/gpx_export)|No|LMW|Export a GPX track file from selected images GPS data harmonic_armature|Yes|LMW|provide a harmonic armature guide hif_group_leader|Yes|LMW|change the group leader in a raw+heif image pair to the heif image -[HDRMerge](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/hdrmerge)|No|LMW|Combine the selected images into an HDR DNG and return the result -[hugin](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/hugin)|No|LMW|Combine selected images into a panorama and return the result -[image_stack](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/image_stack)|No|LMW|Combine a stack of images to remove noise or transient objects -[image_time](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/image_time)|Yes|LMW|Adjust the EXIF image time +[HDRMerge](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/hdrmerge)|No|LMW|Combine the selected images into an HDR DNG and return the result +[hugin](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/hugin)|No|LMW|Combine selected images into a panorama and return the result +[image_stack](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/image_stack)|No|LMW|Combine a stack of images to remove noise or transient objects +[image_time](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/image_time)|Yes|LMW|Adjust the EXIF image time jpg_group_leader|Yes|LMW|change the group leader for a raw+jpg pair to the jpg image -[kml_export](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/kml_export)|No|L|Export photos with a KML file for usage in Google Earth -[LabelsToTags](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/labelstotags)|Yes|LMW|Apply tags based on color labels and ratings -[OpenInExplorer](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/openinexplorer)|No|LMW|Open the selected images in the system file manager -[passport_guide](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/passport_guide)|Yes|LMW|Add passport cropping guide to darkroom crop tool +[kml_export](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/kml_export)|No|L|Export photos with a KML file for usage in Google Earth +[LabelsToTags](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/labelstotags)|Yes|LMW|Apply tags based on color labels and ratings +[OpenInExplorer](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/openinexplorer)|No|LMW|Open the selected images in the system file manager +[passport_guide](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/passport_guide)|Yes|LMW|Add passport cropping guide to darkroom crop tool passport_guide_germany|Yes|LMW|Add passport cropping guide for German passports to darkroom crop tool -[pdf_slideshow](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/pdf_slideshow)|No|LM|Export images to a PDF slideshow -[photils](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/photils)|No|LM|Automatic tag suggestions for your images -[quicktag](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/quicktag)|Yes|LMW|Create shortcuts for quickly applying tags -[rate_group](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/rate_group)|Yes|LMW|Apply or remove a star rating from grouped images -[rename_images](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/rename_images)|Yes|LMW|Rename single or multiple images -[rename-tags](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/rename-tags)|Yes|LMW|Change a tag name -[RL_out_sharp](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/rl_out_sharp)|No|LW|Output sharpening using GMic (Richardson-Lucy algorithm) -[select_non_existing](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/select_non_existing)|Yes|LMW|Enable selection of non-existing images in the the currently worked on images -[select_untagged](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/select_untagged)|Yes|LMW|Enable selection of untagged images -[slideshowMusic](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/slideshowMusic)|No|L|Play music during a slideshow -[transfer_hierarchy](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/transfer_hierarchy)|Yes|LMW|Image move/copy preserving directory hierarchy -[video_ffmpeg](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/contrib/video_ffmpeg)|No|LMW|Export video from darktable +[pdf_slideshow](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/pdf_slideshow)|No|LM|Export images to a PDF slideshow +[photils](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/photils)|No|LM|Automatic tag suggestions for your images +[quicktag](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/quicktag)|Yes|LMW|Create shortcuts for quickly applying tags +[rate_group](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/rate_group)|Yes|LMW|Apply or remove a star rating from grouped images +[rename_images](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/rename_images)|Yes|LMW|Rename single or multiple images +[rename-tags](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/rename-tags)|Yes|LMW|Change a tag name +[RL_out_sharp](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/rl_out_sharp)|No|LW|Output sharpening using GMic (Richardson-Lucy algorithm) +[select_non_existing](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/select_non_existing)|Yes|LMW|Enable selection of non-existing images in the the currently worked on images +[select_untagged](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/select_untagged)|Yes|LMW|Enable selection of untagged images +[slideshowMusic](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/slideshowMusic)|No|L|Play music during a slideshow +[transfer_hierarchy](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/transfer_hierarchy)|Yes|LMW|Image move/copy preserving directory hierarchy +[video_ffmpeg](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/video_ffmpeg)|No|LMW|Export video from darktable ### Example Scripts @@ -85,18 +85,18 @@ These scripts provide examples of how to use specific portions of the API. They Name|Standalone|OS |Purpose ----|:--------:|:---:|------- -[api_version](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/examples/api_version)|Yes|LMW|Print the current API version -[darkroom_demo](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/examples/darkroom_demo)|Yes|LMW|Demonstrate changing images in darkoom -[gettextExample](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/examples/gettextexample)|Yes|LM|How to use translation +[api_version](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/examples/api_version)|Yes|LMW|Print the current API version +[darkroom_demo](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/examples/darkroom_demo)|Yes|LMW|Demonstrate changing images in darkoom +[gettextExample](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/examples/gettextexample)|Yes|LM|How to use translation gui_actions|Yes|LMW|demonstrate controlling the GUI using darktable.gui.action calls -[hello_world](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/examples/hello_world)|Yes|LMW|Prints hello world when darktable starts -[lighttable_demo](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/examples/lighttable_demo)|Yes|LMW|Demonstrate controlling lighttable mode, zoom, sorting and filtering -[moduleExample](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/examples/moduleexample)|Yes|LMW|How to create a lighttable module -[multi_os](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/examples/multi_os)|No|LMW|How to create a cross platform script that calls an external executable -[panels_demo](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/examples/panels_demo)|Yes|LMW|Demonstrate hiding and showing darktable panels -[preferenceExamples](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/examples/preferenceexamples)|Yes|LMW|How to use preferences in a script -[printExamples](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/examples/printexamples)|Yes|LMW|How to use various print functions from a script -[running_os](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/examples/running_os)|Yes|LMW|Print out the running operating system +[hello_world](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/examples/hello_world)|Yes|LMW|Prints hello world when darktable starts +[lighttable_demo](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/examples/lighttable_demo)|Yes|LMW|Demonstrate controlling lighttable mode, zoom, sorting and filtering +[moduleExample](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/examples/moduleexample)|Yes|LMW|How to create a lighttable module +[multi_os](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/examples/multi_os)|No|LMW|How to create a cross platform script that calls an external executable +[panels_demo](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/examples/panels_demo)|Yes|LMW|Demonstrate hiding and showing darktable panels +[preferenceExamples](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/examples/preferenceexamples)|Yes|LMW|How to use preferences in a script +[printExamples](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/examples/printexamples)|Yes|LMW|How to use various print functions from a script +[running_os](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/examples/running_os)|Yes|LMW|Print out the running operating system x-touch|Yes|LMW|demonstrate how to use an x-touch mini MIDI controller to control the darktable GUI ### Tools @@ -105,11 +105,11 @@ Tool scripts perform functions relating to the repository, such as generating do Name|Standalone|OS |Purpose ----|:--------:|:---:|------- -[executable_manager](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/tools/executable_manager)|Yes|LMW|Manage the external executables used by the lua scripts -[gen_i18n_mo](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/tools/gen_i18n_mo)|No|LMW|Generate compiled translation files (.mo) from source files (.po) -[get_lib_manpages](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/tools/get_lib_manpages)|No|LM|Retrieve the library documentation and output it in man page and PDF format -[get_libdoc](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/tools/get_libdoc)|No|LMW|Retrieve the library documentation and output it as text -[script_manager](https://docs.darktable-org/lua/stable/lua.scripts.manual/scripts/tools/script_manager)|No|LMW|Manage (install, update, enable, disable) the lua scripts +[executable_manager](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/tools/executable_manager)|Yes|LMW|Manage the external executables used by the lua scripts +[gen_i18n_mo](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/tools/gen_i18n_mo)|No|LMW|Generate compiled translation files (.mo) from source files (.po) +[get_lib_manpages](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/tools/get_lib_manpages)|No|LM|Retrieve the library documentation and output it in man page and PDF format +[get_libdoc](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/tools/get_libdoc)|No|LMW|Retrieve the library documentation and output it as text +[script_manager](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/tools/script_manager)|No|LMW|Manage (install, update, enable, disable) the lua scripts ### Related third-party projects @@ -142,7 +142,7 @@ The snap version of darktable comes with lua included starting with version 2.4. Ensure git is installed on your system. If it isn't, use the package manager to install it. Then open a terminal and: cd ~/snap/darktable/current - git clone https://github.com/darktable-org/lua-scripts.git lua + git clone https://github.com/darktable.org/lua-scripts.git lua ### flatpak packages @@ -152,7 +152,7 @@ Flatpak packages now use the internal lua interpreter. Ensure git is installed on your system. If it isn't, use the package manager to install it. Then open a terminal and: cd ~/.var/app/org.darktable.Darktable/config/darktable - git clone https://github.com/darktable-org/lua-scripts.git lua + git clone https://github.com/darktable.org/lua-scripts.git lua ### appimage packages @@ -163,14 +163,14 @@ These packages run in their own environment and don't have access to a lua inter Ensure git is installed on your system. If it isn't, use the package manager to install it. Then open a terminal and: cd ~/.config/darktable/ - git clone https://github.com/darktable-org/lua-scripts.git lua + git clone https://github.com/darktable.org/lua-scripts.git lua ### Windows Ensure git is installed on your system. Git can be obtained from https://gitforwindows.org/, as well as other places. If you use the gitforwindows.org distribution, install the Git Bash Shell also as it will aid in debugging the scripts if necessary. Then open a command prompt and run: cd %LOCALAPPDATA%\darktable - git clone https://github.com/darktable-org/lua-scripts.git lua + git clone https://github.com/darktable.org/lua-scripts.git lua If you don't have %LOCALAPPDATA%\darktable you have to start dartable at least once, because the directory is created at the first start of darktable. @@ -237,18 +237,18 @@ To update the script repository, open a terminal or command prompt and do the fo ## Documentation -The [Lua Scripts Manual](https://docs.darktable-org/lua/stable/lua.scripts.manual/) provides documentation +The [Lua Scripts Manual](https://docs.darktable.org/lua/stable/lua.scripts.manual/) provides documentation for the scripts transcribed from the header comments. Each script also contains comments and usage instructions in the header comments. -The [Lua Scripts Library API Manual](https://docs.darktable-org/lua/stable/lua.scripts.api.manual/) provides +The [Lua Scripts Library API Manual](https://docs.darktable.org/lua/stable/lua.scripts.api.manual/) provides documentation of the libraries and functions. Lua-script libraries documentation may also be generated using the tools in the tools/ directory. More information about the scripting with Lua can be found in the darktable user manual: -[Scripting with Lua](https://darktable-org.github.io/dtdocs/lua/) +[Scripting with Lua](https://darktable.org.github.io/dtdocs/lua/) -The [Lua API Manual](https://docs.darktable-org/lua/stable/lua.api.manual/) provides docuemntation of the +The [Lua API Manual](https://docs.darktable.org/lua/stable/lua.api.manual/) provides docuemntation of the darktable Lua API. ## Troubleshooting From 3def8b43d9f66534d0491a96709872d9acec0fa8 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Wed, 1 Jan 2025 17:33:20 -0500 Subject: [PATCH 423/445] README.md - fixed git clone links --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 7a7cf35b..8caa5c2e 100644 --- a/README.md +++ b/README.md @@ -142,7 +142,7 @@ The snap version of darktable comes with lua included starting with version 2.4. Ensure git is installed on your system. If it isn't, use the package manager to install it. Then open a terminal and: cd ~/snap/darktable/current - git clone https://github.com/darktable.org/lua-scripts.git lua + git clone https://github.com/darktable-org/lua-scripts.git lua ### flatpak packages @@ -152,7 +152,7 @@ Flatpak packages now use the internal lua interpreter. Ensure git is installed on your system. If it isn't, use the package manager to install it. Then open a terminal and: cd ~/.var/app/org.darktable.Darktable/config/darktable - git clone https://github.com/darktable.org/lua-scripts.git lua + git clone https://github.com/darktable-org/lua-scripts.git lua ### appimage packages @@ -163,14 +163,14 @@ These packages run in their own environment and don't have access to a lua inter Ensure git is installed on your system. If it isn't, use the package manager to install it. Then open a terminal and: cd ~/.config/darktable/ - git clone https://github.com/darktable.org/lua-scripts.git lua + git clone https://github.com/darktable-org/lua-scripts.git lua ### Windows Ensure git is installed on your system. Git can be obtained from https://gitforwindows.org/, as well as other places. If you use the gitforwindows.org distribution, install the Git Bash Shell also as it will aid in debugging the scripts if necessary. Then open a command prompt and run: cd %LOCALAPPDATA%\darktable - git clone https://github.com/darktable.org/lua-scripts.git lua + git clone https://github.com/darktable-org/lua-scripts.git lua If you don't have %LOCALAPPDATA%\darktable you have to start dartable at least once, because the directory is created at the first start of darktable. From 0ab4b0cd6dfac3a49c9f4efc16f8ea411990125e Mon Sep 17 00:00:00 2001 From: Krzysztof Kotowicz Date: Thu, 2 Jan 2025 15:21:59 +0100 Subject: [PATCH 424/445] Added 50ms sleep to the colorspace change. The old profile still seems to be used occasionally without the sleep. --- contrib/ultrahdr.lua | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/contrib/ultrahdr.lua b/contrib/ultrahdr.lua index ef7a61fd..94df2173 100644 --- a/contrib/ultrahdr.lua +++ b/contrib/ultrahdr.lua @@ -120,6 +120,7 @@ local COLORSPACE_TO_GUI_ACTION = { [DT_COLORSPACE_DISPLAY_P3] = 11 } +local UI_SLEEP_MS = 50 -- How many ms to sleep after UI action. local function set_log_level(level) local old_log_level = log.log_level() @@ -221,9 +222,10 @@ local function set_profile(colorspace) local new = COLORSPACE_TO_GUI_ACTION[colorspace] or colorspace log.msg(log.debug, string.format("Changing export profile from %d to %d", old, new)) dt.gui.action("lib/export/profile", 0, "selection", "next", new - old) + dt.control.sleep(UI_SLEEP_MS) return old else - -- Old method, timing-dependent + -- Old method return set_combobox("lib/export/profile", 0, "plugins/lighttable/export/icctype", colorspace) end end @@ -238,12 +240,12 @@ local function set_combobox(path, instance, config_name, new_config_value) end dt.gui.action(path, 0, "selection", "first", 1.0) - dt.control.sleep(50) + dt.control.sleep(UI_SLEEP_MS) local limit, i = 30, 0 -- in case there is no matching config value in the first n entries of a combobox. while i < limit do i = i + 1 dt.gui.action(path, 0, "selection", "next", 1.0) - dt.control.sleep(50) + dt.control.sleep(UI_SLEEP_MS) if dt.preferences.read("darktable", config_name, "integer") == new_config_value then log.msg(log.debug, string.format(_("Changed %s from %d to %d"), config_name, pref, new_config_value)) return pref From 9f3fb161613334f11c7542916997a28fe1818ab2 Mon Sep 17 00:00:00 2001 From: Krzysztof Kotowicz Date: Sat, 4 Jan 2025 00:49:56 +0100 Subject: [PATCH 425/445] Addressed review comments. --- contrib/ultrahdr.lua | 52 +++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 27 deletions(-) diff --git a/contrib/ultrahdr.lua b/contrib/ultrahdr.lua index 94df2173..e5562324 100644 --- a/contrib/ultrahdr.lua +++ b/contrib/ultrahdr.lua @@ -45,15 +45,13 @@ local dtsys = require "lib/dtutils.system" local dd = require "lib/dtutils.debug" local gettext = dt.gettext.gettext -local namespace = "module_ultrahdr" +local namespace = "ultrahdr" -local LOG_LEVEL = log.info +local LOG_LEVEL = log.info -- works with darktable API version from 4.8.0 on du.check_min_api_version("9.3.0", "ultrahdr") -dt.gettext.bindtextdomain(namespace, dt.configuration.config_dir .. "/lua/locale/") - local function _(msgid) return gettext(msgid) end @@ -96,31 +94,32 @@ flags.module_installed = false -- keep track of whether the module is module_ins local script_data = {} script_data.metadata = { - name = "ultrahdr", + name = _("UltraHDR"), purpose = _("generate UltraHDR images"), author = "Krzysztof Kotowicz" } -local PS = dt.configuration.running_os == "windows" and "\\" or "/" -local ENCODING_VARIANT_SDR_AND_GAINMAP = 1 -local ENCODING_VARIANT_SDR_AND_HDR = 2 -local ENCODING_VARIANT_SDR_AUTO_GAINMAP = 3 -local ENCODING_VARIANT_HDR_ONLY = 4 +local PS = dt.configuration.running_os == "windows" and "\\" or "/" + +local ENCODING_VARIANT_SDR_AND_GAINMAP = 1 +local ENCODING_VARIANT_SDR_AND_HDR = 2 +local ENCODING_VARIANT_SDR_AUTO_GAINMAP = 3 +local ENCODING_VARIANT_HDR_ONLY = 4 -local SELECTION_TYPE_ONE_STACK = 1 -local SELECTION_TYPE_GROUP_BY_FNAME = 2 +local SELECTION_TYPE_ONE_STACK = 1 +local SELECTION_TYPE_GROUP_BY_FNAME = 2 -- Values are defined in darktable/src/common/colorspaces.h -local DT_COLORSPACE_PQ_P3 = 24 -local DT_COLORSPACE_DISPLAY_P3 = 26 +local DT_COLORSPACE_PQ_P3 = 24 +local DT_COLORSPACE_DISPLAY_P3 = 26 -- 1-based position of a colorspace in export profile combobox. -local COLORSPACE_TO_GUI_ACTION = { +local COLORSPACE_TO_GUI_ACTION = { [DT_COLORSPACE_PQ_P3] = 9, [DT_COLORSPACE_DISPLAY_P3] = 11 } -local UI_SLEEP_MS = 50 -- How many ms to sleep after UI action. +local UI_SLEEP_MS = 50 -- How many ms to sleep after UI action. local function set_log_level(level) local old_log_level = log.log_level() @@ -179,7 +178,7 @@ local function save_preferences() end local function default_to(value, default) - if value == 0 then + if value == 0 or value == "" then return default end return value @@ -193,7 +192,8 @@ local function load_preferences() GUI.optionwidgets.selection_type_combo.selected = math.max( dt.preferences.read(namespace, "selection_type", "integer"), SELECTION_TYPE_ONE_STACK) - GUI.optionwidgets.output_filepath_widget.text = dt.preferences.read(namespace, "output_filepath_pattern", "string") + GUI.optionwidgets.output_filepath_widget.text = default_to(dt.preferences.read(namespace, "output_filepath_pattern", "string"), + "$(FILE_FOLDER)/$(FILE_NAME)_ultrahdr") GUI.optionwidgets.overwrite_on_conflict.value = dt.preferences.read(namespace, "overwrite_on_conflict", "bool") GUI.optionwidgets.import_to_darktable.value = dt.preferences.read(namespace, "import_to_darktable", "bool") GUI.optionwidgets.copy_exif.value = dt.preferences.read(namespace, "copy_exif", "bool") @@ -247,11 +247,11 @@ local function set_combobox(path, instance, config_name, new_config_value) dt.gui.action(path, 0, "selection", "next", 1.0) dt.control.sleep(UI_SLEEP_MS) if dt.preferences.read("darktable", config_name, "integer") == new_config_value then - log.msg(log.debug, string.format(_("Changed %s from %d to %d"), config_name, pref, new_config_value)) + log.msg(log.debug, string.format("Changed %s from %d to %d", config_name, pref, new_config_value)) return pref end end - log.msg(log.error, string.format(_("Could not change %s from %d to %d"), config_name, pref, new_config_value)) + log.msg(log.error, string.format("Could not change %s from %d to %d", config_name, pref, new_config_value)) restore_log_level(old_log_level) end @@ -494,7 +494,7 @@ local function generate_ultrahdr(encoding_variant, images, settings, step, total return cleanup(), errors end end - log.msg(log.debug, string.format(_("Exported files: %s, %s"), sdr, gainmap)) + log.msg(log.debug, string.format("Exported files: %s, %s", sdr, gainmap)) update_job_progress() -- Strip EXIFs table.insert(remove_files, sdr .. ".noexif") @@ -721,9 +721,8 @@ local function generate_ultrahdr(encoding_variant, images, settings, step, total end cleanup() update_job_progress() - local msg = string.format(_("Generated %s."), df.get_filename(output_file)) - log.msg(log.info, msg) - dt.print(msg) + log.msg(log.info, string.format("Generated %s.", df.get_filename(output_file))) + dt.print(string.format(_("Generated %s."), df.get_filename(output_file))) restore_log_level(old_log_level) return true, nil end @@ -769,9 +768,8 @@ local function main() job.valid = false end - msg = string.format(_("Generated %d UltraHDR image(s)."), count) - log.msg(log.info, msg) - dt.print(msg) + log.msg(log.info, string.format("Generated %d UltraHDR image(s).", count)) + dt.print(string.format(_("Generated %d UltraHDR image(s)."), count)) restore_log_level(old_log_level) end From 1e33ea419266a93858664d0d85daa0aa91ee719d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nahuel=20Jos=C3=A9?= Date: Mon, 6 Jan 2025 18:47:57 -0300 Subject: [PATCH 426/445] fix: add change encoding to bat file for dtutils windows_command --- lib/dtutils/system.lua | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/dtutils/system.lua b/lib/dtutils/system.lua index 0df0dee9..f7db561b 100644 --- a/lib/dtutils/system.lua +++ b/lib/dtutils/system.lua @@ -87,7 +87,13 @@ function dtutils_system.windows_command(command) if file then dt.print_log("opened file") command = string.gsub(command, "%%", "%%%%") -- escape % from windows shell - file:write(command) + file:write("@echo off\n") + file:write('for /f "tokens=2 delims=:." %%x in (\'chcp\') do set cp=%%x\n') + file:write("chcp 65001>nul\n") -- change the encoding of the terminal to handle non-english characters in path + file:write("\n") + file:write(command .. "\n") + file:write("\n") + file:write("chcp %%cp%%>nul\n") file:close() result = dt.control.execute(fname) From 914a17fb4ecf04c88b79fdb723398651fb792e6e Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Mon, 6 Jan 2025 22:06:35 -0500 Subject: [PATCH 427/445] contrib/AutoGrouper - create group leader for first image in table. Add grouped images to the group leader and not the previous image. --- contrib/AutoGrouper.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/contrib/AutoGrouper.lua b/contrib/AutoGrouper.lua index 67609374..889c9af1 100644 --- a/contrib/AutoGrouper.lua +++ b/contrib/AutoGrouper.lua @@ -132,10 +132,11 @@ local function main(on_collection) for i, image in ipairs(images) do if i == 1 then prev_image = image + image:make_group_leader() elseif string.match(image.exif_datetime_taken, '[%d]') ~= nil then --make sure current image has a timestamp, if so check if it is within the user specified gap value and add to group local curr_image = image if GetTimeDiff(curr_image, prev_image) <= GUI.gap.value then - images[i]:group_with(images[i-1]) + images[i]:group_with(images[i-1].group_leader) end prev_image = curr_image end From 4e140f10d156bda264e80f3c4aba53a8399fffb5 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Fri, 17 Jan 2025 14:18:19 -0500 Subject: [PATCH 428/445] lib/dtutils/system - fixed Lua escaping in windows_command() --- lib/dtutils/system.lua | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/dtutils/system.lua b/lib/dtutils/system.lua index f7db561b..10ea29f3 100644 --- a/lib/dtutils/system.lua +++ b/lib/dtutils/system.lua @@ -86,14 +86,13 @@ function dtutils_system.windows_command(command) local file = io.open(fname, "w") if file then dt.print_log("opened file") - command = string.gsub(command, "%%", "%%%%") -- escape % from windows shell file:write("@echo off\n") file:write('for /f "tokens=2 delims=:." %%x in (\'chcp\') do set cp=%%x\n') file:write("chcp 65001>nul\n") -- change the encoding of the terminal to handle non-english characters in path file:write("\n") file:write(command .. "\n") file:write("\n") - file:write("chcp %%cp%%>nul\n") + file:write("chcp %cp%>nul\n") file:close() result = dt.control.execute(fname) From 96457bc5985a61d94db99533cd0f1abac8e4c3e2 Mon Sep 17 00:00:00 2001 From: Martin Straeten <39386816+MStraeten@users.noreply.github.com> Date: Sat, 18 Jan 2025 23:44:48 +0100 Subject: [PATCH 429/445] Update x-touch.lua switch colorequal tab added recommended additional shortcuts to switch between hue, saturation and brightness tabs: midi:D0=iop/colorequal/page;previous midi:D#0=iop/colorequal/page;next --- examples/x-touch.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/x-touch.lua b/examples/x-touch.lua index 314135e4..7da3d54c 100644 --- a/examples/x-touch.lua +++ b/examples/x-touch.lua @@ -49,6 +49,8 @@ midi:A#-1=iop/toneequal;focus midi:B-1=iop/colorbalancergb;focus midi:C0=iop/channelmixerrgb;focus midi:C#0=iop/colorequal;focus +midi:D0=iop/colorequal/page;previous +midi:D#0=iop/colorequal/page;next ]] local dt = require "darktable" From b70fdc0ecf64192be36eb8508d9fcef3b34150c1 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Fri, 7 Feb 2025 14:29:45 -0500 Subject: [PATCH 430/445] official/apply_camera_style - Fixed decoding errors caused by #18332. --- official/apply_camera_style.lua | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/official/apply_camera_style.lua b/official/apply_camera_style.lua index aac49d16..b162ffef 100644 --- a/official/apply_camera_style.lua +++ b/official/apply_camera_style.lua @@ -52,7 +52,9 @@ local log = require "lib/dtutils.log" local MODULE = "apply_camera_style" local DEFAULT_LOG_LEVEL = log.info local TMP_DIR = dt.configuration.tmp_dir -local STYLE_PREFIX = "_l10n_darktable camera styles|" +local STYLE_PREFIX = "_l10n_darktable|_l10n_camera styles|" +local MAKER = 3 +local STYLE = 4 -- path separator local PS = dt.configuration.running_os == "windows" and "\\" or "/" @@ -222,25 +224,25 @@ local function get_camera_styles() log.msg(log.debug, "got " .. style.name) local parts = du.split(style.name, "|") - parts[2] = string.lower(parts[2]) - log.msg(log.debug, "maker is " .. parts[2]) + parts[MAKER] = string.lower(parts[MAKER]) + log.msg(log.debug, "maker is " .. parts[MAKER]) - if not acs.styles[parts[2]] then - acs.styles[parts[2]] = {} - acs.styles[parts[2]]["styles"] = {} - acs.styles[parts[2]]["patterns"] = {} + if not acs.styles[parts[MAKER]] then + acs.styles[parts[MAKER]] = {} + acs.styles[parts[MAKER]]["styles"] = {} + acs.styles[parts[MAKER]]["patterns"] = {} end - if parts[3] then - if not string.match(parts[3], "]") then - table.insert(acs.styles[parts[2]].styles, style) + if parts[STYLE] then + if not string.match(parts[STYLE], "]") then + table.insert(acs.styles[parts[MAKER]].styles, style) local processed_pattern = process_pattern(parts[#parts]) - table.insert(acs.styles[parts[2]].patterns, processed_pattern) + table.insert(acs.styles[parts[MAKER]].patterns, processed_pattern) log.msg(log.debug, "pattern for " .. style.name .. " is " .. processed_pattern) else - local processed_patterns = process_set(parts[3]) + local processed_patterns = process_set(parts[STYLE]) for _, pat in ipairs(processed_patterns) do - table.insert(acs.styles[parts[2]].styles, style) - table.insert(acs.styles[parts[2]].patterns, pat) + table.insert(acs.styles[parts[MAKER]].styles, style) + table.insert(acs.styles[parts[MAKER]].patterns, pat) log.msg(log.debug, "pattern for " .. style.name .. " is " .. pat) end end From 252cbc96f2af34d165e13153a8913e1a4bfeca0a Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sat, 15 Feb 2025 13:55:08 -0500 Subject: [PATCH 431/445] apply_camera_style - made spaces conditional in the pattern match so that pattern names with spaces will match models that don't have spaces --- official/apply_camera_style.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/official/apply_camera_style.lua b/official/apply_camera_style.lua index aac49d16..b748ef95 100644 --- a/official/apply_camera_style.lua +++ b/official/apply_camera_style.lua @@ -162,6 +162,7 @@ local function process_pattern(pattern) else pattern = string.gsub(pattern, "?", ".") end + pattern = string.gsub(pattern, " ", " ?") -- escape dashes pattern = string.gsub(pattern, "%-", "%%-") -- until we end up with a set, I'll defer set processing, i.e. [...] From 363524fbafd021161bf0a65a828e7e2900e6a26b Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sat, 15 Feb 2025 20:19:29 -0500 Subject: [PATCH 432/445] tools/script_manager - added a start queue for scripts that start at start up to allow for including and using libraries in other than the default path. Scripts are now started after all directories are scanned instead of being started as they were found. --- tools/script_manager.lua | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/tools/script_manager.lua b/tools/script_manager.lua index 573f1825..d1ab17e4 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -178,6 +178,7 @@ sm.log_level = DEFAULT_LOG_LEVEL ]] sm.scripts = {} +sm.start_queue = {} sm.page_status = {} sm.page_status.num_buttons = DEFAULT_BUTTONS_PER_PAGE sm.page_status.buttons_created = 0 @@ -595,6 +596,17 @@ local function deactivate(script) restore_log_level(old_log_level) end +local function start_scripts() + for _, script in ipairs(sm.start_queue) do + activate(script) + end + sm.start_queue = {} +end + +local function queue_script_to_start(script) + table.insert(sm.start_queue, script) +end + local function add_script_name(name, path, folder) local old_log_level = set_log_level(sm.log_level) @@ -614,7 +626,7 @@ local function add_script_name(name, path, folder) table.insert(sm.scripts[folder], script) if pref_read(script.script_name, "bool") then - activate(script) + queue_script_to_start(script) else pref_write(script.script_name, "bool", false) end @@ -821,6 +833,7 @@ local function scan_repositories() end end + start_scripts() update_script_update_choices() restore_log_level(old_log_level) From 067fe29f7655d150a4f3255a3879d93e54256f32 Mon Sep 17 00:00:00 2001 From: Georg Lutz Date: Sun, 23 Feb 2025 12:23:37 +0100 Subject: [PATCH 433/445] Fix version comparison Currently this is a textual string comparison which will break with 10.0.0 API version. --- lib/dtutils.lua | 41 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/lib/dtutils.lua b/lib/dtutils.lua index 6721eac9..87e99cc8 100644 --- a/lib/dtutils.lua +++ b/lib/dtutils.lua @@ -61,7 +61,7 @@ dtutils.libdoc.functions["check_min_api_version"] = { function dtutils.check_min_api_version(min_api, script_name) local current_api = dt.configuration.api_version_string - if min_api > current_api then + if dtutils.compare_versions(min_api, current_api) > 0 then dt.print_error("This application is written for lua api version " .. min_api .. " or later.") dt.print_error("The current lua api version is " .. current_api) dt.print("ERROR: " .. script_name .. " failed to load. Lua API version " .. min_api .. " or later required.") @@ -96,7 +96,7 @@ dtutils.libdoc.functions["check_max_api_version"] = { function dtutils.check_max_api_version(max_api, script_name) local current_api = dt.configuration.api_version_string - if current_api > max_api then + if dtutils.compare_versions(current_api, max_api) > 0 then dt.print_error("This application is written for lua api version " .. max_api .. " or earlier.") dt.print_error("The current lua api version is " .. current_api) dt.print("ERROR: " .. script_name .. " failed to load. Lua API version " .. max_api .. " or earlier required.") @@ -427,4 +427,41 @@ function dtutils.gen_uuid(case) return uuid end +dtutils.libdoc.functions["compare_versions"] = { + Name = [[compare_versions]], + Synopsis = [[compare two version strings]], + Usage = [[local du = require "lib/dtutils" + + local result = du.compare_versions(version1, version2) + version1 - string - the first version string to compare (example: "5.0.0") + version2 - string - the second version string to compare (example: "5.1.0")]], + Description = [[compare_versions compares two version strings and returns 1 if version1 is greater, + -1 if version2 is greater, and 0 if they are equal.]], + Return_Value = [[result - 1 if version1 is greater, -1 if version2 is greater, 0 if they are equal.]], + Limitations = [[]], + Example = [[compare_versions("5.0.0", "5.1.0") returns -1]], + See_Also = [[]], + Reference = [[]], + License = [[]], + Copyright = [[]], +} + +function dtutils.compare_versions(version1, version2) + local v1 = {} + for num in version1:gmatch("%d+") do table.insert(v1, tonumber(num)) end + local v2 = {} + for num in version2:gmatch("%d+") do table.insert(v2, tonumber(num)) end + + for i = 1, math.max(#v1, #v2) do + local num1 = v1[i] or 0 + local num2 = v2[i] or 0 + if num1 > num2 then + return 1 + elseif num1 < num2 then + return -1 + end + end + return 0 +end + return dtutils From 2624338100c0b42298b7809c718f8c6233296c40 Mon Sep 17 00:00:00 2001 From: Georg Lutz Date: Sun, 23 Feb 2025 18:29:34 +0100 Subject: [PATCH 434/445] Rename compare_versions to compare_api_versions --- lib/dtutils.lua | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/dtutils.lua b/lib/dtutils.lua index 87e99cc8..e6595865 100644 --- a/lib/dtutils.lua +++ b/lib/dtutils.lua @@ -61,7 +61,7 @@ dtutils.libdoc.functions["check_min_api_version"] = { function dtutils.check_min_api_version(min_api, script_name) local current_api = dt.configuration.api_version_string - if dtutils.compare_versions(min_api, current_api) > 0 then + if dtutils.compare_api_versions(min_api, current_api) > 0 then dt.print_error("This application is written for lua api version " .. min_api .. " or later.") dt.print_error("The current lua api version is " .. current_api) dt.print("ERROR: " .. script_name .. " failed to load. Lua API version " .. min_api .. " or later required.") @@ -96,7 +96,7 @@ dtutils.libdoc.functions["check_max_api_version"] = { function dtutils.check_max_api_version(max_api, script_name) local current_api = dt.configuration.api_version_string - if dtutils.compare_versions(current_api, max_api) > 0 then + if dtutils.compare_api_versions(current_api, max_api) > 0 then dt.print_error("This application is written for lua api version " .. max_api .. " or earlier.") dt.print_error("The current lua api version is " .. current_api) dt.print("ERROR: " .. script_name .. " failed to load. Lua API version " .. max_api .. " or earlier required.") @@ -427,26 +427,26 @@ function dtutils.gen_uuid(case) return uuid end -dtutils.libdoc.functions["compare_versions"] = { - Name = [[compare_versions]], - Synopsis = [[compare two version strings]], +dtutils.libdoc.functions["compare_api_versions"] = { + Name = [[compare_api_versions]], + Synopsis = [[compare two API version strings]], Usage = [[local du = require "lib/dtutils" - local result = du.compare_versions(version1, version2) + local result = du.compare_api_versions(version1, version2) version1 - string - the first version string to compare (example: "5.0.0") version2 - string - the second version string to compare (example: "5.1.0")]], - Description = [[compare_versions compares two version strings and returns 1 if version1 is greater, + Description = [[compare_api_versions compares two version strings and returns 1 if version1 is greater, -1 if version2 is greater, and 0 if they are equal.]], Return_Value = [[result - 1 if version1 is greater, -1 if version2 is greater, 0 if they are equal.]], Limitations = [[]], - Example = [[compare_versions("5.0.0", "5.1.0") returns -1]], + Example = [[compare_api_versions("5.0.0", "5.1.0") returns -1]], See_Also = [[]], Reference = [[]], License = [[]], Copyright = [[]], } -function dtutils.compare_versions(version1, version2) +function dtutils.compare_api_versions(version1, version2) local v1 = {} for num in version1:gmatch("%d+") do table.insert(v1, tonumber(num)) end local v2 = {} From cddb86ded0257231a7bbf208340493a0a9a45d3e Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Fri, 28 Feb 2025 15:11:15 -0500 Subject: [PATCH 435/445] contrib/autostyle - fixed pattern match for tag result to handle spaces in the pattern --- contrib/autostyle.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/autostyle.lua b/contrib/autostyle.lua index a5feda3f..32add29b 100644 --- a/contrib/autostyle.lua +++ b/contrib/autostyle.lua @@ -106,7 +106,7 @@ local function autostyle_apply_one_image (image) if pref and string.len(pref) >= 6 then -- We need the tag, the value and the style_name provided from the configuration string - local tag, value, style_name = string.match(pref, "(%g+)%s*=%s*(%g+)%s*=>%s*(%g+)") + local tag, value, style_name = string.match(pref, "(%g+)%s*=%s*([%g ]-)%s*=>%s*(%g+)") -- check they all exist (correct syntax) if (not tag) then From 9bf7efe71f57a0a141e836ea33e5b81cfd37c74f Mon Sep 17 00:00:00 2001 From: Georg Lutz Date: Sat, 1 Mar 2025 08:46:00 +0100 Subject: [PATCH 436/445] Fix dbmaint.lua "log.log_msg" triggers a lua function error, because that function does not exist. Additionally add add set_log_level / restore_log_level to improve compatibility with other files. --- contrib/dbmaint.lua | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/contrib/dbmaint.lua b/contrib/dbmaint.lua index 16ca9b91..c08309a2 100644 --- a/contrib/dbmaint.lua +++ b/contrib/dbmaint.lua @@ -115,6 +115,20 @@ local namespace = dbmaint -- F U N C T I O N S -- - - - - - - - - - - - - - - - - - - - - - - - +------------------- +-- helper functions +------------------- + +local function set_log_level(level) + local old_log_level = log.log_level() + log.log_level(level) + return old_log_level +end + +local function restore_log_level(level) + log.log_level(level) +end + local function scan_film_rolls() local missing_films = {} @@ -128,19 +142,21 @@ local function scan_film_rolls() end local function scan_images(film) + local old_log_level = set_log_level(DEFAULT_LOG_LEVEL) local missing_images = {} if film then for i = 1, #film do local image = film[i] - log.log_msg(log.debug, "checking " .. image.filename) + log.msg(log.debug, "checking " .. image.filename) if not df.check_if_file_exists(image.path .. PS .. image.filename) then - log.log_msg(log.info, image.filename .. " not found") + log.msg(log.info, image.filename .. " not found") table.insert(missing_images, image) end end end + restore_log_level(old_log_level) return missing_images end @@ -207,6 +223,8 @@ dbmaint.scan_button = dt.new_widget("button"){ clicked_callback = function(this) local found = nil local found_text = "" + local old_log_level = set_log_level(DEFAULT_LOG_LEVEL) + log.msg(log.debug, "Button clicked") if dbmaint.chooser.selected == 1 then -- film rolls found = scan_film_rolls() if #found > 0 then @@ -216,7 +234,7 @@ dbmaint.scan_button = dt.new_widget("button"){ end end else - log.log_msg(log.debug, "checking path " .. dt.collection[1].path .. " for missing files") + log.msg(log.debug, "checking path " .. dt.collection[1].path .. " for missing files") found = scan_images(dt.collection[1].film) if #found > 0 then for _, image in ipairs(found) do @@ -225,10 +243,14 @@ dbmaint.scan_button = dt.new_widget("button"){ end end if #found > 0 then + log.msg(log.debug, "found " .. #found .. " missing items") dbmaint.list_widget.text = found_text dbmaint.found = found dbmaint.remove_button.sensitive = true + else + log.msg(log.debug, "no missing items found") end + restore_log_level(old_log_level) end, reset_callback = function(this) dbmaint.found = nil From 59b5039579b08189d1aa8bc1f9b638767b3a2761 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sat, 8 Mar 2025 15:46:55 -0500 Subject: [PATCH 437/445] tools/script_manager - Moved start_scripts() later in the script to ensure the UI is populated before starting the scripts. Added a check to see if the script is started and if so the power button is updated to show the script is running. --- tools/script_manager.lua | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tools/script_manager.lua b/tools/script_manager.lua index d1ab17e4..becb3d05 100644 --- a/tools/script_manager.lua +++ b/tools/script_manager.lua @@ -599,6 +599,13 @@ end local function start_scripts() for _, script in ipairs(sm.start_queue) do activate(script) + for i = 1, sm.page_status.num_buttons do + local name = script.metadata and script.metadata.name or script.name + if sm.widgets.labels[i].label == name then + sm.widgets.buttons[i].name = "pb_on" + break + end + end end sm.start_queue = {} end @@ -833,7 +840,6 @@ local function scan_repositories() end end - start_scripts() update_script_update_choices() restore_log_level(old_log_level) @@ -1224,6 +1230,7 @@ local function install_module() log.msg(log.debug, "set run to true, loading preferences") load_preferences() scan_repositories() + start_scripts() restore_log_level(old_log_level) end From ea2596ae137f4f0d01b233d97d5cf4faab1cda41 Mon Sep 17 00:00:00 2001 From: Yuri van der Burg Date: Tue, 18 Mar 2025 20:38:21 +0100 Subject: [PATCH 438/445] Fixed typo in hugin script - should resolve issue # 570 --- contrib/hugin.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/hugin.lua b/contrib/hugin.lua index 85fe5f85..46fbd90c 100644 --- a/contrib/hugin.lua +++ b/contrib/hugin.lua @@ -83,7 +83,7 @@ end local function show_status(storage, image, format, filename, number, total, high_quality, extra_data) - dt.print(string.format(_("exporting to hugin: %d / $d"), number, total)) + dt.print(string.format(_("exporting to hugin: %d / %d"), number, total)) end local function create_panorama(storage, image_table, extra_data) --finalize From f20721373ae715fd9bd7e226523f445b3b47d2ff Mon Sep 17 00:00:00 2001 From: fjb2020 <92430217+fjb2020@users.noreply.github.com> Date: Wed, 19 Mar 2025 15:57:10 +0000 Subject: [PATCH 439/445] Fix issue #571, use of for _,image in ipairs(sel_images) do conflicts with function _(msgid) --- contrib/geoToolbox.lua | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/contrib/geoToolbox.lua b/contrib/geoToolbox.lua index 0fa07301..01a14eea 100644 --- a/contrib/geoToolbox.lua +++ b/contrib/geoToolbox.lua @@ -167,7 +167,7 @@ local function get_first_coordinate() first_elevation = '' first_image_date = 0 - for _,image in ipairs(sel_images) do + for jj,image in ipairs(sel_images) do if not image then first_have_data = false else @@ -206,7 +206,7 @@ local function get_second_coordinate() second_elevation = '' second_image_date = 0 - for _,image in ipairs(sel_images) do + for jj,image in ipairs(sel_images) do if not image then second_have_data = false else @@ -242,7 +242,7 @@ local calc_in_between_slider = dt.new_widget("slider") --ToDo: this needs more love local function calc_in_between() local sel_images = dt.gui.action_images - for _,image in ipairs(sel_images) do + for jj,image in ipairs(sel_images) do if image then image_date = make_time_stamp(image.exif_datetime_taken) if (first_have_data and second_have_data) then @@ -289,7 +289,7 @@ local function copy_gps() copy_gps_longitude = '' copy_gps_elevation = '' - for _,image in ipairs(sel_images) do + for jj,image in ipairs(sel_images) do if not image then copy_gps_have_data = false else @@ -316,7 +316,7 @@ end local function paste_gps(image) local sel_images = dt.gui.action_images - for _,image in ipairs(sel_images) do + for jj,image in ipairs(sel_images) do if (label_copy_gps_lat.value) then image.latitude = copy_gps_latitude end @@ -343,7 +343,7 @@ local function open_location_in_gnome_maps() local i = 0; -- Use the first image with geo information - for _,image in ipairs(sel_images) do + for jj,image in ipairs(sel_images) do if ((image.longitude and image.latitude) and (image.longitude ~= 0 and image.latitude ~= 90) -- Sometimes the north-pole but most likely just wrong data ) then @@ -386,7 +386,7 @@ local function reverse_geocode() local i = 0; -- Use the first image with geo information - for _,image in ipairs(sel_images) do + for jj,image in ipairs(sel_images) do if ((image.longitude and image.latitude) and (image.longitude ~= 0 and image.latitude ~= 90) -- Sometimes the north-pole but most likely just wrong data ) then @@ -461,7 +461,7 @@ local function calc_distance() local sel_images = dt.gui.selection() - for _,image in ipairs(sel_images) do + for jj,image in ipairs(sel_images) do if ((image.longitude and image.latitude) and (image.longitude ~= 0 and image.latitude ~= 90) -- Sometimes the north-pole but most likely just wrong data ) then @@ -545,7 +545,7 @@ local function altitude_profile() local elevationAdd = 0; local sel_images = dt.gui.action_images - for _,image in ipairs(sel_images) do + for jj,image in ipairs(sel_images) do if ((not isnan(image.longitude) and not isnan(image.latitude) and not isnan(image.elevation) and image.elevation) and (image.longitude ~= 0 and image.latitude ~= 90) -- Sometimes the north-pole but most likely just wrong data ) then From 87d18549a6cc1a91d743a270c4074e7f61463bb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Milo=C5=A1=20Komar=C4=8Devi=C4=87?= <4973094+kmilos@users.noreply.github.com> Date: Tue, 1 Apr 2025 16:11:56 +0200 Subject: [PATCH 440/445] Fix de_DE translation charset --- locale/de_DE/LC_MESSAGES/clear_GPS.po | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locale/de_DE/LC_MESSAGES/clear_GPS.po b/locale/de_DE/LC_MESSAGES/clear_GPS.po index ad8960b0..420ec484 100644 --- a/locale/de_DE/LC_MESSAGES/clear_GPS.po +++ b/locale/de_DE/LC_MESSAGES/clear_GPS.po @@ -14,7 +14,7 @@ msgstr "" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=CHARSET\n" +"Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 1.5.4\n" "Language: de_DE\n" From c6eee15d759754799ace381c60e67f29a15a1f5b Mon Sep 17 00:00:00 2001 From: Tasos Bakogiannis Date: Wed, 9 Apr 2025 23:48:48 +0200 Subject: [PATCH 441/445] Align sequence tooltip with code. --- lib/dtutils/string.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/dtutils/string.lua b/lib/dtutils/string.lua index 7648f6f6..e92aff45 100644 --- a/lib/dtutils/string.lua +++ b/lib/dtutils/string.lua @@ -877,7 +877,7 @@ function dtutils_string.get_substitution_tooltip() _("$(VERSION.NAME) - version name from metadata"), _("$(DARKTABLE.VERSION) - current darktable version"), -- _("$(DARKTABLE.NAME) - darktable name"), -- not implemented - _("$(SEQUENCE[n,m]) - sequence number, n: number of digits, m: start number"), + _("$(SEQUENCE[m,n]) - sequence number, m: start number, n: number of digits"), _("$(WIDTH.SENSOR) - image sensor width"), _("$(HEIGHT.SENSOR) - image sensor height"), _("$(WIDTH.RAW) - RAW image width"), From 5309ff1726b23105298c491635f4429168937402 Mon Sep 17 00:00:00 2001 From: Tasos Bakogiannis Date: Thu, 10 Apr 2025 19:25:01 +0200 Subject: [PATCH 442/445] Revert "Align sequence tooltip with code." This reverts commit c6eee15d759754799ace381c60e67f29a15a1f5b. --- lib/dtutils/string.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/dtutils/string.lua b/lib/dtutils/string.lua index e92aff45..7648f6f6 100644 --- a/lib/dtutils/string.lua +++ b/lib/dtutils/string.lua @@ -877,7 +877,7 @@ function dtutils_string.get_substitution_tooltip() _("$(VERSION.NAME) - version name from metadata"), _("$(DARKTABLE.VERSION) - current darktable version"), -- _("$(DARKTABLE.NAME) - darktable name"), -- not implemented - _("$(SEQUENCE[m,n]) - sequence number, m: start number, n: number of digits"), + _("$(SEQUENCE[n,m]) - sequence number, n: number of digits, m: start number"), _("$(WIDTH.SENSOR) - image sensor width"), _("$(HEIGHT.SENSOR) - image sensor height"), _("$(WIDTH.RAW) - RAW image width"), From 0cb9a8872e276487568411e47714b866396fd9d7 Mon Sep 17 00:00:00 2001 From: Tasos Bakogiannis Date: Thu, 10 Apr 2025 19:26:45 +0200 Subject: [PATCH 443/445] Update sequence variable order. --- lib/dtutils/string.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/dtutils/string.lua b/lib/dtutils/string.lua index 7648f6f6..48221f19 100644 --- a/lib/dtutils/string.lua +++ b/lib/dtutils/string.lua @@ -994,7 +994,7 @@ local function treat(var_string) log.msg(log.info, "ret_val is " .. ret_val) elseif string.match(var_string, "SEQUENCE%[") then - local start, width = string.match(var_string, "(%d+),(%d)") + local width, start = string.match(var_string, "(%d+),(%d)") local seq_val = tonumber(substitutes[var]) local pat = "%0" .. width .. "d" substitutes[var_string] = string.format(pat, start + (seq_val - 1)) From 980fe3962c64592c3b5a8d3385b8c04065fa2262 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Thu, 1 May 2025 20:37:24 -0400 Subject: [PATCH 444/445] image_time - added default values of 0 for fields not supplied in set time so that an exiftime can be created.\ --- contrib/image_time.lua | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/contrib/image_time.lua b/contrib/image_time.lua index 28570c1a..c0971306 100644 --- a/contrib/image_time.lua +++ b/contrib/image_time.lua @@ -154,12 +154,12 @@ local function systime2exiftime(systime) end local function vars2exiftime(year, month, day, hour, min, sec) - local y = tonumber(year) and string.format("%4d", year) or " " - local mo = tonumber(month) and string.format("%02d", month) or " " - local d = tonumber(day) and string.format("%02d", day) or " " - local h = tonumber(hour) and string.format("%02d", hour) or " " - local m = tonumber(min) and string.format("%02d", min) or " " - local s = tonumber(sec) and string.format("%02d", sec) or " " + local y = tonumber(year) and string.format("%4d", year) or "0000" + local mo = tonumber(month) and string.format("%02d", month) or "00" + local d = tonumber(day) and string.format("%02d", day) or "00" + local h = tonumber(hour) and string.format("%02d", hour) or "00" + local m = tonumber(min) and string.format("%02d", min) or "00" + local s = tonumber(sec) and string.format("%02d", sec) or "00" return(y .. ":" .. mo .. ":" .. d .. " " .. h .. ":" .. m .. ":" .. s) end From b9cc0dccce648887ae2b54ee5ad0f00fcd1c9f91 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sun, 1 Jun 2025 16:36:52 -0400 Subject: [PATCH 445/445] official/apply_camera_style - made spaces in camera name conditional matches as some are squashed and others (Olympus) are not. --- official/apply_camera_style.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/official/apply_camera_style.lua b/official/apply_camera_style.lua index b162ffef..c82a91b3 100644 --- a/official/apply_camera_style.lua +++ b/official/apply_camera_style.lua @@ -166,6 +166,8 @@ local function process_pattern(pattern) end -- escape dashes pattern = string.gsub(pattern, "%-", "%%-") + -- make spaces optional + pattern = string.gsub(pattern, " ", " ?") -- until we end up with a set, I'll defer set processing, i.e. [...] -- anchor the pattern to ensure we don't short match pattern = "^" .. pattern .. "$"