Merge branch 'master' into script_manager_new_ui

This commit is contained in:
wpferguson
2024-06-07 19:31:25 -04:00
committed by GitHub
77 changed files with 4036 additions and 2134 deletions

View File

@@ -1,219 +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 <http://www.gnu.org/licenses/>.
]]
--[[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
-- Tell gettext where to find the .mo file translating messages for a particular domain
gettext.bindtextdomain("AutoGrouper",dt.configuration.config_dir.."/lua/locale/")
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
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 <http://www.gnu.org/licenses/>.
]]
--[[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

View File

@@ -1,254 +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 <http://www.gnu.org/licenses/>.
]]
--[[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
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
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)
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 <http://www.gnu.org/licenses/>.
]]
--[[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

View File

@@ -1,479 +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 <http://www.gnu.org/licenses/>.
]]
--[[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.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'}
}
}
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 <http://www.gnu.org/licenses/>.
]]
--[[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

View File

@@ -52,10 +52,25 @@ local du = require "lib/dtutils"
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
-- return data structure for script_manager
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
@@ -68,7 +83,7 @@ local ltt = {}
ltt.module_installed = false
ltt.event_registered = false
local LIB_ID = "LabelsToTags"
local LIB_ID = _("LabelsToTags")
-- Helper functions: BEGIN
@@ -109,23 +124,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 +155,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 +185,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)

View File

@@ -1,238 +1,263 @@
--[[
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 <http://www.gnu.org/licenses/>.
]]
--[[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
--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
-- 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)
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 <http://www.gnu.org/licenses/>.
]]
--[[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 = "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)
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)
elseif act_os == "macos" then
call_list_of_files_osx(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

View File

@@ -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 <marco.carrarini@gmail.com>",
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,13 +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.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")
@@ -137,7 +146,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)

View File

@@ -39,13 +39,28 @@ 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")
local gettext = darktable.gettext.gettext
darktable.gettext.bindtextdomain("autostyle", darktable.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 = "autostyle",
purpose = _("automatically apply a style based on image EXIF tag"),
author = "Marc Cousin <cousinmarc@gmail.com>",
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
@@ -54,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'))
@@ -92,19 +107,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 +133,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 +142,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 +169,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 +179,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)

View File

@@ -36,28 +36,34 @@ USAGE
local dt = require "darktable"
local du = require "lib/dtutils"
local gettext = dt.gettext
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)
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 <wpferguson@gmail.com>",
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
-- 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 = {}
@@ -121,7 +127,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
@@ -161,7 +167,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

View File

@@ -39,29 +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 <wpferguson@gmail.com>",
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
-- 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)
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
@@ -81,13 +86,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

View File

@@ -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")
@@ -52,13 +53,12 @@ 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
local gettext = dt.gettext.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/")
dt.gettext.bindtextdomain("color_profile_manager", dt.configuration.config_dir .."/lua/locale/")
local function _(msgid)
return gettext.dgettext("color_profile_manager", msgid)
return gettext(msgid)
end
-- - - - - - - - - - - - - - - - - - - - - - - -
@@ -107,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)
@@ -119,13 +119,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
@@ -364,6 +364,13 @@ end
local script_data = {}
script_data.metadata = {
name = "color_profile_manager",
purpose = _("manage external darktable color profiles"),
author = "Bill Ferguson <wpferguson@gmail.com>",
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"

View File

@@ -40,26 +40,32 @@ 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")
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
-- 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)
end
local cadt = {}
cadt.module_installed = false
cadt.event_registered = false
@@ -99,7 +105,7 @@ local function mcopy_tags()
end
end
dt.print(_('Image tags copied ...'))
dt.print(_('image tags copied ...'))
--create UI tag list
local taglist = ""
@@ -121,7 +127,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
@@ -145,7 +151,7 @@ local function attach_tags()
end
end
end
dt.print(_('Tags attached ...'))
dt.print(_('tags attached ...'))
end
local function detach_tags()
@@ -161,13 +167,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()

View File

@@ -37,10 +37,25 @@ local du = require "lib/dtutils"
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
-- return data structure for script_manager
local script_data = {}
script_data.metadata = {
name = "cr2hdr",
purpose = _("process Magic Lantern dual ISO images"),
author = "Till Theato <theato@ttill.de>",
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
@@ -87,7 +102,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 +113,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 +137,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

View File

@@ -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 <wpferguson@gmail.com>
@@ -54,30 +54,36 @@ local MODULE = "cycle_group_leader"
du.check_min_api_version("7.0.0", MODULE)
-- - - - - - - - - - - - - - - - - - - - - - - - - -
-- I 1 8 N
-- - - - - - - - - - - - - - - - - - - - - - - - - -
local gettext = dt.gettext.gettext
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 <wpferguson@gmail.com>",
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
-- - - - - - - - - - - - - - - - - - - - - - - - - -
-- 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
-- - - - - - - - - - - - - - - - - - - - - - - -
@@ -100,7 +106,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
@@ -147,7 +153,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

314
contrib/dbmaint.lua Normal file
View File

@@ -0,0 +1,314 @@
--[[
dbmaint.lua - perform database maintenance
Copyright (C) 2024 Bill Ferguson <wpferguson.com>.
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 <http://www.gnu.org/licenses/>.
]]
--[[
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 <wpferguson.com>
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 <const> = "dbmaint"
local DEFAULT_LOG_LEVEL <const> = log.error
local PS <const> = 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 <wpferguson.com>",
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

View File

@@ -67,22 +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.bindtextdomain('enfuseAdvanced',dt.configuration.config_dir..'/lua/locale/')
local function _(msgid)
return gettext.dgettext('enfuseAdvanced', msgid)
end
-- INITS --
local AIS = {
name = 'align_image_stack',
@@ -260,7 +269,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 +386,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 +402,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 +437,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 +465,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 +492,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
@@ -729,7 +738,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 +891,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 +925,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 +947,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')

View File

@@ -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.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")
local eL = {}
@@ -64,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 = _("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
}
@@ -106,9 +113,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
@@ -127,9 +134,9 @@ 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"))
dt.print(_("done exporting haldCLUTs"))
job.valid = false
identity:reset()
end

View File

@@ -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,13 +110,6 @@ ee.event_registered = false
ee.widgets = {}
-- 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
-- maximum number of external programs, can be increased to necessity
local MAX_EDITORS = 9
@@ -156,7 +165,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 +232,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 +335,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 +387,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 +485,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,
_("select executable for external editor") , _("(None)"))
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 +500,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

View File

@@ -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
@@ -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,13 +82,6 @@ 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)
end
local function build_image_table(images)
local image_table = {}
local file_extension = ""
@@ -135,7 +141,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
@@ -205,7 +211,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
@@ -257,7 +263,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)
@@ -265,9 +271,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
@@ -399,7 +405,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 +488,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)

View File

@@ -60,13 +60,28 @@ 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")
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 <dant@pnym.net>",
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
@@ -91,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

View File

@@ -26,26 +26,37 @@ Dependencies:
local dt = require "darktable"
local du = require "lib/dtutils"
local df = require "lib/dtutils.file"
local gettext = dt.gettext
local dtsys = require "lib/dtutils.system"
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 <ben.mendis@gmail.com>",
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.dgettext("fujifilm_ratings", msgid)
end
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
@@ -53,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)
local output = io.popen(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(_("Using JPEG Rating: ") .. tostring(jpeg_result))
dt.print_log("using JPEG rating: " .. jpeg_result)
return
end
command = "exiftool -Rating " .. RAF_filename
dt.print_error(command)
output = io.popen(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(_("Using RAF Rating: ") .. tostring(raf_result))
dt.print_log("using RAF rating: " .. raf_result)
end
end

View File

@@ -35,26 +35,33 @@ USAGE
local dt = require "darktable"
local du = require "lib/dtutils"
local df = require "lib/dtutils.file"
local gettext = dt.gettext
local dtsys = require "lib/dtutils.system"
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
-- 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)
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
@@ -80,7 +87,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)
@@ -309,22 +316,22 @@ 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")
local handle = dtsys.io_popen("xdg-user-dir DESKTOP")
local result = handle:read()
handle:close()
if (result == nil) then
@@ -333,8 +340,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

View File

@@ -28,26 +28,33 @@ require "geoToolbox"
local dt = require "darktable"
local du = require "lib/dtutils"
local df = require "lib/dtutils.file"
local gettext = dt.gettext
local dtsys = require "lib/dtutils.system"
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
-- 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)
end
local gT = {}
gT.module_installed = false
@@ -56,7 +63,7 @@ gT.event_registered = false
-- <GUI>
local labelDistance = dt.new_widget("label")
labelDistance.label = _("Distance:")
labelDistance.label = _("distance:")
local label_copy_gps_lat = dt.new_widget("check_button")
{
@@ -300,9 +307,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
@@ -405,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()
@@ -493,7 +500,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()
@@ -516,12 +523,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;
@@ -582,7 +589,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
@@ -612,14 +619,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
@@ -642,20 +649,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,
@@ -664,7 +671,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,--------------------------------------------------------
@@ -694,14 +701,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,--------------------------------------------------------
@@ -711,7 +718,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
@@ -744,14 +751,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

View File

@@ -69,27 +69,33 @@ 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")
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 <wpferguson@gmail.com>",
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
-- 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)
end
local function group_if_not_member(img, new_img)
local image_table = img:get_group_members()
local is_member = false
@@ -109,7 +115,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
@@ -119,7 +125,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
@@ -142,7 +148,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
@@ -213,7 +219,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

View File

@@ -29,22 +29,28 @@ 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
-- 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
local gpx = {}
gpx.module_installed = false
gpx.event_registered = false
@@ -132,11 +138,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

View File

@@ -32,17 +32,30 @@ 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/")
dt.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
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)
@@ -75,4 +88,12 @@ end,
function()
return dt.new_widget("label"){label = _("harmonic armature"), halign = "start"}
end
)
)
local function destroy()
-- nothing to destroy
end
script_data.destroy = destroy
return script_data

View File

@@ -58,30 +58,36 @@ local MODULE = "hif_group_leader"
du.check_min_api_version("7.0.0", MODULE)
-- - - - - - - - - - - - - - - - - - - - - - - - - -
-- I 1 8 N
-- - - - - - - - - - - - - - - - - - - - - - - - - -
local gettext = dt.gettext.gettext
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 <wpferguson@gmail.com>",
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
-- - - - - - - - - - - - - - - - - - - - - - - - - -
-- 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
@@ -182,7 +188,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",
@@ -190,7 +196,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

View File

@@ -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'
@@ -56,22 +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
-- 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)
end
local function user_preference_changed(widget)
user_prefer_gui = widget.value
dt.preferences.write(namespace, user_pref_str, "bool", user_prefer_gui)
@@ -201,7 +207,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 +233,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

View File

@@ -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
@@ -73,22 +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 <wpferguson@gmail.com>",
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
-- 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)
end
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-- GUI definitions
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -259,7 +265,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
@@ -342,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
@@ -452,7 +458,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 +502,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 +526,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 +546,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
@@ -554,7 +560,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
@@ -568,7 +574,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
@@ -580,7 +586,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
@@ -592,7 +598,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)

View File

@@ -107,7 +107,8 @@ 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 dtsys = require "lib/dtutils.system"
local gettext = dt.gettext.gettext
local img_time = {}
img_time.module_installed = false
@@ -115,22 +116,29 @@ 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 <wpferguson@gmail.com>",
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
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)
end
local PS = dt.configuration.runnin_os == "windows" and "\\" or "/"
local ERROR = -1
@@ -175,7 +183,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
@@ -218,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
@@ -236,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
@@ -249,7 +257,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 $s"), image.filename))
datetime = ERROR
end
return datetime
@@ -257,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
@@ -266,7 +274,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 %s"), image.filename))
datetime = ERROR
end
return datetime
@@ -314,7 +322,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 +438,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},
@@ -457,13 +465,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)

View File

@@ -58,30 +58,36 @@ local MODULE = "jpg_group_leader"
du.check_min_api_version("7.0.0", MODULE)
-- - - - - - - - - - - - - - - - - - - - - - - - - -
-- I 1 8 N
-- - - - - - - - - - - - - - - - - - - - - - - - - -
local gettext = dt.gettext.gettext
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 <wpferguson@gmail.com>",
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
-- - - - - - - - - - - - - - - - - - - - - - - - - -
-- 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
@@ -182,7 +188,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",
@@ -190,7 +196,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

View File

@@ -39,30 +39,36 @@ 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 "/"
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
-- 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)
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
@@ -320,14 +326,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
@@ -337,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
@@ -346,23 +352,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 )
@@ -370,16 +376,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

View File

@@ -37,17 +37,30 @@ 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/")
dt.gettext.bindtextdomain("passport_guide", dt.configuration.config_dir .."/lua/locale/")
local function _(msgid)
return gettext.dgettext("passport_guide", 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)
@@ -91,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

View File

@@ -0,0 +1,127 @@
--[[
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 <http://www.gnu.org/licenses/>.
]]
--[[
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
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)
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
)
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

View File

@@ -42,17 +42,16 @@ local dt = require "darktable"
local du = require "lib/dtutils"
local df = require "lib/dtutils.file"
local gettext = dt.gettext
local gettext = dt.gettext.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/")
dt.gettext.bindtextdomain("pdf_slideshow", dt.configuration.config_dir .."/lua/locale/")
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
@@ -62,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
@@ -231,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
@@ -241,7 +247,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

View File

@@ -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,9 +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.bindtextdomain(MODULE_NAME,
dt.configuration.config_dir .. PS .. "lua" .. PS .. "locale" .. PS)
local exporter = dt.new_format("jpeg")
exporter.quality = 80
@@ -66,10 +77,6 @@ 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
@@ -178,7 +185,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()
@@ -235,7 +242,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]
@@ -247,7 +254,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
@@ -313,11 +320,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,9 +435,9 @@ 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.")
GUI.warning_label.label = _("select an image, click \"get tags\" and get \nsuggestions for tags.")
end
GUI.pagination = dt.new_widget("box") {
@@ -473,9 +480,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",

View File

@@ -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,15 +77,6 @@ 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 function _(msgid)
return gettext.dgettext("quicktag", msgid)
end
-- maximum length of button labels
dt.preferences.register("quickTag",
"labellength",

View File

@@ -44,10 +44,25 @@ local du = require "lib/dtutils"
-- added version check
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
-- return data structure for script_manager
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
@@ -62,9 +77,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 +96,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

View File

@@ -36,10 +36,25 @@ 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 = darktable.gettext.gettext
darktable.gettext.bindtextdomain("rename-tags", darktable.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 = "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
@@ -50,8 +65,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 +77,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 +91,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 +119,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 +130,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 +146,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 +161,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

View File

@@ -46,13 +46,12 @@ local df = require "lib/dtutils.file"
du.check_min_api_version("7.0.0", "rename_images")
local gettext = dt.gettext
local gettext = dt.gettext.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/")
dt.gettext.bindtextdomain("rename_images", dt.configuration.config_dir .."/lua/locale/")
local function _(msgid)
return gettext.dgettext("rename_images", msgid)
return gettext(msgid)
end
-- namespace variable
@@ -72,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 <wpferguson@gmail.com>",
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
@@ -86,7 +92,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 +164,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 +216,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 +256,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"))

View File

@@ -29,11 +29,12 @@ 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
dt.gettext.bindtextdomain("select_non_existing", dt.configuration.config_dir .."/lua/locale/")
local function _(msgid)
return gettext.dgettext(MODULE, msgid)
return gettext(msgid)
end
local function stop_job(job)
@@ -73,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

View File

@@ -20,26 +20,32 @@ 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")
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
-- 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)
end
local function stop_job(job)
job.valid = false
end

View File

@@ -27,26 +27,32 @@ 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")
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
-- 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)
end
local function playSlideshowMusic(_, old_view, new_view)
local filename, playMusic
@@ -54,7 +60,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 +76,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
@@ -83,12 +89,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",

View File

@@ -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
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
@@ -151,7 +158,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
@@ -268,17 +275,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 +294,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

View File

@@ -37,14 +37,27 @@ 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")
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
@@ -53,12 +66,6 @@ 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)
end
---- DECLARATIONS
@@ -294,7 +301,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),
@@ -375,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(_("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 +472,7 @@ end
dt.register_storage(
"module_video_ffmpeg",
_(MODULE_NAME),
_("video ffmpeg"),
show_status,
finalize_export,
nil,