--[[ 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