44 Commits

Author SHA1 Message Date
Bill Ferguson
77733b334e Modifed script_manager to handle embedding the lua-scripts in the darktable release. Lua API 9.7.0 starts script_manager from the lua init module. script_manager takes care of running the user luarc file if it exists 2025-12-20 19:42:19 -05:00
wpferguson
7f09e55525 Merge pull request #616 from wpferguson/fix_multi_os
examples/multi_os - replaced ufraw-batch with exiftool
2025-12-07 14:18:29 -05:00
wpferguson
f83ac1366a Merge pull request #617 from wpferguson/ext_editor_sanitize
ext_editor sanitize file name
2025-12-07 14:18:11 -05:00
Bill Ferguson
6cda27172e contrib/ext_editor - sanitize filename before importing to collection 2025-12-06 19:11:12 -05:00
Bill Ferguson
df78522a79 examples/multi_os - replaced ufraw-batch with exiftool to extract
the embedded jpeg or preview image.
2025-12-06 18:40:37 -05:00
wpferguson
6e64d6db6f Merge pull request #613 from wpferguson/string_lib_fixes
String lib fixes
2025-12-04 15:13:56 -05:00
Bill Ferguson
d75f00daa0 lib/dtutils/string - fixed ROLL.NAME to support the original and
the ROLL.NAME[n] variant in the same variable
                     string
2025-12-03 20:54:47 -05:00
Bill Ferguson
3e430ee2be lib/dtutils/string - converted element from string to number for use in test 2025-12-03 18:26:13 -05:00
Bill Ferguson
3856ae3449 lib/dtutils/string - added format_exposure function to take an
exif_exposure and return it as an exposure
                     string (exif_exposure = 500, string 1/500)
2025-12-02 20:40:03 -05:00
Bill Ferguson
d54a9f8b7e lib/dtutils/string - implemented variable substitution for ROLL.NAME[n] 2025-12-02 19:54:10 -05:00
Bill Ferguson
8f6cc850fb lib/dtutils/string - Added Xmp.darktable.version and Xmp.dc.[title,
description,publisher,rights,creator]
2025-12-02 18:57:05 -05:00
Bill Ferguson
e9f18a3d36 lib/dtutils/string - add IMAGE.ID and IMAGE.ID.NEXT variables 2025-12-02 18:34:18 -05:00
wpferguson
f3a89a89bd Merge pull request #612 from wpferguson/fix_apply_camera_style
official/apply_camera_style - fixed pattern matching bugs
2025-12-02 16:30:56 -05:00
Bill Ferguson
d075fb7128 official/apply_camera_style - fixed pattern matching bug that allowed
camera styles to be applied twice

                              fixed pattern matching bug affecting
                              Canon EOS R, RP, and R5

                              Added more debugging statements to
                              pattern matching functions
2025-12-02 16:23:28 -05:00
wpferguson
e831f377bf Merge pull request #610 from wpferguson/fix_selection_to_pdf_open
official/selection_to_pdf
2025-11-23 21:09:02 -05:00
Bill Ferguson
d696e6e3f2 official/selection_to_pdf - added default opens for Linux, MacOS,
and Windows
2025-11-23 21:04:54 -05:00
wpferguson
db505f1e0a Merge pull request #608 from wpferguson/fix_metadata_string_substitution
lib/dtutils/string - image metadata may return a nil so check to
2025-11-14 20:04:29 -05:00
Bill Ferguson
57d15a3fa6 lib/dtutils/string - image metadata may return a nil so check to
see if there is a value and return it otherwise
                     return an empty string
2025-11-11 21:59:07 -05:00
wpferguson
4d54b5eaba Merge pull request #606 from wpferguson/add_official_regenerate_thumbnails
official/regenerate_thumbnails - add a script to fix skull thumbnails
2025-11-09 22:56:05 -05:00
Bill Ferguson
dbf0c5d853 official/regenerate_thumbnails - added check to ensure job has not
been canceled.
2025-11-09 00:13:48 -05:00
Bill Ferguson
193a615772 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.
2025-11-08 21:27:14 -05:00
wpferguson
447980ddc4 Merge pull request #603 from wpferguson/fix_stringlib_sequence_arguments
Fix sequence string substitution variable to accept starting number > 9
2025-11-02 17:05:22 -05:00
Bill Ferguson
8af5476f8d lib/dtutils/string - fixed string substitution sequence to accept
start argument of more than 1 digit
2025-11-02 16:59:32 -05:00
wpferguson
c95547caa7 Merge pull request #584 from balping/patch-1
Add manual coordinate input option to geoToolbox
2025-08-18 17:01:22 -04:00
wpferguson
b4d3b2901f Merge pull request #585 from mreiger/master
Add a script to automatically tag manually modified images
2025-08-18 16:57:00 -04:00
wpferguson
cb6b3161d8 Merge pull request #595 from sjjh/patch-1
Update README.md: added link to script_manager docs
2025-08-18 16:55:27 -04:00
wpferguson
2d82eea237 Merge pull request #594 from deekayhd/master
rename_images: error when renaming images without exif data
2025-08-18 16:53:28 -04:00
Michael Reiger
3beee93af4 Merge branch 'darktable-org:master' into master 2025-08-01 07:36:10 +00:00
sjjh
68291414f3 Update README.md: added link to script_manager docs
just for convenience: added a link to dt documenation for script manager module in the 'enable' section
2025-07-13 16:56:22 +02:00
deekayhd
5662519314 Merge pull request #1 from deekayhd/no_exif_data
rename_images: error with images without exif data
2025-07-09 21:15:42 +02:00
deekayhd
28ab065293 Merge branch 'darktable-org:master' into no_exif_data 2025-07-09 20:52:02 +02:00
wpferguson
aed3275943 Merge pull request #593 from wpferguson/592_fix_RL_out_sharp
fix RL_out_sharp crash
2025-07-05 12:43:12 -04:00
Bill Ferguson
d7aeb43340 contrib/RL_out_sharp - changed MODULE to MODULE_NAME so that message
would print and script wouldn't crash
2025-07-05 12:39:36 -04:00
deekayhd
ea79d10b11 Update string.lua
initialize datetime_taken with proper value if no exif_datetime_taken can be found (e.g. in TIFF files)
2025-07-01 13:55:47 +02:00
Michael Reiger
e4001f984f Merge branch 'darktable-org:master' into master 2025-06-26 22:13:59 +00:00
wpferguson
453d744b69 Merge pull request #588 from wpferguson/18366_fix_apply_style_camera_decoding
fix apply_camera_style style decoding
2025-06-01 17:07:36 -04:00
Bill Ferguson
b9cc0dccce official/apply_camera_style - made spaces in camera name conditional
matches as some are squashed and others
                              (Olympus) are not.
2025-06-01 16:36:52 -04:00
Michael Reiger
84fea20ee5 fixed script desription 2025-06-01 13:28:44 +02:00
Michael Reiger
e054bfc59d Added script to automatically tag manually modified images 2025-06-01 13:12:56 +02:00
Michael Reiger
8cd10dce68 Revert "Modified apply_camera_style script so that the application of a camera style does not mark the image as changed" because that attempt did not work.
This reverts commit f8d49ccd01.
2025-06-01 12:50:59 +02:00
Michael Reiger
f8d49ccd01 Modified apply_camera_style script so that the application of a camera style does not mark the image as changed 2025-05-24 19:31:23 +02:00
Balázs Dura-Kovács
25afb41924 Create tooltips for geoToolbox 2025-05-06 19:37:09 +02:00
Balázs Dura-Kovács
3001a0dc1a Add manual coordinate input option to geoToolbox 2025-05-04 23:23:33 +02:00
Bill Ferguson
b70fdc0ecf official/apply_camera_style - Fixed decoding errors caused by #18332. 2025-02-07 14:29:45 -05:00
11 changed files with 754 additions and 94 deletions

View File

@@ -36,6 +36,7 @@ Name|Standalone|OS |Purpose
----|:--------:|:---:|-------
[AutoGrouper](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/autogrouper)|Yes|LMW|Group images together by time
[autostyle](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/autostyle)|Yes|LMW|Automatically apply styles on import
[auto_tag_modified](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/auto_tag_modified)|Yes|LMW|Automatically tag images which have been manually modified in the darkroom
change_group_leader|Yes|LMW|Change which image leads group
[clear_GPS](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/clear_gps)|Yes|LMW|Reset GPS information for selected images
[CollectHelper](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/collecthelper)|Yes|LMW|Add buttons to selected images module to manipulate the collection
@@ -178,7 +179,7 @@ If you don't have %LOCALAPPDATA%\darktable you have to start dartable at least o
When darktable starts it looks for a file name `~/.config/darktable/luarc` (`%LOCALAPPDATA%\darktable\luarc` for windows) and reads it to see which scripts to include. The file is a plain text file with entries of the form `require "<directory>/<name>"` where directory is the directory containing the scripts, from the above list, and name is the name from the above list. To include GIMP the line would be `require "contrib/gimp"`.
The recommended way to enable and disable specific scripts is using the script manager module. To use script manager do the following:
The recommended way to enable and disable specific scripts is using the [script manager](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/tools/script_manager/) module. To use script manager do the following:
### Linux or MacOS

View File

@@ -106,7 +106,7 @@ local function preserve_metadata(original, sharpened)
if exiftool then
dtsys.external_command("exiftool -overwrite_original_in_place -tagsFromFile " .. original .. " " .. sharpened)
else
dt.print_log(MODULE .. " exiftool not found, metadata not preserved")
dt.print_log(MODULE_NAME .. " exiftool not found, metadata not preserved")
end
end

View File

@@ -0,0 +1,129 @@
--[[
auto_tag_modified.lua - automatically tag an image when it has been manually modified in darkroom
Copyright (C) 2025 Michael Reiger <michael@rauschpfeife.net>, modeled after auto_snapshot.lua by Bill Ferguson <wpferguson@gamil.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/>.
]]
--[[
auto_tag_modified -
automatically tag an image when it has been manually modified in the darkroom, that is if its history has changed at the time it is closed from the darkroom.
(This will not catch applying styles from the light table though.)
ADDITIONAL SOFTWARE NEEDED FOR THIS SCRIPT
None
USAGE
* start the script from script_manager
* open an image in darkroom, and close it after making an operation that changes the history
BUGS, COMMENTS, SUGGESTIONS
Michael Reiger <michael@rauschpfeife.net>
CHANGES
]]
local dt = require "darktable"
local du = require "lib/dtutils"
local log = require "lib/dtutils.log"
-- - - - - - - - - - - - - - - - - - - - - - - -
-- C O N S T A N T S
-- - - - - - - - - - - - - - - - - - - - - - - -
local MODULE <const> = "auto_tag_modified"
local DEFAULT_TAG_NAME <const> = "darktable manually modified"
local DEFAULT_LOG_LEVEL <const> = log.error
-- - - - - - - - - - - - - - - - - - - - - - - -
-- 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 = _("auto tag modified"), -- name of script
purpose = _("automatically tag an image when it has been manually modified in darkroom"), -- purpose of script
author = "Michael Reiger <michael@rauschpfeife.net>", -- your name and optionally e-mail address
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/auto_tag_modified/" -- 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 auto_tag_modified = {}
-- - - - - - - - - - - - - - - - - - - - - - - -
-- P R E F E R E N C E S
-- - - - - - - - - - - - - - - - - - - - - - - -
dt.preferences.register(MODULE, "auto_modified_tag_name", "string", "auto_tag_modified - " .. _("tag name to use for auto tagging modified images"),
_("tag name to use for auto tagging modified images"), DEFAULT_TAG_NAME)
-- - - - - - - - - - - - - - - - - - - - - - - -
-- 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, "darkroom-image-history-changed")
end
script_data.destroy = destroy
-- - - - - - - - - - - - - - - - - - - - - - - -
-- E V E N T S
-- - - - - - - - - - - - - - - - - - - - - - - -
dt.register_event(MODULE, "darkroom-image-history-changed",
function(event, image)
local tag_name = dt.preferences.read(MODULE, "auto_modified_tag_name", "string")
local tag = dt.tags.create(tag_name)
dt.tags.attach(tag, image)
end
)
return script_data

View File

@@ -328,7 +328,7 @@ local function export2collection(storage, image_table, extra_data)
-- create unique filename
new_name = image.path..PS..df.get_filename(temp_name)
new_name = df.create_unique_filename(new_name)
new_name = df.sanitize_filename(df.create_unique_filename(new_name))
-- move image to collection folder, check result, return if error
move_success = df.file_move(temp_name, new_name)

View File

@@ -1,6 +1,7 @@
--[[
This file is part of darktable,
copyright (c) 2016 Tobias Jakobs
copyright (c) 2025 Balázs Dura-Kovács
darktable is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -63,21 +64,33 @@ gT.event_registered = false
local labelDistance = dt.new_widget("label")
labelDistance.label = _("distance:")
local label_copy_gps_lat = dt.new_widget("check_button")
local checkbox_copy_gps_lat = dt.new_widget("check_button")
{
label = _("latitude: "),
value = true
}
local label_copy_gps_lon = dt.new_widget("check_button")
local entry_gps_lat = dt.new_widget("entry")
{
tooltip = _("latitude (editable)"),
placeholder = _("latitude")
}
local checkbox_copy_gps_lon = dt.new_widget("check_button")
{
label = _("longitude: "),
value = true
}
local label_copy_gps_ele = dt.new_widget("check_button")
local entry_gps_lon = dt.new_widget("entry")
{
tooltip = _("longitude (editable)"),
placeholder = _("longitude")
}
local checkbox_copy_gps_ele = dt.new_widget("check_button")
{
label = _("elevation: "),
value = true
}
local entry_gps_ele = dt.new_widget("entry")
{
tooltip = _("elevation (editable)"),
placeholder = _("elevation")
}
-- </GUI>
local function select_with_gps()
@@ -294,20 +307,20 @@ local function copy_gps()
copy_gps_have_data = false
else
copy_gps_have_data = true
if (image.latitude and label_copy_gps_lat.value) then
if (image.latitude and checkbox_copy_gps_lat.value) then
copy_gps_latitude = image.latitude
end
if (image.longitude and label_copy_gps_lon.value) then
if (image.longitude and checkbox_copy_gps_lon.value) then
copy_gps_longitude = image.longitude
end
if (image.elevation and label_copy_gps_ele.value) then
if (image.elevation and checkbox_copy_gps_ele.value) then
copy_gps_elevation = image.elevation
end
end
label_copy_gps_lat.label = _("latitude: ") .. copy_gps_latitude
label_copy_gps_lon.label = _("longitude: ") .. copy_gps_longitude
label_copy_gps_ele.label = _("elevation: ") .. copy_gps_elevation
entry_gps_lat.text = copy_gps_latitude
entry_gps_lon.text = copy_gps_longitude
entry_gps_ele.text = copy_gps_elevation
return
end
@@ -317,14 +330,14 @@ local function paste_gps(image)
local sel_images = dt.gui.action_images
for jj,image in ipairs(sel_images) do
if (label_copy_gps_lat.value) then
image.latitude = copy_gps_latitude
if (checkbox_copy_gps_lat.value) then
image.latitude = entry_gps_lat.text
end
if (label_copy_gps_lon.value) then
image.longitude = copy_gps_longitude
if (checkbox_copy_gps_lon.value) then
image.longitude = entry_gps_lon.text
end
if (label_copy_gps_ele.value) then
image.elevation = copy_gps_elevation
if (checkbox_copy_gps_ele.value) then
image.elevation = entry_gps_ele.text
end
end
end
@@ -663,13 +676,25 @@ gT.widget = dt.new_widget("box")
tooltip = _("copy GPS data"),
clicked_callback = copy_gps
},
label_copy_gps_lat,
label_copy_gps_lon,
label_copy_gps_ele,
dt.new_widget("box"){
orientation = "horizontal",
checkbox_copy_gps_lat,
entry_gps_lat
},
dt.new_widget("box"){
orientation = "horizontal",
checkbox_copy_gps_lon,
entry_gps_lon
},
dt.new_widget("box"){
orientation = "horizontal",
checkbox_copy_gps_ele,
entry_gps_ele
},
dt.new_widget("button")
{
label = _("paste GPS data"),
tooltip = _("paste GPS data"),
label = _("apply GPS data to image"),
tooltip = _("apply GPS data to image"),
clicked_callback = paste_gps
},
separator2,--------------------------------------------------------

View File

@@ -29,8 +29,7 @@
by hovering over the image and pressing the key combination.
ADDITIONAL SOFTWARE NEEDED FOR THIS SCRIPT
* ufraw-batch - https://ufraw.sourceforge.net
MacOS - install with homebrew
* exiftool - https://exiftool.org
USAGE
* require this script from your main lua file
@@ -44,6 +43,7 @@
* Send to Bill Ferguson, wpferguson@gmail.com
CHANGES
20251205 - replaced ufraw-batch with exiftool
]]
--[[
@@ -139,6 +139,36 @@ local function copy_image_attributes(from, to, ...)
end
end
local function check_file_size(img_name)
local result = 0
if dt.configuration.running_os == "windows" then
local path = df.get_path(img_name)
local fname = df.get_filename(img_name)
local p = io.open("forfiles /P " .. path .. " /M " .. fname .. " /C \"cmd /c echo $fsize\"")
if p then
for line in p:lines() do
if line:length() > 5 then
result = tonumber(line)
end
end
p:close()
end
else
local p = io.popen("ls -s " .. img_name)
if p then
local line = p:read("*a")
result = tonumber(du.split(line, " ")[1])
p:close()
end
end
return result
end
--[[
The main function called from the button or the shortcut. It takes one or more raw files, passed
in a table and extracts the embedded jpeg images
@@ -152,11 +182,12 @@ local function extract_embedded_jpeg(images)
in the user's path. When it finds the executable, it returns the command to run it.
]]
local ufraw_executable = df.check_if_bin_exists("ufraw-batch")
if ufraw_executable then
local exiftool_executable = df.check_if_bin_exists("exiftool")
if exiftool_executable then
for _, image in ipairs(images) do
if image.is_raw then
local img_file = du.join({image.path, image.filename}, "/")
local img_file = tostring(image)
local jpg_img_file = string.gsub(img_file, "%....$", ".jpg")
--[[
dtsys.external_command() is operating system aware and formats the command as necessary.
@@ -164,8 +195,12 @@ local function extract_embedded_jpeg(images)
operating system aware and uses the corresponding quotes.
]]
if dtsys.external_command(ufraw_executable .. " --silent --embedded-image " .. df.sanitize_filename(img_file)) then
local jpg_img_file = df.chop_filetype(img_file) .. ".embedded.jpg"
if dtsys.external_command(exiftool_executable .. " -b -JpgFromRaw " .. df.sanitize_filename(img_file) .. " > " .. df.sanitize_filename(jpg_img_file)) then
dt.print_log("created jpg from raw")
if check_file_size(df.sanitize_filename(jpg_img_file)) == 0 then
dt.print_log("using preview")
dtsys.external_command(exiftool_executable .. " -b -PreviewImage " .. df.sanitize_filename(img_file) .. " > " .. df.sanitize_filename(jpg_img_file))
end
dt.print_log("jpg_img_file set to ", jpg_img_file) -- print a debugging message
local myimage = dt.database.import(jpg_img_file)
myimage:group_with(image.group_leader)
@@ -188,8 +223,8 @@ local function extract_embedded_jpeg(images)
end
end
else
dt.print_error("ufraw-batch not found. Exiting...") -- print debugging error message
dt.print("ufraw-batch not found, exiting...") -- print the error to the screen
dt.print_error("exiftool not found. Exiting...") -- print debugging error message
dt.print("exiftool not found, exiting...") -- print the error to the screen
end
end

View File

@@ -542,11 +542,14 @@ local PLACEHOLDERS = {"ROLL.NAME",
"FILE.FOLDER",
"FILE.NAME",
"FILE.EXTENSION",
"ID",
"ID",
"IMAGE.ID",
"IMAGE.ID.NEXT",
"VERSION",
"VERSION.IF.MULTI",
"VERSION.NAME",
"DARKTABLE.VERSION",
"Xmp.darktable.version",
"DARKTABLE.NAME", -- Not Implemented
"SEQUENCE",
"WIDTH.SENSOR",
@@ -612,10 +615,15 @@ local PLACEHOLDERS = {"ROLL.NAME",
"LABELS",
"LABELS.ICONS", -- Not Implemented
"TITLE",
"Xmp.dc.title",
"DESCRIPTION",
"Xmp.dc.description",
"CREATOR",
"Xmp.dc.creator",
"PUBLISHER",
"Xmp.dc.publisher",
"RIGHTS",
"Xmp.dc.rights",
"TAGS", -- Not Implemented
"SIDECAR.TXT", -- Not Implemented
"FOLDER.PICTURES",
@@ -652,6 +660,37 @@ local function get_colorlabels(image)
return labels
end
-- handle the ROLL.NAME[n] case
local function build_rollname_substitution_list(image, variable_string)
local old_log_level = log.log_level()
log.log_level(dtutils_string.log_level)
for match in string.gmatch(variable_string, "%$%(.-%)?%)") do -- grab each complete variable
log.msg(log.info, "match is " .. match)
local var = string.match(match, "%$%((.-%)?)%)") -- strip of the leading $( and trailing )
log.msg(log.info, "var is " .. var)
local element = nil
if string.match(var, "ROLL.NAME%[") then
element = string.match(var, "%[(%d)%]")
local path = du.split(image.film.path, dt.configuration.running_os ~= "windows" and "/" or "\\")
element = tonumber(element) + 1 -- add one because c arrays are 0 based and lua are 1 based
if element > #path then
log.msg(log.warn, "ROLL.NAME element requested was more than number of elements in film roll")
substitutes[var] = ""
else
substitutes[var] = path[(#path + 1) - element]
end
end
end
end
-- find the $CATEGORYn and $CATEGORY[n,m] requests and add them to the substitute list
local function build_category_substitution_list(image, variable_string)
@@ -734,16 +773,33 @@ function dtutils_string.build_substitute_list(image, sequence, variable_string,
local labels = get_colorlabels(image)
local eyear, emon, eday, ehour, emin, esec, emsec
local datetime_taken = ""
local use_millisecs = false
if dt.preferences.read("darktable", "lighttable/ui/milliseconds", "bool") and is_api_9_1 then
use_millisecs = true
end
if image.exif_datetime_taken and image.exif_datetime_taken ~= "" then
datetime_taken = image.exif_datetime_taken
else
if use_millisecs then
datetime_taken = "0000:00:00 00:00:00.0"
else
datetime_taken = "0000:00:00 00:00:00"
end
end
local eyear, emon, eday, ehour, emin, esec, emsec
if use_millisecs then
eyear, emon, eday, ehour, emin, esec, emsec =
string.match(image.exif_datetime_taken, "(%d+):(%d+):(%d+) (%d+):(%d+):(%d+)%.(%d+)$")
string.match(datetime_taken, "(%d+):(%d+):(%d+) (%d+):(%d+):(%d+)%.(%d+)$")
else
emsec = "0"
eyear, emon, eday, ehour, emin, esec =
string.match(image.exif_datetime_taken, "(%d+):(%d+):(%d+) (%d+):(%d+):(%d+)$")
string.match(datetime_taken, "(%d+):(%d+):(%d+) (%d+):(%d+):(%d+)$")
end
local version_multi = #image:get_group_members() > 1 and image.duplicate_index or ""
local replacements = {dtutils_string.get_basename(image.film.path),-- ROLL.NAME
@@ -751,10 +807,13 @@ function dtutils_string.build_substitute_list(image, sequence, variable_string,
dtutils_string.get_basename(image.filename),-- FILE.NAME
dtutils_string.get_filetype(image.filename),-- FILE.EXTENSION
image.id, -- ID
image.id, -- IMAGE.ID
dt.database[#dt.database].id + 1, -- IMAGE.ID.NEXT
image.duplicate_index, -- VERSION
version_multi, -- VERSION.IF_MULTI
image.version_name, -- VERSION.NAME
image.version_name and image.version_name or "", -- VERSION.NAME
dt.configuration.version, -- DARKTABLE.VERSION
dt.configuration.version, -- Xmp.darktable.version
"", -- DARKTABLE.NAME
string.format("%04d", sequence), -- SEQUENCE
image.width, -- WIDTH.SENSOR
@@ -781,8 +840,8 @@ function dtutils_string.build_substitute_list(image, sequence, variable_string,
eyear, -- EXIF.YEAR
string.sub(eyear, 3), -- EXIF.YEAR.SHORT
emon, -- EXIF.MONTH
os.date("%B", exiftime2systime(image.exif_datetime_taken)), -- EXIF.MONTH.LONG
os.date("%b", exiftime2systime(image.exif_datetime_taken)), -- EXIF.MONTH.SHORT
os.date("%B", exiftime2systime(datetime_taken)), -- EXIF.MONTH.LONG
os.date("%b", exiftime2systime(datetime_taken)), -- EXIF.MONTH.SHORT
eday, -- EXIF.DAY
ehour, -- EXIF.HOUR
"", -- EXIF.HOUR.AMPM
@@ -819,11 +878,16 @@ function dtutils_string.build_substitute_list(image, sequence, variable_string,
"", -- RATING.ICONS - wont be implemented
labels, -- LABELS
"", -- LABELS.ICONS - wont be implemented
image.title, -- TITLE
image.description, -- DESCRIPTION
image.creator, -- CREATOR
image.publisher, -- PUBLISHER
image.rights, -- RIGHTS
image.title and image.title or "", -- TITLE
image.title and image.title or "", -- Xmp.dc.title
image.description and image.description or "", -- DESCRIPTION
image.description and image.description or "", -- Xmp.dc.description
image.creator and image.creator or "", -- CREATOR
image.creator and image.creator or "", -- Xmp.dc.creator
image.publisher and image.publisher or "", -- PUBLISHER
image.publisher and image.publisher or "", -- Xmp.dc.publisher
image.rights and image.rights or "", -- RIGHTS
image.rights and image.rights or "", -- Xmp.dc.rights
"", -- TAGS - wont be implemented
"", -- SIDECAR.TXT - wont be implemented
pictures_folder, -- FOLDER.PICTURES
@@ -845,6 +909,7 @@ function dtutils_string.build_substitute_list(image, sequence, variable_string,
-- do category substitutions separately
build_category_substitution_list(image, variable_string)
build_rollname_substitution_list(image, variable_string)
log.log_level(old_log_level)
end
@@ -872,10 +937,13 @@ function dtutils_string.get_substitution_tooltip()
_("$(FILE.NAME) - basename of the input image"),
_("$(FILE.EXTENSION) - extension of the input image"),
_("$(ID) - image ID"),
_("$(IMAGE.ID) - image ID"),
_("$(IMAGE.ID.NEXT) - next image ID to be assigned on import"),
_("$(VERSION) - duplicate version"),
_("$(VERSION.IF_MULTI) - same as $(VERSION) but null string if only one version exists"),
_("$(VERSION.NAME) - version name from metadata"),
_("$(DARKTABLE.VERSION) - current darktable version"),
_("$(Xmp.darktable.version) - current darktable version"),
-- _("$(DARKTABLE.NAME) - darktable name"), -- not implemented
_("$(SEQUENCE[n,m]) - sequence number, n: number of digits, m: start number"),
_("$(WIDTH.SENSOR) - image sensor width"),
@@ -940,10 +1008,15 @@ function dtutils_string.get_substitution_tooltip()
_("$(LABELS) - color labels as text"),
-- _("$(LABELS.ICONS) - color labels as icons"),-- not implemented
_("$(TITLE) - title from metadata"),
_("$(Xmp.dc.title) - title from metadata"),
_("$(DESCRIPTION) - description from metadata"),
_("$(Xmp.dc.description) - description from metadata"),
_("$(CREATOR) - creator from metadata"),
_("$(Xmp.dc.creator) - creator from metadata"),
_("$(PUBLISHER) - publisher from metadata"),
_("$(Xmp.dc.publisher) - publisher from metadata"),
_("$(RIGHTS) - rights from metadata"),
_("$(Xmp.dc.rights) - rights from metadata"),
--_("$(TAGS) - tags as set in metadata settings"),
_("$(CATEGORY[n,category]) - subtag of level n in hierarchical tags"),
_("$(SIDECAR_TXT) - contents of .txt sidecar file, if present"),
@@ -993,8 +1066,13 @@ local function treat(var_string)
if not ret_val then ret_val = "" end
log.msg(log.info, "ret_val is " .. ret_val)
elseif string.match(var_string, "ROLL.NAME%[") then
ret_val = substitutes[var_string]
if not ret_val then ret_val = "" end
log.msg(log.info, "ret_val is " .. ret_val)
elseif string.match(var_string, "SEQUENCE%[") then
local width, start = string.match(var_string, "(%d+),(%d)")
local width, start = string.match(var_string, "(%d+),(%d+)")
local seq_val = tonumber(substitutes[var])
local pat = "%0" .. width .. "d"
substitutes[var_string] = string.format(pat, start + (seq_val - 1))
@@ -1226,6 +1304,49 @@ function dtutils_string.substitute(image, sequence, variable_string, username, p
return str
end
dtutils_string.libdoc.functions["format_exposure"] = {
Name = [[format_exposure]],
Synopsis = [[format exif_exposure from dt_lua_image_t to an exposure time]],
Usage = [[local ds = require "lib/dtutils.string"
ds.format_exposure(image.exif_exposure)
image.exif_exposure - dt_lua_image_t exif exposure field
Description = [[format_exposure takes the EXIF exposure field and formats it into an exposure string]],
Return_Value = [[result - string - the EXIF exposure formatted as an exposure string]],
Limitations = [[]],
Example = [[]],
See_Also = [[https://docs.darktable.org/usermanual/4.6/en/special-topics/variables/]],
Reference = [[]],
License = [[]],
Copyright = [[]],
}
local function _nearbyintf(v)
return math.floor(v + .5)
end
function dtutils_string.format_exposure(exif_exposure)
result = nil
if exif_exposure > 1.0 then
if _nearbyintf(exif_exposure) == exif_exposure then
result = string.format("%.0f″", exif_exposure)
else
result = string.format("%.1f″", exif_exposure)
end
-- catch everything below 0.3 seconds
elseif exif_exposure < 0.2 then
result = string.format("1/%.0f", 1.0 / exif_exposure)
-- catch 1/2, 1/3, ...
elseif _nearbyintf(1.0 / exif_exposure) == (1.0 / exif_exposure) then
result = string.format("1/%.0f", 1.0 / exif_exposure)
-- catch 1/1.3, 1/1.6, ...
elseif (10 * _nearbyintf(10.0 / exif_exposure)) == _nearbyintf(100.0 / exif_exposure) then
result = string.format("1/%.1f", 1.0 / exif_exposure)
else
result = string.format("%.1f″", exif_exposure)
end
return result
end
return dtutils_string

View File

@@ -34,12 +34,17 @@
Bill Ferguson <wpferguson@gmail.com>
CHANGES
20251202 - fixed pattern matching bugs affecting Canon EOS R? series
styles and styles being applied twice if images are reimported
Added more debugging statements to pattern matching functions
]]
local dt = require "darktable"
local du = require "lib/dtutils"
-- local df = require "lib/dtutils.file"
-- local ds = require "lib/dtutils.string"
local ds = require "lib/dtutils.string"
-- local dtsys = require "lib/dtutils.system"
local log = require "lib/dtutils.log"
-- local debug = require "darktable.debug"
@@ -50,9 +55,11 @@ local log = require "lib/dtutils.log"
-- - - - - - - - - - - - - - - - - - - - - - - -
local MODULE <const> = "apply_camera_style"
local DEFAULT_LOG_LEVEL <const> = log.info
local DEFAULT_LOG_LEVEL <const> = log.warn
local TMP_DIR <const> = dt.configuration.tmp_dir
local STYLE_PREFIX <const> = "_l10n_darktable camera styles|"
local STYLE_PREFIX <const> = "_l10n_darktable|_l10n_camera styles|"
local MAKER = 3
local STYLE = 4
-- path separator
local PS <const> = dt.configuration.running_os == "windows" and "\\" or "/"
@@ -152,22 +159,32 @@ local function process_pattern(pattern)
local log_level = set_log_level(acs.log_level)
log.msg(log.debug, "input pattern is " .. pattern)
pattern = string.lower(pattern)
log.msg(log.debug, "lower case pattern is " .. pattern)
-- strip off series
pattern = string.gsub(pattern, " series$", "?")
log.msg(log.debug, "series stripped off pattern is " .. pattern)
-- match a character
if string.match(pattern, "?$") then
if string.match(pattern, "r%?%?$") then
-- handle EOS R case
pattern = string.gsub(pattern, "?", ".?")
pattern = string.gsub(pattern, "%?%?", ".?")
log.msg(log.debug, "matched EOS R pattern is " .. pattern)
else
pattern = string.gsub(pattern, "?", ".")
log.msg(log.debug, "didn't match EOS R pattern is " .. pattern)
end
pattern = string.gsub(pattern, " ", " ?")
-- escape dashes
pattern = string.gsub(pattern, "%-", "%%-")
log.msg(log.debug, "escape dashes conditional pattern is " .. pattern)
-- make spaces optional
pattern = string.gsub(pattern, " ", " ?")
-- until we end up with a set, I'll defer set processing, i.e. [...]
--log.msg(log.debug, "make spaces conditional again? pattern is " .. pattern)
-- anchor the pattern to ensure we don't short match
pattern = "^" .. pattern .. "$"
log.msg(log.debug, "anchored pattern is " .. pattern)
restore_log_level(log_level)
@@ -223,25 +240,25 @@ local function get_camera_styles()
log.msg(log.debug, "got " .. style.name)
local parts = du.split(style.name, "|")
parts[2] = string.lower(parts[2])
log.msg(log.debug, "maker is " .. parts[2])
parts[MAKER] = string.lower(parts[MAKER])
log.msg(log.debug, "maker is " .. parts[MAKER])
if not acs.styles[parts[2]] then
acs.styles[parts[2]] = {}
acs.styles[parts[2]]["styles"] = {}
acs.styles[parts[2]]["patterns"] = {}
if not acs.styles[parts[MAKER]] then
acs.styles[parts[MAKER]] = {}
acs.styles[parts[MAKER]]["styles"] = {}
acs.styles[parts[MAKER]]["patterns"] = {}
end
if parts[3] then
if not string.match(parts[3], "]") then
table.insert(acs.styles[parts[2]].styles, style)
if parts[STYLE] then
if not string.match(parts[STYLE], "]") then
table.insert(acs.styles[parts[MAKER]].styles, style)
local processed_pattern = process_pattern(parts[#parts])
table.insert(acs.styles[parts[2]].patterns, processed_pattern)
table.insert(acs.styles[parts[MAKER]].patterns, processed_pattern)
log.msg(log.debug, "pattern for " .. style.name .. " is " .. processed_pattern)
else
local processed_patterns = process_set(parts[3])
local processed_patterns = process_set(parts[STYLE])
for _, pat in ipairs(processed_patterns) do
table.insert(acs.styles[parts[2]].styles, style)
table.insert(acs.styles[parts[2]].patterns, pat)
table.insert(acs.styles[parts[MAKER]].styles, style)
table.insert(acs.styles[parts[MAKER]].patterns, pat)
log.msg(log.debug, "pattern for " .. style.name .. " is " .. pat)
end
end
@@ -322,9 +339,11 @@ local function has_style_tag(image, tag_name)
log.msg(log.debug, "looking for tag " .. tag_name)
for _, tag in ipairs(image:get_tags()) do
log.msg(log.debug, "checking against " .. tag.name)
if tag.name == tag_name then
log.msg(log.debug, "matched tag " .. tag_name)
log.msg(log.debug, "got attached tag " .. tag.name)
local cleaned_tag_name = string.gsub(tag_name, "_l10n_", "")
log.msg(log.debug, "checking against " .. cleaned_tag_name)
if ds.sanitize_lua(tag.name) == cleaned_tag_name then
log.msg(log.debug, "matched tag " .. cleaned_tag_name)
result = true
end
end
@@ -354,7 +373,7 @@ local function mangle_model(model)
model = string.gsub(model, "eos 1200d", "eos rebel t5")
model = string.gsub(model, "eos 1300d", "eos rebel t6")
model = string.gsub(model, "eos 2000d", "eos rebel t7")
log.msg(log.debug, "mandle model returning " .. model)
log.msg(log.debug, "mangle model returning " .. model)
end
restore_log_level(log_level)
@@ -385,14 +404,15 @@ local function apply_style_to_images(images)
if acs.styles[maker] then
local no_match = true
for i, pattern in ipairs(acs.styles[maker].patterns) do
log.msg(log.debug, "pattern is " .. pattern)
if string.match(model, pattern) or
(i == #acs.styles[maker].patterns and string.match(pattern, "generic")) then
local tag_name = "darktable|style|" .. acs.styles[maker].styles[i].name
if not has_style_tag(image, tag_name) then
image:apply_style(acs.styles[maker].styles[i])
no_match = false
log.msg(log.info, "applied style " .. acs.styles[maker].styles[i].name .. " to " .. image.filename)
end
no_match = false
log.log_level(loglevel)
break
end

View File

@@ -0,0 +1,267 @@
--[[
regenerate_thumbnails.lua - regenerate mipmap cache for selected images
Copyright (C) 2025 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/>.
]]
--[[
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 <wpferguson@gmail.com>
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 <wpferguson@gmail.com>", -- 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 <const> = "regenerate_thumbnails"
local DEFAULT_LOG_LEVEL <const> = log.info
local TMP_DIR <const> = dt.configuration.tmp_dir
-- path separator
local PS <const> = dt.configuration.running_os == "windows" and "\\" or "/"
-- command separator
local CS <const> = 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 not rt.job.valid then
return
end
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

View File

@@ -44,6 +44,10 @@ local function _(msg)
return gettext(msg)
end
local NIX_OPEN <const> = "xdg-open "
local MAC_OPEN <const> = "open "
local WIN_OPEN <const> = "start "
-- return data structure for script_manager
local script_data = {}
@@ -63,8 +67,8 @@ script_data.show = nil -- only required for libs since the destroy_method only h
dt.preferences.register
("selection_to_pdf","Open with","string",
_("a pdf viewer"),
_("can be an absolute pathname or the tool may be in the PATH"),
"xdg-open")
_("can be an absolute pathname or the tool may be in the PATH\nif not specified the system default will be used to open the pdf"),
"")
local title_widget = dt.new_widget("entry") {
placeholder = _("title")
@@ -115,8 +119,9 @@ local function thumbnail(latexfile,i,image,file)
-- fact is that latex will get confused if the filename has multiple dots.
-- so \includegraphics{file.01.jpg} wont work. We need to output the filename
-- and extention separated, e.g: \includegraphics{{file.01}.jpg}
local filenoext=string.gsub(file, "(.*)(%..*)", "%1")
local ext=string.gsub(file, "(.*)(%..*)", "%2")
local filenoext = string.gsub(file, "(.*)(%..*)", "%1")
local ext = string.gsub(file, "(.*)(%..*)", "%2")
my_write(latexfile,"\\begin{minipage}[b]{"..width.."\\textwidth}\n")
my_write(latexfile,"\\includegraphics[width=\\textwidth]{{"..filenoext.."}"..ext.."}\\newline\n")
my_write(latexfile,"\\centering{"..i..": \\verb|"..title.."|}\n")
@@ -138,7 +143,7 @@ dt.register_storage("export_pdf", _("export thumbnails to pdf"),
end
local thumbs_per_line = no_of_thumbs_widget.value
thumbs_per_line = tonumber(thumbs_per_line)
width = (1/thumbs_per_line) - 0.01
width = (1 / thumbs_per_line) - 0.01
local preamble = [[
\documentclass[a4paper,10pt]{article}
@@ -148,31 +153,31 @@ dt.register_storage("export_pdf", _("export thumbnails to pdf"),
\usepackage{geometry}
\geometry{a4paper,left=5mm,right=5mm, top=5mm, bottom=5mm}
\begin{document}
{\Large\bfseries ]]..my_title..[[} \\
{\Large\bfseries ]] .. my_title .. [[} \\
\bigskip\bigskip
]]
local errmsg
local latexfile
latexfile,errmsg=io.open(filename,"w")
latexfile,errmsg = io.open(filename, "w")
if not latexfile then
error(errmsg)
end
my_write(latexfile,preamble)
my_write(latexfile, preamble)
local i = 1
for img,file in pairs(image_table) do
thumbnail(latexfile,i,img,file)
for img, file in pairs(image_table) do
thumbnail(latexfile, i, img, file)
if i % thumbs_per_line == 0 then
my_write(latexfile,"\n\\bigskip\n")
my_write(latexfile, "\n\\bigskip\n")
end
i = i+1
i = i + 1
end
my_write(latexfile,ending)
latexfile:close()
-- convert to PDF
local dir=string.gsub(filename, "(.*/)(.*)", "%1")
local locfile=string.gsub(filename, "(.*/)(.*)", "%2")
local dir = string.gsub(filename, "(.*/)(.*)", "%1")
local locfile = string.gsub(filename, "(.*/)(.*)", "%2")
local command = "pdflatex -halt-on-error -output-directory "..dir.." "..locfile
local result = dt.control.execute(command)
if result ~= 0 then
@@ -181,9 +186,18 @@ dt.register_storage("export_pdf", _("export thumbnails to pdf"),
end
-- open the PDF
local pdffile=string.gsub(filename, ".tex", ".pdf")
local pdffile = string.gsub(filename, ".tex", ".pdf")
command = dt.preferences.read("selection_to_pdf","Open with","string")
command = command.." "..pdffile
if command == "" then
if dt.configuration.running_os == "windows" then
command = WIN_OPEN
elseif dt.configuration.running_os == "macos" then
command = MAC_OPEN
else
command = NIX_OPEN
end
end
command = command .. " " .. pdffile
local result = dt.control.execute(command)
if result ~= 0 then
dt.print(_("problem running pdf viewer")) -- this one is probably usefull to the user

View File

@@ -54,7 +54,7 @@ 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"
local dtdebug = require "darktable.debug"
local gettext = dt.gettext.gettext
@@ -62,6 +62,21 @@ local function _(msgid)
return gettext(msgid)
end
-- figure out where we are running from
local info = debug.getinfo(1, "S")
local scripts_path = info.source:sub(2)
dt.print_log("scripts path is " .. scripts_path)
-- assume user based
local system_based = false
if string.match(scripts_path, dt.configuration.data_dir) then
dt.print_log("script_manager using system based scripts")
system_based = true
end
-- api check
-- du.check_min_api_version("9.3.0", "script_manager")
@@ -71,7 +86,7 @@ end
-- - - - - - - - - - - - - - - - - - - - - - - -
-- script_manager required API version
local SM_API_VER_REQD <const> = "9.3.0"
local SM_API_VER_REQD <const> = "9.7.0"
-- path separator
local PS <const> = dt.configuration.running_os == "windows" and "\\" or "/"
@@ -87,15 +102,29 @@ local DEFAULT_BUTTONS_PER_PAGE <const> = 10
local DEFAULT_LOG_LEVEL <const> = log.warn
local LUA_DIR <const> = dt.configuration.config_dir .. PS .. "lua"
local USER_LUA_DIR <const> = dt.configuration.config_dir .. PS .. "lua"
local SYSTEM_LUA_DIR <const> = dt.configuration.data_dir .. PS .. "lua-scripts"
local LUA_SCRIPT_REPO <const> = "https://github.com/darktable-org/lua-scripts.git"
local LUA_API_VER <const> = "API-" .. dt.configuration.api_version_string
-- local POWER_ICON = dt.configuration.config_dir .. "/lua/data/data/icons/power.png"
local POWER_ICON <const> = dt.configuration.config_dir .. "/lua/data/icons/path20.png"
local BLANK_ICON <const> = dt.configuration.config_dir .. "/lua/data/icons/blank20.png"
local USER_POWER_ICON <const> = dt.configuration.config_dir .. "/lua/data/icons/path20.png"
local USER_BLANK_ICON <const> = dt.configuration.config_dir .. "/lua/data/icons/blank20.png"
local SYSTEM_POWER_ICON <const> = dt.configuration.data_dir .. "/lua-scripts/data/icons/path20.png"
local SYSTEM_BLANK_ICON <const> = dt.configuration.data_dir .. "/lua-scripts/data/icons/blank20.png"
local LUA_DIR = USER_LUA_DIR
local POWER_ICON = USER_POWER_ICON
local BLANK_ICON = USER_BLANK_ICON
if system_based then
LUA_DIR = SYSTEM_LUA_DIR
POWER_ICON = SYSTEM_POWER_ICON
BLANK_ICON = SYSTEM_BLANK_ICON
end
-- - - - - - - - - - - - - - - - - - - - - - - -
-- P R E F E R E N C E S
-- - - - - - - - - - - - - - - - - - - - - - - -
@@ -1243,7 +1272,7 @@ end
script_manager_running_script = "script_manager"
if check_for_updates or SM_API_VER_REQD > dt.configuration.api_version_string then
if (check_for_updates or SM_API_VER_REQD > dt.configuration.api_version_string) and not system_based then
local repo_data = get_repo_status(LUA_DIR)
local current_branch = get_current_repo_branch(LUA_DIR)
local clean = is_repo_clean(repo_data)
@@ -1325,6 +1354,25 @@ end
scan_scripts(LUA_DIR)
log.msg(log.debug, "finished processing scripts")
if system_based then
-- exec user luarc file if it exists
local luarc = loadfile(USER_LUA_DIR .. "rc")
if luarc then
luarc()
end
if df.test_file(USER_LUA_DIR, "d") then
LUA_DIR = USER_LUA_DIR
scan_scripts(LUA_DIR)
LUA_DIR = SYSTEM_LUA_DIR
end
dt.configuration["lua_dir"] = LUA_DIR
dt.print_log("lua dir is " .. dt.configuration.lua_dir)
-- scan_script(USER_LUA_DIR)
end
-- - - - - - - - - - - - - - - - - - - - - - - -
-- U S E R I N T E R F A C E