Merge branch 'master' of github.com:chrisaga/lua-scripts
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
## Changes from most recent to oldest
|
||||
**31 Aug 2021 - wpferguson - remove styles hiding from AutoGrouper.lua**
|
||||
**02 Jul 2021 - wpferguson - merged API-7.0.0-dev branch to master**
|
||||
* API-7.0.0 is darktable 3.6
|
||||
* breaking changes
|
||||
|
||||
@@ -41,9 +41,6 @@ local du = require "lib/dtutils"
|
||||
|
||||
du.check_min_api_version("7.0.0", "AutoGrouper")
|
||||
|
||||
dt.print_log("hiding styles")
|
||||
dt.gui.libs["styles"].visible = false
|
||||
|
||||
local MOD = 'autogrouper'
|
||||
|
||||
-- return data structure for script_manager
|
||||
@@ -218,4 +215,4 @@ script_data.destroy_method = "hide"
|
||||
script_data.restart = restart
|
||||
script_data.show = restart
|
||||
|
||||
return script_data
|
||||
return script_data
|
||||
|
||||
372
contrib/color_profile_manager.lua
Normal file
372
contrib/color_profile_manager.lua
Normal file
@@ -0,0 +1,372 @@
|
||||
--[[
|
||||
|
||||
color_profile_manager.lua - manage external darktable color profiles
|
||||
|
||||
Copyright (C) 2021 Bill Ferguson <wpferguson@gmail.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/>.
|
||||
]]
|
||||
--[[
|
||||
color_profile_manager - manage external darktable color profiles
|
||||
|
||||
This script provides a tool to manage input and output external color
|
||||
profiles used by darktable. Color profiles can be added or removed
|
||||
to/from the correct directories so that darktable can find and use
|
||||
them.
|
||||
|
||||
ADDITIONAL SOFTWARE NEEDED FOR THIS SCRIPT
|
||||
* None
|
||||
|
||||
USAGE
|
||||
* require this script from your main lua file
|
||||
* select the input or output set of color profiles
|
||||
* a list of profiles is displayed. Click the check box beside the
|
||||
profile name to select it for removal. Click the "remove profile"
|
||||
button to remove the profile.
|
||||
* use the file selector to select a color profile to add to the currently
|
||||
selected set (input or output)
|
||||
* click the "add profile" button to add the profile to the selected set
|
||||
|
||||
BUGS, COMMENTS, SUGGESTIONS
|
||||
* Send to Bill Ferguson, wpferguson@gmail.com or raise an issue on
|
||||
https://github.com/dakrtable-org/lua-scripts
|
||||
]]
|
||||
local dt = require "darktable"
|
||||
local du = require "lib/dtutils"
|
||||
local df = require "lib/dtutils.file"
|
||||
|
||||
du.check_min_api_version("7.0.0", "color_profile_manager")
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- L O C A L I Z A T I O N
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
local gettext = dt.gettext
|
||||
|
||||
-- Tell gettext where to find the .mo file translating messages for a particular domain
|
||||
gettext.bindtextdomain("color_profile_manager", dt.configuration.config_dir .. "/lua/locale/")
|
||||
|
||||
local function _(msgid)
|
||||
return gettext.dgettext("color_profile_manager", msgid)
|
||||
end
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- C O N S T A N T S
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
local MODULE_NAME = "color_profile_manager"
|
||||
local PS = dt.configuration.running_os == "windows" and "\\" or "/"
|
||||
local CS = dt.configuration.running_os == "windows" and "&" or ";"
|
||||
local DIR_CMD = dt.configuration.running_os == "windows" and "dir /b" or "ls"
|
||||
local COLOR_IN_DIR = dt.configuration.config_dir .. PS .. "color" .. PS .. "in"
|
||||
local COLOR_OUT_DIR = dt.configuration.config_dir .. PS .. "color" .. PS .. "out"
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- N A M E S P A C E
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
local cpm = {}
|
||||
cpm.widgets = {}
|
||||
cpm.widgets.profile_box = dt.new_widget("box"){
|
||||
orientation = "vertical",
|
||||
}
|
||||
cpm.module_installed = false
|
||||
cpm.event_registered = false
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- F U N C T I O N S
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
local function check_for_directories()
|
||||
if not df.test_file(COLOR_IN_DIR, "d") then
|
||||
dt.print_log("didn't find " .. COLOR_IN_DIR)
|
||||
return false
|
||||
elseif not df.test_file(COLOR_OUT_DIR, "d") then
|
||||
dt.print_log("didn't find " .. COLOR_OUT_DIR)
|
||||
return false
|
||||
else
|
||||
dt.print_log("both directories exist")
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
local function add_directories()
|
||||
df.mkdir(COLOR_IN_DIR)
|
||||
df.mkdir(COLOR_OUT_DIR)
|
||||
end
|
||||
|
||||
local function list_profiles(dir)
|
||||
local files = {}
|
||||
local p = io.popen(DIR_CMD .. " " .. dir)
|
||||
if p then
|
||||
for line in p:lines() do
|
||||
table.insert(files, line)
|
||||
end
|
||||
end
|
||||
p:close()
|
||||
return files
|
||||
end
|
||||
|
||||
local function add_profile(file, dir)
|
||||
df.file_copy(file, dir)
|
||||
dt.print(_("added color profile " .. file .. " to " .. dir))
|
||||
dt.print_log("color profile " .. file .. " added to " .. dir)
|
||||
end
|
||||
|
||||
local function remove_profile(file, dir)
|
||||
os.remove(dir .. PS .. file)
|
||||
dt.print(_("removed color profile " .. file .. " from " .. dir))
|
||||
dt.print_log("color profile " .. file .. " removed from " .. dir)
|
||||
end
|
||||
|
||||
local function clear_profile_box()
|
||||
for i = #cpm.widgets.profile_box, 1, -1 do
|
||||
cpm.widgets.profile_box[i] = nil
|
||||
end
|
||||
end
|
||||
|
||||
local function add_profile_callback()
|
||||
local profile_dir = COLOR_IN_DIR
|
||||
if cpm.widgets.profile_set.selected == 2 then
|
||||
profile_dir = COLOR_OUT_DIR
|
||||
end
|
||||
|
||||
local new_profile = cpm.widgets.profile_selector.value
|
||||
if string.lower(df.get_filetype(new_profile)) ~= "icm" and string.lower(df.get_filetype(new_profile)) ~= "icc" then
|
||||
dt.print(_("ERROR: color profile must be an icc or icm file"))
|
||||
dt.print_error(new_profile .. " selected and isn't an icc or icm file")
|
||||
return
|
||||
end
|
||||
|
||||
-- set selector value to directory that new profile came from
|
||||
-- in case there are more
|
||||
cpm.widgets.profile_selector.value = df.get_path(cpm.widgets.profile_selector.value)
|
||||
add_profile(new_profile, profile_dir)
|
||||
local files = list_profiles(profile_dir)
|
||||
local widgets = {}
|
||||
|
||||
local profile_ptr = 1
|
||||
for i, file in ipairs(files) do
|
||||
if #cpm.widgets.profile_box == 0 or cpm.widgets.profile_box[profile_ptr].label ~= file then
|
||||
table.insert(widgets, dt.new_widget("check_button"){value = false, label = file})
|
||||
else
|
||||
table.insert(widgets, cpm.widgets.profile_box[profile_ptr])
|
||||
profile_ptr = profile_ptr + 1
|
||||
if profile_ptr > #cpm.widgets.profile_box then
|
||||
profile_ptr = #cpm.widgets.profile_box
|
||||
end
|
||||
end
|
||||
end
|
||||
clear_profile_box()
|
||||
for _, widget in ipairs(widgets) do
|
||||
table.insert(cpm.widgets.profile_box, widget)
|
||||
end
|
||||
if not cpm.widgets.remove_box.visible then
|
||||
cpm.widgets.remove_box.visible = true
|
||||
end
|
||||
end
|
||||
|
||||
local function remove_profile_callback()
|
||||
local widgets_to_keep = {}
|
||||
local profile_dir = COLOR_IN_DIR
|
||||
if cpm.widgets.profile_set.selected == 2 then
|
||||
profile_dir = COLOR_OUT_DIR
|
||||
end
|
||||
|
||||
for _, widget in ipairs(cpm.widgets.profile_box) do
|
||||
if widget.value == true then
|
||||
remove_profile(widget.label, profile_dir)
|
||||
else
|
||||
table.insert(widgets_to_keep, widget)
|
||||
end
|
||||
end
|
||||
clear_profile_box()
|
||||
for _, widget in ipairs(widgets_to_keep) do
|
||||
table.insert(cpm.widgets.profile_box, widget)
|
||||
end
|
||||
if #cpm.widgets.profile_box == 0 then
|
||||
cpm.widgets.remove_box.visible = false
|
||||
else
|
||||
cpm.widgets.remove_box.visible = true
|
||||
end
|
||||
end
|
||||
|
||||
local function list_profile_callback(choice)
|
||||
local list_dir = COLOR_IN_DIR
|
||||
if choice == 2 then
|
||||
list_dir = COLOR_OUT_DIR
|
||||
end
|
||||
|
||||
local files = list_profiles(list_dir)
|
||||
|
||||
if #files == 0 then
|
||||
cpm.widgets.remove_box.visible = false
|
||||
else
|
||||
cpm.widgets.remove_box.visible = true
|
||||
end
|
||||
|
||||
clear_profile_box()
|
||||
|
||||
for i, file in ipairs(files) do
|
||||
cpm.widgets.profile_box[i] = dt.new_widget("check_button"){value = false, label = file}
|
||||
end
|
||||
end
|
||||
|
||||
local function install_module()
|
||||
if not cpm.module_installed then
|
||||
dt.register_lib(
|
||||
MODULE_NAME, -- Module name
|
||||
_("color profile manager"), -- Visible name
|
||||
true, -- expandable
|
||||
false, -- resetable
|
||||
{[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_LEFT_CENTER", 0}}, -- containers
|
||||
cpm.widgets.main_widget,
|
||||
nil,-- view_enter
|
||||
nil -- view_leave
|
||||
)
|
||||
cpm.module_installed = true
|
||||
dt.control.sleep(500)
|
||||
if not cpm.initialized then
|
||||
cpm.widgets.profile_set.visible = false
|
||||
cpm.widgets.add_box.visible = false
|
||||
cpm.widgets.remove_box.visible = false
|
||||
else
|
||||
cpm.widgets.profile_set.selected = 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function destroy()
|
||||
dt.gui.libs[MODULE_NAME].visible = false
|
||||
return
|
||||
end
|
||||
|
||||
local function restart()
|
||||
dt.gui.libs[MODULE_NAME].visible = true
|
||||
return
|
||||
end
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- W I D G E T S
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
cpm.initialized = check_for_directories()
|
||||
dt.print_log("cpm.initialized is " .. tostring(cpm.initialized))
|
||||
|
||||
if not cpm.initialized then
|
||||
dt.print_log("creating init_box")
|
||||
cpm.widgets.init_box = dt.new_widget("box"){
|
||||
orientation = "vertical",
|
||||
dt.new_widget("button"){
|
||||
label = _("initialize color profiles"),
|
||||
tooltip = _("create the directory structure to contain the color profiles"),
|
||||
clicked_callback = function(this)
|
||||
add_directories()
|
||||
cpm.initialized = true
|
||||
cpm.widgets.profile_set.visible = true
|
||||
cpm.widgets.add_box.visible = true
|
||||
cpm.widgets.remove_box.visible = false
|
||||
cpm.widgets.init_box.visible = false
|
||||
cpm.widgets.profile_set.selected = 1
|
||||
end
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
cpm.widgets.profile_set = dt.new_widget("combobox"){
|
||||
label = _("select profile set"),
|
||||
tooltip = _("select input or output profiles"),
|
||||
visible = cpm.initialized and false or true,
|
||||
changed_callback = function(this)
|
||||
if cpm.initialized then
|
||||
list_profile_callback(this.selected)
|
||||
end
|
||||
end,
|
||||
_("input"), _("output"),
|
||||
}
|
||||
|
||||
cpm.widgets.profile_selector = dt.new_widget("file_chooser_button"){
|
||||
title = _("select color profile to add"),
|
||||
tooltip = _("select the .icc or .icm file to add"),
|
||||
is_directory = false
|
||||
}
|
||||
|
||||
cpm.widgets.add_box = dt.new_widget("box"){
|
||||
orientation = "vertical",
|
||||
visible = cpm.initialized and true or false,
|
||||
dt.new_widget("section_label"){label = _("add profile")},
|
||||
cpm.widgets.profile_selector,
|
||||
dt.new_widget("button"){
|
||||
label = _("add selected color profile"),
|
||||
tooltip = _("add selected file to profiles"),
|
||||
clicked_callback = function(this)
|
||||
add_profile_callback()
|
||||
end
|
||||
}
|
||||
}
|
||||
|
||||
cpm.widgets.remove_box = dt.new_widget("box"){
|
||||
orientation = "vertical",
|
||||
visible = cpm.initialized and true or false,
|
||||
dt.new_widget("section_label"){label = _("remove profile")},
|
||||
cpm.widgets.profile_box,
|
||||
dt.new_widget("button"){
|
||||
label = _("remove selected profile(s)"),
|
||||
tooltip = _("remove the checked profile(s)"),
|
||||
clicked_callback = function(this)
|
||||
remove_profile_callback()
|
||||
end
|
||||
}
|
||||
}
|
||||
|
||||
local main_widgets = {}
|
||||
|
||||
if not cpm.initialized then
|
||||
table.insert(main_widgets, cpm.widgets.init_box)
|
||||
end
|
||||
table.insert(main_widgets, cpm.widgets.profile_set)
|
||||
table.insert(main_widgets, cpm.widgets.remove_box)
|
||||
table.insert(main_widgets, cpm.widgets.add_box)
|
||||
|
||||
cpm.widgets.main_widget = dt.new_widget("box"){
|
||||
orientation = "vertical",
|
||||
table.unpack(main_widgets)
|
||||
}
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- M A I N
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
if dt.gui.current_view().id == "lighttable" then
|
||||
install_module()
|
||||
else
|
||||
if not cpm.event_registered then
|
||||
dt.register_event(
|
||||
MODULE_NAME, "view-changed",
|
||||
function(event, old_view, new_view)
|
||||
if new_view.name == "lighttable" and old_view.name == "darkroom" then
|
||||
install_module()
|
||||
end
|
||||
end
|
||||
)
|
||||
cpm.event_registered = true
|
||||
end
|
||||
end
|
||||
|
||||
local script_data = {}
|
||||
|
||||
script_data.destroy = destroy
|
||||
script_data.restart = restart
|
||||
script_data.destroy_method = "hide"
|
||||
script_data.show = restart
|
||||
|
||||
return script_data
|
||||
78
contrib/harmonic_armature_guide.lua
Normal file
78
contrib/harmonic_armature_guide.lua
Normal file
@@ -0,0 +1,78 @@
|
||||
--[[
|
||||
harmonic artmature guide for darktable
|
||||
|
||||
copyright (c) 2021 Hubert Kowalski
|
||||
|
||||
darktable is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
darktable is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with darktable. If not, see <http://www.gnu.org/licenses/>.
|
||||
]]
|
||||
|
||||
--[[
|
||||
HARMONIC ARMATURE GUIDE
|
||||
Harmonic Armature (also known as 14 line armature)
|
||||
|
||||
INSTALLATION
|
||||
* copy this file in $CONFIGDIR/lua/contrib where CONFIGDIR is your darktable configuration directory
|
||||
* add the following line in the file $CONFIGDIR/luarc
|
||||
require "contrib/harmonic_armature_guide"
|
||||
|
||||
USAGE
|
||||
* when using guides, select "harmonic armature" as guide
|
||||
]]
|
||||
|
||||
local dt = require "darktable"
|
||||
local du = require "lib/dtutils"
|
||||
local gettext = dt.gettext
|
||||
|
||||
du.check_min_api_version("2.0.0", "harmonic_armature_guide")
|
||||
|
||||
-- Tell gettext where to find the .mo file translating messages for a particular domain
|
||||
gettext.bindtextdomain("harmonic_armature_guide",dt.configuration.config_dir.."/lua/locale/")
|
||||
|
||||
local function _(msgid)
|
||||
return gettext.dgettext("harmonic_armature_guide", msgid)
|
||||
end
|
||||
|
||||
dt.guides.register_guide("harmonic armature",
|
||||
-- draw
|
||||
function(cairo, x, y, width, height, zoom_scale)
|
||||
cairo:save()
|
||||
|
||||
cairo:translate(x, y)
|
||||
cairo:scale(width, height)
|
||||
|
||||
cairo:move_to(0,0)
|
||||
cairo:line_to(1, 0.5)
|
||||
cairo:line_to(0.5, 1)
|
||||
cairo:line_to(0,0)
|
||||
cairo:line_to(1, 1)
|
||||
cairo:line_to(0.5, 0)
|
||||
cairo:line_to(0, 0.5)
|
||||
cairo:line_to(1, 1)
|
||||
|
||||
cairo:move_to(1, 0)
|
||||
cairo:line_to(0, 0.5)
|
||||
cairo:line_to(0.5, 1)
|
||||
cairo:line_to(1, 0)
|
||||
cairo:line_to(0, 1)
|
||||
cairo:line_to(0.5, 0)
|
||||
cairo:line_to(1, 0.5)
|
||||
cairo:line_to(0, 1)
|
||||
|
||||
cairo:restore()
|
||||
end,
|
||||
-- gui
|
||||
function()
|
||||
return dt.new_widget("label"){label = _("harmonic armature"), halign = "start"}
|
||||
end
|
||||
)
|
||||
315
contrib/rename_images.lua
Normal file
315
contrib/rename_images.lua
Normal file
@@ -0,0 +1,315 @@
|
||||
--[[
|
||||
|
||||
rename.lua - rename image file(s)
|
||||
|
||||
Copyright (C) 2020, 2021 Bill Ferguson <wpferguson@gmail.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/>.
|
||||
]]
|
||||
--[[
|
||||
rename - rename an image file or files
|
||||
|
||||
This shortcut resets the GPS information to that contained within
|
||||
the image file. If no GPS info is in the image file, the GPS data
|
||||
is cleared.
|
||||
|
||||
USAGE
|
||||
* require this script from your luarc file or start it from script_manager
|
||||
* select an image or images
|
||||
* enter a renaming pattern
|
||||
* click the button to rename the files
|
||||
|
||||
BUGS, COMMENTS, SUGGESTIONS
|
||||
* Send to Bill Ferguson, wpferguson@gmail.com
|
||||
|
||||
CHANGES
|
||||
|
||||
TODO
|
||||
* Add pattern builder
|
||||
* Add new name preview
|
||||
]]
|
||||
|
||||
local dt = require "darktable"
|
||||
local du = require "lib/dtutils"
|
||||
local df = require "lib/dtutils.file"
|
||||
|
||||
du.check_min_api_version("7.0.0", "rename_images")
|
||||
|
||||
local gettext = dt.gettext
|
||||
|
||||
-- Tell gettext where to find the .mo file translating messages for a particular domain
|
||||
gettext.bindtextdomain("rename_images",dt.configuration.config_dir.."/lua/locale/")
|
||||
|
||||
local function _(msgid)
|
||||
return gettext.dgettext("rename_images", msgid)
|
||||
end
|
||||
|
||||
-- namespace variable
|
||||
local rename = {
|
||||
presets = {},
|
||||
substitutes = {},
|
||||
placeholders = {"ROLL_NAME","FILE_FOLDER","FILE_NAME","FILE_EXTENSION","ID","VERSION","SEQUENCE","YEAR","MONTH","DAY",
|
||||
"HOUR","MINUTE","SECOND","EXIF_YEAR","EXIF_MONTH","EXIF_DAY","EXIF_HOUR","EXIF_MINUTE","EXIF_SECOND",
|
||||
"STARS","LABELS","MAKER","MODEL","TITLE","CREATOR","PUBLISHER","RIGHTS","USERNAME","PICTURES_FOLDER",
|
||||
"HOME","DESKTOP","EXIF_ISO","EXIF_EXPOSURE","EXIF_EXPOSURE_BIAS","EXIF_APERTURE","EXIF_FOCUS_DISTANCE",
|
||||
"EXIF_FOCAL_LENGTH","LONGITUDE","LATITUDE","ELEVATION","LENS","DESCRIPTION","EXIF_CROP"},
|
||||
widgets = {},
|
||||
}
|
||||
rename.module_installed = false
|
||||
rename.event_registered = false
|
||||
|
||||
-- script_manager integration
|
||||
local script_data = {}
|
||||
|
||||
script_data.destroy = nil -- function to destory the script
|
||||
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil
|
||||
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
|
||||
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- C O N S T A N T S
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
local MODULE_NAME = "rename_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 DESKTOP = HOME .. PS .. "Desktop"
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- F U N C T I O N S
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
local function build_substitution_list(image, sequence, datetime, username, pic_folder, home, desktop)
|
||||
-- build the argument substitution list from each image
|
||||
-- local datetime = os.date("*t")
|
||||
local colorlabels = {}
|
||||
if image.red then table.insert(colorlabels, "red") end
|
||||
if image.yellow then table.insert(colorlabels, "yellow") end
|
||||
if image.green then table.insert(colorlabels, "green") end
|
||||
if image.blue then table.insert(colorlabels, "blue") end
|
||||
if image.purple then table.insert(colorlabels, "purple") end
|
||||
local labels = #colorlabels == 1 and colorlabels[1] or du.join(colorlabels, ",")
|
||||
local eyear,emon,eday,ehour,emin,esec = string.match(image.exif_datetime_taken, "(%d-):(%d-):(%d-) (%d-):(%d-):(%d-)$")
|
||||
local replacements = {image.film,image.path,df.get_filename(image.filename),string.upper(df.get_filetype(image.filename)),image.id,image.duplicate_index,
|
||||
sequence,datetime.year,string.format("%02d", datetime.month),string.format("%02d", datetime.day),string.format("%02d", datetime.hour),
|
||||
string.format("%02d", datetime.min),string.format("%02d", datetime.sec),eyear,emon,eday,ehour,emin,esec,image.rating,labels,
|
||||
image.exif_maker,image.exif_model,image.title,image.creator,image.publisher,image.rights,username,pic_folder,home,desktop,
|
||||
image.exif_iso,image.exif_exposure,image.exif_exposure_bias,image.exif_aperture,image.exif_focus_distance,image.exif_focal_length,
|
||||
image.longitude,image.latitude,image.elevation,image.exif_lens,image.description,image.exif_crop}
|
||||
|
||||
for i=1,#rename.placeholders,1 do rename.substitutes[rename.placeholders[i]] = replacements[i] end
|
||||
end
|
||||
|
||||
local function substitute_list(str)
|
||||
-- replace the substitution variables in a string
|
||||
for match in string.gmatch(str, "%$%(.-%)") do
|
||||
local var = string.match(match, "%$%((.-)%)")
|
||||
if rename.substitutes[var] then
|
||||
str = string.gsub(str, "%$%("..var.."%)", rename.substitutes[var])
|
||||
else
|
||||
dt.print_error(_("unrecognized variable " .. var))
|
||||
dt.print(_("unknown variable " .. var .. ", aborting..."))
|
||||
return -1
|
||||
end
|
||||
end
|
||||
return str
|
||||
end
|
||||
|
||||
local function clear_substitute_list()
|
||||
for i=1,#rename.placeholders,1 do rename.substitutes[rename.placeholders[i]] = nil end
|
||||
end
|
||||
|
||||
local function stop_job(job)
|
||||
job.valid = false
|
||||
end
|
||||
|
||||
local function install_module()
|
||||
if not rename.module_installed then
|
||||
dt.register_lib(
|
||||
MODULE_NAME,
|
||||
_("rename images"),
|
||||
true,
|
||||
true,
|
||||
{[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER",700}},
|
||||
dt.new_widget("box"){
|
||||
orientation = "vertical",
|
||||
rename.widgets.pattern,
|
||||
rename.widgets.button,
|
||||
},
|
||||
nil,
|
||||
nil
|
||||
)
|
||||
rename.module_installed = true
|
||||
end
|
||||
end
|
||||
|
||||
local function destroy()
|
||||
dt.gui.libs[MODULE_NAME].visible = false
|
||||
end
|
||||
|
||||
local function restart()
|
||||
dt.gui.libs[MODULE_NAME].visible = true
|
||||
end
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- M A I N
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
local function do_rename(images)
|
||||
if #images > 0 then
|
||||
local pattern = rename.widgets.pattern.text
|
||||
dt.preferences.write(MODULE_NAME, "pattern", "string", pattern)
|
||||
dt.print_log(_("pattern is " .. pattern))
|
||||
if string.len(pattern) > 0 then
|
||||
local datetime = os.date("*t")
|
||||
|
||||
local job = dt.gui.create_job(_("renaming images"), true, stop_job)
|
||||
for i, image in ipairs(images) do
|
||||
if job.valid then
|
||||
job.percent = i / #images
|
||||
build_substitution_list(image, i, datetime, USER, PICTURES, HOME, DESKTOP)
|
||||
local new_name = substitute_list(pattern)
|
||||
if new_name == -1 then
|
||||
dt.print(_("unable to do variable substitution, exiting..."))
|
||||
stop_job(job)
|
||||
return
|
||||
end
|
||||
clear_substitute_list()
|
||||
local args = {}
|
||||
local path = string.sub(df.get_path(new_name), 1, -2)
|
||||
if string.len(path) == 0 then
|
||||
path = image.path
|
||||
end
|
||||
local filename = df.get_filename(new_name)
|
||||
local filmname = image.path
|
||||
if path ~= image.path then
|
||||
if not df.check_if_file_exists(df.sanitize_filename(path)) then
|
||||
df.mkdir(df.sanitize_filename(path))
|
||||
end
|
||||
filmname = path
|
||||
end
|
||||
args[1] = dt.films.new(filmname)
|
||||
args[2] = image
|
||||
if filename ~= image.filename then
|
||||
args[3] = filename
|
||||
end
|
||||
dt.database.move_image(table.unpack(args))
|
||||
end
|
||||
end
|
||||
stop_job(job)
|
||||
local collect_rules = dt.gui.libs.collect.filter()
|
||||
dt.gui.libs.collect.filter(collect_rules)
|
||||
dt.print(_("renamed " .. #images .. " images"))
|
||||
else -- pattern length
|
||||
dt.print_error("no pattern supplied, returning...")
|
||||
dt.print(_("please enter the new name or pattern"))
|
||||
end
|
||||
else -- image count
|
||||
dt.print_error("no images selected, returning...")
|
||||
dt.print(_("please select some images and try again"))
|
||||
end
|
||||
end
|
||||
|
||||
local function reset_callback()
|
||||
rename.widgets.pattern.text = ""
|
||||
end
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- W I D G E T S
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
rename.widgets.pattern = dt.new_widget("entry"){
|
||||
tooltip = _("$(ROLL_NAME) - film roll name\n") ..
|
||||
_("$(FILE_FOLDER) - image file folder\n") ..
|
||||
_("$(FILE_NAME) - image file name\n") ..
|
||||
_("$(FILE_EXTENSION) - image file extension\n") ..
|
||||
_("$(ID) - image id\n") ..
|
||||
_("$(VERSION) - version number\n") ..
|
||||
_("$(SEQUENCE) - sequence number of selection\n") ..
|
||||
_("$(YEAR) - current year\n") ..
|
||||
_("$(MONTH) - current month\n") ..
|
||||
_("$(DAY) - current day\n") ..
|
||||
_("$(HOUR) - current hour\n") ..
|
||||
_("$(MINUTE) - current minute\n") ..
|
||||
_("$(SECOND) - current second\n") ..
|
||||
_("$(EXIF_YEAR) - EXIF year\n") ..
|
||||
_("$(EXIF_MONTH) - EXIF month\n") ..
|
||||
_("$(EXIF_DAY) - EXIF day\n") ..
|
||||
_("$(EXIF_HOUR) - EXIF hour\n") ..
|
||||
_("$(EXIF_MINUTE) - EXIF minute\n") ..
|
||||
_("$(EXIF_SECOND) - EXIF seconds\n") ..
|
||||
_("$(EXIF_ISO) - EXIF ISO\n") ..
|
||||
_("$(EXIF_EXPOSURE) - EXIF exposure\n") ..
|
||||
_("$(EXIF_EXPOSURE_BIAS) - EXIF exposure bias\n") ..
|
||||
_("$(EXIF_APERTURE) - EXIF aperture\n") ..
|
||||
_("$(EXIF_FOCAL_LENGTH) - EXIF focal length\n") ..
|
||||
_("$(EXIF_FOCUS_DISTANCE) - EXIF focus distance\n") ..
|
||||
_("$(EXIF_CROP) - EXIF crop\n") ..
|
||||
_("$(LONGITUDE) - longitude\n") ..
|
||||
_("$(LATITUDE) - latitude\n") ..
|
||||
_("$(ELEVATION) - elevation\n") ..
|
||||
_("$(STARS) - star rating\n") ..
|
||||
_("$(LABELS) - color labels\n") ..
|
||||
_("$(MAKER) - camera maker\n") ..
|
||||
_("$(MODEL) - camera model\n") ..
|
||||
_("$(LENS) - lens\n") ..
|
||||
_("$(TITLE) - title from metadata\n") ..
|
||||
_("$(DESCRIPTION) - description from metadata\n") ..
|
||||
_("$(CREATOR) - creator from metadata\n") ..
|
||||
_("$(PUBLISHER) - publisher from metadata\n") ..
|
||||
_("$(RIGHTS) - rights from metadata\n") ..
|
||||
_("$(USERNAME) - username\n") ..
|
||||
_("$(PICTURES_FOLDER) - pictures folder\n") ..
|
||||
_("$(HOME) - user's home directory\n") ..
|
||||
_("$(DESKTOP) - desktop directory"),
|
||||
placeholder = _("enter pattern $(FILE_FOLDER)/$(FILE_NAME)"),
|
||||
text = ""
|
||||
}
|
||||
|
||||
local pattern_pref = dt.preferences.read(MODULE_NAME, "pattern", "string")
|
||||
if pattern_pref then
|
||||
rename.widgets.pattern.text = pattern_pref
|
||||
end
|
||||
|
||||
rename.widgets.button = dt.new_widget("button"){
|
||||
label = _("rename"),
|
||||
clicked_callback = function(this)
|
||||
do_rename(dt.gui.action_images)
|
||||
end
|
||||
}
|
||||
|
||||
if dt.gui.current_view().id == "lighttable" then
|
||||
install_module()
|
||||
else
|
||||
if not rename.event_registered then
|
||||
dt.register_event(
|
||||
"rename_images", "view-changed",
|
||||
function(event, old_view, new_view)
|
||||
if new_view.name == "lighttable" and old_view.name == "darkroom" then
|
||||
install_module()
|
||||
end
|
||||
end
|
||||
)
|
||||
rename.event_registered = true
|
||||
end
|
||||
end
|
||||
|
||||
script_data.destroy = destroy
|
||||
script_data.restart = restart
|
||||
script_data.destroy_method = "hide"
|
||||
script_data.show = restart
|
||||
|
||||
return script_data
|
||||
Reference in New Issue
Block a user