Compare commits
31 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
961220f222 | ||
|
|
e831f377bf | ||
|
|
d696e6e3f2 | ||
|
|
db505f1e0a | ||
|
|
57d15a3fa6 | ||
|
|
4d54b5eaba | ||
|
|
dbf0c5d853 | ||
|
|
193a615772 | ||
|
|
447980ddc4 | ||
|
|
8af5476f8d | ||
|
|
c95547caa7 | ||
|
|
b4d3b2901f | ||
|
|
cb6b3161d8 | ||
|
|
2d82eea237 | ||
|
|
3beee93af4 | ||
|
|
68291414f3 | ||
|
|
5662519314 | ||
|
|
28ab065293 | ||
|
|
aed3275943 | ||
|
|
d7aeb43340 | ||
|
|
ea79d10b11 | ||
|
|
e4001f984f | ||
|
|
453d744b69 | ||
|
|
b9cc0dccce | ||
|
|
84fea20ee5 | ||
|
|
e054bfc59d | ||
|
|
8cd10dce68 | ||
|
|
f8d49ccd01 | ||
|
|
25afb41924 | ||
|
|
3001a0dc1a | ||
|
|
b70fdc0ecf |
@@ -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
|
[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
|
[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
|
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
|
[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
|
[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"`.
|
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
|
### Linux or MacOS
|
||||||
|
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ local function preserve_metadata(original, sharpened)
|
|||||||
if exiftool then
|
if exiftool then
|
||||||
dtsys.external_command("exiftool -overwrite_original_in_place -tagsFromFile " .. original .. " " .. sharpened)
|
dtsys.external_command("exiftool -overwrite_original_in_place -tagsFromFile " .. original .. " " .. sharpened)
|
||||||
else
|
else
|
||||||
dt.print_log(MODULE .. " exiftool not found, metadata not preserved")
|
dt.print_log(MODULE_NAME .. " exiftool not found, metadata not preserved")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
129
contrib/auto_tag_modified.lua
Normal file
129
contrib/auto_tag_modified.lua
Normal 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
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
--[[
|
--[[
|
||||||
This file is part of darktable,
|
This file is part of darktable,
|
||||||
copyright (c) 2016 Tobias Jakobs
|
copyright (c) 2016 Tobias Jakobs
|
||||||
|
copyright (c) 2025 Balázs Dura-Kovács
|
||||||
|
|
||||||
darktable is free software: you can redistribute it and/or modify
|
darktable is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
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")
|
local labelDistance = dt.new_widget("label")
|
||||||
labelDistance.label = _("distance:")
|
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
|
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
|
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
|
value = true
|
||||||
}
|
}
|
||||||
|
local entry_gps_ele = dt.new_widget("entry")
|
||||||
|
{
|
||||||
|
tooltip = _("elevation (editable)"),
|
||||||
|
placeholder = _("elevation")
|
||||||
|
}
|
||||||
-- </GUI>
|
-- </GUI>
|
||||||
|
|
||||||
local function select_with_gps()
|
local function select_with_gps()
|
||||||
@@ -294,20 +307,20 @@ local function copy_gps()
|
|||||||
copy_gps_have_data = false
|
copy_gps_have_data = false
|
||||||
else
|
else
|
||||||
copy_gps_have_data = true
|
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
|
copy_gps_latitude = image.latitude
|
||||||
end
|
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
|
copy_gps_longitude = image.longitude
|
||||||
end
|
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
|
copy_gps_elevation = image.elevation
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
label_copy_gps_lat.label = _("latitude: ") .. copy_gps_latitude
|
entry_gps_lat.text = copy_gps_latitude
|
||||||
label_copy_gps_lon.label = _("longitude: ") .. copy_gps_longitude
|
entry_gps_lon.text = copy_gps_longitude
|
||||||
label_copy_gps_ele.label = _("elevation: ") .. copy_gps_elevation
|
entry_gps_ele.text = copy_gps_elevation
|
||||||
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
@@ -317,14 +330,14 @@ local function paste_gps(image)
|
|||||||
local sel_images = dt.gui.action_images
|
local sel_images = dt.gui.action_images
|
||||||
|
|
||||||
for jj,image in ipairs(sel_images) do
|
for jj,image in ipairs(sel_images) do
|
||||||
if (label_copy_gps_lat.value) then
|
if (checkbox_copy_gps_lat.value) then
|
||||||
image.latitude = copy_gps_latitude
|
image.latitude = entry_gps_lat.text
|
||||||
end
|
end
|
||||||
if (label_copy_gps_lon.value) then
|
if (checkbox_copy_gps_lon.value) then
|
||||||
image.longitude = copy_gps_longitude
|
image.longitude = entry_gps_lon.text
|
||||||
end
|
end
|
||||||
if (label_copy_gps_ele.value) then
|
if (checkbox_copy_gps_ele.value) then
|
||||||
image.elevation = copy_gps_elevation
|
image.elevation = entry_gps_ele.text
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -663,13 +676,25 @@ gT.widget = dt.new_widget("box")
|
|||||||
tooltip = _("copy GPS data"),
|
tooltip = _("copy GPS data"),
|
||||||
clicked_callback = copy_gps
|
clicked_callback = copy_gps
|
||||||
},
|
},
|
||||||
label_copy_gps_lat,
|
dt.new_widget("box"){
|
||||||
label_copy_gps_lon,
|
orientation = "horizontal",
|
||||||
label_copy_gps_ele,
|
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")
|
dt.new_widget("button")
|
||||||
{
|
{
|
||||||
label = _("paste GPS data"),
|
label = _("apply GPS data to image"),
|
||||||
tooltip = _("paste GPS data"),
|
tooltip = _("apply GPS data to image"),
|
||||||
clicked_callback = paste_gps
|
clicked_callback = paste_gps
|
||||||
},
|
},
|
||||||
separator2,--------------------------------------------------------
|
separator2,--------------------------------------------------------
|
||||||
|
|||||||
@@ -734,16 +734,33 @@ function dtutils_string.build_substitute_list(image, sequence, variable_string,
|
|||||||
|
|
||||||
local labels = get_colorlabels(image)
|
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
|
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 =
|
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
|
else
|
||||||
emsec = "0"
|
emsec = "0"
|
||||||
eyear, emon, eday, ehour, emin, esec =
|
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
|
end
|
||||||
|
|
||||||
|
|
||||||
local version_multi = #image:get_group_members() > 1 and image.duplicate_index or ""
|
local version_multi = #image:get_group_members() > 1 and image.duplicate_index or ""
|
||||||
|
|
||||||
local replacements = {dtutils_string.get_basename(image.film.path),-- ROLL.NAME
|
local replacements = {dtutils_string.get_basename(image.film.path),-- ROLL.NAME
|
||||||
@@ -753,7 +770,7 @@ function dtutils_string.build_substitute_list(image, sequence, variable_string,
|
|||||||
image.id, -- ID
|
image.id, -- ID
|
||||||
image.duplicate_index, -- VERSION
|
image.duplicate_index, -- VERSION
|
||||||
version_multi, -- VERSION.IF_MULTI
|
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, -- DARKTABLE.VERSION
|
||||||
"", -- DARKTABLE.NAME
|
"", -- DARKTABLE.NAME
|
||||||
string.format("%04d", sequence), -- SEQUENCE
|
string.format("%04d", sequence), -- SEQUENCE
|
||||||
@@ -781,8 +798,8 @@ function dtutils_string.build_substitute_list(image, sequence, variable_string,
|
|||||||
eyear, -- EXIF.YEAR
|
eyear, -- EXIF.YEAR
|
||||||
string.sub(eyear, 3), -- EXIF.YEAR.SHORT
|
string.sub(eyear, 3), -- EXIF.YEAR.SHORT
|
||||||
emon, -- EXIF.MONTH
|
emon, -- EXIF.MONTH
|
||||||
os.date("%B", exiftime2systime(image.exif_datetime_taken)), -- EXIF.MONTH.LONG
|
os.date("%B", exiftime2systime(datetime_taken)), -- EXIF.MONTH.LONG
|
||||||
os.date("%b", exiftime2systime(image.exif_datetime_taken)), -- EXIF.MONTH.SHORT
|
os.date("%b", exiftime2systime(datetime_taken)), -- EXIF.MONTH.SHORT
|
||||||
eday, -- EXIF.DAY
|
eday, -- EXIF.DAY
|
||||||
ehour, -- EXIF.HOUR
|
ehour, -- EXIF.HOUR
|
||||||
"", -- EXIF.HOUR.AMPM
|
"", -- EXIF.HOUR.AMPM
|
||||||
@@ -819,11 +836,11 @@ function dtutils_string.build_substitute_list(image, sequence, variable_string,
|
|||||||
"", -- RATING.ICONS - wont be implemented
|
"", -- RATING.ICONS - wont be implemented
|
||||||
labels, -- LABELS
|
labels, -- LABELS
|
||||||
"", -- LABELS.ICONS - wont be implemented
|
"", -- LABELS.ICONS - wont be implemented
|
||||||
image.title, -- TITLE
|
image.title and image.title or "", -- TITLE
|
||||||
image.description, -- DESCRIPTION
|
image.description and image.description or "", -- DESCRIPTION
|
||||||
image.creator, -- CREATOR
|
image.creator and image.creator or "", -- CREATOR
|
||||||
image.publisher, -- PUBLISHER
|
image.publisher and image.publisher or "", -- PUBLISHER
|
||||||
image.rights, -- RIGHTS
|
image.rights and image.rights or "", -- RIGHTS
|
||||||
"", -- TAGS - wont be implemented
|
"", -- TAGS - wont be implemented
|
||||||
"", -- SIDECAR.TXT - wont be implemented
|
"", -- SIDECAR.TXT - wont be implemented
|
||||||
pictures_folder, -- FOLDER.PICTURES
|
pictures_folder, -- FOLDER.PICTURES
|
||||||
@@ -994,7 +1011,7 @@ local function treat(var_string)
|
|||||||
log.msg(log.info, "ret_val is " .. ret_val)
|
log.msg(log.info, "ret_val is " .. ret_val)
|
||||||
|
|
||||||
elseif string.match(var_string, "SEQUENCE%[") then
|
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 seq_val = tonumber(substitutes[var])
|
||||||
local pat = "%0" .. width .. "d"
|
local pat = "%0" .. width .. "d"
|
||||||
substitutes[var_string] = string.format(pat, start + (seq_val - 1))
|
substitutes[var_string] = string.format(pat, start + (seq_val - 1))
|
||||||
|
|||||||
@@ -34,12 +34,17 @@
|
|||||||
Bill Ferguson <wpferguson@gmail.com>
|
Bill Ferguson <wpferguson@gmail.com>
|
||||||
|
|
||||||
CHANGES
|
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 dt = require "darktable"
|
||||||
local du = require "lib/dtutils"
|
local du = require "lib/dtutils"
|
||||||
-- local df = require "lib/dtutils.file"
|
-- 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 dtsys = require "lib/dtutils.system"
|
||||||
local log = require "lib/dtutils.log"
|
local log = require "lib/dtutils.log"
|
||||||
-- local debug = require "darktable.debug"
|
-- local debug = require "darktable.debug"
|
||||||
@@ -50,9 +55,11 @@ local log = require "lib/dtutils.log"
|
|||||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
local MODULE <const> = "apply_camera_style"
|
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 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
|
-- path separator
|
||||||
local PS <const> = dt.configuration.running_os == "windows" and "\\" or "/"
|
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)
|
local log_level = set_log_level(acs.log_level)
|
||||||
|
|
||||||
|
log.msg(log.debug, "input pattern is " .. pattern)
|
||||||
|
|
||||||
pattern = string.lower(pattern)
|
pattern = string.lower(pattern)
|
||||||
|
log.msg(log.debug, "lower case pattern is " .. pattern)
|
||||||
-- strip off series
|
-- strip off series
|
||||||
pattern = string.gsub(pattern, " series$", "?")
|
pattern = string.gsub(pattern, " series$", "?")
|
||||||
|
log.msg(log.debug, "series stripped off pattern is " .. pattern)
|
||||||
-- match a character
|
-- match a character
|
||||||
if string.match(pattern, "?$") then
|
if string.match(pattern, "r%?%?$") then
|
||||||
-- handle EOS R case
|
-- handle EOS R case
|
||||||
pattern = string.gsub(pattern, "?", ".?")
|
pattern = string.gsub(pattern, "%?%?", ".?")
|
||||||
|
log.msg(log.debug, "matched EOS R pattern is " .. pattern)
|
||||||
else
|
else
|
||||||
pattern = string.gsub(pattern, "?", ".")
|
pattern = string.gsub(pattern, "?", ".")
|
||||||
|
log.msg(log.debug, "didn't match EOS R pattern is " .. pattern)
|
||||||
end
|
end
|
||||||
pattern = string.gsub(pattern, " ", " ?")
|
|
||||||
-- escape dashes
|
-- escape dashes
|
||||||
pattern = string.gsub(pattern, "%-", "%%-")
|
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. [...]
|
-- 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
|
-- anchor the pattern to ensure we don't short match
|
||||||
pattern = "^" .. pattern .. "$"
|
pattern = "^" .. pattern .. "$"
|
||||||
|
log.msg(log.debug, "anchored pattern is " .. pattern)
|
||||||
|
|
||||||
restore_log_level(log_level)
|
restore_log_level(log_level)
|
||||||
|
|
||||||
@@ -223,25 +240,25 @@ local function get_camera_styles()
|
|||||||
log.msg(log.debug, "got " .. style.name)
|
log.msg(log.debug, "got " .. style.name)
|
||||||
|
|
||||||
local parts = du.split(style.name, "|")
|
local parts = du.split(style.name, "|")
|
||||||
parts[2] = string.lower(parts[2])
|
parts[MAKER] = string.lower(parts[MAKER])
|
||||||
log.msg(log.debug, "maker is " .. parts[2])
|
log.msg(log.debug, "maker is " .. parts[MAKER])
|
||||||
|
|
||||||
if not acs.styles[parts[2]] then
|
if not acs.styles[parts[MAKER]] then
|
||||||
acs.styles[parts[2]] = {}
|
acs.styles[parts[MAKER]] = {}
|
||||||
acs.styles[parts[2]]["styles"] = {}
|
acs.styles[parts[MAKER]]["styles"] = {}
|
||||||
acs.styles[parts[2]]["patterns"] = {}
|
acs.styles[parts[MAKER]]["patterns"] = {}
|
||||||
end
|
end
|
||||||
if parts[3] then
|
if parts[STYLE] then
|
||||||
if not string.match(parts[3], "]") then
|
if not string.match(parts[STYLE], "]") then
|
||||||
table.insert(acs.styles[parts[2]].styles, style)
|
table.insert(acs.styles[parts[MAKER]].styles, style)
|
||||||
local processed_pattern = process_pattern(parts[#parts])
|
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)
|
log.msg(log.debug, "pattern for " .. style.name .. " is " .. processed_pattern)
|
||||||
else
|
else
|
||||||
local processed_patterns = process_set(parts[3])
|
local processed_patterns = process_set(parts[STYLE])
|
||||||
for _, pat in ipairs(processed_patterns) do
|
for _, pat in ipairs(processed_patterns) do
|
||||||
table.insert(acs.styles[parts[2]].styles, style)
|
table.insert(acs.styles[parts[MAKER]].styles, style)
|
||||||
table.insert(acs.styles[parts[2]].patterns, pat)
|
table.insert(acs.styles[parts[MAKER]].patterns, pat)
|
||||||
log.msg(log.debug, "pattern for " .. style.name .. " is " .. pat)
|
log.msg(log.debug, "pattern for " .. style.name .. " is " .. pat)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -322,9 +339,11 @@ local function has_style_tag(image, tag_name)
|
|||||||
log.msg(log.debug, "looking for tag " .. tag_name)
|
log.msg(log.debug, "looking for tag " .. tag_name)
|
||||||
|
|
||||||
for _, tag in ipairs(image:get_tags()) do
|
for _, tag in ipairs(image:get_tags()) do
|
||||||
log.msg(log.debug, "checking against " .. tag.name)
|
log.msg(log.debug, "got attached tag " .. tag.name)
|
||||||
if tag.name == tag_name then
|
local cleaned_tag_name = string.gsub(tag_name, "_l10n_", "")
|
||||||
log.msg(log.debug, "matched tag " .. tag_name)
|
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
|
result = true
|
||||||
end
|
end
|
||||||
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 1200d", "eos rebel t5")
|
||||||
model = string.gsub(model, "eos 1300d", "eos rebel t6")
|
model = string.gsub(model, "eos 1300d", "eos rebel t6")
|
||||||
model = string.gsub(model, "eos 2000d", "eos rebel t7")
|
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
|
end
|
||||||
|
|
||||||
restore_log_level(log_level)
|
restore_log_level(log_level)
|
||||||
@@ -385,14 +404,15 @@ local function apply_style_to_images(images)
|
|||||||
if acs.styles[maker] then
|
if acs.styles[maker] then
|
||||||
local no_match = true
|
local no_match = true
|
||||||
for i, pattern in ipairs(acs.styles[maker].patterns) do
|
for i, pattern in ipairs(acs.styles[maker].patterns) do
|
||||||
|
log.msg(log.debug, "pattern is " .. pattern)
|
||||||
if string.match(model, pattern) or
|
if string.match(model, pattern) or
|
||||||
(i == #acs.styles[maker].patterns and string.match(pattern, "generic")) then
|
(i == #acs.styles[maker].patterns and string.match(pattern, "generic")) then
|
||||||
local tag_name = "darktable|style|" .. acs.styles[maker].styles[i].name
|
local tag_name = "darktable|style|" .. acs.styles[maker].styles[i].name
|
||||||
if not has_style_tag(image, tag_name) then
|
if not has_style_tag(image, tag_name) then
|
||||||
image:apply_style(acs.styles[maker].styles[i])
|
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)
|
log.msg(log.info, "applied style " .. acs.styles[maker].styles[i].name .. " to " .. image.filename)
|
||||||
end
|
end
|
||||||
|
no_match = false
|
||||||
log.log_level(loglevel)
|
log.log_level(loglevel)
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
|
|||||||
267
official/regenerate_thumbnails.lua
Normal file
267
official/regenerate_thumbnails.lua
Normal 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
|
||||||
@@ -44,6 +44,10 @@ local function _(msg)
|
|||||||
return gettext(msg)
|
return gettext(msg)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local NIX_OPEN <const> = "xdg-open "
|
||||||
|
local MAC_OPEN <const> = "open "
|
||||||
|
local WIN_OPEN <const> = "start "
|
||||||
|
|
||||||
-- return data structure for script_manager
|
-- return data structure for script_manager
|
||||||
|
|
||||||
local script_data = {}
|
local script_data = {}
|
||||||
@@ -63,8 +67,8 @@ script_data.show = nil -- only required for libs since the destroy_method only h
|
|||||||
dt.preferences.register
|
dt.preferences.register
|
||||||
("selection_to_pdf","Open with","string",
|
("selection_to_pdf","Open with","string",
|
||||||
_("a pdf viewer"),
|
_("a pdf viewer"),
|
||||||
_("can be an absolute pathname or the tool may be in the PATH"),
|
_("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"),
|
||||||
"xdg-open")
|
"")
|
||||||
|
|
||||||
local title_widget = dt.new_widget("entry") {
|
local title_widget = dt.new_widget("entry") {
|
||||||
placeholder = _("title")
|
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.
|
-- 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
|
-- so \includegraphics{file.01.jpg} wont work. We need to output the filename
|
||||||
-- and extention separated, e.g: \includegraphics{{file.01}.jpg}
|
-- 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,"\\begin{minipage}[b]{"..width.."\\textwidth}\n")
|
||||||
my_write(latexfile,"\\includegraphics[width=\\textwidth]{{"..filenoext.."}"..ext.."}\\newline\n")
|
my_write(latexfile,"\\includegraphics[width=\\textwidth]{{"..filenoext.."}"..ext.."}\\newline\n")
|
||||||
my_write(latexfile,"\\centering{"..i..": \\verb|"..title.."|}\n")
|
my_write(latexfile,"\\centering{"..i..": \\verb|"..title.."|}\n")
|
||||||
@@ -138,7 +143,7 @@ dt.register_storage("export_pdf", _("export thumbnails to pdf"),
|
|||||||
end
|
end
|
||||||
local thumbs_per_line = no_of_thumbs_widget.value
|
local thumbs_per_line = no_of_thumbs_widget.value
|
||||||
thumbs_per_line = tonumber(thumbs_per_line)
|
thumbs_per_line = tonumber(thumbs_per_line)
|
||||||
width = (1/thumbs_per_line) - 0.01
|
width = (1 / thumbs_per_line) - 0.01
|
||||||
|
|
||||||
local preamble = [[
|
local preamble = [[
|
||||||
\documentclass[a4paper,10pt]{article}
|
\documentclass[a4paper,10pt]{article}
|
||||||
@@ -148,31 +153,31 @@ dt.register_storage("export_pdf", _("export thumbnails to pdf"),
|
|||||||
\usepackage{geometry}
|
\usepackage{geometry}
|
||||||
\geometry{a4paper,left=5mm,right=5mm, top=5mm, bottom=5mm}
|
\geometry{a4paper,left=5mm,right=5mm, top=5mm, bottom=5mm}
|
||||||
\begin{document}
|
\begin{document}
|
||||||
{\Large\bfseries ]]..my_title..[[} \\
|
{\Large\bfseries ]] .. my_title .. [[} \\
|
||||||
\bigskip\bigskip
|
\bigskip\bigskip
|
||||||
]]
|
]]
|
||||||
|
|
||||||
local errmsg
|
local errmsg
|
||||||
local latexfile
|
local latexfile
|
||||||
latexfile,errmsg=io.open(filename,"w")
|
latexfile,errmsg = io.open(filename, "w")
|
||||||
if not latexfile then
|
if not latexfile then
|
||||||
error(errmsg)
|
error(errmsg)
|
||||||
end
|
end
|
||||||
my_write(latexfile,preamble)
|
my_write(latexfile, preamble)
|
||||||
local i = 1
|
local i = 1
|
||||||
for img,file in pairs(image_table) do
|
for img, file in pairs(image_table) do
|
||||||
thumbnail(latexfile,i,img,file)
|
thumbnail(latexfile, i, img, file)
|
||||||
if i % thumbs_per_line == 0 then
|
if i % thumbs_per_line == 0 then
|
||||||
my_write(latexfile,"\n\\bigskip\n")
|
my_write(latexfile, "\n\\bigskip\n")
|
||||||
end
|
end
|
||||||
i = i+1
|
i = i + 1
|
||||||
end
|
end
|
||||||
my_write(latexfile,ending)
|
my_write(latexfile,ending)
|
||||||
latexfile:close()
|
latexfile:close()
|
||||||
|
|
||||||
-- convert to PDF
|
-- convert to PDF
|
||||||
local dir=string.gsub(filename, "(.*/)(.*)", "%1")
|
local dir = string.gsub(filename, "(.*/)(.*)", "%1")
|
||||||
local locfile=string.gsub(filename, "(.*/)(.*)", "%2")
|
local locfile = string.gsub(filename, "(.*/)(.*)", "%2")
|
||||||
local command = "pdflatex -halt-on-error -output-directory "..dir.." "..locfile
|
local command = "pdflatex -halt-on-error -output-directory "..dir.." "..locfile
|
||||||
local result = dt.control.execute(command)
|
local result = dt.control.execute(command)
|
||||||
if result ~= 0 then
|
if result ~= 0 then
|
||||||
@@ -181,9 +186,18 @@ dt.register_storage("export_pdf", _("export thumbnails to pdf"),
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- open the PDF
|
-- 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 = 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)
|
local result = dt.control.execute(command)
|
||||||
if result ~= 0 then
|
if result ~= 0 then
|
||||||
dt.print(_("problem running pdf viewer")) -- this one is probably usefull to the user
|
dt.print(_("problem running pdf viewer")) -- this one is probably usefull to the user
|
||||||
|
|||||||
Reference in New Issue
Block a user