From 2a2fbd18cddaf3a70c20ae105101ea00927a1dd4 Mon Sep 17 00:00:00 2001 From: BzKevin <36381472+BzKevin@users.noreply.github.com> Date: Wed, 13 Feb 2019 12:21:57 -0500 Subject: [PATCH 01/11] Add HDRMerge --- contrib/HDRMerge.lua | 368 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 368 insertions(+) create mode 100644 contrib/HDRMerge.lua diff --git a/contrib/HDRMerge.lua b/contrib/HDRMerge.lua new file mode 100644 index 00000000..9829be1d --- /dev/null +++ b/contrib/HDRMerge.lua @@ -0,0 +1,368 @@ +--[[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 if you have that option enabled. +Additional tags or style can be applied on auto import as well, if you desire. + +Base Options: +Select your desired BPS and 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 + +----KNOWN ISSUES---- +]] + +local dt = require "darktable" +local df = require "lib/dtutils.file" +local dsys = require "lib/dtutils.system" +require "official/yield" + +--Check if HDRMerge is installed-- +local not_installed = 0 +dt.print_log("HDRMerge - Executable Path Preference: "..df.get_executable_path_preference("HDRMerge")) +local HDRMerge_path = df.check_if_bin_exists("HDRMerge") +if not HDRMerge_path then + dt.print_error("HDRMerge not found") + dt.print("ERROR - HDRMerge not found") + not_installed = 1 +end + +--Detect OS and modify accordingly-- +local os_path_seperator = "/" +if dt.configuration.running_os == "windows" then os_path_seperator = "\\" end + +-- READ PREFERENCES -- +local pref_bps = dt.preferences.read("module_HDRMerge", "bits_per_sample", "enum") +local pref_bps_enum = 0 +if pref_bps == "32" then + pref_bps_enum = 3 +elseif pref_bps == "24" then + pref_bps_enum = 2 +else + pref_bps_enum = 1 +end +local pref_size = dt.preferences.read("module_HDRMerge", "preview_size", "enum") +local pref_size_enum = 0 +if pref_size == "none" then + pref_size_enum = 3 +elseif pref_size == "full" then + pref_size_enum = 2 +else + pref_size_enum = 1 +end +--pref_cpytags = dt.preferences.read("module_HDRMerge", "copy_tags", "bool") +--pref_addtags = dt.preferences.read("module_HDRMerge", "add_tags", "string") +local pref_style = dt.preferences.read("module_HDRMerge", "style", "string") + +--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 + +-- FUNCTION -- +local function build_execute_command(cmd, args, file_list) + local result = cmd.." "..args.." "..file_list + return result +end +local function HDRMerge() + if not_installed == 1 then + dt.print("Required software not found") + dt.print_log("Required software not found - HDRMerge did not run") + return + end + dt.print_log("Running HDRMerge") + dt.print("Running HDRMerge") + gui_job = dt.gui.create_job("HDRMerge", 1) + + --Inits-- + local images = dt.gui.selection() + local images_to_merge = "" + local image_path = "" + local curr_image = "" + local first_image = "" + local last_image = "" + local output_file = "" + local num_images = 0 + + --Read Settings-- + local set_bps = HDRMerge_cmbx_bps.value + local set_size = HDRMerge_cmbx_size.value + local set_batch = HDRMerge_chkbtn_batch.value + local set_gap = HDRMerge_sldr_gap.value + local set_cpytags = HDRMerge_chkbtn_cpytags.value + local set_tag = HDRMerge_entry_tag.text + + --Create Images String-- + for _,image in pairs(images) do + curr_image = image.path..os_path_seperator..image.filename + images_to_merge = images_to_merge..df.sanitize_filename(curr_image).." " + last_image = string.gsub(string.match(image.filename,'^.*%.'), "%." , "") + image_path = image.path + if _ == 1 then first_image = last_image end + num_images = num_images + 1 + end + output_file = image_path..os_path_seperator..first_image.."-"..string.match(last_image, '%d*$')..".dng" + output_file = df.create_unique_filename(output_file) + --output_file = df.sanitize_filename(output_file) + --Check if at least 2 images selected-- + if num_images < 2 then + dt.print_error("Less than 2 images selected") + dt.print("ERROR - please select at least 2 images") + gui_job.valid = false + return + end + + --Create Command Args-- + cmd_args = "-b "..set_bps.." -p "..set_size + if (set_batch) then + cmd_args = cmd_args.." -B -g "..set_gap.." -a" + else --add ability to launch with gui here by omiting -o arg + cmd_args = cmd_args.." -o "..df.sanitize_filename(output_file) + end + + gui_job.percent = .1 + + --Execute with Run Command-- + run_cmd = build_execute_command(HDRMerge_path, cmd_args, images_to_merge) + dt.print_log("run_cmd = "..run_cmd) + resp = dsys.external_command(run_cmd) + + gui_job.percent = .9 + + if resp == 0 and not(set_batch) then + --Import Image-- + imported = dt.database.import(output_file) + + --Apply Selected Style (IF)-- + if HDRMerge_cmbx_style.selected > 1 then + set_style = styles[HDRMerge_cmbx_style.selected - 1] + dt.styles.apply(set_style , imported) + end + + --Copy Tags (IF)-- + if (set_cpytags) then + all_tags = dt.tags.get_tags(images[1]) + for _,tag in pairs(all_tags) do + if string.match(tag.name, 'darktable|') == nil then + dt.tags.attach(tag, imported) + end + end + end + + --Apply Entered Tags (IF)-- + if set_tag ~= nil then + for tag in string.gmatch(set_tag, '[^,]+') do + tag = string.gsub(tag, " ", "") + tag = dt.tags.create(tag) + dt.tags.attach(tag, imported) + end + end + + dt.print_log("Merge Successful") + dt.print("Merge Successful") + elseif resp == 0 then + dt.print_log("Merge Successful") + dt.print("Merge Successful") + else + dt.print_error("Merge Not Successful") + dt.print("ERROR - Merge Not Successful") + end + gui_job.percent = 1 + gui_job.valid = false +end + +-- GUI -- +HDRMerge_lbl_base= dt.new_widget("section_label"){ + label = "Base Options", + } +HDRMerge_cmbx_bps = dt.new_widget("combobox"){ + label = 'Bits Per Sample', + tooltip = 'Output file\'s bit depth \ndefault: '..pref_bps, + value = pref_bps_enum, + "16", "24", "32", + } +HDRMerge_cmbx_size = dt.new_widget("combobox"){ + label = 'Preview Size', + tooltip = 'Output file\'s built-in preview size \ndefault: '..pref_size, + value = pref_size_enum, + "half", "full", "none", + } +HDRMerge_lbl_batch= dt.new_widget("section_label"){ + label = "Batch Options", + } +HDRMerge_chkbtn_batch = dt.new_widget("check_button"){ + label = ' Batch Mode', + value = false, --pref_batch, + tooltip ='Operate in batch mode. When operating in batch mode output files will NOT be auto-imported \ndefault: (false).', + } +HDRMerge_sldr_gap = dt.new_widget("slider"){ + label = 'Batch Gap [sec.]', + tooltip = 'Gap, in seconds, between batch mode groups \ndefault: (3).', + soft_min = 1, + soft_max = 60, + hard_min = 1, + hard_max = 60, + step = 1, + digits = 0, + value = 3, --pref_gap, + } +HDRMerge_lbl_out= dt.new_widget("section_label"){ + label = "Auto-import Options", + } +HDRMerge_cmbx_style = dt.new_widget("combobox"){ + label = "Apply Style on Import", + tooltip = "Apply selected style on auto-import to newly created HDRMerge DNG\nDoes not apply when in Batch mode.", + value = 1, + "none", + } +pref_style_enum = 1 +for k=1, (styles_count-1) do + HDRMerge_cmbx_style[k+1] = styles[k].name + if styles[k].name == pref_style then pref_style_enum = k+1 end +end +HDRMerge_cmbx_style.value = pref_style_enum +HDRMerge_chkbtn_cpytags = dt.new_widget("check_button"){ + label = ' Copy Tags', + value = dt.preferences.read("module_HDRMerge", "copy_tags", "bool"), + tooltip ='Copy tags from first image. When operating in batch mode this will NOT be performed. \ndefault: (true).', + } +HDRMerge_lbl_tags= dt.new_widget("label"){ + label = 'Additional Tags', + } +HDRMerge_entry_tag = dt.new_widget("entry"){ + tooltip = "Additional tags to be added on import. Seperate with commas, all spaces will be removed", + text = dt.preferences.read("module_HDRMerge", "add_tags", "string"), + placeholder = "Enter tags, seperated by commas", + editable = true +} +HDRMerge_btn_run = dt.new_widget("button"){ + label = "Run HDRMerge", + tooltip = "Runs HDRMerge on selected images, with selected settings", + clicked_callback = function() HDRMerge() end + } +HDRMerge_lbl_note= dt.new_widget("label"){ + label = 'Defaults can be adjusted under:\n"Settings > lua options"', + } +dt.register_lib( + "HDRMerge_Lib", -- Module name + "HDRMerge", -- name + true, -- expandable + false, -- resetable + {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 99}}, -- containers + dt.new_widget("box"){ + orientation = "vertical", + HDRMerge_lbl_base, + HDRMerge_cmbx_bps, + HDRMerge_cmbx_size, + HDRMerge_lbl_batch, + HDRMerge_chkbtn_batch, + HDRMerge_sldr_gap, + HDRMerge_lbl_out, + HDRMerge_cmbx_style, + HDRMerge_chkbtn_cpytags, + HDRMerge_lbl_tags, + HDRMerge_entry_tag, + HDRMerge_btn_run, + HDRMerge_lbl_note + } +) + +-- PREFERENCES -- +HDRMerge_entry_widget_tags = dt.new_widget("entry"){ + tooltip = "Seperate with commas, all spaces will be removed", + text = nil, + placeholder = "Enter default tags", + editable = true +} +dt.preferences.register("module_HDRMerge", "add_tags", -- name + "string", -- type + 'HDRMerge: Defualt additional tags', -- label + 'Changes DEFAULT entry in the additional tags option. Requires restart to take effect.', -- tooltip + "", -- default + HDRMerge_entry_widget_tags +) +HDRMerge_entry_widget_style = dt.new_widget("entry"){ + tooltip = "Enter the style name exactly as it is", + text = nil, + placeholder = "Enter Style name", + editable = true +} +dt.preferences.register("module_HDRMerge", "style", -- name + "string", -- type + 'HDRMerge: Defualt Style', -- label + 'Changes DEFAULT entry in the Style option. Requires restart to take effect.', -- tooltip + "", -- default + HDRMerge_entry_widget_style +) +dt.preferences.register("module_HDRMerge", "copy_tags", -- name + "bool", -- type + 'HDRMerge: Copy tags from first image by default', -- label + 'Changes DEFAULT selection for Copy Tags, Requires restart to take effect.', -- tooltip + true -- default +) +dt.preferences.register("module_HDRMerge", "preview_size", -- name + "enum", -- type + 'HDRMerge: Default DNG Preview Size', -- label + "Change the DEFAULT preview size. Requires restart to take effect.", -- tooltip + "half", -- default + "full", "none" --values +) +dt.preferences.register("module_HDRMerge", "bits_per_sample", -- name + "enum", -- type + 'HDRMerge: Default Bits Per Sample', -- label + 'Change the DEFAULT bit depth. Requires restart to take effect.', -- tooltip + "16", -- default + "24","32" --value +) + +if not HDRMerge_path then + HDRMerge_path = "" +end +HDRMerge_path_widget = dt.new_widget("file_chooser_button"){ + title = "Select HDRMerge[.exe] file", + value = HDRMerge_path, + is_directory = false, +} +dt.preferences.register("executable_paths", "HDRMerge", -- name + "file", -- type + 'HDRMerge: Binary Location', -- label + 'Install location of HDRMerge[.exe]. Requires restart to take effect.', -- tooltip + "HDRMerge", -- default + HDRMerge_path_widget +) From 2cb3397d759c1850fd343c4d9898c84a848f87af Mon Sep 17 00:00:00 2001 From: BzKevin <36381472+BzKevin@users.noreply.github.com> Date: Fri, 15 Feb 2019 13:22:49 -0500 Subject: [PATCH 02/11] Update HDRMerge Now only checks for binary proper install once the functionality of the program is actually utilized. This avoids to many external command calls at dt startup just to check if certain things are installed. --- contrib/HDRMerge.lua | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/contrib/HDRMerge.lua b/contrib/HDRMerge.lua index 9829be1d..4300b6cf 100644 --- a/contrib/HDRMerge.lua +++ b/contrib/HDRMerge.lua @@ -52,14 +52,9 @@ local dsys = require "lib/dtutils.system" require "official/yield" --Check if HDRMerge is installed-- -local not_installed = 0 -dt.print_log("HDRMerge - Executable Path Preference: "..df.get_executable_path_preference("HDRMerge")) -local HDRMerge_path = df.check_if_bin_exists("HDRMerge") -if not HDRMerge_path then - dt.print_error("HDRMerge not found") - dt.print("ERROR - HDRMerge not found") - not_installed = 1 -end +local first_run = true +local not_installed = false +local HDRMerge_path --Detect OS and modify accordingly-- local os_path_seperator = "/" @@ -101,7 +96,16 @@ local function build_execute_command(cmd, args, file_list) return result end local function HDRMerge() - if not_installed == 1 then + if first_run then + HDRMerge_path = df.check_if_bin_exists("HDRMerge") + if not HDRMerge_path then + dt.print_error("HDRMerge not found") + dt.print("ERROR - HDRMerge not found") + not_installed = true + end + first_run = false + end + if not_installed then dt.print("Required software not found") dt.print_log("Required software not found - HDRMerge did not run") return @@ -350,15 +354,6 @@ dt.preferences.register("module_HDRMerge", "bits_per_sample", -- name "16", -- default "24","32" --value ) - -if not HDRMerge_path then - HDRMerge_path = "" -end -HDRMerge_path_widget = dt.new_widget("file_chooser_button"){ - title = "Select HDRMerge[.exe] file", - value = HDRMerge_path, - is_directory = false, -} dt.preferences.register("executable_paths", "HDRMerge", -- name "file", -- type 'HDRMerge: Binary Location', -- label From 5fd3a56a3181b16dbcd381076b2effbabf9a98b3 Mon Sep 17 00:00:00 2001 From: BzKevin <36381472+BzKevin@users.noreply.github.com> Date: Fri, 15 Feb 2019 14:24:51 -0500 Subject: [PATCH 03/11] Remove extraneous widgets in preferences I now understand how preferences work better and have removed the extraneous widgets which were doing nothing --- contrib/HDRMerge.lua | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/contrib/HDRMerge.lua b/contrib/HDRMerge.lua index 4300b6cf..9614f491 100644 --- a/contrib/HDRMerge.lua +++ b/contrib/HDRMerge.lua @@ -308,31 +308,17 @@ dt.register_lib( ) -- PREFERENCES -- -HDRMerge_entry_widget_tags = dt.new_widget("entry"){ - tooltip = "Seperate with commas, all spaces will be removed", - text = nil, - placeholder = "Enter default tags", - editable = true -} dt.preferences.register("module_HDRMerge", "add_tags", -- name "string", -- type 'HDRMerge: Defualt additional tags', -- label 'Changes DEFAULT entry in the additional tags option. Requires restart to take effect.', -- tooltip - "", -- default - HDRMerge_entry_widget_tags + "" -- default ) -HDRMerge_entry_widget_style = dt.new_widget("entry"){ - tooltip = "Enter the style name exactly as it is", - text = nil, - placeholder = "Enter Style name", - editable = true -} dt.preferences.register("module_HDRMerge", "style", -- name "string", -- type 'HDRMerge: Defualt Style', -- label 'Changes DEFAULT entry in the Style option. Requires restart to take effect.', -- tooltip - "", -- default - HDRMerge_entry_widget_style + "" -- default ) dt.preferences.register("module_HDRMerge", "copy_tags", -- name "bool", -- type @@ -358,6 +344,5 @@ dt.preferences.register("executable_paths", "HDRMerge", -- name "file", -- type 'HDRMerge: Binary Location', -- label 'Install location of HDRMerge[.exe]. Requires restart to take effect.', -- tooltip - "HDRMerge", -- default - HDRMerge_path_widget + "HDRMerge" -- default ) From 7bc4846c0a4143b47637405be71336371247558a Mon Sep 17 00:00:00 2001 From: BzKevin <36381472+BzKevin@users.noreply.github.com> Date: Sun, 3 Mar 2019 15:48:08 -0500 Subject: [PATCH 04/11] Refactored After experiencing some issues after upgrading to dt2.6 I decided it would be worthwhile to refactor the code for more reliable performance. Specifically the script would crash dt when attempting to apply a style on import and sometimes just fail to run. I have refactored this in a manor that should make it more logical for future users to add/maintain as applicable. Refactored script has only been tested on Windows 10 w/ dt2.6. Hopefullt all cross-platform aspects have been maintained. --- contrib/HDRMerge.lua | 510 ++++++++++++++++++++++--------------------- 1 file changed, 267 insertions(+), 243 deletions(-) diff --git a/contrib/HDRMerge.lua b/contrib/HDRMerge.lua index 9614f491..c0cafc3b 100644 --- a/contrib/HDRMerge.lua +++ b/contrib/HDRMerge.lua @@ -28,11 +28,11 @@ Install: (see here for more detail: https://github.com/darktable-org/lua-scripts 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 if you have that option enabled. +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 and Preview Size. +Select your desired BPS (bits per sample and Embedded Preview Size. Batch Options: Select if you want to run in batch mode or not @@ -42,46 +42,50 @@ See HDRMerge manual for further detail: http://jcelaya.github.io/hdrmerge/docume 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 - -----KNOWN ISSUES---- ]] local dt = require "darktable" local df = require "lib/dtutils.file" local dsys = require "lib/dtutils.system" -require "official/yield" - ---Check if HDRMerge is installed-- -local first_run = true -local not_installed = false -local HDRMerge_path - ---Detect OS and modify accordingly-- -local os_path_seperator = "/" -if dt.configuration.running_os == "windows" then os_path_seperator = "\\" end +local mod = 'module_HDRMerge' +local os_path_seperator = '/' +if dt.configuration.running_os == 'windows' then os_path_seperator = '\\' end --- READ PREFERENCES -- -local pref_bps = dt.preferences.read("module_HDRMerge", "bits_per_sample", "enum") -local pref_bps_enum = 0 -if pref_bps == "32" then - pref_bps_enum = 3 -elseif pref_bps == "24" then - pref_bps_enum = 2 -else - pref_bps_enum = 1 -end -local pref_size = dt.preferences.read("module_HDRMerge", "preview_size", "enum") -local pref_size_enum = 0 -if pref_size == "none" then - pref_size_enum = 3 -elseif pref_size == "full" then - pref_size_enum = 2 -else - pref_size_enum = 1 -end ---pref_cpytags = dt.preferences.read("module_HDRMerge", "copy_tags", "bool") ---pref_addtags = dt.preferences.read("module_HDRMerge", "add_tags", "string") -local pref_style = dt.preferences.read("module_HDRMerge", "style", "string") +dt.preferences.register("executable_paths", "HDRMerge", -- name + "file", -- type + 'HDRMerge: binary location', -- label + 'Install location of HDRMerge. Requires restart to take effect.', -- tooltip + "HDRMerge" -- default +) +local temp +local HDRM = { + 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 = { + HDR = { + bps ={}, + size ={}, + batch ={}, + gap ={} + }, + Target = { + style ={}, + copy_tags ={}, + add_tags ={} + }, + run = {} +} --Detect User Styles-- local styles = dt.styles @@ -90,259 +94,279 @@ for _,i in pairs(dt.styles) do if type(i) == "userdata" then styles_count = styles_count + 1 end end --- FUNCTION -- -local function build_execute_command(cmd, args, file_list) - local result = cmd.." "..args.." "..file_list +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 the passed in text string + front = string.match(text, '^%s') + back = string.match(text, '%s$') + if front then + text = string.sub(text,2) + end + if back then + text = string.sub(text,1,-2) + end + return text +end + +local function BuildExecuteCmd(prog_table) + local result = prog_table.bin..' '..prog_table.arg_string..' '..prog_table.images_string return result end -local function HDRMerge() - if first_run then - HDRMerge_path = df.check_if_bin_exists("HDRMerge") - if not HDRMerge_path then - dt.print_error("HDRMerge not found") - dt.print("ERROR - HDRMerge not found") - not_installed = true + +local function PreCall(prog_tbl) + 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 + else + prog.bin = CleanSpaces(prog.bin) + end + prog.first_run = false end - first_run = false end - if not_installed then - dt.print("Required software not found") - dt.print_log("Required software not found - HDRMerge did not run") +end + +local function UpdateActivePreference() + 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 HDRMerge_main() + PreCall({HDRM}) + if HDRM.install_error then + dt.print_error('HDRMerge install issue, please ensure the binary path is proper') return end - dt.print_log("Running HDRMerge") - dt.print("Running HDRMerge") - gui_job = dt.gui.create_job("HDRMerge", 1) - - --Inits-- - local images = dt.gui.selection() - local images_to_merge = "" - local image_path = "" - local curr_image = "" - local first_image = "" - local last_image = "" - local output_file = "" - local num_images = 0 - - --Read Settings-- - local set_bps = HDRMerge_cmbx_bps.value - local set_size = HDRMerge_cmbx_size.value - local set_batch = HDRMerge_chkbtn_batch.value - local set_gap = HDRMerge_sldr_gap.value - local set_cpytags = HDRMerge_chkbtn_cpytags.value - local set_tag = HDRMerge_entry_tag.text - - --Create Images String-- - for _,image in pairs(images) do - curr_image = image.path..os_path_seperator..image.filename - images_to_merge = images_to_merge..df.sanitize_filename(curr_image).." " - last_image = string.gsub(string.match(image.filename,'^.*%.'), "%." , "") - image_path = image.path - if _ == 1 then first_image = last_image end - num_images = num_images + 1 + images = dt.gui.selection() + local count = 0 + for _,image in pairs(images) do + count = count + 1 end - output_file = image_path..os_path_seperator..first_image.."-"..string.match(last_image, '%d*$')..".dng" - output_file = df.create_unique_filename(output_file) - --output_file = df.sanitize_filename(output_file) - --Check if at least 2 images selected-- - if num_images < 2 then - dt.print_error("Less than 2 images selected") - dt.print("ERROR - please select at least 2 images") - gui_job.valid = false + if count < 2 then + dt.print_error('not enough images selected, select at least 2 images to merge') return end - --Create Command Args-- - cmd_args = "-b "..set_bps.." -p "..set_size - if (set_batch) then - cmd_args = cmd_args.." -B -g "..set_gap.." -a" - else --add ability to launch with gui here by omiting -o arg - cmd_args = cmd_args.." -o "..df.sanitize_filename(output_file) - end + UpdateActivePreference() - gui_job.percent = .1 + --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 + 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 + end + HDRM.images_string = CleanSpaces(HDRM.images_string) + out_path = out_path..os_path_seperator..smallest_name..'-'..largest_id..'.dng' + out_path = df.create_unique_filename(out_path) - --Execute with Run Command-- - run_cmd = build_execute_command(HDRMerge_path, cmd_args, images_to_merge) - dt.print_log("run_cmd = "..run_cmd) - resp = dsys.external_command(run_cmd) + --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 + HDRM.arg_string = CleanSpaces(HDRM.arg_string) - gui_job.percent = .9 + -- create run command and execute + local run_cmd = BuildExecuteCmd(HDRM) + resp = dsys.external_command(run_cmd) - if resp == 0 and not(set_batch) then - --Import Image-- - imported = dt.database.import(output_file) - - --Apply Selected Style (IF)-- - if HDRMerge_cmbx_style.selected > 1 then - set_style = styles[HDRMerge_cmbx_style.selected - 1] + if resp == 0 and not GUI.HDR.batch.value then + local imported = dt.database.import(out_path) + if GUI.Target.style.selected > 1 then + local set_style = styles[GUI.Target.style.selected - 1] dt.styles.apply(set_style , imported) end - - --Copy Tags (IF)-- - if (set_cpytags) then - all_tags = dt.tags.get_tags(images[1]) + if GUI.Target.copy_tags.value then + 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 + if string.match(tag.name, 'darktable|') == nil then dt.tags.attach(tag, imported) end end end - - --Apply Entered Tags (IF)-- + local set_tag = GUI.Target.add_tags.text if set_tag ~= nil then for tag in string.gmatch(set_tag, '[^,]+') do - tag = string.gsub(tag, " ", "") + tag = CleanSpaces(tag) tag = dt.tags.create(tag) dt.tags.attach(tag, imported) end end - - dt.print_log("Merge Successful") - dt.print("Merge Successful") - elseif resp == 0 then - dt.print_log("Merge Successful") - dt.print("Merge Successful") else - dt.print_error("Merge Not Successful") - dt.print("ERROR - Merge Not Successful") + dt.print_error('HDRMerge failed') end - gui_job.percent = 1 - gui_job.valid = false + end --- GUI -- -HDRMerge_lbl_base= dt.new_widget("section_label"){ - label = "Base Options", - } -HDRMerge_cmbx_bps = dt.new_widget("combobox"){ - label = 'Bits Per Sample', - tooltip = 'Output file\'s bit depth \ndefault: '..pref_bps, - value = pref_bps_enum, - "16", "24", "32", - } -HDRMerge_cmbx_size = dt.new_widget("combobox"){ - label = 'Preview Size', - tooltip = 'Output file\'s built-in preview size \ndefault: '..pref_size, - value = pref_size_enum, - "half", "full", "none", - } -HDRMerge_lbl_batch= dt.new_widget("section_label"){ - label = "Batch Options", - } -HDRMerge_chkbtn_batch = dt.new_widget("check_button"){ - label = ' Batch Mode', - value = false, --pref_batch, - tooltip ='Operate in batch mode. When operating in batch mode output files will NOT be auto-imported \ndefault: (false).', - } -HDRMerge_sldr_gap = dt.new_widget("slider"){ - label = 'Batch Gap [sec.]', - tooltip = 'Gap, in seconds, between batch mode groups \ndefault: (3).', +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 = 60, + soft_max = 30, hard_min = 1, - hard_max = 60, + hard_max = 3600, step = 1, digits = 0, - value = 3, --pref_gap, - } -HDRMerge_lbl_out= dt.new_widget("section_label"){ - label = "Auto-import Options", - } -HDRMerge_cmbx_style = dt.new_widget("combobox"){ - label = "Apply Style on Import", - tooltip = "Apply selected style on auto-import to newly created HDRMerge DNG\nDoes not apply when in Batch mode.", - value = 1, + 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", - } -pref_style_enum = 1 + 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 - HDRMerge_cmbx_style[k+1] = styles[k].name - if styles[k].name == pref_style then pref_style_enum = k+1 end + GUI.Target.style[k+1] = styles[k].name end -HDRMerge_cmbx_style.value = pref_style_enum -HDRMerge_chkbtn_cpytags = dt.new_widget("check_button"){ - label = ' Copy Tags', - value = dt.preferences.read("module_HDRMerge", "copy_tags", "bool"), - tooltip ='Copy tags from first image. When operating in batch mode this will NOT be performed. \ndefault: (true).', - } -HDRMerge_lbl_tags= dt.new_widget("label"){ - label = 'Additional Tags', - } -HDRMerge_entry_tag = dt.new_widget("entry"){ +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 = dt.preferences.read("module_HDRMerge", "add_tags", "string"), + text = temp, placeholder = "Enter tags, seperated by commas", editable = true } -HDRMerge_btn_run = dt.new_widget("button"){ - label = "Run HDRMerge", - tooltip = "Runs HDRMerge on selected images, with selected settings", - clicked_callback = function() HDRMerge() end - } -HDRMerge_lbl_note= dt.new_widget("label"){ - label = 'Defaults can be adjusted under:\n"Settings > lua options"', - } +GUI.run = dt.new_widget("button"){ + label = 'merge', + tooltip ='run HDRMerge with the above specified settings', + clicked_callback = function() HDRMerge_main() end +} dt.register_lib( "HDRMerge_Lib", -- Module name "HDRMerge", -- name true, -- expandable - false, -- resetable + true, -- resetable {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 99}}, -- containers dt.new_widget("box"){ orientation = "vertical", - HDRMerge_lbl_base, - HDRMerge_cmbx_bps, - HDRMerge_cmbx_size, - HDRMerge_lbl_batch, - HDRMerge_chkbtn_batch, - HDRMerge_sldr_gap, - HDRMerge_lbl_out, - HDRMerge_cmbx_style, - HDRMerge_chkbtn_cpytags, - HDRMerge_lbl_tags, - HDRMerge_entry_tag, - HDRMerge_btn_run, - HDRMerge_lbl_note - } + 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 + } ) --- PREFERENCES -- -dt.preferences.register("module_HDRMerge", "add_tags", -- name - "string", -- type - 'HDRMerge: Defualt additional tags', -- label - 'Changes DEFAULT entry in the additional tags option. Requires restart to take effect.', -- tooltip - "" -- default -) -dt.preferences.register("module_HDRMerge", "style", -- name - "string", -- type - 'HDRMerge: Defualt Style', -- label - 'Changes DEFAULT entry in the Style option. Requires restart to take effect.', -- tooltip - "" -- default -) -dt.preferences.register("module_HDRMerge", "copy_tags", -- name - "bool", -- type - 'HDRMerge: Copy tags from first image by default', -- label - 'Changes DEFAULT selection for Copy Tags, Requires restart to take effect.', -- tooltip - true -- default -) -dt.preferences.register("module_HDRMerge", "preview_size", -- name - "enum", -- type - 'HDRMerge: Default DNG Preview Size', -- label - "Change the DEFAULT preview size. Requires restart to take effect.", -- tooltip - "half", -- default - "full", "none" --values -) -dt.preferences.register("module_HDRMerge", "bits_per_sample", -- name - "enum", -- type - 'HDRMerge: Default Bits Per Sample', -- label - 'Change the DEFAULT bit depth. Requires restart to take effect.', -- tooltip - "16", -- default - "24","32" --value -) -dt.preferences.register("executable_paths", "HDRMerge", -- name - "file", -- type - 'HDRMerge: Binary Location', -- label - 'Install location of HDRMerge[.exe]. Requires restart to take effect.', -- tooltip - "HDRMerge" -- default -) From 85c242ff0e926541b4cf6628ec124e1e38bc4a29 Mon Sep 17 00:00:00 2001 From: BzKevin <36381472+BzKevin@users.noreply.github.com> Date: Mon, 4 Mar 2019 09:45:05 -0500 Subject: [PATCH 05/11] Comments added, minor updates I have added comments throughout, mainly to the functions I improved the performance of the CleanSpaces() function Improved communication to user via dt.print() --- contrib/HDRMerge.lua | 68 +++++++++++++++++++------------------------- 1 file changed, 29 insertions(+), 39 deletions(-) diff --git a/contrib/HDRMerge.lua b/contrib/HDRMerge.lua index c0cafc3b..354c028a 100644 --- a/contrib/HDRMerge.lua +++ b/contrib/HDRMerge.lua @@ -58,7 +58,7 @@ dt.preferences.register("executable_paths", "HDRMerge", -- name "HDRMerge" -- default ) local temp -local HDRM = { +local HDRM = { --HDRMerge Program Table name = 'HDRMerge', bin = '', first_run = true, @@ -72,7 +72,7 @@ local HDRM = { gap ={text = '-g ', style = 'integer'} } } -local GUI = { +local GUI = { --GUI Elements Table HDR = { bps ={}, size ={}, @@ -102,9 +102,8 @@ local function InRange(test, low, high) --tests if test value is within range of 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 +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/ @@ -122,24 +121,18 @@ local function GetFileName(full_path) return path, filename, identifier, extension end -local function CleanSpaces(text) --removes spaces from the front and back of the passed in text string - front = string.match(text, '^%s') - back = string.match(text, '%s$') - if front then - text = string.sub(text,2) - end - if back then - text = string.sub(text,1,-2) - 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) - local result = prog_table.bin..' '..prog_table.arg_string..' '..prog_table.images_string +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) +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) @@ -153,30 +146,27 @@ local function PreCall(prog_tbl) end end -local function UpdateActivePreference() +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 HDRMerge_main() - PreCall({HDRM}) +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, please ensure the binary path is proper') + dt.print_error('HDRMerge install issue') + dt.print('HDRMerge install issue, please ensure the binary path is proper') return end - images = dt.gui.selection() - local count = 0 - for _,image in pairs(images) do - count = count + 1 - end - if count < 2 then - dt.print_error('not enough images selected, select at least 2 images to merge') + 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() + 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 = '' @@ -185,7 +175,7 @@ local function HDRMerge_main() local smallest_name = '' local largest_id = 0 local source_raw = {} - for _,image in pairs(images) do + 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 @@ -198,7 +188,6 @@ local function HDRMerge_main() end if source_id > largest_id then largest_id = source_id end end - HDRM.images_string = CleanSpaces(HDRM.images_string) out_path = out_path..os_path_seperator..smallest_name..'-'..largest_id..'.dng' out_path = df.create_unique_filename(out_path) @@ -209,38 +198,40 @@ local function HDRMerge_main() else HDRM.arg_string = HDRM.arg_string..'-o '..df.sanitize_filename(out_path) end - HDRM.arg_string = CleanSpaces(HDRM.arg_string) -- 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) - if GUI.Target.style.selected > 1 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 + 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 + 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 +-- GUI Elements -- local lbl_hdr = dt.new_widget('section_label'){ label = 'HDRMerge options' } @@ -347,9 +338,9 @@ GUI.Target.add_tags = dt.new_widget("entry"){ GUI.run = dt.new_widget("button"){ label = 'merge', tooltip ='run HDRMerge with the above specified settings', - clicked_callback = function() HDRMerge_main() end + clicked_callback = function() main() end } -dt.register_lib( +dt.register_lib( -- register HDRMerge module "HDRMerge_Lib", -- Module name "HDRMerge", -- name true, -- expandable @@ -369,4 +360,3 @@ dt.register_lib( GUI.run } ) - From 5d3910da499b7a368ccc1622ad8972cc77508dbf Mon Sep 17 00:00:00 2001 From: BzKevin <36381472+BzKevin@users.noreply.github.com> Date: Tue, 5 Mar 2019 09:14:28 -0500 Subject: [PATCH 06/11] Tab to Space --- contrib/HDRMerge.lua | 472 +++++++++++++++++++++---------------------- 1 file changed, 236 insertions(+), 236 deletions(-) diff --git a/contrib/HDRMerge.lua b/contrib/HDRMerge.lua index 354c028a..4039350c 100644 --- a/contrib/HDRMerge.lua +++ b/contrib/HDRMerge.lua @@ -51,312 +51,312 @@ local mod = 'module_HDRMerge' local os_path_seperator = '/' if dt.configuration.running_os == 'windows' then os_path_seperator = '\\' end -dt.preferences.register("executable_paths", "HDRMerge", -- name - "file", -- type - 'HDRMerge: binary location', -- label - 'Install location of HDRMerge. Requires restart to take effect.', -- tooltip - "HDRMerge" -- default +dt.preferences.register("executable_paths", "HDRMerge", -- name + "file", -- type + 'HDRMerge: binary location', -- label + 'Install location of HDRMerge. Requires restart to take effect.', -- tooltip + "HDRMerge" -- default ) 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 = {} + HDR = { + bps ={}, + size ={}, + batch ={}, + gap ={} + }, + Target = { + style ={}, + copy_tags ={}, + add_tags ={} + }, + run = {} } --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 + 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*") + + 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 - else - prog.bin = CleanSpaces(prog.bin) - end - prog.first_run = false - end - end + 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 + else + prog.bin = CleanSpaces(prog.bin) + end + prog.first_run = false + end + 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 - 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 - 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 + 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 + _, 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 + 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 -- 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 } 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", - 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 - } + "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", + 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 + } ) From 7a3a9ba559ee0b2f1f6b71a74e4531a07df74fc4 Mon Sep 17 00:00:00 2001 From: BzKevin <36381472+BzKevin@users.noreply.github.com> Date: Tue, 12 Mar 2019 11:19:22 -0400 Subject: [PATCH 07/11] Removed preferences for exe The GUI is now made of a stack which has two boxes in it. One box contains all the normal GUI elements, the other contains a file chooser button and a normal button to call an update routine. This box is only displayed if an issue is found. I decided to track the install status via a preference boolean, rather than calling df_check_if_bin_exists at startup every time. I do this because on my windows PC I was starting to get slow startups with too many scripts installed and many many flashing CMD windows at startup as well, which was a nuisance. --- contrib/HDRMerge.lua | 78 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 61 insertions(+), 17 deletions(-) diff --git a/contrib/HDRMerge.lua b/contrib/HDRMerge.lua index 4039350c..f9409070 100644 --- a/contrib/HDRMerge.lua +++ b/contrib/HDRMerge.lua @@ -51,12 +51,6 @@ local mod = 'module_HDRMerge' local os_path_seperator = '/' if dt.configuration.running_os == 'windows' then os_path_seperator = '\\' end -dt.preferences.register("executable_paths", "HDRMerge", -- name - "file", -- type - 'HDRMerge: binary location', -- label - 'Install location of HDRMerge. Requires restart to take effect.', -- tooltip - "HDRMerge" -- default -) local temp local HDRM = { --HDRMerge Program Table name = 'HDRMerge', @@ -84,7 +78,12 @@ local GUI = { --GUI Elements Table copy_tags ={}, add_tags ={} }, - run = {} + run = {}, + stack = {}, + options = {}, + exes = {}, + exe_chooser = {}, + exe_update = {}, } --Detect User Styles-- @@ -138,12 +137,29 @@ local function PreCall(prog_tbl) --looks to see if this is the first call, if so 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 end +end + +local function ExeUpdate(prog_tbl) + dt.preferences.write(mod, 'bin_exists', 'bool', true) + for _,prog in pairs(prog_tbl) do + 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 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 @@ -340,6 +356,43 @@ GUI.run = dt.new_widget("button"){ tooltip ='run HDRMerge with the above specified settings', clicked_callback = function() main() end } +GUI.exe_chooser = dt.new_widget('file_chooser_button'){ + title = "Select HDRmerge executable", + value = df.get_executable_path_preference(HDRM.name), + is_directory = false +} +GUI.exe_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 +} +GUI.exes = dt.new_widget('box'){ + orientation = 'vertical', + GUI.exe_chooser, + GUI.exe_update +} +GUI.stack = dt.new_widget('stack'){ + active = 1, + GUI.options, + GUI.exes +} +if not dt.preferences.read(mod, 'bin_exists', 'bool') then + GUI.stack.active = 2 +end + dt.register_lib( -- register HDRMerge module "HDRMerge_Lib", -- Module name "HDRMerge", -- name @@ -348,15 +401,6 @@ dt.register_lib( -- register HDRMerge module {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 99}}, -- containers 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 + GUI.stack } ) From d88af9ffd9a102c68aab6ad9be765a8a4c406dc0 Mon Sep 17 00:00:00 2001 From: BzKevin <36381472+BzKevin@users.noreply.github.com> Date: Tue, 12 Mar 2019 11:20:04 -0400 Subject: [PATCH 08/11] Minor tweaks to last commit --- contrib/HDRMerge.lua | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/contrib/HDRMerge.lua b/contrib/HDRMerge.lua index f9409070..d8d8327a 100644 --- a/contrib/HDRMerge.lua +++ b/contrib/HDRMerge.lua @@ -144,7 +144,10 @@ local function PreCall(prog_tbl) --looks to see if this is the first call, if so prog.first_run = false end end - if not dt.preferences.read(mod, 'bin_exists', 'bool') then GUI.stack.active = 2 end + if not dt.preferences.read(mod, 'bin_exists', 'bool') then + GUI.stack.active = 2 + dt.print('please update you binary locatoin') + end end local function ExeUpdate(prog_tbl) @@ -159,7 +162,12 @@ local function ExeUpdate(prog_tbl) end prog.first_run = false end - if dt.preferences.read(mod, 'bin_exists', 'bool') then GUI.stack.active = 1 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 @@ -385,11 +393,12 @@ GUI.exes = dt.new_widget('box'){ GUI.exe_update } GUI.stack = dt.new_widget('stack'){ - active = 1, GUI.options, GUI.exes } -if not dt.preferences.read(mod, 'bin_exists', 'bool') then +if dt.preferences.read(mod, 'bin_exists', 'bool') then + GUI.stack.active = 1 +else GUI.stack.active = 2 end From 844e89a652b85cb9a262ef5264ab1c2b4b0fde34 Mon Sep 17 00:00:00 2001 From: BzKevin <36381472+BzKevin@users.noreply.github.com> Date: Tue, 12 Mar 2019 12:25:37 -0400 Subject: [PATCH 09/11] Use file chooser to set executable path preference previous commit failed to actually utilize the newly created file chooser to set the path preference --- contrib/HDRMerge.lua | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/contrib/HDRMerge.lua b/contrib/HDRMerge.lua index d8d8327a..57d19d40 100644 --- a/contrib/HDRMerge.lua +++ b/contrib/HDRMerge.lua @@ -81,9 +81,10 @@ local GUI = { --GUI Elements Table run = {}, stack = {}, options = {}, - exes = {}, - exe_chooser = {}, - exe_update = {}, + exes = { + HDRMerge = {}, + update = {}, + } } --Detect User Styles-- @@ -152,6 +153,7 @@ end local function ExeUpdate(prog_tbl) dt.preferences.write(mod, 'bin_exists', 'bool', true) + dt.preferences.write('executable_paths', prog.name, 'string', GUI.exes[prog.name].value) for _,prog in pairs(prog_tbl) do prog.bin = df.check_if_bin_exists(prog.name) if not prog.bin then @@ -163,11 +165,11 @@ local function ExeUpdate(prog_tbl) 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 + 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 @@ -364,12 +366,12 @@ GUI.run = dt.new_widget("button"){ tooltip ='run HDRMerge with the above specified settings', clicked_callback = function() main() end } -GUI.exe_chooser = dt.new_widget('file_chooser_button'){ +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.exe_update = dt.new_widget('button'){ +GUI.exes.update = dt.new_widget('button'){ label = 'update', tooltip ='update the binary path with current value', clicked_callback = function() ExeUpdate({HDRM}) end @@ -387,17 +389,17 @@ GUI.options = dt.new_widget('box'){ GUI.Target.add_tags, GUI.run } -GUI.exes = dt.new_widget('box'){ +local exes_box = dt.new_widget('box'){ orientation = 'vertical', - GUI.exe_chooser, - GUI.exe_update + GUI.exes.HDRMerge, + GUI.exes.update } GUI.stack = dt.new_widget('stack'){ GUI.options, - GUI.exes + exes_box } if dt.preferences.read(mod, 'bin_exists', 'bool') then - GUI.stack.active = 1 + GUI.stack.active = 1 else GUI.stack.active = 2 end From 4b3b1f7786a602177e620734dbf882714ad6e615 Mon Sep 17 00:00:00 2001 From: BzKevin <36381472+BzKevin@users.noreply.github.com> Date: Tue, 12 Mar 2019 12:42:37 -0400 Subject: [PATCH 10/11] Fix bug when updating exe preference Move the preference.write() call inside the for loop --- contrib/HDRMerge.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/HDRMerge.lua b/contrib/HDRMerge.lua index 57d19d40..6b45781f 100644 --- a/contrib/HDRMerge.lua +++ b/contrib/HDRMerge.lua @@ -153,8 +153,8 @@ end local function ExeUpdate(prog_tbl) dt.preferences.write(mod, 'bin_exists', 'bool', true) - dt.preferences.write('executable_paths', prog.name, 'string', GUI.exes[prog.name].value) 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 From 7ffdf1631ce597d2185927bc386728829a5d5f4b Mon Sep 17 00:00:00 2001 From: BzKevin <36381472+BzKevin@users.noreply.github.com> Date: Fri, 22 Mar 2019 09:05:11 -0400 Subject: [PATCH 11/11] Make text translatable --- contrib/HDRMerge.lua | 111 +++++++++++++++++++++++-------------------- 1 file changed, 59 insertions(+), 52 deletions(-) diff --git a/contrib/HDRMerge.lua b/contrib/HDRMerge.lua index 6b45781f..ad7dd3a8 100644 --- a/contrib/HDRMerge.lua +++ b/contrib/HDRMerge.lua @@ -17,14 +17,14 @@ ]] --[[About this Plugin -This plugin adds the module "HDRMerge" to darktable's lighttable view +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. + 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 @@ -44,13 +44,20 @@ 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 df = require "lib/dtutils.file" -local dsys = require "lib/dtutils.system" +local dt = require 'darktable' +local df = require 'lib/dtutils.file' +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 +-- 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 function _(msgid) + return gettext.dgettext('HDRMerge', msgid) +end + local temp local HDRM = { --HDRMerge Program Table name = 'HDRMerge', @@ -89,9 +96,9 @@ local GUI = { --GUI Elements Table --Detect User Styles-- local styles = dt.styles -local styles_count = 1 -- "none" = 1 +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) @@ -114,10 +121,10 @@ local function GetFileName(full_path) --Parses a full path (path/filename_identi 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*") + 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 @@ -147,7 +154,7 @@ local function PreCall(prog_tbl) --looks to see if this is the first call, if so end if not dt.preferences.read(mod, 'bin_exists', 'bool') then GUI.stack.active = 2 - dt.print('please update you binary locatoin') + dt.print(_('please update you binary locatoin')) end end @@ -166,9 +173,9 @@ local function ExeUpdate(prog_tbl) end if dt.preferences.read(mod, 'bin_exists', 'bool') then GUI.stack.active = 1 - dt.print('update successful') + dt.print(_('update successful')) else - dt.print('update unsuccessful, please try again') + dt.print(_('update unsuccessful, please try again')) end end @@ -182,13 +189,13 @@ 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') + 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') + dt.print(_('not enough images selected, select at least 2 images to merge')) return end @@ -203,7 +210,7 @@ local function main() 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).." " + 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) @@ -249,23 +256,23 @@ local function main() dt.tags.attach(tag, imported) end end - dt.print('HDRMerge completed successfully') + dt.print(_('HDRMerge completed successfully')) else - dt.print_error('HDRMerge failed') - dt.print('HDRMerge failed') + dt.print_error(_('HDRMerge failed')) + dt.print(_('HDRMerge failed')) end 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', + label = _('bits per sample'), + tooltip =_('number of bits per sample in the output image'), selected = temp, '16','24','32', changed_callback = function(self) @@ -281,10 +288,10 @@ GUI.HDR.bps = dt.new_widget('combobox'){ 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', + label = _('embedded preview size'), + tooltip =_('size of the embedded preview in output image'), selected = temp, - 'none','half','full', + _('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) @@ -296,9 +303,9 @@ GUI.HDR.size = dt.new_widget('combobox'){ end } GUI.HDR.batch = dt.new_widget('check_button'){ - label = 'batch mode', + label = _('batch mode'), value = dt.preferences.read(mod, 'active_batch', 'bool'), - tooltip = 'enable batch mode operation \nNOTE: resultant files will NOT be auto-imported', + 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 @@ -308,8 +315,8 @@ GUI.HDR.batch = dt.new_widget('check_button'){ 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', + label = _('batch gap [sec.]'), + tooltip = _('gap, in seconds, between batch mode groups'), soft_min = 1, soft_max = 30, hard_min = 1, @@ -323,13 +330,13 @@ GUI.HDR.gap = dt.new_widget('slider'){ 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", + label = _('apply style on import'), + tooltip = _('Apply selected style on auto-import to newly created image'), selected = 1, - "none", + _('none'), changed_callback = function(self) dt.preferences.write(mod, 'active_style', 'string', self.value) dt.preferences.write(mod, 'active_style_ind', 'integer', self.selected) @@ -347,33 +354,33 @@ 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', + label = _('copy tags'), value = dt.preferences.read(mod, 'active_copy_tags', 'bool'), - tooltip = 'copy tags from first source image', + 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", +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, seperated by commas'), editable = true } -GUI.run = dt.new_widget("button"){ - label = 'merge', - tooltip ='run HDRMerge with the above specified settings', +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", + 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', + label = _('update'), + tooltip =_('update the binary path with current value'), clicked_callback = function() ExeUpdate({HDRM}) end } GUI.options = dt.new_widget('box'){ @@ -399,19 +406,19 @@ GUI.stack = dt.new_widget('stack'){ exes_box } if dt.preferences.read(mod, 'bin_exists', 'bool') then - GUI.stack.active = 1 + GUI.stack.active = 1 else GUI.stack.active = 2 end dt.register_lib( -- register HDRMerge module - "HDRMerge_Lib", -- Module name - "HDRMerge", -- name + '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", + {[dt.gui.views.lighttable] = {'DT_UI_CONTAINER_PANEL_RIGHT_CENTER', 99}}, -- containers + dt.new_widget('box'){ + orientation = 'vertical', GUI.stack } )