darktable/photo-what-what.lua
--[[
photo-what-what.lua - pww plugin for Darktable
Copyright (C) 2025 Trevor Bentley <pww@x.mrmekon.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/>.
]]
--[[
photo-what-what - use pww to automatically tag selected image(s)
This launches pww, a utility for automatic image tagging, which
analyzes the image and attaches new tags based on its content.
These new tags are then imported into Darktable.
ADDITIONAL SOFTWARE NEEDED FOR THIS SCRIPT
* photo-what-what
* libexiv2
* libgexiv2
* libopenimageio
* any application that outputs a list of image tags
USAGE
* install & configure pww so it works with `photo-what-what <img>`
- or change default paths in darktable settings
* copy this script into darktable's lua/contrib/ directory
* require this script in darktable's luarc config file
* select one or more images
* click the "auto-tag images (pww)" button
BUGS, COMMENTS, SUGGESTIONS
* Send to Trevor Bentley: pww@x.mrmekon.com
CHANGES
* 2025-01-13: initial implementation
]]
local dt = require "darktable"
local du = require "lib/dtutils"
local dlog = require "lib/dtutils.log"
local dsys = require 'lib/dtutils.system'
local namespace <const> = "photo-what-what"
local LOG_LEVEL <const> = dlog.info
local gettext = dt.gettext.gettext
local
return gettext(msgid)
end
-- return data structure for script_manager
local script_data = {}
script_data.metadata = {
name = _("photo-what-what"),
purpose = _("automatically tag image(s) with photo-what-what analysis tool"),
author = "Trevor Bentley <pww@x.mmekon.com>",
help = ""
}
script_data.destroy = nil
script_data.destroy_method = nil
script_data.restart = nil
script_data.show = nil
du.check_min_api_version("9.0.0", "photo-what-what")
local PS <const> = dt.configuration.running_os == "windows" and "\\" or "/"
local settings = {
pww_bin_path = {},
pww_script_path = {},
}
local
if value == 0 or value == "" then
return default
end
return value
end
local
settings.pww_bin_path = default_to(dt.preferences.read(namespace, "pww_bin_path", "string"), "photo-what-what")
settings.pww_script_path = default_to(dt.preferences.read(namespace, "pww_script_path", "string"), "")
end
local job
local
if job then
job.valid = false
end
end
local
load_preferences()
local selection = dt.gui.selection()
-- process each selected image
job = dt.gui.create_job(_("pww auto-tagging"), true, stop_job)
for idx, image in ipairs(images) do
if not job.valid then
break
end
job.percent = ((idx-1) / #images)
-- I can't believe DT doesn't do this for us
local file = image.path .. PS .. image.filename
-- build up command from strings. yucky.
local cmd = settings.pww_bin_path
cmd = string.format("%s", cmd)
if settings.pww_script_path ~= "" then
cmd = string.format("%s -b \"%s\"", cmd, settings.pww_script_path)
end
cmd = string.format("%s \"%s\"", cmd, file)
-- run pww
local resp = dsys.external_command(cmd)
if resp ~= 0 then
dt.print("error running photo-what-what")
if job.valid then
job.valid = false
end
break
end
-- re-import file to read the updated metadata, since it was changed outside of darktable.
-- This does not change the image ID.
dt.database.import(file)
-- re-select the same selection, since importing clears it
dt.gui.selection(selection)
end
if job.valid then
job.valid = false
end
end
local
dt.destroy_event("photo-what-what", "shortcut")
dt.gui.libs.image.destroy_action("photo-what-what")
end
script_data.destroy = destroy
load_preferences()
-- register preferences in darktable settings
dt.preferences.register(namespace, "pww_script_path", "string", "pww script path", "Full path to identifier application/script used by pww (optional)", "")
dt.preferences.register(namespace, "pww_bin_path", "string", "pww bin path", "Full path to the photo-what-what executable", "photo-what-what")
-- register button in action menu
dt.gui.libs.image.register_action(
namespace, _("auto-tag images (pww)"),
function(event, images) call_pww(images) end,
_("auto-tag image(s) with photo-what-what analysis tool")
)
-- register keyboard shortcut handler
dt.register_event(
namespace, "shortcut",
function(event, shortcut) call_pww(dt.gui.action_images) end,
_("auto-tag image(s) with photo-what-what analysis tool")
)
return script_data