From 193a615772d82700fb6537fe7d48afa029d78684 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sat, 8 Nov 2025 21:27:14 -0500 Subject: [PATCH 1/2] official/regenerate_thumbnails - add a script to fix skull thumbnails by dropping the cache for the image and regenerating it. Adds a button to the actions on selected images module. Also has a shortcut to apply the script by hovering and triggering the shortcut. --- official/regenerate_thumbnails.lua | 264 +++++++++++++++++++++++++++++ 1 file changed, 264 insertions(+) create mode 100644 official/regenerate_thumbnails.lua diff --git a/official/regenerate_thumbnails.lua b/official/regenerate_thumbnails.lua new file mode 100644 index 00000000..cbef00c6 --- /dev/null +++ b/official/regenerate_thumbnails.lua @@ -0,0 +1,264 @@ +--[[ + + regenerate_thumbnails.lua - regenerate mipmap cache for selected images + + 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 . +]] +--[[ + regenerate_thumbnails - regenerate mipmap cache for selected images + + regenerate_thumbnails drops the cached thumbnail for each selected image + and generates a new thumbnail. + + ADDITIONAL SOFTWARE NEEDED FOR THIS SCRIPT + None + + USAGE + * enable the script in script_manager + * assign a shortcut, if desired, to apply the script by hovering + over a skull and using the shortcut to regenerate the thumbnail + + 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" + + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- 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 = _("regenerate_thumbnails"), -- visible name of script + purpose = _("regenerate mipmap cache for selected images"), -- purpose of script + author = "Bill Ferguson ", -- your name and optionally e-mail address + help = "https://docs.darktable.org/lua/development/lua.scripts.manual/scripts/official/regenerate_thumbnails" -- URL to help/documentation +} + + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- C O N S T A N T S +-- - - - - - - - - - - - - - - - - - - - - - - - + +local MODULE = "regenerate_thumbnails" +local DEFAULT_LOG_LEVEL = log.info +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 ";" + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- L O G L E V E L +-- - - - - - - - - - - - - - - - - - - - - - - - + +log.log_level(DEFAULT_LOG_LEVEL) + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- N A M E S P A C E +-- - - - - - - - - - - - - - - - - - - - - - - - + +local regenerate_thumbnails = {} + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- G L O B A L V A R I A B L E S +-- - - - - - - - - - - - - - - - - - - - - - - - + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- P R E F E R E N C E S +-- - - - - - - - - - - - - - - - - - - - - - - - + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- A L I A S E S +-- - - - - - - - - - - - - - - - - - - - - - - - + +local namespace = regenerate_thumbnails +local rt = regenerate_thumbnails + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- F U N C T I O N S +-- - - - - - - - - - - - - - - - - - - - - - - - + +------------------- +-- helper functions +------------------- + +local function set_log_level(level) + local old_log_level = log.log_level() + log.log_level(level) + return old_log_level +end + +local function restore_log_level(level) + log.log_level(level) +end + +local function pref_read(name, pref_type) + local old_log_level = set_log_level(sm.log_level) + + log.msg(log.debug, "name is " .. name .. " and type is " .. pref_type) + + local val = dt.preferences.read(MODULE, name, pref_type) + + log.msg(log.debug, "read value " .. tostring(val)) + + restore_log_level(old_log_level) + return val +end + +local function pref_write(name, pref_type, value) + local old_log_level = set_log_level(sm.log_level) + + log.msg(log.debug, "writing value " .. tostring(value) .. " for name " .. name) + + dt.preferences.write(MODULE, name, pref_type, value) + + restore_log_level(old_log_level) +end + +local function stop_job() + rt.job.valid = false +end + +local function generate_thumbnails(images) + local has_job = false + + if #images > 50 then + rt.job = dt.gui.create_job("regenerating thumbnails", true, stop_job) + has_job = true + end + + for count, image in ipairs(images) do + image:drop_cache() + image:generate_cache(true, 1, 3) + if has_job then + if count % 10 == 0 then + rt.job.percent = count / #images + end + end + end + if has_job then + rt.job.valid = false + end +end + +local function update_button_sensitivity() + if #dt.gui.action_images > 0 then + dt.gui.libs.image.set_sensitive(MODULE, true) + else + dt.gui.libs.image.set_sensitive(MODULE, false) + end +end + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- M A I N P R O G R A M +-- - - - - - - - - - - - - - - - - - - - - - - - + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- U S E R I N T E R F A C E +-- - - - - - - - - - - - - - - - - - - - - - - - + +dt.gui.libs.image.register_action( + MODULE, + _("generate thumbnails"), + function(event, images) + generate_thumbnails(images) + end, + _("generate thumbnails") +) + +update_button_sensitivity() + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- D A R K T A B L E I N T E G R A T I O N +-- - - - - - - - - - - - - - - - - - - - - - - - + +local function destroy() + dt.destroy_event(MODULE, "selection-changed") + dt.destroy_event(MODULE, "mouse-over-image-changed") + dt.gui.libs.image.destroy_action(MODULE, "regenerate thumbnails") +end + +script_data.destroy = destroy + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- E V E N T S +-- - - - - - - - - - - - - - - - - - - - - - - - + +dt.register_event(MODULE, "shortcut", + function(event, shortcut) + local images = dt.gui.action_images + if images then + generate_thumbnails(images) + end + end, "regenerate thumbnails" +) + +dt.register_event(MODULE, "selection-changed", + function(event) + update_button_sensitivity() + end +) + +dt.register_event(MODULE, "mouse-over-image-changed", + function(event, image) + if #dt.gui.selection() < 1 then + if image then + dt.gui.libs.image.set_sensitive(MODULE, true) + else + dt.gui.libs.image.set_sensitive(MODULE, false) + end + end + end +) + +return script_data From dbf0c5d853da0a3de0cd4877abf79a9e1a975e6e Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sun, 9 Nov 2025 00:13:48 -0500 Subject: [PATCH 2/2] official/regenerate_thumbnails - added check to ensure job has not been canceled. --- official/regenerate_thumbnails.lua | 3 +++ 1 file changed, 3 insertions(+) diff --git a/official/regenerate_thumbnails.lua b/official/regenerate_thumbnails.lua index cbef00c6..ffe1dafe 100644 --- a/official/regenerate_thumbnails.lua +++ b/official/regenerate_thumbnails.lua @@ -181,6 +181,9 @@ local function generate_thumbnails(images) image:drop_cache() image:generate_cache(true, 1, 3) if has_job then + if not rt.job.valid then + return + end if count % 10 == 0 then rt.job.percent = count / #images end