diff --git a/README.md b/README.md index fbf5aa6..5c56b3a 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ # dtlua -- darktable lua scripts +`add_lens_info`: script to add manual lens info. from [[https://discuss.pixls.us/t/add-lens-information-in-darktable/45262/19|pixls.us]] * `cr2hdr`: the `contrib/cr2hdr` script from [[https://github.com/darktable-org/lua-scripts|lua-scripts]], but with a locale fix * `ext_proc`: external processing with arbitrary command * `open_ooc`: open associated ooc jpegs for selected raw files diff --git a/add_lens_info.lua b/add_lens_info.lua new file mode 100644 index 0000000..a043428 --- /dev/null +++ b/add_lens_info.lua @@ -0,0 +1,366 @@ +--[[ + + add_lens_info.lua - add user specifed lens information to exif_lens field + + Copyright (C) 2025 Bill Ferguson . + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +]] +--[[ + add_lens_info - add user specifed lens information to exif_lens field + + apply_lens_info takes user specified lens information strings and applies + them to the image database entries in darktable. + + ADDITIONAL SOFTWARE NEEDED FOR THIS SCRIPT + none + + USAGE + * start script from script manager + * add lens information string and save it + * select lens information string in module + * select image(s) to apply the lens information to + * click apply lens information button, or use shortcut to apply the change + + BUGS, COMMENTS, SUGGESTIONS + Bill Ferguson + + CHANGES +]] + +local dt = require "darktable" +local du = require "lib/dtutils" +-- local df = require "lib/dtutils.file" +-- local ds = require "lib/dtutils.string" +-- local dtsys = require "lib/dtutils.system" +local log = require "lib/dtutils.log" +-- local debug = require "darktable.debug" + + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- C O N S T A N T S +-- - - - - - - - - - - - - - - - - - - - - - - - + +local MODULE = "add_lens_info" +local DEFAULT_LOG_LEVEL = log.warn +local TMP_DIR = dt.configuration.tmp_dir + +-- path separator +local PS = dt.configuration.running_os == "windows" and "\\" or "/" + +-- command separator +local CS = dt.configuration.running_os == "windows" and "&" or ";" + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- A P I C H E C K +-- - - - - - - - - - - - - - - - - - - - - - - - + +du.check_min_api_version("7.0.0", MODULE) -- choose the minimum version that contains the features you need + + +-- - - - - - - - - - - - - - - - - - - - - - - - - - +-- I 1 8 N +-- - - - - - - - - - - - - - - - - - - - - - - - - - + +local gettext = dt.gettext.gettext + +local function _(msgid) + return gettext(msgid) +end + + +-- - - - - - - - - - - - - - - - - - - - - - - - - - +-- S C R I P T M A N A G E R I N T E G R A T I O N +-- - - - - - - - - - - - - - - - - - - - - - - - - - + +local script_data = {} + +script_data.destroy = nil -- function to destory the script +script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet +script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again +script_data.show = nil -- only required for libs since the destroy_method only hides them + +script_data.metadata = { + name = _("add lens info"), -- visible name of script + purpose = _("add user specifed lens information to exif_lens field"), -- purpose of script + author = "Bill Ferguson ", -- your name and optionally e-mail address + help = "" -- URL to help/documentation +} + + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- L O G L E V E L +-- - - - - - - - - - - - - - - - - - - - - - - - + +log.log_level(DEFAULT_LOG_LEVEL) + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- N A M E S P A C E +-- - - - - - - - - - - - - - - - - - - - - - - - + +local add_lens_info = {} + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- G L O B A L V A R I A B L E S +-- - - - - - - - - - - - - - - - - - - - - - - - + +-- the lenses we know about +add_lens_info.lenses = {} + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- P R E F E R E N C E S +-- - - - - - - - - - - - - - - - - - - - - - - - + +-- lens data is stored in a string in the darktablerc file + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- A L I A S E S +-- - - - - - - - - - - - - - - - - - - - - - - - + +local namespace = add_lens_info +local ali = add_lens_info + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- F U N C T I O N S +-- - - - - - - - - - - - - - - - - - - - - - - - + +local function read_lens_preferences() + local lenses = dt.preferences.read(MODULE, "lenses", "string") + if string.len(lenses) > 1 then + if string.match(lenses, ".+$.+") then + ali.lenses = du.split(lenses, '%$') + else + table.insert(ali.lenses, lenses) + end + end +end + +local function save_lens_preferences() + dt.preferences.write(MODULE, "lenses", "string", table.concat(ali.lenses, '$')) +end + +local function set_buttons_sensitive() + if #dt.gui.action_images > 0 then + ali.apply_lens_selection.sensitive = true + dt.gui.libs.image.set_sensitive(MODULE, true) + else + ali.apply_lens_selection.sensitive = false + dt.gui.libs.image.set_sensitive(MODULE, false) + end +end + +local function apply_lens_name() + local images = dt.gui.action_images + + dt.print_log("image count is " .. #images) + + for _, image in ipairs(images) do + image.exif_lens = ali.lenses[ali.select_lens_name.selected] + end +end + +local function install_module() + if not namespace.module_installed then + dt.register_lib( + MODULE, -- Module name + script_data.metadata.name, -- Visible name + true, -- expandable + false, -- resetable + {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 400}}, -- containers + namespace.main_widget, + nil,-- view_enter + nil -- view_leave + ) + namespace.module_installed = true + end +end + +local function update_combobox_choices(combobox, choice_table, selected) + local items = #combobox + local choices = #choice_table + for i, name in ipairs(choice_table) do + combobox[i] = name + end + if choices < items then + for j = items, choices + 1, -1 do + combobox[j] = nil + end + end + combobox.value = selected +end + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- U S E R I N T E R F A C E +-- - - - - - - - - - - - - - - - - - - - - - - - + +ali.stack_selector = dt.new_widget("combobox"){ + tooltip = "choose to add a lens or select the lens name to be applied", + selected = dt.preferences.read(MODULE, "selector", "integer") > 0 and dt.preferences.read(MODULE, "selector", "integer") or 1, + _("add new lens name"), + _("select lens name"), + changed_callback = function(this) + dt.preferences.write(MODULE, "selector", "integer", this.selected) + if ali.module_installed then + ali.stack.active = this.selected + end + end +} + +ali.lens_name = dt.new_widget("entry"){ + placeholder = _("lens name/identification"), + text = "" +} + +ali.add_lens = dt.new_widget("button"){ + label = _("add new lens"), + tooltip = _("add new lens string to choices"), + clicked_callback = function(this) + table.insert(ali.lenses, ali.lens_name.text) + table.sort(ali.lenses) + local new_lens_place + for i, lens_name in ipairs(ali.lenses) do + if ali.lens_name.text == lens_name then + new_lens_place = i + break + end + end + update_combobox_choices(ali.select_lens_name, ali.lenses, new_lens_place) + ali.lens_name.text = "" + save_lens_preferences() + end +} + +ali.add_new_lens = dt.new_widget("box"){ + orientation = "vertical", + dt.new_widget("label"){ label = _("add new lens") }, + ali.lens_name, + ali.add_lens +} + +ali.select_lens_name = dt.new_widget("combobox"){ + tooltip = _("select lens name to apply to images"), +} +read_lens_preferences() +if #ali.lenses > 0 then + update_combobox_choices(ali.select_lens_name, ali.lenses, 1) +end + +ali.apply_lens_selection = dt.new_widget("button"){ + label = _("apply lens name"), + tooltip = _("apply lens name to selected images"), + sensitive = false, + clicked_callback = function(this) + apply_lens_name() + end +} + +ali.select_lens = dt.new_widget("box"){ + orientation = "vertical", + dt.new_widget("label"){ label = _("select lens name to apply") }, + ali.select_lens_name, + ali.apply_lens_selection +} + +ali.stack = dt.new_widget("stack"){ + ali.add_new_lens, + ali.select_lens, + active = 1 +} + +ali.stack_selector = dt.new_widget("combobox"){ + tooltip = "choose to add a lens or select the lens name to be applied", + selected = dt.preferences.read(MODULE, "selector", "integer") > 0 and dt.preferences.read(MODULE, "selector", "integer") or 1, + _("add new lens name"), + _("select lens name"), + changed_callback = function(this) + dt.preferences.write(MODULE, "selector", "integer", this.selected) + if ali.module_installed then + ali.stack.active = this.selected + else + ali.stack.active = dt.preferences.read(MODULE, "selector", "integer") + end + end +} + +ali.main_widget = dt.new_widget("box"){ + orientation = "vertical", + ali.stack_selector, + ali.stack +} + +dt.gui.libs.image.register_action(MODULE, _("apply lens name"), apply_lens_name, _("apply lens name from apply lens info module to selected images")) +dt.gui.libs.image.set_sensitive(MODULE, false) +-- - - - - - - - - - - - - - - - - - - - - - - - +-- M A I N P R O G R A M +-- - - - - - - - - - - - - - - - - - - - - - - - + +read_lens_preferences() + +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 + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- 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 +-- - - - - - - - - - - - - - - - - - - - - - - - + +dt.register_event(MODULE, "shortcut", + function(event, shortcut) + apply_lens_name() + end, _("apply lens name") +) + +dt.register_event(MODULE, "selection-changed", + function(event) + set_buttons_sensitive() + end +) + +return script_data