171 Commits

Author SHA1 Message Date
wpferguson
f272aeb9fe Merge pull request #335 from wpferguson/revert-dt35-api-changes
Revert API 6.1+ compatibility changes.  Partially fixes #334
2021-06-19 16:38:36 -04:00
wpferguson
cf26b82d87 Merge pull request #336 from wpferguson/312_image_path_in_ui
Fix 312 - change case of image_path_in_ui module label
2021-06-19 14:01:46 -04:00
Bill Ferguson
2041fb34c9 [image_path_in_ui] changed case of module title to respect darktable
UI.
2021-06-19 13:57:39 -04:00
Bill Ferguson
4b63240ab9 Reverted register_event calls back to API 6.1.0 2021-06-11 21:44:38 -04:00
Bill Ferguson
9d59479049 Revert changes to accomadate API changes greater than 6.1 2021-06-11 19:47:43 -04:00
wpferguson
350cdfa436 Merge pull request #333 from wpferguson/fix_quicktag
Fix contrib/quicktag
2021-06-02 23:44:26 -04:00
Bill Ferguson
15de64dcf5 [contrib/quicktag] changed new entry field is_password setting to false
so that the user can see what they are typing.
2021-06-02 23:41:02 -04:00
wpferguson
d9c2519a83 Merge pull request #331 from wpferguson/fix_HDRmerge
Fix HDRmerge
2021-03-21 23:34:14 -04:00
wpferguson
9885e34f82 [Changelog] Added latest changes 2021-03-20 00:01:44 -04:00
wpferguson
ed0adfbae1 [Changelog] Added latest changes 2021-03-20 00:01:25 -04:00
wpferguson
beafb6c21b [HDRmerge] fixed crash resulting users renaming images from
camera default.

           Minor code cleanup
2021-03-19 23:52:28 -04:00
supertobi
7810791991 Merge pull request #330 from scheckmedia/master
photils plugin
2021-03-15 13:36:04 +01:00
Tobias Scheck
1d10d5234f refactore print method 2021-03-15 11:41:52 +01:00
Tobias Scheck
9900f46be4 add option to apply selected tags from a single image to multiple images (close #3); add setting parameter to enable/disable the export of an image before tag suggestion (close #5) 2021-03-15 11:36:37 +01:00
wpferguson
0d2c4dfb3a Merge pull request #329 from wpferguson/gimp_detached
GIMP run detached
2021-02-25 21:07:05 -05:00
wpferguson
752e27d97f Added detached mode to Edit with GIMP so that GIMP can keep running and accepting new images 2021-02-25 21:04:59 -05:00
wpferguson
33523fbe36 Merge pull request #328 from wpferguson/doc_updates
Update ChangeLog
2021-02-24 20:18:56 -05:00
wpferguson
db47dd5110 Update for Mark64/ext_editor_darkroom 2021-02-24 20:11:30 -05:00
wpferguson
a71097a8c9 Merge pull request #327 from Mark-64/ext_editor_darkroom
External editors: make gui visible in darkroom
2021-02-24 20:02:30 -05:00
U-DESKTOP-HQME86J\marco
931e448ebd more compact code 2021-02-24 19:21:32 +01:00
U-DESKTOP-HQME86J\marco
abd8bf4a60 option to display module in darkroom 2021-02-24 14:14:38 +01:00
U-DESKTOP-HQME86J\marco
aee1f82d04 restore current module registration 2021-02-23 07:40:30 +01:00
U-DESKTOP-HQME86J\marco
8112472df5 restore initialization line deleted by mistake 2021-02-22 08:17:46 +01:00
U-DESKTOP-HQME86J\marco
c9fa13b97b revert MAX_EDITORS to 9 2021-02-21 20:59:30 +01:00
U-DESKTOP-HQME86J\marco
73cd301ff4 ext_editor visible in darkroom 2021-02-21 20:55:23 +01:00
wpferguson
aa33ae0706 Merge pull request #325 from wpferguson/doc_updates
Update documentation
2021-02-19 17:30:13 -05:00
wpferguson
4e9c45c162 Updated README.md with links to the lua documentation. Added fujifilm_dynamic_range script to contrib. Added ChangeLog.md to keep track of recent changes. 2021-02-19 17:17:53 -05:00
wpferguson
f35cea75d3 Merge pull request #324 from wpferguson/API_6_2_3_register_action_changes
API 6.2.3 compatibility
2021-02-17 22:30:35 -05:00
wpferguson
4053ceb9e5 [API 6.2.3] Added changes for API 6.2.3 compatibility 2021-02-17 22:24:02 -05:00
wpferguson
448da35327 Merge pull request #322 from wpferguson/bugfix_select_untagged
fix select_untagged
2021-02-10 14:53:43 -05:00
wpferguson
6d9c4c90ba Used image table returned to callback, and returned selection table to caller so that it could do the selection. 2021-02-10 14:52:03 -05:00
wpferguson
5b8282e933 Merge pull request #321 from wpferguson/fix_6_2_1
Fix API 6.2.1 transition
2021-02-10 00:21:20 -05:00
wpferguson
b1498aa664 inline if didn't work. Added intermediate register_event function in transition library 2021-02-10 00:18:48 -05:00
wpferguson
2b28f021ee Merge pull request #320 from wpferguson/fix_6_2_2
fix API 6.2.2 compatibility
2021-02-09 23:38:56 -05:00
wpferguson
dc4938c377 inline if didn't work. Replaced with full if/else 2021-02-09 23:36:54 -05:00
wpferguson
69b846a856 Merge pull request #319 from wpferguson/api_6_2_2_register_selection
API 6.2.2 compatibility
2021-02-04 23:07:56 -05:00
wpferguson
1460396d4f [contrib/select_untagged] Added check for API 6.2.2 and added name
field to register_selection if it is
2021-02-04 23:04:21 -05:00
wpferguson
b9804d9d48 Merge pull request #318 from wpferguson/api_6_2_1_lua_event_changes
Added compatibility for lua events API change 6.2.1.
2021-02-01 18:31:19 -05:00
wpferguson
ade7008127 Added compatibility for lua events API change 6.2.1. 2021-02-01 18:27:20 -05:00
wpferguson
da0235ab27 Merge pull request #317 from wpferguson/correct_api_version
[dtutils] fixed api version check
2021-01-21 21:36:36 -05:00
wpferguson
c17e832572 [dtutils] fixed api version check 2021-01-21 21:34:43 -05:00
wpferguson
c12d6f01e7 Merge pull request #316 from wpferguson/add_database_get_image_to_find_by_image_id
add database.get_image() to dutils.find_image_by_id()
2021-01-21 21:26:08 -05:00
wpferguson
778ad2ce20 [dtutils] added database.get_image() to find_image_by_id() for users with lua API 6.2.0 or greater 2021-01-21 21:20:17 -05:00
wpferguson
33ef58ac97 Merge pull request #315 from schwerdf/master
New utility function for random image access by ID.
2021-01-19 17:37:23 -05:00
wpferguson
8091ba9398 Merge pull request #313 from chrisaga/master
copy_attach_detachtags.lua localization proposal
2021-01-19 14:20:09 -05:00
August Schwerdfeger
8e0bf9e991 Corrected names in documentation of 'find_image_by_id'. 2021-01-19 01:34:36 -06:00
August Schwerdfeger
daee82aa6a Added a new utility function to look up an image in the database by ID. 2021-01-19 01:05:50 -06:00
chrisaga
359a1fa3a9 As discussed, localize module name in GUI 2021-01-10 19:54:10 +01:00
wpferguson
021b32c1d4 Merge pull request #314 from dtorop/fujifilm-dynamic-range
Fujifilm dynamic range
2021-01-07 23:38:11 -05:00
Dan Torop
1d1eb6a768 fujifilm-dynamic-range: remove translations, use full exiftool path
Suggestions as per @wpferguson:

"We came to a decision a while ago to not translate debug
messages(i.e. print_log() and print_error()) because the author might
not be able to read the output if it was a language they weren't
familiar with. So the only thing we translate are labels, tooltips,
and dt.print() messages."

"df.check_if_bin_exists() returns the full path to the
executable. Using the returned value would let the script run on
windows and macos too."
2021-01-07 22:55:55 -05:00
Dan Torop
a9fd0718b0 fujifilm-dynamic-range: skip non-Fuji non-raws and clean-ups
Don't bother to pull EXIF data unless the imported image is a Fujifilm
raw.

Cleanup conditionals for error handling by immediately returning on
failure, avoiding deep nested conditionals.

Cleanup log/error output with clearer messages.
2021-01-06 11:21:05 -05:00
Dan Torop
6341a0a459 fujifilm-dynamic-range: better logging and error handling
Use dt.print_log() for log messages. Print error output if no results
or results not parseable from exiftool.

Also update the date, it's 2021.
2021-01-06 10:28:52 -05:00
Dan Torop
952b8b2eb2 fujifilm-dynamic-range: better exiftool parsing & comments
Get tab-delimited output from exiftool without rounding.  Add comments
to explain the choice of tags being read and tool to read them.
2021-01-06 10:11:59 -05:00
Dan Torop
b08d7f27d2 fujifilm_dynamic_range : first draft
Read RawExposureBias and adjust "EXIF Exposure Bias" based upon this.
2021-01-05 22:38:27 -05:00
chrisaga
a71889021f add copy_attach_detachtags.po header 2021-01-03 21:02:25 +01:00
chrisaga
367631af99 copy_attach_detachtags.lua localization 2021-01-03 20:55:45 +01:00
wpferguson
62753d1a50 Merge pull request #309 from chrisaga/master
script_manager.lua function clear_button reset tooltip
2020-12-29 11:12:26 -05:00
chrisaga
dfe589e843 script_manager.lua function clear_button must reset tooltip too 2020-12-28 19:18:35 +01:00
wpferguson
d09574bb17 Merge pull request #308 from chrisaga/master
script_manager.lua localization proposal (including minor changes in …
2020-12-28 12:50:14 -05:00
chrisaga
2be12e5b37 script_manager.lua localization proposal (including minor changes in the script) 2020-12-28 10:42:15 +01:00
wpferguson
d2086b6480 Merge pull request #307 from chrisaga/master
More clear_GPS.lua localization
2020-12-27 20:40:09 -05:00
chrisaga
132668d04c More clear_GPS.lua localization 2020-12-27 18:22:19 +01:00
wpferguson
0a4aa95965 Merge pull request #306 from chrisaga/localize-copy_paste_metadata.lua
Localize copy paste metadata.lua
2020-12-26 17:18:21 -05:00
wpferguson
af1e774d1f Merge pull request #305 from chrisaga/patch-1
Update clear_GPS.lua
2020-12-26 17:16:45 -05:00
chrisaga
e5271d79a0 Localize copy_paste_metadata.lua 2020-12-26 13:27:53 +01:00
chrisaga
dfd714540e fr po-file for copy_paste_metadata 2020-12-26 13:21:00 +01:00
chrisaga
a0fd22be19 Update clear_GPS.lua
Changed first line of header which was referring to another plugin (gimp.lua)
2020-12-26 12:08:38 +01:00
wpferguson
c0dc55b18e Merge pull request #303 from wpferguson/script_manager_3.4
Merry Christmas aka new script manager
2020-12-24 09:56:22 -05:00
wpferguson
258def1cf8 Merge pull request #304 from wpferguson/logging_cleanup
Reduce the amount of trace information in log messages.
2020-12-24 09:55:24 -05:00
wpferguson
b2095fd947 Merge pull request #299 from wpferguson/fix_check_if_bin_exists_and_executable_paths
Fix check if bin exists and executable paths
2020-12-24 09:54:52 -05:00
wpferguson
e51278f76e Merge branch 'master' into fix_check_if_bin_exists_and_executable_paths 2020-12-24 09:54:29 -05:00
wpferguson
9af60063d8 [dtutils.log] changed the amount of trace information based on log level.
script, caller, line number, msg were printed for all log
              levels, but changed to return less info except in log.debug
              log.error, and log.critical messages.  All messages print
              the script name except for log.screen.
2020-12-23 22:52:46 -05:00
wpferguson
37b523f989 [script_manager] rewrite of script_manager for a better fit with
darktable 3.4 and the new scripts_installer. Changed
                 interface to paged instead of scrolled so that less
                 screen space is required.  Added capability to
                 install/update external repositories and seamlessly
                 integrate with script_manager.
2020-12-23 19:54:16 -05:00
wpferguson
622a9ebab4 Merge pull request #301 from pitbuster/master
Sanitize filename in fujifilm_ratings.lua to handle spaces.
2020-12-14 00:07:28 -05:00
Felipe Contreras
b26ec58f9f Sanitize filename in fujifilm_ratings.lua to handle spaces. 2020-12-13 22:00:39 -03:00
wpferguson
976ad4ab17 Merge pull request #297 from wpferguson/remove_yield
Remove official/yield.lua
2020-11-26 19:08:57 -05:00
wpferguson
8dcf19834c Merge pull request #298 from wpferguson/add_sanitize_decimals_to_enfuseAdvanced
Add sanitize_decimals() to enfuseAdvanced
2020-11-25 19:42:25 -05:00
Bill Ferguson
43315bb9cc [enfuseAdvanced] added a sanitize_decimals function to sanitize the command lines. 2020-11-25 19:39:49 -05:00
Bill Ferguson
4ab20d8088 Removed official/yield.lua since it was only required for lua API 3.x and less (darktable 2.0 and before). Removed require from scripts that had included it. 2020-11-21 18:33:26 -05:00
wpferguson
485de32bb4 Merge pull request #294 from wpferguson/fix_enfuseAdvanced_decimal_separator
fix enfuseAdvanced crash on comma decimal separator
2020-11-19 00:38:06 -05:00
Bill Ferguson
536b9726b2 [enfuseAdvanced] Added check for comma decimal separator. Replace with period if found. 2020-11-19 00:35:17 -05:00
wpferguson
41ae43e741 Merge pull request #293 from wpferguson/fix_multi_os_crash
Fix multi_os crash
2020-11-17 19:05:23 -05:00
Bill Ferguson
b5b49245fa Needlessly creating the executable path preference for the ufraw-batch executable on linux caused the value to be saved as the startup directory, which in turn caused a crash when trying to extract the embedded jpg. 2020-11-17 18:53:54 -05:00
wpferguson
d172ac7049 Merge pull request #290 from wpferguson/get_enfusedAdvanced_running
Fix translation in enfuseAdvanced
2020-09-16 00:10:23 -04:00
Bill Ferguson
8808306a5f [contrib/enfusedAdvanced.lua] _ was declared globally in a subroutine, thus negating translation once the subroutine was called. 2020-09-16 00:05:53 -04:00
wpferguson
00dac577f6 Merge pull request #289 from wpferguson/fix_enfuseAdvanced_print_error
fix print errors in enfuseAdvanced - this takes care of the current last comment in #186
2020-09-14 20:56:10 -04:00
Bill Ferguson
85c218b350 [contrib/enfuseAdvanced] fixed translations in for loops by changing the unused variable _ to x so that the translation function _() doesn't get replaced with the value of _. 2020-09-14 20:47:29 -04:00
supertobi
6f71ef4d6b Merge pull request #288 from homer3018/patch-1
Typo
2020-09-11 16:04:19 +02:00
homer3018
394cbdb454 Typo 2020-09-11 00:05:22 +02:00
supertobi
62e2a7969d Merge pull request #287 from darktable-org/supertobi-patch-1
README - suggested update #286 by heviiguy
2020-09-06 20:13:28 +02:00
supertobi
d9c284b54d Update README.md
README - suggested update #286
2020-09-06 20:01:34 +02:00
wpferguson
bd2bc3659c Merge pull request #284 from wpferguson/update_install_instructions
Update README.md
2020-08-23 00:40:49 -04:00
Bill Ferguson
f76fa01240 Updated install instructions adding flatpak information and updating preferred way to enable and disable scripts. 2020-08-18 12:08:23 -04:00
wpferguson
45d62f418c Merge pull request #283 from wpferguson/script_manager_collapsible
script_manager resizes smaller
2020-08-16 15:59:06 -04:00
Bill Ferguson
650325257b made button a local variable 2020-08-16 15:57:41 -04:00
Bill Ferguson
a0a8a61d56 Enabled latest dev changes in lua API so that script_manager responds better to panel resizing 2020-08-16 15:52:57 -04:00
wpferguson
998732287b Merge pull request #282 from wpferguson/change_name_to_id
Fix script_manager not starting (and any other register_lib module)
2020-08-16 13:21:48 -04:00
Bill Ferguson
509c7da384 changed darktable.current_view().name to darktable.current_view().id for view check because name is translated and id is not. 2020-08-16 13:18:27 -04:00
wpferguson
771e03ce76 Merge pull request #279 from wpferguson/278_fix_register_lib_hang
278 fix register lib hang
2020-08-14 20:23:54 -04:00
supertobi
7d9b8dbdda Update video_ffmpeg.lua
added more framerate options
2020-08-10 15:21:25 +02:00
Bill Ferguson
912ae93d10 Added check to ensure we are in lighttable view prior to callling darktable.register_lib. If darktable was invoked in single image (darkroom) mode, then an event handler is registered to detect the change from darkroom mode to lighttable mode so that we can then call darktable.register_lib. 2020-08-09 01:56:48 -04:00
Bill Ferguson
b613cc266a Added check to ensure we are in lighttable view prior to callling darktable.register_lib. If darktable was invoked in single image (darkroom) mode, then an event handler is registered to detect the change from darkroom mode to lighttable mode so that we can then call darktable.register_lib. 2020-08-09 01:56:38 -04:00
Bill Ferguson
dfb8d4e7c6 Added check to ensure we are in lighttable view prior to callling darktable.register_lib. If darktable was invoked in single image (darkroom) mode, then an event handler is registered to detect the change from darkroom mode to lighttable mode so that we can then call darktable.register_lib. 2020-08-09 01:48:36 -04:00
Bill Ferguson
b8e3ec4302 Added check to ensure we are in lighttable view prior to callling darktable.register_lib. If darktable was invoked in single image (darkroom) mode, then an event handler is registered to detect the change from darkroom mode to lighttable mode so that we can then call darktable.register_lib. 2020-08-09 01:43:31 -04:00
Bill Ferguson
d4e21b7877 Added check to ensure we are in lighttable view prior to callling darktable.register_lib. If darktable was invoked in single image (darkroom) mode, then an event handler is registered to detect the change from darkroom mode to lighttable mode so that we can then call darktable.register_lib. 2020-08-09 01:43:20 -04:00
Bill Ferguson
d10cf968f1 Added check to ensure we are in lighttable view prior to callling darktable.register_lib. If darktable was invoked in single image (darkroom) mode, then an event handler is registered to detect the change from darkroom mode to lighttable mode so that we can then call darktable.register_lib. 2020-08-09 01:33:09 -04:00
Bill Ferguson
880ec7fc58 Added check to ensure we are in lighttable view prior to callling darktable.register_lib. If darktable was invoked in single image (darkroom) mode, then an event handler is registered to detect the change from darkroom mode to lighttable mode so that we can then call darktable.register_lib. 2020-08-09 01:26:45 -04:00
Bill Ferguson
432b6b5dd7 Added check to ensure we are in lighttable view prior to callling darktable.register_lib. If darktable was invoked in single image (darkroom) mode, then an event handler is registered to detect the change from darkroom mode to lighttable mode so that we can then call darktable.register_lib. 2020-08-09 01:21:17 -04:00
Bill Ferguson
5f5ad426bf Added check to ensure we are in lighttable view prior to callling darktable.register_lib. If darktable was invoked in single image (darkroom) mode, then an event handler is registered to detect the change from darkroom mode to lighttable mode so that we can then call darktable.register_lib. 2020-08-09 01:01:33 -04:00
Bill Ferguson
52acdb9036 Added check to ensure we are in lighttable view prior to callling darktable.register_lib. If darktable was invoked in single image (darkroom) mode, then an event handler is registered to detect the change from darkroom mode to lighttable mode so that we can then call darktable.register_lib. 2020-08-09 00:45:27 -04:00
Bill Ferguson
138b23674a Added check to ensure we are in lighttable view prior to callling darktable.register_lib. If darktable was invoked in single image (darkroom) mode, then an event handler is registered to detect the change from darkroom mode to lighttable mode so that we can then call darktable.register_lib. 2020-08-09 00:36:43 -04:00
Bill Ferguson
8a710798f7 Added check to ensure we are in lighttable view prior to callling darktable.register_lib. If darktable was invoked in single image (darkroom) mode, then an event handler is registered to detect the change from darkroom mode to lighttable mode so that we can then call darktable.register_lib. 2020-08-09 00:17:34 -04:00
Bill Ferguson
be5557080b Added check to ensure we are in lighttable view prior to callling darktable.register_lib. If darktable was invoked in single image (darkroom) mode, then an event handler is registered to detect the change from darkroom mode to lighttable mode so that we can then call darktable.register_lib. 2020-08-08 23:38:48 -04:00
Bill Ferguson
994b9c6472 Added check to ensure we are in lighttable view prior to callling darktable.register_lib. If darktable was invoked in single image (darkroom) mode, then an event handler is registered to detect the change from darkroom mode to lighttable mode so that we can then call darktable.register_lib. 2020-08-08 23:28:50 -04:00
Bill Ferguson
d05536bed4 Added check to ensure we are in lighttable view prior to callling darktable.register_lib. If darktable was invoked in single image (darkroom) mode, then an event handler is registered to detect the change from darkroom mode to lighttable mode so that we can then call darktable.register_lib. 2020-08-08 23:21:54 -04:00
Bill Ferguson
cc4f1d7251 Added check to ensure we are in lighttable view prior to callling darktable.register_lib. If darktable was invoked in single image (darkroom) mode, then an event handler is registered to detect the change from darkroom mode to lighttable mode so that we can then call darktable.register_lib. 2020-08-08 23:11:33 -04:00
Bill Ferguson
2ddd0965cd Added check to ensure we are in lighttable view prior to callling darktable.register_lib. If darktable was invoked in single image (darkroom) mode, then an event handler is registered to detect the change from darkroom mode to lighttable mode so that we can then call darktable.register_lib. 2020-08-08 22:40:54 -04:00
Bill Ferguson
4e68e420cc removed debugging print statemant 2020-08-08 22:40:40 -04:00
Bill Ferguson
50be8a9240 Added check to ensure we are in lighttable view prior to callling darktable.register_lib. If darktable was invoked in single image (darkroom) mode, then an event handler is registered to detect the change from darkroom mode to lighttable mode so that we can then call darktable.register_lib. 2020-08-08 22:11:29 -04:00
Bill Ferguson
d1e330eee0 Added check to ensure we are in lighttable view prior to callling
darktable.register_lib.  If darktable was invoked in single
image (darkroom) mode, then an event handler is registered to
detect the change from darkroom mode to lighttable mode so that
we can then call darktable.register_lib.
2020-08-08 22:01:58 -04:00
supertobi
6aa5893b5f Merge pull request #277 from wpferguson/update_readme
Update README.md
2020-08-04 21:32:43 +02:00
Bill Ferguson
797d668ebb Fixed typo 2020-08-04 11:11:41 -04:00
Bill Ferguson
b23595ff54 Added latest scripts 2020-08-03 18:52:28 -04:00
wpferguson
6903f8385b Merge pull request #267 from wpferguson/image_time
Image time
2020-08-02 17:36:24 -04:00
wpferguson
e8205c6435 Merge pull request #276 from wpferguson/executable_manager_feedback
executable_manager provide feedback
2020-08-02 17:35:03 -04:00
wpferguson
c114856699 Merge pull request #275 from camjc/patch-1
Typo in README
2020-07-19 15:39:58 -04:00
Bill Ferguson
57a9a8495c made newly added strings translatable 2020-07-19 15:38:08 -04:00
Bill Ferguson
53bb95e6fd Added entry widget to display the current setting, or a placeholder specifying what would or should happen depending on operating system to provide visual feedback. 2020-07-19 13:13:24 -04:00
Cameron Chamberlain
a40fe3099d Typo in README 2020-07-19 10:54:48 +10:00
wpferguson
8d38ea0cf2 Merge pull request #270 from Mark-64/RL_output_sharpen_doc
add doc comments to RL_output_sharpen
2020-07-05 20:51:14 -04:00
wpferguson
ac81c95f7e Merge pull request #271 from Mark-64/ext_editor_add_doc
add documentation comments to ext_editor
2020-07-05 20:50:14 -04:00
wpferguson
48b915b0b2 Merge pull request #247 from noahwc/exportlut
Add an exporthaldclut lighttable module
2020-07-05 20:48:22 -04:00
Noah
593917db9a Fix gettext implementation 2020-07-04 23:20:30 -07:00
U-DESKTOP-HQME86J\marco
2d49b49bec add doc comments to ext_editor 2020-07-04 10:45:59 +02:00
U-DESKTOP-HQME86J\marco
323c8b6845 add doc comments 2020-07-04 10:27:06 +02:00
Bill Ferguson
e5ab30006b Added reset function. Changed namespace to img_time. 2020-06-24 21:51:40 -04:00
Bill Ferguson
14b97cdbd9 Created image_time.lua to adjust non-destructively adjust image time. 2020-06-21 17:14:36 -04:00
wpferguson
8f0f0a5298 Merge pull request #265 from wpferguson/correct_OpenInExplorer_shortcut
Fix OpenInExplorer shortcut function call
2020-06-21 16:37:27 -04:00
Bill Ferguson
497dbc8eaa Fixed function call arguments in shortcut. 2020-06-21 16:32:14 -04:00
wpferguson
11baf14280 Merge pull request #263 from wpferguson/preklov_OpenInExplorer_use_links
OpenInExplorer links option - This is @preklov's PR and he deserves the credit for the changes.  I just wasn't git ninja enough to figure out how to fix the problems, so I pulled it into a local branch and fixed it.
2020-06-20 15:02:42 -04:00
Bill Ferguson
948e8690dd Pulled preklov's branch, resolved conflicts, then merged into new branch with only 1 commit, essentially squashing the delete and replace file commits. 2020-06-20 14:49:31 -04:00
Noah
802c17d590 Added translated text 2020-06-16 01:59:43 -07:00
Noah
71e72b688f Exported luts now have folder hierarchy 2020-06-16 01:50:59 -07:00
supertobi
877b56ad67 Merge pull request #261 from scheckmedia/master
move function to create temp files to dtutils/file.lua
2020-06-15 14:08:03 +02:00
Tobias Scheck
87502fb17f move function to create temp files to dtutils/file.lua 2020-06-15 11:16:14 +02:00
supertobi
ed3e141601 Merge pull request #259 from GLLM/patch-1
Add the possibility to define a shortcut for OpenInExplorer LUA script
2020-06-15 10:33:30 +02:00
supertobi
f66d3ed3aa Merge pull request #236 from Mark-64/ext_editor_v4
Ext editor v4
2020-06-15 10:32:13 +02:00
supertobi
5488e45c78 Merge pull request #256 from scheckmedia/master
add photils plugin
2020-06-15 10:27:38 +02:00
Tobias Scheck
72bd66d3f5 add option to display confidence value, add notice that windows version is not available yet 2020-06-14 08:57:17 +02:00
Tobias Scheck
1378441dfa change labels to lower case to fit darktable style 2020-06-14 07:47:28 +02:00
GLLM
26d97b8cdf Update OpenInExplorer.lua
Add the possibility to define a shortcut for this LUA script.
2020-06-11 22:06:00 +02:00
Tobias Scheck
2e27b812d6 fix spelling 2020-06-10 14:48:27 +02:00
Tobias Scheck
fd97ac18da add comments for clarification; formatting 2020-06-10 14:48:18 +02:00
wpferguson
b9d14a2711 Merge pull request #257 from wpferguson/script_manager_sanitize
Bug Fix: script_manager can't process paths with lua special characters
2020-06-09 20:30:04 -04:00
Bill Ferguson
1c9042c496 Added a sanitize_lua function to the string library for sanitizing
strings of lua "magic" characters before using the string in a string
function that involves matching.

script_manager needs the path to the lua directory sanitized of lua
"magic" characters to prevent failure to extract the category and script
names.
2020-06-09 20:22:02 -04:00
Tobias Scheck
60fa4b9ee0 update description 2020-06-09 08:50:26 +02:00
Tobias Scheck
33f91af1af add photils plugin 2020-06-06 12:39:26 +02:00
wpferguson
05d86e89da Merge pull request #255 from wpferguson/update_README.md
Update README.md
2020-05-30 20:18:21 -04:00
Bill Ferguson
a02176fc63 Added instructions for using script_manager.lua as the luarc file. 2020-05-30 20:12:39 -04:00
Noah Clarke
23131a301b Fix include path 2020-05-07 12:15:31 -07:00
Noah
aef7363bee make 8bit not 16bit luts (extra depth uneeded) 2020-05-06 13:19:12 -07:00
Noah
4455347930 Exporting luts now creates a job 2020-05-06 01:14:34 -07:00
Noah
5709cfebd4 Remove unneeded API check 2020-05-05 00:02:47 -07:00
Noah
01184bee72 Updated API version check and forced PNG to 16 bits 2020-05-04 23:58:52 -07:00
Noah
286ef77663 Some error checking and warnings 2020-04-19 00:36:47 -07:00
Noah
28b9073010 Code and UI cleanup 2020-04-16 23:42:51 -07:00
Noah
fe97e29654 Working? version 2020-04-16 22:59:33 -07:00
Noah
792e782e8c basic frontend 2020-04-16 22:27:57 -07:00
Noah
33b99a97e4 initial module minus style picker 2020-04-16 17:51:09 -07:00
U-DESKTOP-HQME86J\marco
a8e5a9b453 default no. of editors 2020-03-22 17:55:15 +01:00
U-DESKTOP-HQME86J\marco
2d69536489 fixes and code cleaning 2020-03-22 17:50:51 +01:00
56 changed files with 4110 additions and 1438 deletions

72
ChangeLog.md Normal file
View File

@@ -0,0 +1,72 @@
## Changes from most recent to oldest
** 19 Jun 2021 - wpferguson - fix issue 312, image_path_in_ui**
** 02 Jun 2021 - wpferguson - fix contrib/quicktag**
* set new entry field is_password to false so entry
is visible to user while typing.
** 19 Mar 2021 - wpferguson - fixed crash in contrib/HDRmerge.lua**
* Made generated filename routine gracefully handle names that
are not in the expected format.
** 15 Mar 2021 - scheckmedia - updated contrib/photils.lua**
* refactor print method
* add option to apply selected tags from a single image to multiple images
* add setting parameter to enable/disable the export of an image before tag suggestion
** 25 Feb 2021 - wpferguson - added detached mode to contrib/gimp.lua**
* Added run_detached checkbox to the exporter GUI. Selecting run_detached
let's GIMP keep running and accepting additional images. It does not return
the edited images to darktable.
**24 Feb 2021 - Mark64 - make ext_editor lib visible in darkroom view**
**17 Feb 2021 - wpferguson - API 6.2.3 register_action changes**
* Added check for API version and supplied a name argument if the
API version was greater than or equal to 6.2.3
**10 Feb 2021 - wpferguson - bugfix select_untagged**
* Fixed callback to return a list of images as expected instead of
doing the selection in the callback
**10 Feb 2021 - wpferguson - bugfix API 6.2.1 compatibility**
* The inline check for API version didn't handle argument return
correctly so added a transition library with a register_event function
override to check the API version and process the arguments correctly.
**9 Feb 2021 - wpferguson - bugfix API 6.2.2 compatibility**
* The inline check for API version didn't handle argument return
correctly so changed it to a full if/else block
**4 Reb 2021 - wpferguson - API 6.2.2 compatibililty**
* Added check for API version and supplied a name argument to register_selection
if the API version was greater than or eqal to 6.2.2
**1 Feb 2021 - wpferguson - API 6.2.1 compatibility**
* Added check for API version and supplied a name argument to register_event
if the API version was greater than or eqal to 6.2.1
**21 Jan 2021 - wpferguson - Modified dtutils function find_image_by_id**
* For users with API 6.2.0 or greater - Enabled use of new API function
darktable.database_get_image() in find_image_by_id().
**19 Jan 2021 - schwerdf - Added dtutils library function find_image_by_id()**
* Added new library function to retrieve an image from the library based on it's ID instead
of it's row number in the database
**10 Jan 2021 - chrisaga - copy_attach_detach_tags localization**
**7 Jan 2021 - dtorop - add contrib/fujifilm_dynamic_range**
* add a new contrib script, fujifilm_dynamic_range to adjust exposure
based on the exposure bias camera setting

182
README.md
View File

@@ -7,23 +7,25 @@ efforts of the darktable developers, maintainers, contributors and community. Th
contained in the repository, whether they can be run by themselves (Standalone - Yes) or depend on other contained in the repository, whether they can be run by themselves (Standalone - Yes) or depend on other
scripts (Standalone - No), what operating systems they are known to work on (L - Linux, M - MacOS, W - Windows), and their purpose. scripts (Standalone - No), what operating systems they are known to work on (L - Linux, M - MacOS, W - Windows), and their purpose.
For the latest changes, see the [ChangeLog](ChangeLog.md)
### Official Scripts ### Official Scripts
These scripts are written primarily by the darktable developers and maintained by the authors and/or repository maintainers. They are located in the official/ directory. These scripts are written primarily by the darktable developers and maintained by the authors and/or repository maintainers. They are located in the official/ directory.
Name|Standalone|OS |Purpose Name|Standalone|OS |Purpose
----|:--------:|:---:|------- ----|:--------:|:---:|-------
check_for_updates|Yes|LMW|Check for updates to darktable [check_for_updates](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/official/check_for_updates)|Yes|LMW|Check for updates to darktable
copy_paste_metadata|Yes|LMW|Copy and paste metadata, tags, ratings, and color labels between images [copy_paste_metadata](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/official/copy_paste_metadata)|Yes|LMW|Copy and paste metadata, tags, ratings, and color labels between images
delete_long_tags|Yes|LMW|Delete all tags longer than a specified length [delete_long_tags](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/official/delete_long_tags)|Yes|LMW|Delete all tags longer than a specified length
delete_unused_tags|Yes|LMW|Delete tags that have no associated images [delete_unused_tags](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/official/delete_unused_tags)|Yes|LMW|Delete tags that have no associated images
enfuse|No|L|Exposure blend several images (HDR) [enfuse](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/official/enfuse)|No|L|Exposure blend several images (HDR)
generate_image_txt|No|L|Generate txt sidecar files to be overlaid on zoomed images [generate_image_txt](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/official/generate_image_txt)|No|L|Generate txt sidecar files to be overlaid on zoomed images
image_path_in_ui|Yes|LMW|Plugin to display selected image path [image_path_in_ui](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/official/image_path_in_ui)|Yes|LMW|Plugin to display selected image path
import_filter_manager|Yes|LMW|Manager for import filters [import_filter_manager](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/official/import_filter_manager)|Yes|LMW|Manager for import filters
import_filters|No|LMW|Two import filters for use with import_filter_manager [import_filters](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/official/import_filters)|No|LMW|Two import filters for use with import_filter_manager
save_selection|Yes|LMW|Provide save and restore from multiple selection buffers [save_selection](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/official/save_selection)|Yes|LMW|Provide save and restore from multiple selection buffers
selection_to_pdf|No|L|Generate a PDF file from the selected images [selection_to_pdf](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/official/selection_to_pdf)|No|L|Generate a PDF file from the selected images
### Contributed Scripts ### Contributed Scripts
@@ -32,36 +34,40 @@ These scripts are contributed by users. They are meant to have an "owner", i.e.
Name|Standalone|OS |Purpose Name|Standalone|OS |Purpose
----|:--------:|:---:|------- ----|:--------:|:---:|-------
AutoGrouper|Yes|LMW|Group images together by time [AutoGrouper](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/AutoGrouper)|Yes|LMW|Group images together by time
autostyle|Yes|LMW|Automatically apply styles on import [autostyle](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/autostyle)|Yes|LMW|Automatically apply styles on import
clear_GPS|Yes|LMW|Reset GPS information for selected images [clear_GPS](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/clear_GPS)|Yes|LMW|Reset GPS information for selected images
CollectHelper|Yes|LMW|Add buttons to selected images module to manipulate the collection [CollectHelper](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/CollectHelper)|Yes|LMW|Add buttons to selected images module to manipulate the collection
copy_attach_detach_tags|Yes|LMW|Copy and paste tags from/to images [copy_attach_detach_tags](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/copy_attach_detach_tags)|Yes|LMW|Copy and paste tags from/to images
cr2hdr|Yes|L|Process image created with Magic Lantern Dual ISO [cr2hdr](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/cr2hdr)|Yes|L|Process image created with Magic Lantern Dual ISO
enfuseAdvanced|No|LMW|Merge multiple images into Dynamic Range Increase (DRI) or Depth From Focus (DFF) images [enfuseAdvanced](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/enfuseAdvanced)|No|LMW|Merge multiple images into Dynamic Range Increase (DRI) or Depth From Focus (DFF) images
ext_editor|No|LW|Export pictures to collection and edit them with up to nine user-defined external editors [exportLUT](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/exportLUT)|Yes|LMW|Create a LUT from a style and export it
face_recognition|No|LM|Identify and tag images using facial recognition [ext_editor](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/ext_editor)|No|LW|Export pictures to collection and edit them with up to nine user-defined external editors
fujifilm_ratings|No|LM|Support importing Fujifilm ratings [face_recognition](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/face_recognition)|No|LM|Identify and tag images using facial recognition
geoJSON_export|No|L|Create a geo JSON script with thumbnails for use in ... [fujifilm_dynamic_range](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/fujifilm_dynamic_range)|No|LMW|Correct fujifilm exposure based on exposure bias camera setting
geoToolbox|No|LMW|A toolbox of geo functions [fujifilm_ratings](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/fujifilm_ratings)|No|LM|Support importing Fujifilm ratings
gimp|No|LMW|Open an image in GIMP for editing and return the result [geoJSON_export](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/geoJSON_export)|No|L|Create a geo JSON script with thumbnails for use in ...
gpx_export|No|LMW|Export a GPX track file from selected images GPS data [geoToolbox](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/geoToolbox)|No|LMW|A toolbox of geo functions
HDRMerge|No|LMW|Combind the selected images into an HDR DNG and return the result [gimp](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/gimp)|No|LMW|Open an image in GIMP for editing and return the result
hugin|No|LMW|Combine selected images into a panorama and return the result [gpx_export](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/gpx_export)|No|LMW|Export a GPX track file from selected images GPS data
image_stack|No|LMW|Combine a stack of images to remove noise or transient objects [HDRMerge](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/HDRMerge)|No|LMW|Combine the selected images into an HDR DNG and return the result
kml_export|No|L|Export photos with a KML file for usage in Google Earth [hugin](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/hugin)|No|LMW|Combine selected images into a panorama and return the result
LabelsToTags|Yes|LMW|Apply tags based on color labels and ratings [image_stack](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/image_stack)|No|LMW|Combine a stack of images to remove noise or transient objects
OpenInExplorer|No|LMW|Open the selected images in the system file manager [image_time](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/image_time)|Yes|LMW|Adjust the EXIF image time
passport_guide|Yes|LMW|Add passport cropping guide to darkroom crop tool [kml_export](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/kml_export)|No|L|Export photos with a KML file for usage in Google Earth
pdf_slideshow|No|LM|Export images to a PDF slideshow [LabelsToTags](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/LabelsToTags)|Yes|LMW|Apply tags based on color labels and ratings
quicktag|Yes|LMW|Create shortcuts for quickly applying tags [OpenInExplorer](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/OpenInExplorer)|No|LMW|Open the selected images in the system file manager
rate_group|Yes|LMW|Apply or remove a star rating from grouped images [passport_guide](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/passport_guide)|Yes|LMW|Add passport cropping guide to darkroom crop tool
rename-tags|Yes|LMW|Change a tag name [pdf_slideshow](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/pdf_slideshow)|No|LM|Export images to a PDF slideshow
RL_out_sharp|No|LW|Output sharpening using GMic (Richardson-Lucy algorithm) [photils](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/photils)|No|LM|Automatic tag suggestions for your images
select_untagged|Yes|LMW|Enable selection of untagged images [quicktag](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/quicktag)|Yes|LMW|Create shortcuts for quickly applying tags
slideshowMusic|No|L|Play music during a slideshow [rate_group](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/rate_group)|Yes|LMW|Apply or remove a star rating from grouped images
transfer_hierarchy|Yes|LMW|Image move/copy preserving directory hierarchy [rename-tags](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/rename-tags)|Yes|LMW|Change a tag name
video_ffmpeg|No|LMW|Export video from darktable [RL_out_sharp](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/RL_out_sharp)|No|LW|Output sharpening using GMic (Richardson-Lucy algorithm)
[select_untagged](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/select_untagged)|Yes|LMW|Enable selection of untagged images
[slideshowMusic](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/slideshowMusic)|No|L|Play music during a slideshow
[transfer_hierarchy](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/transfer_hierarchy)|Yes|LMW|Image move/copy preserving directory hierarchy
[video_ffmpeg](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/video_ffmpeg)|No|LMW|Export video from darktable
### Example Scripts ### Example Scripts
@@ -69,17 +75,17 @@ These scripts provide examples of how to use specific portions of the API. They
Name|Standalone|OS |Purpose Name|Standalone|OS |Purpose
----|:--------:|:---:|------- ----|:--------:|:---:|-------
api_version|Yes|LMW|Print the current API version [api_version](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/api_version)|Yes|LMW|Print the current API version
darkroom_demo|Yes|LMW|Demonstrate changing images in darkoom [darkroom_demo](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/darkroom_demo)|Yes|LMW|Demonstrate changing images in darkoom
gettextExample|Yes|LM|How to use translation [gettextExample](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/gettextExample)|Yes|LM|How to use translation
hello_world|Yes|LMW|Prints hello world when darktable starts [hello_world](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/hello_world)|Yes|LMW|Prints hello world when darktable starts
lighttable_demo|Yes|LMW|Demonstrate controlling lighttable mode, zoom, sorting and filtering [lighttable_demo](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/lighttable_demo)|Yes|LMW|Demonstrate controlling lighttable mode, zoom, sorting and filtering
moduleExample|Yes|LMW|How to create a lighttable module [moduleExample](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/moduleExample)|Yes|LMW|How to create a lighttable module
multi_os|No|LMW|How to create a cross platform script that calls an external executable [multi_os](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/multi_os)|No|LMW|How to create a cross platform script that calls an external executable
panels_demo|Yes|LMW|Demonstrate hiding and showing darktable panels [panels_demo](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/panels_demo)|Yes|LMW|Demonstrate hiding and showing darktable panels
preferenceExamples|Yes|LMW|How to use preferences in a script [preferenceExamples](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/preferenceExamples)|Yes|LMW|How to use preferences in a script
printExamples|Yes|LMW|How to use various print functions from a script [printExamples](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/printExamples)|Yes|LMW|How to use various print functions from a script
running_os|Yes|LMW|Print out the running operating system [running_os](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/running_os)|Yes|LMW|Print out the running operating system
### Tools ### Tools
@@ -87,11 +93,11 @@ Tool scripts perform functions relating to the repository, such as generating do
Name|Standalone|OS |Purpose Name|Standalone|OS |Purpose
----|:--------:|:---:|------- ----|:--------:|:---:|-------
executable_manager|Yes|LMW|Manage the external executables used by the lua scripts [executable_manager](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/tools/executable_manager)|Yes|LMW|Manage the external executables used by the lua scripts
gen_i18n_mo|No|LMW|Generate compiled translation files (.mo) from source files (.po) [gen_i18n_mo](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/tools/gen_i18n_mo)|No|LMW|Generate compiled translation files (.mo) from source files (.po)
get_lib_manpages|No|LM|Retrieve the library documentation and output it in man page and PDF format [get_lib_manpages](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/tools/get_lib_manpages)|No|LM|Retrieve the library documentation and output it in man page and PDF format
get_libdoc|No|LMW|Retrieve the library documentation and output it as text [get_libdoc](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/tools/get_libdoc)|No|LMW|Retrieve the library documentation and output it as text
script_manager|No|LMW|Manage (install, update, enable, disable) the lua scripts [script_manager](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/tools/script_manager)|No|LMW|Manage (install, update, enable, disable) the lua scripts
### Related third-party projects ### Related third-party projects
@@ -116,14 +122,24 @@ are met as well as providing an easy update path. Single scripts listed as stand
### snap packages ### snap packages
The snap version of darktable comes with lua included starting with version 2.4.3snap2. It is currently in the edge channel, but should reach the stable channel soon. The snap version of darktable comes with lua included starting with version 2.4.3snap2.
Ensure git is installed on your system. If it isn't, use the package manager to install it. Then open a terminal and: Ensure git is installed on your system. If it isn't, use the package manager to install it. Then open a terminal and:
cd ~/snap/darktable/current cd ~/snap/darktable/current
git clone https://github.com/darktable-org/lua-scripts.git lua git clone https://github.com/darktable-org/lua-scripts.git lua
### flatpak and appimage packages ### flatpak packages
Flatpak packages now use the internal lua interpreter.
Ensure git is installed on your system. If it isn't, use the package manager to install it. Then open a terminal and:
cd ~/.var/app/org.darktable.Darktable/config/darktable
git clone https://github.com/darktable-org/lua-scripts.git lua
### appimage packages
These packages run in their own environment and don't have access to a lua interpreter, therefore the scripts can't run. The packagers could enable the internal interpreter, or allow the package to link the interpreter from the operating system, or bundle a copy of lua with the package. If you use one of these packages and wish to use the lua scripts, please contact the package maintainer and suggest the above fixes. These packages run in their own environment and don't have access to a lua interpreter, therefore the scripts can't run. The packagers could enable the internal interpreter, or allow the package to link the interpreter from the operating system, or bundle a copy of lua with the package. If you use one of these packages and wish to use the lua scripts, please contact the package maintainer and suggest the above fixes.
@@ -138,8 +154,6 @@ Ensure git is installed on your system. If it isn't, use the package manager to
Ensure git is installed on your system. Git can be obtained from https://gitforwindows.org/, as well as other places. If you use the gitforwindows.org distribution, install the Git Bash Shell also as it will aid in debugging the scripts if necessary. Then open a command prompt and run: Ensure git is installed on your system. Git can be obtained from https://gitforwindows.org/, as well as other places. If you use the gitforwindows.org distribution, install the Git Bash Shell also as it will aid in debugging the scripts if necessary. Then open a command prompt and run:
Open a command prompt.
cd %LOCALAPPDATA%\darktable cd %LOCALAPPDATA%\darktable
git clone https://github.com/darktable-org/lua-scripts.git lua git clone https://github.com/darktable-org/lua-scripts.git lua
@@ -149,6 +163,24 @@ 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:
### Linux or MacOS
echo 'require "tools/script_manager"' > ~/.config/darktable/luarc
### Windows
echo "require 'tools/script_manager'" > %LOCALAPPDATA%\darktable\luarc
### Snap
echo 'require "tools/script_manager"' > ~/snap/darktable/current/luarc
### Flatpak
echo require "tools/script_manager"' > ~/.var/app/org.darktable.Darktable/config/darktable/luarc
You can also create or add lines to the luarc file from the command line: You can also create or add lines to the luarc file from the command line:
`echo 'require "contrib/gimp"' > ~/.config/darktable/luarc` to create the file with a gimp entry\ `echo 'require "contrib/gimp"' > ~/.config/darktable/luarc` to create the file with a gimp entry\
@@ -172,6 +204,12 @@ To update the script repository, open a terminal or command prompt and do the fo
cd ~/snap/darktable/current/lua cd ~/snap/darktable/current/lua
git pull git pull
### Flatpak
cd ~/.var/app/org.darktable.Darktable/config/darktable/lua
git pull
### Linux and MacOS ### Linux and MacOS
cd ~/.config/darktable/lua/ cd ~/.config/darktable/lua/
@@ -184,15 +222,19 @@ To update the script repository, open a terminal or command prompt and do the fo
## Documentation ## Documentation
Each script includes its own documentation and usage in its header, please refer to them. The [Lua Scripts Manual](https://darktable-org.github.io/luadocs/lua.scripts.manual/) provides documentation
for the scripts transcribed from the header comments. Each script also contains comments and usage instructions
in the header comments.
Lua-script libraries documentation may be generated using the tools in the tools/ directory. The [Lua Scripts Library API Manual](https://darktable-org.github.io/luadocs/lua.scripts.api.manual/) provides
documentation of the libraries and functions. Lua-script libraries documentation may also be generated using
the tools in the tools/ directory.
More information about the scripting with Lua can be found in the darktable user manual: More information about the scripting with Lua can be found in the darktable user manual:
https://www.darktable.org/usermanual/en/lua_chapter.html [Scripting with Lua](https://darktable-org.github.io/dtdocs/lua/)
The darktable Lua API documentation is here: The [Lua API Manual](https://darktable-org.github.io/luadocs/lua.api.manual/) provides docuemntation of the
https://www.darktable.org/lua-api/ darktable Lua API.
## Troubleshooting ## Troubleshooting
@@ -202,13 +244,17 @@ Running darktable with Lua debugging enabled provides more information about wha
Open a terminal and start darktable with the command `snap run darktable -d lua`. This provides debugging information to give you insight into what is happening. Open a terminal and start darktable with the command `snap run darktable -d lua`. This provides debugging information to give you insight into what is happening.
### Linux and MacOS ### Linux
Open a terminal and start darktable with the command `darktable -d lua`. This provides debugging information to give you insight into what is happening. Open a terminal and start darktable with the command `darktable -d lua`. This provides debugging information to give you insight into what is happening.
### MacOS
Open a terminal and start darktable with the command `/Applications/darktable.app/Contents/MacOS/darktable -d lua`. This provides debugging information to give you insight into what is happening.
### Windows ### Windows
Open the Git Bash Shell. Start darktable with the command `/c/Program\ Files/darktable/bin/darktable -d lua`. This provides debugging information to give you insight into what is happening. Open a command prompt. Start darktable with the command "C:\Program Files\darktable\bin\darktable" -d lua > log.txt. This provides debugging information to give you insight into what is happening.
## Contributing ## Contributing

View File

@@ -37,14 +37,27 @@ selected images, the other button performs grouping on the entire active collect
]] ]]
local dt = require "darktable" local dt = require "darktable"
local MOD = 'autogrouper' local MOD = 'autogrouper'
local gettext = dt.gettext local gettext = dt.gettext
-- Tell gettext where to find the .mo file translating messages for a particular domain -- Tell gettext where to find the .mo file translating messages for a particular domain
local CURR_API_STRING = dt.configuration_api_version_string
gettext.bindtextdomain("AutoGrouper",dt.configuration.config_dir.."/lua/locale/") gettext.bindtextdomain("AutoGrouper",dt.configuration.config_dir.."/lua/locale/")
local function _(msgid) local function _(msgid)
return gettext.dgettext("AutoGrouper", msgid) return gettext.dgettext("AutoGrouper", msgid)
end end
local Ag = {}
Ag.module_installed = false
Ag.event_registered = false
local GUI = {
gap = {},
selected = {},
collection = {}
}
local function InRange(test, low, high) --tests if test value is within range of low and high (inclusive) local function InRange(test, low, high) --tests if test value is within range of low and high (inclusive)
if test >= low and test <= high then if test >= low and test <= high then
return true return true
@@ -111,12 +124,26 @@ local function main(on_collection)
end end
end end
local function install_module()
if not Ag.module_installed then
dt.register_lib(
'AutoGroup_Lib', -- Module name
_('auto group'), -- name
true, -- expandable
true, -- resetable
{[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 99}}, -- containers
dt.new_widget("box"){
orientation = "vertical",
GUI.gap,
GUI.selected,
GUI.collection
}
)
Ag.module_installed = true
end
end
-- GUI -- -- GUI --
GUI = {
gap = {},
selected = {},
collection = {}
}
temp = dt.preferences.read(MOD, 'active_gap', 'integer') temp = dt.preferences.read(MOD, 'active_gap', 'integer')
if not InRange(temp, 1, 86400) then temp = 3 end if not InRange(temp, 1, 86400) then temp = 3 end
GUI.gap = dt.new_widget('slider'){ GUI.gap = dt.new_widget('slider'){
@@ -143,16 +170,20 @@ GUI.collection = dt.new_widget("button"){
tooltip =_('auto group the entire collection'), tooltip =_('auto group the entire collection'),
clicked_callback = function() main(true) end clicked_callback = function() main(true) end
} }
dt.register_lib(
'AutoGroup_Lib', -- Module name if dt.gui.current_view().id == "lighttable" then
_('auto group'), -- name install_module()
true, -- expandable else
true, -- resetable if not Ag.event_registered then
{[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 99}}, -- containers dt.register_event(
dt.new_widget("box"){ "view-changed",
orientation = "vertical", function(event, old_view, new_view)
GUI.gap, if new_view.name == "lighttable" and old_view.name == "darkroom" then
GUI.selected, install_module()
GUI.collection end
} end
) )
Ag.event_registered = true
end
end

View File

@@ -53,6 +53,8 @@ local all_active = false
-- Tell gettext where to find the .mo file translating messages for a particular domain -- Tell gettext where to find the .mo file translating messages for a particular domain
gettext.bindtextdomain("CollectHelper",dt.configuration.config_dir.."/lua/locale/") gettext.bindtextdomain("CollectHelper",dt.configuration.config_dir.."/lua/locale/")
local CURR_API_STRING = dt.configuration.api_version_string
local function _(msgid) local function _(msgid)
return gettext.dgettext("CollectHelper", msgid) return gettext.dgettext("CollectHelper", msgid)
end end

View File

@@ -46,379 +46,406 @@ Select a style, whether you want tags to be copied from the original, and any ad
local dt = require 'darktable' local dt = require 'darktable'
local df = require 'lib/dtutils.file' local df = require 'lib/dtutils.file'
local dsys = require 'lib/dtutils.system' local dsys = require 'lib/dtutils.system'
local mod = 'module_HDRMerge' local mod = 'module_HDRMerge'
local os_path_seperator = '/' local os_path_seperator = '/'
if dt.configuration.running_os == 'windows' then os_path_seperator = '\\' end if dt.configuration.running_os == 'windows' then os_path_seperator = '\\' end
local CURR_API_STRING = dt.configuration.api_version_string
-- Tell gettext where to find the .mo file translating messages for a particular domain -- Tell gettext where to find the .mo file translating messages for a particular domain
local gettext = dt.gettext local gettext = dt.gettext
gettext.bindtextdomain('HDRMerge',dt.configuration.config_dir..'/lua/locale/') gettext.bindtextdomain('HDRMerge', dt.configuration.config_dir..'/lua/locale/')
local function _(msgid) local function _(msgid)
return gettext.dgettext('HDRMerge', msgid) return gettext.dgettext('HDRMerge', msgid)
end end
local temp local temp
local HDRM = { --HDRMerge Program Table local HDRM = { --HDRMerge Program Table
name = 'HDRMerge', name = 'HDRMerge',
bin = '', bin = '',
first_run = true, first_run = true,
install_error = false, install_error = false,
arg_string = '', arg_string = '',
images_string = '', images_string = '',
args = { args = {
bps ={text = '-b ', style = 'integer'}, bps = {text = '-b ', style = 'integer'},
size ={text = '-p ', style = 'string'}, size = {text = '-p ', style = 'string'},
batch ={text = '-B ', style = 'bool'}, batch = {text = '-B ', style = 'bool'},
gap ={text = '-g ', style = 'integer'} gap = {text = '-g ', style = 'integer'}
} }
} }
local GUI = { --GUI Elements Table local GUI = { --GUI Elements Table
HDR = { HDR = {
bps ={}, bps ={},
size ={}, size ={},
batch ={}, batch ={},
gap ={} gap ={}
}, },
Target = { Target = {
style ={}, style ={},
copy_tags ={}, copy_tags ={},
add_tags ={} add_tags ={}
}, },
run = {}, run = {},
stack = {}, stack = {},
options = {}, options = {},
exes = { exes = {
HDRMerge = {}, HDRMerge = {},
update = {}, update = {},
} }
} }
HDRM.module_installed = false
HDRM.event_registered = false
--Detect User Styles-- --Detect User Styles--
local styles = dt.styles local styles = dt.styles
local styles_count = 1 -- 'none' = 1 local styles_count = 1 -- 'none' = 1
for _,i in pairs(dt.styles) do for _,i in pairs(dt.styles) do
if type(i) == 'userdata' then styles_count = styles_count + 1 end if type(i) == 'userdata' then styles_count = styles_count + 1 end
end end
local function InRange(test, low, high) --tests if test value is within range of low and high (inclusive) local function InRange(test, low, high) --tests if test value is within range of low and high (inclusive)
if test >= low and test <= high then if test >= low and test <= high then
return true return true
else else
return false return false
end end
end end
local function GetFileName(full_path) --Parses a full path (path/filename_identifier.extension) into individual parts local function GetFileName(full_path) --Parses a full path (path/filename_identifier.extension) into individual parts
--[[Input: Folder1/Folder2/Folder3/Img_0001.CR2 --[[Input: Folder1/Folder2/Folder3/Img_0001.CR2
Returns: Returns:
path: Folder1/Folder2/Folder3/ path: Folder1/Folder2/Folder3/
filename: Img_0001 filename: Img_0001
identifier: 0001 identifier: 0001
extension: .CR2 extension: .CR2
EX: EX:
path_1, file_1, id_1, ext_1 = GetFileName(full_path_1) path_1, file_1, id_1, ext_1 = GetFileName(full_path_1)
]] ]]
local path = string.match(full_path, '.*[\\/]') local path = string.match(full_path, '.*[\\/]')
local filename = string.gsub(string.match(full_path, '[%w-_]*%.') , '%.' , '' ) local filename = string.gsub(string.match(full_path, '[%w-_]*%.') , '%.' , '' )
local identifier = string.match(filename, '%d*$') local identifier = string.match(filename, '%d*$')
local extension = string.match(full_path, '%.%w*') local extension = string.match(full_path, '%.%w*')
return path, filename, identifier, extension return path, filename, identifier, extension
end end
local function CleanSpaces(text) --removes spaces from the front and back of passed in text local function CleanSpaces(text) --removes spaces from the front and back of passed in text
text = string.gsub(text,'^%s*','') text = string.gsub(text,'^%s*','')
text = string.gsub(text,'%s*$','') text = string.gsub(text,'%s*$','')
return text return text
end end
local function BuildExecuteCmd(prog_table) --creates a program command using elements of the passed in program table local function BuildExecuteCmd(prog_table) --creates a program command using elements of the passed in program table
local result = CleanSpaces(prog_table.bin)..' '..CleanSpaces(prog_table.arg_string)..' '..CleanSpaces(prog_table.images_string) local result = CleanSpaces(prog_table.bin)..' '..CleanSpaces(prog_table.arg_string)..' '..CleanSpaces(prog_table.images_string)
return result return result
end end
local function PreCall(prog_tbl) --looks to see if this is the first call, if so checks to see if program is installed properly local function PreCall(prog_tbl) --looks to see if this is the first call, if so checks to see if program is installed properly
for _,prog in pairs(prog_tbl) do for _,prog in pairs(prog_tbl) do
if prog.first_run then if prog.first_run then
prog.bin = df.check_if_bin_exists(prog.name) prog.bin = df.check_if_bin_exists(prog.name)
if not prog.bin then if not prog.bin then
prog.install_error = true prog.install_error = true
dt.preferences.write(mod, 'bin_exists', 'bool', false) dt.preferences.write(mod, 'bin_exists', 'bool', false)
else else
prog.bin = CleanSpaces(prog.bin) prog.bin = CleanSpaces(prog.bin)
end end
prog.first_run = false prog.first_run = false
end
end
if not dt.preferences.read(mod, 'bin_exists', 'bool') then
GUI.stack.active = 2
dt.print(_('please update you binary locatoin'))
end end
end
if not dt.preferences.read(mod, 'bin_exists', 'bool') then
GUI.stack.active = 2
dt.print(_('please update you binary location'))
end
end end
local function ExeUpdate(prog_tbl) local function ExeUpdate(prog_tbl)
dt.preferences.write(mod, 'bin_exists', 'bool', true) dt.preferences.write(mod, 'bin_exists', 'bool', true)
for _,prog in pairs(prog_tbl) do for _,prog in pairs(prog_tbl) do
dt.preferences.write('executable_paths', prog.name, 'string', GUI.exes[prog.name].value) dt.preferences.write('executable_paths', prog.name, 'string', GUI.exes[prog.name].value)
prog.bin = df.check_if_bin_exists(prog.name) prog.bin = df.check_if_bin_exists(prog.name)
if not prog.bin then if not prog.bin then
prog.install_error = true prog.install_error = true
dt.preferences.write(mod, 'bin_exists', 'bool', false) dt.preferences.write(mod, 'bin_exists', 'bool', false)
else
prog.bin = CleanSpaces(prog.bin)
end
prog.first_run = false
end
if dt.preferences.read(mod, 'bin_exists', 'bool') then
GUI.stack.active = 1
dt.print(_('update successful'))
else else
dt.print(_('update unsuccessful, please try again')) prog.bin = CleanSpaces(prog.bin)
end end
prog.first_run = false
end
if dt.preferences.read(mod, 'bin_exists', 'bool') then
GUI.stack.active = 1
dt.print(_('update successful'))
else
dt.print(_('update unsuccessful, please try again'))
end
end end
local function UpdateActivePreference() --sliders & entry boxes do not have a click/changed callback, so their values must be saved to the active preference local function UpdateActivePreference() --sliders & entry boxes do not have a click/changed callback, so their values must be saved to the active preference
temp = GUI.HDR.gap.value temp = GUI.HDR.gap.value
dt.preferences.write(mod, 'active_gap', 'integer', temp) dt.preferences.write(mod, 'active_gap', 'integer', temp)
temp = GUI.Target.add_tags.text temp = GUI.Target.add_tags.text
dt.preferences.write(mod, 'active_add_tags', 'string', temp) dt.preferences.write(mod, 'active_add_tags', 'string', temp)
end end
local function main() local function main()
PreCall({HDRM}) --check if furst run then check if install OK PreCall({HDRM}) --check if furst run then check if install OK
if HDRM.install_error then if HDRM.install_error then
dt.print_error(_('HDRMerge install issue')) dt.print_error(_('HDRMerge install issue'))
dt.print(_('HDRMerge install issue, please ensure the binary path is proper')) dt.print(_('HDRMerge install issue, please ensure the binary path is proper'))
return return
end
images = dt.gui.selection() --get selected images
if #images < 2 then --ensure enough images selected
dt.print(_('not enough images selected, select at least 2 images to merge'))
return
end
UpdateActivePreference() --save current gui elements to active preference so those values will be pre-loaded at next startup
--create image string and output path
HDRM.images_string = ''
local out_path = ''
local smallest_id = math.huge
local smallest_name = ''
local largest_id = 0
local source_raw = {}
for _,image in pairs(images) do --loop to concat the images string, also track the image indexes for use in creating the final image name (eg; IMG_1034-1037.dng)
local curr_image = image.path..os_path_seperator..image.filename
HDRM.images_string = HDRM.images_string..df.sanitize_filename(curr_image)..' '
out_path = image.path
_unused, source_name, source_id = GetFileName(image.filename)
source_id = tonumber(source_id) or 0
if source_id < smallest_id then
smallest_id = source_id
smallest_name = source_name
source_raw = image
end end
images = dt.gui.selection() --get selected images if source_id > largest_id then largest_id = source_id end
if #images < 2 then --ensure enough images selected end
dt.print(_('not enough images selected, select at least 2 images to merge')) out_path = out_path..os_path_seperator..smallest_name..'-'..largest_id..'.dng'
return out_path = df.create_unique_filename(out_path)
--create argument string
HDRM.arg_string = HDRM.args.bps.text..GUI.HDR.bps.value..' '..HDRM.args.size.text..GUI.HDR.size.value..' '
if GUI.HDR.batch.value then
HDRM.arg_string = HDRM.arg_string..HDRM.args.batch.text..HDRM.args.gap.text..math.floor(GUI.HDR.gap.value)..' -a'
else
HDRM.arg_string = HDRM.arg_string..'-o '..df.sanitize_filename(out_path)
end
-- create run command and execute
local run_cmd = BuildExecuteCmd(HDRM)
resp = dsys.external_command(run_cmd)
if resp == 0 and not GUI.HDR.batch.value then
local imported = dt.database.import(out_path) -- import the new file
if GUI.Target.style.selected > 1 then -- apply selected style
local set_style = styles[GUI.Target.style.selected - 1]
dt.styles.apply(set_style , imported)
end end
if GUI.Target.copy_tags.value then -- copy tags from the original file (ignore 'darktable' generated tags)
UpdateActivePreference() --save current gui elements to active preference so those values will be pre-loaded at next startup local all_tags = dt.tags.get_tags(source_raw)
for _,tag in pairs(all_tags) do
--create image string and output path if string.match(tag.name, 'darktable|') == nil then dt.tags.attach(tag, imported) end
HDRM.images_string = '' end
local out_path = ''
local smallest_id = math.huge
local smallest_name = ''
local largest_id = 0
local source_raw = {}
for _,image in pairs(images) do --loop to concat the images string, also track the image indexes for use in creating the final image name (eg; IMG_1034-1037.dng)
local curr_image = image.path..os_path_seperator..image.filename
HDRM.images_string = HDRM.images_string..df.sanitize_filename(curr_image)..' '
out_path = image.path
_, source_name, source_id = GetFileName(image.filename)
source_id = tonumber(source_id)
if source_id < smallest_id then
smallest_id = source_id
smallest_name = source_name
source_raw = image
end
if source_id > largest_id then largest_id = source_id end
end end
out_path = out_path..os_path_seperator..smallest_name..'-'..largest_id..'.dng' local set_tag = GUI.Target.add_tags.text
out_path = df.create_unique_filename(out_path) if set_tag ~= nil then -- add additional user-specified tags
for tag in string.gmatch(set_tag, '[^,]+') do
--create argument string tag = CleanSpaces(tag)
HDRM.arg_string = HDRM.args.bps.text..GUI.HDR.bps.value..' '..HDRM.args.size.text..GUI.HDR.size.value..' ' tag = dt.tags.create(tag)
if GUI.HDR.batch.value then dt.tags.attach(tag, imported)
HDRM.arg_string = HDRM.arg_string..HDRM.args.batch.text..HDRM.args.gap.text..math.floor(GUI.HDR.gap.value)..' -a' end
else
HDRM.arg_string = HDRM.arg_string..'-o '..df.sanitize_filename(out_path)
end
-- create run command and execute
local run_cmd = BuildExecuteCmd(HDRM)
resp = dsys.external_command(run_cmd)
if resp == 0 and not GUI.HDR.batch.value then
local imported = dt.database.import(out_path) -- import the new file
if GUI.Target.style.selected > 1 then -- apply selected style
local set_style = styles[GUI.Target.style.selected - 1]
dt.styles.apply(set_style , imported)
end
if GUI.Target.copy_tags.value then -- copy tags from the original file (ignore 'darktable' generated tags)
local all_tags = dt.tags.get_tags(source_raw)
for _,tag in pairs(all_tags) do
if string.match(tag.name, 'darktable|') == nil then dt.tags.attach(tag, imported) end
end
end
local set_tag = GUI.Target.add_tags.text
if set_tag ~= nil then -- add additional user-specified tags
for tag in string.gmatch(set_tag, '[^,]+') do
tag = CleanSpaces(tag)
tag = dt.tags.create(tag)
dt.tags.attach(tag, imported)
end
end
dt.print(_('HDRMerge completed successfully'))
else
dt.print_error(_('HDRMerge failed'))
dt.print(_('HDRMerge failed'))
end end
dt.print(_('HDRMerge completed successfully'))
else
dt.print_error(_('HDRMerge failed'))
dt.print(_('HDRMerge failed'))
end
end end
local function install_module()
if not HDRM.module_installed then
dt.register_lib( -- register HDRMerge module
'HDRMerge_Lib', -- Module name
_('HDRMerge'), -- name
true, -- expandable
true, -- resetable
{[dt.gui.views.lighttable] = {'DT_UI_CONTAINER_PANEL_RIGHT_CENTER', 99}}, -- containers
dt.new_widget('box'){
orientation = 'vertical',
GUI.stack
}
)
HDRM.module_installed = true
end
end
-- GUI Elements -- -- GUI Elements --
local lbl_hdr = dt.new_widget('section_label'){ local lbl_hdr = dt.new_widget('section_label'){
label = _('HDRMerge options') label = _('HDRMerge options')
} }
temp = dt.preferences.read(mod, 'active_bps_ind', 'integer') temp = dt.preferences.read(mod, 'active_bps_ind', 'integer')
if not InRange(temp, 1, 3) then temp = 3 end if not InRange(temp, 1, 3) then temp = 3 end
GUI.HDR.bps = dt.new_widget('combobox'){ GUI.HDR.bps = dt.new_widget('combobox'){
label = _('bits per sample'), label = _('bits per sample'),
tooltip =_('number of bits per sample in the output image'), tooltip =_('number of bits per sample in the output image'),
selected = temp, selected = temp,
'16','24','32', '16','24','32',
changed_callback = function(self) changed_callback = function(self)
dt.preferences.write(mod, 'active_bps', 'integer', self.value) dt.preferences.write(mod, 'active_bps', 'integer', self.value)
dt.preferences.write(mod, 'active_bps_ind', 'integer', self.selected) dt.preferences.write(mod, 'active_bps_ind', 'integer', self.selected)
end, end,
reset_callback = function(self) reset_callback = function(self)
self.selected = 3 self.selected = 3
dt.preferences.write(mod, 'active_bps', 'integer', self.value) dt.preferences.write(mod, 'active_bps', 'integer', self.value)
dt.preferences.write(mod, 'active_bps_ind', 'integer', self.selected) dt.preferences.write(mod, 'active_bps_ind', 'integer', self.selected)
end end
} }
temp = dt.preferences.read(mod, 'active_size_ind', 'integer') temp = dt.preferences.read(mod, 'active_size_ind', 'integer')
if not InRange(temp, 1, 3) then temp = 2 end if not InRange(temp, 1, 3) then temp = 2 end
GUI.HDR.size = dt.new_widget('combobox'){ GUI.HDR.size = dt.new_widget('combobox'){
label = _('embedded preview size'), label = _('embedded preview size'),
tooltip =_('size of the embedded preview in output image'), tooltip =_('size of the embedded preview in output image'),
selected = temp, selected = temp,
_('none'),_('half'),_('full'), _('none'),_('half'),_('full'),
changed_callback = function(self) changed_callback = function(self)
dt.preferences.write(mod, 'active_size', 'string', self.value) dt.preferences.write(mod, 'active_size', 'string', self.value)
dt.preferences.write(mod, 'active_size_ind', 'integer', self.selected) dt.preferences.write(mod, 'active_size_ind', 'integer', self.selected)
end, end,
reset_callback = function(self) reset_callback = function(self)
self.selected = 2 self.selected = 2
dt.preferences.write(mod, 'active_size', 'string', self.value) dt.preferences.write(mod, 'active_size', 'string', self.value)
dt.preferences.write(mod, 'active_size_ind', 'integer', self.selected) dt.preferences.write(mod, 'active_size_ind', 'integer', self.selected)
end end
} }
GUI.HDR.batch = dt.new_widget('check_button'){ GUI.HDR.batch = dt.new_widget('check_button'){
label = _('batch mode'), label = _('batch mode'),
value = dt.preferences.read(mod, 'active_batch', 'bool'), value = dt.preferences.read(mod, 'active_batch', 'bool'),
tooltip = _('enable batch mode operation \nNOTE: resultant files will NOT be auto-imported'), tooltip = _('enable batch mode operation \nNOTE: resultant files will NOT be auto-imported'),
clicked_callback = function(self) clicked_callback = function(self)
dt.preferences.write(mod, 'active_batch', 'bool', self.value) dt.preferences.write(mod, 'active_batch', 'bool', self.value)
GUI.HDR.gap.sensitive = self.value GUI.HDR.gap.sensitive = self.value
end, end,
reset_callback = function(self) self.value = false end reset_callback = function(self) self.value = false end
} }
temp = dt.preferences.read(mod, 'active_gap', 'integer') temp = dt.preferences.read(mod, 'active_gap', 'integer')
if not InRange(temp, 1, 3600) then temp = 3 end if not InRange(temp, 1, 3600) then temp = 3 end
GUI.HDR.gap = dt.new_widget('slider'){ GUI.HDR.gap = dt.new_widget('slider'){
label = _('batch gap [sec.]'), label = _('batch gap [sec.]'),
tooltip = _('gap, in seconds, between batch mode groups'), tooltip = _('gap, in seconds, between batch mode groups'),
soft_min = 1, soft_min = 1,
soft_max = 30, soft_max = 30,
hard_min = 1, hard_min = 1,
hard_max = 3600, hard_max = 3600,
step = 1, step = 1,
digits = 0, digits = 0,
value = temp, value = temp,
sensitive = GUI.HDR.batch.value, sensitive = GUI.HDR.batch.value,
reset_callback = function(self) reset_callback = function(self)
self.value = 3 self.value = 3
end end
} }
local lbl_import = dt.new_widget('section_label'){ local lbl_import = dt.new_widget('section_label'){
label = _('import options') label = _('import options')
} }
GUI.Target.style = dt.new_widget('combobox'){ GUI.Target.style = dt.new_widget('combobox'){
label = _('apply style on import'), label = _('apply style on import'),
tooltip = _('Apply selected style on auto-import to newly created image'), tooltip = _('Apply selected style on auto-import to newly created image'),
selected = 1, selected = 1,
_('none'), _('none'),
changed_callback = function(self) changed_callback = function(self)
dt.preferences.write(mod, 'active_style', 'string', self.value) dt.preferences.write(mod, 'active_style', 'string', self.value)
dt.preferences.write(mod, 'active_style_ind', 'integer', self.selected) dt.preferences.write(mod, 'active_style_ind', 'integer', self.selected)
end, end,
reset_callback = function(self) reset_callback = function(self)
self.selected = 1 self.selected = 1
dt.preferences.write(mod, 'active_style', 'string', self.value) dt.preferences.write(mod, 'active_style', 'string', self.value)
dt.preferences.write(mod, 'active_style_ind', 'integer', self.selected) dt.preferences.write(mod, 'active_style_ind', 'integer', self.selected)
end end
} }
for k=1, (styles_count-1) do for k=1, (styles_count-1) do
GUI.Target.style[k+1] = styles[k].name GUI.Target.style[k+1] = styles[k].name
end end
temp = dt.preferences.read(mod, 'active_style_ind', 'integer') temp = dt.preferences.read(mod, 'active_style_ind', 'integer')
if not InRange(temp, 1, styles_count) then temp = 1 end if not InRange(temp, 1, styles_count) then temp = 1 end
GUI.Target.style.selected = temp GUI.Target.style.selected = temp
GUI.Target.copy_tags = dt.new_widget('check_button'){ GUI.Target.copy_tags = dt.new_widget('check_button'){
label = _('copy tags'), label = _('copy tags'),
value = dt.preferences.read(mod, 'active_copy_tags', 'bool'), value = dt.preferences.read(mod, 'active_copy_tags', 'bool'),
tooltip = _('copy tags from first source image'), tooltip = _('copy tags from first source image'),
clicked_callback = function(self) dt.preferences.write(mod, 'active_copy_tags', 'bool', self.value) end, clicked_callback = function(self) dt.preferences.write(mod, 'active_copy_tags', 'bool', self.value) end,
reset_callback = function(self) self.value = true end reset_callback = function(self) self.value = true end
} }
temp = dt.preferences.read(mod, 'active_add_tags', 'string') temp = dt.preferences.read(mod, 'active_add_tags', 'string')
if temp == '' then temp = nil end if temp == '' then temp = nil end
GUI.Target.add_tags = dt.new_widget('entry'){ GUI.Target.add_tags = dt.new_widget('entry'){
tooltip = _('Additional tags to be added on import. Seperate with commas, all spaces will be removed'), tooltip = _('Additional tags to be added on import. Seperate with commas, all spaces will be removed'),
text = temp, text = temp,
placeholder = _('Enter tags, seperated by commas'), placeholder = _('Enter tags, seperated by commas'),
editable = true editable = true
} }
GUI.run = dt.new_widget('button'){ GUI.run = dt.new_widget('button'){
label = _('merge'), label = _('merge'),
tooltip =_('run HDRMerge with the above specified settings'), tooltip =_('run HDRMerge with the above specified settings'),
clicked_callback = function() main() end clicked_callback = function() main() end
} }
GUI.exes.HDRMerge = dt.new_widget('file_chooser_button'){ GUI.exes.HDRMerge = dt.new_widget('file_chooser_button'){
title = _('Select HDRmerge executable'), title = _('Select HDRmerge executable'),
value = df.get_executable_path_preference(HDRM.name), value = df.get_executable_path_preference(HDRM.name),
is_directory = false is_directory = false
} }
GUI.exes.update = dt.new_widget('button'){ GUI.exes.update = dt.new_widget('button'){
label = _('update'), label = _('update'),
tooltip =_('update the binary path with current value'), tooltip =_('update the binary path with current value'),
clicked_callback = function() ExeUpdate({HDRM}) end clicked_callback = function() ExeUpdate({HDRM}) end
} }
GUI.options = dt.new_widget('box'){ GUI.options = dt.new_widget('box'){
orientation = 'vertical', orientation = 'vertical',
lbl_hdr, lbl_hdr,
GUI.HDR.bps, GUI.HDR.bps,
GUI.HDR.size, GUI.HDR.size,
GUI.HDR.batch, GUI.HDR.batch,
GUI.HDR.gap, GUI.HDR.gap,
lbl_import, lbl_import,
GUI.Target.style, GUI.Target.style,
GUI.Target.copy_tags, GUI.Target.copy_tags,
GUI.Target.add_tags, GUI.Target.add_tags,
GUI.run GUI.run
} }
local exes_box = dt.new_widget('box'){ local exes_box = dt.new_widget('box'){
orientation = 'vertical', orientation = 'vertical',
GUI.exes.HDRMerge, GUI.exes.HDRMerge,
GUI.exes.update GUI.exes.update
} }
GUI.stack = dt.new_widget('stack'){ GUI.stack = dt.new_widget('stack'){
GUI.options, GUI.options,
exes_box exes_box
} }
if dt.preferences.read(mod, 'bin_exists', 'bool') then if dt.preferences.read(mod, 'bin_exists', 'bool') then
GUI.stack.active = 1 GUI.stack.active = 1
else else
GUI.stack.active = 2 GUI.stack.active = 2
end end
dt.register_lib( -- register HDRMerge module if dt.gui.current_view().id == "lighttable" then
'HDRMerge_Lib', -- Module name install_module()
_('HDRMerge'), -- name else
true, -- expandable if not HDRM.event_registered then
true, -- resetable dt.register_event(
{[dt.gui.views.lighttable] = {'DT_UI_CONTAINER_PANEL_RIGHT_CENTER', 99}}, -- containers "view-changed",
dt.new_widget('box'){ function(event, old_view, new_view)
orientation = 'vertical', if new_view.name == "lighttable" and old_view.name == "darkroom" then
GUI.stack install_module()
} end
) end
)
HDRM.event_registered = true
end
end

View File

@@ -55,7 +55,12 @@ du.check_min_api_version("3.0.0", "LabelsToTags")
-- Lua 5.3 no longer has "unpack" but "table.unpack" -- Lua 5.3 no longer has "unpack" but "table.unpack"
unpack = unpack or table.unpack unpack = unpack or table.unpack
local ltt = {}
ltt.module_installed = false
ltt.event_registered = false
local LIB_ID = "LabelsToTags" local LIB_ID = "LabelsToTags"
local CURR_API_STRING = darktable.configuration.api_version_string
-- Helper functions: BEGIN -- Helper functions: BEGIN
@@ -184,7 +189,7 @@ local function doTagging(selfC)
job.valid = false job.valid = false
end end
local my_widget = darktable.new_widget("box") { ltt.my_widget = darktable.new_widget("box") {
orientation = "vertical", orientation = "vertical",
mappingComboBox, mappingComboBox,
darktable.new_widget("button") { darktable.new_widget("button") {
@@ -217,6 +222,15 @@ darktable.register_tag_mapping = function(name, mapping)
mappingComboBox.reset_callback(mappingComboBox) mappingComboBox.reset_callback(mappingComboBox)
end end
local function install_module()
if not ltt.module_installed then
darktable.register_lib(LIB_ID,"labels to tags",true,true,{
[darktable.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER",20},
},ltt.my_widget,nil,nil)
ltt.module_installed = true
end
end
--[[ --[[
darktable.register_tag_mapping("Example", darktable.register_tag_mapping("Example",
{ ["+----*"] = { "Red", "Only red" }, { ["+----*"] = { "Red", "Only red" },
@@ -229,6 +243,19 @@ darktable.register_tag_mapping("Example",
["*****R"] = { "Rejected" } }) ["*****R"] = { "Rejected" } })
]] ]]
darktable.register_lib(LIB_ID,"labels to tags",true,true,{ if darktable.gui.current_view().id == "lighttable" then
[darktable.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER",20}, install_module()
},my_widget,nil,nil) else
if not ltt.event_registered then
darktable.register_event(
"view-changed",
function(event, old_view, new_view)
if new_view.name == "lighttable" and old_view.name == "darkroom" then
install_module()
end
end
)
ltt.event_registered = true
end
end

View File

@@ -32,12 +32,18 @@ Install: (see here for more detail: https://github.com/darktable-org/lua-scripts
Select the photo(s) you wish to find in your operating system's file manager and press "show in file explorer" in the "selected images" section. Select the photo(s) you wish to find in your operating system's file manager and press "show in file explorer" in the "selected images" section.
- Nautilus (Linux), Explorer (Windows), and Finder (macOS before Catalina) will open one window for each selected image at the file's location. The file name will be highlighted. - Nautilus (Linux), Explorer (Windows), and Finder (macOS prior to Mojave) will open one window for each selected image at the file's location. The file name will be highlighted.
- On macOS Catalina the Finder will open one window for each different directory. In these windows only the last one of the corresponding files will be highlighted (bug or feature?). - On macOS Mojave and Catalina the Finder will open one window for each different directory. In these windows only the last one of the corresponding files will be highlighted (bug or feature?).
- Dolphin (Linux) will open one window with tabs for the different directories. All the selected images' file names are highlighted in their respective directories. - Dolphin (Linux) will open one window with tabs for the different directories. All the selected images' file names are highlighted in their respective directories.
As an alternative option you can choose to show the image file names as symbolic links in an arbitrary directory. Go to preferences|Lua options. This option is not available for Windows users as on Windows solely admins are allowed to create links.
- Pros: You do not clutter up your display with multiple windows. So there is no need to limit the number of selections.
- Cons: If you want to work with the files you are one step behind the original data.
----KNOWN ISSUES---- ----KNOWN ISSUES----
]] ]]
@@ -50,6 +56,7 @@ local gettext = dt.gettext
--Check API version --Check API version
du.check_min_api_version("5.0.0", "OpenInExplorer") du.check_min_api_version("5.0.0", "OpenInExplorer")
-- Tell gettext where to find the .mo file translating messages for a particular domain
gettext.bindtextdomain("OpenInExplorer",dt.configuration.config_dir.."/lua/locale/") gettext.bindtextdomain("OpenInExplorer",dt.configuration.config_dir.."/lua/locale/")
local function _(msgid) local function _(msgid)
@@ -58,54 +65,153 @@ end
local act_os = dt.configuration.running_os local act_os = dt.configuration.running_os
local PS = act_os == "windows" and "\\" or "/" local PS = act_os == "windows" and "\\" or "/"
local CURR_API_STRING = dt.configuration.api_version_string
--Detect OS and quit if it is not supported-- --Detect OS and quit if it is not supported.
local proper_install = true
if act_os ~= "macos" and act_os ~= "windows" and act_os ~= "linux" then if act_os ~= "macos" and act_os ~= "windows" and act_os ~= "linux" then
proper_install = false dt.print(_("OpenInExplorer plug-in only supports Linux, macOS, and Windows at this time"))
dt.print_error(_('OpenInExplorer plug-in only supports Linux, macOS, and Windows at this time')) dt.print_error("OpenInExplorer plug-in only supports Linux, macOS, and Windows at this time")
return return
end end
--Format strings for the commands to open the corresponding OS' file manager local use_links, links_dir = false, ""
local fmng_cmd = {} if act_os ~= "windows" then
fmng_cmd.linux = [[busctl --user call org.freedesktop.FileManager1 /org/freedesktop/FileManager1 org.freedesktop.FileManager1 ShowItems ass %d %s""]] use_links = dt.preferences.read("OpenInExplorer", "use_links", "bool")
fmng_cmd.macos = 'open -Rn %s' links_dir = dt.preferences.read("OpenInExplorer", "linked_image_files_dir", "string")
fmng_cmd.windows = 'explorer.exe /select, %s' end
--The working function that opens the file manager windows with the selected image file names highlighted. --Check if the directory exists that was chosen for the file links. Return boolean.
local function open_in_fmanager(op_sys, fmcmd) local function check_if_links_dir_exists()
local images = dt.gui.selection() local dir_exists = true
local curr_image, run_cmd, file_uris = '', '', '' if not links_dir then
if #images == 0 then --Just for paranoic reasons. I tried, but I couldn't devise a setting for a nil value.
dt.print(_('Please select an image')) dt.print(_("No links directory selected.\nPlease check the dt preferences (lua options)"))
elseif #images <= 15 then dt.print_error("OpenInExplorer: No links directory selected")
for _,image in pairs(images) do dir_exists = false
curr_image = image.path..PS..image.filename elseif not df.check_if_file_exists(links_dir) then
if op_sys == 'linux' then dt.print(string.format(_("Links directory '%s' not found.\nPlease check the dt preferences (lua options)"), links_dir))
file_uris = file_uris .. df.sanitize_filename("file://" .. curr_image) .. " " dt.print_error(string.format("OpenInExplorer: Links directory '%s' not found", links_dir))
dt.print_log("file_uris is " .. file_uris) dir_exists = false
else end
run_cmd = string.format(fmcmd, df.sanitize_filename(curr_image)) return dir_exists
dt.print_log("OpenInExplorer run_cmd = "..run_cmd) end
dsys.external_command(run_cmd)
end --Format strings for the commands to open the corresponding OS's file manager.
end local open_dir = {}
if op_sys == 'linux' then open_dir.windows = "explorer.exe /n, %s"
run_cmd = string.format(fmcmd, #images, file_uris) open_dir.macos = "open %s"
dt.print_log("OpenInExplorer run_cmd = "..run_cmd) open_dir.linux = [[busctl --user call org.freedesktop.FileManager1 /org/freedesktop/FileManager1 org.freedesktop.FileManager1 ShowFolders ass 1 %s ""]]
dsys.external_command(run_cmd)
end local open_files = {}
else open_files.windows = "explorer.exe /select, %s"
dt.print(_('Please select fewer images (max 15)')) open_files.macos = "open -Rn %s"
open_files.linux = [[busctl --user call org.freedesktop.FileManager1 /org/freedesktop/FileManager1 org.freedesktop.FileManager1 ShowItems ass %d %s ""]]
--Call the file mangager for each selected image on Linux.
--There is one call to busctl containing a list of all the image file names.
local function call_list_of_files(selected_images)
local current_image, file_uris, run_cmd = "", "", ""
for _, image in pairs(selected_images) do
current_image = image.path..PS..image.filename
file_uris = file_uris .. df.sanitize_filename("file://" .. current_image) .. " "
dt.print_log("file_uris is " .. file_uris)
end
run_cmd = string.format(open_files.linux, #selected_images, file_uris)
dt.print_log("OpenInExplorer run_cmd = "..run_cmd)
dsys.external_command(run_cmd)
end
--Call the file manager for each selected image on Windows and macOS.
local function call_file_by_file(selected_images)
local current_image, run_cmd = "", ""
for _, image in pairs(selected_images) do
current_image = image.path..PS..image.filename
run_cmd = string.format(open_files[act_os], df.sanitize_filename(current_image))
dt.print_log("OpenInExplorer run_cmd = "..run_cmd)
dsys.external_command(run_cmd)
end end
end end
--Create a link for each selected image, and finally call the file manager.
local function set_links(selected_images)
local current_image, link_target, run_cmd, k = "", "", "", nil
for k, image in pairs(selected_images) do
current_image = image.path..PS..image.filename
link_target = df.create_unique_filename(links_dir .. PS .. image.filename)
run_cmd = string.format("ln -s %s %s", df.sanitize_filename(current_image), df.sanitize_filename(link_target))
--[[
In case Windows will allow normal users to create soft links:
if act_os == "windows" then
run_cmd = string.format("mklink %s %s", df.sanitize_filename(link_target), df.sanitize_filename(current_image))
end
]]
if dsys.external_command(run_cmd) ~= 0 then
dt.print(_("Failed to create links. Missing rights?"))
dt.print_error("OpenInExplorer: Failed to create links")
return
end
end
--The URI format is necessary only for the Linux busctl command.
--But it is accepted by the Windows Explorer and macOS's Finder all the same.
run_cmd = string.format(open_dir[act_os], df.sanitize_filename("file://"..links_dir))
dt.print_log("OpenInExplorer run_cmd = "..run_cmd)
dsys.external_command(run_cmd)
end
--The working function that starts the particular task.
local function open_in_fmanager()
local images = dt.gui.selection()
if #images == 0 then
dt.print(_("Please select an image"))
else
if use_links and not check_if_links_dir_exists() then
return
end
if #images > 15 and not use_links then
dt.print(_("Please select fewer images (max. 15)"))
elseif use_links then
set_links(images)
else
if act_os == "linux" then
call_list_of_files(images)
else
call_file_by_file(images)
end
end
end
end
-- GUI -- -- GUI --
if proper_install then dt.gui.libs.image.register_action(
dt.gui.libs.image.register_action( _("show in file explorer"),
_("show in file explorer"), function() open_in_fmanager() end,
function() open_in_fmanager(act_os, fmng_cmd[act_os]) end, _("Open the file manager at the selected image's location")
_("Opens the file manager at the selected image's location") )
if act_os ~= "windows" then
dt.preferences.register("OpenInExplorer", "linked_image_files_dir", -- name
"directory", -- type
_("OpenInExplorer: linked files directory"), -- label
_("Directory to store the links to the file names. Requires restart to take effect"), -- tooltip
"Links to image files", -- default
dt.new_widget("file_chooser_button"){
title = _("Select directory"),
is_directory = true,
}
)
dt.preferences.register("OpenInExplorer", "use_links", -- name
"bool", -- type
_("OpenInExplorer: use links"), -- label
_("Use links instead of multiple windows. Requires restart to take effect"), -- tooltip
false, -- default
""
) )
end end
dt.register_event(
"shortcut",
function(event, shortcut) open_in_fmanager() end,
"OpenInExplorer"
)

View File

@@ -1,10 +1,29 @@
--[[ --[[
Richardson-Lucy output sharpening for darktable using GMic
darktable 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.
darktable 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 darktable. If not, see <http://www.gnu.org/licenses/>.
]]
--[[
DESCRIPTION DESCRIPTION
RL_out_sharp.lua - Richardson-Lucy output sharpening using GMic RL_out_sharp.lua - Richardson-Lucy output sharpening using GMic
This script provides a new target storage "RL output sharpen". This script provides a new target storage "RL output sharpen".
Images exported will be sharpened using GMic (RL deblur algorithm) Images exported will be sharpened using GMic (RL deblur algorithm)
REQUIRED SOFTWARE
GMic command line interface (CLI) https://gmic.eu/download.shtml
USAGE USAGE
* require this script from main lua file * require this script from main lua file
@@ -33,7 +52,6 @@
CHANGES CHANGES
* 20200308 - initial version * 20200308 - initial version
]] ]]
local dt = require "darktable" local dt = require "darktable"
@@ -156,7 +174,7 @@ sigma_slider = dt.new_widget("slider"){
soft_max = 2.0, soft_max = 2.0,
hard_min = 0.0, hard_min = 0.0,
hard_max = 3.0, hard_max = 3.0,
step = 0.1, step = 0.05,
digits = 2, digits = 2,
value = 1.0 value = 1.0
} }

View File

@@ -42,6 +42,7 @@ local filelib = require "lib/dtutils.file"
-- Forward declare the functions -- Forward declare the functions
local autostyle_apply_one_image,autostyle_apply_one_image_event,autostyle_apply,exiftool_attribute,capture local autostyle_apply_one_image,autostyle_apply_one_image_event,autostyle_apply,exiftool_attribute,capture
local CURR_API_STRING = darktable.configuration.api_version_string
-- Tested it with darktable 1.6.1 and darktable git from 2014-01-25 -- Tested it with darktable 1.6.1 and darktable git from 2014-01-25
du.check_min_api_version("2.0.2", "autostyle") du.check_min_api_version("2.0.2", "autostyle")
@@ -151,11 +152,12 @@ function get_stdout(cmd)
end end
-- Registering events -- Registering events
darktable.register_event("shortcut",autostyle_apply, darktable.register_event("shortcut", autostyle_apply,
"Apply your chosen style from exiftool tags") "Apply your chosen style from exiftool tags")
darktable.preferences.register("autostyle","exif_tag","string","Autostyle: EXIF_tag=value=>style","apply a style automatically if an EXIF_tag matches value. Find the tag with exiftool","") darktable.preferences.register("autostyle","exif_tag","string","Autostyle: EXIF_tag=value=>style","apply a style automatically if an EXIF_tag matches value. Find the tag with exiftool","")
darktable.register_event("post-import-image",autostyle_apply_one_image_event) darktable.register_event("post-import-image",
autostyle_apply_one_image_event)

View File

@@ -1,6 +1,6 @@
--[[ --[[
clear_GPS.lua - export and edit with GIMP clear_GPS.lua - plugin for Darktable
Copyright (C) 2016 Bill Ferguson <wpferguson@gmail.com>. Copyright (C) 2016 Bill Ferguson <wpferguson@gmail.com>.
@@ -38,12 +38,14 @@
local dt = require "darktable" local dt = require "darktable"
local du = require "lib/dtutils" local du = require "lib/dtutils"
local gettext = dt.gettext local gettext = dt.gettext
-- not a number -- not a number
local NaN = 0/0 local NaN = 0/0
du.check_min_api_version("3.0.0", "clear_GPS") du.check_min_api_version("3.0.0", "clear_GPS")
local CURR_API_STRING = dt.configuration.api_version_string
-- Tell gettext where to find the .mo file translating messages for a particular domain -- Tell gettext where to find the .mo file translating messages for a particular domain
@@ -62,15 +64,14 @@ local function clear_GPS(images)
end end
end end
dt.gui.libs.image.register_action( dt.gui.libs.image.register_action(
_("clear GPS data"), _("clear GPS data"),
function(event, images) clear_GPS(images) end, function(event, images) clear_GPS(images) end,
"clear GPS data" _("Clear GPS data from selected images")
) )
dt.register_event( dt.register_event(
"shortcut", "shortcut",
function(event, shortcut) clear_GPS(dt.gui.action_images) end, function(event, shortcut) clear_GPS(dt.gui.action_images) end,
"clear GPS data" _("Clear GPS data")
) )

View File

@@ -43,6 +43,7 @@ local debug = require "darktable.debug"
local gettext = dt.gettext local gettext = dt.gettext
du.check_min_api_version("3.0.0", "copy_attach_detach_tags") du.check_min_api_version("3.0.0", "copy_attach_detach_tags")
local CURR_API_STRING = dt.configuration.api_version_string
-- Tell gettext where to find the .mo file translating messages for a particular domain -- Tell gettext where to find the .mo file translating messages for a particular domain
gettext.bindtextdomain("copy_attach_detach_tags",dt.configuration.config_dir.."/lua/locale/") gettext.bindtextdomain("copy_attach_detach_tags",dt.configuration.config_dir.."/lua/locale/")
@@ -51,6 +52,11 @@ local function _(msgid)
return gettext.dgettext("copy_attach_detach_tags", msgid) return gettext.dgettext("copy_attach_detach_tags", msgid)
end end
local cadt = {}
cadt.module_installed = false
cadt.event_registered = false
cadt.widget_table = {}
local image_tags = {} local image_tags = {}
@@ -107,7 +113,7 @@ local function mcopy_tags()
local function attach_tags() local function attach_tags()
if next(image_tags) == nil then if next(image_tags) == nil then
dt.print(_('No tags to attached, please copy tags first.')) dt.print(_('No tag to attach, please copy tags first.'))
return true return true
end end
@@ -156,6 +162,26 @@ local function replace_tags()
dt.print(_('Tags replaced')) dt.print(_('Tags replaced'))
end end
local function install_module()
if not cadt.module_installed then
dt.register_lib("tagging_addon",_('tagging addon'),true,true,{
[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER",500}
},
dt.new_widget("box") {
-- orientation = "vertical",
reset_callback = function()
taglist_label.label = ""
image_tags = {}
end,
table.unpack(cadt.widget_table),
},
nil,
nil
)
cadt.module_installed = true
end
end
-- create modul Tagging addons -- create modul Tagging addons
taglist_label.reset_callback = mcopy_tags taglist_label.reset_callback = mcopy_tags
@@ -169,52 +195,55 @@ local taglabel = dt.new_widget("label") {
local box1 = dt.new_widget("box"){ local box1 = dt.new_widget("box"){
orientation = "horizontal", orientation = "horizontal",
dt.new_widget("button") { dt.new_widget("button") {
label = _('multi copy tags'), label = _('multi copy tags'),
clicked_callback = mcopy_tags}, tooltip = _('copy tags from selected image(s)'),
clicked_callback = mcopy_tags},
dt.new_widget("button") { dt.new_widget("button") {
label = _('paste tags'), tooltip = _('paste tags to selected image(s)'),
clicked_callback = attach_tags} label = _('paste tags'),
clicked_callback = attach_tags}
} }
local box2 = dt.new_widget("box"){ local box2 = dt.new_widget("box"){
orientation = "horizontal", orientation = "horizontal",
dt.new_widget("button") { dt.new_widget("button") {
label = _('replace tags'), label = _('replace tags'),
clicked_callback = replace_tags}, tooltip = _('replace tags from selected image(s)'),
clicked_callback = replace_tags},
dt.new_widget("button") { dt.new_widget("button") {
label = _('remove all tags'), label = _('remove all tags'),
clicked_callback = detach_tags} tooltip = _('remove tags from selected image(s)'),
clicked_callback = detach_tags}
} }
local sep = dt.new_widget("separator"){} local sep = dt.new_widget("separator"){}
-- pack elements into widget table for a nicer layout -- pack elements into widget table for a nicer layout
local widget_table = {}
widget_table[1] = box1 cadt.widget_table[1] = box1
widget_table[#widget_table+1] = box2 cadt.widget_table[#cadt.widget_table+1] = box2
widget_table[#widget_table+1] = sep cadt.widget_table[#cadt.widget_table+1] = sep
widget_table[#widget_table+1] = taglabel cadt.widget_table[#cadt.widget_table+1] = taglabel
widget_table[#widget_table+1] = taglist_label cadt.widget_table[#cadt.widget_table+1] = taglist_label
-- create modul -- create modul
dt.register_lib("tagging_addon","Tagging addon",true,true,{ if dt.gui.current_view().id == "lighttable" then
[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER",500} install_module()
}, else
dt.new_widget("box") { if not cadt.event_registered then
-- orientation = "vertical", dt.register_event(
reset_callback = function() "view-changed",
taglist_label.label = "" function(event, old_view, new_view)
image_tags = {} if new_view.name == "lighttable" and old_view.name == "darkroom" then
end, install_module()
table.unpack(widget_table), end
}, end
nil, )
nil cadt.event_registered = true
) end
end
-- shortcut for copy -- shortcut for copy

View File

@@ -37,6 +37,7 @@ local du = require "lib/dtutils"
-- Tested with darktable 2.0.1 -- Tested with darktable 2.0.1
du.check_min_api_version("2.0.0", "cr2hdr") du.check_min_api_version("2.0.0", "cr2hdr")
local CURR_API_STRING = darktable.configuration.api_version_string
local queue = {} local queue = {}
local processed_files = {} local processed_files = {}
@@ -107,8 +108,11 @@ local function convert_action_images(shortcut)
convert_images() convert_images()
end end
darktable.register_event("shortcut", convert_action_images, "Run cr2hdr (Magic Lantern DualISO converter) on selected images") darktable.register_event("shortcut",
darktable.register_event("post-import-image", file_imported) convert_action_images, "Run cr2hdr (Magic Lantern DualISO converter) on selected images")
darktable.register_event("post-import-film", film_imported) darktable.register_event("post-import-image",
file_imported)
darktable.register_event("post-import-film",
film_imported)
darktable.preferences.register("cr2hdr", "onimport", "bool", "Invoke on import", "If true then cr2hdr will try to proccess every file during importing. Warning: cr2hdr is quite slow even in figuring out on whether the file is Dual ISO or not.", false) darktable.preferences.register("cr2hdr", "onimport", "bool", "Invoke on import", "If true then cr2hdr will try to proccess every file during importing. Warning: cr2hdr is quite slow even in figuring out on whether the file is Dual ISO or not.", false)

View File

@@ -180,6 +180,11 @@ for _,i in pairs(dt.styles) do
end end
-- FUNCTION -- -- FUNCTION --
local function sanitize_decimals(cmd) -- make sure decimal separator is a '.'
return string.gsub(cmd, '(%d),(%d)', "%1.%2")
end
local function InRange(test, low, high) -- tests if test value is within range of low and high (inclusive) local function InRange(test, low, high) -- tests if test value is within range of low and high (inclusive)
if test >= low and test <= high then if test >= low and test <= high then
return true return true
@@ -240,7 +245,7 @@ end
local function ExeUpdate(prog_tbl) --updates executable paths and verifies them local function ExeUpdate(prog_tbl) --updates executable paths and verifies them
dt.preferences.write(mod, 'bin_exists', 'bool', true) dt.preferences.write(mod, 'bin_exists', 'bool', true)
for _,prog in pairs(prog_tbl) do for x,prog in pairs(prog_tbl) do
dt.preferences.write('executable_paths', prog.name, 'string', GUI.exes[prog.name].value) dt.preferences.write('executable_paths', prog.name, 'string', GUI.exes[prog.name].value)
prog.bin = df.check_if_bin_exists(prog.name) prog.bin = df.check_if_bin_exists(prog.name)
if not prog.bin then if not prog.bin then
@@ -311,7 +316,7 @@ local function UpdateENFargs(image_table, prefix) --updates the Enfuse arguments
local largest_id = 0 local largest_id = 0
local first_raw = {} local first_raw = {}
for raw, temp_image in pairs(image_table) do for raw, temp_image in pairs(image_table) do
_, source_name, source_id = GetFileName(raw.filename) local _, source_name, source_id = GetFileName(raw.filename)
source_id = tonumber(source_id) source_id = tonumber(source_id)
if source_id < smallest_id then if source_id < smallest_id then
smallest_id = source_id smallest_id = source_id
@@ -435,6 +440,9 @@ local function main(storage, image_table, extra_data)
local job = dt.gui.create_job('aligning images') local job = dt.gui.create_job('aligning images')
image_table, images_to_remove, AIS.images_string = UpdateAISargs(image_table, images_to_remove) image_table, images_to_remove, AIS.images_string = UpdateAISargs(image_table, images_to_remove)
local run_cmd = BuildExecuteCmd(AIS) local run_cmd = BuildExecuteCmd(AIS)
dt.print_log("AIS run command is " .. run_cmd)
run_cmd = sanitize_decimals(run_cmd)
dt.print_log("AIS decimaal sanitized command is " .. run_cmd)
local resp = dsys.external_command(run_cmd) local resp = dsys.external_command(run_cmd)
job.valid = false job.valid = false
if resp ~= 0 then if resp ~= 0 then
@@ -455,11 +463,14 @@ local function main(storage, image_table, extra_data)
local image_num = 0 local image_num = 0
local job = dt.gui.create_job('blending '..#variants..' image(s)', true) --create a GUI job bar to display enfuse progress local job = dt.gui.create_job('blending '..#variants..' image(s)', true) --create a GUI job bar to display enfuse progress
UpdateActivePreference() --load current GUI values into active preference (only applies to elements without a clicked/changed callback) UpdateActivePreference() --load current GUI values into active preference (only applies to elements without a clicked/changed callback)
for _,prefix in pairs(variants) do --for each image to be created load in the preference values, build arguments string, output image, and run command then execute. for x,prefix in pairs(variants) do --for each image to be created load in the preference values, build arguments string, output image, and run command then execute.
job.percent = image_num /(#variants) job.percent = image_num /(#variants)
image_num = image_num+1 image_num = image_num+1
ENF.images_string, final_image, source_raw = UpdateENFargs(image_table, prefix) ENF.images_string, final_image, source_raw = UpdateENFargs(image_table, prefix)
local run_cmd = BuildExecuteCmd(ENF) local run_cmd = BuildExecuteCmd(ENF)
dt.print_log("ENF run command is " .. run_cmd)
run_cmd = sanitize_decimals(run_cmd)
dt.print_log("ENF decimaal sanitized command is " .. run_cmd)
local resp = dsys.external_command(run_cmd) local resp = dsys.external_command(run_cmd)
if resp ~= 0 then if resp ~= 0 then
remove_temp_files(images_to_remove) remove_temp_files(images_to_remove)
@@ -470,11 +481,16 @@ local function main(storage, image_table, extra_data)
--copy exif data from original file --copy exif data from original file
run_cmd = EXF.bin..' -TagsFromFile '..df.sanitize_filename(source_raw.path..os_path_seperator..source_raw.filename)..' -exif:all --subifd:all -overwrite_original '..df.sanitize_filename(final_image) run_cmd = EXF.bin..' -TagsFromFile '..df.sanitize_filename(source_raw.path..os_path_seperator..source_raw.filename)..' -exif:all --subifd:all -overwrite_original '..df.sanitize_filename(final_image)
-- replace comma decimal separator with period
dt.print_log("EXF run command is " .. run_cmd)
run_cmd = sanitize_decimals(run_cmd)
dt.print_log("EXF decimaal sanitized command is " .. run_cmd)
resp = dsys.external_command(run_cmd) resp = dsys.external_command(run_cmd)
if GUI.Target.auto_import.value then --import image into dt if specified if GUI.Target.auto_import.value then --import image into dt if specified
local imported = dt.database.import(final_image) local imported = dt.database.import(final_image)
dt.print_log("image imported")
if GUI.Target.apply_style.selected > 1 then --apply specified style to imported image if GUI.Target.apply_style.selected > 1 then --apply specified style to imported image
local set_style = styles[GUI.Target.apply_style.selected - 1] local set_style = styles[GUI.Target.apply_style.selected - 1]
dt.styles.apply(set_style , imported) dt.styles.apply(set_style , imported)
@@ -939,7 +955,7 @@ GUI.Presets.current_preset = dt.new_widget('combobox'){
end end
} }
GUI.Presets.load = dt.new_widget('button'){ GUI.Presets.load = dt.new_widget('button'){
label = _('laod fusion preset'), label = _('load fusion preset'),
tooltip = _('load current fusion parameters from selected preset'), tooltip = _('load current fusion parameters from selected preset'),
clicked_callback = function() LoadFromPreference(GUI.Presets.current_preset.value) end clicked_callback = function() LoadFromPreference(GUI.Presets.current_preset.value) end
} }

175
contrib/exportLUT.lua Normal file
View File

@@ -0,0 +1,175 @@
--[[
This file is part of darktable,
copyright (c) 2020 Noah Clarke
darktable 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.
darktable 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 darktable. If not, see <http://www.gnu.org/licenses/>.
]]
--[[
Add the following line to .config/darktable/luarc to enable this lightable module:
require "contrib/exportLut"
Given a haldCLUT identity file this script generates haldCLUTS from all the user's
styles and exports them to a location of their choosing.
Warning: during export if a naming collision occurs the older file is automatically
overwritten silently.
]]
local dt = require "darktable"
local du = require "lib/dtutils"
local df = require("lib/dtutils.file")
local ds = require("lib/dtutils.system")
local gettext = dt.gettext
gettext.bindtextdomain("exportLUT",dt.configuration.config_dir.."/lua/locale/")
local CURR_API_STRING = dt.configuration.api_version_string
local function _(msgid)
return gettext.dgettext("exportLUT", msgid)
end
du.check_min_api_version("5.0.0", "exportLUT")
local eL = {}
eL.module_installed = false
eL.event_registered = false
eL.widgets = {}
-- Thanks Kevin Ertel for this bit
local os_path_seperator = '/'
if dt.configuration.running_os == 'windows' then os_path_seperator = '\\' end
local mkdir_command = 'mkdir -p '
if dt.configuration.running_os == 'windows' then mkdir_command = 'mkdir ' end
local file_chooser_button = dt.new_widget("file_chooser_button"){
title = _("Identity_file_chooser"),
value = "",
is_directory = false
}
local export_chooser_button = dt.new_widget("file_chooser_button"){
title = _("Export_location_chooser"),
value = "",
is_directory = true
}
local identity_label = dt.new_widget("label"){
label = _("choose the identity haldclut file")
}
local output_label = dt.new_widget("label"){
label = _("choose the output location")
}
local warning_label = dt.new_widget("label"){
label = _("WARNING: files may be silently overwritten")
}
local function end_job(job)
job.valid = false
end
local function output_path(style_name, job)
local output_location = export_chooser_button.value .. os_path_seperator .. style_name .. ".png"
output_location = string.gsub(output_location, "|", os_path_seperator)
local output_dir = string.reverse(output_location)
output_dir = string.gsub(output_dir, ".-" .. os_path_seperator, os_path_seperator, 1)
output_dir = string.reverse(output_dir)
if(output_dir ~= "") then
df.mkdir(df.sanitize_filename(output_dir))
end
return output_location
end
local function export_luts()
local identity = dt.database.import(file_chooser_button.value)
if(type(identity) ~= "userdata") then
dt.print(_("Invalid identity lut file"))
else
local job = dt.gui.create_job(_('Exporting styles as haldCLUTs'), true, end_job)
local size = 1
for style_num, style in ipairs(dt.styles) do
size = size + 1
end
local count = 0
for style_num, style in ipairs(dt.styles) do
identity:reset()
dt.styles.apply(style, identity)
local io_lut = dt.new_format("png")
io_lut.bpp = 8
io_lut:write_image(identity, output_path(style.name, job))
count = count + 1
job.percent = count / size
dt.print(_("Exported: ") .. output_path(style.name, job))
end
dt.print(_("Done exporting haldCLUTs"))
job.valid = false
identity:reset()
end
end
local function install_module()
if not eL.module_installed then
dt.register_lib(
_("export haldclut"),
_("export haldclut"),
true,
false,
{[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}},
dt.new_widget("box")
{
orientation = "vertical",
table.unpack(eL.widgets),
},
nil,
nil
)
eL.module_installed = true
end
end
local export_button = dt.new_widget("button"){
label = _("export"),
clicked_callback = export_luts
}
table.insert(eL.widgets, identity_label)
table.insert(eL.widgets, file_chooser_button)
table.insert(eL.widgets, output_label)
table.insert(eL.widgets, export_chooser_button)
table.insert(eL.widgets, warning_label)
table.insert(eL.widgets, export_button)
if dt.gui.current_view().id == "lighttable" then
install_module()
else
if not eL.event_registered then
dt.register_event(
"view-changed",
function(event, old_view, new_view)
if new_view.name == "lighttable" and old_view.name == "darkroom" then
install_module()
end
end
)
eL.event_registered = true
end
end

View File

@@ -1,64 +1,67 @@
--[[ --[[
ext_editor.lua - edit images with external editors
DESCRIPTION darktable 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.
darktable 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 darktable. If not, see <http://www.gnu.org/licenses/>.
]]
--[[
ext_editor.lua - edit images with external editors ext_editor.lua - edit images with external editors
This script provides helpers to edit image files with programs external to darktable. This script provides helpers to edit image files with programs external to darktable. It adds:
It adds: - a new target storage "collection". Image exported will be reimported to collection for further edit with external programs
- a new target storage "collection". Image exported will be reimported to collection for - a new module "external editors", visible in lightable and darkroom, to select a program from a list
further edit with external programs - of up to 9 external editors and run it on a selected image (adjust this limit by changing MAX_EDITORS)
- a new lighttable module "external editors", to select a program from a list of up to - a set of lua preferences in order to configure name and path of up to 9 external editors
- 9 external editors and run it on a selected image (adjust this limit by changing MAX_EDITORS) - a set of lua shortcuts in order to quick launch the external editors
- a set of lua preferences in order to configure name and path of up to 9 external editors
- a set of lua shortcuts in order to quick launch the external editors
USAGE USAGE
* require this script from main lua file * require this script from main lua file
-- setup -- -- setup --
* in "preferences/lua options" configure name and path/command of external programs * in "preferences/lua options" configure name and path/command of external programs
* note that if a program name is left empty, that and all following entries will be ignored * note that if a program name is left empty, that and all following entries will be ignored
* in "preferences/shortcuts/lua" configure shortcuts for external programs (optional) * in "preferences/shortcuts/lua" configure shortcuts for external programs (optional)
* whenever programs preferences are changed, in lighttable/external editors, press "update list" * whenever programs preferences are changed, in external editors GUI, press "update list"
-- use -- -- use --
* in the export dialog choose "collection" and select the format and bit depth for the * in the export dialog choose "collection" and select the format and bit depth for the
exported image exported image
* press "export" * press "export"
* the exported image will be imported into collection and grouped with the original image * the exported image will be imported into collection and grouped with the original image
* in lighttable, select an image for editing with en external program
* (or in darkroom for the image being edited):
* in external editors GUI, select program and press "edit"
* edit the image with the external editor, overwite the file, quit the external program
* the selected image will be updated
or
* in external editors GUI, select program and press "edit a copy"
* edit the image with the external editor, overwite the file, quit the external program
* a copy of the selected image will be created and updated
or
* use the shortcut to edit the current image with the corresponding external editor
* overwite the file, quit the external program
* the image will be updated
* select an image for editing with en external program, and: * warning: mouseover on lighttable/filmstrip will prevail on current image
* in lighttable/external editors, select program and press "edit" * this is the default DT behavior, not a bug of this script
* edit the image with the external editor, overwite the file, quit the external program
* the selected image will be updated
or
* in lighttable/external editors, select program and press "edit a copy"
* edit the image with the external editor, overwite the file, quit the external program
* a copy of the selected image will be created and updated
or
* in lighttable select target storage "collection"
* enter in darkroom
* to create an export or a copy press CRTL+E
* use the shortcut to edit the current image with the corresponding external editor
* overwite the file, quit the external program
* the darkroom view will be updated
* warning: mouseover on lighttable/filmstrip will prevail on current image
* this is the default DT behavior, not a bug of this script
CAVEATS CAVEATS
* MAC compatibility not tested * MAC compatibility not tested
TODO BUGS, COMMENTS, SUGGESTIONS
* send multiple images to the same program, maybe
BUGS, COMMENTS, SUGGESTIONS
* send to Marco Carrarini, marco.carrarini@gmail.com * send to Marco Carrarini, marco.carrarini@gmail.com
CHANGES
* 20191224 - initial version
* 20191227 - added button "update list", better error handling, fixed bug with groups/tags in "edit"
]] ]]
@@ -70,15 +73,22 @@ local dtsys = require "lib/dtutils.system"
-- module name -- module name
local MODULE_NAME = "ext_editor" local MODULE_NAME = "ext_editor"
local CURR_API_STRING = dt.configuration.api_version_string
-- check API version -- check API version
du.check_min_api_version("5.0.2", MODULE_NAME) -- darktable 3.0 du.check_min_api_version("5.0.2", MODULE_NAME) -- darktable 3.x
-- OS compatibility -- OS compatibility
local PS = dt.configuration.running_os == "windows" and "\\" or "/" local PS = dt.configuration.running_os == "windows" and "\\" or "/"
-- namespace
local ee = {}
ee.module_installed = false
ee.event_registered = false
ee.widgets = {}
-- translation -- translation
local gettext = dt.gettext local gettext = dt.gettext
@@ -98,6 +108,7 @@ local n_entries
local allowed_file_types = {"JPG", "jpg", "JPEG", "jpeg", "TIF", "tif", "TIFF", "tiff", "EXR", "exr", "PNG", "png"} local allowed_file_types = {"JPG", "jpg", "JPEG", "jpeg", "TIF", "tif", "TIFF", "tiff", "EXR", "exr", "PNG", "png"}
-- last used editor initialization
if not dt.preferences.read(MODULE_NAME, "initialized", "bool") then if not dt.preferences.read(MODULE_NAME, "initialized", "bool") then
dt.preferences.write(MODULE_NAME, "lastchoice", "integer", 0) dt.preferences.write(MODULE_NAME, "lastchoice", "integer", 0)
dt.preferences.write(MODULE_NAME, "initialized", "bool", true) dt.preferences.write(MODULE_NAME, "initialized", "bool", true)
@@ -163,11 +174,7 @@ local function OpenWith(images, choice, copy)
local bin = program_paths[choice] local bin = program_paths[choice]
local friendly_name = program_names[choice] local friendly_name = program_names[choice]
-- check if external program executable exists, return if not if dt.configuration.running_os == "macos" then bin = "open -W -a "..bin end
if not df.check_if_bin_exists(bin) then
dt.print(friendly_name.._(" not found"))
return
end
-- image to be edited -- image to be edited
local image local image
@@ -175,7 +182,7 @@ local function OpenWith(images, choice, copy)
local name = image.path..PS..image.filename local name = image.path..PS..image.filename
-- check if image format is allowed -- check if image format is allowed
local file_ext = df.get_filetype (image.filename) local file_ext = df.get_filetype(image.filename)
local allowed = false local allowed = false
for i,v in pairs(allowed_file_types) do for i,v in pairs(allowed_file_types) do
if v == file_ext then if v == file_ext then
@@ -207,11 +214,7 @@ local function OpenWith(images, choice, copy)
if copy then if copy then
-- create unique filename -- create unique filename
while df.check_if_file_exists(df.sanitize_filename(new_name)) do new_name = df.create_unique_filename(new_name)
new_name = df.filename_increment(new_name)
-- limit to 50 more exports of the original export
if string.match(df.get_basename(new_name), "_%d%d$") == "_50" then break end
end
-- physical copy, check result, return if error -- physical copy, check result, return if error
local copy_success = df.file_copy(name, new_name) local copy_success = df.file_copy(name, new_name)
@@ -274,13 +277,9 @@ local function OpenWith(images, choice, copy)
new_image = dt.database.import(name) new_image = dt.database.import(name)
new_image:group_with(image_leader) new_image:group_with(image_leader)
end end
-- refresh darkroom view
if dt.gui.current_view() == dt.gui.views.darkroom then
dt.gui.views.darkroom.display_image(new_image)
end
end end
-- restore image tags, rating and color, must be put after refresh darkroom view -- restore image tags, rating and color
for i, tag in ipairs(tags) do dt.tags.attach(tag, new_image) end for i, tag in ipairs(tags) do dt.tags.attach(tag, new_image) end
new_image.rating = rating new_image.rating = rating
new_image.red = red new_image.red = red
@@ -292,8 +291,12 @@ local function OpenWith(images, choice, copy)
-- select the new image -- select the new image
local selection = {} local selection = {}
table.insert(selection, new_image) table.insert(selection, new_image)
dt.gui.selection (selection) dt.gui.selection(selection)
-- refresh darkroom view
if dt.gui.current_view().id == "darkroom" then
dt.gui.views.darkroom.display_image(new_image)
end
end end
@@ -306,7 +309,7 @@ local function program_shortcut(event, shortcut)
-- export images and reimport in collection ----------------------------------- -- export images and reimport in collection -----------------------------------
local function export2collection(storage, image_table, extra_data) local function export2collection(storage, image_table, extra_data)
local new_name, new_image, result local temp_name, new_name, new_image, move_success
for image, temp_name in pairs(image_table) do for image, temp_name in pairs(image_table) do
@@ -314,11 +317,7 @@ local function export2collection(storage, image_table, extra_data)
-- create unique filename -- create unique filename
new_name = image.path..PS..df.get_filename(temp_name) new_name = image.path..PS..df.get_filename(temp_name)
while df.check_if_file_exists(df.sanitize_filename(new_name)) do new_name = df.create_unique_filename(new_name)
new_name = df.filename_increment(new_name)
-- limit to 50 more exports of the original export
if string.match(df.get_basename(new_name), "_%d%d$") == "_50" then break end
end
-- move image to collection folder, check result, return if error -- move image to collection folder, check result, return if error
move_success = df.file_move(temp_name, new_name) move_success = df.file_move(temp_name, new_name)
@@ -332,14 +331,37 @@ local function export2collection(storage, image_table, extra_data)
new_image:group_with(image.group_leader) new_image:group_with(image.group_leader)
end end
dt.print (_("finished exporting")) dt.print(_("finished exporting"))
end end
-- register new storage ------------------------------------------------------- -- install the module in the UI -----------------------------------------------
-- note that placing this declaration later makes the export selected module local function install_module(dr)
-- not to remember the choice "collection" when restarting DT, don't know why
dt.register_storage("exp2coll", _("collection"), null, export2collection) local views = {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}
if dr then
views = {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100},
[dt.gui.views.darkroom] = {"DT_UI_CONTAINER_PANEL_LEFT_CENTER", 100}}
end
if not ee.module_installed then
-- register new module "external editors" in lighttable and darkroom ----
dt.register_lib(
MODULE_NAME,
_("external editors"),
true, -- expandable
false, -- resetable
views,
dt.new_widget("box") {
orientation = "vertical",
table.unpack(ee.widgets),
},
nil, -- view_enter
nil -- view_leave
)
ee.module_installed = true
end
end
-- combobox, with variable number of entries ---------------------------------- -- combobox, with variable number of entries ----------------------------------
@@ -394,41 +416,57 @@ local box1 = dt.new_widget("box") {
} }
-- register new module "external editors" in lighttable ------------------------ -- table with all the widgets --------------------------------------------------
dt.register_lib( table.insert(ee.widgets, combobox)
MODULE_NAME, table.insert(ee.widgets, box1)
_("external editors"),
true, -- expandable
false, -- resetable -- register new module, but only when in lighttable ----------------------------
{[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, local show_dr = dt.preferences.read(MODULE_NAME, "show_in_darkrooom", "bool")
dt.new_widget("box") { if dt.gui.current_view().id == "lighttable" then
orientation = "vertical", install_module(show_dr)
combobox, else
box1 if not ee.event_registered then
}, dt.register_event(
nil, -- view_enter "view-changed",
nil -- view_leave function(event, old_view, new_view)
) if new_view.name == "lighttable" and old_view.name == "darkroom" then
install_module(show_dr)
end
end
)
ee.event_registered = true
end
end
-- initialize list of programs and widgets ------------------------------------ -- initialize list of programs and widgets ------------------------------------
UpdateProgramList(combobox, button_edit, button_edit_copy, false) UpdateProgramList(combobox, button_edit, button_edit_copy, false)
-- register new storage -------------------------------------------------------
dt.register_storage("exp2coll", _("collection"), nil, export2collection)
-- register the new preferences ----------------------------------------------- -- register the new preferences -----------------------------------------------
for i = MAX_EDITORS, 1, -1 do for i = MAX_EDITORS, 1, -1 do
dt.preferences.register(MODULE_NAME, "program_path_"..i, "file", dt.preferences.register(MODULE_NAME, "program_path_"..i, "file",
_("executable for external editor ")..i, _("executable for external editor ")..i,
_("select executable for external editor") , _("(None)")) _("select executable for external editor") , _("(None)"))
dt.preferences.register(MODULE_NAME, "program_name_"..i, "string", dt.preferences.register(MODULE_NAME, "program_name_"..i, "string",
_("name of external editor ")..i, _("name of external editor ")..i,
_("friendly name of external editor"), "") _("friendly name of external editor"), "")
end end
dt.preferences.register(MODULE_NAME, "show_in_darkrooom", "bool",
_("show external editors in darkroom"),
_("check to show external editors module also in darkroom (requires restart)"), false)
-- register the new shortcuts ------------------------------------------------- -- register the new shortcuts -------------------------------------------------
for i = 1, MAX_EDITORS do for i = 1, MAX_EDITORS do
dt.register_event("shortcut", program_shortcut, _("edit with program ")..string.format("%02d", i)) dt.register_event("shortcut",
program_shortcut, _("edit with program ")..string.format("%02d", i))
end end

View File

@@ -44,6 +44,7 @@ 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 dtsys = require "lib/dtutils.system" local dtsys = require "lib/dtutils.system"
local gettext = dt.gettext local gettext = dt.gettext
-- constants -- constants
@@ -51,10 +52,13 @@ local gettext = dt.gettext
local MODULE = "face_recognition" local MODULE = "face_recognition"
local PS = dt.configuration.running_os == "windows" and '\\' or '/' local PS = dt.configuration.running_os == "windows" and '\\' or '/'
local OUTPUT = dt.configuration.tmp_dir .. PS .. "facerecognition.txt" local OUTPUT = dt.configuration.tmp_dir .. PS .. "facerecognition.txt"
local CURR_API_STRING = dt.configuration.api_version_string
-- namespace -- namespace
local fc = {} local fc = {}
fc.module_installed = false
fc.event_registered = false
-- ensure we meet the minimum api -- ensure we meet the minimum api
du.check_min_api_version("5.0.0", "face_recognition") du.check_min_api_version("5.0.0", "face_recognition")
@@ -337,6 +341,22 @@ local function face_recognition ()
end end
end end
local function install_module()
if not fc.module_installed then
dt.register_lib(
"face_recognition", -- Module name
_("face recognition"), -- Visible name
true, -- expandable
true, -- resetable
{[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 300}}, -- containers
fc.widget,
nil,-- view_enter
nil -- view_leave
)
fc.module_installed = true
end
end
-- build the interface -- build the interface
fc.unknown_tag = dt.new_widget("entry"){ fc.unknown_tag = dt.new_widget("entry"){
@@ -466,16 +486,21 @@ fc.widget = dt.new_widget("box"){
table.unpack(widgets), table.unpack(widgets),
} }
dt.register_lib( if dt.gui.current_view().id == "lighttable" then
"face_recognition", -- Module name install_module()
_("face recognition"), -- Visible name else
true, -- expandable if not fc.event_registered then
true, -- resetable dt.register_event(
{[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 300}}, -- containers "view-changed",
fc.widget, function(event, old_view, new_view)
nil,-- view_enter if new_view.name == "lighttable" and old_view.name == "darkroom" then
nil -- view_leave install_module()
) end
end
)
fc.event_registered = true
end
end
fc.tolerance.value = dt.preferences.read(MODULE, "tolerance", "float") fc.tolerance.value = dt.preferences.read(MODULE, "tolerance", "float")

View File

@@ -0,0 +1,111 @@
--[[ fujifilm_dynamic_range-0.1
Compensate for Fujifilm raw files made using "dynamic range".
Copyright (C) 2021 Dan Torop <dant@pnym.net>
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 2 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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
]]
--[[About this Plugin
Support for adjusting darktable exposure by Fujifilm raw exposure
bias. This corrects for a DR100/DR200/DR400 "dynamic range" setting.
Dependencies:
- exiftool (https://www.sno.phy.queensu.ca/~phil/exiftool/)
Based upon fujifilm_ratings by Ben Mendis
The relevant tag is RawExposureBias (0x9650). This appears to
represent the shift in EV for the chosen DR setting (whether manual or
automatic). Note that even at 100DR ("standard") there is an EV shift:
100 DR -> -0.72 EV
200 DR -> -1.72 EV
400 DR -> -2.72 EV
The ideal would be to use exiv2 to read this tag, as this is the same
code which darktable import uses. Unfortunately, exiv2 as of v0.27.3
can't read this tag. As it is encoded as a 4-byte ratio of two signed
shorts -- a novel data type -- it will require some attention to fix
this.
There is an exiv2-readable DevelopmentDynamicRange tag which maps to
RawExposureBias as above. DevelopmentDynamicRange is only present
when tag DynamicRangeSetting (0x1402) is Manual/Raw (0x0001). When it
is Auto (0x0000), the equivalent data is tag AutoDynamicRange
(0x140b). But exiv2 currently can't read that tag either.
Hence for now this code uses exiftool to read RawExposureBias, as a
more general solution. As exiftool is approx. 10x slower than exiv2
(Perl vs. C++), this may slow large imports.
These tags have been checked on a Fujifilm X100S and X100V. Other
cameras may behave in other ways.
--]]
local dt = require "darktable"
local du = require "lib/dtutils"
local df = require "lib/dtutils.file"
du.check_min_api_version("4.0.0", "fujifilm_dynamic_range")
local CURR_API_STRING = dt.configuration.api_version_string
local function detect_dynamic_range(event, image)
if image.exif_maker ~= "FUJIFILM" then
dt.print_log("[fujifilm_dynamic_range] ignoring non-Fujifilm image")
return
end
-- it would be nice to check image.is_raw but this appears to not yet be set
if not string.match(image.filename, "%.RAF$") then
dt.print_log("[fujifilm_dynamic_range] ignoring non-raw image")
return
end
local command = df.check_if_bin_exists("exiftool")
if not command then
dt.print_error("[fujifilm_dynamic_range] exiftool not found")
return
end
local RAF_filename = df.sanitize_filename(tostring(image))
-- without -n flag, exiftool will round to the nearest tenth
command = command .. " -RawExposureBias -n -t " .. RAF_filename
dt.print_log(command)
output = io.popen(command)
local raf_result = output:read("*all")
output:close()
if #raf_result == 0 then
dt.print_error("[fujifilm_dynamic_range] no output returned by exiftool")
return
end
raf_result = string.match(raf_result, "\t(.*)")
if not raf_result then
dt.print_error("[fujifilm_dynamic_range] could not parse exiftool output")
return
end
if image.exif_exposure_bias ~= image.exif_exposure_bias then
-- is NAN (this is unlikely as RAFs should have ExposureBiasValue set)
image.exif_exposure_bias = 0
end
-- this should be auto-applied if plugins/darkroom/workflow is scene-referred
-- note that scene-referred workflow exposure preset also pushes exposure up by 0.5 EV
image.exif_exposure_bias = image.exif_exposure_bias + tonumber(raf_result)
dt.print_log("[fujifilm_dynamic_range] raw exposure bias " .. tostring(raf_result))
end
dt.register_event("post-import-image",
detect_dynamic_range)
dt.print_log("[fujifilm_dynamic_range] loaded")

View File

@@ -26,9 +26,11 @@ Dependencies:
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 gettext = dt.gettext local gettext = dt.gettext
du.check_min_api_version("4.0.0", "fujifilm_ratings") du.check_min_api_version("4.0.0", "fujifilm_ratings")
local CURR_API_STRING = dt.configuration.api_version_string
gettext.bindtextdomain("fujifilm_ratings", dt.configuration.config_dir.."/lua/locale/") gettext.bindtextdomain("fujifilm_ratings", dt.configuration.config_dir.."/lua/locale/")
@@ -41,7 +43,7 @@ local function detect_rating(event, image)
dt.print_error(_("exiftool not found")) dt.print_error(_("exiftool not found"))
return return
end end
local RAF_filename = tostring(image) local RAF_filename = df.sanitize_filename(tostring(image))
local JPEG_filename = string.gsub(RAF_filename, "%.RAF$", ".JPG") local JPEG_filename = string.gsub(RAF_filename, "%.RAF$", ".JPG")
local command = "exiftool -Rating " .. JPEG_filename local command = "exiftool -Rating " .. JPEG_filename
dt.print_error(command) dt.print_error(command)
@@ -66,6 +68,7 @@ local function detect_rating(event, image)
end end
end end
dt.register_event("post-import-image", detect_rating) dt.register_event("post-import-image",
detect_rating)
print(_("fujifilm_ratings loaded.")) print(_("fujifilm_ratings loaded."))

View File

@@ -35,7 +35,6 @@ USAGE
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"
require "official/yield"
local gettext = dt.gettext local gettext = dt.gettext
du.check_min_api_version("3.0.0", "geoJSON_export") du.check_min_api_version("3.0.0", "geoJSON_export")

View File

@@ -28,10 +28,11 @@ require "geoToolbox"
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"
require "official/yield"
local gettext = dt.gettext local gettext = dt.gettext
du.check_min_api_version("3.0.0", "geoToolbox") du.check_min_api_version("3.0.0", "geoToolbox")
local CURR_API_STRING = dt.configuration.api_version_string
-- Tell gettext where to find the .mo file translating messages for a particular domain -- Tell gettext where to find the .mo file translating messages for a particular domain
gettext.bindtextdomain("geoToolbox",dt.configuration.config_dir.."/lua/locale/") gettext.bindtextdomain("geoToolbox",dt.configuration.config_dir.."/lua/locale/")
@@ -40,6 +41,12 @@ local function _(msgid)
return gettext.dgettext("geoToolbox", msgid) return gettext.dgettext("geoToolbox", msgid)
end end
local gT = {}
gT.module_installed = false
gT.event_registered = false
-- <GUI> -- <GUI>
local labelDistance = dt.new_widget("label") local labelDistance = dt.new_widget("label")
labelDistance.label = _("Distance:") labelDistance.label = _("Distance:")
@@ -572,6 +579,22 @@ local function altitude_profile()
end end
local function install_module()
if not gT.module_installed then
dt.register_lib(
"geoToolbox", -- Module name
"geo toolbox", -- name
true, -- expandable
false, -- resetable
{[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, -- containers
gT.widget,
nil,-- view_enter
nil -- view_leave
)
gT.module_installed = true
end
end
local separator = dt.new_widget("separator"){} local separator = dt.new_widget("separator"){}
local separator2 = dt.new_widget("separator"){} local separator2 = dt.new_widget("separator"){}
@@ -579,13 +602,7 @@ local separator3 = dt.new_widget("separator"){}
local separator4 = dt.new_widget("separator"){} local separator4 = dt.new_widget("separator"){}
local separator5 = dt.new_widget("separator"){} local separator5 = dt.new_widget("separator"){}
dt.register_lib( gT.widget = dt.new_widget("box")
"geoToolbox", -- Module name
"geo toolbox", -- name
true, -- expandable
false, -- resetable
{[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, -- containers
dt.new_widget("box")
{ {
orientation = "vertical", orientation = "vertical",
dt.new_widget("button") dt.new_widget("button")
@@ -664,10 +681,24 @@ dt.register_lib(
clicked_callback = altitude_profile clicked_callback = altitude_profile
}, },
labelDistance labelDistance
}, }
nil,-- view_enter
nil -- view_leave
) if dt.gui.current_view().id == "lighttable" then
install_module()
else
if not gT.event_registered then
dt.register_event(
"view-changed",
function(event, old_view, new_view)
if new_view.name == "lighttable" and old_view.name == "darkroom" then
install_module()
end
end
)
gT.event_registered = true
end
end
-- Preferences -- Preferences
dt.preferences.register("geoToolbox", dt.preferences.register("geoToolbox",
@@ -678,11 +709,15 @@ dt.preferences.register("geoToolbox",
'' ) '' )
-- Register -- Register
dt.register_event("shortcut", print_calc_distance, _("Calculate the distance from latitude and longitude in km")) dt.register_event("shortcut",
dt.register_event("mouse-over-image-changed", toolbox_calc_distance) print_calc_distance, _("Calculate the distance from latitude and longitude in km"))
dt.register_event("mouse-over-image-changed",
toolbox_calc_distance)
dt.register_event("shortcut", select_with_gps, _("Select all images with GPS information")) dt.register_event("shortcut",
dt.register_event("shortcut", select_without_gps, _("Select all images without GPS information")) select_with_gps, _("Select all images with GPS information"))
dt.register_event("shortcut",
select_without_gps, _("Select all images without GPS information"))
-- vim: shiftwidth=2 expandtab tabstop=2 cindent syntax=lua -- vim: shiftwidth=2 expandtab tabstop=2 cindent syntax=lua
-- kate: hl Lua; -- kate: hl Lua;

View File

@@ -41,7 +41,9 @@
* require this script from your main lua file * require this script from your main lua file
* select an image or images for editing with GIMP * select an image or images for editing with GIMP
* in the export dialog select "Edit with GIMP" and select the format and bit depth for the * in the export dialog select "Edit with GIMP" and select the format and bit depth for the
exported image exported image. Check the "run_detached" button to run GIMP in detached mode. Images
will not be returned to darktable in this mode, but additional images can be sent to
GIMP without stopping it.
* Press "export" * Press "export"
* Edit the image with GIMP then save the changes with File->Overwrite.... * Edit the image with GIMP then save the changes with File->Overwrite....
* Exit GIMP * Exit GIMP
@@ -103,6 +105,8 @@ end
local function gimp_edit(storage, image_table, extra_data) --finalize local function gimp_edit(storage, image_table, extra_data) --finalize
local run_detached = dt.preferences.read("gimp", "run_detached", "bool")
local gimp_executable = df.check_if_bin_exists("gimp") local gimp_executable = df.check_if_bin_exists("gimp")
if not gimp_executable then if not gimp_executable then
@@ -111,7 +115,11 @@ local function gimp_edit(storage, image_table, extra_data) --finalize
end end
if dt.configuration.running_os == "macos" then if dt.configuration.running_os == "macos" then
gimp_executable = "open -W -a " .. gimp_executable if run_detached then
gimp_executable = "open -a " .. gimp_executable
else
gimp_executable = "open -W -a " .. gimp_executable
end
end end
-- list of exported images -- list of exported images
@@ -130,54 +138,67 @@ local function gimp_edit(storage, image_table, extra_data) --finalize
local gimpStartCommand local gimpStartCommand
gimpStartCommand = gimp_executable .. " " .. img_list gimpStartCommand = gimp_executable .. " " .. img_list
if run_detached then
if dt.configuration.running_os == "windows" then
gimpStartCommand = "start /b \"\" " .. gimpStartCommand
else
gimpStartCommand = gimpStartCommand .. " &"
end
end
dt.print_log(gimpStartCommand) dt.print_log(gimpStartCommand)
dtsys.external_command(gimpStartCommand) dtsys.external_command(gimpStartCommand)
-- for each of the image, exported image pairs if not run_detached then
-- move the exported image into the directory with the original
-- then import the image into the database which will group it with the original
-- and then copy over any tags other than darktable tags
for image,exported_image in pairs(image_table) do -- for each of the image, exported image pairs
-- move the exported image into the directory with the original
-- then import the image into the database which will group it with the original
-- and then copy over any tags other than darktable tags
local myimage_name = image.path .. "/" .. df.get_filename(exported_image) for image,exported_image in pairs(image_table) do
while df.check_if_file_exists(myimage_name) do local myimage_name = image.path .. "/" .. df.get_filename(exported_image)
myimage_name = df.filename_increment(myimage_name)
-- limit to 99 more exports of the original export while df.check_if_file_exists(myimage_name) do
if string.match(df.get_basename(myimage_name), "_(d-)$") == "99" then myimage_name = df.filename_increment(myimage_name)
break -- limit to 99 more exports of the original export
if string.match(df.get_basename(myimage_name), "_(d-)$") == "99" then
break
end
end end
end
dt.print_log("moving " .. exported_image .. " to " .. myimage_name) dt.print_log("moving " .. exported_image .. " to " .. myimage_name)
local result = df.file_move(exported_image, myimage_name) local result = df.file_move(exported_image, myimage_name)
if result then if result then
dt.print_log("importing file") dt.print_log("importing file")
local myimage = dt.database.import(myimage_name) local myimage = dt.database.import(myimage_name)
group_if_not_member(image, myimage) group_if_not_member(image, myimage)
for _,tag in pairs(dt.tags.get_tags(image)) do for _,tag in pairs(dt.tags.get_tags(image)) do
if not (string.sub(tag.name,1,9) == "darktable") then if not (string.sub(tag.name,1,9) == "darktable") then
dt.print_log("attaching tag") dt.print_log("attaching tag")
dt.tags.attach(tag,myimage) dt.tags.attach(tag,myimage)
end
end end
end end
end end
end end
end end
-- Register -- Register
local executables = {"gimp"} gimp_widget = dt.new_widget("check_button"){
label = _("run detached"),
if dt.configuration.running_os ~= "linux" then tooltip = _("don't import resulting image back into darktable"),
gimp_widget = df.executable_path_widget(executables) value = dt.preferences.read("gimp", "run_detached", "bool"),
end clicked_callback = function(this)
dt.preferences.write("gimp", "run_detached", "bool", this.value)
end
}
dt.register_storage("module_gimp", _("Edit with GIMP"), show_status, gimp_edit, nil, nil, gimp_widget) dt.register_storage("module_gimp", _("Edit with GIMP"), show_status, gimp_edit, nil, nil, gimp_widget)

View File

@@ -25,9 +25,11 @@ For each source folder, a separate <trk> is generated in the gpx file.
local dt = require "darktable" local dt = require "darktable"
local df = require "lib/dtutils.file" local df = require "lib/dtutils.file"
local dl = require "lib/dtutils" local dl = require "lib/dtutils"
local gettext = dt.gettext local gettext = dt.gettext
dl.check_min_api_version("3.0.0", "gpx-export") dl.check_min_api_version("3.0.0", "gpx-export")
local CURR_API_STRING = dt.configuration.api_version_string
-- Tell gettext where to find the .mo file translating messages for a particular domain -- Tell gettext where to find the .mo file translating messages for a particular domain
gettext.bindtextdomain("gpx_export",dt.configuration.config_dir.."/lua/locale/") gettext.bindtextdomain("gpx_export",dt.configuration.config_dir.."/lua/locale/")
@@ -36,6 +38,10 @@ local function _(msgid)
return gettext.dgettext("gpx_export", msgid) return gettext.dgettext("gpx_export", msgid)
end end
local gpx = {}
gpx.module_installed = false
gpx.event_registered = false
local path_entry = dt.new_widget("entry") local path_entry = dt.new_widget("entry")
{ {
text = dt.preferences.read("gpx_exporter", "gpxExportPath", "string"), text = dt.preferences.read("gpx_exporter", "gpxExportPath", "string"),
@@ -127,31 +133,55 @@ local function create_gpx_file()
end end
end end
dt.register_lib( local function install_module()
"gpx_exporter", if not gpx.module_installed then
"gpx export", dt.register_lib(
true, -- expandable "gpx_exporter",
true, -- resetable "gpx export",
{[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, -- containers true, -- expandable
true, -- resetable
{[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, -- containers
gpx.widget,
nil,-- view_enter
nil -- view_leave
)
gpx.module_installed = true
end
end
gpx.widget = dt.new_widget("box")
{
orientation = "vertical",
dt.new_widget("button")
{
label = _("export"),
tooltip = _("export gpx file"),
clicked_callback = create_gpx_file
},
dt.new_widget("box") dt.new_widget("box")
{ {
orientation = "vertical", orientation = "horizontal",
dt.new_widget("button") dt.new_widget("label")
{ {
label = _("export"), label = _("file:"),
tooltip = _("export gpx file"),
clicked_callback = create_gpx_file
},
dt.new_widget("box")
{
orientation = "horizontal",
dt.new_widget("label")
{
label = _("file:"),
},
path_entry
}, },
path_entry
}, },
nil,-- view_enter }
nil -- view_leave
)
if dt.gui.current_view().id == "lighttable" then
install_module()
else
if not gpx.event_registered then
dt.register_event(
"view-changed",
function(event, old_view, new_view)
if new_view.name == "lighttable" and old_view.name == "darkroom" then
install_module()
end
end
)
gpx.event_registered = true
end
end

View File

@@ -40,7 +40,6 @@ local du = require "lib/dtutils"
local df = require "lib/dtutils.file" local df = require "lib/dtutils.file"
local log = require "lib/dtutils.log" local log = require "lib/dtutils.log"
local dtsys = require "lib/dtutils.system" local dtsys = require "lib/dtutils.system"
require "official/yield"
local gettext = dt.gettext local gettext = dt.gettext
local namespace = 'module_hugin' local namespace = 'module_hugin'
@@ -227,4 +226,4 @@ dt.register_storage(namespace, _("hugin panorama"), show_status, create_panorama
-- --
-- vim: shiftwidth=2 expandtab tabstop=2 cindent syntax=lua -- vim: shiftwidth=2 expandtab tabstop=2 cindent syntax=lua

566
contrib/image_time.lua Normal file
View File

@@ -0,0 +1,566 @@
--[[
image_time.lua - synchronize image time for images shot with different cameras
Copyright (C) 2019, 2020 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/>.
]]
--[[
image_time - non-destructively modify the image time
DESCRIPTION
image_time non destructively adjusts image times by modifying the
database image exif_datetime_taken field. There are 4 modes: adjust time,
set time, synchronize time, and reset time.
ADJUST TIME
adjust time mode lets you chose an offset in terms of years, months,
days, hours, minutes, and seconds. The adjustment can be added or
subtracted.
WARNING: When adding and subtracting months the result will usually
be what is expected unless the time being adjusted is at the end of
the month. This is because a month is a variable amount of time that
can be 28, 29, 30 or 31 days depending on the month. Example: It's
March 31st and I subtract a month which not sets the time to February
31st. When that gets set to a valid time, then the date changes to
March 3rd.
SET TIME
set time mode allows you to pick a date and time and set the image
time accordingly. Fields may be left out. This is useful when
importing scanned images that don't have an embedded date.
SYNCHRONIZE TIME
I recently purchased a 7DmkII to replace my aging 7D. My 7D was still
serviceable, so I bought a remote control and figured I'd try shooting
events from 2 different perspectives. I didn't think to synchonize the
time between the 2 cameras, so when I loaded the images and sorted by
time it was a disaster. I hacked a script together with hard coded values
to adjust the exif_datetime_taken value in the database for the 7D images
so that everything sorted properly. I've tried shooting with 2 cameras
several times since that first attempt. I've gotten better at getting the
camera times close, but still haven't managed to get them to sync. So I
decided to think the problem through and write a proper script to take
care of the problem.
RESET TIME
Select the images and click reset.
USAGE
ADJUST TIME
Change the year, month, day, hour, minute, second dropdowns to the amount
of change desired. Select add or subtract. Select the images. Click
adjust.
SET TIME
Set the time fields to the desired time. Select the images to change. Click
set.
SYNCHRONIZE TIME
Select 2 images, one from each camera, of the same moment in time. Click
the Calculate button to calculate the time difference. The difference is
displayed in the difference entry. You can manually adjust it by changing
the value if necessary.
Select the images that need their time adjusted. Determine which way to adjust
adjust the time (add or subtract) and select the appropriate choice.
If the image times get messed up and you just want to start over, select reset time
from the mode and reset the image times.
RESET TIME
Select the images and click reset.
ADDITIONAL SOFTWARE REQUIRED
* exiv2
BUGS, COMMENTS, SUGGESTIONS
* Send to 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 gettext = dt.gettext
local img_time = {}
img_time.module_installed = false
img_time.event_registered = false
du.check_min_api_version("3.0.0", "image_time")
local CURR_API_STRING = dt.configuration.api_version_string
-- Tell gettext where to find the .mo file translating messages for a particular domain
gettext.bindtextdomain("image_time",dt.configuration.config_dir.."/lua/locale/")
local function _(msgid)
return gettext.dgettext("image_time", msgid)
end
local PS = dt.configuration.runnin_os == "windows" and "\\" or "/"
local ERROR = -1
-- function to convert from exif time to system time
local function exiftime2systime(exiftime)
local yr,mo,dy,h,m,s = string.match(exiftime, "(%d-):(%d-):(%d-) (%d-):(%d-):(%d+)")
return(os.time{year=yr, month=mo, day=dy, hour=h, min=m, sec=s})
end
-- function to convert from systime to exif time
local function systime2exiftime(systime)
local t = os.date("*t", systime)
return(string.format("%4d:%02d:%02d %02d:%02d:%02d", t.year, t.month, t.day, t.hour, t.min, t.sec))
end
local function vars2exiftime(year, month, day, hour, min, sec)
local y = tonumber(year) and string.format("%4d", year) or " "
local mo = tonumber(month) and string.format("%02d", month) or " "
local d = tonumber(day) and string.format("%02d", day) or " "
local h = tonumber(hour) and string.format("%02d", hour) or " "
local m = tonumber(min) and string.format("%02d", min) or " "
local s = tonumber(sec) and string.format("%02d", sec) or " "
return(y .. ":" .. mo .. ":" .. d .. " " .. h .. ":" .. m .. ":" .. s)
end
local function exiftime2vars(exiftime)
return string.match(exiftime, "(%d+):(%d+):(%d+) (%d+):(%d+):(%d+)")
end
local function calc_time_difference(image1, image2)
return math.abs(exiftime2systime(image1.exif_datetime_taken) - exiftime2systime(image2.exif_datetime_taken))
end
local function adjust_image_time(image, difference)
image.exif_datetime_taken = systime2exiftime(exiftime2systime(image.exif_datetime_taken) + difference)
return
end
local function calculate_difference(images)
if #images == 2 then
img_time.diff_entry.text = calc_time_difference(images[1], images[2])
img_time.btn.sensitive = true
else
dt.print(_("Error: 2 images must be selected"))
end
end
local function synchronize_times(images, difference)
for _, image in ipairs(images) do
adjust_image_time(image, difference)
end
end
local function synchronize_time(images)
local sign = 1
if img_time.sdir.value == "subtract" then
sign = -1
end
synchronize_times(images, tonumber(img_time.diff_entry.text) * sign)
end
local function add_time(images)
synchronize_times(images, tonumber(img_time.diff_entry.text))
end
local function year_month2months(year, month)
year_months = tonumber(year) and year * 12 or 0
local months = tonumber(month) and tonumber(month) or 0
return year_months + months
end
local function months2year_month(months)
dt.print_log("months is " .. months)
local year = math.floor(months / 12)
local month = months - (year * 12)
return year, month
end
local function get_image_taken_time(image)
-- get original image time
local datetime = nil
local exiv2 = df.check_if_bin_exists("exiv2")
if exiv2 then
p = io.popen(exiv2 .. " -K Exif.Image.DateTime " .. image.path .. PS .. image.filename)
if p then
for line in p:lines() do
if string.match(line, "Exif.Image.DateTime") then
datetime = string.match(line, "(%d-:%d-:%d- %d-:%d-:%d+)")
end
end
p:close()
end
else
dt.print(_("unable to detect exiv2"))
datetime = ERROR
end
return datetime
end
local function _get_windows_image_file_creation_time(image)
local datetime = nil
local p = io.popen("dir " .. image.path .. PS .. image.filename)
if p then
for line in p:lines() do
if string.match(line, ds.sanitize_lua(image.filename)) then
local mo, day, yr, hr, min, apm = string.match(line, "(%d+)/(%d+)/(%d+) (%d-):(%d+) (%S+)")
if apm == "PM" then
hr = hr + 12
end
datetime = vars2exiftime(yr, mo, day, hr, min, 0)
end
end
p:close()
else
dt.print(_("unable to get information for ") .. image.filename)
datetime = ERROR
end
return datetime
end
local function _get_nix_image_file_creation_time(image)
local datetime = nil
local p = io.popen("ls -lL --time-style=full-iso " .. image.path .. PS .. image.filename)
if p then
for line in p:lines() do
if string.match(line, ds.sanitize_lua(image.filename)) then
datetime = vars2exiftime(string.match(line, "(%d+)%-(%d-)%-(%d-) (%d-):(%d-):(%d+)."))
end
end
p:close()
else
dt.print(_("unable to get information for ") .. image.filename)
datetime = ERROR
end
return datetime
end
local function get_image_file_creation_time(image)
-- no exif time in the image file so get the creation time
local datetime = nil
if dt.configuration.running_os == "windows" then
datetime = _get_windows_image_file_creation_time(image)
else
datetime = _get_nix_image_file_creation_time(image)
end
return datetime
end
local function get_original_image_time(image)
local image_time = image.exif_datetime_taken
local reset_time = nil
reset_time = get_image_taken_time(image)
if reset_time then
if reset_time == ERROR then
return image_time
else
return reset_time
end
else
reset_time = get_image_file_creation_time(image)
if reset_time then
if reset_time == ERROR then
return image_time
else
return reset_time
end
end
end
end
local function reset_time(images)
if #images > 0 then
for _, image in ipairs(images) do
image.exif_datetime_taken = get_original_image_time(image)
end
else
dt.print_error(_("reset time: no images selected"))
dt.print(_("please select the images that need their time reset"))
end
end
local function adjust_time(images)
local SEC_MIN = 60
local SEC_HR = SEC_MIN * 60
local SEC_DY = SEC_HR * 24
local offset = nil
local sign = 1
if #images < 1 then
dt.print(_("please select some images and try again"))
return
end
if img_time.adir.value == _("subtract") then
sign = -1
end
for _, image in ipairs(images) do
local y, mo, d, h, m, s = exiftime2vars(image.exif_datetime_taken)
local image_months = year_month2months(y, mo)
local months_diff = year_month2months(img_time.ayr.value, img_time.amo.value)
y, mo = months2year_month(image_months + (months_diff * sign))
local exif_new = vars2exiftime(y, mo, d, h, m, s)
offset = img_time.ady.value * SEC_DY
offset = offset + img_time.ahr.value * SEC_HR
offset = offset + img_time.amn.value * SEC_MIN
offset = offset + img_time.asc.value
offset = offset * sign
image.exif_datetime_taken = systime2exiftime(exiftime2systime(exif_new) + offset)
end
end
local function set_time(images)
if #images < 1 then
dt.print(_("please select some images and try again"))
return
end
local y = img_time.syr.value
local mo = img_time.smo.value
local d = img_time.sdy.value
local h = img_time.shr.value
local m = img_time.smn.value
local s = img_time.ssc.value
for _, image in ipairs(images) do
image.exif_datetime_taken = vars2exiftime(y, mo, d, h, m, s)
end
end
local function seq(first, last)
local result = {}
local num = first
while num <= last do
table.insert(result, num)
num = num + 1
end
return table.unpack(result)
end
local function reset_widgets()
dt.print_log("took the reset function")
img_time.ayr.selected = 1
img_time.amo.selected = 1
img_time.ady.selected = 1
img_time.ahr.selected = 1
img_time.ayr.selected = 1
img_time.amn.selected = 1
img_time.asc.selected = 1
img_time.adir.selected = 1
img_time.syr.selected = #img_time.syr
img_time.smo.selected = 1
img_time.sdy.selected = 1
img_time.shr.selected = 1
img_time.smn.selected = 1
img_time.ssc.selected = 1
img_time.adir.selected = 1
end
local function install_module()
if not img_time.module_installed then
dt.register_lib(
"image_time", -- Module name
_("image time"), -- Visible name
true, -- expandable
true, -- resetable
{[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, -- containers
img_time.widget,
nil,-- view_enter
nil -- view_leave
)
img_time.module_installed = true
end
end
-- widgets
img_time.widgets = {
-- name, type, tooltip, placeholder,
{"ayr", "combobox", _("years"), _("years to adjust by, 0 - ?"), {seq(0,20)}, 1},
{"amo", "combobox", _("months"), ("months to adjust by, 0-12"), {seq(0,12)}, 1},
{"ady", "combobox", _("days"), ("days to adjust by, 0-31"), {seq(0,31)}, 1},
{"ahr", "combobox", _("hours"), _("hours to adjust by, 0-23"), {seq(0,23)}, 1},
{"amn", "combobox", _("minutes"), _("minutes to adjust by, 0-59"), {seq(0,59)}, 1},
{"asc", "combobox", _("seconds"), _("seconds to adjust by, 0-59"), {seq(0,59)}, 1},
{"adir", "combobox", _("add/subtract"), _("add or subtract time"), {_("add"), _("subtract")}, 1},
{"syr", "combobox", _("year"), _("year to set, 1900 - now"), {" ", seq(1900,os.date("*t", os.time()).year)}, 1},
{"smo", "combobox", _("month"), _("month to set, 1-12"), {" ", seq(1,12)}, 1},
{"sdy", "combobox", _("day"), _("day to set, 1-31"), {" ", seq(1,31)}, 1},
{"shr", "combobox", _("hour"), _("hour to set, 0-23"), {" ", seq(0,23)}, 1},
{"smn", "combobox", _("minute"), _("minutes to set, 0-59"), {" ", seq(0, 59)}, 1},
{"ssc", "combobox", _("seconds"), _("seconds to set, 0-59"), {" ", seq(0,59)}, 1},
{"sdir", "combobox", _("add/subtract"), _("add or subtract time"), {_("add"), _("subtract")}, 1},
}
for _, widget in ipairs(img_time.widgets) do
img_time[widget[1]] = dt.new_widget(widget[2]){
label = widget[3],
tooltip = widget[4],
selected = widget[6],
table.unpack(widget[5])
}
end
img_time.syr.selected = #img_time.syr
img_time.diff_entry = dt.new_widget("entry"){
tooltip = _("Time difference between images in seconds"),
placeholder = _("Select 2 images and use the calculate button"),
text = "",
}
img_time.calc_btn = dt.new_widget("button"){
label = _("Calculate"),
tooltip = _("calculate time difference between 2 images"),
clicked_callback = function()
calculate_difference(dt.gui.action_images)
end
}
img_time.btn = dt.new_widget("button"){
label = _("synchronize image times"),
tooltip = _("apply the time difference from selected images"),
sensitive = false,
clicked_callback = function()
synchronize_time(dt.gui.action_images)
end
}
img_time.stack = dt.new_widget("stack"){
dt.new_widget("box"){
orientation = "vertical",
dt.new_widget("label"){label = _("adjust time")},
dt.new_widget("section_label"){label = _("days, months, years")},
img_time.ady,
img_time.amo,
img_time.ayr,
dt.new_widget("section_label"){label = _("hours, minutes, seconds")},
img_time.ahr,
img_time.amn,
img_time.asc,
dt.new_widget("section_label"){label = _("adjustment direction")},
img_time.adir,
dt.new_widget("button"){
label = _("adjust"),
clicked_callback = function()
adjust_time(dt.gui.action_images)
end
}
},
dt.new_widget("box"){
orientation = "vertical",
dt.new_widget("label"){label = _("set time")},
dt.new_widget("section_label"){label = _("date: ")},
img_time.sdy,
img_time.smo,
img_time.syr,
dt.new_widget("section_label"){label = _("time:")},
img_time.shr,
img_time.smn,
img_time.ssc,
dt.new_widget("button"){
label = _("set"),
clicked_callback = function()
set_time(dt.gui.action_images)
end
}
},
dt.new_widget("box"){
orientation = "vertical",
dt.new_widget("label"){label = _("synchronize image time")},
dt.new_widget("section_label"){label = _("calculate difference between images")},
img_time.diff_entry,
img_time.calc_btn,
dt.new_widget("section_label"){label = _("apply difference")},
img_time.sdir,
img_time.btn,
},
dt.new_widget("box"){
orientation = "vertical",
dt.new_widget("label"){label = _("reset to original time")},
dt.new_widget("separator"){},
dt.new_widget("button"){
label = _("reset"),
clicked_callback = function()
reset_time(dt.gui.action_images)
end
}
},
}
img_time.mode = dt.new_widget("combobox"){
label = _("mode"),
tooltip = _("select mode"),
selected = 1,
changed_callback = function(this)
img_time.stack.active = this.selected
end,
_("adjust time"),
_("set time"),
_("synchronize time"),
_("reset time")
}
img_time.widget = dt.new_widget("box"){
orientation = "vertical",
reset_callback = function(this)
reset_widgets()
end,
img_time.mode,
img_time.stack,
}
if dt.gui.current_view().id == "lighttable" then
install_module()
else
if not img_time.event_registered then
dt.register_event(
"view-changed",
function(event, old_view, new_view)
if new_view.name == "lighttable" and old_view.name == "darkroom" then
install_module()
end
end
)
img_time.event_registered = true
end
end

View File

@@ -41,7 +41,6 @@ format (all fields can be the empty string):
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"
require "official/yield"
local gettext = dt.gettext local gettext = dt.gettext

475
contrib/photils.lua Normal file
View File

@@ -0,0 +1,475 @@
--[[ photils Auto Tagging plugin
copyright (c) 2020 Tobias Scheck
darktable 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.
darktable 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 darktable. If not, see <http://www.gnu.org/licenses/>.
--]]
--[[
A darktable plugin that tries to predict keywords based on the selected image.
This plugin uses photils-cli to handle this task. Photils-cli is an application
that passes the image through a neural network, classifies it, and extracts the
suggested tags. Everything happens offline without the need that your data are
sent over the internet.
ADDITIONAL SOFTWARE NEEDED FOR THIS SCRIPT
* photils-cli - https://github.com/scheckmedia/photils-cli at the moment only
available for Linux and MacOS
USAGE
* require this script from your main lua file
To do this add this line to the file .config/darktable/luarc:
require "contrib/photils"
* Select an image
* Press "get tags"
* Select the tags you want from a list of suggestions
* Press "Attach .. Tags" to add the selected tags to your image
--]]
local dt = require "darktable"
local du = require "lib/dtutils"
local df = require "lib/dtutils.file"
local dtsys = require "lib/dtutils.system"
local MODULE_NAME = "photils"
du.check_min_api_version("5.0.0", MODULE_NAME)
local CURR_API_STRING = dt.configuration.api_version_string
local PS = dt.configuration.running_os == "windows" and "\\" or "/"
local gettext = dt.gettext
gettext.bindtextdomain(MODULE_NAME,
dt.configuration.config_dir .. PS .. "lua" .. PS .. "locale" .. PS)
local exporter = dt.new_format("jpeg")
exporter.quality = 80
exporter.max_height = 224
exporter.max_width = 224
-- helper functions
local function _(msgid)
return gettext.dgettext(MODULE_NAME, msgid)
end
local function num_keys(tbl)
local num = 0
for _ in pairs(tbl) do num = num + 1 end
return num
end
local function has_key(tbl, value)
for k, _ in pairs(tbl) do
if k == value then
return true
end
end
return false
end
local photils_installed = df.check_if_bin_exists("photils-cli")
--[[
local state object
maybe per_page is a preference variable but I think 10
is a good value for the ui
]]
local PHOTILS = {
tags = {},
confidences = {},
page = 1,
per_page = 10,
selected_tags = {},
in_pagination = false,
tagged_image = "",
module_installed = false,
event_registered = false,
plugin_display_views = {
[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100},
[dt.gui.views.darkroom] = {"DT_UI_CONTAINER_PANEL_LEFT_CENTER", 100}
},
}
local GUI = {
container = dt.new_widget("box") {
orientation = "vertical",
sensitive = true,
dt.new_widget("button") {
label = _("get tags"),
sensitive = photils_installed,
clicked_callback = function() PHOTILS.on_tags_clicked() end
},
reset_callback = function() PHOTILS.on_reset(true) end
},
stack = dt.new_widget("stack"),
prev_button = dt.new_widget("button") {
label = "<",
sensitive = false,
clicked_callback = function()
PHOTILS.page = PHOTILS.page - 1
PHOTILS.paginate()
end
},
next_button = dt.new_widget("button") {
label = ">",
sensitive = false,
clicked_callback = function()
PHOTILS.page = PHOTILS.page + 1
PHOTILS.paginate()
end
},
tag_box = dt.new_widget("box") {orientation = "vertical"},
tag_view = dt.new_widget("box") {orientation = "vertical"},
page_label = dt.new_widget("label") {label = ""},
error_view = dt.new_widget("box") {orientation = "vertical"},
warning_label = dt.new_widget("label") {
label = ""
},
restart_required_label = dt.new_widget("label") {
label = _("requires a restart to be applied")
},
attach_button = dt.new_widget("button") {
label = "",
sensitive = false,
clicked_callback = function(self) PHOTILS.attach_tags() end
},
confidence_slider = dt.new_widget("slider") {
step = 1,
digits = 0,
value = 90,
hard_max = 100,
hard_min = 0,
soft_max = 100,
soft_min = 0,
label = _("min confidence value")
},
warning = dt.new_widget("label")
}
function PHOTILS.image_changed()
local current_image = tostring(dt.gui.selection()[1])
if current_image ~= PHOTILS.tagged_image then
if PHOTILS.tagged_image ~= "" then
PHOTILS.tagged_image_has_changed()
end
PHOTILS.tagged_image = tostring(current_image)
end
end
function PHOTILS.tagged_image_has_changed()
GUI.warning.label = _("The suggested tags were not generated\n for the currently selected image!")
end
function PHOTILS.paginate()
PHOTILS.in_pagination = true
local num_pages = math.ceil(#PHOTILS.tags / PHOTILS.per_page)
GUI.page_label.label = string.format(_(" page %s of %s "), PHOTILS.page,
num_pages)
if PHOTILS.page <= 1 then
PHOTILS.page = 1
GUI.prev_button.sensitive = false
else
GUI.prev_button.sensitive = true
end
if PHOTILS.page > num_pages - 1 then
PHOTILS.page = num_pages
GUI.next_button.sensitive = false
else
GUI.next_button.sensitive = true
end
--[[
calculates the start positon in the tag array based on the current page
and takes N tags from that array to show these in darktable
e.g. page 1 goes from 1 to 10, page 2 from 11 to 20 a.s.o.
the paginaton approach is related to a problem with the dynamic addition
of mutliple widgets https://github.com/darktable-org/darktable/issues/4934#event-3318100463
]]--
local offset = ((PHOTILS.page - 1) * PHOTILS.per_page) + 1
local tag_index = 1
for i = offset, offset + PHOTILS.per_page - 1, 1 do
local tag = PHOTILS.tags[i]
local conf = PHOTILS.confidences[i]
GUI.tag_box[tag_index].value = has_key(PHOTILS.selected_tags, tag)
if tag then
if dt.preferences.read(MODULE_NAME, "show_confidence", "bool") then
tag = tag .. string.format(" (%.3f)", conf)
end
GUI.tag_box[tag_index].label = tag
GUI.tag_box[tag_index].sensitive = true
else
GUI.tag_box[tag_index].label = ""
GUI.tag_box[tag_index].sensitive = false
end
tag_index = tag_index + 1
end
PHOTILS.in_pagination = false
end
function PHOTILS.attach_tags()
local num_selected = #dt.gui.selection()
local job = dt.gui.create_job(_("Apply tag to image"), true)
for i = 1, num_selected, 1 do
local image = dt.gui.selection()[i]
for tag, _ in pairs(PHOTILS.selected_tags) do
local dt_tag = dt.tags.create(tag)
dt.tags.attach(dt_tag, image)
end
job.percent = i / num_selected
end
dt.print(_("Tags successfully attached to image"))
job.valid = false
end
function PHOTILS.get_tags(image, with_export)
local tmp_file = df.create_tmp_file()
local in_arg = df.sanitize_filename(tostring(image))
local out_arg = df.sanitize_filename(tmp_file)
local executable = photils_installed
if dt.configuration.running_os == "macos" then
executable = executable .. "/Contents/MacOS/photils-cli"
end
if with_export then
dt.print_log("use export to for prediction")
local export_file = df.create_tmp_file()
exporter:write_image(image, export_file)
in_arg = df.sanitize_filename(tostring(export_file))
end
local command = executable .. " -c " .. " -i " .. in_arg .. " -o " .. out_arg
local ret = dtsys.external_command(command)
if ret > 0 then
dt.print_error(string.format("command %s returned error code %d", command, ret))
os.remove(tmp_file)
-- try to export the image and run tagging
if not with_export then
return PHOTILS.get_tags(image, true)
end
return false
end
for i = #PHOTILS.tags, 1, -1 do
PHOTILS.tags[i] = nil
PHOTILS.confidences[i] = nil
end
for tag in io.lines(tmp_file) do
local splitted = du.split(tag, ":")
if 100 * tonumber(splitted[2]) >= GUI.confidence_slider.value then
PHOTILS.tags[#PHOTILS.tags + 1] = splitted[1]
PHOTILS.confidences[#PHOTILS.confidences+1] = splitted[2]
end
end
dt.print(string.format(_("%s found %d tags for your image"), MODULE_NAME,
#PHOTILS.tags))
os.remove(tmp_file)
return true
end
function PHOTILS.on_tags_clicked()
PHOTILS.page = 1
GUI.warning.label = ""
PHOTILS.on_reset(false)
local images = dt.gui.selection()
if #images == 0 then
dt.print(_("No image selected."))
dt.control.sleep(2000)
else
if #images > 1 then
dt.print(_("This plugin can only handle a single image."))
dt.gui.selection({images[1]})
dt.control.sleep(2000)
end
with_export = dt.preferences.read(MODULE_NAME, "export_image_before_for_tags", "bool")
if not PHOTILS.get_tags(images[1], with_export) then
local msg = string.format(_("%s failed, see terminal output for details"), MODULE_NAME)
GUI.warning_label.label = msg
GUI.stack.active = GUI.error_view
dt.print(msg)
return
end
if #PHOTILS.tags == 0 then
local msg = string.format(_("no tags where found"), MODULE_NAME)
GUI.warning_label.label = msg
GUI.stack.active = GUI.error_view
return
end
GUI.stack.active = GUI.tag_view
PHOTILS.paginate()
end
end
function PHOTILS.tag_selected(tag_button)
if PHOTILS.in_pagination then return end
if tag_button.value then
local tag = tag_button.label
if dt.preferences.read(MODULE_NAME, "show_confidence", "bool") then
local idx = string.find(tag, "%(") - 2
tag = string.sub(tag, 0, idx)
end
PHOTILS.selected_tags[tag] = tag
else
PHOTILS.selected_tags[tag_button.label] = nil
end
local num_selected = num_keys(PHOTILS.selected_tags)
if num_selected == 0 then
GUI.attach_button.label = ""
GUI.attach_button.sensitive = false
else
GUI.attach_button.label = string.format(_("attach %d tags"),
num_selected)
GUI.attach_button.sensitive = true
end
end
function PHOTILS.on_reset(with_view)
if with_view then GUI.stack.active = 1 end
for k, _ in pairs(PHOTILS.selected_tags) do
PHOTILS.selected_tags[k] = nil
end
for _, v in ipairs(GUI.tag_box) do
v.value = false
end
GUI.attach_button.label = ""
GUI.attach_button.sensitive = false
end
local function install_module()
if not PHOTILS.module_installed then
dt.register_lib(MODULE_NAME,
"photils autotagger",
true,
true,
PHOTILS.plugin_display_views,
GUI.container,
nil,
nil
)
PHOTILS.module_installed = true
end
end
-- add a fix number of buttons
for _ = 1, PHOTILS.per_page, 1 do
local btn_tag = dt.new_widget("check_button") {
label = "",
sensitive = false,
clicked_callback = PHOTILS.tag_selected
}
table.insert(GUI.tag_box, btn_tag)
end
if not photils_installed then
GUI.warning_label.label = _("photils-cli not found")
dt.print_log(_("photils-cli not found"))
else
GUI.warning_label.label = _("Select an image, click \"get tags\" and get \nsuggestions for tags.")
end
GUI.pagination = dt.new_widget("box") {
orientation = "horizontal",
GUI.prev_button,
GUI.page_label,
GUI.next_button
}
table.insert(GUI.error_view, GUI.warning_label)
if not photils_installed then
table.insert(GUI.error_view, df.executable_path_widget({"photils-cli"}))
table.insert(GUI.error_view, GUI.restart_required_label)
end
table.insert(GUI.stack, GUI.error_view)
table.insert(GUI.stack, GUI.tag_view)
table.insert(GUI.tag_view, GUI.pagination)
table.insert(GUI.tag_view, GUI.tag_box)
table.insert(GUI.tag_view, GUI.attach_button)
table.insert(GUI.tag_view, GUI.warning)
table.insert(GUI.container, GUI.confidence_slider)
table.insert(GUI.container, GUI.stack)
GUI.stack.active = 1
-- uses photils: prefix because script settings are all together and not seperated by script
dt.preferences.register(MODULE_NAME,
"show_confidence",
"bool",
_("photils: show confidence value"),
_("if enabled, the confidence value for each tag is displayed"),
true)
dt.preferences.register(MODULE_NAME,
"export_image_before_for_tags",
"bool",
_("photils: use exported image for tag request"),
_("If enabled, the image passed to photils for tag suggestion is based on the exported, already edited image. " ..
"Otherwise, the embedded thumbnail of the RAW file will be used for tag suggestion." ..
"The embedded thumbnail could speedup the tag suggestion but can fail if the RAW file is not supported."),
true)
dt.register_event("mouse-over-image-changed",
PHOTILS.image_changed)
if dt.gui.current_view().id == "lighttable" then
install_module()
else
if not PHOTILS.event_registered then
dt.register_event(
"view-changed",
function(event, old_view, new_view)
if new_view.name == "lighttable" and old_view.name == "darkroom" then
install_module()
end
end
)
PHOTILS.event_registered = true
end
end

View File

@@ -47,10 +47,17 @@ local dt = require "darktable"
local du = require "lib/dtutils" local du = require "lib/dtutils"
local debug = require "darktable.debug" local debug = require "darktable.debug"
local qt = {}
qt.module_installed = false
qt.event_registered = false
qt.widget_table = {}
local gettext = dt.gettext local gettext = dt.gettext
du.check_min_api_version("3.0.0", "quicktag") du.check_min_api_version("3.0.0", "quicktag")
local CURR_API_STRING = dt.configuration.api_version_string
-- Tell gettext where to find the .mo file translating messages for a particular domain -- Tell gettext where to find the .mo file translating messages for a particular domain
gettext.bindtextdomain("quicktag",dt.configuration.config_dir.."/lua/locale/") gettext.bindtextdomain("quicktag",dt.configuration.config_dir.."/lua/locale/")
@@ -177,12 +184,33 @@ local function update_quicktag_list()
end end
end end
local function install_module()
if not qt.module_installed then
dt.register_lib(
"quicktag", -- Module name
"quicktag", -- name
true, -- expandable
false, -- resetable
{[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 490}},
dt.new_widget("box"){
orientation = "vertical",
table.unpack(qt.widget_table),
},
nil,-- view_enter
nil -- view_leave
)
qt.module_installed = true
end
end
update_quicktag_list() update_quicktag_list()
local new_quicktag = dt.new_widget("entry"){ local new_quicktag = dt.new_widget("entry"){
text = "", text = "",
placeholder = _("new tag"), placeholder = _("new tag"),
is_password = true, is_password = false,
editable = true, editable = true,
tooltip = _("enter your tag here") tooltip = _("enter your tag here")
} }
@@ -213,33 +241,32 @@ local new_qt_widget = dt.new_widget ("box") {
-- back UI elements in a table -- back UI elements in a table
-- thanks to wpferguson for the hint -- thanks to wpferguson for the hint
local widget_table = {}
for i=1,qnr do for i=1,qnr do
widget_table[#widget_table + 1] = button[i] qt.widget_table[#qt.widget_table + 1] = button[i]
end end
widget_table[#widget_table + 1] = dt.new_widget("separator"){} qt.widget_table[#qt.widget_table + 1] = dt.new_widget("separator"){}
widget_table[#widget_table + 1] = old_quicktag qt.widget_table[#qt.widget_table + 1] = old_quicktag
widget_table[#widget_table + 1] = new_qt_widget qt.widget_table[#qt.widget_table + 1] = new_qt_widget
--create module --create module
dt.register_lib( if dt.gui.current_view().id == "lighttable" then
"quicktag", -- Module name install_module()
"quicktag", -- name else
true, -- expandable if not qt.event_registered then
false, -- resetable dt.register_event(
{[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 490}}, "view-changed",
function(event, old_view, new_view)
dt.new_widget("box"){ if new_view.name == "lighttable" and old_view.name == "darkroom" then
orientation = "vertical", install_module()
table.unpack(widget_table), end
end
}, )
nil,-- view_enter qt.event_registered = true
nil -- view_leave end
) end
-- create shortcuts -- create shortcuts
for i=1,qnr do for i=1,qnr do

View File

@@ -43,6 +43,7 @@ local du = require "lib/dtutils"
-- added version check -- added version check
du.check_min_api_version("3.0.0", "rate_group") du.check_min_api_version("3.0.0", "rate_group")
local CURR_API_STRING = dt.configuration.api_version_string
local function apply_rating(rating) local function apply_rating(rating)
local images = dt.gui.action_images local images = dt.gui.action_images
@@ -59,30 +60,37 @@ local function apply_rating(rating)
end end
end end
dt.register_event("shortcut",function(event, shortcut) dt.register_event("shortcut",
function(event, shortcut)
apply_rating(-1) apply_rating(-1)
end, "Reject group") end, "Reject group")
dt.register_event("shortcut",function(event, shortcut) dt.register_event("shortcut",
function(event, shortcut)
apply_rating(0) apply_rating(0)
end, "Rate group 0") end, "Rate group 0")
dt.register_event("shortcut",function(event, shortcut) dt.register_event("shortcut",
function(event, shortcut)
apply_rating(1) apply_rating(1)
end, "Rate group 1") end, "Rate group 1")
dt.register_event("shortcut",function(event, shortcut) dt.register_event("shortcut",
function(event, shortcut)
apply_rating(2) apply_rating(2)
end, "Rate group 2") end, "Rate group 2")
dt.register_event("shortcut",function(event, shortcut) dt.register_event("shortcut",
function(event, shortcut)
apply_rating(3) apply_rating(3)
end, "Rate group 3") end, "Rate group 3")
dt.register_event("shortcut",function(event, shortcut) dt.register_event("shortcut",
function(event, shortcut)
apply_rating(4) apply_rating(4)
end, "Rate group 4") end, "Rate group 4")
dt.register_event("shortcut",function(event, shortcut) dt.register_event("shortcut",
function(event, shortcut)
apply_rating(5) apply_rating(5)
end, "Rate group 5") end, "Rate group 5")

View File

@@ -34,6 +34,11 @@ local debug = require "darktable.debug"
-- check API version -- check API version
du.check_min_api_version("3.0.0", "rename-tags") du.check_min_api_version("3.0.0", "rename-tags")
local CURR_API_STRING = darktable.configuration.api_version_string
local rt = {}
rt.module_installed = false
rt.event_registered = false
-- GUI entries -- GUI entries
local old_tag = darktable.new_widget("entry") { tooltip = "Enter old tag" } local old_tag = darktable.new_widget("entry") { tooltip = "Enter old tag" }
@@ -99,6 +104,13 @@ local function rename_tags()
rename_reset() rename_reset()
end end
local function install_module()
if not rt.module_installed then
darktable.register_lib ("rename_tags", "rename tag", true, true, {[darktable.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 20},}, rt.rename_widget, nil, nil)
rt.module_installed = true
end
end
-- GUI -- GUI
local old_widget = darktable.new_widget ("box") { local old_widget = darktable.new_widget ("box") {
orientation = "horizontal", orientation = "horizontal",
@@ -112,7 +124,7 @@ local new_widget = darktable.new_widget ("box") {
new_tag new_tag
} }
local rename_widget = darktable.new_widget ("box") { rt.rename_widget = darktable.new_widget ("box") {
orientation = "vertical", orientation = "vertical",
reset_callback = rename_reset, reset_callback = rename_reset,
old_widget, old_widget,
@@ -120,6 +132,20 @@ local rename_widget = darktable.new_widget ("box") {
darktable.new_widget("button") { label = "Go", clicked_callback = rename_tags } darktable.new_widget("button") { label = "Go", clicked_callback = rename_tags }
} }
if darktable.gui.current_view().id == "lighttable" then
install_module()
else
if not rt.event_registered then
darktable.register_event(
"view-changed",
function(event, old_view, new_view)
if new_view.name == "lighttable" and old_view.name == "darkroom" then
install_module()
end
end
)
rt.event_registered = true
end
end
darktable.register_lib ("rename_tags", "rename tag", true, true, {[darktable.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 20},}, rename_widget, nil, nil)

View File

@@ -26,6 +26,7 @@ du.check_min_api_version("3.0.0", "select_untagged")
-- Tell gettext where to find the .mo file translating messages for a particular domain -- Tell gettext where to find the .mo file translating messages for a particular domain
gettext.bindtextdomain("select_untagged",dt.configuration.config_dir.."/lua/locale/") gettext.bindtextdomain("select_untagged",dt.configuration.config_dir.."/lua/locale/")
local CURR_API_STRING = dt.configuration.api_version_string
local function _(msgid) local function _(msgid)
return gettext.dgettext("select_untagged", msgid) return gettext.dgettext("select_untagged", msgid)
@@ -35,23 +36,23 @@ local function stop_job(job)
job.valid = false job.valid = false
end end
local function select_untagged_images() local function select_untagged_images(event, images)
job = dt.gui.create_job(_("select untagged images"), true, stop_job) job = dt.gui.create_job(_("select untagged images"), true, stop_job)
local selection = {} local selection = {}
for key,image in ipairs(dt.collection) do for key,image in ipairs(images) do
if(job.valid) then if(job.valid) then
job.percent = (key-1)/#dt.collection job.percent = (key - 1)/#images
local tags = dt.tags.get_tags(image) local tags = dt.tags.get_tags(image)
local hasTags = false local hasTags = false
for _,tag in ipairs(tags) do for _,tag in ipairs(tags) do
if not string.match(tag.name,"darktable|") then if not string.match(tag.name, "darktable|") then
hasTags = true hasTags = true
end end
end end
if hasTags == false then if hasTags == false then
table.insert(selection,image) table.insert(selection, image)
end end
else else
break break
@@ -59,7 +60,11 @@ local function select_untagged_images()
end end
job.valid = false job.valid = false
dt.gui.selection(selection) -- return table of images to set the selection to
return selection
end end
dt.gui.libs.select.register_selection(_("select untagged"),select_untagged_images,_("select all images containing no tags or only tags added by darktable")) dt.gui.libs.select.register_selection(
_("select untagged"),
select_untagged_images,
_("select all images containing no tags or only tags added by darktable"))

View File

@@ -27,11 +27,13 @@ USAGE
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"
require "official/yield"
local gettext = dt.gettext local gettext = dt.gettext
du.check_min_api_version("2.0.2", "slideshowMusic") du.check_min_api_version("2.0.2", "slideshowMusic")
local CURR_API_STRING = dt.configuration.api_version_string
-- Tell gettext where to find the .mo file translating messages for a particular domain -- Tell gettext where to find the .mo file translating messages for a particular domain
gettext.bindtextdomain("slideshowMusic",dt.configuration.config_dir.."/lua/locale/") gettext.bindtextdomain("slideshowMusic",dt.configuration.config_dir.."/lua/locale/")
@@ -77,4 +79,5 @@ dt.preferences.register("slideshowMusic",
_("Plays music with rhythmbox if a slideshow starts"), _("Plays music with rhythmbox if a slideshow starts"),
true) true)
-- Register -- Register
dt.register_event("view-changed",playSlideshowMusic) dt.register_event("view-changed",
playSlideshowMusic)

View File

@@ -83,6 +83,7 @@ dtutils.check_min_api_version("5.0.0", LIB_ID)
local MKDIR_COMMAND = darktable.configuration.running_os == "windows" and "mkdir " or "mkdir -p " local MKDIR_COMMAND = darktable.configuration.running_os == "windows" and "mkdir " or "mkdir -p "
local PATH_SEPARATOR = darktable.configuration.running_os == "windows" and "\\\\" or "/" local PATH_SEPARATOR = darktable.configuration.running_os == "windows" and "\\\\" or "/"
local PATH_SEGMENT_REGEX = "(" .. PATH_SEPARATOR .. "?)([^" .. PATH_SEPARATOR .. "]+)" local PATH_SEGMENT_REGEX = "(" .. PATH_SEPARATOR .. "?)([^" .. PATH_SEPARATOR .. "]+)"
local CURR_API_STRING = darktable.configuration.api_version_string
unpack = unpack or table.unpack unpack = unpack or table.unpack
gmatch = string.gfind or string.gmatch gmatch = string.gfind or string.gmatch
@@ -99,6 +100,10 @@ end
-- Helper functions: BEGIN -- Helper functions: BEGIN
local th = {}
th.module_installed = false
th.event_registered = false
local function pathExists(path) local function pathExists(path)
local success, err, errno = os.rename(path, path) local success, err, errno = os.rename(path, path)
if not success then if not success then
@@ -122,6 +127,16 @@ local function createDirectory(path)
end end
end end
local function install_module()
if not th.module_installed then
darktable.register_lib(LIB_ID,
"transfer hierarchy", true, true, {
[darktable.gui.views.lighttable] = { "DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 700 }
}, th.transfer_widget, nil, nil)
th.module_installed = true
end
end
-- Helper functions: END -- Helper functions: END
@@ -292,7 +307,7 @@ end
local transfer_widget = darktable.new_widget("box") { th.transfer_widget = darktable.new_widget("box") {
orientation = "vertical", orientation = "vertical",
darktable.new_widget("button") { darktable.new_widget("button") {
label = _("calculate"), label = _("calculate"),
@@ -347,12 +362,18 @@ darktable.preferences.register(
-- Preferences: END -- Preferences: END
if darktable.gui.current_view().id == "lighttable" then
install_module()
else
if not th.event_registered then
darktable.register_event(
darktable.register_lib(LIB_ID, "view-changed",
"transfer hierarchy", true, true, { function(event, old_view, new_view)
[darktable.gui.views.lighttable] = { "DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 700 } if new_view.name == "lighttable" and old_view.name == "darkroom" then
}, transfer_widget, nil, nil) install_module()
end
end
)
th.event_registered = true
end
end

View File

@@ -96,7 +96,7 @@ local resolutions = {
} }
} }
local framerates = {"15", "16", "23.98", "24", "25", "29,97", "30", "48", "50", "59.94", "60"} local framerates = {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "15", "16", "23.98", "24", "25", "29,97", "30", "48", "50", "59.94", "60", "120", "240", "300"}
local formats = { local formats = {
["AVI"] = { ["AVI"] = {

View File

@@ -34,6 +34,7 @@ local dt = require "darktable"
local du = require "lib/dtutils" local du = require "lib/dtutils"
du.check_min_api_version("3.0.0", "moduleExample") du.check_min_api_version("3.0.0", "moduleExample")
local CURR_API_STRING = dt.configuration.api_version_string
-- translation -- translation
@@ -46,6 +47,44 @@ local function _(msgid)
return gettext.dgettext("moduleExample", msgid) return gettext.dgettext("moduleExample", msgid)
end end
-- declare a local namespace and a couple of variables we'll need to install the module
local mE = {}
mE.widgets = {}
mE.event_registered = false -- keep track of whether we've added an event callback or not
mE.module_installed = false -- keep track of whether the module is module_installed
--[[ We have to create the module in one of two ways depending on which view darktable starts
in. In orker to not repeat code, we wrap the darktable.register_lib in a local function.
]]
local function install_module()
if not mE.module_installed then
-- https://www.darktable.org/lua-api/index.html#darktable_register_lib
dt.register_lib(
"exampleModule", -- Module name
"exampleModule", -- name
true, -- expandable
false, -- resetable
{[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, -- containers
-- https://www.darktable.org/lua-api/types_lua_box.html
dt.new_widget("box") -- widget
{
orientation = "vertical",
dt.new_widget("button")
{
label = _("MyButton"),
clicked_callback = function (_)
dt.print(_("Button clicked"))
end
},
table.unpack(mE.widgets),
},
nil,-- view_enter
nil -- view_leave
)
mE.module_installed = true
end
end
-- https://www.darktable.org/lua-api/types_lua_check_button.html -- https://www.darktable.org/lua-api/types_lua_check_button.html
local check_button = dt.new_widget("check_button"){label = _("MyCheck_button"), value = true} local check_button = dt.new_widget("check_button"){label = _("MyCheck_button"), value = true}
@@ -90,35 +129,35 @@ local slider = dt.new_widget("slider")
value = 52 -- The current value of the slider value = 52 -- The current value of the slider
} }
-- https://www.darktable.org/lua-api/index.html#darktable_register_lib -- pack the widgets in a table for loading in the module
dt.register_lib(
"exampleModule", -- Module name table.insert(mE.widgets, check_button)
"exampleModule", -- name table.insert(mE.widgets, combobox)
true, -- expandable table.insert(mE.widgets, entry)
false, -- resetable table.insert(mE.widgets, file_chooser_button)
{[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, -- containers table.insert(mE.widgets, label)
-- https://www.darktable.org/lua-api/types_lua_box.html table.insert(mE.widgets, separator)
dt.new_widget("box") -- widget table.insert(mE.widgets, slider)
{
orientation = "vertical", -- ... and tell dt about it all
dt.new_widget("button")
{
label = _("MyButton"), if dt.gui.current_view().id == "lighttable" then -- make sure we are in lighttable view
clicked_callback = function (_) install_module() -- register the lib
dt.print(_("Button clicked")) else
if not mE.event_registered then -- if we are not in lighttable view then register an event to signal when we might be
-- https://www.darktable.org/lua-api/index.html#darktable_register_event
dt.register_event(
"view-changed", -- we want to be informed when the view changes
function(event, old_view, new_view)
if new_view.name == "lighttable" and old_view.name == "darkroom" then -- if the view changes from darkroom to lighttable
install_module() -- register the lib
end
end end
}, )
check_button, mE.event_registered = true -- keep track of whether we have an event handler installed
combobox, end
entry, end
file_chooser_button,
label,
separator,
slider
},
nil,-- view_enter
nil -- view_leave
)
-- vim: shiftwidth=2 expandtab tabstop=2 cindent syntax=lua -- vim: shiftwidth=2 expandtab tabstop=2 cindent syntax=lua
-- kate: hl Lua; -- kate: hl Lua;

View File

@@ -52,7 +52,7 @@
]] ]]
local dt = require "darktable" local dt = require "darktable"
--[[ --[[
require "lib/..." provides access to functions that have been pulled from various require "lib/..." provides access to functions that have been pulled from various
scripts and consolidated into libraries. Using the libraries eliminates having to scripts and consolidated into libraries. Using the libraries eliminates having to
@@ -62,6 +62,7 @@ local dt = require "darktable"
local du = require "lib/dtutils" -- utilities local du = require "lib/dtutils" -- utilities
local df = require "lib/dtutils.file" -- file utilities local df = require "lib/dtutils.file" -- file utilities
local dtsys = require "lib/dtutils.system" -- system utilities local dtsys = require "lib/dtutils.system" -- system utilities
local CURR_API_STRING = dt.configuration.api_version_string
--[[ --[[
darktable is an international program, and it's user interface has been translated into darktable is an international program, and it's user interface has been translated into
@@ -204,24 +205,26 @@ end
to see if the executable is there. to see if the executable is there.
]] ]]
local executable = "ufraw-batch" if dt.configuration.running_os ~= "linux" then
local ufraw_batch_path_widget = dt.new_widget("file_chooser_button"){ local executable = "ufraw-batch"
title = _("Select ufraw-batch[.exe] executable"), local ufraw_batch_path_widget = dt.new_widget("file_chooser_button"){
value = df.get_executable_path_preference(executable), title = _("Select ufraw-batch[.exe] executable"),
is_directory = false, value = df.get_executable_path_preference(executable),
changed_callback = function(self) is_directory = false,
if df.check_if_bin_exists(self.value) then changed_callback = function(self)
df.set_executable_path_preference(executable, self.value) if df.check_if_bin_exists(self.value) then
df.set_executable_path_preference(executable, self.value)
end
end end
end }
} dt.preferences.register("executable_paths", "ufraw-batch", -- name
dt.preferences.register("executable_paths", "ufraw-batch", -- name "file", -- type
"file", -- type _('multi_os: ufraw-batch location'), -- label
_('multi_os: ufraw-batch location'), -- label _('Installed location of ufraw-batch. Requires restart to take effect.'), -- tooltip
_('Installed location of ufraw-batch. Requires restart to take effect.'), -- tooltip "ufraw-batch", -- default
"ufraw-batch", -- default ufraw_batch_path_widget
ufraw_batch_path_widget )
) end
--[[ --[[
Add a button to the selected images module in lighttable Add a button to the selected images module in lighttable
@@ -232,6 +235,7 @@ dt.gui.libs.image.register_action(
function(event, images) extract_embedded_jpeg(images) end, function(event, images) extract_embedded_jpeg(images) end,
"extract embedded jpeg" "extract embedded jpeg"
) )
--[[ --[[
Add a shortcut Add a shortcut

View File

@@ -283,4 +283,51 @@ function dtutils.check_os(operating_systems)
return false return false
end end
dtutils.libdoc.functions["find_image_by_id"] = {
Name = [[find_image_by_id]],
Synopsis = [[look up an image by ID in the database]],
Usage = [[local du = require "lib/dtutils"
local img = du.find_image_by_id(imgid)
id - int - the ID to look up
]],
Description = [[find_image_by_id looks up an image by ID in the database.]],
Return_Value = [[result - dt_lua_image_t - image with the given ID if found, nil if not]],
Limitations = [[]],
Example = [[]],
See_Also = [[]],
Reference = [[]],
License = [[]],
Copyright = [[]],
}
function dtutils.find_image_by_id(imgid)
if #dt.database == 0 or imgid > dt.database[#dt.database].id then
return nil
end
if dt.configuration.api_version_string >= "6.2.0" then
return dt.database.get_image(imgid)
else
local min = 1
local max = #dt.database
while (max-min)//2 > 0 do
local mid = min + (max-min)//2
local midID = dt.database[mid].id
if imgid == midID then
return dt.database[mid]
elseif imgid < midID then
max = mid-1
else
min = mid+1
end
end
if dt.database[min].id == imgid then
return dt.database[min]
elseif dt.database[max].id == imgid then
return dt.database[max]
else
return nil
end
end
end
return dtutils return dtutils

View File

@@ -329,6 +329,7 @@ local function _old_check_if_bin_exists(bin) -- only run on windows if preferen
local path = nil local path = nil
if string.match(bin, "\\") then if string.match(bin, "\\") then
path = bin path = bin
else else
path = dtutils_file.get_executable_path_preference(bin) path = dtutils_file.get_executable_path_preference(bin)
@@ -540,7 +541,7 @@ function dtutils_file.check_if_file_exists(filepath)
local p = io.popen("if exist " .. dtutils_file.sanitize_filename(filepath) .. " (echo 'yes') else (echo 'no')") local p = io.popen("if exist " .. dtutils_file.sanitize_filename(filepath) .. " (echo 'yes') else (echo 'no')")
local ans = p:read("*all") local ans = p:read("*all")
p:close() p:close()
if string.match(ans, "yes") then if string.match(ans, "yes") then
result = true result = true
end end
-- result = os.execute('if exist "'..filepath..'" (cmd /c exit 0) else (cmd /c exit 1)') -- result = os.execute('if exist "'..filepath..'" (cmd /c exit 0) else (cmd /c exit 1)')
@@ -690,8 +691,8 @@ dtutils_file.libdoc.functions["filename_increment"] = {
local result = df.filename_increment(filepath) local result = df.filename_increment(filepath)
filepath - string - filename to increment]], filepath - string - filename to increment]],
Description = [[filename_increment solves the problem of filename confllict by adding an Description = [[filename_increment solves the problem of filename confllict by adding an
increment to the filename. If the supplied filename has no increment then increment to the filename. If the supplied filename has no increment then
"01" is added to the basename. If the filename already has an increment, then "01" is added to the basename. If the filename already has an increment, then
1 is added to it and the filename returned.]], 1 is added to it and the filename returned.]],
Return_Value = [[result - string - the incremented filename]], Return_Value = [[result - string - the incremented filename]],
@@ -743,7 +744,7 @@ dtutils_file.libdoc.functions["create_unique_filename"] = {
filepath - string - the path and filename requested]], filepath - string - the path and filename requested]],
Description = [[create_unique_filename takes a requested filepath and checks to see if Description = [[create_unique_filename takes a requested filepath and checks to see if
it exists. If if doesn't then it's returned intact. If it already exists, then a two it exists. If if doesn't then it's returned intact. If it already exists, then a two
digit increment is added to the filename and it is tested again. The increment keeps digit increment is added to the filename and it is tested again. The increment keeps
increasing until either a unique filename is found or there have been 100 attempts.]], increasing until either a unique filename is found or there have been 100 attempts.]],
Return_Value = [[result - string - the incremented filename]], Return_Value = [[result - string - the incremented filename]],
Limitations = [[create_unique_filename will only attempt 100 increments.]], Limitations = [[create_unique_filename will only attempt 100 increments.]],
@@ -822,7 +823,7 @@ dtutils_file.libdoc.functions["executable_path_widget"] = {
local widget = df.executable_path_widget(executables) local widget = df.executable_path_widget(executables)
executables - table - a table of strings that are executable names]], executables - table - a table of strings that are executable names]],
Description = [[executable_path_widget takes a table of executable names Description = [[executable_path_widget takes a table of executable names
and builds a set of file selector widgets to get the path to the executable. and builds a set of file selector widgets to get the path to the executable.
The resulting widgets are wrapped in a box widget and returned.]], The resulting widgets are wrapped in a box widget and returned.]],
Return_Value = [[widget - widget - a widget containing a file selector widget for Return_Value = [[widget - widget - a widget containing a file selector widget for
each executable.]], each executable.]],
@@ -837,10 +838,10 @@ dtutils_file.libdoc.functions["executable_path_widget"] = {
function dtutils_file.executable_path_widget(executables) function dtutils_file.executable_path_widget(executables)
local box_widgets = {} local box_widgets = {}
table.insert(box_widgets, dt.new_widget("section_label"){label = "select executable(s)"}) table.insert(box_widgets, dt.new_widget("section_label"){label = "select executable(s)"})
for _, executable in pairs(executables) do for _, executable in pairs(executables) do
table.insert(box_widgets, dt.new_widget("label"){label = "select " .. executable .. " executable"}) table.insert(box_widgets, dt.new_widget("label"){label = "select " .. executable .. " executable"})
local path = dtutils_file.get_executable_path_preference(executable) local path = dtutils_file.get_executable_path_preference(executable)
if not path then if not path then
path = "" path = ""
end end
table.insert(box_widgets, dt.new_widget("file_chooser_button"){ table.insert(box_widgets, dt.new_widget("file_chooser_button"){
@@ -870,7 +871,7 @@ dtutils_file.libdoc.functions["sanitize_filename"] = {
local sanitized_filename = df.sanitize_filename(filename) local sanitized_filename = df.sanitize_filename(filename)
filename - string - a filepath and filename]], filename - string - a filepath and filename]],
Description = [[sanitize_file places quotes around the filename in an Description = [[sanitize_file places quotes around the filename in an
operating system specific manner. The result is safe to pass as operating system specific manner. The result is safe to pass as
an argument to the operating system.]], an argument to the operating system.]],
Return_Value = [[sanitized_filename - string - quoted filename]], Return_Value = [[sanitized_filename - string - quoted filename]],
Limitations = [[]], Limitations = [[]],
@@ -892,7 +893,7 @@ dtutils_file.libdoc.functions["mkdir"] = {
df.mkdir(path) df.mkdir(path)
path - string - a directory path]], path - string - a directory path]],
Description = [[mkdir creates directories if not already exists. It Description = [[mkdir creates directories if not already exists. It
create whole parents subtree if needed create whole parents subtree if needed
]], ]],
Return_Value = [[path - string - a directory path]], Return_Value = [[path - string - a directory path]],
@@ -904,7 +905,7 @@ dtutils_file.libdoc.functions["mkdir"] = {
Copyright = [[]], Copyright = [[]],
} }
function dtutils_file.mkdir(path) function dtutils_file.mkdir(path)
if not dtutils_file.check_if_file_exists(path) then if not dtutils_file.check_if_file_exists(path) then
local mkdir_cmd = dt.configuration.running_os == "windows" and "mkdir" or "mkdir -p" local mkdir_cmd = dt.configuration.running_os == "windows" and "mkdir" or "mkdir -p"
return dsys.external_command(mkdir_cmd.." "..path) return dsys.external_command(mkdir_cmd.." "..path)
@@ -983,5 +984,6 @@ if dt.configuration.running_os == "windows" then
false) false)
end end
return dtutils_file return dtutils_file

View File

@@ -51,54 +51,63 @@ local dt_print_error = dt.print_error
local dt_print_log = dt.print_log local dt_print_log = dt.print_log
local dt_print = dt.print local dt_print = dt.print
-- set the default log levels -- set the default log levels
dtutils_log.debug = { dtutils_log.debug = {
label = "DEBUG:", label = "DEBUG: ",
enabled = false, enabled = false,
engine = dt_print_log, engine = dt_print_log,
caller_info = 3,
level = 1, level = 1,
} }
dtutils_log.info = { dtutils_log.info = {
label = "INFO:", label = "INFO: ",
enable = false, enable = false,
engine = dt_print_log, engine = dt_print_log,
caller_info = 1,
level = 2, level = 2,
} }
dtutils_log.warn = { dtutils_log.warn = {
label = "WARN:", label = "WARN: ",
enabled = false, enabled = false,
engine = dt_print_log, engine = dt_print_log,
caller_info = 2,
level = 3, level = 3,
} }
dtutils_log.error = { dtutils_log.error = {
label = "ERROR:", label = "ERROR: ",
enabled = true, enabled = true,
engine = dt_print_error, engine = dt_print_log,
caller_info = 3,
level = 4, level = 4,
} }
dtutils_log.success = { dtutils_log.success = {
label = "SUCCESS:", label = "SUCCESS: ",
enabled = true, enabled = true,
engine = dt_print_log, engine = dt_print_log,
caller_info = 2,
level = 5, level = 5,
} }
dtutils_log.screen = { dtutils_log.screen = {
label = "", label = "",
enabled = true, enabled = true,
engine = dt_print, engine = dt_print,
caller_info = 0,
level = 9, level = 9,
} }
dtutils_log.always = { dtutils_log.always = {
label = "", label = "",
enabled = true, enabled = true,
engine = dt_print_log, engine = dt_print_log,
caller_info = 3,
level = 9, level = 9,
} }
dtutils_log.critical = { dtutils_log.critical = {
label = "CRITICAL:", label = "CRITICAL: ",
enabled = true, enabled = true,
engine = print, engine = print,
caller_info = 3,
level = 9, level = 9,
} }
@@ -120,7 +129,7 @@ result = log.caller(level)
Copyright = [[]], Copyright = [[]],
} }
function dtutils_log.caller(level) function dtutils_log.caller(level, info)
local name = debug.getinfo(level).name local name = debug.getinfo(level).name
local lineno = nil local lineno = nil
local source = nil local source = nil
@@ -131,7 +140,16 @@ function dtutils_log.caller(level)
-- we just need the filename, so grab it from the string -- we just need the filename, so grab it from the string
-- Thanks, Tobias Jakobs :-) -- Thanks, Tobias Jakobs :-)
source = string.match(source, "@.-([^\\/]-%.?[^%.\\/]*)$") source = string.match(source, "@.-([^\\/]-%.?[^%.\\/]*)$")
return name .. ": " .. source .. ": " .. lineno .. ":"
if info == 0 then
return ""
elseif info == 1 then
return source .. ": "
elseif info == 2 then
return source .. ": " .. name .. ": "
else
return source .. ": " .. name .. ": " .. lineno .. ":"
end
else else
return "callback:" return "callback:"
end end
@@ -182,7 +200,7 @@ function dtutils_log.msg(level, ...)
end end
local log_msg = level.label local log_msg = level.label
if level.engine ~= dt_screen and call_level ~= 0 then if level.engine ~= dt_screen and call_level ~= 0 then
log_msg = log_msg .. dtutils_log.caller(call_level) .. " " log_msg = log_msg .. dtutils_log.caller(call_level, level.caller_info) .. " "
elseif log_msg:len() > 2 then elseif log_msg:len() > 2 then
log_msg = log_msg .. " " log_msg = log_msg .. " "
end end

View File

@@ -269,5 +269,31 @@ function dtutils_string.sanitize(str)
end end
end end
dtutils_string.libdoc.functions["sanitize_lua"] = {
Name = [[sanitize_lua]],
Synopsis = [[escape lua 'magic' characters from a pattern string]],
Usage = [[local ds = require "lib/dtutils.string"
local result = ds.sanitize_lua(str)
str - string - the string that needs to be made safe]],
Description = [[sanitize_lua escapes lua 'magic' characters so that
a string may be used in lua string/patten matching.]],
Return_Value = [[result - string - a lua pattern safe string]],
Limitations = [[]],
Example = [[]],
See_Also = [[]],
Reference = [[]],
License = [[]],
Copyright = [[]],
}
function dtutils_string.sanitize_lua(str)
str = string.gsub(str, "%-", "%%-")
str = string.gsub(str, "%(", "%%(")
str = string.gsub(str, "%)", "%%)")
return str
end
return dtutils_string return dtutils_string

View File

@@ -1,7 +1,6 @@
local dtutils_system = {} local dtutils_system = {}
local dt = require "darktable" local dt = require "darktable"
require "official/yield" -- necessary for dt.control.execute()
dtutils_system.libdoc = { dtutils_system.libdoc = {
Name = [[dtutils.system]], Name = [[dtutils.system]],

View File

@@ -1,39 +1,78 @@
# OpenInExplorer Darktable Plug-In. # SOME DESCRIPTIVE TITLE.
# Copyright (C) 2020 Volker Lenhardt # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package. # This file is distributed under the same license as the PACKAGE package.
# Volker Lenhardt <volker.lenhardt@unitybox.de>, 2020. # Volker Lenhardt <volker.lenhardt@unitybox.de>, 2020.
# #
#, fuzzy #, fuzzy
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: OpenInExplorer\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-04-19 14:43+0200\n" "POT-Creation-Date: 2020-06-11 19:07+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: Volker Lenhardt <volker.lenhardt@unitybox.de>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
"Language: de_DE\n" "Language: de_DE\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
#: OpenInExplorer.lua:64 #: OpenInExplorer.lua:71
msgid "" msgid ""
"OpenInExplorer plug-in only supports Linux, macOS, and Windows at this time" "OpenInExplorer plug-in only supports Linux and macOS, and Windows at this time"
msgstr "OpenInExplorer-Plug-in kann nur auf macOS, Linux oder Windows laufen" msgstr "OpenInExplorer-Plug-in unterstützt zur Zeit nur Linux, macOS oder Windows"
#: OpenInExplorer.lua:79 #: OpenInExplorer.lua:87
msgid ""
"No links directory selected.\n"
"Please check the dt preferences (lua options)"
msgstr "Kein Verknüpfungs-Verzeichnis ausgewählt.\nBitte die dt-Voreinstellungen überprüfen (Lua-Optionen)"
#: OpenInExplorer.lua:91
#, lua-format
msgid ""
"Links directory '%s' not found.\n"
"Please check the dt preferences (lua options)"
msgstr "Das Verknüpfungs-Verzeichnis '%s' konnte nicht gefunden werden.\nBitte die dt-Voreinstellungen überprüfen (Lua-Optionen)"
#: OpenInExplorer.lua:148
msgid "Failed to create links. Missing rights?"
msgstr "Die Verknüpfungen konnten nicht erstellt werden. Fehlende Rechte?"
#: OpenInExplorer.lua:164
msgid "Please select an image" msgid "Please select an image"
msgstr "Es wurde kein Bild ausgewählt" msgstr "Es wurde kein Bild ausgewählt"
#: OpenInExplorer.lua:98 #: OpenInExplorer.lua:170
msgid "Please select fewer images (max 15)" msgid "Please select fewer images (max. 15)"
msgstr "Bitte nicht mehr als 15 Bilder auswählen" msgstr "Bitte nicht mehr als 15 Bilder auswählen"
#: OpenInExplorer.lua:105 #: OpenInExplorer.lua:186
msgid "show in file explorer" msgid "show in file explorer"
msgstr "im Dateimanager anzeigen" msgstr "im Dateimanager anzeigen"
#: OpenInExplorer.lua:107 #: OpenInExplorer.lua:188
msgid "Opens the file manager at the selected image's location" msgid "Open the file manager at the selected image's location"
msgstr "Öffnet den Dateimanager an der Position des ausgewählten Bildes" msgstr "Öffnet den Dateimanager an der Position des ausgewählten Bildes"
#: OpenInExplorer.lua:193
msgid "OpenInExplorer: linked files directory"
msgstr "OpenInExplorer: Verknüpfungs-Verzeichnis"
#: OpenInExplorer.lua:194
msgid ""
"Directory to store the links to the file names. Requires restart to take "
"effect"
msgstr "Verzeichnis für die Verknüpfungen zu den Dateinamen. Erfordert dt-Neustart"
#: OpenInExplorer.lua:197
msgid "Select directory"
msgstr "Verzeichnis auswählen"
#: OpenInExplorer.lua:203
msgid "OpenInExplorer: use links"
msgstr "OpenInExplorer: Verknüpfungen nutzen"
#: OpenInExplorer.lua:204
msgid "Use links instead of multiple windows. Requires restart to take effect"
msgstr "Verknüpfungen statt einzelner Fenster nutzen. Erfordert dt-Neustart"

View File

@@ -0,0 +1,73 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: Lua photils\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-05-12 13:12+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: \n"
"Language-Team: \n"
"Language: de\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
msgid "get tags"
msgstr "hole stichwörter"
msgid "requires a restart to be applied"
msgstr "erfordert einen Neustart um angewendet zu werden"
msgid "min confidence value"
msgstr "min vertrauenswert"
msgid ""
"The suggested tags were not generated\n"
" for the currently selected image!"
msgstr ""
"Die vorgeschlagenen Stichwörter wurden für das\n"
"aktuell ausgewählte Bild nicht generiert!"
#, lua-format
msgid " page %s of %s "
msgstr " seite %s von %s "
msgid "Tags successfully attached to image"
msgstr "Stichwörter erfolgreich an Bild angefügt"
#, lua-format
msgid "Error writing to `%s`"
msgstr "Fehler beim Schreiben in `%s`"
#, lua-format
msgid "%s failed, see terminal output for details"
msgstr "%s fehlgeschlagen, siehe Terminal-Ausgabe für Details"
#, lua-format
msgid "%s found %d tags for your image"
msgstr "%s gefunden %d-Stichwörter für Ihr Bild"
msgid "No image selected."
msgstr "Kein Bild ausgewählt."
msgid "This plugin can only handle a single image."
msgstr "Dieses Plugin kann nur ein einziges Bild verarbeiten."
#, lua-format
msgid "attach %d tags"
msgstr "%d stichwörter anhängen"
msgid "photils-cli not found"
msgstr "photils-cli nicht gefunden"
msgid ""
"Select an image, click \"Get Tags\" and get \n"
"suggestions for tags."
msgstr ""
"Wählen Sie ein Bild aus, drücken Sie \"Hole Stichwörter\"\n"
" und erhalten Sie Vorschläge für Stichwörter."

View File

@@ -7,21 +7,29 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: \n" "Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-09-07 22:25-0400\n" "POT-Creation-Date: 2020-12-27 17:55+0100\n"
"PO-Revision-Date: 2016-10-03 14:55+0200\n" "PO-Revision-Date: 2020-12-27 17:55+0100\n"
"Last-Translator: Pascal Obry <pascal@obry.net>\n" "Last-Translator: Christophe Agathon <christophe.agathon@gmail.com>\n"
"Language-Team: \n"
"Language: fr_FR\n" "Language: fr_FR\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 1.8.9\n" "X-Generator: Poedit 2.3\n"
"Language: fr_FR\n"
"X-Poedit-SourceCharset: UTF-8\n" "X-Poedit-SourceCharset: UTF-8\n"
"X-Poedit-KeywordsList: gettext;dgettext:2;dcgettext:2ngettext:1,2;" "X-Poedit-KeywordsList: _;gettext;dgettext:2;dcgettext:2ngettext:1,2;"
"dngettext:2,3\n" "dngettext:2,3\n"
"X-Poedit-Basepath: .\n" "X-Poedit-Basepath: ../../../contrib\n"
"Language-Team: \n" "X-Poedit-SearchPath-0: clear_GPS.lua\n"
#: clear_GPS.lua:62 #: clear_GPS.lua:67
msgid "clear GPS data" msgid "clear GPS data"
msgstr "effacer données GPS" msgstr "effacer données GPS"
#: clear_GPS.lua:69
msgid "Clear GPS data from selected images"
msgstr "Effacer les données GPS des images sélectionnées"
#: clear_GPS.lua:75
msgid "Clear GPS data"
msgstr "Effacer les données GPS"

View File

@@ -0,0 +1,78 @@
# French messages for copy_attach_detach_tags.lua
# Christophe Agathon <christophe.agathon@gmail.com>, 2021
msgid ""
msgstr ""
"Project-Id-Version: \n"
"POT-Creation-Date: 2021-01-10 19:39+0100\n"
"PO-Revision-Date: 2021-01-10 19:43+0100\n"
"Last-Translator: Christophe Agathon <christophe.agathon@gmail.com>\n"
"Language-Team: \n"
"Language: fr_FR\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 2.3\n"
"X-Poedit-Basepath: ../../../contrib\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
"X-Poedit-KeywordsList: _\n"
"X-Poedit-SearchPath-0: copy_attach_detach_tags.lua\n"
#: copy_attach_detach_tags.lua:93
msgid "Image tags copied ..."
msgstr "Mots-clés de l'image copiés ..."
#: copy_attach_detach_tags.lua:115
msgid "No tag to attach, please copy tags first."
msgstr "Pas de mot-clé à attacher, veuillez d'abord copier les mots-clés."
#: copy_attach_detach_tags.lua:139
msgid "Tags attached ..."
msgstr "Mots-clés attachés ..."
#: copy_attach_detach_tags.lua:155
msgid "Tags removed from image(s)."
msgstr "Mots-clés supprimés des images."
#: copy_attach_detach_tags.lua:161
msgid "Tags replaced"
msgstr "Mots-clés remplacés"
#: copy_attach_detach_tags.lua:166
msgid "tagging addon"
msgstr "mots-clés extra"
#: copy_attach_detach_tags.lua:189
msgid "tag clipboard"
msgstr "presse-papier des mots-clés"
#: copy_attach_detach_tags.lua:197
msgid "multi copy tags"
msgstr "copier mots-clés"
#: copy_attach_detach_tags.lua:198 copy_attach_detach_tags.lua:252
msgid "copy tags from selected image(s)"
msgstr "copier les mots-clés des images sélectionnnées"
#: copy_attach_detach_tags.lua:201 copy_attach_detach_tags.lua:257
msgid "paste tags to selected image(s)"
msgstr "coller les mots clés dans les images sélectionnées"
#: copy_attach_detach_tags.lua:202
msgid "paste tags"
msgstr "coller mots-clés"
#: copy_attach_detach_tags.lua:210
msgid "replace tags"
msgstr "remplacer mots-clés"
#: copy_attach_detach_tags.lua:211 copy_attach_detach_tags.lua:267
msgid "replace tags from selected image(s)"
msgstr "remplacer les mots-clés des images sélectionnées"
#: copy_attach_detach_tags.lua:214
msgid "remove all tags"
msgstr "supprimer tous mots-clés"
#: copy_attach_detach_tags.lua:215 copy_attach_detach_tags.lua:262
msgid "remove tags from selected image(s)"
msgstr "supprimer les mots-clés des images sélectionnées"

View File

@@ -0,0 +1,35 @@
# French messages for copy_paste_metadata.lua
# Christophe Agathon <christophe.agathon@gmail.com>, 2020
msgid ""
msgstr ""
"Project-Id-Version: copy_paste_metadata\n"
"POT-Creation-Date: 2020-12-26 12:49+0100\n"
"PO-Revision-Date: 2020-12-26 12:52+0100\n"
"Last-Translator: Christophe Agathon <christophe.agathon@gmail.com>\n"
"Language-Team: \n"
"Language: fr_FR\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 2.3\n"
"X-Poedit-Basepath: ../../../official\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
"X-Poedit-SourceCharset: UTF-8\n"
"X-Poedit-KeywordsList: _\n"
"X-Poedit-SearchPath-0: copy_paste_metadata.lua\n"
#: copy_paste_metadata.lua:115
msgid "copy metadata"
msgstr "copier les métadonnées"
#: copy_paste_metadata.lua:117
msgid "copy metadata of the first selected image"
msgstr "copier les métadonnées de la première image sélectionnée"
#: copy_paste_metadata.lua:121
msgid "paste metadata"
msgstr "coller les métadonnées"
#: copy_paste_metadata.lua:123
msgid "paste metadata to the selected images"
msgstr "coller les métadonnées vers les images sélectionnées"

View File

@@ -0,0 +1,188 @@
# French messages for script_manager.lua
# Christophe Agathon <christophe.agathon@gmail.com>, 2020
msgid ""
msgstr ""
"Project-Id-Version: \n"
"POT-Creation-Date: 2020-12-28 10:22+0100\n"
"PO-Revision-Date: 2020-12-28 10:24+0100\n"
"Last-Translator: Christophe Agathon <christophe.agathon@gmail.com>\n"
"Language-Team: \n"
"Language: fr_FR\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 2.3\n"
"X-Poedit-Basepath: ../../../tools\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
"X-Poedit-KeywordsList: _\n"
"X-Poedit-SearchPath-0: script_manager.lua\n"
#: script_manager.lua:190
msgid "Cant read from "
msgstr "Ne peut pas lire "
#: script_manager.lua:204
msgid "Loaded "
msgstr "Script chargé : "
#: script_manager.lua:207
msgid " failed to load"
msgstr " non chargé"
#: script_manager.lua:223
msgid " will not start when darktable is restarted"
msgstr " ne démarrera pas lorsque darktable sera redémarré"
#: script_manager.lua:281 script_manager.lua:345
msgid "find command is "
msgstr "la commande find est "
#: script_manager.lua:321
msgid "lua scripts successfully updated"
msgstr "mise à jour des scripts lua réussie"
#: script_manager.lua:381
msgid "category "
msgstr "la catégorie "
#: script_manager.lua:381
msgid " is already in use. Please specify a different category name."
msgstr " est déjà utilisée. Indiquez un autre nom de catégorie SVP."
#: script_manager.lua:410
msgid "scripts successfully installed into category "
msgstr "les scripts ont été installés dans la catégorie "
#: script_manager.lua:426
msgid "No scripts found to install"
msgstr "Nous n'avons pas trouvé de script à installer"
#: script_manager.lua:430
msgid "failed to download scripts"
msgstr "impossible de télécharger les scripts"
# Peut-être que « activé » serait mieux, mais ce n'est pas la traduction de « started »
#: script_manager.lua:458
msgid " started"
msgstr " démarré"
# Peut-être que « désactivé » serait mieux, mais ce n'est pas la traduction de « stopped »
#: script_manager.lua:460
msgid " stopped"
msgstr " arrêté"
#: script_manager.lua:545
msgid "Page "
msgstr "Page "
#: script_manager.lua:545
msgid " of "
msgstr " sur "
#: script_manager.lua:674
msgid "scripts to update"
msgstr "scripts à mettre à jour"
#: script_manager.lua:675
msgid "select the scripts installation to update"
msgstr "sélectionnez les scripts à mettre à jour"
#: script_manager.lua:684 script_manager.lua:742
msgid "update scripts"
msgstr "mettre à jour les scripts"
#: script_manager.lua:685
msgid "update the lua scripts from the repository"
msgstr "metre à jour les scripts depuis le dépôt"
#: script_manager.lua:696
msgid "enter the URL of the git repository containing the scripts you wish to add"
msgstr "indiquez l'URL du dépôt git contenant les scripts que vous souhaitez ajouter"
#: script_manager.lua:701
msgid "name of new category"
msgstr "nom de la nouvelle catégorie"
#: script_manager.lua:702
msgid "enter a category name for the additional scripts"
msgstr "indiquez un nom de catégorie pour les scripts supplémentaires"
#: script_manager.lua:707
msgid "URL to download additional scripts from"
msgstr "URL d'où seront téléchargés les scripts"
#: script_manager.lua:709
msgid "new category to place scripts in"
msgstr "nouvelle catégorie où seront placés les scripts"
#: script_manager.lua:712
msgid "install additional scripts"
msgstr "installer les scripts supplémentaires"
#: script_manager.lua:720
msgid "Enable \"Disable Scripts\" button"
msgstr "Activer le bouton « Désactiver les Scripts »"
#: script_manager.lua:730
msgid "Disable Scripts"
msgstr "Désactiver les scripts"
#: script_manager.lua:736
msgid "lua scripts will not run the next time darktable is started"
msgstr "les scripts lua ne seront pas lancés au prochain démarrage de darktable"
#: script_manager.lua:745
msgid "add more scripts"
msgstr "ajouter des scripts"
#: script_manager.lua:747
msgid "disable scripts"
msgstr "désactiver les scripts"
#: script_manager.lua:755
msgid "category"
msgstr "catégorie"
#: script_manager.lua:756
msgid "select the script category"
msgstr "sélectionner la catégorie"
#: script_manager.lua:780
msgid "Page:"
msgstr "Page :"
#: script_manager.lua:808
msgid "Scripts"
msgstr "Scripts"
#: script_manager.lua:817
msgid "scripts per page"
msgstr "scripts par page"
#: script_manager.lua:818
msgid "select number of start/stop buttons to display"
msgstr "sélectionner le nombre de boutons marche/arrêt à afficher"
#: script_manager.lua:829
msgid "change number of buttons"
msgstr "changer le nombre de boutons"
#: script_manager.lua:837
msgid "Configuration"
msgstr "Configuration"
#: script_manager.lua:858
msgid "action"
msgstr "action"
#: script_manager.lua:864
msgid "install/update scripts"
msgstr "installer/mettre à jour des scripts"
#: script_manager.lua:864
msgid "configure"
msgstr "configurer"
#: script_manager.lua:864
msgid "start/stop scripts"
msgstr "démarrer/arrêter des scripts"

View File

@@ -27,8 +27,10 @@ USAGE
local dt = require "darktable" local dt = require "darktable"
local du = require "lib/dtutils" local du = require "lib/dtutils"
local gettext = dt.gettext
du.check_min_api_version("3.0.0", "copy_paste_metadata") du.check_min_api_version("3.0.0", "copy_paste_metadata")
local CURR_API_STRING = dt.configuration.api_version_string
-- set this to "false" if you don't want to overwrite metadata fields -- set this to "false" if you don't want to overwrite metadata fields
-- (title, description, creator, publisher and rights) that are already set -- (title, description, creator, publisher and rights) that are already set
@@ -48,6 +50,13 @@ local publisher = ""
local rights = "" local rights = ""
local tags = {} local tags = {}
-- Tell gettext where to find the .mo file translating messages for a particular domain
gettext.bindtextdomain("copy_paste_metadata",dt.configuration.config_dir.."/lua/locale/")
local function _(msgid)
return gettext.dgettext("copy_paste_metadata", msgid)
end
local function copy(image) local function copy(image)
if not image then if not image then
have_data = false have_data = false
@@ -105,15 +114,15 @@ local function paste(images)
end end
dt.gui.libs.image.register_action( dt.gui.libs.image.register_action(
"copy metadata", _("copy metadata"),
function(event, images) copy(images[1]) end, function(event, images) copy(images[1]) end,
"copy metadata of the first selected image" _("copy metadata of the first selected image")
) )
dt.gui.libs.image.register_action( dt.gui.libs.image.register_action(
"paste metadata", _("paste metadata"),
function(event, images) paste(images) end, function(event, images) paste(images) end,
"paste metadata to the selected images" _("paste metadata to the selected images")
) )
dt.register_event( dt.register_event(

View File

@@ -38,6 +38,7 @@ local df = require "lib/dtutils.file"
local dtsys = require "lib/dtutils.system" local dtsys = require "lib/dtutils.system"
local PS = dt.configuration.running_os == "windows" and "\\" or "/" local PS = dt.configuration.running_os == "windows" and "\\" or "/"
local CURR_API_STRING = dt.configuration.api_version_string
local gettext = dt.gettext local gettext = dt.gettext
@@ -46,10 +47,35 @@ du.check_min_api_version("3.0.0", "enfuse")
-- Tell gettext where to find the .mo file translating messages for a particular domain -- Tell gettext where to find the .mo file translating messages for a particular domain
gettext.bindtextdomain("enfuse",dt.configuration.config_dir..PS .. "lua" .. PS .. "locale" .. PS) gettext.bindtextdomain("enfuse",dt.configuration.config_dir..PS .. "lua" .. PS .. "locale" .. PS)
local enf = {}
enf.event_registered = false
enf.module_installed = false
enf.lib_widgets = {}
local function _(msgid) local function _(msgid)
return gettext.dgettext("enfuse", msgid) return gettext.dgettext("enfuse", msgid)
end end
local function install_module()
if not enf.module_installed then
dt.register_lib(
"enfuse", -- plugin name
"enfuse", -- name
true, -- expandable
false, -- resetable
{[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, -- containers
dt.new_widget("box") -- widget
{
orientation = "vertical",
sensitive = enfuse_installed,
table.unpack(enf.lib_widgets)
},
nil,-- view_enter
nil -- view_leave
)
enf.module_installed = true
end
end
-- add a new lib -- add a new lib
-- is enfuse installed? -- is enfuse installed?
local enfuse_installed = df.check_if_bin_exists("enfuse") local enfuse_installed = df.check_if_bin_exists("enfuse")
@@ -229,30 +255,30 @@ if enfuse_installed then
local lib_widgets = {} local lib_widgets = {}
if not enfuse_installed then if not enfuse_installed then
table.insert(lib_widgets, df.executable_path_widget({"ffmpeg"})) table.insert(enf.lib_widgets, df.executable_path_widget({"ffmpeg"}))
end end
table.insert(lib_widgets, exposure_mu) table.insert(enf.lib_widgets, exposure_mu)
table.insert(lib_widgets, depth) table.insert(enf.lib_widgets, depth)
table.insert(lib_widgets, blend_colorspace) table.insert(enf.lib_widgets, blend_colorspace)
table.insert(lib_widgets, enfuse_button) table.insert(enf.lib_widgets, enfuse_button)
-- ... and tell dt about it all -- ... and tell dt about it all
dt.register_lib( if dt.gui.current_view().id == "lighttable" then
"enfuse", -- plugin name install_module()
"enfuse", -- name else
true, -- expandable if not enf.event_registered then
false, -- resetable dt.register_event(
{[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, -- containers "view-changed",
dt.new_widget("box") -- widget function(event, old_view, new_view)
{ if new_view.name == "lighttable" and old_view.name == "darkroom" then
orientation = "vertical", install_module()
sensitive = enfuse_installed, end
table.unpack(lib_widgets) end
}, )
nil,-- view_enter enf.event_registered = true
nil -- view_leave end
) end
else else
dt.print_error("enfuse executable not found") dt.print_error("enfuse executable not found")
error("enfuse executable not found") error("enfuse executable not found")

View File

@@ -37,9 +37,9 @@ USAGE
local dt = require "darktable" local dt = require "darktable"
local du = require "lib/dtutils" local du = require "lib/dtutils"
require "darktable.debug" require "darktable.debug"
require "official/yield"
du.check_min_api_version("2.1.0", "generate_image_txt") du.check_min_api_version("2.1.0", "generate_image_txt")
local CURR_API_STRING = dt.configuration.api_version_string
dt.preferences.register("generate_image_txt", dt.preferences.register("generate_image_txt",
"enabled", "enabled",
@@ -66,7 +66,8 @@ end
local command_setting = dt.preferences.read("generate_image_txt", "command", "string") local command_setting = dt.preferences.read("generate_image_txt", "command", "string")
check_command(command_setting) check_command(command_setting)
dt.register_event("mouse-over-image-changed", function(event, img) dt.register_event("mouse-over-image-changed",
function(event, img)
-- no need to waste processing time if the image has a txt file already -- no need to waste processing time if the image has a txt file already
if not img or img.has_txt or not dt.preferences.read("generate_image_txt", "enabled", "bool") then if not img or img.has_txt or not dt.preferences.read("generate_image_txt", "enabled", "bool") then
return return

View File

@@ -32,9 +32,24 @@ local dt = require "darktable"
local du = require "lib/dtutils" local du = require "lib/dtutils"
du.check_min_api_version("2.0.0", "image_path_in_ui") du.check_min_api_version("2.0.0", "image_path_in_ui")
local CURR_API_STRING = dt.configuration.api_version_string
local ipiu = {}
ipiu.module_installed = false
ipiu.event_registered = false
local main_label = dt.new_widget("label"){selectable = true, ellipsize = "middle", halign = "start"} local main_label = dt.new_widget("label"){selectable = true, ellipsize = "middle", halign = "start"}
local function install_module()
if not ipiu.module_installed then
dt.register_lib("image_path_no_ui", "selected images path", true, false,{
[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_LEFT_CENTER", 300}
}, main_label
)
ipiu.module_installed = true
end
end
local function reset_widget() local function reset_widget()
local selection = dt.gui.selection() local selection = dt.gui.selection()
local result = "" local result = ""
@@ -54,12 +69,23 @@ end
main_label.reset_callback = reset_widget main_label.reset_callback = reset_widget
dt.register_lib("image_path_no_ui","Selected Images path",true,false,{ if dt.gui.current_view().id == "lighttable" then
[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_LEFT_CENTER",300} install_module()
}, main_label else
); if not ipiu.event_registered then
dt.register_event(
"ipiu", "view-changed",
function(event, old_view, new_view)
if new_view.name == "lighttable" and old_view.name == "darkroom" then
install_module()
end
end
)
ipiu.event_registered = true
end
end
dt.register_event("mouse-over-image-changed",reset_widget); dt.register_event("mouse-over-image-changed", reset_widget);
-- --
-- vim: shiftwidth=2 expandtab tabstop=2 cindent syntax=lua -- vim: shiftwidth=2 expandtab tabstop=2 cindent syntax=lua

View File

@@ -34,6 +34,7 @@ local dt = require "darktable"
local import_filter_list = {} local import_filter_list = {}
local n_import_filters = 1 local n_import_filters = 1
local CURR_API_STRING = dt.configuration.api_version_string
-- allow changing the filter from the preferences -- allow changing the filter from the preferences
dt.preferences.register("import_filter_manager", "active_filter", "string", dt.preferences.register("import_filter_manager", "active_filter", "string",

View File

@@ -37,21 +37,22 @@ local dt = require "darktable"
local du = require "lib/dtutils" local du = require "lib/dtutils"
du.check_min_api_version("2.0.0", "save_selection") du.check_min_api_version("2.0.0", "save_selection")
local CURR_API_STRING = dt.configuration.api_version_string
local buffer_count = 5 local buffer_count = 5
for i=1,buffer_count do for i=1,buffer_count do
local saved_selection local saved_selection
dt.register_event("shortcut",function() dt.register_event("shortcut", function()
saved_selection = dt.gui.selection() saved_selection = dt.gui.selection()
end,"save to buffer "..i) end,"save to buffer "..i)
dt.register_event("shortcut",function() dt.register_event("shortcut", function()
dt.gui.selection(saved_selection) dt.gui.selection(saved_selection)
end,"restore from buffer "..i) end,"restore from buffer "..i)
end end
local bounce_buffer = {} local bounce_buffer = {}
dt.register_event("shortcut",function() dt.register_event("shortcut", function()
bounce_buffer = dt.gui.selection(bounce_buffer) bounce_buffer = dt.gui.selection(bounce_buffer)
end,"switch selection with temporary buffer") end,"switch selection with temporary buffer")

View File

@@ -35,7 +35,6 @@ Plugin allows you to choose how many thumbnails you need per row
]] ]]
local dt = require "darktable" local dt = require "darktable"
local du = require "lib/dtutils" local du = require "lib/dtutils"
require "official/yield"
du.check_min_api_version("2.0.0", "selection_to_pdf") du.check_min_api_version("2.0.0", "selection_to_pdf")

View File

@@ -1,42 +0,0 @@
--[[
This file is part of darktable,
Copyright 2016 by Tobias Jakobs.
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/>.
]]
--[[
darktable yield compatibility script
USAGE
* require this script from your main Lua file in the first line
]]
local dt = require "darktable"
local yield_orig = coroutine.yield
if (dt.configuration.api_version_major < 4) then
dt.control = {}
dt.control.execute = function(command)
yield_orig("RUN_COMMAND", command)
end
dt.control.read = function(command)
yield_orig("FILE_READABLE", command)
end
dt.control.sleep = function(command)
yield_orig("WAIT_MS", command)
end
end
-- vim: shiftwidth=2 expandtab tabstop=2 cindent syntax=lua
-- kate: hl Lua;

View File

@@ -37,9 +37,14 @@ du.check_min_api_version("5.0.0", "executable_manager")
local PS = dt.configuration.running_os == "windows" and "\\" or "/" local PS = dt.configuration.running_os == "windows" and "\\" or "/"
local gettext = dt.gettext local gettext = dt.gettext
local CURR_API_STRING = dt.configuration.api_version_string
gettext.bindtextdomain("executable_manager",dt.configuration.config_dir.."/lua/locale/") gettext.bindtextdomain("executable_manager",dt.configuration.config_dir.."/lua/locale/")
local exec_man = {} -- our own namespace
exec_man.module_installed = false
exec_man.event_registered = false
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - -- - - - - - - - - - - - - - - - - - - - - - - - - - - -
-- F U N C T I O N S -- F U N C T I O N S
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - -- - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -86,12 +91,30 @@ local function update_combobox_choices(combobox, choice_table, selected)
combobox.value = selected combobox.value = selected
end end
local function install_module()
if not exec_man.module_installed then
dt.register_lib(
"executable_manager", -- Module name
"executable manager", -- Visible name
true, -- expandable
false, -- resetable
{[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_LEFT_BOTTOM", 100}}, -- containers
dt.new_widget("box") -- widget
{
orientation = "vertical",
exec_man.selector,
exec_man.stack,
},
nil,-- view_enter
nil -- view_leave
)
exec_man.module_installed = true
end
end
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - -- - - - - - - - - - - - - - - - - - - - - - - - - - - -
-- M A I N P R O G R A M -- M A I N P R O G R A M
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - -- - - - - - - - - - - - - - - - - - - - - - - - - - - -
local exec_man = {} -- our own namespace
local DARKTABLERC = dt.configuration.config_dir .. PS .. "darktablerc" local DARKTABLERC = dt.configuration.config_dir .. PS .. "darktablerc"
@@ -117,8 +140,15 @@ for _,pref in ipairs(matches) do
end end
local executable_path_widgets = {} local executable_path_widgets = {}
local executable_path_values = {}
local placeholder_text = dt.configuration.running_os == windows and _("select an executable") or _("search path for executable")
for i,exec in ipairs(exec_table) do for i,exec in ipairs(exec_table) do
executable_path_values[exec] = dt.new_widget("entry"){
text = df.get_executable_path_preference(exec),
placeholder = placeholder_text,
editable = false
}
executable_path_widgets[exec] = dt.new_widget("file_chooser_button"){ executable_path_widgets[exec] = dt.new_widget("file_chooser_button"){
title = _("select ") .. exec .. _(" executable"), title = _("select ") .. exec .. _(" executable"),
value = df.get_executable_path_preference(exec), value = df.get_executable_path_preference(exec),
@@ -126,6 +156,7 @@ for i,exec in ipairs(exec_table) do
changed_callback = function(self) changed_callback = function(self)
if df.check_if_bin_exists(self.value) then if df.check_if_bin_exists(self.value) then
df.set_executable_path_preference(exec, self.value) df.set_executable_path_preference(exec, self.value)
executable_path_values[exec].text = df.get_executable_path_preference(exec)
end end
end end
} }
@@ -155,13 +186,18 @@ exec_man.selector = dt.new_widget("combobox"){
for i,exec in ipairs(exec_table) do for i,exec in ipairs(exec_table) do
exec_man.stack[i] = dt.new_widget("box"){ exec_man.stack[i] = dt.new_widget("box"){
dt.new_widget("section_label"){label = _("current")},
executable_path_values[exec],
dt.new_widget("section_label"){label = _("select")},
executable_path_widgets[exec], executable_path_widgets[exec],
dt.new_widget("section_label"){label = _("reset")},
dt.new_widget("button"){ dt.new_widget("button"){
label = "clear", label = "clear",
tooltip = _("Clear path for ") .. exec, tooltip = _("Clear path for ") .. exec,
clicked_callback = function() clicked_callback = function()
df.set_executable_path_preference(exec, "") df.set_executable_path_preference(exec, "")
executable_path_widgets[exec].value = "" executable_path_widgets[exec].value = ""
executable_path_values[exec].text = ""
end end
} }
@@ -174,19 +210,18 @@ update_combobox_choices(exec_man.selector, exec_table, 1)
-- register the lib -- register the lib
dt.register_lib( if dt.gui.current_view().id == "lighttable" then
"executable_manager", -- Module name install_module()
"executable manager", -- Visible name else
true, -- expandable if not exec_man.event_registered then
false, -- resetable dt.register_event(
{[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_LEFT_BOTTOM", 100}}, -- containers "view-changed",
dt.new_widget("box") -- widget function(event, old_view, new_view)
{ if new_view.name == "lighttable" and old_view.name == "darkroom" then
orientation = "vertical", install_module()
exec_man.selector, end
exec_man.stack, end
}, )
nil,-- view_enter exec_man.event_registered = true
nil -- view_leave end
) end

File diff suppressed because it is too large Load Diff