Compare commits
318 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
62e932990e | ||
|
|
980fe3962c | ||
|
|
0043769946 | ||
|
|
0cb9a8872e | ||
|
|
5309ff1726 | ||
|
|
c6eee15d75 | ||
|
|
8c2d0ddf2e | ||
|
|
87d18549a6 | ||
|
|
6fdd78114f | ||
|
|
f20721373a | ||
|
|
9c0f8d63e6 | ||
|
|
ea2596ae13 | ||
|
|
a9191cf084 | ||
|
|
59b5039579 | ||
|
|
e070a1462c | ||
|
|
faa3302a37 | ||
|
|
115dbbec32 | ||
|
|
9bf7efe71f | ||
|
|
3ec9dc4963 | ||
|
|
cddb86ded0 | ||
|
|
2624338100 | ||
|
|
067fe29f76 | ||
|
|
926272b1cd | ||
|
|
363524fbaf | ||
|
|
edeceb268e | ||
|
|
252cbc96f2 | ||
|
|
96457bc598 | ||
|
|
cd31d18075 | ||
|
|
4e140f10d1 | ||
|
|
593f8049a0 | ||
|
|
89973b3f9a | ||
|
|
deca366ce4 | ||
|
|
914a17fb4e | ||
|
|
1e33ea4192 | ||
|
|
9f3fb16161 | ||
|
|
3f064783b7 | ||
|
|
0ab4b0cd6d | ||
|
|
e2f5c993b8 | ||
|
|
3def8b43d9 | ||
|
|
7b2942ca29 | ||
|
|
bfed38f1db | ||
|
|
6d16a8778b | ||
|
|
3c67c0c693 | ||
|
|
1ba488d073 | ||
|
|
3bdbfd12bf | ||
|
|
77c405882d | ||
|
|
ecc3fb29f5 | ||
|
|
a09140c03c | ||
|
|
95e2e4924e | ||
|
|
72ce0b0f93 | ||
|
|
e4da226661 | ||
|
|
a3404b64de | ||
|
|
13ae486ab3 | ||
|
|
268aa7df42 | ||
|
|
ea7ac8e474 | ||
|
|
2a4452cd20 | ||
|
|
749db97dd5 | ||
|
|
84a1c1ddfe | ||
|
|
3791b47914 | ||
|
|
f6a1d1c20b | ||
|
|
118bbad5cb | ||
|
|
44e442e7eb | ||
|
|
08726427aa | ||
|
|
39f63cc8c5 | ||
|
|
99c3548950 | ||
|
|
7e8340c526 | ||
|
|
2e95c4837b | ||
|
|
fe6d262d9b | ||
|
|
794b12305c | ||
|
|
1a3a7f17ff | ||
|
|
496f8e704d | ||
|
|
28f87566e1 | ||
|
|
865d29fb40 | ||
|
|
1986f4e148 | ||
|
|
b963eaa38c | ||
|
|
3b520d6291 | ||
|
|
87ca8bde27 | ||
|
|
d27df0c0ed | ||
|
|
9bceb79a15 | ||
|
|
ed9f2bb0d0 | ||
|
|
b5c93e55d1 | ||
|
|
9bfda93b51 | ||
|
|
daa0877b4c | ||
|
|
da275c2a66 | ||
|
|
3fa913d68a | ||
|
|
e4e194b0ec | ||
|
|
c70ebf4297 | ||
|
|
7e3c6471ff | ||
|
|
a39f6feba7 | ||
|
|
ee7e92019a | ||
|
|
96b7ba24bc | ||
|
|
8581af29d2 | ||
|
|
ab532a724c | ||
|
|
b1e6bb8daa | ||
|
|
26e797d5e5 | ||
|
|
3941c7ab52 | ||
|
|
b7c8759af3 | ||
|
|
c5711880d3 | ||
|
|
e7dbd6e369 | ||
|
|
1b5cb1ae6e | ||
|
|
2953cf7e91 | ||
|
|
5e4ba9da5e | ||
|
|
3a1f6bbc7a | ||
|
|
21ec2883fe | ||
|
|
a0af01884d | ||
|
|
8e129d3825 | ||
|
|
d123634679 | ||
|
|
13f210bec9 | ||
|
|
8e4767c42a | ||
|
|
300bb9d443 | ||
|
|
4f8df88fec | ||
|
|
44da339202 | ||
|
|
0e37a287ca | ||
|
|
2af2530e45 | ||
|
|
99eb595f4c | ||
|
|
31cdd3f24a | ||
|
|
631d89e581 | ||
|
|
526e97a4e1 | ||
|
|
a835ab89bc | ||
|
|
da7674ca51 | ||
|
|
0e535b850c | ||
|
|
64840089e9 | ||
|
|
d754e37cf4 | ||
|
|
f6cb8091e7 | ||
|
|
e359567620 | ||
|
|
36a6a54364 | ||
|
|
ecff920537 | ||
|
|
842f2fca66 | ||
|
|
ee9384b9a7 | ||
|
|
272c35499a | ||
|
|
4165d46b33 | ||
|
|
5bed7c914c | ||
|
|
684178b27e | ||
|
|
a72abe0ad0 | ||
|
|
8863f6ade7 | ||
|
|
e0463eba83 | ||
|
|
3a2ff7a7b9 | ||
|
|
ce7ddfa472 | ||
|
|
3fb00586c3 | ||
|
|
167620fadf | ||
|
|
f0bdc890c1 | ||
|
|
abdfc9de0b | ||
|
|
c65e070a76 | ||
|
|
05c57c0247 | ||
|
|
5be3d6986e | ||
|
|
f0e3627800 | ||
|
|
ea08557a0e | ||
|
|
ac43afd8c9 | ||
|
|
ee98f96a4f | ||
|
|
a33eeddbd6 | ||
|
|
746c6a07c4 | ||
|
|
96fee48ef2 | ||
|
|
6c686128d2 | ||
|
|
6ca8f0034e | ||
|
|
3d1f12fe44 | ||
|
|
a079860cd8 | ||
|
|
b07c680332 | ||
|
|
200fc059c0 | ||
|
|
aeb1f2226c | ||
|
|
46e729b40e | ||
|
|
66b613dc29 | ||
|
|
535ba78a06 | ||
|
|
cc11c1c3b8 | ||
|
|
fba639e98a | ||
|
|
3e37c06b84 | ||
|
|
1b272be5f5 | ||
|
|
9f423eeef3 | ||
|
|
dc81c0b1c5 | ||
|
|
e8a99c8396 | ||
|
|
7c93868bf0 | ||
|
|
36023d8d4f | ||
|
|
97aa4ce363 | ||
|
|
316a89d6a8 | ||
|
|
d4a479b025 | ||
|
|
dd22c947c6 | ||
|
|
09f47b7b09 | ||
|
|
ba94914c0e | ||
|
|
3bb4e9c59a | ||
|
|
f8c076f308 | ||
|
|
94f41db6fc | ||
|
|
5727b2d251 | ||
|
|
c95f8a23b2 | ||
|
|
88e4ac1a64 | ||
|
|
a3fe02bf95 | ||
|
|
ff20098175 | ||
|
|
cdf4b743dd | ||
|
|
3efc1805ca | ||
|
|
0b46cf8abf | ||
|
|
28622e620e | ||
|
|
f21a117d29 | ||
|
|
35cbff03dd | ||
|
|
5571e2f2dc | ||
|
|
3c77f2e863 | ||
|
|
4ff1111341 | ||
|
|
abfa8e9878 | ||
|
|
bbe9109fca | ||
|
|
34d5df65b2 | ||
|
|
539f25517b | ||
|
|
5b55a3116d | ||
|
|
3e032616a0 | ||
|
|
9f2dbef4f0 | ||
|
|
2abb83b485 | ||
|
|
32e966f8d9 | ||
|
|
67538a4de2 | ||
|
|
96471ae7e7 | ||
|
|
038418b89f | ||
|
|
fe48d7498c | ||
|
|
2f330ea9cc | ||
|
|
81b0f1fb48 | ||
|
|
9088bc9144 | ||
|
|
c3ce8d532d | ||
|
|
f1d8ad7fce | ||
|
|
a3b295112f | ||
|
|
c36618f5fb | ||
|
|
fecbb39347 | ||
|
|
cbe2c5329a | ||
|
|
dcbe575e9c | ||
|
|
417c165d16 | ||
|
|
232baab86b | ||
|
|
3ed4219e6c | ||
|
|
97e33672ea | ||
|
|
7b2018412a | ||
|
|
3e2afffed8 | ||
|
|
1399e8a4b4 | ||
|
|
5c3b2777f0 | ||
|
|
bf138abeb2 | ||
|
|
284c0f9714 | ||
|
|
e41029d3f4 | ||
|
|
55e68f8cd0 | ||
|
|
ac945b9843 | ||
|
|
f6916c3a15 | ||
|
|
cd3788f012 | ||
|
|
ebd2cd7bf7 | ||
|
|
52b4508e08 | ||
|
|
b1b3392b92 | ||
|
|
19fdbc14c5 | ||
|
|
63d5aad465 | ||
|
|
9d6ff85893 | ||
|
|
125af63bda | ||
|
|
ddf0c89402 | ||
|
|
3b0ff3475a | ||
|
|
401509cfe4 | ||
|
|
9c4e906033 | ||
|
|
65c22e475a | ||
|
|
a11726889d | ||
|
|
e78e718769 | ||
|
|
86ee8adbce | ||
|
|
40949b3855 | ||
|
|
06ab263e74 | ||
|
|
bccc86c70a | ||
|
|
231e9b352b | ||
|
|
e47ab34745 | ||
|
|
1fd2ca20ab | ||
|
|
05a73d8810 | ||
|
|
12640c7d29 | ||
|
|
febc3b1659 | ||
|
|
9fdd69556c | ||
|
|
4735be470a | ||
|
|
66b33d6f48 | ||
|
|
37dba718a2 | ||
|
|
c11845cbf9 | ||
|
|
f9fe33f930 | ||
|
|
3b8e802e42 | ||
|
|
f54d449316 | ||
|
|
1b0fe4d7b9 | ||
|
|
cf1dca9e1a | ||
|
|
45d54ef4e8 | ||
|
|
8bfab0325b | ||
|
|
4b99d00ab5 | ||
|
|
a5961eb066 | ||
|
|
95e19ef163 | ||
|
|
d4eb6577bf | ||
|
|
294b693905 | ||
|
|
23835edc1f | ||
|
|
5f29211f79 | ||
|
|
025f4299ea | ||
|
|
dc50d40886 | ||
|
|
867c49b1b9 | ||
|
|
13f02c95ea | ||
|
|
d55dae73f0 | ||
|
|
34b9831472 | ||
|
|
014a0fc1c9 | ||
|
|
bf17dccd69 | ||
|
|
890168d0d0 | ||
|
|
191aecacdf | ||
|
|
44ec01b136 | ||
|
|
a177da2040 | ||
|
|
c899040688 | ||
|
|
e8af665b3c | ||
|
|
875734d455 | ||
|
|
14d5a79db2 | ||
|
|
e1b2715ee9 | ||
|
|
7ecd5ca55d | ||
|
|
931e7a4d37 | ||
|
|
1792410efe | ||
|
|
8cbd9224f1 | ||
|
|
24b552d619 | ||
|
|
68ae9326bf | ||
|
|
b4626f2787 | ||
|
|
2fc8ed78e4 | ||
|
|
236b25a235 | ||
|
|
a4f6af73ec | ||
|
|
fad74d6438 | ||
|
|
3e2d4c956d | ||
|
|
cd1d623390 | ||
|
|
9e0374d597 | ||
|
|
e47672b495 | ||
|
|
1905be8577 | ||
|
|
4726821e7d | ||
|
|
7ac37ddc1a | ||
|
|
ad10542b30 | ||
|
|
5331a38f10 | ||
|
|
c9943a2065 | ||
|
|
3889742e06 | ||
|
|
6bf3706455 | ||
|
|
8e412c3eb3 | ||
|
|
3070ca0bc4 | ||
|
|
28ae2ea501 |
73
ChangeLog.md
73
ChangeLog.md
@@ -1,5 +1,78 @@
|
||||
## Changes from most recent to oldest
|
||||
|
||||
**06 Jun 2024 - wpferguson**
|
||||
* fix fujifilm_ratings running on all images
|
||||
* added string library functions to sanitize windows io.popen and os.execute functions
|
||||
* added database maintenance script
|
||||
|
||||
**05 Jun 2024 - wpferguson**
|
||||
* added fix for executable_manager not being visible on windows
|
||||
|
||||
**30 May 2024 - kkotowicz**
|
||||
* open in explorer now uses applescript on macos to open multiple files
|
||||
|
||||
**20 May 2024 - wpferguson**
|
||||
* added string variable substitution to the string library
|
||||
|
||||
**16 May 2024 - wpferguson**
|
||||
* fix crash in script_manager
|
||||
|
||||
**15 May 2024 - wpferguson**
|
||||
* added metadata to scripts (name, author, purpose, help url)
|
||||
|
||||
**06 May 2024 - christian.sueltrop**
|
||||
* added passport_guide_germany script
|
||||
|
||||
**08 Apr 2024 - wpferguson**
|
||||
* made script_manager aware of library modules in other directories besides lib
|
||||
|
||||
**29 Mar 2024 - wpferguson**
|
||||
* updated examples/gui_action to use NaN instead of nan
|
||||
|
||||
**29 Mar 2024 - dterrahe**
|
||||
* add lua action script example
|
||||
|
||||
**28 Jan 2024 - wpferguson**
|
||||
* fix script_manager crash when script existed in top level lua directory
|
||||
|
||||
**24 Jan 2024 - wpferguson**
|
||||
* don't set lib visibility unless we are in lighttable mode
|
||||
|
||||
**15 Jan 2024 - MStraeten**
|
||||
* update x-touch.lua with support for primaries slider
|
||||
|
||||
**14 Jan 2024 - wpferguson**
|
||||
* added cycle_group_leader script
|
||||
* added hif_group_leader script
|
||||
* added jpg_group_leader script
|
||||
|
||||
**28 Oct 2023 - ddittmar**
|
||||
* Added select non existing image script
|
||||
|
||||
**17 Oct 2023 - wpferguson**
|
||||
* script_manager wrap username in quotes to handle spaces in username
|
||||
|
||||
**20 Sep 2023 - wpferguson**
|
||||
* script_manager explicitly set stopped scripts to false
|
||||
|
||||
**18 Aug 2023 - wpferguson**
|
||||
* swap the position of executable_manager and script_manager due to windows gtk bug
|
||||
|
||||
**17 Jul 2023 - wpferguson**
|
||||
* update check for update instructions
|
||||
* update flatpak readme
|
||||
|
||||
**16 Jul 2023 - wpferguson**
|
||||
* added script_data.show function to contrib/gpx_export
|
||||
|
||||
**15 Jul 2023 - wpferguson**
|
||||
* script_manager updates
|
||||
* added check_max_api_version for the case where the API no longer supports the required
|
||||
functions
|
||||
|
||||
**14 Jul 2023 - spaceChRis**
|
||||
* add tooltip to filter manager
|
||||
|
||||
**25 Mar 2023 - wpferguson**
|
||||
* Added script_manager darktable shortcut integration
|
||||
* Moved filename/path/extension string functions to string library
|
||||
|
||||
148
README.md
148
README.md
@@ -15,17 +15,17 @@ These scripts are written primarily by the darktable developers and maintained b
|
||||
|
||||
Name|Standalone|OS |Purpose
|
||||
----|:--------:|:---:|-------
|
||||
[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](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](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](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/official/delete_unused_tags)|Yes|LMW|Delete tags that have no associated images
|
||||
[enfuse](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/official/enfuse)|No|L|Exposure blend several images (HDR)
|
||||
[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](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](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/official/import_filter_manager)|Yes|LMW|Manager for import filters
|
||||
[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](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](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/official/selection_to_pdf)|No|L|Generate a PDF file from the selected images
|
||||
[check_for_updates](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/official/check_for_updates)|Yes|LMW|Check for updates to darktable
|
||||
[copy_paste_metadata](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/official/copy_paste_metadata)|Yes|LMW|Copy and paste metadata, tags, ratings, and color labels between images
|
||||
[delete_long_tags](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/official/delete_long_tags)|Yes|LMW|Delete all tags longer than a specified length
|
||||
[delete_unused_tags](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/official/delete_unused_tags)|Yes|LMW|Delete tags that have no associated images
|
||||
[enfuse](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/official/enfuse)|No|L|Exposure blend several images (HDR)
|
||||
[generate_image_txt](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/official/generate_image_txt)|No|L|Generate txt sidecar files to be overlaid on zoomed images
|
||||
[image_path_in_ui](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/official/image_path_in_ui)|Yes|LMW|Plugin to display selected image path
|
||||
[import_filter_manager](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/official/import_filter_manager)|Yes|LMW|Manager for import filters
|
||||
[import_filters](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/official/import_filters)|No|LMW|Two import filters for use with import_filter_manager
|
||||
[save_selection](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/official/save_selection)|Yes|LMW|Provide save and restore from multiple selection buffers
|
||||
[selection_to_pdf](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/official/selection_to_pdf)|No|L|Generate a PDF file from the selected images
|
||||
|
||||
|
||||
### Contributed Scripts
|
||||
@@ -34,42 +34,50 @@ These scripts are contributed by users. They are meant to have an "owner", i.e.
|
||||
|
||||
Name|Standalone|OS |Purpose
|
||||
----|:--------:|:---:|-------
|
||||
[AutoGrouper](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/autogrouper)|Yes|LMW|Group images together by time
|
||||
[autostyle](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/autostyle)|Yes|LMW|Automatically apply styles on import
|
||||
[AutoGrouper](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/autogrouper)|Yes|LMW|Group images together by time
|
||||
[autostyle](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/autostyle)|Yes|LMW|Automatically apply styles on import
|
||||
change_group_leader|Yes|LMW|Change which image leads group
|
||||
[clear_GPS](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/clear_gps)|Yes|LMW|Reset GPS information for selected images
|
||||
[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](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](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/cr2hdr)|Yes|L|Process image created with Magic Lantern Dual ISO
|
||||
[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
|
||||
[exportLUT](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/exportlut)|Yes|LMW|Create a LUT from a style and export it
|
||||
[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
|
||||
[face_recognition](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/face_recognition)|No|LM|Identify and tag images using facial recognition
|
||||
[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
|
||||
[fujifilm_ratings](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/fujifilm_ratings)|No|LM|Support importing Fujifilm ratings
|
||||
[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 ...
|
||||
[geoToolbox](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/geotoolbox)|No|LMW|A toolbox of geo functions
|
||||
[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
|
||||
[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
|
||||
[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
|
||||
[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
|
||||
[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
|
||||
[image_time](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/image_time)|Yes|LMW|Adjust the EXIF image time
|
||||
[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
|
||||
[LabelsToTags](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/labelstotags)|Yes|LMW|Apply tags based on color labels and ratings
|
||||
[OpenInExplorer](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/openinexplorer)|No|LMW|Open the selected images in the system file manager
|
||||
[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
|
||||
[pdf_slideshow](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/pdf_slideshow)|No|LM|Export images to a PDF slideshow
|
||||
[photils](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/photils)|No|LM|Automatic tag suggestions for your images
|
||||
[quicktag](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/quicktag)|Yes|LMW|Create shortcuts for quickly applying tags
|
||||
[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
|
||||
[rename_images](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/rename_images)|Yes|LMW|Rename single or multiple images
|
||||
[rename-tags](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/rename-tags)|Yes|LMW|Change a tag name
|
||||
[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
|
||||
[clear_GPS](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/clear_gps)|Yes|LMW|Reset GPS information for selected images
|
||||
[CollectHelper](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/collecthelper)|Yes|LMW|Add buttons to selected images module to manipulate the collection
|
||||
color_profile_manager|Yes|LMW|Manage darktable input and output color profiles
|
||||
[copy_attach_detach_tags](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/copy_attach_detach_tags)|Yes|LMW|Copy and paste tags from/to images
|
||||
[cr2hdr](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/cr2hdr)|Yes|L|Process image created with Magic Lantern Dual ISO
|
||||
cycle_group_leader|Yes|LMW|cycle through images of a group making each the group leader in turn
|
||||
dbmaint|Yes|LMW|find and remove database entries for missing film rolls and images
|
||||
[enfuseAdvanced](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/enfuseadvanced)|No|LMW|Merge multiple images into Dynamic Range Increase (DRI) or Depth From Focus (DFF) images
|
||||
[exportLUT](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/exportlut)|Yes|LMW|Create a LUT from a style and export it
|
||||
[ext_editor](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/ext_editor)|No|LW|Export pictures to collection and edit them with up to nine user-defined external editors
|
||||
[face_recognition](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/face_recognition)|No|LM|Identify and tag images using facial recognition
|
||||
[fujifilm_dynamic_range](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/fujifilm_dynamic_range)|No|LMW|Correct fujifilm exposure based on exposure bias camera setting
|
||||
[fujifilm_ratings](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/fujifilm_ratings)|No|LM|Support importing Fujifilm ratings
|
||||
[geoJSON_export](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/geojson_export)|No|L|Create a geo JSON script with thumbnails for use in ...
|
||||
[geoToolbox](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/geotoolbox)|No|LMW|A toolbox of geo functions
|
||||
[gimp](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/gimp)|No|LMW|Open an image in GIMP for editing and return the result
|
||||
[gpx_export](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/gpx_export)|No|LMW|Export a GPX track file from selected images GPS data
|
||||
harmonic_armature|Yes|LMW|provide a harmonic armature guide
|
||||
hif_group_leader|Yes|LMW|change the group leader in a raw+heif image pair to the heif image
|
||||
[HDRMerge](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/hdrmerge)|No|LMW|Combine the selected images into an HDR DNG and return the result
|
||||
[hugin](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/hugin)|No|LMW|Combine selected images into a panorama and return the result
|
||||
[image_stack](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/image_stack)|No|LMW|Combine a stack of images to remove noise or transient objects
|
||||
[image_time](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/image_time)|Yes|LMW|Adjust the EXIF image time
|
||||
jpg_group_leader|Yes|LMW|change the group leader for a raw+jpg pair to the jpg image
|
||||
[kml_export](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/kml_export)|No|L|Export photos with a KML file for usage in Google Earth
|
||||
[LabelsToTags](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/labelstotags)|Yes|LMW|Apply tags based on color labels and ratings
|
||||
[OpenInExplorer](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/openinexplorer)|No|LMW|Open the selected images in the system file manager
|
||||
[passport_guide](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/passport_guide)|Yes|LMW|Add passport cropping guide to darkroom crop tool
|
||||
passport_guide_germany|Yes|LMW|Add passport cropping guide for German passports to darkroom crop tool
|
||||
[pdf_slideshow](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/pdf_slideshow)|No|LM|Export images to a PDF slideshow
|
||||
[photils](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/photils)|No|LM|Automatic tag suggestions for your images
|
||||
[quicktag](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/quicktag)|Yes|LMW|Create shortcuts for quickly applying tags
|
||||
[rate_group](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/rate_group)|Yes|LMW|Apply or remove a star rating from grouped images
|
||||
[rename_images](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/rename_images)|Yes|LMW|Rename single or multiple images
|
||||
[rename-tags](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/rename-tags)|Yes|LMW|Change a tag name
|
||||
[RL_out_sharp](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/rl_out_sharp)|No|LW|Output sharpening using GMic (Richardson-Lucy algorithm)
|
||||
[select_non_existing](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/select_non_existing)|Yes|LMW|Enable selection of non-existing images in the the currently worked on images
|
||||
[select_untagged](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/select_untagged)|Yes|LMW|Enable selection of untagged images
|
||||
[slideshowMusic](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/slideshowMusic)|No|L|Play music during a slideshow
|
||||
[transfer_hierarchy](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/transfer_hierarchy)|Yes|LMW|Image move/copy preserving directory hierarchy
|
||||
[video_ffmpeg](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/video_ffmpeg)|No|LMW|Export video from darktable
|
||||
|
||||
### Example Scripts
|
||||
|
||||
@@ -77,17 +85,19 @@ These scripts provide examples of how to use specific portions of the API. They
|
||||
|
||||
Name|Standalone|OS |Purpose
|
||||
----|:--------:|:---:|-------
|
||||
[api_version](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/api_version)|Yes|LMW|Print the current API version
|
||||
[darkroom_demo](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/darkroom_demo)|Yes|LMW|Demonstrate changing images in darkoom
|
||||
[gettextExample](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/gettextexample)|Yes|LM|How to use translation
|
||||
[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](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/lighttable_demo)|Yes|LMW|Demonstrate controlling lighttable mode, zoom, sorting and filtering
|
||||
[moduleExample](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/moduleexample)|Yes|LMW|How to create a lighttable module
|
||||
[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](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/panels_demo)|Yes|LMW|Demonstrate hiding and showing darktable panels
|
||||
[preferenceExamples](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/preferenceexamples)|Yes|LMW|How to use preferences in 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](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/running_os)|Yes|LMW|Print out the running operating system
|
||||
[api_version](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/examples/api_version)|Yes|LMW|Print the current API version
|
||||
[darkroom_demo](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/examples/darkroom_demo)|Yes|LMW|Demonstrate changing images in darkoom
|
||||
[gettextExample](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/examples/gettextexample)|Yes|LM|How to use translation
|
||||
gui_actions|Yes|LMW|demonstrate controlling the GUI using darktable.gui.action calls
|
||||
[hello_world](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/examples/hello_world)|Yes|LMW|Prints hello world when darktable starts
|
||||
[lighttable_demo](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/examples/lighttable_demo)|Yes|LMW|Demonstrate controlling lighttable mode, zoom, sorting and filtering
|
||||
[moduleExample](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/examples/moduleexample)|Yes|LMW|How to create a lighttable module
|
||||
[multi_os](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/examples/multi_os)|No|LMW|How to create a cross platform script that calls an external executable
|
||||
[panels_demo](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/examples/panels_demo)|Yes|LMW|Demonstrate hiding and showing darktable panels
|
||||
[preferenceExamples](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/examples/preferenceexamples)|Yes|LMW|How to use preferences in a script
|
||||
[printExamples](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/examples/printexamples)|Yes|LMW|How to use various print functions from a script
|
||||
[running_os](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/examples/running_os)|Yes|LMW|Print out the running operating system
|
||||
x-touch|Yes|LMW|demonstrate how to use an x-touch mini MIDI controller to control the darktable GUI
|
||||
|
||||
### Tools
|
||||
|
||||
@@ -95,11 +105,11 @@ Tool scripts perform functions relating to the repository, such as generating do
|
||||
|
||||
Name|Standalone|OS |Purpose
|
||||
----|:--------:|:---:|-------
|
||||
[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](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](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](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](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/tools/script_manager)|No|LMW|Manage (install, update, enable, disable) the lua scripts
|
||||
[executable_manager](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/tools/executable_manager)|Yes|LMW|Manage the external executables used by the lua scripts
|
||||
[gen_i18n_mo](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/tools/gen_i18n_mo)|No|LMW|Generate compiled translation files (.mo) from source files (.po)
|
||||
[get_lib_manpages](https://docs.darktable.org/lua/stable/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](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/tools/get_libdoc)|No|LMW|Retrieve the library documentation and output it as text
|
||||
[script_manager](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/tools/script_manager)|No|LMW|Manage (install, update, enable, disable) the lua scripts
|
||||
|
||||
### Related third-party projects
|
||||
|
||||
@@ -117,6 +127,8 @@ The following third-party projects are listed for information only. Think of thi
|
||||
* [nbremond77/darktable](https://github.com/nbremond77/darktable/tree/master/scripts)
|
||||
* [s5k6/dtscripts](https://github.com/s5k6/dtscripts)
|
||||
* [ChristianBirzer/darktable_extra_scripts](https://github.com/ChristianBirzer/darktable_extra_scripts)
|
||||
* [fjb2020/darktable-scripts](https://github.com//fjb2020/darktable-scripts)
|
||||
* [bastibe/Darktable-Film-Simulation-Panel](https://github.com/bastibe/Darktable-Film-Simulation-Panel)
|
||||
|
||||
## Download and Install
|
||||
|
||||
@@ -174,7 +186,7 @@ The recommended way to enable and disable specific scripts is using the script m
|
||||
|
||||
### Windows
|
||||
|
||||
echo "require 'tools/script_manager'" > %LOCALAPPDATA%\darktable\luarc
|
||||
echo require "tools/script_manager" > %LOCALAPPDATA%\darktable\luarc
|
||||
|
||||
### Snap
|
||||
|
||||
@@ -182,7 +194,7 @@ The recommended way to enable and disable specific scripts is using the script m
|
||||
|
||||
### Flatpak
|
||||
|
||||
echo require "tools/script_manager"' > ~/.var/app/org.darktable.Darktable/config/darktable/luarc
|
||||
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:
|
||||
|
||||
@@ -225,18 +237,18 @@ To update the script repository, open a terminal or command prompt and do the fo
|
||||
|
||||
## Documentation
|
||||
|
||||
The [Lua Scripts Manual](https://darktable-org.github.io/luadocs/lua.scripts.manual/) provides documentation
|
||||
The [Lua Scripts Manual](https://docs.darktable.org/lua/stable/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.
|
||||
|
||||
The [Lua Scripts Library API Manual](https://darktable-org.github.io/luadocs/lua.scripts.api.manual/) provides
|
||||
The [Lua Scripts Library API Manual](https://docs.darktable.org/lua/stable/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:
|
||||
[Scripting with Lua](https://darktable-org.github.io/dtdocs/lua/)
|
||||
[Scripting with Lua](https://darktable.org.github.io/dtdocs/lua/)
|
||||
|
||||
The [Lua API Manual](https://darktable-org.github.io/luadocs/lua.api.manual/) provides docuemntation of the
|
||||
The [Lua API Manual](https://docs.darktable.org/lua/stable/lua.api.manual/) provides docuemntation of the
|
||||
darktable Lua API.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
@@ -43,21 +43,27 @@ du.check_min_api_version("7.0.0", "AutoGrouper")
|
||||
|
||||
local MOD = 'autogrouper'
|
||||
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
local function _(msgid)
|
||||
return gettext(msgid)
|
||||
end
|
||||
|
||||
-- return data structure for script_manager
|
||||
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("auto group"),
|
||||
purpose = _("automatically group images by time interval"),
|
||||
author = "Kevin Ertel",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/AutoGrouper/"
|
||||
}
|
||||
|
||||
script_data.destroy = nil -- function to destory the script
|
||||
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil
|
||||
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
|
||||
|
||||
local gettext = dt.gettext
|
||||
-- Tell gettext where to find the .mo file translating messages for a particular domain
|
||||
gettext.bindtextdomain("AutoGrouper",dt.configuration.config_dir.."/lua/locale/")
|
||||
|
||||
local function _(msgid)
|
||||
return gettext.dgettext("AutoGrouper", msgid)
|
||||
end
|
||||
script_data.show = nil -- only required for libs since the destroy_method only hides them
|
||||
|
||||
local Ag = {}
|
||||
Ag.module_installed = false
|
||||
@@ -126,10 +132,11 @@ local function main(on_collection)
|
||||
for i, image in ipairs(images) do
|
||||
if i == 1 then
|
||||
prev_image = image
|
||||
image:make_group_leader()
|
||||
elseif string.match(image.exif_datetime_taken, '[%d]') ~= nil then --make sure current image has a timestamp, if so check if it is within the user specified gap value and add to group
|
||||
local curr_image = image
|
||||
if GetTimeDiff(curr_image, prev_image) <= GUI.gap.value then
|
||||
images[i]:group_with(images[i-1])
|
||||
images[i]:group_with(images[i-1].group_leader)
|
||||
end
|
||||
prev_image = curr_image
|
||||
end
|
||||
|
||||
@@ -47,31 +47,36 @@ In the "Selected Images" module click on "Collect on this Image"
|
||||
|
||||
local dt = require "darktable"
|
||||
local du = require "lib/dtutils"
|
||||
local gettext = dt.gettext
|
||||
local gettext = dt.gettext.gettext
|
||||
local previous = nil
|
||||
local all_active = false
|
||||
|
||||
-- Tell gettext where to find the .mo file translating messages for a particular domain
|
||||
gettext.bindtextdomain("CollectHelper",dt.configuration.config_dir.."/lua/locale/")
|
||||
|
||||
du.check_min_api_version("7.0.0", "CollectHelper")
|
||||
|
||||
local function _(msgid)
|
||||
return gettext(msgid)
|
||||
end
|
||||
|
||||
-- return data structure for script_manager
|
||||
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("collection helper"),
|
||||
purpose = _("add collection helper buttons"),
|
||||
author = "Kevin Ertel",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/CollectHelper/"
|
||||
}
|
||||
|
||||
script_data.destroy = nil -- function to destory the script
|
||||
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil
|
||||
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
|
||||
|
||||
local function _(msgid)
|
||||
return gettext.dgettext("CollectHelper", msgid)
|
||||
end
|
||||
script_data.show = nil -- only required for libs since the destroy_method only hides them
|
||||
|
||||
-- FUNCTION --
|
||||
local function CheckSingleImage(selection)
|
||||
if #selection ~= 1 then
|
||||
dt.print(_("Please select a single image"))
|
||||
dt.print(_("please select a single image"))
|
||||
return true
|
||||
end
|
||||
return false
|
||||
@@ -204,47 +209,47 @@ end
|
||||
dt.gui.libs.image.register_action(
|
||||
"CollectHelper_prev", _("collect: previous"),
|
||||
function() PreviousCollection() end,
|
||||
_("Sets the Collect parameters to be the previously active parameters")
|
||||
_("sets the collect parameters to be the previously active parameters")
|
||||
)
|
||||
if dt.preferences.read('module_CollectHelper','folder','bool') then
|
||||
dt.gui.libs.image.register_action(
|
||||
"CollectHelper_folder", _("collect: folder"),
|
||||
function() CollectOnFolder(_ , false) end,
|
||||
_("Sets the Collect parameters to be the selected images's folder")
|
||||
_("sets the collect parameters to be the selected images's folder")
|
||||
)
|
||||
end
|
||||
if dt.preferences.read('module_CollectHelper','colors','bool') then
|
||||
dt.gui.libs.image.register_action(
|
||||
"CollectHelper_labels", _("collect: color label(s)"),
|
||||
function() CollectOnColors(_ , false) end,
|
||||
_("Sets the Collect parameters to be the selected images's color label(s)")
|
||||
_("sets the collect parameters to be the selected images's color label(s)")
|
||||
)
|
||||
end
|
||||
if dt.preferences.read('module_CollectHelper','all_and','bool') then
|
||||
dt.gui.libs.image.register_action(
|
||||
"CollectHelper_and", _("collect: all (AND)"),
|
||||
function() CollectOnAll_AND() end,
|
||||
_("Sets the Collect parameters based on all activated CollectHelper options")
|
||||
_("sets the collect parameters based on all activated CollectHelper options")
|
||||
)
|
||||
end
|
||||
|
||||
-- PREFERENCES --
|
||||
dt.preferences.register("module_CollectHelper", "all_and", -- name
|
||||
"bool", -- type
|
||||
_('CollectHelper: All'), -- label
|
||||
_('Will create a collect parameter set that utilizes all enabled CollectHelper types (AND)'), -- tooltip
|
||||
_('CollectHelper: all'), -- label
|
||||
_('creates a collect parameter set that utilizes all enabled CollectHelper types (and)'), -- tooltip
|
||||
true -- default
|
||||
)
|
||||
dt.preferences.register("module_CollectHelper", "colors", -- name
|
||||
"bool", -- type
|
||||
_('CollectHelper: Color Label(s)'), -- label
|
||||
_('Enable the button that allows you to swap to a collection based on selected image\'s COLOR LABEL(S)'), -- tooltip
|
||||
_('CollectHelper: color label(s)'), -- label
|
||||
_('enable the button that allows you to swap to a collection based on selected image\'s color label(s)'), -- tooltip
|
||||
true -- default
|
||||
)
|
||||
dt.preferences.register("module_CollectHelper", "folder", -- name
|
||||
"bool", -- type
|
||||
_('CollectHelper: Folder'), -- label
|
||||
_('Enable the button that allows you to swap to a collection based on selected image\'s FOLDER location'), -- tooltip
|
||||
_('CollectHelper: folder'), -- label
|
||||
_('enable the button that allows you to swap to a collection based on selected image\'s folder location'), -- tooltip
|
||||
true -- default
|
||||
)
|
||||
|
||||
|
||||
@@ -51,13 +51,28 @@ local dsys = require 'lib/dtutils.system'
|
||||
|
||||
du.check_min_api_version("7.0.0", "HDRmerge")
|
||||
|
||||
-- Tell gettext where to find the .mo file translating messages for a particular domain
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
local function _(msgid)
|
||||
return gettext(msgid)
|
||||
end
|
||||
|
||||
-- return data structure for script_manager
|
||||
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("HDR merge"),
|
||||
purpose = _("merge bracketed images into an HDR DNG image"),
|
||||
author = "Kevin Ertel",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/HDRmerge"
|
||||
}
|
||||
|
||||
script_data.destroy = nil -- function to destory the script
|
||||
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil
|
||||
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
|
||||
script_data.show = nil -- only required for libs since the destroy_method only hides them
|
||||
|
||||
|
||||
local mod = 'module_HDRMerge'
|
||||
@@ -65,13 +80,6 @@ local os_path_seperator = '/'
|
||||
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
|
||||
local gettext = dt.gettext
|
||||
gettext.bindtextdomain('HDRMerge', dt.configuration.config_dir..'/lua/locale/')
|
||||
local function _(msgid)
|
||||
return gettext.dgettext('HDRMerge', msgid)
|
||||
end
|
||||
|
||||
local temp
|
||||
local HDRM = { --HDRMerge Program Table
|
||||
name = 'HDRMerge',
|
||||
@@ -207,8 +215,8 @@ end
|
||||
local function main()
|
||||
PreCall({HDRM}) --check if furst run then check if install OK
|
||||
if HDRM.install_error then
|
||||
dt.print_error(_('HDRMerge install issue'))
|
||||
dt.print(_('HDRMerge install issue, please ensure the binary path is proper'))
|
||||
dt.print_error('HDRMerge install issue')
|
||||
dt.print(_('HDRMerge install issue, please ensure the binary path is correct'))
|
||||
return
|
||||
end
|
||||
images = dt.gui.selection() --get selected images
|
||||
@@ -276,7 +284,7 @@ local function main()
|
||||
end
|
||||
dt.print(_('HDRMerge completed successfully'))
|
||||
else
|
||||
dt.print_error(_('HDRMerge failed'))
|
||||
dt.print_error('HDRMerge failed')
|
||||
dt.print(_('HDRMerge failed'))
|
||||
end
|
||||
|
||||
@@ -377,7 +385,7 @@ local lbl_import = dt.new_widget('section_label'){
|
||||
}
|
||||
GUI.Target.style = dt.new_widget('combobox'){
|
||||
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,
|
||||
_('none'),
|
||||
changed_callback = function(self)
|
||||
@@ -406,18 +414,18 @@ GUI.Target.copy_tags = dt.new_widget('check_button'){
|
||||
temp = dt.preferences.read(mod, 'active_add_tags', 'string')
|
||||
if temp == '' then temp = nil end
|
||||
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, separate with commas, all spaces will be removed'),
|
||||
text = temp,
|
||||
placeholder = _('Enter tags, seperated by commas'),
|
||||
placeholder = _('enter tags, separated by commas'),
|
||||
editable = true
|
||||
}
|
||||
GUI.run = dt.new_widget('button'){
|
||||
label = _('merge'),
|
||||
tooltip =_('run HDRMerge with the above specified settings'),
|
||||
tooltip =_('run HDRMerge with the above settings'),
|
||||
clicked_callback = function() main() end
|
||||
}
|
||||
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),
|
||||
is_directory = false
|
||||
}
|
||||
|
||||
@@ -52,13 +52,27 @@ local du = require "lib/dtutils"
|
||||
|
||||
du.check_min_api_version("7.0.0", "LabelsToTags")
|
||||
|
||||
local gettext = darktable.gettext.gettext
|
||||
|
||||
local function _(msgid)
|
||||
return gettext(msgid)
|
||||
end
|
||||
|
||||
-- return data structure for script_manager
|
||||
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("labels to tags"),
|
||||
purpose = _("allows the mass-application of tags using color labels and ratings as a guide"),
|
||||
author = "August Schwerdfeger (august@schwerdfeger.name)",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/LabelsToTags"
|
||||
}
|
||||
|
||||
script_data.destroy = nil -- function to destory the script
|
||||
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil
|
||||
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
|
||||
script_data.show = nil -- only required for libs since the destroy_method only hides them
|
||||
|
||||
-- Lua 5.3 no longer has "unpack" but "table.unpack"
|
||||
unpack = unpack or table.unpack
|
||||
@@ -67,7 +81,7 @@ local ltt = {}
|
||||
ltt.module_installed = false
|
||||
ltt.event_registered = false
|
||||
|
||||
local LIB_ID = "LabelsToTags"
|
||||
local LIB_ID = _("LabelsToTags")
|
||||
|
||||
-- Helper functions: BEGIN
|
||||
|
||||
@@ -108,23 +122,23 @@ end
|
||||
|
||||
|
||||
local initialAvailableMappings = {
|
||||
["Colors"] = { ["+*****"] = { "Red" },
|
||||
["*+****"] = { "Yellow" },
|
||||
["**+***"] = { "Green" },
|
||||
["***+**"] = { "Blue" },
|
||||
["****+*"] = { "Purple" } },
|
||||
["Single colors"] = { ["+----*"] = { "Red", "Only red" },
|
||||
["-+---*"] = { "Yellow", "Only yellow" },
|
||||
["--+--*"] = { "Green", "Only green" },
|
||||
["---+-*"] = { "Blue", "Only blue" },
|
||||
["----+*"] = { "Purple", "Only purple" } },
|
||||
["Ratings"] = { ["*****0"] = { "No stars", "Not rejected" },
|
||||
["*****1"] = { "One star", "Not rejected" },
|
||||
["*****2"] = { "Two stars", "Not rejected" },
|
||||
["*****3"] = { "Three stars", "Not rejected" },
|
||||
["*****4"] = { "Four stars", "Not rejected" },
|
||||
["*****5"] = { "Five stars", "Not rejected" },
|
||||
["*****R"] = { "Rejected" } }
|
||||
[_("colors")] = { ["+*****"] = { _("red") },
|
||||
["*+****"] = { _("yellow") },
|
||||
["**+***"] = { _("green") },
|
||||
["***+**"] = { _("blue") },
|
||||
["****+*"] = { _("purple") } },
|
||||
[_("single colors")] = { ["+----*"] = { _("red"), _("only red") },
|
||||
["-+---*"] = { _("yellow"), _("only yellow") },
|
||||
["--+--*"] = { _("green"), _("only green") },
|
||||
["---+-*"] = { _("blue"), _("only blue") },
|
||||
["----+*"] = { _("purple"), _("only purple") } },
|
||||
[_("ratings")] = { ["*****0"] = { _("no stars"), _("not rejected") },
|
||||
["*****1"] = { _("one star"), _("not rejected") },
|
||||
["*****2"] = { _("two stars"), _("not rejected") },
|
||||
["*****3"] = { _("three stars"), _("not rejected") },
|
||||
["*****4"] = { _("four stars"), _("not rejected") },
|
||||
["*****5"] = { _("five stars"), _("not rejected") },
|
||||
["*****R"] = { _("rejected") } }
|
||||
}
|
||||
|
||||
local availableMappings = {}
|
||||
@@ -139,14 +153,14 @@ end
|
||||
|
||||
local function getComboboxTooltip()
|
||||
if availableMappings == nil or next(availableMappings) == nil then
|
||||
return("No registered mappings -- using defaults")
|
||||
return(_("no registered mappings -- using defaults"))
|
||||
else
|
||||
return("Select a label-to-tag mapping")
|
||||
return(_("select a label-to-tag mapping"))
|
||||
end
|
||||
end
|
||||
|
||||
local mappingComboBox = darktable.new_widget("combobox"){
|
||||
label = "mapping",
|
||||
label = _("mapping"),
|
||||
value = 1,
|
||||
tooltip = getComboboxTooltip(),
|
||||
reset_callback = function(selfC)
|
||||
@@ -169,7 +183,7 @@ local mappingComboBox = darktable.new_widget("combobox"){
|
||||
}
|
||||
|
||||
local function doTagging(selfC)
|
||||
local job = darktable.gui.create_job(string.format("labels to tags (%d image" .. (#(darktable.gui.action_images) == 1 and "" or "s") .. ")",#(darktable.gui.action_images)),true)
|
||||
local job = darktable.gui.create_job(string.format(_("labels to tags (%d image%s)"), #(darktable.gui.action_images), (#(darktable.gui.action_images) == 1 and "" or "s")), true)
|
||||
job.percent = 0.0
|
||||
local pctIncrement = 1.0 / #(darktable.gui.action_images)
|
||||
|
||||
@@ -200,8 +214,8 @@ ltt.my_widget = darktable.new_widget("box") {
|
||||
orientation = "vertical",
|
||||
mappingComboBox,
|
||||
darktable.new_widget("button") {
|
||||
label = "start",
|
||||
tooltip = "Tag all selected images",
|
||||
label = _("start"),
|
||||
tooltip = _("tag all selected images"),
|
||||
clicked_callback = doTagging
|
||||
}
|
||||
}
|
||||
@@ -231,7 +245,7 @@ end
|
||||
|
||||
local function install_module()
|
||||
if not ltt.module_installed then
|
||||
darktable.register_lib(LIB_ID,"labels to tags",true,true,{
|
||||
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
|
||||
|
||||
@@ -51,32 +51,37 @@ local dt = require "darktable"
|
||||
local du = require "lib/dtutils"
|
||||
local df = require "lib/dtutils.file"
|
||||
local dsys = require "lib/dtutils.system"
|
||||
local gettext = dt.gettext
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
--Check API version
|
||||
du.check_min_api_version("7.0.0", "OpenInExplorer")
|
||||
|
||||
local function _(msgid)
|
||||
return gettext(msgid)
|
||||
end
|
||||
|
||||
-- return data structure for script_manager
|
||||
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("open in explorer"),
|
||||
purpose = _("open a selected file in the system file manager"),
|
||||
author = "Kevin Ertel",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/OpenInExplorer"
|
||||
}
|
||||
|
||||
script_data.destroy = nil -- function to destory the script
|
||||
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil
|
||||
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
|
||||
|
||||
-- Tell gettext where to find the .mo file translating messages for a particular domain
|
||||
gettext.bindtextdomain("OpenInExplorer",dt.configuration.config_dir.."/lua/locale/")
|
||||
|
||||
local function _(msgid)
|
||||
return gettext.dgettext("OpenInExplorer", msgid)
|
||||
end
|
||||
script_data.show = nil -- only required for libs since the destroy_method only hides them
|
||||
|
||||
local act_os = dt.configuration.running_os
|
||||
local PS = act_os == "windows" and "\\" or "/"
|
||||
|
||||
--Detect OS and quit if it is not supported.
|
||||
if act_os ~= "macos" and act_os ~= "windows" and act_os ~= "linux" then
|
||||
dt.print(_("OpenInExplorer plug-in only supports Linux, macOS, and Windows at this time"))
|
||||
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")
|
||||
return
|
||||
end
|
||||
@@ -92,11 +97,11 @@ local function check_if_links_dir_exists()
|
||||
local dir_exists = true
|
||||
if not links_dir then
|
||||
--Just for paranoic reasons. I tried, but I couldn't devise a setting for a nil value.
|
||||
dt.print(_("No links directory selected.\nPlease check the dt preferences (lua options)"))
|
||||
dt.print(_("no links directory selected\nplease check the dt preferences (lua options)"))
|
||||
dt.print_error("OpenInExplorer: No links directory selected")
|
||||
dir_exists = false
|
||||
elseif not df.check_if_file_exists(links_dir) then
|
||||
dt.print(string.format(_("Links directory '%s' not found.\nPlease check the dt preferences (lua options)"), links_dir))
|
||||
dt.print(string.format(_("links directory '%s' not found\nplease check the dt preferences (lua options)"), links_dir))
|
||||
dt.print_error(string.format("OpenInExplorer: Links directory '%s' not found", links_dir))
|
||||
dir_exists = false
|
||||
end
|
||||
@@ -111,9 +116,26 @@ open_dir.linux = [[busctl --user call org.freedesktop.FileManager1 /org/freedesk
|
||||
|
||||
local open_files = {}
|
||||
open_files.windows = "explorer.exe /select, %s"
|
||||
open_files.macos = "open -Rn %s"
|
||||
open_files.macos = "osascript -e 'tell application \"Finder\" to (reveal {%s}) activate'"
|
||||
open_files.linux = [[busctl --user call org.freedesktop.FileManager1 /org/freedesktop/FileManager1 org.freedesktop.FileManager1 ShowItems ass %d %s ""]]
|
||||
|
||||
reveal_file_osx_cmd = "\"%s\" as POSIX file"
|
||||
|
||||
--Call the osx Finder with each selected image selected.
|
||||
--For images in multiple folders, Finder will open a separate window for each
|
||||
local function call_list_of_files_osx(selected_images)
|
||||
local cmds = {}
|
||||
for _, image in pairs(selected_images) do
|
||||
current_image = image.path..PS..image.filename
|
||||
-- AppleScript needs double quoted strings, and the whole command is wrapped in single quotes.
|
||||
table.insert(cmds, string.format(reveal_file_osx_cmd, string.gsub(string.gsub(current_image, "\"", "\\\""), "'", "'\"'\"'")))
|
||||
end
|
||||
reveal_cmd = table.concat(cmds, ",")
|
||||
run_cmd = string.format(open_files.macos, reveal_cmd)
|
||||
dt.print_log("OSX run_cmd = "..run_cmd)
|
||||
dsys.external_command(run_cmd)
|
||||
end
|
||||
|
||||
--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)
|
||||
@@ -153,7 +175,7 @@ local function set_links(selected_images)
|
||||
end
|
||||
]]
|
||||
if dsys.external_command(run_cmd) ~= 0 then
|
||||
dt.print(_("Failed to create links. Missing rights?"))
|
||||
dt.print(_("failed to create links, missing rights?"))
|
||||
dt.print_error("OpenInExplorer: Failed to create links")
|
||||
return
|
||||
end
|
||||
@@ -169,18 +191,20 @@ end
|
||||
local function open_in_fmanager()
|
||||
local images = dt.gui.selection()
|
||||
if #images == 0 then
|
||||
dt.print(_("Please select an image"))
|
||||
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)"))
|
||||
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)
|
||||
elseif act_os == "macos" then
|
||||
call_list_of_files_osx(images)
|
||||
else
|
||||
call_file_by_file(images)
|
||||
end
|
||||
@@ -202,7 +226,7 @@ end
|
||||
dt.gui.libs.image.register_action(
|
||||
"OpenInExplorer", _("show in file explorer"),
|
||||
function() open_in_fmanager() end,
|
||||
_("Open the file manager at the selected image's location")
|
||||
_("open the file manager at the selected image's location")
|
||||
)
|
||||
|
||||
|
||||
@@ -210,17 +234,17 @@ 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
|
||||
_("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"),
|
||||
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
|
||||
_("use links instead of multiple windows, requires restart to take effect"), -- tooltip
|
||||
false, -- default
|
||||
""
|
||||
)
|
||||
|
||||
@@ -65,31 +65,50 @@ local MODULE_NAME = "RL_out_sharp"
|
||||
-- check API version
|
||||
du.check_min_api_version("7.0.0", MODULE_NAME)
|
||||
|
||||
-- translation
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
local function _(msgid)
|
||||
return gettext(msgid)
|
||||
end
|
||||
|
||||
-- return data structure for script_manager
|
||||
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("RL output sharpening"),
|
||||
purpose = _("Richardson-Lucy output sharpening using GMic"),
|
||||
author = "Marco Carrarini <marco.carrarini@gmail.com>",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/RL_out_sharp"
|
||||
}
|
||||
|
||||
script_data.destroy = nil -- function to destory the script
|
||||
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil
|
||||
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
|
||||
script_data.show = nil -- only required for libs since the destroy_method only hides them
|
||||
|
||||
-- OS compatibility
|
||||
local PS = dt.configuration.running_os == "windows" and "\\" or "/"
|
||||
|
||||
-- translation
|
||||
local gettext = dt.gettext
|
||||
gettext.bindtextdomain(MODULE_NAME, dt.configuration.config_dir..PS.."lua"..PS.."locale"..PS)
|
||||
local function _(msgid)
|
||||
return gettext.dgettext(MODULE_NAME, msgid)
|
||||
end
|
||||
|
||||
-- initialize module preferences
|
||||
if not dt.preferences.read(MODULE_NAME, "initialized", "bool") then
|
||||
dt.preferences.write(MODULE_NAME, "sigma", "string", "0.7")
|
||||
dt.preferences.write(MODULE_NAME, "iterations", "string", "10")
|
||||
dt.preferences.write(MODULE_NAME, "jpg_quality", "string", "95")
|
||||
dt.preferences.write(MODULE_NAME, "initialized", "bool", true)
|
||||
end
|
||||
|
||||
-- preserve original image metadata in the output image -----------------------
|
||||
local function preserve_metadata(original, sharpened)
|
||||
local exiftool = df.check_if_bin_exists("exiftool")
|
||||
|
||||
if exiftool then
|
||||
dtsys.external_command("exiftool -overwrite_original_in_place -tagsFromFile " .. original .. " " .. sharpened)
|
||||
else
|
||||
dt.print_log(MODULE .. " exiftool not found, metadata not preserved")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- setup export ---------------------------------------------------------------
|
||||
@@ -136,7 +155,7 @@ local function export2RL(storage, image_table, extra_data)
|
||||
for image, temp_name in pairs(image_table) do
|
||||
|
||||
i = i + 1
|
||||
dt.print(_("sharpening image ")..i.." ...")
|
||||
dt.print(string.format(_("sharpening image %d ..."), i))
|
||||
-- create unique filename
|
||||
new_name = output_folder..PS..df.get_basename(temp_name)..".jpg"
|
||||
new_name = df.create_unique_filename(new_name)
|
||||
@@ -155,6 +174,9 @@ local function export2RL(storage, image_table, extra_data)
|
||||
return
|
||||
end
|
||||
|
||||
-- copy metadata from input_file to output_file
|
||||
preserve_metadata(input_file, output_file)
|
||||
|
||||
-- delete temp image
|
||||
os.remove(temp_name)
|
||||
|
||||
|
||||
132
contrib/auto_snapshot.lua
Normal file
132
contrib/auto_snapshot.lua
Normal file
@@ -0,0 +1,132 @@
|
||||
--[[
|
||||
|
||||
auto_snapshot.lua - automatically take a snapshot when an image is loaded in darkroom
|
||||
|
||||
Copyright (C) 2024 Bill Ferguson <wpferguson@gamil.com>.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
]]
|
||||
--[[
|
||||
auto_snapshot -
|
||||
|
||||
automatically take a snapshot when an image is loaded in darkroom
|
||||
|
||||
ADDITIONAL SOFTWARE NEEDED FOR THIS SCRIPT
|
||||
None
|
||||
|
||||
USAGE
|
||||
* start the script from script_manager
|
||||
* open an image in darkroom
|
||||
|
||||
BUGS, COMMENTS, SUGGESTIONS
|
||||
Bill Ferguson <wpferguson@gamil.com>
|
||||
|
||||
CHANGES
|
||||
]]
|
||||
|
||||
local dt = require "darktable"
|
||||
local du = require "lib/dtutils"
|
||||
local log = require "lib/dtutils.log"
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- C O N S T A N T S
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
local MODULE <const> = "auto_snapshot"
|
||||
local DEFAULT_LOG_LEVEL <const> = log.error
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- A P I C H E C K
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
du.check_min_api_version("7.0.0", MODULE) -- choose the minimum version that contains the features you need
|
||||
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- I 1 8 N
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
local function _(msgid)
|
||||
return gettext(msgid)
|
||||
end
|
||||
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- S C R I P T M A N A G E R I N T E G R A T I O N
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
local script_data = {}
|
||||
|
||||
script_data.destroy = nil -- function to destory the script
|
||||
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet
|
||||
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
|
||||
script_data.show = nil -- only required for libs since the destroy_method only hides them
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("auto snapshot"), -- name of script
|
||||
purpose = _("automatically take a snapshot when an image is loaded in darkroom"), -- purpose of script
|
||||
author = "Bill Ferguson <wpferguson@gamil.com>", -- your name and optionally e-mail address
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/auto_snapshot/" -- URL to help/documentation
|
||||
}
|
||||
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- L O G L E V E L
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
log.log_level(DEFAULT_LOG_LEVEL)
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- N A M E S P A C E
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
local auto_snapshot = {}
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- P R E F E R E N C E S
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
dt.preferences.register(MODULE, "always_create_snapshot", "bool", "auto_snapshot - " .. _("always automatically create_snapshot"),
|
||||
_("create a snapshot even if the image is altered"), false)
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- D A R K T A B L E I N T E G R A T I O N
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
local function destroy()
|
||||
dt.destroy_event(MODULE, "darkroom-image-loaded")
|
||||
end
|
||||
|
||||
script_data.destroy = destroy
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- E V E N T S
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
dt.register_event(MODULE, "darkroom-image-loaded",
|
||||
function(event, clean, image)
|
||||
local always = dt.preferences.read(MODULE, "always_create_snapshot", "bool")
|
||||
if clean and always then
|
||||
dt.gui.libs.snapshots.take_snapshot()
|
||||
elseif clean and not image.is_altered then
|
||||
dt.gui.libs.snapshots.take_snapshot()
|
||||
end
|
||||
|
||||
end
|
||||
)
|
||||
|
||||
|
||||
return script_data
|
||||
@@ -39,16 +39,33 @@ GPLv2
|
||||
local darktable = require "darktable"
|
||||
local du = require "lib/dtutils"
|
||||
local filelib = require "lib/dtutils.file"
|
||||
local syslib = require "lib/dtutils.system"
|
||||
|
||||
du.check_min_api_version("7.0.0", "autostyle")
|
||||
|
||||
local gettext = darktable.gettext.gettext
|
||||
|
||||
local function _(msgid)
|
||||
return gettext(msgid)
|
||||
end
|
||||
|
||||
-- return data structure for script_manager
|
||||
|
||||
local script_data = {}
|
||||
|
||||
local have_not_printed_config_message = true
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("auto style"),
|
||||
purpose = _("automatically apply a style based on image EXIF tag"),
|
||||
author = "Marc Cousin <cousinmarc@gmail.com>",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/autostyle/"
|
||||
}
|
||||
|
||||
script_data.destroy = nil -- function to destory the script
|
||||
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil
|
||||
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
|
||||
script_data.show = nil -- only required for libs since the destroy_method only hides them
|
||||
|
||||
-- run command and retrieve stdout
|
||||
local function get_stdout(cmd)
|
||||
@@ -86,24 +103,26 @@ end
|
||||
local function autostyle_apply_one_image (image)
|
||||
|
||||
local pref = darktable.preferences.read("autostyle", "exif_tag", "string")
|
||||
|
||||
if pref and string.len(pref) >= 6 then
|
||||
-- We need the tag, the value and the style_name provided from the configuration string
|
||||
local tag, value, style_name = string.match(pref, "(%g+)%s*=%s*(%g+)%s*=>%s*(%g+)")
|
||||
local tag, value, style_name = string.match(pref, "(%g+)%s*=%s*([%g ]-)%s*=>%s*(%g+)")
|
||||
|
||||
-- check they all exist (correct syntax)
|
||||
if (not tag) then
|
||||
darktable.print("EXIF TAG not found in " .. pref)
|
||||
darktable.print(string.format(_("EXIF tag not found in %s"), pref))
|
||||
return 0
|
||||
end
|
||||
if (not value) then
|
||||
darktable.print("value to match not found in " .. pref)
|
||||
darktable.print(string.format(_("value to match not found in %s"), pref))
|
||||
return 0
|
||||
end
|
||||
if (not style_name) then
|
||||
darktable.print("style name not found in " .. pref)
|
||||
darktable.print(string.format(_("style name not found in %s"), pref))
|
||||
return 0
|
||||
end
|
||||
if not filelib.check_if_bin_exists("exiftool") then
|
||||
darktable.print("Can't find exiftool")
|
||||
darktable.print(_("can't find exiftool"))
|
||||
return 0
|
||||
end
|
||||
|
||||
@@ -117,7 +136,7 @@ local function autostyle_apply_one_image (image)
|
||||
end
|
||||
end
|
||||
if (not style) then
|
||||
darktable.print("style not found for autostyle: " .. style_name)
|
||||
darktable.print(string.format(_("style not found for autostyle: %s"), style_name))
|
||||
return 0
|
||||
end
|
||||
|
||||
@@ -126,7 +145,7 @@ local function autostyle_apply_one_image (image)
|
||||
--darktable.print_error("dr_attr:" .. auto_dr_attr)
|
||||
-- If the lookup fails, stop here
|
||||
if (not ok) then
|
||||
darktable.print("Couldn't get attribute " .. auto_dr_attr .. " from exiftool's output")
|
||||
darktable.print(string.format(_("couldn't get attribute %s from exiftool's output"), auto_dr_attr))
|
||||
return 0
|
||||
end
|
||||
if auto_dr_attr == value then
|
||||
@@ -137,6 +156,10 @@ local function autostyle_apply_one_image (image)
|
||||
darktable.print_log("Image " .. image.filename .. ": autostyle not applied, exif tag " .. pref .. " not matched: " .. auto_dr_attr)
|
||||
return 0
|
||||
end
|
||||
elseif have_not_printed_config_message then
|
||||
have_not_printed_config_message = false
|
||||
darktable.print(string.format(_("%s is not configured, please configure the preference in Lua options"), script_data.metadata.name))
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -153,7 +176,7 @@ local function autostyle_apply(shortcut)
|
||||
images_submitted = images_submitted + 1
|
||||
images_processed = images_processed + autostyle_apply_one_image(image)
|
||||
end
|
||||
darktable.print("Applied auto style to " .. images_processed .. " out of " .. images_submitted .. " image(s)")
|
||||
darktable.print(string.format(_("applied auto style to %d out of %d image(s)"), images_processed, images_submitted))
|
||||
end
|
||||
|
||||
local function destroy()
|
||||
@@ -163,9 +186,11 @@ end
|
||||
|
||||
-- Registering events
|
||||
darktable.register_event("autostyle", "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",
|
||||
string.format("%s: EXIF_tag=value=>style", script_data.metadata.name),
|
||||
_("apply a style automatically if an EXIF tag matches value, find the tag with exiftool"), "")
|
||||
|
||||
darktable.register_event("autostyle", "post-import-image",
|
||||
autostyle_apply_one_image_event)
|
||||
|
||||
@@ -36,29 +36,34 @@ USAGE
|
||||
local dt = require "darktable"
|
||||
local du = require "lib/dtutils"
|
||||
|
||||
local gettext = dt.gettext
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
local MODULE = "change_group_leader"
|
||||
|
||||
du.check_min_api_version("3.0.0", MODULE)
|
||||
|
||||
local function _(msgid)
|
||||
return gettext(msgid)
|
||||
end
|
||||
|
||||
-- return data structure for script_manager
|
||||
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("change group leader"),
|
||||
purpose = _("automatically change the leader of raw+jpg paired image groups"),
|
||||
author = "Bill Ferguson <wpferguson@gmail.com>",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/change_group_leader"
|
||||
}
|
||||
|
||||
script_data.destroy = nil -- function to destory the script
|
||||
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil
|
||||
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
|
||||
|
||||
-- Tell gettext where to find the .mo file translating messages for a particular domain
|
||||
gettext.bindtextdomain(MODULE, dt.configuration.config_dir.."/lua/locale/")
|
||||
|
||||
local function _(msgid)
|
||||
return gettext.dgettext(MODULE, msgid)
|
||||
end
|
||||
script_data.show = nil -- only required for libs since the destroy_method only hides them
|
||||
|
||||
-- create a namespace to contain persistent data and widgets
|
||||
chg_grp_ldr = {}
|
||||
local chg_grp_ldr = {}
|
||||
|
||||
local cgl = chg_grp_ldr
|
||||
|
||||
@@ -75,7 +80,7 @@ local function install_module()
|
||||
if not cgl.module_installed then
|
||||
dt.register_lib(
|
||||
MODULE, -- Module name
|
||||
_("change_group_leader"), -- Visible name
|
||||
_("change group leader"), -- Visible name
|
||||
true, -- expandable
|
||||
false, -- resetable
|
||||
{[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 700}}, -- containers
|
||||
@@ -120,7 +125,7 @@ end
|
||||
|
||||
local function process_image_groups(images)
|
||||
if #images < 1 then
|
||||
dt.print(_("No images selected."))
|
||||
dt.print(_("no images selected"))
|
||||
dt.print_log(MODULE .. "no images seletected, returning...")
|
||||
else
|
||||
local mode = cgl.widgets.mode.value
|
||||
@@ -160,7 +165,7 @@ cgl.widgets.mode = dt.new_widget("combobox"){
|
||||
}
|
||||
|
||||
cgl.widgets.execute = dt.new_widget("button"){
|
||||
label = _("Execute"),
|
||||
label = _("execute"),
|
||||
clicked_callback = function()
|
||||
process_image_groups(dt.gui.action_images)
|
||||
end
|
||||
|
||||
@@ -39,28 +39,33 @@
|
||||
local dt = require "darktable"
|
||||
local du = require "lib/dtutils"
|
||||
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
local function _(msgid)
|
||||
return gettext(msgid)
|
||||
end
|
||||
|
||||
-- return data structure for script_manager
|
||||
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("clear GPS info"),
|
||||
purpose = _("remove GPS data from selected image(s)"),
|
||||
author = "Bill Ferguson <wpferguson@gmail.com>",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/clear_gps/"
|
||||
}
|
||||
|
||||
script_data.destroy = nil -- function to destory the script
|
||||
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet
|
||||
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
|
||||
|
||||
local gettext = dt.gettext
|
||||
script_data.show = nil -- only required for libs since the destroy_method only hides them
|
||||
|
||||
-- not a number
|
||||
local NaN = 0/0
|
||||
|
||||
du.check_min_api_version("7.0.0", "clear_GPS")
|
||||
|
||||
-- Tell gettext where to find the .mo file translating messages for a particular domain
|
||||
gettext.bindtextdomain("clear_GPS",dt.configuration.config_dir.."/lua/locale/")
|
||||
|
||||
local function _(msgid)
|
||||
return gettext.dgettext("clear_GPS", msgid)
|
||||
end
|
||||
|
||||
local function clear_GPS(images)
|
||||
for _, image in ipairs(images) do
|
||||
-- set the location information to Not a Number (NaN) so it displays correctly
|
||||
@@ -80,13 +85,13 @@ script_data.destroy = destroy
|
||||
dt.gui.libs.image.register_action(
|
||||
"clear_GPS", _("clear GPS data"),
|
||||
function(event, images) clear_GPS(images) end,
|
||||
_("Clear GPS data from selected images")
|
||||
_("clear GPS data from selected images")
|
||||
)
|
||||
|
||||
dt.register_event(
|
||||
"clear_GPS", "shortcut",
|
||||
function(event, shortcut) clear_GPS(dt.gui.action_images) end,
|
||||
_("Clear GPS data")
|
||||
_("clear GPS data from selected images")
|
||||
)
|
||||
|
||||
return script_data
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
local dt = require "darktable"
|
||||
local du = require "lib/dtutils"
|
||||
local df = require "lib/dtutils.file"
|
||||
local dtsys = require "lib/dtutils.system"
|
||||
|
||||
du.check_min_api_version("7.0.0", "color_profile_manager")
|
||||
|
||||
@@ -52,13 +53,10 @@ du.check_min_api_version("7.0.0", "color_profile_manager")
|
||||
-- L O C A L I Z A T I O N
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
local gettext = dt.gettext
|
||||
|
||||
-- Tell gettext where to find the .mo file translating messages for a particular domain
|
||||
gettext.bindtextdomain("color_profile_manager", dt.configuration.config_dir .. "/lua/locale/")
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
local function _(msgid)
|
||||
return gettext.dgettext("color_profile_manager", msgid)
|
||||
return gettext(msgid)
|
||||
end
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
@@ -119,13 +117,13 @@ end
|
||||
|
||||
local function add_profile(file, dir)
|
||||
df.file_copy(file, dir)
|
||||
dt.print(_("added color profile " .. file .. " to " .. dir))
|
||||
dt.print(string.format(_("added color profile %s to %s"), file, dir))
|
||||
dt.print_log("color profile " .. file .. " added to " .. dir)
|
||||
end
|
||||
|
||||
local function remove_profile(file, dir)
|
||||
os.remove(dir .. PS .. file)
|
||||
dt.print(_("removed color profile " .. file .. " from " .. dir))
|
||||
dt.print(string.format(_("removed color profile %s from %s"), file, dir))
|
||||
dt.print_log("color profile " .. file .. " removed from " .. dir)
|
||||
end
|
||||
|
||||
@@ -364,6 +362,13 @@ end
|
||||
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("color profile manager"),
|
||||
purpose = _("manage external darktable color profiles"),
|
||||
author = "Bill Ferguson <wpferguson@gmail.com>",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/color_profile_manager"
|
||||
}
|
||||
|
||||
script_data.destroy = destroy
|
||||
script_data.restart = restart
|
||||
script_data.destroy_method = "hide"
|
||||
|
||||
@@ -40,24 +40,29 @@ local dt = require "darktable"
|
||||
local du = require "lib/dtutils"
|
||||
local debug = require "darktable.debug"
|
||||
|
||||
local gettext = dt.gettext
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
du.check_min_api_version("7.0.0", "copy_attach_detach_tags")
|
||||
|
||||
local function _(msgid)
|
||||
return gettext(msgid)
|
||||
end
|
||||
|
||||
-- return data structure for script_manager
|
||||
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("copy attach detach tags"),
|
||||
purpose = _("shortcuts to copy, paste, replace, or remove tags from images"),
|
||||
author = "Christian Kanzian",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/copy_attach_detach_tags"
|
||||
}
|
||||
|
||||
script_data.destroy = nil -- function to destory the script
|
||||
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil
|
||||
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
|
||||
|
||||
-- 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/")
|
||||
|
||||
local function _(msgid)
|
||||
return gettext.dgettext("copy_attach_detach_tags", msgid)
|
||||
end
|
||||
script_data.show = nil -- only required for libs since the destroy_method only hides them
|
||||
|
||||
local cadt = {}
|
||||
cadt.module_installed = false
|
||||
@@ -98,7 +103,7 @@ local function mcopy_tags()
|
||||
end
|
||||
end
|
||||
|
||||
dt.print(_('Image tags copied ...'))
|
||||
dt.print(_('image tags copied ...'))
|
||||
|
||||
--create UI tag list
|
||||
local taglist = ""
|
||||
@@ -120,7 +125,7 @@ local function mcopy_tags()
|
||||
local function attach_tags()
|
||||
|
||||
if next(image_tags) == nil then
|
||||
dt.print(_('No tag to attach, please copy tags first.'))
|
||||
dt.print(_('no tag to attach, please copy tags first.'))
|
||||
return true
|
||||
end
|
||||
|
||||
@@ -144,7 +149,7 @@ local function attach_tags()
|
||||
end
|
||||
end
|
||||
end
|
||||
dt.print(_('Tags attached ...'))
|
||||
dt.print(_('tags attached ...'))
|
||||
end
|
||||
|
||||
local function detach_tags()
|
||||
@@ -160,13 +165,13 @@ local function detach_tags()
|
||||
end
|
||||
end
|
||||
end
|
||||
dt.print(_('Tags removed from image(s).'))
|
||||
dt.print(_('tags removed from image(s).'))
|
||||
end
|
||||
|
||||
local function replace_tags()
|
||||
detach_tags()
|
||||
attach_tags()
|
||||
dt.print(_('Tags replaced'))
|
||||
dt.print(_('tags replaced'))
|
||||
end
|
||||
|
||||
local function install_module()
|
||||
|
||||
@@ -37,13 +37,27 @@ local du = require "lib/dtutils"
|
||||
|
||||
du.check_min_api_version("7.0.0", "cr2hdr")
|
||||
|
||||
local gettext = darktable.gettext.gettext
|
||||
|
||||
local function _(msgid)
|
||||
return gettext(msgid)
|
||||
end
|
||||
|
||||
-- return data structure for script_manager
|
||||
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("cr2hdr"),
|
||||
purpose = _("process Magic Lantern dual ISO images"),
|
||||
author = "Till Theato <theato@ttill.de>",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/cr2hdr"
|
||||
}
|
||||
|
||||
script_data.destroy = nil -- function to destory the script
|
||||
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil
|
||||
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
|
||||
script_data.show = nil -- only required for libs since the destroy_method only hides them
|
||||
|
||||
local queue = {}
|
||||
local processed_files = {}
|
||||
@@ -86,7 +100,7 @@ end
|
||||
local function convert_images()
|
||||
if next(queue) == nil then return end
|
||||
|
||||
job = darktable.gui.create_job("Dual ISO conversion", true, stop_conversion)
|
||||
job = darktable.gui.create_job(_("dual ISO conversion"), true, stop_conversion)
|
||||
for key,image in pairs(queue) do
|
||||
if job.valid then
|
||||
job.percent = (key-1)/#queue
|
||||
@@ -97,7 +111,7 @@ local function convert_images()
|
||||
end
|
||||
local success_count = 0
|
||||
for _ in pairs(processed_files) do success_count = success_count + 1 end
|
||||
darktable.print("Dual ISO conversion successful on " .. success_count .. "/" .. #queue .. " images.")
|
||||
darktable.print(string.format(_("dual ISO conversion successful on %d/%d images."), success_count, #queue))
|
||||
job.valid = false
|
||||
processed_files = {}
|
||||
queue = {}
|
||||
@@ -121,13 +135,13 @@ local function destroy()
|
||||
end
|
||||
|
||||
darktable.register_event("cr2hdr", "shortcut",
|
||||
convert_action_images, "Run cr2hdr (Magic Lantern DualISO converter) on selected images")
|
||||
convert_action_images, _("run cr2hdr (Magic Lantern DualISO converter) on selected images"))
|
||||
darktable.register_event("cr2hdr", "post-import-image",
|
||||
file_imported)
|
||||
darktable.register_event("cr2hdr", "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\nwarning: cr2hdr is quite slow even in figuring out on whether the file is dual ISO or not."), false)
|
||||
|
||||
script_data.destroy = destroy
|
||||
|
||||
|
||||
162
contrib/cycle_group_leader.lua
Normal file
162
contrib/cycle_group_leader.lua
Normal file
@@ -0,0 +1,162 @@
|
||||
--[[
|
||||
|
||||
cycle_group_leader.lua - change image group leader
|
||||
|
||||
Copyright (C) 2024 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/>.
|
||||
]]
|
||||
--[[
|
||||
cycle_group_leader - change image grouip leader
|
||||
|
||||
cycle_group_leader changes the group leader to the next
|
||||
image in the group. If the end of the group is reached
|
||||
then the next image is wrapped around to the first image.
|
||||
|
||||
ADDITIONAL SOFTWARE NEEDED FOR THIS SCRIPT
|
||||
None
|
||||
|
||||
USAGE
|
||||
* enable with script_manager
|
||||
* assign a key to the shortcut
|
||||
|
||||
BUGS, COMMENTS, SUGGESTIONS
|
||||
Bill Ferguson <wpferguson@gmail.com>
|
||||
|
||||
CHANGES
|
||||
]]
|
||||
|
||||
local dt = require "darktable"
|
||||
local du = require "lib/dtutils"
|
||||
local df = require "lib/dtutils.file"
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- C O N S T A N T S
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
local MODULE = "cycle_group_leader"
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- A P I C H E C K
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
du.check_min_api_version("7.0.0", MODULE)
|
||||
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- I 1 8 N
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
local function _(msgid)
|
||||
return gettext(msgid)
|
||||
end
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- S C R I P T M A N A G E R I N T E G R A T I O N
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("cycle group leader"),
|
||||
purpose = _("change image group leader"),
|
||||
author = "Bill Ferguson <wpferguson@gmail.com>",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/cycle_group_leader"
|
||||
}
|
||||
|
||||
script_data.destroy = nil -- function to destory the script
|
||||
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet
|
||||
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
|
||||
script_data.show = nil -- only required for libs since the destroy_method only hides them
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- F U N C T I O N S
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
local function toggle_global_toolbox_grouping()
|
||||
dt.gui.libs.global_toolbox.grouping = false
|
||||
dt.gui.libs.global_toolbox.grouping = true
|
||||
end
|
||||
|
||||
local function hinter_msg(msg)
|
||||
dt.print_hinter(msg)
|
||||
dt.control.sleep(1500)
|
||||
dt.print_hinter(" ")
|
||||
end
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- M A I N P R O G R A M
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
local function cycle_group_leader(image)
|
||||
local group_images = image:get_group_members()
|
||||
if #group_images < 2 then
|
||||
hinter_msg(_("no images to cycle through in group"))
|
||||
return
|
||||
else
|
||||
local position = nil
|
||||
for i, img in ipairs(group_images) do
|
||||
if image == img then
|
||||
position = i
|
||||
end
|
||||
end
|
||||
|
||||
if position == #group_images then
|
||||
position = 1
|
||||
else
|
||||
position = position + 1
|
||||
end
|
||||
|
||||
new_leader = group_images[position]
|
||||
new_leader:make_group_leader()
|
||||
dt.gui.selection({new_leader})
|
||||
|
||||
if dt.gui.libs.global_toolbox.grouping then
|
||||
-- toggle the grouping to make the new leader show
|
||||
toggle_global_toolbox_grouping()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- D A R K T A B L E I N T E G R A T I O N
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
local function destroy()
|
||||
-- put things to destroy (events, storages, etc) here
|
||||
dt.destroy_event(MODULE, "shortcut")
|
||||
end
|
||||
|
||||
script_data.destroy = destroy
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- E V E N T S
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
dt.register_event(MODULE, "shortcut",
|
||||
function(event, shortcut)
|
||||
-- ignore the film roll, it contains all the images, not just the imported
|
||||
local images = dt.gui.selection()
|
||||
if #images < 1 then
|
||||
dt.print(_("no image selected, please select an image and try again"))
|
||||
else
|
||||
cycle_group_leader(images[1])
|
||||
end
|
||||
end,
|
||||
_("cycle group leader")
|
||||
)
|
||||
|
||||
return script_data
|
||||
334
contrib/dbmaint.lua
Normal file
334
contrib/dbmaint.lua
Normal file
@@ -0,0 +1,334 @@
|
||||
--[[
|
||||
|
||||
dbmaint.lua - perform database maintenance
|
||||
|
||||
Copyright (C) 2024 Bill Ferguson <wpferguson@gamil.com>.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
]]
|
||||
--[[
|
||||
dbmaint - perform database maintenance
|
||||
|
||||
Perform database maintenance to clean up missing images and filmstrips.
|
||||
|
||||
ADDITIONAL SOFTWARE NEEDED FOR THIS SCRIPT
|
||||
None
|
||||
|
||||
USAGE
|
||||
* start dbmaint from script_manager
|
||||
* scan for missing film rolls or missing images
|
||||
* look at the results and choose to delete or not
|
||||
|
||||
BUGS, COMMENTS, SUGGESTIONS
|
||||
Bill Ferguson <wpferguson@gamil.com>
|
||||
|
||||
CHANGES
|
||||
]]
|
||||
|
||||
local dt = require "darktable"
|
||||
local du = require "lib/dtutils"
|
||||
local df = require "lib/dtutils.file"
|
||||
local log = require "lib/dtutils.log"
|
||||
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- C O N S T A N T S
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
local MODULE <const> = "dbmaint"
|
||||
local DEFAULT_LOG_LEVEL <const> = log.error
|
||||
local PS <const> = dt.configuration.running_os == "windows" and "\\" or "/"
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- A P I C H E C K
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
du.check_min_api_version("7.0.0", MODULE) -- choose the minimum version that contains the features you need
|
||||
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- I 1 8 N
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
local function _(msgid)
|
||||
return gettext(msgid)
|
||||
end
|
||||
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- S C R I P T M A N A G E R I N T E G R A T I O N
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
local script_data = {}
|
||||
|
||||
script_data.destroy = nil -- function to destory the script
|
||||
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet
|
||||
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
|
||||
script_data.show = nil -- only required for libs since the destroy_method only hides them
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("db maintenance"),
|
||||
purpose = _("perform database maintenance"),
|
||||
author = "Bill Ferguson <wpferguson@gamil.com>",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/dbmaint/"
|
||||
}
|
||||
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- L O G L E V E L
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
log.log_level(DEFAULT_LOG_LEVEL)
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- N A M E S P A C E
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
local dbmaint = {}
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- G L O B A L V A R I A B L E S
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
dbmaint.main_widget = nil
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- A L I A S E S
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
local namespace = dbmaint
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- F U N C T I O N S
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
-------------------
|
||||
-- helper functions
|
||||
-------------------
|
||||
|
||||
local function set_log_level(level)
|
||||
local old_log_level = log.log_level()
|
||||
log.log_level(level)
|
||||
return old_log_level
|
||||
end
|
||||
|
||||
local function restore_log_level(level)
|
||||
log.log_level(level)
|
||||
end
|
||||
|
||||
local function scan_film_rolls()
|
||||
local missing_films = {}
|
||||
|
||||
for _, filmroll in ipairs(dt.films) do
|
||||
if not df.check_if_file_exists(filmroll.path) then
|
||||
table.insert(missing_films, filmroll)
|
||||
end
|
||||
end
|
||||
|
||||
return missing_films
|
||||
end
|
||||
|
||||
local function scan_images(film)
|
||||
local old_log_level = set_log_level(DEFAULT_LOG_LEVEL)
|
||||
local missing_images = {}
|
||||
|
||||
if film then
|
||||
for i = 1, #film do
|
||||
local image = film[i]
|
||||
log.msg(log.debug, "checking " .. image.filename)
|
||||
if not df.check_if_file_exists(image.path .. PS .. image.filename) then
|
||||
log.msg(log.info, image.filename .. " not found")
|
||||
table.insert(missing_images, image)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
restore_log_level(old_log_level)
|
||||
return missing_images
|
||||
end
|
||||
|
||||
local function remove_missing_film_rolls(list)
|
||||
for _, filmroll in ipairs(list) do
|
||||
filmroll:delete(true)
|
||||
end
|
||||
end
|
||||
|
||||
-- force the lighttable to reload
|
||||
|
||||
local function refresh_lighttable(film)
|
||||
local rules = dt.gui.libs.collect.filter()
|
||||
dt.gui.libs.collect.filter(rules)
|
||||
end
|
||||
|
||||
local function remove_missing_images(list)
|
||||
local film = list[1].film
|
||||
for _, image in ipairs(list) do
|
||||
image:delete()
|
||||
end
|
||||
refresh_lighttable(film)
|
||||
end
|
||||
|
||||
local function install_module()
|
||||
if not namespace.module_installed then
|
||||
dt.register_lib(
|
||||
MODULE, -- Module name
|
||||
_("DB maintenance"), -- Visible name
|
||||
true, -- expandable
|
||||
true, -- resetable
|
||||
{[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_LEFT_CENTER", 0}}, -- containers
|
||||
namespace.main_widget,
|
||||
nil,-- view_enter
|
||||
nil -- view_leave
|
||||
)
|
||||
namespace.module_installed = true
|
||||
end
|
||||
end
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- U S E R I N T E R F A C E
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
dbmaint.list_widget = dt.new_widget("text_view"){
|
||||
editable = false,
|
||||
reset_callback = function(this)
|
||||
this.text = ""
|
||||
end
|
||||
}
|
||||
|
||||
dbmaint.chooser = dt.new_widget("combobox"){
|
||||
label = _("scan for"),
|
||||
selected = 1,
|
||||
_("film rolls"), _("images"),
|
||||
reset_callback = function(this)
|
||||
this.selected = 1
|
||||
end
|
||||
}
|
||||
|
||||
dbmaint.scan_button = dt.new_widget("button"){
|
||||
label = _("scan"),
|
||||
tooltip = _("click to scan for missing film rolls/files"),
|
||||
clicked_callback = function(this)
|
||||
local found = nil
|
||||
local found_text = ""
|
||||
local old_log_level = set_log_level(DEFAULT_LOG_LEVEL)
|
||||
log.msg(log.debug, "Button clicked")
|
||||
if dbmaint.chooser.selected == 1 then -- film rolls
|
||||
found = scan_film_rolls()
|
||||
if #found > 0 then
|
||||
for _, film in ipairs(found) do
|
||||
local dir_name = du.split(film.path, PS)
|
||||
found_text = found_text .. dir_name[#dir_name] .. "\n"
|
||||
end
|
||||
end
|
||||
else
|
||||
log.msg(log.debug, "checking path " .. dt.collection[1].path .. " for missing files")
|
||||
found = scan_images(dt.collection[1].film)
|
||||
if #found > 0 then
|
||||
for _, image in ipairs(found) do
|
||||
found_text = found_text .. image.filename .. "\n"
|
||||
end
|
||||
end
|
||||
end
|
||||
if #found > 0 then
|
||||
log.msg(log.debug, "found " .. #found .. " missing items")
|
||||
dbmaint.list_widget.text = found_text
|
||||
dbmaint.found = found
|
||||
dbmaint.remove_button.sensitive = true
|
||||
else
|
||||
log.msg(log.debug, "no missing items found")
|
||||
end
|
||||
restore_log_level(old_log_level)
|
||||
end,
|
||||
reset_callback = function(this)
|
||||
dbmaint.found = nil
|
||||
end
|
||||
}
|
||||
|
||||
dbmaint.remove_button = dt.new_widget("button"){
|
||||
label = _("remove"),
|
||||
tooltip = _("remove missing film rolls/images"),
|
||||
sensitive = false,
|
||||
clicked_callback = function(this)
|
||||
if dbmaint.chooser.selected == 1 then -- film rolls
|
||||
remove_missing_film_rolls(dbmaint.found)
|
||||
else
|
||||
remove_missing_images(dbmaint.found)
|
||||
end
|
||||
dbmaint.found = nil
|
||||
dbmaint.list_widget.text = ""
|
||||
this.sensitive = false
|
||||
end,
|
||||
reset_callback = function(this)
|
||||
this.sensitive = false
|
||||
end
|
||||
}
|
||||
|
||||
dbmaint.main_widget = dt.new_widget("box"){
|
||||
orientation = "vertical",
|
||||
dt.new_widget("section_label"){label = _("missing items")},
|
||||
dbmaint.list_widget,
|
||||
dt.new_widget("label"){label = ""},
|
||||
dbmaint.chooser,
|
||||
dt.new_widget("label"){label = ""},
|
||||
dbmaint.scan_button,
|
||||
dbmaint.remove_button
|
||||
}
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- D A R K T A B L E I N T E G R A T I O N
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
local function destroy()
|
||||
dt.gui.libs[MODULE].visible = false
|
||||
|
||||
if namespace.event_registered then
|
||||
dt.destroy_event(MODULE, "view-changed")
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
local function restart()
|
||||
dt.gui.libs[MODULE].visible = true
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
script_data.destroy = destroy
|
||||
script_data.restart = restart
|
||||
script_data.destroy_method = "hide"
|
||||
script_data.show = restart
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- E V E N T S
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
if dt.gui.current_view().id == "lighttable" then
|
||||
install_module()
|
||||
else
|
||||
if not namespace.event_registered then
|
||||
dt.register_event(MODULE, "view-changed",
|
||||
function(event, old_view, new_view)
|
||||
if new_view.name == "lighttable" and old_view.name == "darkroom" then
|
||||
install_module()
|
||||
end
|
||||
end
|
||||
)
|
||||
namespace.event_registered = true
|
||||
end
|
||||
end
|
||||
|
||||
return script_data
|
||||
@@ -67,20 +67,28 @@ if dt.configuration.running_os == 'windows' then os_path_seperator = '\\' end
|
||||
|
||||
du.check_min_api_version("7.0.0", "enfuseAdvanced")
|
||||
|
||||
-- Tell gettext where to find the .mo file translating messages for a particular domain
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
local function _(msgid)
|
||||
return gettext(msgid)
|
||||
end
|
||||
|
||||
-- return data structure for script_manager
|
||||
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("enfuse advanced"),
|
||||
purpose = _("focus stack or exposure blend images"),
|
||||
author = "Kevin Ertel",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/enfuseAdvanced"
|
||||
}
|
||||
|
||||
script_data.destroy = nil -- function to destory the script
|
||||
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil
|
||||
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
|
||||
|
||||
-- Tell gettext where to find the .mo file translating messages for a particular domain
|
||||
local gettext = dt.gettext
|
||||
gettext.bindtextdomain('enfuseAdvanced',dt.configuration.config_dir..'/lua/locale/')
|
||||
local function _(msgid)
|
||||
return gettext.dgettext('enfuseAdvanced', msgid)
|
||||
end
|
||||
script_data.show = nil -- only required for libs since the destroy_method only hides them
|
||||
|
||||
-- INITS --
|
||||
local AIS = {
|
||||
@@ -259,7 +267,7 @@ local function ExeUpdate(prog_tbl) --updates executable paths and verifies them
|
||||
if not prog.bin then
|
||||
prog.install_error = true
|
||||
dt.preferences.write(mod, 'bin_exists', 'bool', false)
|
||||
dt.print(_('issue with ')..prog.name.._(' executable'))
|
||||
dt.print(string.format(_("issue with %s executable"), prog.name))
|
||||
else
|
||||
prog.bin = CleanSpaces(prog.bin)
|
||||
end
|
||||
@@ -376,7 +384,7 @@ local function SaveToPreference(preset) --save the present values of enfuse GUI
|
||||
dt.preferences.write(mod, preset..argument, arg_data.style, temp)
|
||||
end
|
||||
end
|
||||
dt.print(_('saved to ')..preset)
|
||||
dt.print(string.format(_("saved to %s"), preset))
|
||||
end
|
||||
|
||||
local function LoadFromPreference(preset) --load values from the specified 'preset' into the GUI elements
|
||||
@@ -392,7 +400,7 @@ local function LoadFromPreference(preset) --load values from the specified 'pres
|
||||
dt.preferences.write(mod, 'active_'..argument, arg_data.style, temp)
|
||||
end
|
||||
end
|
||||
dt.print(_('loaded from ')..preset)
|
||||
dt.print(string.format(_("loaded from %s"), preset))
|
||||
end
|
||||
|
||||
local function remove_temp_files(images_to_remove) --deletes all files specified by the input string
|
||||
@@ -427,7 +435,7 @@ local function support_format(storage, format) --tells dt we only support TIFF e
|
||||
end
|
||||
|
||||
local function show_status(storage, image, format, filename, number, total, high_quality, extra_data) --outputs message to user showing script export status
|
||||
dt.print(_('export for image fusion ')..tostring(math.floor(number))..' / '..tostring(math.floor(total)))
|
||||
dt.print(string.format(_("export for image fusion %d / %d"), math.floor(number), math.floor(total)))
|
||||
end
|
||||
|
||||
local function main(storage, image_table, extra_data)
|
||||
@@ -435,7 +443,7 @@ local function main(storage, image_table, extra_data)
|
||||
dt.print(_('too few images selected, please select at least 2 images'))
|
||||
return
|
||||
elseif extra_data[1] == 2 then
|
||||
dt.print(_('installation error, please verify binary paths are proper'))
|
||||
dt.print(_('installation error, please verify binary paths are correct'))
|
||||
return
|
||||
end
|
||||
local images_to_remove = ''
|
||||
@@ -455,8 +463,8 @@ local function main(storage, image_table, extra_data)
|
||||
job.valid = false
|
||||
if resp ~= 0 then
|
||||
remove_temp_files(images_to_remove)
|
||||
dt.print_error(AIS.name.._(' failed'))
|
||||
dt.print(AIS.name.._(' failed'))
|
||||
dt.print(string.format(_("%s failed"), AIS.name))
|
||||
dt.print_error(AIS.name .. ' failed')
|
||||
return
|
||||
end
|
||||
end
|
||||
@@ -482,8 +490,8 @@ local function main(storage, image_table, extra_data)
|
||||
local resp = dsys.external_command(run_cmd)
|
||||
if resp ~= 0 then
|
||||
remove_temp_files(images_to_remove)
|
||||
dt.print_error(ENF.name.._(' failed'))
|
||||
dt.print(ENF.name.._(' failed'))
|
||||
dt.print_error(ENF.name..' failed')
|
||||
dt.print(string.format(_("%s failed"), ENF.name))
|
||||
return
|
||||
end
|
||||
|
||||
@@ -728,7 +736,7 @@ GUI.ENF.hard_masks = dt.new_widget('check_button'){
|
||||
GUI.ENF.save_masks = dt.new_widget('check_button'){
|
||||
label = _('save masks'),
|
||||
value = dt.preferences.read(mod, 'active_save_masks', 'bool'),
|
||||
tooltip = _('Save the generated weight masks to your home directory,\nenblend saves masks as 8 bit grayscale, \ni.e. single channel images. \nfor accuracy we recommend to choose a lossless format.'),
|
||||
tooltip = _('save the generated weight masks to your home directory,\nenblend saves masks as 8 bit grayscale, \ni.e. single channel images. \nfor accuracy we recommend to choose a lossless format.'),
|
||||
clicked_callback = function(self) dt.preferences.write(mod, 'active_save_masks', 'bool', self.value) end,
|
||||
reset_callback = function(self) self.value = false end
|
||||
}
|
||||
@@ -881,7 +889,7 @@ GUI.Target.output_directory = dt.new_widget('file_chooser_button'){
|
||||
GUI.Target.source_location = dt.new_widget('check_button'){
|
||||
label = _('save to source image location'),
|
||||
value = dt.preferences.read(mod, 'active_source_location', 'bool'),
|
||||
tooltip = _('If checked ignores the location above and saves output image(s) to the same location as the source images.'),
|
||||
tooltip = _('if checked ignores the location above and saves output image(s) to the same location as the source images.'),
|
||||
clicked_callback = function(self) dt.preferences.write(mod, 'active_source_location', 'bool', self.value) end,
|
||||
reset_callback = function(self) self.value = true end
|
||||
}
|
||||
@@ -915,8 +923,8 @@ GUI.Target.auto_import = dt.new_widget('check_button'){
|
||||
}
|
||||
temp = dt.preferences.read(mod, 'active_apply_style_ind', 'integer')
|
||||
GUI.Target.apply_style = dt.new_widget('combobox'){
|
||||
label = _('Apply Style on Import'),
|
||||
tooltip = _('Apply selected style on auto-import to newly created blended image'),
|
||||
label = _('apply style on Import'),
|
||||
tooltip = _('apply selected style on auto-import to newly created blended image'),
|
||||
selected = 1,
|
||||
'none',
|
||||
changed_callback = function(self)
|
||||
@@ -937,16 +945,16 @@ GUI.Target.apply_style.selected = temp
|
||||
GUI.Target.copy_tags = dt.new_widget('check_button'){
|
||||
label = _('copy tags'),
|
||||
value = dt.preferences.read(mod, 'active_copy_tags', 'bool'),
|
||||
tooltip = _('Copy tags from first image.'),
|
||||
tooltip = _('copy tags from first image.'),
|
||||
clicked_callback = function(self) dt.preferences.write(mod, 'active_copy_tags', 'bool', self.value) end,
|
||||
reset_callback = function(self) self.value = true end
|
||||
}
|
||||
temp = dt.preferences.read(mod, 'active_add_tags', 'string')
|
||||
if temp == '' then temp = nil end
|
||||
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,
|
||||
placeholder = 'Enter tags, seperated by commas',
|
||||
placeholder = _('enter tags, separated by commas'),
|
||||
editable = true
|
||||
}
|
||||
temp = dt.preferences.read(mod, 'active_current_preset_ind', 'integer')
|
||||
@@ -1013,7 +1021,7 @@ GUI.Presets.variants_type = dt.new_widget('combobox'){
|
||||
GUI.Presets.variants_type.sensitive = GUI.Presets.variants.value
|
||||
temp = df.get_executable_path_preference(AIS.name)
|
||||
GUI.exes.align_image_stack = dt.new_widget('file_chooser_button'){
|
||||
title = 'AIS binary path',
|
||||
title = 'align_image_stack ' .. _('binary path'),
|
||||
value = temp,
|
||||
tooltip = temp,
|
||||
is_directory = false,
|
||||
@@ -1021,7 +1029,7 @@ GUI.exes.align_image_stack = dt.new_widget('file_chooser_button'){
|
||||
}
|
||||
temp = df.get_executable_path_preference(ENF.name)
|
||||
GUI.exes.enfuse = dt.new_widget('file_chooser_button'){
|
||||
title = 'enfuse binary path',
|
||||
title = 'enfuse ' .. _('binary path'),
|
||||
value = temp,
|
||||
tooltip = temp,
|
||||
is_directory = false,
|
||||
@@ -1029,7 +1037,7 @@ GUI.exes.enfuse = dt.new_widget('file_chooser_button'){
|
||||
}
|
||||
temp = df.get_executable_path_preference(EXF.name)
|
||||
GUI.exes.exiftool = dt.new_widget('file_chooser_button'){
|
||||
title = 'Exiftool binary path',
|
||||
title = 'exiftool ' .. _('binary path'),
|
||||
value = temp,
|
||||
tooltip = temp,
|
||||
is_directory = false,
|
||||
|
||||
@@ -33,21 +33,27 @@ local ds = require("lib/dtutils.system")
|
||||
|
||||
du.check_min_api_version("7.0.0", "exportLUT")
|
||||
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
local function _(msgid)
|
||||
return gettext(msgid)
|
||||
end
|
||||
|
||||
-- return data structure for script_manager
|
||||
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("export LUT"),
|
||||
purpose = _("export a style as a LUT"),
|
||||
author = "Noah Clarke",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/exportLUT"
|
||||
}
|
||||
|
||||
script_data.destroy = nil -- function to destory the script
|
||||
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil
|
||||
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
|
||||
|
||||
local gettext = dt.gettext
|
||||
|
||||
gettext.bindtextdomain("exportLUT",dt.configuration.config_dir.."/lua/locale/")
|
||||
|
||||
local function _(msgid)
|
||||
return gettext.dgettext("exportLUT", msgid)
|
||||
end
|
||||
script_data.show = nil -- only required for libs since the destroy_method only hides them
|
||||
|
||||
du.check_min_api_version("5.0.0", "exportLUT")
|
||||
|
||||
@@ -63,13 +69,13 @@ 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"),
|
||||
title = _("choose the identity file"),
|
||||
value = "",
|
||||
is_directory = false
|
||||
}
|
||||
|
||||
local export_chooser_button = dt.new_widget("file_chooser_button"){
|
||||
title = _("Export_location_chooser"),
|
||||
title = _("choose the export location"),
|
||||
value = "",
|
||||
is_directory = true
|
||||
}
|
||||
@@ -105,9 +111,9 @@ 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"))
|
||||
dt.print(_("invalid identity lut file"))
|
||||
else
|
||||
local job = dt.gui.create_job(_('Exporting styles as haldCLUTs'), true, end_job)
|
||||
local job = dt.gui.create_job(_('exporting styles as haldCLUTs'), true, end_job)
|
||||
|
||||
local size = 1
|
||||
|
||||
@@ -126,9 +132,9 @@ local function export_luts()
|
||||
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))
|
||||
dt.print(string.format(_("exported: %s"), output_path(style.name, job)))
|
||||
end
|
||||
dt.print(_("Done exporting haldCLUTs"))
|
||||
dt.print(_("done exporting haldCLUTs"))
|
||||
job.valid = false
|
||||
identity:reset()
|
||||
end
|
||||
|
||||
@@ -75,13 +75,28 @@ local dtsys = require "lib/dtutils.system"
|
||||
local MODULE_NAME = "ext_editor"
|
||||
du.check_min_api_version("7.0.0", MODULE_NAME)
|
||||
|
||||
-- translation
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
local function _(msgid)
|
||||
return gettext(msgid)
|
||||
end
|
||||
|
||||
-- return data structure for script_manager
|
||||
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("external editors"),
|
||||
purpose = _("edit images with external editors"),
|
||||
author = "Marco Carrarini, marco.carrarini@gmail.com",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/ext_editor"
|
||||
}
|
||||
|
||||
script_data.destroy = nil -- function to destory the script
|
||||
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil
|
||||
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
|
||||
script_data.show = nil -- only required for libs since the destroy_method only hides them
|
||||
|
||||
-- OS compatibility
|
||||
local PS = dt.configuration.running_os == "windows" and "\\" or "/"
|
||||
@@ -93,13 +108,6 @@ ee.event_registered = false
|
||||
ee.widgets = {}
|
||||
|
||||
|
||||
-- translation
|
||||
local gettext = dt.gettext
|
||||
gettext.bindtextdomain(MODULE_NAME, dt.configuration.config_dir..PS.."lua"..PS.."locale"..PS)
|
||||
local function _(msgid)
|
||||
return gettext.dgettext(MODULE_NAME, msgid)
|
||||
end
|
||||
|
||||
-- maximum number of external programs, can be increased to necessity
|
||||
local MAX_EDITORS = 9
|
||||
|
||||
@@ -155,7 +163,7 @@ local function UpdateProgramList(combobox, button_edit, button_edit_copy, update
|
||||
button_edit.sensitive = active
|
||||
button_edit_copy.sensitive = active
|
||||
|
||||
if update_button_pressed then dt.print(n_entries.._(" editors configured")) end
|
||||
if update_button_pressed then dt.print(string.format(_("%d editors configured"), n_entries)) end
|
||||
end
|
||||
|
||||
|
||||
@@ -222,17 +230,17 @@ local function OpenWith(images, choice, copy)
|
||||
-- physical copy, check result, return if error
|
||||
local copy_success = df.file_copy(name, new_name)
|
||||
if not copy_success then
|
||||
dt.print(_("error copying file ")..name)
|
||||
dt.print(string.format(_("error copying file %s"), name))
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
-- launch the external editor, check result, return if error
|
||||
local run_cmd = bin.." "..df.sanitize_filename(new_name)
|
||||
dt.print(_("launching ")..friendly_name.."...")
|
||||
dt.print(string.format(_("launching %s..."), friendly_name))
|
||||
local result = dtsys.external_command(run_cmd)
|
||||
if result ~= 0 then
|
||||
dt.print(_("error launching ")..friendly_name)
|
||||
dt.print(string.format(_("error launching %s"), friendly_name))
|
||||
return
|
||||
end
|
||||
|
||||
@@ -325,7 +333,7 @@ local function export2collection(storage, image_table, extra_data)
|
||||
-- move image to collection folder, check result, return if error
|
||||
move_success = df.file_move(temp_name, new_name)
|
||||
if not move_success then
|
||||
dt.print(_("error moving file ")..temp_name)
|
||||
dt.print(string.format(_("error moving file %s"), temp_name))
|
||||
return
|
||||
end
|
||||
|
||||
@@ -377,7 +385,7 @@ end
|
||||
local function restart()
|
||||
for i = 1, MAX_EDITORS do
|
||||
dt.register_event(MODULE_NAME .. i, "shortcut",
|
||||
program_shortcut, _("edit with program ")..string.format("%02d", i))
|
||||
program_shortcut, string.format(_("edit with program %02d"), i))
|
||||
end
|
||||
dt.register_storage("exp2coll", _("collection"), nil, export2collection)
|
||||
dt.gui.libs[MODULE_NAME].visible = true
|
||||
@@ -475,11 +483,11 @@ dt.register_storage("exp2coll", _("collection"), nil, export2collection)
|
||||
-- register the new preferences -----------------------------------------------
|
||||
for i = MAX_EDITORS, 1, -1 do
|
||||
dt.preferences.register(MODULE_NAME, "program_path_"..i, "file",
|
||||
_("executable for external editor ")..i,
|
||||
_("select executable for external editor") , _("(None)"))
|
||||
string.format(_("executable for external editor %d"), i),
|
||||
_("select executable for external editor") , _("(none)"))
|
||||
|
||||
dt.preferences.register(MODULE_NAME, "program_name_"..i, "string",
|
||||
_("name of external editor ")..i,
|
||||
string.format(_("name of external editor %d"), i),
|
||||
_("friendly name of external editor"), "")
|
||||
end
|
||||
dt.preferences.register(MODULE_NAME, "show_in_darkrooom", "bool",
|
||||
@@ -490,7 +498,7 @@ dt.preferences.register(MODULE_NAME, "show_in_darkrooom", "bool",
|
||||
-- register the new shortcuts -------------------------------------------------
|
||||
for i = 1, MAX_EDITORS do
|
||||
dt.register_event(MODULE_NAME .. i, "shortcut",
|
||||
program_shortcut, _("edit with program ")..string.format("%02d", i))
|
||||
program_shortcut, string.format(_("edit with program %02d"), i))
|
||||
end
|
||||
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ local dt = require "darktable"
|
||||
local du = require "lib/dtutils"
|
||||
local df = require "lib/dtutils.file"
|
||||
local dtsys = require "lib/dtutils.system"
|
||||
local gettext = dt.gettext
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
-- constants
|
||||
|
||||
@@ -54,13 +54,25 @@ local OUTPUT = dt.configuration.tmp_dir .. PS .. "facerecognition.txt"
|
||||
|
||||
du.check_min_api_version("7.0.0", MODULE)
|
||||
|
||||
local function _(msgid)
|
||||
return gettext(msgid)
|
||||
end
|
||||
|
||||
-- return data structure for script_manager
|
||||
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("face recognition"),
|
||||
purpose = _("use facial recognition to tag images"),
|
||||
author = "Sebastian Witt",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/face_recognition"
|
||||
}
|
||||
|
||||
script_data.destroy = nil -- function to destory the script
|
||||
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil
|
||||
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
|
||||
script_data.show = nil -- only required for libs since the destroy_method only hides them
|
||||
|
||||
-- namespace
|
||||
|
||||
@@ -68,13 +80,6 @@ local fc = {}
|
||||
fc.module_installed = false
|
||||
fc.event_registered = false
|
||||
|
||||
-- Tell gettext where to find the .mo file translating messages for a particular domain
|
||||
gettext.bindtextdomain("face_recognition", dt.configuration.config_dir.."/lua/locale/")
|
||||
|
||||
local function _(msgid)
|
||||
return gettext.dgettext("face_recognition", msgid)
|
||||
end
|
||||
|
||||
local function build_image_table(images)
|
||||
local image_table = {}
|
||||
local file_extension = ""
|
||||
@@ -134,7 +139,7 @@ local function do_export(img_tbl, images)
|
||||
job.percent = 0.0
|
||||
for export,img in pairs(img_tbl) do
|
||||
exp_cnt = exp_cnt + 1
|
||||
dt.print(string.format(_("Exporting image %i of %i images"), exp_cnt, images))
|
||||
dt.print(string.format(_("exporting image %i of %i images"), exp_cnt, images))
|
||||
exporter:write_image(img, export, upsize)
|
||||
job.percent = job.percent + percent_step
|
||||
end
|
||||
@@ -204,7 +209,7 @@ local function face_recognition ()
|
||||
local bin_path = df.check_if_bin_exists("face_recognition")
|
||||
|
||||
if not bin_path then
|
||||
dt.print(_("Face recognition not found"))
|
||||
dt.print(_("face recognition not found"))
|
||||
return
|
||||
end
|
||||
|
||||
@@ -256,7 +261,7 @@ local function face_recognition ()
|
||||
local command = bin_path .. " --cpus " .. nrCores .. " --tolerance " .. tolerance .. " " .. knownPath .. " " .. path .. " > " .. OUTPUT
|
||||
os.setlocale()
|
||||
dt.print_log("Face recognition: Running command: " .. command)
|
||||
dt.print(_("Starting face recognition..."))
|
||||
dt.print(_("starting face recognition..."))
|
||||
|
||||
dtsys.external_command(command)
|
||||
|
||||
@@ -264,9 +269,9 @@ local function face_recognition ()
|
||||
local f = io.open(OUTPUT, "rb")
|
||||
|
||||
if not f then
|
||||
dt.print(_("Face recognition failed"))
|
||||
dt.print(_("face recognition failed"))
|
||||
else
|
||||
dt.print(_("Face recognition finished"))
|
||||
dt.print(_("face recognition finished"))
|
||||
f:close ()
|
||||
end
|
||||
|
||||
@@ -398,7 +403,7 @@ fc.category_tags = dt.new_widget("entry"){
|
||||
|
||||
fc.tolerance = dt.new_widget("slider"){
|
||||
label = _("tolerance"),
|
||||
tooltip = ("detection tolerance - 0.6 default - lower if too many faces detected"),
|
||||
tooltip = _("detection tolerance - 0.6 default - lower if too many faces detected"),
|
||||
soft_min = 0.0,
|
||||
hard_min = 0.0,
|
||||
soft_max = 1.0,
|
||||
@@ -481,12 +486,12 @@ table.insert(widgets, fc.num_cores)
|
||||
table.insert(widgets, fc.export_format)
|
||||
table.insert(widgets, dt.new_widget("box"){
|
||||
orientation = "horizontal",
|
||||
dt.new_widget("label"){ label = _("width ")},
|
||||
dt.new_widget("label"){ label = _("width")},
|
||||
fc.width,
|
||||
})
|
||||
table.insert(widgets, dt.new_widget("box"){
|
||||
orientation = "horizontal",
|
||||
dt.new_widget("label"){ label = _("height ")},
|
||||
dt.new_widget("label"){ label = _("height")},
|
||||
fc.height,
|
||||
})
|
||||
table.insert(widgets, fc.execute)
|
||||
|
||||
@@ -60,16 +60,30 @@ cameras may behave in other ways.
|
||||
local dt = require "darktable"
|
||||
local du = require "lib/dtutils"
|
||||
local df = require "lib/dtutils.file"
|
||||
local dtsys = require "lib/dtutils.system"
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
du.check_min_api_version("7.0.0", "fujifilm_dynamic_range")
|
||||
|
||||
local function _(msgid)
|
||||
return gettext(msgid)
|
||||
end
|
||||
|
||||
-- return data structure for script_manager
|
||||
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("fujifilm dynamic range"),
|
||||
purpose = _("compensate for Fujifilm raw files made using \"dynamic range\""),
|
||||
author = "Dan Torop <dant@pnym.net>",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/fujifilm_dynamic_range"
|
||||
}
|
||||
|
||||
script_data.destroy = nil -- function to destory the script
|
||||
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil
|
||||
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
|
||||
script_data.show = nil -- only required for libs since the destroy_method only hides them
|
||||
|
||||
local function detect_dynamic_range(event, image)
|
||||
if image.exif_maker ~= "FUJIFILM" then
|
||||
@@ -110,6 +124,17 @@ local function detect_dynamic_range(event, image)
|
||||
-- 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))
|
||||
-- handle any duplicates
|
||||
if #image:get_group_members() > 1 then
|
||||
local basename = df.get_basename(image.filename)
|
||||
local grouped_images = image:get_group_members()
|
||||
for _, img in ipairs(grouped_images) do
|
||||
if string.match(img.filename, basename) and img.duplicate_index > 0 then
|
||||
-- its a duplicate
|
||||
img.exif_exposure_bias = img.exif_exposure_bias + tonumber(raf_result)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function destroy()
|
||||
|
||||
@@ -26,51 +26,61 @@ Dependencies:
|
||||
local dt = require "darktable"
|
||||
local du = require "lib/dtutils"
|
||||
local df = require "lib/dtutils.file"
|
||||
local gettext = dt.gettext
|
||||
local dtsys = require "lib/dtutils.system"
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
du.check_min_api_version("7.0.0", "fujifilm_ratings")
|
||||
|
||||
local function _(msgid)
|
||||
return gettext(msgid)
|
||||
end
|
||||
|
||||
-- return data structure for script_manager
|
||||
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("fujifilm ratings"),
|
||||
purpose = _("import Fujifilm in-camera ratings"),
|
||||
author = "Ben Mendis <ben.mendis@gmail.com>",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/fujifilm_ratings"
|
||||
}
|
||||
|
||||
script_data.destroy = nil -- function to destory the script
|
||||
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil
|
||||
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
|
||||
|
||||
gettext.bindtextdomain("fujifilm_ratings", dt.configuration.config_dir.."/lua/locale/")
|
||||
|
||||
local function _(msgid)
|
||||
return gettext.dgettext("fujifilm_ratings", msgid)
|
||||
end
|
||||
script_data.show = nil -- only required for libs since the destroy_method only hides them
|
||||
|
||||
local function detect_rating(event, image)
|
||||
if not string.match(image.filename, "%.RAF$") and not string.match(image.filename, "%.raf$") then
|
||||
return
|
||||
end
|
||||
if not df.check_if_bin_exists("exiftool") then
|
||||
dt.print_error(_("exiftool not found"))
|
||||
dt.print_error("exiftool not found")
|
||||
return
|
||||
end
|
||||
local RAF_filename = df.sanitize_filename(tostring(image))
|
||||
local JPEG_filename = string.gsub(RAF_filename, "%.RAF$", ".JPG")
|
||||
local command = "exiftool -Rating " .. JPEG_filename
|
||||
dt.print_error(command)
|
||||
dt.print_log(command)
|
||||
local output = io.popen(command)
|
||||
local jpeg_result = output:read("*all")
|
||||
output:close()
|
||||
if string.len(jpeg_result) > 0 then
|
||||
jpeg_result = string.gsub(jpeg_result, "^Rating.*(%d)", "%1")
|
||||
image.rating = tonumber(jpeg_result)
|
||||
dt.print_error(_("Using JPEG Rating: ") .. tostring(jpeg_result))
|
||||
dt.print_log("using JPEG rating: " .. jpeg_result)
|
||||
return
|
||||
end
|
||||
command = "exiftool -Rating " .. RAF_filename
|
||||
dt.print_error(command)
|
||||
dt.print_log(command)
|
||||
output = io.popen(command)
|
||||
local raf_result = output:read("*all")
|
||||
output:close()
|
||||
if string.len(raf_result) > 0 then
|
||||
raf_result = string.gsub(raf_result, "^Rating.*(%d)", "%1")
|
||||
image.rating = tonumber(raf_result)
|
||||
dt.print_error(_("Using RAF Rating: ") .. tostring(raf_result))
|
||||
dt.print_log("using RAF rating: " .. raf_result)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -35,24 +35,30 @@ USAGE
|
||||
local dt = require "darktable"
|
||||
local du = require "lib/dtutils"
|
||||
local df = require "lib/dtutils.file"
|
||||
local gettext = dt.gettext
|
||||
local dtsys = require "lib/dtutils.system"
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
du.check_min_api_version("7.0.0", "geoJSON_export")
|
||||
|
||||
local function _(msgid)
|
||||
return gettext(msgid)
|
||||
end
|
||||
|
||||
-- return data structure for script_manager
|
||||
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("geoJSON export"),
|
||||
purpose = _("export a geoJSON file from geo data"),
|
||||
author = "Tobias Jakobs",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/geoJSON_export"
|
||||
}
|
||||
|
||||
script_data.destroy = nil -- function to destory the script
|
||||
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil
|
||||
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
|
||||
|
||||
-- Tell gettext where to find the .mo file translating messages for a particular domain
|
||||
gettext.bindtextdomain("geoJSON_export",dt.configuration.config_dir.."/lua/locale/")
|
||||
|
||||
local function _(msgid)
|
||||
return gettext.dgettext("geoJSON_export", msgid)
|
||||
end
|
||||
script_data.show = nil -- only required for libs since the destroy_method only hides them
|
||||
|
||||
-- Sort a table
|
||||
local function spairs(_table, order) -- Code copied from http://stackoverflow.com/questions/15706270/sort-a-table-in-lua
|
||||
@@ -79,24 +85,24 @@ local function spairs(_table, order) -- Code copied from http://stackoverflow.co
|
||||
end
|
||||
|
||||
local function show_status(storage, image, format, filename, number, total, high_quality, extra_data)
|
||||
dt.print(string.format(_("Export Image %i/%i"), number, total))
|
||||
dt.print(string.format(_("export image %i/%i"), number, total))
|
||||
end
|
||||
|
||||
local function create_geoJSON_file(storage, image_table, extra_data)
|
||||
if not df.check_if_bin_exists("mkdir") then
|
||||
dt.print_error(_("mkdir not found"))
|
||||
dt.print_error("mkdir not found")
|
||||
return
|
||||
end
|
||||
if not df.check_if_bin_exists("convert") then
|
||||
dt.print_error(_("convert not found"))
|
||||
dt.print_error("convert not found")
|
||||
return
|
||||
end
|
||||
if not df.check_if_bin_exists("xdg-open") then
|
||||
dt.print_error(_("xdg-open not found"))
|
||||
dt.print_error("xdg-open not found")
|
||||
return
|
||||
end
|
||||
if not df.check_if_bin_exists("xdg-user-dir") then
|
||||
dt.print_error(_("xdg-user-dir not found"))
|
||||
dt.print_error("xdg-user-dir not found")
|
||||
return
|
||||
end
|
||||
|
||||
@@ -287,7 +293,7 @@ local function create_geoJSON_file(storage, image_table, extra_data)
|
||||
file:write(geoJSON_file)
|
||||
file:close()
|
||||
|
||||
dt.print("geoJSON file created in "..exportDirectory)
|
||||
dt.print(string.format(_("%s file created in %s"), "geoJSON", exportDirectory))
|
||||
|
||||
-- Open the file with the standard programm
|
||||
if ( dt.preferences.read("geoJSON_export","OpengeoJSONFile","bool") == true ) then
|
||||
@@ -307,20 +313,20 @@ end
|
||||
dt.preferences.register("geoJSON_export",
|
||||
"CreateMapBoxHTMLFile",
|
||||
"bool",
|
||||
_("geoJSON export: Create an additional HTML file"),
|
||||
_("Creates a HTML file, that loads the geoJASON file. (Needs a MapBox key"),
|
||||
"geoJSON export: ".._("Create an additional HTML file"),
|
||||
_("creates an HTML file that loads the geoJSON file. (needs a MapBox key"),
|
||||
false )
|
||||
dt.preferences.register("geoJSON_export",
|
||||
"mapBoxKey",
|
||||
"string",
|
||||
_("geoJSON export: MapBox Key"),
|
||||
_("https://www.mapbox.com/studio/account/tokens"),
|
||||
"geoJSON export: MapBox " .. _("key"),
|
||||
"https://www.mapbox.com/studio/account/tokens",
|
||||
'' )
|
||||
dt.preferences.register("geoJSON_export",
|
||||
"OpengeoJSONFile",
|
||||
"bool",
|
||||
_("geoJSON export: Open geoJSON file after export"),
|
||||
_("Opens the geoJSON file after the export with the standard program for geoJSON files"),
|
||||
"geoJSON export: " .. _("open geoJSON file after export"),
|
||||
_("opens the geoJSON file after the export with the standard program for geoJSON files"),
|
||||
false )
|
||||
|
||||
local handle = io.popen("xdg-user-dir DESKTOP")
|
||||
@@ -332,8 +338,8 @@ end
|
||||
dt.preferences.register("geoJSON_export",
|
||||
"ExportDirectory",
|
||||
"directory",
|
||||
_("geoJSON export: Export directory"),
|
||||
_("A directory that will be used to export the geoJSON files"),
|
||||
_("geoJSON export: export directory"),
|
||||
_("a directory that will be used to export the geoJSON files"),
|
||||
result )
|
||||
|
||||
-- Register
|
||||
|
||||
@@ -28,24 +28,30 @@ require "geoToolbox"
|
||||
local dt = require "darktable"
|
||||
local du = require "lib/dtutils"
|
||||
local df = require "lib/dtutils.file"
|
||||
local gettext = dt.gettext
|
||||
local dtsys = require "lib/dtutils.system"
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
du.check_min_api_version("7.0.0", "geoToolbox")
|
||||
|
||||
local function _(msgid)
|
||||
return gettext(msgid)
|
||||
end
|
||||
|
||||
-- return data structure for script_manager
|
||||
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("geo toolbox"),
|
||||
purpose = _("geodata tools"),
|
||||
author = "Tobias Jakobs",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/geoToolbox"
|
||||
}
|
||||
|
||||
script_data.destroy = nil -- function to destory the script
|
||||
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil
|
||||
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
|
||||
|
||||
-- Tell gettext where to find the .mo file translating messages for a particular domain
|
||||
gettext.bindtextdomain("geoToolbox",dt.configuration.config_dir.."/lua/locale/")
|
||||
|
||||
local function _(msgid)
|
||||
return gettext.dgettext("geoToolbox", msgid)
|
||||
end
|
||||
script_data.show = nil -- only required for libs since the destroy_method only hides them
|
||||
|
||||
|
||||
local gT = {}
|
||||
@@ -55,21 +61,21 @@ gT.event_registered = false
|
||||
|
||||
-- <GUI>
|
||||
local labelDistance = dt.new_widget("label")
|
||||
labelDistance.label = _("Distance:")
|
||||
labelDistance.label = _("distance:")
|
||||
|
||||
local label_copy_gps_lat = dt.new_widget("check_button")
|
||||
{
|
||||
label = _("latitude:"),
|
||||
label = _("latitude: "),
|
||||
value = true
|
||||
}
|
||||
local label_copy_gps_lon = dt.new_widget("check_button")
|
||||
{
|
||||
label = _("longitude:"),
|
||||
label = _("longitude: "),
|
||||
value = true
|
||||
}
|
||||
local label_copy_gps_ele = dt.new_widget("check_button")
|
||||
{
|
||||
label = _("elevation:"),
|
||||
label = _("elevation: "),
|
||||
value = true
|
||||
}
|
||||
-- </GUI>
|
||||
@@ -161,7 +167,7 @@ local function get_first_coordinate()
|
||||
first_elevation = ''
|
||||
first_image_date = 0
|
||||
|
||||
for _,image in ipairs(sel_images) do
|
||||
for jj,image in ipairs(sel_images) do
|
||||
if not image then
|
||||
first_have_data = false
|
||||
else
|
||||
@@ -200,7 +206,7 @@ local function get_second_coordinate()
|
||||
second_elevation = ''
|
||||
second_image_date = 0
|
||||
|
||||
for _,image in ipairs(sel_images) do
|
||||
for jj,image in ipairs(sel_images) do
|
||||
if not image then
|
||||
second_have_data = false
|
||||
else
|
||||
@@ -236,7 +242,7 @@ local calc_in_between_slider = dt.new_widget("slider")
|
||||
--ToDo: this needs more love
|
||||
local function calc_in_between()
|
||||
local sel_images = dt.gui.action_images
|
||||
for _,image in ipairs(sel_images) do
|
||||
for jj,image in ipairs(sel_images) do
|
||||
if image then
|
||||
image_date = make_time_stamp(image.exif_datetime_taken)
|
||||
if (first_have_data and second_have_data) then
|
||||
@@ -283,7 +289,7 @@ local function copy_gps()
|
||||
copy_gps_longitude = ''
|
||||
copy_gps_elevation = ''
|
||||
|
||||
for _,image in ipairs(sel_images) do
|
||||
for jj,image in ipairs(sel_images) do
|
||||
if not image then
|
||||
copy_gps_have_data = false
|
||||
else
|
||||
@@ -300,7 +306,7 @@ local function copy_gps()
|
||||
end
|
||||
|
||||
label_copy_gps_lat.label = _("latitude: ") .. copy_gps_latitude
|
||||
label_copy_gps_lon.label = _("longitude: ") ..copy_gps_longitude
|
||||
label_copy_gps_lon.label = _("longitude: ") .. copy_gps_longitude
|
||||
label_copy_gps_ele.label = _("elevation: ") .. copy_gps_elevation
|
||||
|
||||
return
|
||||
@@ -310,7 +316,7 @@ end
|
||||
local function paste_gps(image)
|
||||
local sel_images = dt.gui.action_images
|
||||
|
||||
for _,image in ipairs(sel_images) do
|
||||
for jj,image in ipairs(sel_images) do
|
||||
if (label_copy_gps_lat.value) then
|
||||
image.latitude = copy_gps_latitude
|
||||
end
|
||||
@@ -337,7 +343,7 @@ local function open_location_in_gnome_maps()
|
||||
local i = 0;
|
||||
|
||||
-- Use the first image with geo information
|
||||
for _,image in ipairs(sel_images) do
|
||||
for jj,image in ipairs(sel_images) do
|
||||
if ((image.longitude and image.latitude) and
|
||||
(image.longitude ~= 0 and image.latitude ~= 90) -- Sometimes the north-pole but most likely just wrong data
|
||||
) then
|
||||
@@ -364,12 +370,12 @@ end
|
||||
local function reverse_geocode()
|
||||
|
||||
if not df.check_if_bin_exists("curl") then
|
||||
dt.print_error(_("curl not found"))
|
||||
dt.print_error("curl not found")
|
||||
return
|
||||
end
|
||||
|
||||
if not df.check_if_bin_exists("jq") then
|
||||
dt.print_error(_("jq not found"))
|
||||
dt.print_error("jq not found")
|
||||
return
|
||||
end
|
||||
|
||||
@@ -380,7 +386,7 @@ local function reverse_geocode()
|
||||
local i = 0;
|
||||
|
||||
-- Use the first image with geo information
|
||||
for _,image in ipairs(sel_images) do
|
||||
for jj,image in ipairs(sel_images) do
|
||||
if ((image.longitude and image.latitude) and
|
||||
(image.longitude ~= 0 and image.latitude ~= 90) -- Sometimes the north-pole but most likely just wrong data
|
||||
) then
|
||||
@@ -455,7 +461,7 @@ local function calc_distance()
|
||||
|
||||
local sel_images = dt.gui.selection()
|
||||
|
||||
for _,image in ipairs(sel_images) do
|
||||
for jj,image in ipairs(sel_images) do
|
||||
if ((image.longitude and image.latitude) and
|
||||
(image.longitude ~= 0 and image.latitude ~= 90) -- Sometimes the north-pole but most likely just wrong data
|
||||
) then
|
||||
@@ -487,12 +493,12 @@ local function calc_distance()
|
||||
|
||||
if (distance < 1) then
|
||||
distance = distance * 1000
|
||||
distanceUnit = _("m")
|
||||
distanceUnit = "m"
|
||||
else
|
||||
distanceUnit = _("km")
|
||||
distanceUnit = "km"
|
||||
end
|
||||
|
||||
return string.format(_("Distance: %.2f %s"), distance, distanceUnit)
|
||||
return string.format(_("distance: %.2f %s"), distance, distanceUnit)
|
||||
end
|
||||
|
||||
local function print_calc_distance()
|
||||
@@ -515,12 +521,12 @@ local altitude_filename = dt.new_widget("entry")
|
||||
text = "altitude.csv",
|
||||
placeholder = "altitude.csv",
|
||||
editable = true,
|
||||
tooltip = _("Name of the exported file"),
|
||||
tooltip = _("name of the exported file"),
|
||||
reset_callback = function(self) self.text = "text" end
|
||||
}
|
||||
|
||||
local function altitude_profile()
|
||||
dt.print(_("Start export"))
|
||||
dt.print(_("start export"))
|
||||
local sel_images = dt.gui.action_images
|
||||
|
||||
local lat1 = 0;
|
||||
@@ -539,7 +545,7 @@ local function altitude_profile()
|
||||
local elevationAdd = 0;
|
||||
|
||||
local sel_images = dt.gui.action_images
|
||||
for _,image in ipairs(sel_images) do
|
||||
for jj,image in ipairs(sel_images) do
|
||||
if ((not isnan(image.longitude) and not isnan(image.latitude) and not isnan(image.elevation) and image.elevation) and
|
||||
(image.longitude ~= 0 and image.latitude ~= 90) -- Sometimes the north-pole but most likely just wrong data
|
||||
) then
|
||||
@@ -581,7 +587,7 @@ local function altitude_profile()
|
||||
file = io.open(exportDirectory.."/"..exportFilename, "w")
|
||||
file:write(csv_file)
|
||||
file:close()
|
||||
dt.print(_("File created in ")..exportDirectory)
|
||||
dt.print(string.format(_("file created in %s"), exportDirectory))
|
||||
|
||||
end
|
||||
|
||||
@@ -589,7 +595,7 @@ local function install_module()
|
||||
if not gT.module_installed then
|
||||
dt.register_lib(
|
||||
"geoToolbox", -- Module name
|
||||
"geo toolbox", -- name
|
||||
_("geo toolbox"), -- name
|
||||
true, -- expandable
|
||||
false, -- resetable
|
||||
{[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, -- containers
|
||||
@@ -611,14 +617,14 @@ end
|
||||
|
||||
local function restart()
|
||||
dt.register_event("geoToolbox_cd", "shortcut",
|
||||
print_calc_distance, _("Calculate the distance from latitude and longitude in km"))
|
||||
print_calc_distance, _("calculate the distance from latitude and longitude in km"))
|
||||
dt.register_event("geoToolbox", "mouse-over-image-changed",
|
||||
toolbox_calc_distance)
|
||||
|
||||
dt.register_event("geoToolbox_wg", "shortcut",
|
||||
select_with_gps, _("Select all images with GPS information"))
|
||||
select_with_gps, _("select all images with GPS information"))
|
||||
dt.register_event("geoToolbox_ng", "shortcut",
|
||||
select_without_gps, _("Select all images without GPS information"))
|
||||
select_without_gps, _("select all images without GPS information"))
|
||||
|
||||
dt.gui.libs["geoToolbox"].visible = true
|
||||
end
|
||||
@@ -641,20 +647,20 @@ gT.widget = dt.new_widget("box")
|
||||
dt.new_widget("button")
|
||||
{
|
||||
label = _("select geo images"),
|
||||
tooltip = _("Select all images with GPS information"),
|
||||
tooltip = _("select all images with GPS information"),
|
||||
clicked_callback = select_with_gps
|
||||
},
|
||||
dt.new_widget("button")
|
||||
{
|
||||
label = _("select non-geo images"),
|
||||
tooltip = _("Select all images without GPS information"),
|
||||
tooltip = _("select all images without GPS information"),
|
||||
clicked_callback = select_without_gps
|
||||
},
|
||||
separator,--------------------------------------------------------
|
||||
dt.new_widget("button")
|
||||
{
|
||||
label = _("copy GPS data"),
|
||||
tooltip = _("Copy GPS data"),
|
||||
tooltip = _("copy GPS data"),
|
||||
clicked_callback = copy_gps
|
||||
},
|
||||
label_copy_gps_lat,
|
||||
@@ -663,7 +669,7 @@ gT.widget = dt.new_widget("box")
|
||||
dt.new_widget("button")
|
||||
{
|
||||
label = _("paste GPS data"),
|
||||
tooltip = _("Paste GPS data"),
|
||||
tooltip = _("paste GPS data"),
|
||||
clicked_callback = paste_gps
|
||||
},
|
||||
separator2,--------------------------------------------------------
|
||||
@@ -693,14 +699,14 @@ gT.widget = dt.new_widget("box")
|
||||
dt.new_widget("button")
|
||||
{
|
||||
label = _("open in Gnome Maps"),
|
||||
tooltip = _("Open location in Gnome Maps"),
|
||||
tooltip = _("open location in Gnome Maps"),
|
||||
clicked_callback = open_location_in_gnome_maps
|
||||
},
|
||||
separator4,--------------------------------------------------------
|
||||
dt.new_widget("button")
|
||||
{
|
||||
label = _("reverse geocode"),
|
||||
tooltip = _("This just shows the name of the location, but doesn't add it as tag"),
|
||||
tooltip = _("this just shows the name of the location, but doesn't add it as tag"),
|
||||
clicked_callback = reverse_geocode
|
||||
},
|
||||
separator5,--------------------------------------------------------
|
||||
@@ -710,7 +716,7 @@ gT.widget = dt.new_widget("box")
|
||||
dt.new_widget("button")
|
||||
{
|
||||
label = _("export altitude CSV file"),
|
||||
tooltip = _("Create an altitude profile using the GPS data in the metadata"),
|
||||
tooltip = _("create an altitude profile using the GPS data in the metadata"),
|
||||
clicked_callback = altitude_profile
|
||||
},
|
||||
labelDistance
|
||||
@@ -738,19 +744,19 @@ dt.preferences.register("geoToolbox",
|
||||
"mapBoxKey",
|
||||
"string",
|
||||
_("geoToolbox export: MapBox Key"),
|
||||
_("https://www.mapbox.com/studio/account/tokens"),
|
||||
"https://www.mapbox.com/studio/account/tokens",
|
||||
'' )
|
||||
|
||||
-- Register
|
||||
dt.register_event("geoToolbox_cd", "shortcut",
|
||||
print_calc_distance, _("Calculate the distance from latitude and longitude in km"))
|
||||
print_calc_distance, _("calculate the distance from latitude and longitude in km"))
|
||||
dt.register_event("geoToolbox", "mouse-over-image-changed",
|
||||
toolbox_calc_distance)
|
||||
|
||||
dt.register_event("geoToolbox_wg", "shortcut",
|
||||
select_with_gps, _("Select all images with GPS information"))
|
||||
select_with_gps, _("select all images with GPS information"))
|
||||
dt.register_event("geoToolbox_ng", "shortcut",
|
||||
select_without_gps, _("Select all images without GPS information"))
|
||||
select_without_gps, _("select all images without GPS information"))
|
||||
|
||||
script_data.destroy = destroy
|
||||
script_data.restart = restart
|
||||
|
||||
@@ -69,25 +69,30 @@ local dt = require "darktable"
|
||||
local du = require "lib/dtutils"
|
||||
local df = require "lib/dtutils.file"
|
||||
local dtsys = require "lib/dtutils.system"
|
||||
local gettext = dt.gettext
|
||||
local gettext = dt.gettext.gettext
|
||||
local gimp_widget = nil
|
||||
|
||||
du.check_min_api_version("7.0.0", "gimp")
|
||||
|
||||
local function _(msgid)
|
||||
return gettext(msgid)
|
||||
end
|
||||
|
||||
-- return data structure for script_manager
|
||||
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("edit with GIMP"),
|
||||
purpose = _("export and edit with GIMP"),
|
||||
author = "Bill Ferguson <wpferguson@gmail.com>",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/gimp"
|
||||
}
|
||||
|
||||
script_data.destroy = nil -- function to destory the script
|
||||
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil
|
||||
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
|
||||
|
||||
-- Tell gettext where to find the .mo file translating messages for a particular domain
|
||||
gettext.bindtextdomain("gimp",dt.configuration.config_dir.."/lua/locale/")
|
||||
|
||||
local function _(msgid)
|
||||
return gettext.dgettext("gimp", msgid)
|
||||
end
|
||||
script_data.show = nil -- only required for libs since the destroy_method only hides them
|
||||
|
||||
local function group_if_not_member(img, new_img)
|
||||
local image_table = img:get_group_members()
|
||||
@@ -108,7 +113,7 @@ end
|
||||
|
||||
local function show_status(storage, image, format, filename,
|
||||
number, total, high_quality, extra_data)
|
||||
dt.print(string.format(_("Export Image %i/%i"), number, total))
|
||||
dt.print(string.format(_("export image %i/%i"), number, total))
|
||||
end
|
||||
|
||||
local function gimp_edit(storage, image_table, extra_data) --finalize
|
||||
@@ -118,7 +123,7 @@ local function gimp_edit(storage, image_table, extra_data) --finalize
|
||||
local gimp_executable = df.check_if_bin_exists("gimp")
|
||||
|
||||
if not gimp_executable then
|
||||
dt.print_error(_("GIMP not found"))
|
||||
dt.print_error("GIMP not found")
|
||||
return
|
||||
end
|
||||
|
||||
@@ -141,7 +146,7 @@ local function gimp_edit(storage, image_table, extra_data) --finalize
|
||||
img_list = img_list ..exp_img.. " "
|
||||
end
|
||||
|
||||
dt.print(_("Launching GIMP..."))
|
||||
dt.print(_("launching GIMP..."))
|
||||
|
||||
local gimpStartCommand
|
||||
gimpStartCommand = gimp_executable .. " " .. img_list
|
||||
@@ -212,7 +217,7 @@ gimp_widget = dt.new_widget("check_button"){
|
||||
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)
|
||||
|
||||
--
|
||||
script_data.destroy = destroy
|
||||
|
||||
@@ -25,24 +25,29 @@ For each source folder, a separate <trk> is generated in the gpx file.
|
||||
local dt = require "darktable"
|
||||
local df = require "lib/dtutils.file"
|
||||
local dl = require "lib/dtutils"
|
||||
local gettext = dt.gettext
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
dl.check_min_api_version("7.0.0", "gpx_export")
|
||||
|
||||
local function _(msgid)
|
||||
return gettext(msgid)
|
||||
end
|
||||
|
||||
-- return data structure for script_manager
|
||||
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("gpx export"),
|
||||
purpose = _("export gpx information to a file"),
|
||||
author = "Jannis_V",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/gpx_export"
|
||||
}
|
||||
|
||||
script_data.destroy = nil -- function to destory the script
|
||||
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil
|
||||
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
|
||||
|
||||
-- Tell gettext where to find the .mo file translating messages for a particular domain
|
||||
gettext.bindtextdomain("gpx_export",dt.configuration.config_dir.."/lua/locale/")
|
||||
|
||||
local function _(msgid)
|
||||
return gettext.dgettext("gpx_export", msgid)
|
||||
end
|
||||
script_data.show = nil -- only required for libs since the destroy_method only hides them
|
||||
|
||||
local gpx = {}
|
||||
gpx.module_installed = false
|
||||
@@ -131,11 +136,11 @@ local function create_gpx_file()
|
||||
|
||||
local file = io.open(path, "w")
|
||||
if (file == nil) then
|
||||
dt.print(_("invalid path: ")..path)
|
||||
dt.print(string.format(_("invalid path: %s"), path))
|
||||
else
|
||||
file:write(gpx_file)
|
||||
file:close()
|
||||
dt.print(_("gpx file created: ")..path)
|
||||
dt.print(string.format(_("gpx file created: "), path))
|
||||
end
|
||||
end
|
||||
|
||||
@@ -143,7 +148,7 @@ local function install_module()
|
||||
if not gpx.module_installed then
|
||||
dt.register_lib(
|
||||
"gpx_exporter",
|
||||
"gpx export",
|
||||
_("gpx export"),
|
||||
true, -- expandable
|
||||
true, -- resetable
|
||||
{[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, -- containers
|
||||
@@ -203,5 +208,6 @@ end
|
||||
script_data.destroy = destroy
|
||||
script_data.restart = restart
|
||||
script_data.destroy_method = "hide"
|
||||
script_data.show = restart
|
||||
|
||||
return script_data
|
||||
|
||||
@@ -32,17 +32,28 @@ USAGE
|
||||
|
||||
local dt = require "darktable"
|
||||
local du = require "lib/dtutils"
|
||||
local gettext = dt.gettext
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
du.check_min_api_version("2.0.0", "harmonic_armature_guide")
|
||||
|
||||
-- Tell gettext where to find the .mo file translating messages for a particular domain
|
||||
gettext.bindtextdomain("harmonic_armature_guide",dt.configuration.config_dir.."/lua/locale/")
|
||||
|
||||
local function _(msgid)
|
||||
return gettext.dgettext("harmonic_armature_guide", msgid)
|
||||
return gettext(msgid)
|
||||
end
|
||||
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("harmonic armature guide"),
|
||||
purpose = _("harmonic artmature guide"),
|
||||
author = "Hubert Kowalski",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/harmonic_armature_guide"
|
||||
}
|
||||
|
||||
script_data.destroy = nil -- function to destory the script
|
||||
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil
|
||||
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
|
||||
script_data.show = nil -- only required for libs since the destroy_method only hides them
|
||||
|
||||
dt.guides.register_guide("harmonic armature",
|
||||
-- draw
|
||||
function(cairo, x, y, width, height, zoom_scale)
|
||||
@@ -76,3 +87,11 @@ function()
|
||||
return dt.new_widget("label"){label = _("harmonic armature"), halign = "start"}
|
||||
end
|
||||
)
|
||||
|
||||
local function destroy()
|
||||
-- nothing to destroy
|
||||
end
|
||||
|
||||
script_data.destroy = destroy
|
||||
|
||||
return script_data
|
||||
|
||||
200
contrib/hif_group_leader.lua
Normal file
200
contrib/hif_group_leader.lua
Normal file
@@ -0,0 +1,200 @@
|
||||
--[[
|
||||
|
||||
hif_group_leader.lua - Make hif image group leader
|
||||
|
||||
Copyright (C) 2024 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/>.
|
||||
]]
|
||||
--[[
|
||||
hif_group_leader - Make hif image group leader
|
||||
|
||||
After a film roll is imported, check for RAW-JPG image groups
|
||||
and make the JPG image the group leader. This is on by default
|
||||
but can be disabled in preferences.
|
||||
|
||||
Shortcuts are included to filter existing collections or
|
||||
selections of images and make the hif the group leader.
|
||||
|
||||
ADDITIONAL SOFTWARE NEEDED FOR THIS SCRIPT
|
||||
None
|
||||
|
||||
USAGE
|
||||
Start script from script_manager
|
||||
Assign keys to the shortcuts
|
||||
|
||||
BUGS, COMMENTS, SUGGESTIONS
|
||||
Bill Ferguson <wpferguson@gmail.com>
|
||||
|
||||
CHANGES
|
||||
]]
|
||||
|
||||
local dt = require "darktable"
|
||||
local du = require "lib/dtutils"
|
||||
local df = require "lib/dtutils.file"
|
||||
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- C O N S T A N T S
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
local MODULE = "hif_group_leader"
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- A P I C H E C K
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
du.check_min_api_version("7.0.0", MODULE)
|
||||
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- I 1 8 N
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
local function _(msgid)
|
||||
return gettext(msgid)
|
||||
end
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- S C R I P T M A N A G E R I N T E G R A T I O N
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("HIF group leader"),
|
||||
purpose = _("make hif image group leader"),
|
||||
author = "Bill Ferguson <wpferguson@gmail.com>",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/hif_group_leader"
|
||||
}
|
||||
|
||||
script_data.destroy = nil -- function to destory the script
|
||||
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet
|
||||
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
|
||||
script_data.show = nil -- only required for libs since the destroy_method only hides them
|
||||
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- P R E F E R E N C E S
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
dt.preferences.register(MODULE, "on_import", "bool", _("make hif group leader on import"), _("automatically make the hif file the group leader when raw + hif are imported"), true)
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- N A M E S P A C E
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
local jgloi = {}
|
||||
jgloi.images = {}
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- F U N C T I O N S
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
local function toggle_global_toolbox_grouping()
|
||||
dt.gui.libs.global_toolbox.grouping = false
|
||||
dt.gui.libs.global_toolbox.grouping = true
|
||||
end
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- M A I N P R O G R A M
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
local function make_hif_group_leader(images)
|
||||
-- if the image is part of a group, make it the leader
|
||||
for _, image in ipairs(images) do
|
||||
if #image:get_group_members() > 1 then
|
||||
image:make_group_leader()
|
||||
end
|
||||
end
|
||||
if dt.gui.libs.global_toolbox.grouping then
|
||||
-- toggle the grouping to make the new leader show
|
||||
toggle_global_toolbox_grouping()
|
||||
end
|
||||
end
|
||||
|
||||
local function make_existing_hif_group_leader(images)
|
||||
for _, image in ipairs(images) do
|
||||
if string.lower(df.get_filetype(image.filename)) == "hif" then
|
||||
if #image:get_group_members() > 1 then
|
||||
image:make_group_leader()
|
||||
end
|
||||
end
|
||||
end
|
||||
if dt.gui.libs.global_toolbox.grouping then
|
||||
-- toggle the grouping to make the new leader show
|
||||
toggle_global_toolbox_grouping()
|
||||
end
|
||||
end
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- D A R K T A B L E I N T E G R A T I O N
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
local function destroy()
|
||||
if dt.preferences.read(MODULE, "on_import", "bool") then
|
||||
dt.destroy_event(MODULE, "post-import-film")
|
||||
dt.destroy_event(MODULE, "post-import-image")
|
||||
end
|
||||
dt.destroy_event(MODULE .. "_collect", "shortcut")
|
||||
dt.destroy_event(MODULE .. "_select", "shortcut")
|
||||
end
|
||||
|
||||
script_data.destroy = destroy
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- E V E N T S
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
if dt.preferences.read(MODULE, "on_import", "bool") then
|
||||
dt.register_event(MODULE, "post-import-film",
|
||||
function(event, film_roll)
|
||||
-- ignore the film roll, it contains all the images, not just the imported
|
||||
local images = jgloi.images
|
||||
if #images > 0 then
|
||||
jgloi.images = {}
|
||||
make_hif_group_leader(images)
|
||||
end
|
||||
end
|
||||
)
|
||||
|
||||
dt.register_event(MODULE, "post-import-image",
|
||||
function(event, image)
|
||||
if string.lower(df.get_filetype(image.filename)) == "hif" then
|
||||
table.insert(jgloi.images, image)
|
||||
end
|
||||
end
|
||||
)
|
||||
end
|
||||
|
||||
dt.register_event(MODULE .. "_collect", "shortcut",
|
||||
function(event, shortcut)
|
||||
-- ignore the film roll, it contains all the images, not just the imported
|
||||
local images = dt.collection
|
||||
make_existing_hif_group_leader(images)
|
||||
end,
|
||||
_("make hif group leader for collection")
|
||||
)
|
||||
|
||||
dt.register_event(MODULE .. "_select", "shortcut",
|
||||
function(event, shortcut)
|
||||
local images = dt.gui.selection()
|
||||
make_existing_hif_group_leader(images)
|
||||
end,
|
||||
_("make hif group leader for selection")
|
||||
)
|
||||
|
||||
return script_data
|
||||
@@ -40,7 +40,7 @@ local du = require "lib/dtutils"
|
||||
local df = require "lib/dtutils.file"
|
||||
local log = require "lib/dtutils.log"
|
||||
local dtsys = require "lib/dtutils.system"
|
||||
local gettext = dt.gettext
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
local namespace = 'module_hugin'
|
||||
local user_pref_str = 'prefer_gui'
|
||||
@@ -56,20 +56,25 @@ local PQ = dt.configuration.running_os == "windows" and '"' or "'"
|
||||
-- works with darktable API version from 5.0.0 on
|
||||
du.check_min_api_version("7.0.0", "hugin")
|
||||
|
||||
local function _(msgid)
|
||||
return gettext(msgid)
|
||||
end
|
||||
|
||||
-- return data structure for script_manager
|
||||
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("hugin"),
|
||||
purpose = _("stitch images into a panorama"),
|
||||
author = "Wolfgang Goetz",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/hugin"
|
||||
}
|
||||
|
||||
script_data.destroy = nil -- function to destory the script
|
||||
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil
|
||||
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
|
||||
|
||||
-- Tell gettext where to find the .mo file translating messages for a particular domain
|
||||
gettext.bindtextdomain("hugin",dt.configuration.config_dir.."/lua/locale/")
|
||||
|
||||
local function _(msgid)
|
||||
return gettext.dgettext("hugin", msgid)
|
||||
end
|
||||
script_data.show = nil -- only required for libs since the destroy_method only hides them
|
||||
|
||||
local function user_preference_changed(widget)
|
||||
user_prefer_gui = widget.value
|
||||
@@ -78,7 +83,7 @@ end
|
||||
|
||||
local function show_status(storage, image, format, filename,
|
||||
number, total, high_quality, extra_data)
|
||||
dt.print("exporting to hugin: "..tostring(number).."/"..tostring(total))
|
||||
dt.print(string.format(_("exporting to hugin: %d / %d"), number, total))
|
||||
end
|
||||
|
||||
local function create_panorama(storage, image_table, extra_data) --finalize
|
||||
@@ -139,7 +144,7 @@ local function create_panorama(storage, image_table, extra_data) --finalize
|
||||
end
|
||||
|
||||
if first_file == nil then
|
||||
dt.print("no file selected")
|
||||
dt.print(_("no file selected"))
|
||||
return
|
||||
end
|
||||
|
||||
@@ -200,7 +205,7 @@ local function create_panorama(storage, image_table, extra_data) --finalize
|
||||
if df.check_if_file_exists(src_path) then
|
||||
log.msg(log.debug, "found ", src_path, " importing to ", dst_path)
|
||||
df.file_move(src_path, dst_path)
|
||||
dt.print(_("importing file "..dst_path))
|
||||
dt.print(string.format(_("importing file %s"), dst_path))
|
||||
dt.database.import(dst_path)
|
||||
end
|
||||
end
|
||||
@@ -226,7 +231,7 @@ hugin_widget = dt.new_widget("box") {
|
||||
orientation = "vertical",
|
||||
dt.new_widget("check_button")
|
||||
{
|
||||
label = _(" launch hugin gui"),
|
||||
label = _("launch hugin gui"),
|
||||
value = user_prefer_gui,
|
||||
tooltip = _('launch hugin in gui mode'),
|
||||
clicked_callback = user_preference_changed
|
||||
|
||||
@@ -64,7 +64,7 @@ local dt = require "darktable"
|
||||
local du = require "lib/dtutils"
|
||||
local df = require "lib/dtutils.file"
|
||||
local dtsys = require "lib/dtutils.system"
|
||||
local gettext = dt.gettext
|
||||
local gettext = dt.gettext.gettext
|
||||
local job = nil
|
||||
|
||||
-- path separator constant
|
||||
@@ -73,20 +73,25 @@ local PS = dt.configuration.running_os == "windows" and "\\" or "/"
|
||||
-- works with LUA API version 5.0.0
|
||||
du.check_min_api_version("7.0.0", "image_stack")
|
||||
|
||||
local function _(msgid)
|
||||
return gettext(msgid)
|
||||
end
|
||||
|
||||
-- return data structure for script_manager
|
||||
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("image stack"),
|
||||
purpose = _("process a stack of images"),
|
||||
author = "Bill Ferguson <wpferguson@gmail.com>",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/image_stack"
|
||||
}
|
||||
|
||||
script_data.destroy = nil -- function to destory the script
|
||||
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil
|
||||
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
|
||||
|
||||
-- Tell gettext where to find the .mo file translating messages for a particular domain
|
||||
gettext.bindtextdomain("image_stack",dt.configuration.config_dir.."/lua/locale/")
|
||||
|
||||
local function _(msgid)
|
||||
return gettext.dgettext("image_stack", msgid)
|
||||
end
|
||||
script_data.show = nil -- only required for libs since the destroy_method only hides them
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- GUI definitions
|
||||
@@ -134,19 +139,19 @@ local chkbtn_will_align = dt.new_widget("check_button"){
|
||||
local chkbtn_radial_distortion = dt.new_widget("check_button"){
|
||||
label = _('optimize radial distortion for all images'),
|
||||
value = dt.preferences.read("align_image_stack", "def_radial_distortion", "bool"),
|
||||
tooltip = _('optimize radial distortion for all images, \nexcept for first'),
|
||||
tooltip = _('optimize radial distortion for all images, \nexcept the first'),
|
||||
}
|
||||
|
||||
local chkbtn_optimize_field = dt.new_widget("check_button"){
|
||||
label = _('optimize field of view for all images'),
|
||||
value = dt.preferences.read("align_image_stack", "def_optimize_field", "bool"),
|
||||
tooltip =_('optimize field of view for all images, except for first. \nUseful for aligning focus stacks (DFF) with slightly \ndifferent magnification.'),
|
||||
tooltip =_('optimize field of view for all images, except the first. \nUseful for aligning focus stacks (DFF) with slightly \ndifferent magnification.'),
|
||||
}
|
||||
|
||||
local chkbtn_optimize_image_center = dt.new_widget("check_button"){
|
||||
label = _('optimize image center shift for all images'),
|
||||
value = dt.preferences.read("align_image_stack", "def_optimize_image_center", "bool"),
|
||||
tooltip =_('optimize image center shift for all images, \nexcept for first.'),
|
||||
tooltip =_('optimize image center shift for all images, \nexcept the first.'),
|
||||
}
|
||||
|
||||
local chkbtn_auto_crop = dt.new_widget("check_button"){
|
||||
@@ -258,7 +263,7 @@ end
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
local function show_status(storage, image, format, filename, number, total, high_quality, extra_data)
|
||||
dt.print(string.format(_("Export Image %i/%i"), number, total))
|
||||
dt.print(string.format(_("export image %i/%i"), number, total))
|
||||
end
|
||||
|
||||
-- read the gui and populate the align_image_stack arguments
|
||||
@@ -451,7 +456,7 @@ local function copy_image_attributes(from, to, ...)
|
||||
to.rights = from.rights
|
||||
to.description = from.description
|
||||
else
|
||||
dt.print_error(_("Unrecognized option to copy_image_attributes: " .. arg))
|
||||
dt.print_error("Unrecognized option to copy_image_attributes: " .. arg)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -495,11 +500,11 @@ local function image_stack(storage, image_table, extra_data)
|
||||
|
||||
if image_count < 2 then
|
||||
dt.print(_("ERROR: at least 2 images required for image stacking, exiting..."))
|
||||
dt.print_error(_(image_count .. " image(s) selected, at least 2 required"))
|
||||
dt.print_error(image_count .. " image(s) selected, at least 2 required")
|
||||
return
|
||||
end
|
||||
|
||||
job = dt.gui.create_job("image stack", true, stop_job)
|
||||
job = dt.gui.create_job(_("image stack"), true, stop_job)
|
||||
job.percent = job.percent + percent_step
|
||||
|
||||
-- align images if requested
|
||||
@@ -519,13 +524,13 @@ local function image_stack(storage, image_table, extra_data)
|
||||
job.percent = job.percent + percent_step
|
||||
else
|
||||
dt.print(_("ERROR: image alignment failed"))
|
||||
dt.print_error(_("image alignment failed"))
|
||||
dt.print_error("image alignment failed")
|
||||
cleanup(img_list)
|
||||
return
|
||||
end
|
||||
else
|
||||
dt.print(_("ERROR: align_image_stack not found"))
|
||||
dt.print_error(_("align_image_stack not found"))
|
||||
dt.print_error("align_image_stack not found")
|
||||
cleanup(img_list)
|
||||
return
|
||||
end
|
||||
@@ -539,7 +544,7 @@ local function image_stack(storage, image_table, extra_data)
|
||||
local ignore_tif_tags = " -quiet -define tiff:ignore-tags=40965,42032,42033,42034,42036,18246,18249,36867,34864,34866 "
|
||||
if convert_executable then
|
||||
local convert_command = convert_executable .. ignore_tif_tags .. convert_arguments
|
||||
dt.print_log(_("convert command is " .. convert_command))
|
||||
dt.print_log("convert command is " .. convert_command)
|
||||
dt.print(_("processing image stack"))
|
||||
local result = dtsys.external_command(convert_command)
|
||||
if result == 0 then
|
||||
@@ -553,7 +558,7 @@ local function image_stack(storage, image_table, extra_data)
|
||||
local import_filename = df.create_unique_filename(film_roll_path .. PS .. df.get_filename(output_filename))
|
||||
df.file_move(output_filename, import_filename)
|
||||
imported_image = dt.database.import(import_filename)
|
||||
local created_tag = dt.tags.create(_("Created with|image_stack"))
|
||||
local created_tag = dt.tags.create(_("created with|image_stack"))
|
||||
dt.tags.attach(created_tag, imported_image)
|
||||
-- all the images are the same except for time, so just copy the attributes
|
||||
-- from the first
|
||||
@@ -567,7 +572,7 @@ local function image_stack(storage, image_table, extra_data)
|
||||
|
||||
if tag_source then
|
||||
dt.print(_("tagging source images"))
|
||||
local source_tag = dt.tags.create(_("Source file|" .. imported_image.filename))
|
||||
local source_tag = dt.tags.create(_("source file|" .. imported_image.filename))
|
||||
for img, _ in pairs(image_table) do
|
||||
dt.tags.attach(source_tag, img)
|
||||
end
|
||||
@@ -579,7 +584,7 @@ local function image_stack(storage, image_table, extra_data)
|
||||
end
|
||||
else
|
||||
dt.print(_("ERROR: convert executable not found"))
|
||||
dt.print_error(_("convert executable not found"))
|
||||
dt.print_error("convert executable not found")
|
||||
cleanup(img_list)
|
||||
end
|
||||
job.valid = false
|
||||
@@ -591,7 +596,7 @@ end
|
||||
|
||||
dt.preferences.register("align_image_stack", "align_use_gpu", -- name
|
||||
"bool", -- type
|
||||
_('align image stack: use GPU for remaping'), -- label
|
||||
_('align image stack: use GPU for remapping'), -- label
|
||||
_('set the GPU remapping for image align'), -- tooltip
|
||||
false)
|
||||
|
||||
|
||||
@@ -107,7 +107,8 @@ 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 dtsys = require "lib/dtutils.system"
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
local img_time = {}
|
||||
img_time.module_installed = false
|
||||
@@ -115,21 +116,27 @@ img_time.event_registered = false
|
||||
|
||||
du.check_min_api_version("7.0.0", "image_time")
|
||||
|
||||
local function _(msgid)
|
||||
return gettext(msgid)
|
||||
end
|
||||
|
||||
-- return data structure for script_manager
|
||||
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("image time"),
|
||||
purpose = _("synchronize image time for images shot with different cameras or adjust or set image time"),
|
||||
author = "Bill Ferguson <wpferguson@gmail.com>",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/image_time"
|
||||
}
|
||||
|
||||
script_data.destroy = nil -- function to destory the script
|
||||
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil
|
||||
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
|
||||
script_data.show = nil -- only required for libs since the destroy_method only hides them
|
||||
|
||||
|
||||
-- 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
|
||||
@@ -147,12 +154,12 @@ local function systime2exiftime(systime)
|
||||
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 " "
|
||||
local y = tonumber(year) and string.format("%4d", year) or "0000"
|
||||
local mo = tonumber(month) and string.format("%02d", month) or "00"
|
||||
local d = tonumber(day) and string.format("%02d", day) or "00"
|
||||
local h = tonumber(hour) and string.format("%02d", hour) or "00"
|
||||
local m = tonumber(min) and string.format("%02d", min) or "00"
|
||||
local s = tonumber(sec) and string.format("%02d", sec) or "00"
|
||||
return(y .. ":" .. mo .. ":" .. d .. " " .. h .. ":" .. m .. ":" .. s)
|
||||
end
|
||||
|
||||
@@ -174,7 +181,7 @@ local function calculate_difference(images)
|
||||
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"))
|
||||
dt.print(_("ERROR: 2 images must be selected"))
|
||||
end
|
||||
end
|
||||
|
||||
@@ -186,7 +193,7 @@ end
|
||||
|
||||
local function synchronize_time(images)
|
||||
local sign = 1
|
||||
if img_time.sdir.value == "subtract" then
|
||||
if img_time.sdir.value == _("subtract") then
|
||||
sign = -1
|
||||
end
|
||||
synchronize_times(images, tonumber(img_time.diff_entry.text) * sign)
|
||||
@@ -248,7 +255,7 @@ local function _get_windows_image_file_creation_time(image)
|
||||
end
|
||||
p:close()
|
||||
else
|
||||
dt.print(_("unable to get information for ") .. image.filename)
|
||||
dt.print(string.format(_("unable to get information for %s"), image.filename))
|
||||
datetime = ERROR
|
||||
end
|
||||
return datetime
|
||||
@@ -265,7 +272,7 @@ local function _get_nix_image_file_creation_time(image)
|
||||
end
|
||||
p:close()
|
||||
else
|
||||
dt.print(_("unable to get information for ") .. image.filename)
|
||||
dt.print(string.format(_("unable to get information for %s"), image.filename))
|
||||
datetime = ERROR
|
||||
end
|
||||
return datetime
|
||||
@@ -313,7 +320,7 @@ local function reset_time(images)
|
||||
image.exif_datetime_taken = get_original_image_time(image)
|
||||
end
|
||||
else
|
||||
dt.print_error(_("reset time: no images selected"))
|
||||
dt.print_error("reset time: no images selected")
|
||||
dt.print(_("please select the images that need their time reset"))
|
||||
end
|
||||
end
|
||||
@@ -429,8 +436,8 @@ end
|
||||
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},
|
||||
{"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},
|
||||
@@ -456,13 +463,13 @@ 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"),
|
||||
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"),
|
||||
label = _("calculate"),
|
||||
tooltip = _("calculate time difference between 2 images"),
|
||||
clicked_callback = function()
|
||||
calculate_difference(dt.gui.action_images)
|
||||
@@ -502,7 +509,7 @@ img_time.stack = dt.new_widget("stack"){
|
||||
dt.new_widget("box"){
|
||||
orientation = "vertical",
|
||||
dt.new_widget("label"){label = _("set time")},
|
||||
dt.new_widget("section_label"){label = _("date: ")},
|
||||
dt.new_widget("section_label"){label = _("date:")},
|
||||
img_time.sdy,
|
||||
img_time.smo,
|
||||
img_time.syr,
|
||||
|
||||
200
contrib/jpg_group_leader.lua
Normal file
200
contrib/jpg_group_leader.lua
Normal file
@@ -0,0 +1,200 @@
|
||||
--[[
|
||||
|
||||
jpg_group_leader.lua - Make jpg image group leader
|
||||
|
||||
Copyright (C) 2024 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/>.
|
||||
]]
|
||||
--[[
|
||||
jpg_group_leader - Make jpg image group leader
|
||||
|
||||
After a film roll is imported, check for RAW-JPG image groups
|
||||
and make the JPG image the group leader. This is on by default
|
||||
but can be disabled in preferences.
|
||||
|
||||
Shortcuts are included to filter existing collections or
|
||||
selections of images and make the jpg the group leader.
|
||||
|
||||
ADDITIONAL SOFTWARE NEEDED FOR THIS SCRIPT
|
||||
None
|
||||
|
||||
USAGE
|
||||
Start script from script_manager
|
||||
Assign keys to the shortcuts
|
||||
|
||||
BUGS, COMMENTS, SUGGESTIONS
|
||||
Bill Ferguson <wpferguson@gmail.com>
|
||||
|
||||
CHANGES
|
||||
]]
|
||||
|
||||
local dt = require "darktable"
|
||||
local du = require "lib/dtutils"
|
||||
local df = require "lib/dtutils.file"
|
||||
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- C O N S T A N T S
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
local MODULE = "jpg_group_leader"
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- A P I C H E C K
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
du.check_min_api_version("7.0.0", MODULE)
|
||||
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- I 1 8 N
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
local function _(msgid)
|
||||
return gettext(msgid)
|
||||
end
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- S C R I P T M A N A G E R I N T E G R A T I O N
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("JPG group leader"),
|
||||
purpose = _("make jpg image group leader"),
|
||||
author = "Bill Ferguson <wpferguson@gmail.com>",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/jpg_group_leader"
|
||||
}
|
||||
|
||||
script_data.destroy = nil -- function to destory the script
|
||||
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet
|
||||
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
|
||||
script_data.show = nil -- only required for libs since the destroy_method only hides them
|
||||
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- P R E F E R E N C E S
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
dt.preferences.register(MODULE, "on_import", "bool", _("make jpg group leader on import"), _("automatically make the jpg file the group leader when raw + jpg are imported"), true)
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- N A M E S P A C E
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
local jgloi = {}
|
||||
jgloi.images = {}
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- F U N C T I O N S
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
local function toggle_global_toolbox_grouping()
|
||||
dt.gui.libs.global_toolbox.grouping = false
|
||||
dt.gui.libs.global_toolbox.grouping = true
|
||||
end
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- M A I N P R O G R A M
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
local function make_jpg_group_leader(images)
|
||||
-- if the image is part of a group, make it the leader
|
||||
for _, image in ipairs(images) do
|
||||
if #image:get_group_members() > 1 then
|
||||
image:make_group_leader()
|
||||
end
|
||||
end
|
||||
if dt.gui.libs.global_toolbox.grouping then
|
||||
-- toggle the grouping to make the new leader show
|
||||
toggle_global_toolbox_grouping()
|
||||
end
|
||||
end
|
||||
|
||||
local function make_existing_jpg_group_leader(images)
|
||||
for _, image in ipairs(images) do
|
||||
if string.lower(df.get_filetype(image.filename)) == "jpg" then
|
||||
if #image:get_group_members() > 1 then
|
||||
image:make_group_leader()
|
||||
end
|
||||
end
|
||||
end
|
||||
if dt.gui.libs.global_toolbox.grouping then
|
||||
-- toggle the grouping to make the new leader show
|
||||
toggle_global_toolbox_grouping()
|
||||
end
|
||||
end
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- D A R K T A B L E I N T E G R A T I O N
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
local function destroy()
|
||||
if dt.preferences.read(MODULE, "on_import", "bool") then
|
||||
dt.destroy_event(MODULE, "post-import-film")
|
||||
dt.destroy_event(MODULE, "post-import-image")
|
||||
end
|
||||
dt.destroy_event(MODULE .. "_collect", "shortcut")
|
||||
dt.destroy_event(MODULE .. "_select", "shortcut")
|
||||
end
|
||||
|
||||
script_data.destroy = destroy
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- E V E N T S
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
if dt.preferences.read(MODULE, "on_import", "bool") then
|
||||
dt.register_event(MODULE, "post-import-film",
|
||||
function(event, film_roll)
|
||||
-- ignore the film roll, it contains all the images, not just the imported
|
||||
local images = jgloi.images
|
||||
if #images > 0 then
|
||||
jgloi.images = {}
|
||||
make_jpg_group_leader(images)
|
||||
end
|
||||
end
|
||||
)
|
||||
|
||||
dt.register_event(MODULE, "post-import-image",
|
||||
function(event, image)
|
||||
if string.lower(df.get_filetype(image.filename)) == "jpg" then
|
||||
table.insert(jgloi.images, image)
|
||||
end
|
||||
end
|
||||
)
|
||||
end
|
||||
|
||||
dt.register_event(MODULE .. "_collect", "shortcut",
|
||||
function(event, shortcut)
|
||||
-- ignore the film roll, it contains all the images, not just the imported
|
||||
local images = dt.collection
|
||||
make_existing_jpg_group_leader(images)
|
||||
end,
|
||||
_("make jpg group leader for collection")
|
||||
)
|
||||
|
||||
dt.register_event(MODULE .. "_select", "shortcut",
|
||||
function(event, shortcut)
|
||||
local images = dt.gui.selection()
|
||||
make_existing_jpg_group_leader(images)
|
||||
end,
|
||||
_("make jpg group leader for selection")
|
||||
)
|
||||
|
||||
return script_data
|
||||
@@ -39,29 +39,34 @@ local df = require "lib/dtutils.file"
|
||||
local ds = require "lib/dtutils.string"
|
||||
local dsys = require "lib/dtutils.system"
|
||||
|
||||
local gettext = dt.gettext
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
local PS = dt.configuration.running_os == "windows" and "\\" or "/"
|
||||
|
||||
du.check_min_api_version("7.0.0", "kml_export")
|
||||
|
||||
local function _(msgid)
|
||||
return gettext(msgid)
|
||||
end
|
||||
|
||||
-- return data structure for script_manager
|
||||
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("kml export"),
|
||||
purpose = _("export KML/KMZ data to a file"),
|
||||
author = "Tobias Jakobs",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/kml_export"
|
||||
}
|
||||
|
||||
script_data.destroy = nil -- function to destory the script
|
||||
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil
|
||||
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
|
||||
|
||||
-- Tell gettext where to find the .mo file translating messages for a particular domain
|
||||
gettext.bindtextdomain("kml_export",dt.configuration.config_dir.."/lua/locale/")
|
||||
|
||||
local function _(msgid)
|
||||
return gettext.dgettext("kml_export", msgid)
|
||||
end
|
||||
script_data.show = nil -- only required for libs since the destroy_method only hides them
|
||||
|
||||
local function show_status(storage, image, format, filename, number, total, high_quality, extra_data)
|
||||
dt.print(string.format(_("Export Image %i/%i"), number, total))
|
||||
dt.print(string.format(_("export image %i/%i"), number, total))
|
||||
end
|
||||
|
||||
-- Add duplicate index to filename
|
||||
@@ -88,12 +93,12 @@ local function create_kml_file(storage, image_table, extra_data)
|
||||
end
|
||||
|
||||
if not df.check_if_bin_exists(magickPath) then
|
||||
dt.print_error(_("magick not found"))
|
||||
dt.print_error("magick not found")
|
||||
return
|
||||
end
|
||||
if dt.configuration.running_os == "linux" then
|
||||
if not df.check_if_bin_exists("xdg-user-dir") then
|
||||
dt.print_error(_("xdg-user-dir not found"))
|
||||
dt.print_error("xdg-user-dir not found")
|
||||
return
|
||||
end
|
||||
end
|
||||
@@ -103,7 +108,7 @@ local function create_kml_file(storage, image_table, extra_data)
|
||||
if ( dt.preferences.read("kml_export","CreateKMZ","bool") == true
|
||||
and dt.configuration.running_os == "linux") then
|
||||
if not df.check_if_bin_exists("zip") then
|
||||
dt.print_error(_("zip not found"))
|
||||
dt.print_error("zip not found")
|
||||
return
|
||||
end
|
||||
exportDirectory = dt.configuration.tmp_dir
|
||||
@@ -319,14 +324,14 @@ if dt.configuration.running_os == "windows" then
|
||||
"OpenKmlFile",
|
||||
"bool",
|
||||
_("KML export: Open KML file after export"),
|
||||
_("Opens the KML file after the export with the standard program for KML files"),
|
||||
_("opens the KML file after the export with the standard program for KML files"),
|
||||
false )
|
||||
else
|
||||
dt.preferences.register("kml_export",
|
||||
"OpenKmlFile",
|
||||
"bool",
|
||||
_("KML export: Open KML/KMZ file after export"),
|
||||
_("Opens the KML file after the export with the standard program for KML files"),
|
||||
_("KML export: open KML/KMZ file after export"),
|
||||
_("opens the KML file after the export with the standard program for KML files"),
|
||||
false )
|
||||
end
|
||||
|
||||
@@ -345,23 +350,23 @@ end
|
||||
dt.preferences.register("kml_export",
|
||||
"ExportDirectory",
|
||||
"directory",
|
||||
_("KML export: Export directory"),
|
||||
_("A directory that will be used to export the KML/KMZ files"),
|
||||
_("KML export: export directory"),
|
||||
_("a directory that will be used to export the KML/KMZ files"),
|
||||
defaultDir )
|
||||
|
||||
if dt.configuration.running_os ~= "linux" then
|
||||
dt.preferences.register("kml_export",
|
||||
"magickPath", -- name
|
||||
"file", -- type
|
||||
_("KML export: ImageMagick binary Location"), -- label
|
||||
_("Install location of magick[.exe]. Requires restart to take effect."), -- tooltip
|
||||
_("KML export: ImageMagick binary location"), -- label
|
||||
_("install location of magick[.exe], requires restart to take effect"), -- tooltip
|
||||
"magick") -- default
|
||||
end
|
||||
|
||||
dt.preferences.register("kml_export",
|
||||
"CreatePath",
|
||||
"bool",
|
||||
_("KML export: Connect images with path"),
|
||||
_("KML export: connect images with path"),
|
||||
_("connect all images with a path"),
|
||||
false )
|
||||
|
||||
@@ -369,16 +374,16 @@ if dt.configuration.running_os == "linux" then
|
||||
dt.preferences.register("kml_export",
|
||||
"CreateKMZ",
|
||||
"bool",
|
||||
_("KML export: Create KMZ file"),
|
||||
_("Compress all imeges to one KMZ file"),
|
||||
_("KML export: create KMZ file"),
|
||||
_("compress all imeges to one KMZ file"),
|
||||
true )
|
||||
end
|
||||
|
||||
-- Register
|
||||
if dt.configuration.running_os == "windows" then
|
||||
dt.register_storage("kml_export", _("KML Export"), nil, create_kml_file)
|
||||
dt.register_storage("kml_export", _("KML export"), nil, create_kml_file)
|
||||
else
|
||||
dt.register_storage("kml_export", _("KML/KMZ Export"), nil, create_kml_file)
|
||||
dt.register_storage("kml_export", _("KML/KMZ export"), nil, create_kml_file)
|
||||
end
|
||||
|
||||
script_data.destroy = destroy
|
||||
|
||||
@@ -37,17 +37,28 @@ USAGE
|
||||
|
||||
local dt = require "darktable"
|
||||
local du = require "lib/dtutils"
|
||||
local gettext = dt.gettext
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
du.check_min_api_version("2.0.0", "passport_guide")
|
||||
|
||||
-- Tell gettext where to find the .mo file translating messages for a particular domain
|
||||
gettext.bindtextdomain("passport_guide",dt.configuration.config_dir.."/lua/locale/")
|
||||
|
||||
local function _(msgid)
|
||||
return gettext.dgettext("passport_guide", msgid)
|
||||
return gettext(msgid)
|
||||
end
|
||||
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("passport guide"),
|
||||
purpose = _("guides for cropping passport photos"),
|
||||
author = "Kåre Hampf",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/passport_guide"
|
||||
}
|
||||
|
||||
script_data.destroy = nil -- function to destory the script
|
||||
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil
|
||||
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
|
||||
script_data.show = nil -- only required for libs since the destroy_method only hides them
|
||||
|
||||
dt.guides.register_guide("passport",
|
||||
-- draw
|
||||
function(cairo, x, y, width, height, zoom_scale)
|
||||
@@ -91,5 +102,13 @@ function()
|
||||
end
|
||||
)
|
||||
|
||||
local function destroy()
|
||||
-- nothing to destroy
|
||||
end
|
||||
|
||||
script_data.destroy = destroy
|
||||
|
||||
return script_data
|
||||
|
||||
-- kate: tab-indents: off; indent-width 2; replace-tabs on; remove-trailing-space on; hl Lua;
|
||||
-- vim: shiftwidth=2 expandtab tabstop=2 cindent syntax=lua
|
||||
|
||||
125
contrib/passport_guide_germany.lua
Normal file
125
contrib/passport_guide_germany.lua
Normal file
@@ -0,0 +1,125 @@
|
||||
--[[
|
||||
German passport photo cropping guide for darktable.
|
||||
Derived from the passport cropping guide by Kåre Hampf.
|
||||
|
||||
copyright (c) 2017 Kåre Hampf
|
||||
copyright (c) 2024 Christian Sültrop
|
||||
|
||||
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/>.
|
||||
]]
|
||||
|
||||
--[[
|
||||
PASSPORT CROPPING GUIDE
|
||||
Guides for cropping passport and ID card ("Personalausweis") photos based on the "Passbild-Schablone"
|
||||
from the German Federal Ministry of the Interior and Community.
|
||||
(https://www.bmi.bund.de/SharedDocs/downloads/DE/veroeffentlichungen/themen/moderne-verwaltung/ausweise/passbild-schablone-erwachsene.pdf?__blob=publicationFile&v=3)
|
||||
|
||||
INSTALLATION
|
||||
* copy this file in $CONFIGDIR/lua/ where CONFIGDIR is your darktable configuration directory
|
||||
* add the following line in the file $CONFIGDIR/luarc
|
||||
require "passport_guide_germany"
|
||||
* (optional) add the line:
|
||||
"plugins/darkroom/clipping/extra_aspect_ratios/passport 35x45mm=45:35"
|
||||
to $CONFIGDIR/darktablerc
|
||||
|
||||
USAGE
|
||||
* when using the cropping tool, select "Passport Photo Germany" as guide and if you added the line in yout rc
|
||||
select "passport 35x45mm" as aspect
|
||||
]]
|
||||
|
||||
local dt = require "darktable"
|
||||
local du = require "lib/dtutils"
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
du.check_min_api_version("2.0.0", "passport_guide_germany")
|
||||
|
||||
-- Tell gettext where to find the .mo file translating messages for a particular domain
|
||||
local function _(msgid)
|
||||
return gettext(msgid)
|
||||
end
|
||||
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("passport guide Germany"),
|
||||
purpose = _("guides for cropping passport and ID card (\"Personalausweis\") photos based on the \"Passbild-Schablone\" from the German Federal Ministry of the Interior and Community"),
|
||||
author = "menschmachine",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/passport_guide_germany"
|
||||
}
|
||||
|
||||
script_data.destroy = nil -- function to destory the script
|
||||
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil
|
||||
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
|
||||
script_data.show = nil -- only required for libs since the destroy_method only hides them
|
||||
|
||||
dt.guides.register_guide("Passport Photo Germany",
|
||||
-- draw
|
||||
function(cairo, x, y, width, height, zoom_scale)
|
||||
local _width, _height
|
||||
|
||||
-- get the max 35x45 rectangle
|
||||
local aspect_ratio = 45 / 35
|
||||
if width * aspect_ratio > height then
|
||||
_width = height / aspect_ratio
|
||||
_height = height
|
||||
else
|
||||
_width = width
|
||||
_height = width * aspect_ratio
|
||||
end
|
||||
|
||||
cairo:save()
|
||||
|
||||
cairo:translate(x + (width - _width) / 2, y + (height - _height) / 2)
|
||||
cairo:scale(_width / 35, _height / 45)
|
||||
|
||||
-- the outer rectangle
|
||||
cairo:rectangle( 0, 0, 35, 45)
|
||||
|
||||
-- Nose position: The nose tip must be between these lines
|
||||
cairo:draw_line(15.5, 45, 15.5, 13)
|
||||
cairo:draw_line(35-15.5, 45, 35-15.5, 13)
|
||||
|
||||
-- Face height
|
||||
-- optimum face height: The upper end of the head should be between these lines
|
||||
cairo:draw_line(0, 4, 35, 4)
|
||||
cairo:draw_line(0, 8, 35, 8)
|
||||
|
||||
-- tolerated face height: The upper end of the head must not be below this line
|
||||
cairo:draw_line(6, 13, 30, 13)
|
||||
|
||||
-- Eye area: The eyes must be between these lines
|
||||
cairo:draw_line(0, 13, 35, 13)
|
||||
cairo:draw_line(0, 23, 35, 23)
|
||||
|
||||
-- Cheek line: The cheek must lie on this line
|
||||
cairo:draw_line(9, 45-5, 27, 45-5)
|
||||
|
||||
cairo:restore()
|
||||
end,
|
||||
-- gui
|
||||
function()
|
||||
return dt.new_widget("label"){label = _("Passport Photo Germany"), halign = "start"}
|
||||
end
|
||||
)
|
||||
|
||||
local function destroy()
|
||||
-- noting to destroy
|
||||
end
|
||||
|
||||
script_data.destroy = destroy
|
||||
|
||||
return script_data
|
||||
|
||||
-- kate: tab-indents: off; indent-width 2; replace-tabs on; remove-trailing-space on; hl Lua;
|
||||
-- vim: shiftwidth=2 expandtab tabstop=2 cindent syntax=lua
|
||||
@@ -42,17 +42,14 @@ local dt = require "darktable"
|
||||
local du = require "lib/dtutils"
|
||||
local df = require "lib/dtutils.file"
|
||||
|
||||
local gettext = dt.gettext
|
||||
|
||||
-- Tell gettext where to find the .mo file translating messages for a particular domain
|
||||
gettext.bindtextdomain("pdf_slideshow",dt.configuration.config_dir.."/lua/locale/")
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
local function _(msgid)
|
||||
return gettext.dgettext("pdf_slideshow", msgid)
|
||||
return gettext(msgid)
|
||||
end
|
||||
|
||||
if not df.check_if_bin_exists("pdflatex") then
|
||||
dt.print_error(_("pdflatex not found"))
|
||||
dt.print_error("pdflatex not found")
|
||||
return
|
||||
end
|
||||
|
||||
@@ -62,9 +59,17 @@ du.check_min_api_version("7.0.0", "pdf_slideshow")
|
||||
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("PDF slideshow"),
|
||||
purpose = _("generates a PDF slideshow (via Latex) containing all selected images one per slide"),
|
||||
author = "Pascal Obry",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/pdf_slideshow"
|
||||
}
|
||||
|
||||
script_data.destroy = nil -- function to destory the script
|
||||
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil
|
||||
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
|
||||
script_data.show = nil -- only required for libs since the destroy_method only hides them
|
||||
|
||||
dt.preferences.register
|
||||
("pdf_slideshow","open with","string",
|
||||
@@ -230,7 +235,7 @@ dt.register_storage("pdf_slideshow",_("pdf slideshow"),
|
||||
local result = dt.control.execute(command)
|
||||
if result ~= 0 then
|
||||
dt.print(_("problem running pdflatex")) -- this one is probably usefull to the user
|
||||
error(_("problem running ")..command)
|
||||
error("problem running "..command)
|
||||
end
|
||||
|
||||
-- open the PDF
|
||||
@@ -240,7 +245,7 @@ dt.register_storage("pdf_slideshow",_("pdf slideshow"),
|
||||
local result = dt.control.execute(command)
|
||||
if result ~= 0 then
|
||||
dt.print(_("problem running pdf viewer")) -- this one is probably usefull to the user
|
||||
error(_("problem running ")..command)
|
||||
error("problem running "..command)
|
||||
end
|
||||
|
||||
-- finally do some clean-up
|
||||
|
||||
@@ -44,19 +44,30 @@ local dtsys = require "lib/dtutils.system"
|
||||
local MODULE_NAME = "photils"
|
||||
du.check_min_api_version("7.0.0", MODULE_NAME)
|
||||
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
local function _(msgid)
|
||||
return gettext(msgid)
|
||||
end
|
||||
|
||||
-- return data structure for script_manager
|
||||
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("photils"),
|
||||
purpose = _("suggest tags based on image classification"),
|
||||
author = "Tobias Scheck",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/photils"
|
||||
}
|
||||
|
||||
script_data.destroy = nil -- function to destory the script
|
||||
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil
|
||||
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
|
||||
script_data.show = nil -- only required for libs since the destroy_method only hides them
|
||||
|
||||
|
||||
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
|
||||
@@ -65,10 +76,6 @@ 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
|
||||
@@ -177,7 +184,7 @@ function PHOTILS.image_changed()
|
||||
end
|
||||
|
||||
function PHOTILS.tagged_image_has_changed()
|
||||
GUI.warning.label = _("The suggested tags were not generated\n for the currently selected image!")
|
||||
GUI.warning.label = _("the suggested tags were not generated\n for the currently selected image!")
|
||||
end
|
||||
|
||||
function PHOTILS.paginate()
|
||||
@@ -234,7 +241,7 @@ end
|
||||
|
||||
function PHOTILS.attach_tags()
|
||||
local num_selected = #dt.gui.selection()
|
||||
local job = dt.gui.create_job(_("Apply tag to image"), true)
|
||||
local job = dt.gui.create_job(_("apply tag to image"), true)
|
||||
|
||||
for i = 1, num_selected, 1 do
|
||||
local image = dt.gui.selection()[i]
|
||||
@@ -246,7 +253,7 @@ function PHOTILS.attach_tags()
|
||||
job.percent = i / num_selected
|
||||
end
|
||||
|
||||
dt.print(_("Tags successfully attached to image"))
|
||||
dt.print(_("tags successfully attached to image"))
|
||||
job.valid = false
|
||||
end
|
||||
|
||||
@@ -312,11 +319,11 @@ function PHOTILS.on_tags_clicked()
|
||||
local images = dt.gui.selection()
|
||||
|
||||
if #images == 0 then
|
||||
dt.print(_("No image selected."))
|
||||
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.print(_("this plugin can only handle a single image."))
|
||||
dt.gui.selection({images[1]})
|
||||
dt.control.sleep(2000)
|
||||
end
|
||||
@@ -331,7 +338,7 @@ function PHOTILS.on_tags_clicked()
|
||||
end
|
||||
|
||||
if #PHOTILS.tags == 0 then
|
||||
local msg = string.format(_("no tags where found"), MODULE_NAME)
|
||||
local msg = string.format(_("no tags were found"), MODULE_NAME)
|
||||
GUI.warning_label.label = msg
|
||||
GUI.stack.active = GUI.error_view
|
||||
return
|
||||
@@ -386,7 +393,7 @@ end
|
||||
local function install_module()
|
||||
if not PHOTILS.module_installed then
|
||||
dt.register_lib(MODULE_NAME,
|
||||
"photils autotagger",
|
||||
_("photils auto-tagger"),
|
||||
true,
|
||||
true,
|
||||
PHOTILS.plugin_display_views,
|
||||
@@ -427,9 +434,9 @@ end
|
||||
|
||||
if not photils_installed then
|
||||
GUI.warning_label.label = _("photils-cli not found")
|
||||
dt.print_log(_("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.")
|
||||
GUI.warning_label.label = _("select an image, click \"get tags\" and get \nsuggestions for tags.")
|
||||
end
|
||||
|
||||
GUI.pagination = dt.new_widget("box") {
|
||||
@@ -472,9 +479,9 @@ 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."),
|
||||
_("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("photils", "mouse-over-image-changed",
|
||||
|
||||
@@ -49,10 +49,23 @@ local debug = require "darktable.debug"
|
||||
|
||||
du.check_min_api_version("7.0.0", "quicktag")
|
||||
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
local function _(msgid)
|
||||
return gettext(msgid)
|
||||
end
|
||||
|
||||
-- return data structure for script_manager
|
||||
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("quick tag"),
|
||||
purpose = _("use buttons to quickly apply tags assigned to them"),
|
||||
author = "Christian Kanzian",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/quicktag"
|
||||
}
|
||||
|
||||
script_data.destroy = nil -- function to destory the script
|
||||
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil
|
||||
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
|
||||
@@ -62,15 +75,6 @@ qt.module_installed = false
|
||||
qt.event_registered = false
|
||||
qt.widget_table = {}
|
||||
|
||||
local gettext = dt.gettext
|
||||
|
||||
-- Tell gettext where to find the .mo file translating messages for a particular domain
|
||||
gettext.bindtextdomain("quicktag",dt.configuration.config_dir.."/lua/locale/")
|
||||
|
||||
local function _(msgid)
|
||||
return gettext.dgettext("quicktag", msgid)
|
||||
end
|
||||
|
||||
-- maximum length of button labels
|
||||
dt.preferences.register("quickTag",
|
||||
"labellength",
|
||||
@@ -193,7 +197,7 @@ local function install_module()
|
||||
if not qt.module_installed then
|
||||
dt.register_lib(
|
||||
"quicktag", -- Module name
|
||||
"quicktag", -- name
|
||||
_("quick tag"), -- name
|
||||
true, -- expandable
|
||||
false, -- resetable
|
||||
{[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 490}},
|
||||
@@ -300,7 +304,7 @@ end
|
||||
for i=1,qnr do
|
||||
dt.register_event("quicktag " .. tostring(i), "shortcut",
|
||||
function(event, shortcut) tagattach(tostring(quicktag_table[i])) end,
|
||||
string.format(_("quicktag %i"),i))
|
||||
string.format(_("quick tag %i"),i))
|
||||
end
|
||||
|
||||
script_data.destroy = destroy
|
||||
|
||||
@@ -44,13 +44,27 @@ local du = require "lib/dtutils"
|
||||
-- added version check
|
||||
du.check_min_api_version("7.0.0", "rate_group")
|
||||
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
local function _(msgid)
|
||||
return gettext(msgid)
|
||||
end
|
||||
|
||||
-- return data structure for script_manager
|
||||
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("rate group"),
|
||||
purpose = _("rate all images in a group"),
|
||||
author = "Dom H (dom@hxy.io)",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/rate_group"
|
||||
}
|
||||
|
||||
script_data.destroy = nil -- function to destory the script
|
||||
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil
|
||||
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
|
||||
script_data.show = nil -- only required for libs since the destroy_method only hides them
|
||||
|
||||
local function apply_rating(rating)
|
||||
local images = dt.gui.action_images
|
||||
@@ -61,9 +75,9 @@ local function apply_rating(rating)
|
||||
end
|
||||
end
|
||||
if rating < 0 then
|
||||
dt.print("rejecting group(s)")
|
||||
dt.print(_("rejecting group(s)"))
|
||||
else
|
||||
dt.print("applying rating " ..rating.. " to group(s)")
|
||||
dt.print(string.format(_("applying rating %d to group(s)"), rating))
|
||||
end
|
||||
end
|
||||
|
||||
@@ -80,37 +94,38 @@ end
|
||||
dt.register_event("rg_reject", "shortcut",
|
||||
function(event, shortcut)
|
||||
apply_rating(-1)
|
||||
end, "Reject group")
|
||||
end, _("reject group"))
|
||||
|
||||
dt.register_event("rg0", "shortcut",
|
||||
function(event, shortcut)
|
||||
apply_rating(0)
|
||||
end, "Rate group 0")
|
||||
end, string.format(_("rate group %d"), 0)
|
||||
)
|
||||
|
||||
dt.register_event("rg1", "shortcut",
|
||||
function(event, shortcut)
|
||||
apply_rating(1)
|
||||
end, "Rate group 1")
|
||||
end, string.format(_("rate group %d"), 1))
|
||||
|
||||
dt.register_event("rg2", "shortcut",
|
||||
function(event, shortcut)
|
||||
apply_rating(2)
|
||||
end, "Rate group 2")
|
||||
end, string.format(_("rate group %d"), 2))
|
||||
|
||||
dt.register_event("rg3", "shortcut",
|
||||
function(event, shortcut)
|
||||
apply_rating(3)
|
||||
end, "Rate group 3")
|
||||
end, string.format(_("rate group %d"), 3))
|
||||
|
||||
dt.register_event("rg4", "shortcut",
|
||||
function(event, shortcut)
|
||||
apply_rating(4)
|
||||
end, "Rate group 4")
|
||||
end, string.format(_("rate group %d"), 4))
|
||||
|
||||
dt.register_event("rg5", "shortcut",
|
||||
function(event, shortcut)
|
||||
apply_rating(5)
|
||||
end, "Rate group 5")
|
||||
end, string.format(_("rate group %d"), 5))
|
||||
|
||||
script_data.destroy = destroy
|
||||
|
||||
|
||||
@@ -36,21 +36,35 @@ local debug = require "darktable.debug"
|
||||
du.check_min_api_version("7.0.0", "rename-tags")
|
||||
du.deprecated("contrib/rename-tags.lua","darktable release 4.0")
|
||||
|
||||
local gettext = darktable.gettext.gettext
|
||||
|
||||
local function _(msgid)
|
||||
return gettext(msgid)
|
||||
end
|
||||
|
||||
-- return data structure for script_manager
|
||||
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("rename tags"),
|
||||
purpose = _("rename an existing tag"),
|
||||
author = "Sebastian Witt (se.witt@gmx.net)",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/rename-tags"
|
||||
}
|
||||
|
||||
script_data.destroy = nil -- function to destory the script
|
||||
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil
|
||||
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
|
||||
script_data.show = nil -- only required for libs since the destroy_method only hides them
|
||||
|
||||
local rt = {}
|
||||
rt.module_installed = false
|
||||
rt.event_registered = false
|
||||
|
||||
-- GUI entries
|
||||
local old_tag = darktable.new_widget("entry") { tooltip = "Enter old tag" }
|
||||
local new_tag = darktable.new_widget("entry") { tooltip = "Enter new tag" }
|
||||
local old_tag = darktable.new_widget("entry") { tooltip = _("enter old tag") }
|
||||
local new_tag = darktable.new_widget("entry") { tooltip = _("enter new tag") }
|
||||
|
||||
local function rename_reset()
|
||||
old_tag.text = ''
|
||||
@@ -61,11 +75,11 @@ end
|
||||
local function rename_tags()
|
||||
-- If entries are empty, return
|
||||
if old_tag.text == '' then
|
||||
darktable.print ("Old tag can't be empty")
|
||||
darktable.print (_("old tag can't be empty"))
|
||||
return
|
||||
end
|
||||
if new_tag.text == '' then
|
||||
darktable.print ("New tag can't be empty")
|
||||
darktable.print (_("new tag can't be empty"))
|
||||
return
|
||||
end
|
||||
|
||||
@@ -75,12 +89,12 @@ local function rename_tags()
|
||||
local ot = darktable.tags.find (old_tag.text)
|
||||
|
||||
if not ot then
|
||||
darktable.print ("Old tag does not exist")
|
||||
darktable.print (_("old tag does not exist"))
|
||||
return
|
||||
end
|
||||
|
||||
-- Show job
|
||||
local job = darktable.gui.create_job ("Renaming tag", true)
|
||||
local job = darktable.gui.create_job (_("renaming tag"), true)
|
||||
|
||||
old_tag.editable = false
|
||||
new_tag.editable = false
|
||||
@@ -103,7 +117,7 @@ local function rename_tags()
|
||||
darktable.tags.delete (ot)
|
||||
|
||||
job.valid = false
|
||||
darktable.print ("Renamed tags for " .. count .. " images")
|
||||
darktable.print (string.format(_("renamed tags for %d images"), count))
|
||||
old_tag.editable = true
|
||||
new_tag.editable = true
|
||||
|
||||
@@ -114,7 +128,7 @@ 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)
|
||||
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
|
||||
@@ -130,13 +144,13 @@ end
|
||||
-- GUI
|
||||
local old_widget = darktable.new_widget ("box") {
|
||||
orientation = "horizontal",
|
||||
darktable.new_widget("label") { label = "Old tag" },
|
||||
darktable.new_widget("label") { label = _("old tag") },
|
||||
old_tag
|
||||
}
|
||||
|
||||
local new_widget = darktable.new_widget ("box") {
|
||||
orientation = "horizontal",
|
||||
darktable.new_widget("label") { label = "New tag" },
|
||||
darktable.new_widget("label") { label = _("new tag") },
|
||||
new_tag
|
||||
}
|
||||
|
||||
@@ -145,7 +159,7 @@ rt.rename_widget = darktable.new_widget ("box") {
|
||||
reset_callback = rename_reset,
|
||||
old_widget,
|
||||
new_widget,
|
||||
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
|
||||
|
||||
@@ -43,27 +43,19 @@
|
||||
local dt = require "darktable"
|
||||
local du = require "lib/dtutils"
|
||||
local df = require "lib/dtutils.file"
|
||||
local ds = require "lib/dtutils.string"
|
||||
|
||||
du.check_min_api_version("7.0.0", "rename_images")
|
||||
|
||||
local gettext = dt.gettext
|
||||
|
||||
-- Tell gettext where to find the .mo file translating messages for a particular domain
|
||||
gettext.bindtextdomain("rename_images",dt.configuration.config_dir.."/lua/locale/")
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
local function _(msgid)
|
||||
return gettext.dgettext("rename_images", msgid)
|
||||
return gettext(msgid)
|
||||
end
|
||||
|
||||
-- namespace variable
|
||||
local rename = {
|
||||
presets = {},
|
||||
substitutes = {},
|
||||
placeholders = {"ROLL_NAME","FILE_FOLDER","FILE_NAME","FILE_EXTENSION","ID","VERSION","SEQUENCE","YEAR","MONTH","DAY",
|
||||
"HOUR","MINUTE","SECOND","EXIF_YEAR","EXIF_MONTH","EXIF_DAY","EXIF_HOUR","EXIF_MINUTE","EXIF_SECOND",
|
||||
"STARS","LABELS","MAKER","MODEL","TITLE","CREATOR","PUBLISHER","RIGHTS","USERNAME","PICTURES_FOLDER",
|
||||
"HOME","DESKTOP","EXIF_ISO","EXIF_EXPOSURE","EXIF_EXPOSURE_BIAS","EXIF_APERTURE","EXIF_FOCUS_DISTANCE",
|
||||
"EXIF_FOCAL_LENGTH","LONGITUDE","LATITUDE","ELEVATION","LENS","DESCRIPTION","EXIF_CROP"},
|
||||
widgets = {},
|
||||
}
|
||||
rename.module_installed = false
|
||||
@@ -72,9 +64,17 @@ rename.event_registered = false
|
||||
-- script_manager integration
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("rename images"),
|
||||
purpose = _("rename an image file or files"),
|
||||
author = "Bill Ferguson <wpferguson@gmail.com>",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/rename_images"
|
||||
}
|
||||
|
||||
script_data.destroy = nil -- function to destory the script
|
||||
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil
|
||||
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
|
||||
script_data.show = nil -- only required for libs since the destroy_method only hides them
|
||||
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
@@ -85,90 +85,13 @@ local MODULE_NAME = "rename_images"
|
||||
local PS = dt.configuration.running_os == "windows" and "\\" or "/"
|
||||
local USER = os.getenv("USERNAME")
|
||||
local HOME = os.getenv(dt.configuration.running_os == "windows" and "HOMEPATH" or "HOME")
|
||||
local PICTURES = HOME .. PS .. dt.configuration.running_os == "windows" and "My Pictures" or "Pictures"
|
||||
local PICTURES = HOME .. PS .. dt.configuration.running_os == "windows" and _("My Pictures") or _("Pictures")
|
||||
local DESKTOP = HOME .. PS .. "Desktop"
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- F U N C T I O N S
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
local function build_substitution_list(image, sequence, datetime, username, pic_folder, home, desktop)
|
||||
-- build the argument substitution list from each image
|
||||
-- local datetime = os.date("*t")
|
||||
local colorlabels = {}
|
||||
if image.red then table.insert(colorlabels, "red") end
|
||||
if image.yellow then table.insert(colorlabels, "yellow") end
|
||||
if image.green then table.insert(colorlabels, "green") end
|
||||
if image.blue then table.insert(colorlabels, "blue") end
|
||||
if image.purple then table.insert(colorlabels, "purple") end
|
||||
local labels = #colorlabels == 1 and colorlabels[1] or du.join(colorlabels, ",")
|
||||
local eyear,emon,eday,ehour,emin,esec = string.match(image.exif_datetime_taken, "(%d-):(%d-):(%d-) (%d-):(%d-):(%d-)$")
|
||||
local replacements = {image.film,
|
||||
image.path,
|
||||
df.get_filename(image.filename),
|
||||
string.upper(df.get_filetype(image.filename)),
|
||||
image.id,image.duplicate_index,
|
||||
string.format("%04d", sequence),
|
||||
datetime.year,
|
||||
string.format("%02d", datetime.month),
|
||||
string.format("%02d", datetime.day),
|
||||
string.format("%02d", datetime.hour),
|
||||
string.format("%02d", datetime.min),
|
||||
string.format("%02d", datetime.sec),
|
||||
eyear,
|
||||
emon,
|
||||
eday,
|
||||
ehour,
|
||||
emin,
|
||||
esec,
|
||||
image.rating,
|
||||
labels,
|
||||
image.exif_maker,
|
||||
image.exif_model,
|
||||
image.title,
|
||||
image.creator,
|
||||
image.publisher,
|
||||
image.rights,
|
||||
username,
|
||||
pic_folder,
|
||||
home,
|
||||
desktop,
|
||||
image.exif_iso,
|
||||
image.exif_exposure,
|
||||
image.exif_exposure_bias,
|
||||
image.exif_aperture,
|
||||
image.exif_focus_distance,
|
||||
image.exif_focal_length,
|
||||
image.longitude,
|
||||
image.latitude,
|
||||
image.elevation,
|
||||
image.exif_lens,
|
||||
image.description,
|
||||
image.exif_crop
|
||||
}
|
||||
|
||||
for i=1,#rename.placeholders,1 do rename.substitutes[rename.placeholders[i]] = replacements[i] end
|
||||
end
|
||||
|
||||
local function substitute_list(str)
|
||||
-- replace the substitution variables in a string
|
||||
for match in string.gmatch(str, "%$%(.-%)") do
|
||||
local var = string.match(match, "%$%((.-)%)")
|
||||
if rename.substitutes[var] then
|
||||
str = string.gsub(str, "%$%("..var.."%)", rename.substitutes[var])
|
||||
else
|
||||
dt.print_error(_("unrecognized variable " .. var))
|
||||
dt.print(_("unknown variable " .. var .. ", aborting..."))
|
||||
return -1
|
||||
end
|
||||
end
|
||||
return str
|
||||
end
|
||||
|
||||
local function clear_substitute_list()
|
||||
for i=1,#rename.placeholders,1 do rename.substitutes[rename.placeholders[i]] = nil end
|
||||
end
|
||||
|
||||
local function stop_job(job)
|
||||
job.valid = false
|
||||
end
|
||||
@@ -207,9 +130,10 @@ end
|
||||
|
||||
local function do_rename(images)
|
||||
if #images > 0 then
|
||||
local first_image = images[1]
|
||||
local pattern = rename.widgets.pattern.text
|
||||
dt.preferences.write(MODULE_NAME, "pattern", "string", pattern)
|
||||
dt.print_log(_("pattern is " .. pattern))
|
||||
dt.print_log("pattern is " .. pattern)
|
||||
if string.len(pattern) > 0 then
|
||||
local datetime = os.date("*t")
|
||||
|
||||
@@ -217,14 +141,14 @@ local function do_rename(images)
|
||||
for i, image in ipairs(images) do
|
||||
if job.valid then
|
||||
job.percent = i / #images
|
||||
build_substitution_list(image, i, datetime, USER, PICTURES, HOME, DESKTOP)
|
||||
local new_name = substitute_list(pattern)
|
||||
ds.build_substitute_list(image, i, pattern, USER, PICTURES, HOME, DESKTOP)
|
||||
local new_name = ds.substitute_list(pattern)
|
||||
if new_name == -1 then
|
||||
dt.print(_("unable to do variable substitution, exiting..."))
|
||||
stop_job(job)
|
||||
return
|
||||
end
|
||||
clear_substitute_list()
|
||||
ds.clear_substitute_list()
|
||||
local args = {}
|
||||
local path = string.sub(df.get_path(new_name), 1, -2)
|
||||
if string.len(path) == 0 then
|
||||
@@ -249,7 +173,8 @@ local function do_rename(images)
|
||||
stop_job(job)
|
||||
local collect_rules = dt.gui.libs.collect.filter()
|
||||
dt.gui.libs.collect.filter(collect_rules)
|
||||
dt.print(_("renamed " .. #images .. " images"))
|
||||
dt.gui.views.lighttable.set_image_visible(first_image)
|
||||
dt.print(string.format(_("renamed %d images"), #images))
|
||||
else -- pattern length
|
||||
dt.print_error("no pattern supplied, returning...")
|
||||
dt.print(_("please enter the new name or pattern"))
|
||||
@@ -269,50 +194,8 @@ end
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
rename.widgets.pattern = dt.new_widget("entry"){
|
||||
tooltip = _("$(ROLL_NAME) - film roll name\n") ..
|
||||
_("$(FILE_FOLDER) - image file folder\n") ..
|
||||
_("$(FILE_NAME) - image file name\n") ..
|
||||
_("$(FILE_EXTENSION) - image file extension\n") ..
|
||||
_("$(ID) - image id\n") ..
|
||||
_("$(VERSION) - version number\n") ..
|
||||
_("$(SEQUENCE) - sequence number of selection\n") ..
|
||||
_("$(YEAR) - current year\n") ..
|
||||
_("$(MONTH) - current month\n") ..
|
||||
_("$(DAY) - current day\n") ..
|
||||
_("$(HOUR) - current hour\n") ..
|
||||
_("$(MINUTE) - current minute\n") ..
|
||||
_("$(SECOND) - current second\n") ..
|
||||
_("$(EXIF_YEAR) - EXIF year\n") ..
|
||||
_("$(EXIF_MONTH) - EXIF month\n") ..
|
||||
_("$(EXIF_DAY) - EXIF day\n") ..
|
||||
_("$(EXIF_HOUR) - EXIF hour\n") ..
|
||||
_("$(EXIF_MINUTE) - EXIF minute\n") ..
|
||||
_("$(EXIF_SECOND) - EXIF seconds\n") ..
|
||||
_("$(EXIF_ISO) - EXIF ISO\n") ..
|
||||
_("$(EXIF_EXPOSURE) - EXIF exposure\n") ..
|
||||
_("$(EXIF_EXPOSURE_BIAS) - EXIF exposure bias\n") ..
|
||||
_("$(EXIF_APERTURE) - EXIF aperture\n") ..
|
||||
_("$(EXIF_FOCAL_LENGTH) - EXIF focal length\n") ..
|
||||
_("$(EXIF_FOCUS_DISTANCE) - EXIF focus distance\n") ..
|
||||
_("$(EXIF_CROP) - EXIF crop\n") ..
|
||||
_("$(LONGITUDE) - longitude\n") ..
|
||||
_("$(LATITUDE) - latitude\n") ..
|
||||
_("$(ELEVATION) - elevation\n") ..
|
||||
_("$(STARS) - star rating\n") ..
|
||||
_("$(LABELS) - color labels\n") ..
|
||||
_("$(MAKER) - camera maker\n") ..
|
||||
_("$(MODEL) - camera model\n") ..
|
||||
_("$(LENS) - lens\n") ..
|
||||
_("$(TITLE) - title from metadata\n") ..
|
||||
_("$(DESCRIPTION) - description from metadata\n") ..
|
||||
_("$(CREATOR) - creator from metadata\n") ..
|
||||
_("$(PUBLISHER) - publisher from metadata\n") ..
|
||||
_("$(RIGHTS) - rights from metadata\n") ..
|
||||
_("$(USERNAME) - username\n") ..
|
||||
_("$(PICTURES_FOLDER) - pictures folder\n") ..
|
||||
_("$(HOME) - user's home directory\n") ..
|
||||
_("$(DESKTOP) - desktop directory"),
|
||||
placeholder = _("enter pattern $(FILE_FOLDER)/$(FILE_NAME)"),
|
||||
tooltip = ds.get_substitution_tooltip(),
|
||||
placeholder = _("enter pattern") .. "$(FILE_FOLDER)/$(FILE_NAME)",
|
||||
text = ""
|
||||
}
|
||||
|
||||
|
||||
84
contrib/select_non_existing.lua
Normal file
84
contrib/select_non_existing.lua
Normal file
@@ -0,0 +1,84 @@
|
||||
--[[
|
||||
This file is part of darktable,
|
||||
copyright (c) 2023 Dirk Dittmar
|
||||
|
||||
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/>.
|
||||
]]
|
||||
--[[
|
||||
Enable selection of non-existing images in the the currently worked on images, e.g. the ones selected by the collection module.
|
||||
]]
|
||||
|
||||
local dt = require "darktable"
|
||||
local du = require "lib/dtutils"
|
||||
local df = require "lib/dtutils.file"
|
||||
|
||||
-- module name
|
||||
local MODULE = "select_non_existing"
|
||||
|
||||
du.check_min_api_version("9.1.0", MODULE)
|
||||
|
||||
-- figure out the path separator
|
||||
local PS = dt.configuration.running_os == "windows" and "\\" or "/"
|
||||
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
local function _(msgid)
|
||||
return gettext(msgid)
|
||||
end
|
||||
|
||||
local function stop_job(job)
|
||||
job.valid = false
|
||||
end
|
||||
|
||||
local function select_nonexisting_images(event, images)
|
||||
local selection = {}
|
||||
|
||||
local job = dt.gui.create_job(_("select non existing images"), true, stop_job)
|
||||
for key,image in ipairs(images) do
|
||||
if(job.valid) then
|
||||
job.percent = (key - 1)/#images
|
||||
local filepath = image.path..PS..image.filename
|
||||
local file_exists = df.test_file(filepath, "e")
|
||||
dt.print_log(filepath.." exists? => "..tostring(file_exists))
|
||||
if (not file_exists) then
|
||||
table.insert(selection, image)
|
||||
end
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
stop_job(job)
|
||||
|
||||
return selection
|
||||
end
|
||||
|
||||
local function destroy()
|
||||
dt.gui.libs.select.destroy_selection(MODULE)
|
||||
end
|
||||
|
||||
dt.gui.libs.select.register_selection(
|
||||
MODULE,
|
||||
_("select non existing"),
|
||||
select_nonexisting_images,
|
||||
_("select all non-existing images in the current images"))
|
||||
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("select non existing"),
|
||||
purpose = _("enable selection of non-existing images"),
|
||||
author = "Dirk Dittmar",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/select_non_existing"
|
||||
}
|
||||
|
||||
script_data.destroy = destroy
|
||||
return script_data
|
||||
@@ -20,24 +20,29 @@ Enable selection of untagged images (darktable|* tags are ignored)
|
||||
|
||||
local dt = require "darktable"
|
||||
local du = require "lib/dtutils"
|
||||
local gettext = dt.gettext
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
du.check_min_api_version("7.0.0", "select_untagged")
|
||||
|
||||
local function _(msgid)
|
||||
return gettext(msgid)
|
||||
end
|
||||
|
||||
-- return data structure for script_manager
|
||||
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("select untagged"),
|
||||
purpose = _("enable selection of untagged images"),
|
||||
author = "Jannis_V",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/select_untagged"
|
||||
}
|
||||
|
||||
script_data.destroy = nil -- function to destory the script
|
||||
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil
|
||||
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
|
||||
|
||||
-- Tell gettext where to find the .mo file translating messages for a particular domain
|
||||
gettext.bindtextdomain("select_untagged",dt.configuration.config_dir.."/lua/locale/")
|
||||
|
||||
local function _(msgid)
|
||||
return gettext.dgettext("select_untagged", msgid)
|
||||
end
|
||||
script_data.show = nil -- only required for libs since the destroy_method only hides them
|
||||
|
||||
local function stop_job(job)
|
||||
job.valid = false
|
||||
|
||||
@@ -27,24 +27,29 @@ USAGE
|
||||
local dt = require "darktable"
|
||||
local du = require "lib/dtutils"
|
||||
local df = require "lib/dtutils.file"
|
||||
local gettext = dt.gettext
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
du.check_min_api_version("7.0.0", "slideshowMusic")
|
||||
|
||||
local function _(msgid)
|
||||
return gettext(msgid)
|
||||
end
|
||||
|
||||
-- return data structure for script_manager
|
||||
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("slideshow music"),
|
||||
purpose = _("play music during a slideshow"),
|
||||
author = "Tobias Jakobs",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/slideshowMusic"
|
||||
}
|
||||
|
||||
script_data.destroy = nil -- function to destory the script
|
||||
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil
|
||||
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
|
||||
|
||||
-- Tell gettext where to find the .mo file translating messages for a particular domain
|
||||
gettext.bindtextdomain("slideshowMusic",dt.configuration.config_dir.."/lua/locale/")
|
||||
|
||||
local function _(msgid)
|
||||
return gettext.dgettext("slideshowMusic", msgid)
|
||||
end
|
||||
script_data.show = nil -- only required for libs since the destroy_method only hides them
|
||||
|
||||
local function playSlideshowMusic(_, old_view, new_view)
|
||||
local filename, playMusic
|
||||
@@ -53,7 +58,7 @@ local function playSlideshowMusic(_, old_view, new_view)
|
||||
playMusic = dt.preferences.read("slideshowMusic","PlaySlideshowMusic","bool")
|
||||
|
||||
if not df.check_if_bin_exists("rhythmbox-client") then
|
||||
dt.print_error(_("rhythmbox-client not found"))
|
||||
dt.print_error("rhythmbox-client not found")
|
||||
return
|
||||
end
|
||||
|
||||
@@ -69,7 +74,7 @@ local function playSlideshowMusic(_, old_view, new_view)
|
||||
if (old_view and old_view.id == "slideshow") then
|
||||
stopCommand = "rhythmbox-client --pause"
|
||||
--dt.print_error(stopCommand)
|
||||
dt.control.execute( stopCommand)
|
||||
dt.control.execute(stopCommand)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -82,12 +87,12 @@ function destroy()
|
||||
end
|
||||
|
||||
-- Preferences
|
||||
dt.preferences.register("slideshowMusic", "SlideshowMusic", "file", _("Slideshow background music file"), "", "")
|
||||
dt.preferences.register("slideshowMusic", "SlideshowMusic", "file", _("slideshow background music file"), "", "")
|
||||
dt.preferences.register("slideshowMusic",
|
||||
"PlaySlideshowMusic",
|
||||
"bool",
|
||||
_("Play slideshow background music"),
|
||||
_("Plays music with rhythmbox if a slideshow starts"),
|
||||
_("play slideshow background music"),
|
||||
_("plays music with rhythmbox if a slideshow starts"),
|
||||
true)
|
||||
-- Register
|
||||
dt.register_event("slideshow_music", "view-changed",
|
||||
|
||||
@@ -76,17 +76,30 @@ local darktable = require("darktable")
|
||||
local dtutils = require("lib/dtutils")
|
||||
local dtutils_file = require("lib/dtutils.file")
|
||||
local dtutils_system = require("lib/dtutils.system")
|
||||
local gettext = darktable.gettext.gettext
|
||||
|
||||
local LIB_ID = "transfer_hierarchy"
|
||||
dtutils.check_min_api_version("7.0.0", LIB_ID)
|
||||
|
||||
local function _(msgid)
|
||||
return gettext(msgid)
|
||||
end
|
||||
|
||||
-- return data structure for script_manager
|
||||
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("transfer hierarchy"),
|
||||
purpose = _("allows the moving or copying of images from one directory tree to another, while preserving the existing hierarchy"),
|
||||
author = "August Schwerdfeger (august@schwerdfeger.name)",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/transfer_hierarchy"
|
||||
}
|
||||
|
||||
script_data.destroy = nil -- function to destory the script
|
||||
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil
|
||||
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
|
||||
script_data.show = nil -- only required for libs since the destroy_method only hides them
|
||||
|
||||
local MKDIR_COMMAND = darktable.configuration.running_os == "windows" and "mkdir " or "mkdir -p "
|
||||
local PATH_SEPARATOR = darktable.configuration.running_os == "windows" and "\\\\" or "/"
|
||||
@@ -95,12 +108,6 @@ local PATH_SEGMENT_REGEX = "(" .. PATH_SEPARATOR .. "?)([^" .. PATH_SEPARATOR ..
|
||||
unpack = unpack or table.unpack
|
||||
gmatch = string.gfind or string.gmatch
|
||||
|
||||
darktable.gettext.bindtextdomain(LIB_ID, darktable.configuration.config_dir .. PATH_SEPARATOR .. "lua" .. PATH_SEPARATOR .. "locale" .. PATH_SEPARATOR)
|
||||
|
||||
local function _(msgid)
|
||||
return darktable.gettext.dgettext(LIB_ID, msgid)
|
||||
end
|
||||
|
||||
-- Header material: END
|
||||
|
||||
|
||||
@@ -137,7 +144,7 @@ end
|
||||
local function install_module()
|
||||
if not th.module_installed then
|
||||
darktable.register_lib(LIB_ID,
|
||||
"transfer hierarchy", true, true, {
|
||||
_("transfer hierarchy"), true, true, {
|
||||
[darktable.gui.views.lighttable] = { "DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 700 }
|
||||
}, th.transfer_widget, nil, nil)
|
||||
th.module_installed = true
|
||||
@@ -150,7 +157,7 @@ end
|
||||
-- Widgets and business logic: BEGIN
|
||||
|
||||
local sourceTextBox = darktable.new_widget("entry") {
|
||||
tooltip = _("Lowest directory containing all selected images"),
|
||||
tooltip = _("lowest directory containing all selected images"),
|
||||
editable = false
|
||||
}
|
||||
sourceTextBox.reset_callback = function() sourceTextBox.text = "" end
|
||||
@@ -267,17 +274,17 @@ local function doTransfer(transferFunc)
|
||||
films[film] = destBase .. string.sub(film.path, #sourceBase+1)
|
||||
if not pathExists(films[film]) then
|
||||
if createDirectory(films[film]) == nil then
|
||||
darktable.print(_("transfer hierarchy: ERROR: could not create directory: " .. films[film]))
|
||||
darktable.print(string.format(_("transfer hierarchy: ERROR: could not create directory: %s"), films[film]))
|
||||
return
|
||||
end
|
||||
end
|
||||
if not pathIsDirectory(films[film]) then
|
||||
darktable.print(_("transfer hierarchy: ERROR: not a directory: " .. films[film]))
|
||||
darktable.print(string.format(_("transfer hierarchy: ERROR: not a directory: %s"), films[film]))
|
||||
return
|
||||
end
|
||||
destFilms[film] = darktable.films.new(films[film])
|
||||
if destFilms[film] == nil then
|
||||
darktable.print(_("transfer hierarchy: ERROR: could not create film: " .. film.path))
|
||||
darktable.print(string.format(_("transfer hierarchy: ERROR: could not create film: %s"), film.path))
|
||||
end
|
||||
end
|
||||
|
||||
@@ -286,7 +293,7 @@ local function doTransfer(transferFunc)
|
||||
srcFilms[img] = img.film
|
||||
end
|
||||
|
||||
local job = darktable.gui.create_job(string.format(_("transfer hierarchy") .. " (%d image" .. (#(darktable.gui.action_images) == 1 and "" or "s") .. ")", #(darktable.gui.action_images)), true, stopTransfer)
|
||||
local job = darktable.gui.create_job(string.format(_("transfer hierarchy (%d image%s)"), #(darktable.gui.action_images), (#(darktable.gui.action_images) == 1 and "" or "s")), true, stopTransfer)
|
||||
job.percent = 0.0
|
||||
local pctIncrement = 1.0 / #(darktable.gui.action_images)
|
||||
for _,img in ipairs(darktable.gui.action_images) do
|
||||
@@ -344,7 +351,7 @@ th.transfer_widget = darktable.new_widget("box") {
|
||||
},
|
||||
darktable.new_widget("button") {
|
||||
label = _("copy"),
|
||||
tooltip = _("Copy all selected images"),
|
||||
tooltip = _("copy all selected images"),
|
||||
clicked_callback = doCopy
|
||||
}
|
||||
}
|
||||
|
||||
1066
contrib/ultrahdr.lua
Normal file
1066
contrib/ultrahdr.lua
Normal file
File diff suppressed because it is too large
Load Diff
@@ -37,27 +37,33 @@ local dt = require "darktable"
|
||||
local du = require "lib/dtutils"
|
||||
local df = require "lib/dtutils.file"
|
||||
local dsys = require "lib/dtutils.system"
|
||||
local gettext = dt.gettext
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
du.check_min_api_version("7.0.0", "video_ffmpeg")
|
||||
|
||||
local function _(msgid)
|
||||
return gettext(msgid)
|
||||
end
|
||||
|
||||
-- return data structure for script_manager
|
||||
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("video ffmpeg"),
|
||||
purpose = _("timelapse video plugin based on ffmpeg"),
|
||||
author = "Dominik Markiewicz",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contib/video_ffmpeg"
|
||||
}
|
||||
|
||||
script_data.destroy = nil -- function to destory the script
|
||||
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil
|
||||
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
|
||||
script_data.show = nil -- only required for libs since the destroy_method only hides them
|
||||
|
||||
local MODULE_NAME = "video_ffmpeg"
|
||||
|
||||
local PS = dt.configuration.running_os == "windows" and "\\" or "/"
|
||||
gettext.bindtextdomain(MODULE_NAME, dt.configuration.config_dir..PS.."lua"..PS.."locale"..PS)
|
||||
|
||||
local function _(msgid)
|
||||
return gettext.dgettext(MODULE_NAME, msgid)
|
||||
end
|
||||
|
||||
|
||||
---- DECLARATIONS
|
||||
|
||||
@@ -240,8 +246,8 @@ local function string_pref_write(name, widget_attribute)
|
||||
end
|
||||
|
||||
local framerates_selector = dt.new_widget("combobox"){
|
||||
label = _("framerate"),
|
||||
tooltip = _("select framerate of output video"),
|
||||
label = _("frame rate"),
|
||||
tooltip = _("select frame rate of output video"),
|
||||
value = combobox_pref_read("framerate", framerates),
|
||||
changed_callback = combobox_pref_write("framerate"),
|
||||
table.unpack(framerates)
|
||||
@@ -293,7 +299,7 @@ else
|
||||
end
|
||||
|
||||
local output_directory_chooser = dt.new_widget("file_chooser_button"){
|
||||
title = _("Select export path"),
|
||||
title = _("select export path"),
|
||||
is_directory = true,
|
||||
tooltip =_("select the target directory for the timelapse. \nthe filename is created automatically."),
|
||||
value = string_pref_read("export_path", defaultVideoDir),
|
||||
@@ -374,7 +380,7 @@ local module_widget = dt.new_widget("box") {
|
||||
---- EXPORT & REGISTRATION
|
||||
|
||||
local function show_status(enf_storage, image, format, filename, number, total, high_quality, extra_data)
|
||||
dt.print(_("export ")..tostring(number).." / "..tostring(total))
|
||||
dt.print(string.format(_("export %d / %d", number), total))
|
||||
end
|
||||
|
||||
local function init_export(storage, img_format, images, high_quality, extra_data)
|
||||
@@ -410,7 +416,7 @@ local function export(extra_data)
|
||||
local ffmpeg_path = df.check_if_bin_exists("ffmpeg")
|
||||
if not ffmpeg_path then
|
||||
dt.print_error("ffmpeg not found")
|
||||
dt.print("ERROR - ffmpeg not found")
|
||||
dt.print(_("ERROR - ffmpeg not found"))
|
||||
return
|
||||
end
|
||||
local dir = extra_data["tmp_dir"]
|
||||
@@ -442,7 +448,7 @@ local function finalize_export(storage, images_table, extra_data)
|
||||
dt.print_error(filename, file.filename)
|
||||
df.file_move(filename, tmp_dir .. PS .. i .. extra_data["img_ext"])
|
||||
end
|
||||
dt.print("Start video building...")
|
||||
dt.print(_("start video building..."))
|
||||
local result, path = export(extra_data)
|
||||
if result ~= 0 then
|
||||
dt.print(_("ERROR: cannot build image, see console for more info"))
|
||||
@@ -464,7 +470,7 @@ end
|
||||
|
||||
dt.register_storage(
|
||||
"module_video_ffmpeg",
|
||||
_(MODULE_NAME),
|
||||
_("video ffmpeg"),
|
||||
show_status,
|
||||
finalize_export,
|
||||
nil,
|
||||
|
||||
BIN
data/icons/blank20.png
Normal file
BIN
data/icons/blank20.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.5 KiB |
BIN
data/icons/path20.png
Normal file
BIN
data/icons/path20.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.1 KiB |
@@ -23,6 +23,14 @@ USAGE
|
||||
]]
|
||||
local dt = require "darktable"
|
||||
|
||||
-- translation facilities
|
||||
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
local function _(msg)
|
||||
return gettext(msg)
|
||||
end
|
||||
|
||||
-- script_manager integration to allow a script to be removed
|
||||
-- without restarting darktable
|
||||
local function destroy()
|
||||
@@ -30,12 +38,21 @@ local function destroy()
|
||||
end
|
||||
|
||||
local result = dt.configuration.api_version_string
|
||||
dt.print_error("API Version: "..result)
|
||||
dt.print_log("API Version: " .. result)
|
||||
dt.print("API " .. _("version") .. ": " .. result)
|
||||
|
||||
-- set the destroy routine so that script_manager can call it when
|
||||
-- it's time to destroy the script and then return the data to
|
||||
-- script_manager
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("APIversion"),
|
||||
purpose = _("display api_version example"),
|
||||
author = "Tobias Jakobs",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/examples/api_version"
|
||||
}
|
||||
|
||||
script_data.destroy = destroy
|
||||
|
||||
return script_data
|
||||
|
||||
@@ -40,7 +40,7 @@ local du = require "lib/dtutils"
|
||||
-- V E R S I O N C H E C K
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
du.check_min_api_version("5.0.2", "darkroom_mode") -- darktable 3.0
|
||||
du.check_min_api_version("5.0.2", "darkroom_demo") -- darktable 3.0
|
||||
|
||||
-- script_manager integration to allow a script to be removed
|
||||
-- without restarting darktable
|
||||
@@ -52,17 +52,16 @@ end
|
||||
-- C O N S T A N T S
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
local MODULE_NAME = "darkroom"
|
||||
local MODULE_NAME = "darkroom_demo"
|
||||
local PS = dt.configuration.running_os == "windows" and "\\" or "/"
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- T R A N S L A T I O N S
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
local gettext = dt.gettext
|
||||
gettext.bindtextdomain(MODULE_NAME, dt.configuration.config_dir..PS.."lua"..PS.."locale"..PS)
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
local function _(msgid)
|
||||
return gettext.dgettext(MODULE_NAME, msgid)
|
||||
return gettext(msgid)
|
||||
end
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
@@ -92,13 +91,13 @@ dt.gui.current_view(dt.gui.views.darkroom)
|
||||
|
||||
local max_images = 10
|
||||
|
||||
dt.print(_("Showing images, with a pause in between each"))
|
||||
dt.print(_("showing images, with a pause between each"))
|
||||
sleep(1500)
|
||||
|
||||
-- display first 10 images of collection pausing for a second between each
|
||||
|
||||
for i, img in ipairs(dt.collection) do
|
||||
dt.print(_("Displaying image " .. i))
|
||||
dt.print(string.format(_("displaying image "), i))
|
||||
dt.gui.views.darkroom.display_image(img)
|
||||
sleep(1500)
|
||||
if i == max_images then
|
||||
@@ -108,7 +107,7 @@ end
|
||||
|
||||
-- return to lighttable view
|
||||
|
||||
dt.print(_("Restoring view"))
|
||||
dt.print(_("restoring view"))
|
||||
sleep(1500)
|
||||
dt.gui.current_view(current_view)
|
||||
|
||||
@@ -116,6 +115,14 @@ dt.gui.current_view(current_view)
|
||||
-- it's time to destroy the script and then return the data to
|
||||
-- script_manager
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("darkroom demo"),
|
||||
purpose = _("example demonstrating how to control image display in darkroom mode"),
|
||||
author = "Bill Ferguson <wpferguson@gmail.com>",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/examples/darkroom_demo"
|
||||
}
|
||||
|
||||
script_data.destroy = destroy
|
||||
|
||||
return script_data
|
||||
|
||||
@@ -67,27 +67,31 @@ end
|
||||
-- Not translated Text
|
||||
dt.print_error("Hello World!")
|
||||
|
||||
local gettext = dt.gettext
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
-- Translate a string using the darktable textdomain
|
||||
dt.print_error(gettext.gettext("image"))
|
||||
|
||||
-- Tell gettext where to find the .mo file translating messages for a particular domain
|
||||
|
||||
gettext.bindtextdomain("gettextExample",dt.configuration.config_dir.."/lua/locale/")
|
||||
-- Translate a string using the specified textdomain
|
||||
dt.print_error(gettext.dgettext("gettextExample", 'Hello World!'))
|
||||
dt.print_error(gettext("image"))
|
||||
|
||||
-- Define a local function called _ to make the code more readable and have it call dgettext
|
||||
-- with the proper domain.
|
||||
local function _(msgid)
|
||||
return gettext.dgettext("gettextExample", msgid)
|
||||
return gettext(msgid)
|
||||
end
|
||||
dt.print_error(_('Hello World!'))
|
||||
|
||||
dt.print_error(_("hello world!"))
|
||||
|
||||
-- set the destroy routine so that script_manager can call it when
|
||||
-- it's time to destroy the script and then return the data to
|
||||
-- script_manager
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("gettext example"),
|
||||
purpose = _("example of how translations works"),
|
||||
author = "Tobias Jakobs",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/examples/gettextExample"
|
||||
}
|
||||
|
||||
script_data.destroy = destroy
|
||||
|
||||
return script_data
|
||||
|
||||
142
examples/gui_action.lua
Normal file
142
examples/gui_action.lua
Normal file
@@ -0,0 +1,142 @@
|
||||
local dt = require "darktable"
|
||||
|
||||
local NaN = 0/0
|
||||
|
||||
local wg = {}
|
||||
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
local function _(msgid)
|
||||
return gettext(msgid)
|
||||
end
|
||||
|
||||
-- return data structure for script_manager
|
||||
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("gui action"),
|
||||
purpose = _("example of how to use darktable.gui.action() calls"),
|
||||
author = "Diederik ter Rahe",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/examples/gui_action"
|
||||
}
|
||||
|
||||
script_data.destroy = nil -- function to destory the script
|
||||
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet
|
||||
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
|
||||
script_data.show = nil -- only required for libs since the destroy_method only hides them
|
||||
|
||||
wg.action = dt.new_widget("entry"){
|
||||
text = "lib/filter/view",
|
||||
placeholder = _("action path"),
|
||||
tooltip = _("enter the full path of an action, for example 'lib/filter/view'")
|
||||
}
|
||||
|
||||
wg.instance = dt.new_widget("combobox"){
|
||||
label = _("instance"),
|
||||
tooltip = _("the instance of an image processing module to execute action on"),
|
||||
"0", "+1", "-1", "+2", "-2", "+3", "-3", "+4", "-4", "+5", "-5", "+6", "-6", "+7", "-7", "+8", "-8", "+9", "-9"
|
||||
}
|
||||
|
||||
wg.element = dt.new_widget("entry"){
|
||||
text = "",
|
||||
placeholder = _("action element"),
|
||||
tooltip = _("enter the element of an action, for example 'selection', or leave empty for default")
|
||||
}
|
||||
|
||||
wg.effect = dt.new_widget("entry"){
|
||||
text = "next",
|
||||
placeholder = _("action effect"),
|
||||
tooltip = _("enter the effect of an action, for example 'next', or leave empty for default")
|
||||
}
|
||||
|
||||
wg.speed = dt.new_widget("entry"){
|
||||
text = "1",
|
||||
placeholder = _("action speed"),
|
||||
tooltip = _("enter the speed to use in action execution, or leave empty to only read state")
|
||||
}
|
||||
|
||||
wg.check = dt.new_widget("check_button"){
|
||||
label = _('perform action'),
|
||||
tooltip = _('perform action or only read return'),
|
||||
clicked_callback = function()
|
||||
wg.speed.sensitive = wg.check.value
|
||||
end,
|
||||
value = true
|
||||
}
|
||||
|
||||
wg.return_value = dt.new_widget("entry"){
|
||||
text = "",
|
||||
sensitive = false
|
||||
}
|
||||
|
||||
dt.register_lib(
|
||||
"execute_action", -- Module name
|
||||
_("execute gui actions"), -- name
|
||||
true, -- expandable
|
||||
false, -- resetable
|
||||
{[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_LEFT_CENTER", 100},
|
||||
[dt.gui.views.darkroom] = {"DT_UI_CONTAINER_PANEL_LEFT_CENTER", 100}},
|
||||
dt.new_widget("box")
|
||||
{
|
||||
orientation = "vertical",
|
||||
|
||||
dt.new_widget("box")
|
||||
{
|
||||
orientation = "horizontal",
|
||||
dt.new_widget("label"){label = _("action path"), halign = "start"},
|
||||
wg.action
|
||||
},
|
||||
wg.instance,
|
||||
dt.new_widget("box")
|
||||
{
|
||||
orientation = "horizontal",
|
||||
dt.new_widget("label"){label = _("element"), halign = "start"},
|
||||
wg.element
|
||||
},
|
||||
dt.new_widget("box")
|
||||
{
|
||||
orientation = "horizontal",
|
||||
dt.new_widget("label"){label = _("effect"), halign = "start"},
|
||||
wg.effect
|
||||
},
|
||||
wg.check,
|
||||
dt.new_widget("box")
|
||||
{
|
||||
orientation = "horizontal",
|
||||
dt.new_widget("label"){label = _("speed"), halign = "start"},
|
||||
wg.speed
|
||||
},
|
||||
dt.new_widget("button")
|
||||
{
|
||||
label = _("execute action"),
|
||||
tooltip = _("execute the action specified in the fields above"),
|
||||
clicked_callback = function(_)
|
||||
local sp = NaN
|
||||
if wg.check.value then sp = wg.speed.text end
|
||||
wg.return_value.text = dt.gui.action(wg.action.text, tonumber(wg.instance.value), wg.element.text, wg.effect.text, tonumber(sp))
|
||||
end
|
||||
},
|
||||
dt.new_widget("box")
|
||||
{
|
||||
orientation = "horizontal",
|
||||
dt.new_widget("label"){label = "return value:", halign = "start"},
|
||||
wg.return_value
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
local function restart()
|
||||
dt.gui.libs["execute_action"].visible = true
|
||||
end
|
||||
|
||||
local function destroy()
|
||||
dt.gui.libs["execute_action"].visible = false
|
||||
end
|
||||
|
||||
script_data.destroy = destroy
|
||||
script_data.destroy_method = "hide"
|
||||
script_data.restart = restart
|
||||
script_data.show = restart
|
||||
|
||||
return script_data
|
||||
@@ -29,20 +29,36 @@ USAGE
|
||||
local dt = require "darktable"
|
||||
local du = require "lib/dtutils"
|
||||
|
||||
-- translation facilities
|
||||
|
||||
du.check_min_api_version("2.0.0", "hello_world")
|
||||
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
local function _(msg)
|
||||
return gettext(msg)
|
||||
end
|
||||
|
||||
-- script_manager integration to allow a script to be removed
|
||||
-- without restarting darktable
|
||||
local function destroy()
|
||||
-- nothing to destroy
|
||||
end
|
||||
|
||||
dt.print("hello, world")
|
||||
dt.print(_("hello, world"))
|
||||
|
||||
-- set the destroy routine so that script_manager can call it when
|
||||
-- it's time to destroy the script and then return the data to
|
||||
-- script_manager
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("hello world"),
|
||||
purpose = _("example of how to print a message to the screen"),
|
||||
author = "Tobias Ellinghaus",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/examples/hello_world"
|
||||
}
|
||||
|
||||
script_data.destroy = destroy
|
||||
|
||||
return script_data
|
||||
|
||||
@@ -59,11 +59,12 @@ end
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- T R A N S L A T I O N S
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
local gettext = dt.gettext
|
||||
gettext.bindtextdomain(MODULE_NAME, dt.configuration.config_dir..PS.."lua"..PS.."locale"..PS)
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
dt.gettext.bindtextdomain("lighttable_demo", dt.configuration.config_dir .."/lua/locale/")
|
||||
|
||||
local function _(msgid)
|
||||
return gettext.dgettext(MODULE_NAME, msgid)
|
||||
return gettext(msgid)
|
||||
end
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
@@ -145,17 +146,17 @@ sleep(2000)
|
||||
|
||||
for n, layout in ipairs(layouts) do
|
||||
dt.gui.libs.lighttable_mode.layout(layout)
|
||||
dt.print(_("set lighttable layout to " .. layout))
|
||||
dt.print_log(_("set lighttable layout to " .. layout))
|
||||
dt.print(string.format(_("set lighttable layout to %s"), layout))
|
||||
dt.print_log("set lighttable layout to " .. layout)
|
||||
sleep(1500)
|
||||
for i = 1, 10 do
|
||||
dt.gui.libs.lighttable_mode.zoom_level(i)
|
||||
dt.print(_("Set zoom level to " .. i))
|
||||
dt.print(string.format(_("set zoom level to %d"), i))
|
||||
sleep(1500)
|
||||
end
|
||||
for i = 9, 1, -1 do
|
||||
dt.gui.libs.lighttable_mode.zoom_level(i)
|
||||
dt.print(_("Set zoom level to " .. i))
|
||||
dt.print(string.format(_("set zoom level to %d"), i))
|
||||
sleep(1500)
|
||||
end
|
||||
end
|
||||
@@ -174,12 +175,12 @@ dt.print_log("starting sorts")
|
||||
|
||||
for n, sort in ipairs(sorts) do
|
||||
dt.gui.libs.filter.sort(sort)
|
||||
dt.print(_("set lighttable sort to " .. sort))
|
||||
dt.print(string.format(_("set lighttable sort to %s"), sort))
|
||||
sleep(1500)
|
||||
|
||||
for m, sort_order in ipairs(sort_orders) do
|
||||
dt.gui.libs.filter.sort_order(sort_order)
|
||||
dt.print(_("sort order set to " .. sort_order))
|
||||
dt.print(string.format(_("sort order set to %s"), sort_order))
|
||||
sleep(1500)
|
||||
end
|
||||
end
|
||||
@@ -190,12 +191,12 @@ dt.print(_("lighttable filtering demonstration"))
|
||||
|
||||
for n, rating in ipairs(ratings) do
|
||||
dt.gui.libs.filter.rating(rating)
|
||||
dt.print(_("set filter to " .. rating))
|
||||
dt.print(string.format(_("set filter to %s"), rating))
|
||||
sleep(1500)
|
||||
|
||||
for m, rating_comparator in ipairs(rating_comparators) do
|
||||
dt.gui.libs.filter.rating_comparator(rating_comparator)
|
||||
dt.print(_("set rating comparator to " .. rating_comparator))
|
||||
dt.print(string.format(_("set rating comparator to %s"), rating_comparator))
|
||||
sleep(1500)
|
||||
end
|
||||
end
|
||||
@@ -215,6 +216,14 @@ current_sort_order = dt.gui.libs.filter.sort_order(current_sort_order)
|
||||
-- it's time to destroy the script and then return the data to
|
||||
-- script_manager
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("lighttable demo"),
|
||||
purpose = _("example demonstrating how to control lighttable display modes"),
|
||||
author = "Bill Ferguson <wpferguson@gmail.com>",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/examples/lighttable_demo"
|
||||
}
|
||||
|
||||
script_data.destroy = destroy
|
||||
|
||||
return script_data
|
||||
|
||||
@@ -35,25 +35,31 @@ local du = require "lib/dtutils"
|
||||
|
||||
du.check_min_api_version("7.0.0", "moduleExample")
|
||||
|
||||
-- https://www.darktable.org/lua-api/index.html#darktable_gettext
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
local function _(msgid)
|
||||
return gettext(msgid)
|
||||
end
|
||||
|
||||
-- return data structure for script_manager
|
||||
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = ("module example"),
|
||||
purpose = _("example of how to create a lighttable module"),
|
||||
author = "Tobias Jakobs",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/examples/moduleExample"
|
||||
}
|
||||
|
||||
script_data.destroy = nil -- function to destory the script
|
||||
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil
|
||||
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
|
||||
script_data.show = nil -- only required for libs since the destroy_method only hides them
|
||||
|
||||
-- translation
|
||||
|
||||
-- https://www.darktable.org/lua-api/index.html#darktable_gettext
|
||||
local gettext = dt.gettext
|
||||
|
||||
gettext.bindtextdomain("moduleExample", dt.configuration.config_dir .. "/lua/locale/")
|
||||
|
||||
local function _(msgid)
|
||||
return gettext.dgettext("moduleExample", msgid)
|
||||
end
|
||||
|
||||
-- declare a local namespace and a couple of variables we'll need to install the module
|
||||
local mE = {}
|
||||
mE.widgets = {}
|
||||
@@ -69,7 +75,7 @@ local function install_module()
|
||||
-- https://www.darktable.org/lua-api/index.html#darktable_register_lib
|
||||
dt.register_lib(
|
||||
"exampleModule", -- Module name
|
||||
"exampleModule", -- name
|
||||
_("example module"), -- name
|
||||
true, -- expandable
|
||||
false, -- resetable
|
||||
{[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, -- containers
|
||||
@@ -79,9 +85,9 @@ local function install_module()
|
||||
orientation = "vertical",
|
||||
dt.new_widget("button")
|
||||
{
|
||||
label = _("MyButton"),
|
||||
label = _("my ") .. "button",
|
||||
clicked_callback = function (_)
|
||||
dt.print(_("Button clicked"))
|
||||
dt.print(_("button clicked"))
|
||||
end
|
||||
},
|
||||
table.unpack(mE.widgets),
|
||||
@@ -104,10 +110,10 @@ local function restart()
|
||||
end
|
||||
|
||||
-- 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 = _("my ") .. "check_button", value = true}
|
||||
|
||||
-- https://www.darktable.org/lua-api/types_lua_combobox.html
|
||||
local combobox = dt.new_widget("combobox"){label = _("MyCombobox"), value = 2, "8", "16", "32"}
|
||||
local combobox = dt.new_widget("combobox"){label = _("my ") .. "combobox", value = 2, "8", "16", "32"}
|
||||
|
||||
-- https://www.darktable.org/lua-api/types_lua_entry.html
|
||||
local entry = dt.new_widget("entry")
|
||||
@@ -116,21 +122,21 @@ local entry = dt.new_widget("entry")
|
||||
placeholder = _("placeholder"),
|
||||
is_password = false,
|
||||
editable = true,
|
||||
tooltip = _("Tooltip Text"),
|
||||
tooltip = _("tooltip text"),
|
||||
reset_callback = function(self) self.text = "text" end
|
||||
}
|
||||
|
||||
-- https://www.darktable.org/lua-api/types_lua_file_chooser_button.html
|
||||
local file_chooser_button = dt.new_widget("file_chooser_button")
|
||||
{
|
||||
title = _("MyFile_chooser_button"), -- The title of the window when choosing a file
|
||||
title = _("my ") .. "file_chooser_button", -- The title of the window when choosing a file
|
||||
value = "", -- The currently selected file
|
||||
is_directory = false -- True if the file chooser button only allows directories to be selecte
|
||||
}
|
||||
|
||||
-- https://www.darktable.org/lua-api/types_lua_label.html
|
||||
local label = dt.new_widget("label")
|
||||
label.label = _("MyLabel") -- This is an alternative way to the "{}" syntax to set a property
|
||||
label.label = _("my ") .. "label" -- This is an alternative way to the "{}" syntax to set a property
|
||||
|
||||
-- https://www.darktable.org/lua-api/types_lua_separator.html
|
||||
local separator = dt.new_widget("separator"){}
|
||||
@@ -138,7 +144,7 @@ local separator = dt.new_widget("separator"){}
|
||||
-- https://www.darktable.org/lua-api/types_lua_slider.html
|
||||
local slider = dt.new_widget("slider")
|
||||
{
|
||||
label = _("MySlider"),
|
||||
label = _("my ") .. "slider",
|
||||
soft_min = 10, -- The soft minimum value for the slider, the slider can't go beyond this point
|
||||
soft_max = 100, -- The soft maximum value for the slider, the slider can't go beyond this point
|
||||
hard_min = 0, -- The hard minimum value for the slider, the user can't manually enter a value beyond this point
|
||||
|
||||
@@ -70,13 +70,10 @@ local dtsys = require "lib/dtutils.system" -- system utilities
|
||||
translations, inserting this lays the groundwork for anyone who wants to translate the strings.
|
||||
]]
|
||||
|
||||
local gettext = dt.gettext
|
||||
|
||||
-- Tell gettext where to find the .mo file translating messages for a particular domain
|
||||
gettext.bindtextdomain("multi_os",dt.configuration.config_dir.."/lua/locale/")
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
local function _(msgid)
|
||||
return gettext.dgettext("multi_os", msgid)
|
||||
return gettext(msgid)
|
||||
end
|
||||
|
||||
--[[
|
||||
@@ -187,12 +184,12 @@ local function extract_embedded_jpeg(images)
|
||||
end
|
||||
else
|
||||
dt.print_error(image.filename .. " is not a raw file. No image can be extracted") -- print debugging error message
|
||||
dt.print(image.filename .. " is not a raw file. No image can be extracted") -- print the error to the screen
|
||||
dt.print(string.format(_("%s is not a raw file, no image can be extracted"), image.filename)) -- print the error to the screen
|
||||
end
|
||||
end
|
||||
else
|
||||
dt.print_error("ufraw-batch not found. Exiting...") -- print debugging error message
|
||||
dt.print("ufraw-batch not found. Exiting...") -- print the error to the screen
|
||||
dt.print("ufraw-batch not found, exiting...") -- print the error to the screen
|
||||
end
|
||||
end
|
||||
|
||||
@@ -216,7 +213,7 @@ end
|
||||
if dt.configuration.running_os ~= "linux" then
|
||||
local executable = "ufraw-batch"
|
||||
local ufraw_batch_path_widget = dt.new_widget("file_chooser_button"){
|
||||
title = _("Select ufraw-batch[.exe] executable"),
|
||||
title = string.format(_("select %s executable"), "ufraw-batch[.exe]"),
|
||||
value = df.get_executable_path_preference(executable),
|
||||
is_directory = false,
|
||||
changed_callback = function(self)
|
||||
@@ -227,8 +224,8 @@ if dt.configuration.running_os ~= "linux" then
|
||||
}
|
||||
dt.preferences.register("executable_paths", "ufraw-batch", -- name
|
||||
"file", -- type
|
||||
_('multi_os: ufraw-batch location'), -- label
|
||||
_('Installed location of ufraw-batch. Requires restart to take effect.'), -- tooltip
|
||||
'multi_os: ufraw-batch ' .. _('location'), -- label
|
||||
_('installed location of ufraw-batch, requires restart to take effect.'), -- tooltip
|
||||
"ufraw-batch", -- default
|
||||
ufraw_batch_path_widget
|
||||
)
|
||||
@@ -241,7 +238,7 @@ end
|
||||
dt.gui.libs.image.register_action(
|
||||
"multi_os", _("extract embedded jpeg"),
|
||||
function(event, images) extract_embedded_jpeg(images) end,
|
||||
"extract embedded jpeg"
|
||||
_("extract embedded jpeg")
|
||||
)
|
||||
|
||||
--[[
|
||||
@@ -251,7 +248,7 @@ dt.gui.libs.image.register_action(
|
||||
dt.register_event(
|
||||
"multi_os", "shortcut",
|
||||
function(event, shortcut) extract_embedded_jpeg(dt.gui.action_images) end,
|
||||
"extract embedded jpeg"
|
||||
_("extract embedded jpeg")
|
||||
)
|
||||
|
||||
--[[
|
||||
@@ -261,6 +258,14 @@ dt.register_event(
|
||||
]]
|
||||
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("multi OS"),
|
||||
purpose = _("example module thet runs on different operating systems"),
|
||||
author = "Bill Ferguson <wpferguson@gmail.com>",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/examples/multi_os"
|
||||
}
|
||||
|
||||
script_data.destroy = destroy
|
||||
|
||||
return script_data
|
||||
|
||||
@@ -53,17 +53,16 @@ end
|
||||
-- C O N S T A N T S
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
local MODULE_NAME = "panels"
|
||||
local MODULE_NAME = "panels_demo"
|
||||
local PS = dt.configuration.running_os == "windows" and "\\" or "/"
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- T R A N S L A T I O N S
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
local gettext = dt.gettext
|
||||
gettext.bindtextdomain(MODULE_NAME, dt.configuration.config_dir..PS.."lua"..PS.."locale"..PS)
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
local function _(msgid)
|
||||
return gettext.dgettext(MODULE_NAME, msgid)
|
||||
return gettext(msgid)
|
||||
end
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
@@ -94,29 +93,29 @@ dt.gui.panel_show_all()
|
||||
|
||||
-- hide center_top, center_bottom, left, top, right, bottom in order
|
||||
|
||||
dt.print(_("Hiding all panels, one at a tme"))
|
||||
dt.print(_("hiding all panels, one at a time"))
|
||||
sleep(1500)
|
||||
|
||||
for i = 1, #panels do
|
||||
dt.print(_("Hiding " .. panels[i]))
|
||||
dt.print(string.format(_("hiding %s"), panels[i]))
|
||||
dt.gui.panel_hide(panels[i])
|
||||
sleep(1500)
|
||||
end
|
||||
|
||||
-- display left, then top, then right, then bottom
|
||||
|
||||
dt.print(_("Make panels visible, one at a time"))
|
||||
dt.print(_("make panels visible, one at a time"))
|
||||
sleep(1500)
|
||||
|
||||
for i = #panels, 1, -1 do
|
||||
dt.print(_("Showing " .. panels[i]))
|
||||
dt.print(string.format(_("showing %s"), panels[i]))
|
||||
dt.gui.panel_show(panels[i])
|
||||
sleep(1500)
|
||||
end
|
||||
|
||||
-- hide all
|
||||
|
||||
dt.print(_("Hiding all panels"))
|
||||
dt.print(_("hiding all panels"))
|
||||
sleep(1500)
|
||||
|
||||
dt.gui.panel_hide_all()
|
||||
@@ -124,7 +123,7 @@ sleep(1500)
|
||||
|
||||
-- show all
|
||||
|
||||
dt.print(_("Showing all panels"))
|
||||
dt.print(_("showing all panels"))
|
||||
sleep(1500)
|
||||
|
||||
dt.gui.panel_show_all()
|
||||
@@ -132,7 +131,7 @@ sleep(1500)
|
||||
|
||||
-- restore
|
||||
|
||||
dt.print(_("Restoring panels to starting configuration"))
|
||||
dt.print(_("restoring panels to starting configuration"))
|
||||
for i = 1, #panels do
|
||||
if panel_status[i] then
|
||||
dt.gui.panel_show(panels[i])
|
||||
@@ -145,6 +144,14 @@ end
|
||||
-- it's time to destroy the script and then return the data to
|
||||
-- script_manager
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("panels demo"),
|
||||
purpose = _("example demonstrating how to contol panel visibility"),
|
||||
author = "Bill Ferguson <wpferguson@gmail.com>",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/examples/panels_demo"
|
||||
}
|
||||
|
||||
script_data.destroy = destroy
|
||||
|
||||
return script_data
|
||||
|
||||
@@ -24,28 +24,45 @@ USAGE
|
||||
local dt = require "darktable"
|
||||
local du = require "lib/dtutils"
|
||||
|
||||
-- translation facilities
|
||||
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
local function _(msg)
|
||||
return gettext(msg)
|
||||
end
|
||||
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("preference examples"),
|
||||
purpose = _("example to show the different preference types that are possible"),
|
||||
author = "Tobias Jakobs",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/examples/preferenceExamples"
|
||||
}
|
||||
|
||||
du.check_min_api_version("2.0.1", "preferenceExamples")
|
||||
|
||||
|
||||
dt.preferences.register("preferenceExamples", -- script: This is a string used to avoid name collision in preferences (i.e namespace). Set it to something unique, usually the name of the script handling the preference.
|
||||
"preferenceExamplesString", -- name
|
||||
"string", -- type
|
||||
"Example String", -- label
|
||||
"Example String Tooltip", -- tooltip
|
||||
_("example") .. " string", -- label
|
||||
_("example") .. " string " .. _("tooltip"), -- tooltip
|
||||
"String") -- default
|
||||
|
||||
dt.preferences.register("preferenceExamples", -- script: This is a string used to avoid name collision in preferences (i.e namespace). Set it to something unique, usually the name of the script handling the preference.
|
||||
"preferenceExamplesBool", -- name
|
||||
"bool", -- type
|
||||
"Example Boolean", -- label
|
||||
"Example Boolean Tooltip", -- tooltip
|
||||
_("example") .. " boolean", -- label
|
||||
_("example") .. " boolean " .. _("tooltip"), -- tooltip
|
||||
true) -- default
|
||||
|
||||
dt.preferences.register("preferenceExamples", -- script: This is a string used to avoid name collision in preferences (i.e namespace). Set it to something unique, usually the name of the script handling the preference.
|
||||
"preferenceExamplesInteger", -- name
|
||||
"integer", -- type
|
||||
"Example Integer", -- label
|
||||
"Example Integer Tooltip", -- tooltip
|
||||
_("example") .. " integer", -- label
|
||||
_("example") .. " integer " .. _("tooltip"), -- tooltip
|
||||
2, -- default
|
||||
1, -- min
|
||||
99) -- max
|
||||
@@ -53,8 +70,8 @@ dt.preferences.register("preferenceExamples", -- script: This is a string
|
||||
dt.preferences.register("preferenceExamples", -- script: This is a string used to avoid name collision in preferences (i.e namespace). Set it to something unique, usually the name of the script handling the preference.
|
||||
"preferenceExamplesFloat", -- name
|
||||
"float", -- type
|
||||
"Example Float", -- label
|
||||
"Example Float Tooltip", -- tooltip
|
||||
_("example") .. " float", -- label
|
||||
_("example") .. " float " .. _("tooltip"), -- tooltip
|
||||
1.3, -- default
|
||||
1, -- min
|
||||
99, -- max
|
||||
@@ -63,22 +80,30 @@ dt.preferences.register("preferenceExamples", -- script: This is a string
|
||||
dt.preferences.register("preferenceExamples", -- script: This is a string used to avoid name collision in preferences (i.e namespace). Set it to something unique, usually the name of the script handling the preference.
|
||||
"preferenceExamplesFile", -- name
|
||||
"file", -- type
|
||||
"Example File", -- label
|
||||
"Example File Tooltip", -- tooltip
|
||||
_("example") .. " file", -- label
|
||||
_("example") .. " file " .. _("tooltip"), -- tooltip
|
||||
"") -- default
|
||||
|
||||
dt.preferences.register("preferenceExamples", -- script: This is a string used to avoid name collision in preferences (i.e namespace). Set it to something unique, usually the name of the script handling the preference.
|
||||
"preferenceExamplesDirectory", -- name
|
||||
"directory", -- type
|
||||
"Example Directory", -- label
|
||||
"Example Directory Tooltip", -- tooltip
|
||||
_("example") .. " directory", -- label
|
||||
_("example") .. " directory " .. _("tooltip"), -- tooltip
|
||||
"") -- default
|
||||
|
||||
dt.preferences.register("preferenceExamples", -- script: This is a string used to avoid name collision in preferences (i.e namespace). Set it to something unique, usually the name of the script handling the preference.
|
||||
"preferenceExamplesEnum", -- name
|
||||
"enum", -- type
|
||||
"Example Enum", -- label
|
||||
"Example Enum Tooltip", -- tooltip
|
||||
_("example") .. " enum", -- label
|
||||
_("example") .. " enum " .. _("tooltip"), -- tooltip
|
||||
"Enum 1", -- default
|
||||
"Enum 1", "Enum 2") -- values
|
||||
|
||||
|
||||
local function destroy()
|
||||
-- nothing to destroy
|
||||
end
|
||||
|
||||
script_data.destroy = destroy
|
||||
|
||||
return script_data
|
||||
|
||||
@@ -24,6 +24,14 @@ local du = require "lib/dtutils"
|
||||
|
||||
du.check_min_api_version("5.0.0", "printExamples")
|
||||
|
||||
-- translation facilities
|
||||
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
local function _(msg)
|
||||
return gettext(msg)
|
||||
end
|
||||
|
||||
-- script_manager integration to allow a script to be removed
|
||||
-- without restarting darktable
|
||||
local function destroy()
|
||||
@@ -32,7 +40,7 @@ end
|
||||
|
||||
-- Will print a string to the darktable control log (the long
|
||||
-- overlayed window that appears over the main panel).
|
||||
dt.print("print")
|
||||
dt.print(_("print"))
|
||||
|
||||
-- This function will print its parameter if the Lua logdomain is
|
||||
-- activated. Start darktable with the "-d lua" command line option
|
||||
@@ -48,6 +56,14 @@ dt.print_log("print log")
|
||||
-- it's time to destroy the script and then return the data to
|
||||
-- script_manager
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("print examples"),
|
||||
purpose = _("example showing the different types of printing messages"),
|
||||
author = "Tobias Jakobs",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/examples/printExamples"
|
||||
}
|
||||
|
||||
script_data.destroy = destroy
|
||||
|
||||
return script_data
|
||||
|
||||
@@ -30,18 +30,34 @@ local du = require "lib/dtutils"
|
||||
|
||||
du.check_min_api_version("5.0.0", "running_os")
|
||||
|
||||
-- translation facilities
|
||||
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
local function _(msg)
|
||||
return gettext(msg)
|
||||
end
|
||||
|
||||
-- script_manager integration to allow a script to be removed
|
||||
-- without restarting darktable
|
||||
local function destroy()
|
||||
-- nothing to destroy
|
||||
end
|
||||
|
||||
dt.print("You are running: "..dt.configuration.running_os)
|
||||
dt.print(string.format(_("you are running: %s"), dt.configuration.running_os))
|
||||
|
||||
-- set the destroy routine so that script_manager can call it when
|
||||
-- it's time to destroy the script and then return the data to
|
||||
-- script_manager
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("running OS"),
|
||||
purpose = _("example of how to determine the operating system being used"),
|
||||
author = "Tobias Jakobs",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/examples/running_os"
|
||||
}
|
||||
|
||||
script_data.destroy = destroy
|
||||
|
||||
return script_data
|
||||
|
||||
208
examples/x-touch.lua
Normal file
208
examples/x-touch.lua
Normal file
@@ -0,0 +1,208 @@
|
||||
--[[
|
||||
This file is part of darktable,
|
||||
copyright (c) 2023 Diederik ter Rahe
|
||||
|
||||
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/>.
|
||||
]]
|
||||
--[[
|
||||
X-Touch Mini flexible encoder shortcuts
|
||||
|
||||
This script will create virtual sliders that are mapped dynamically to
|
||||
the most relevant sliders for the currently focused processing module.
|
||||
Tailored modules are color zones, tone equalizer, color calibration and
|
||||
mask manager properties. The script can easily be amended for other
|
||||
devices or personal preferences. Virtual "toggle" buttons can be created
|
||||
as well, that dynamically change meaning depending on current status.
|
||||
|
||||
USAGE
|
||||
* require this script from your main lua file
|
||||
* restart darktable
|
||||
* create shortcuts for each of the encoders on the x-touch mini
|
||||
to a virtual slider under lua/x-touch
|
||||
or import the following shortcutsrc file in the shortcuts dialog/preferences tab:
|
||||
|
||||
None;midi:CC1=lua/x-touch/knob 1
|
||||
None;midi:CC2=lua/x-touch/knob 2
|
||||
None;midi:CC3=lua/x-touch/knob 3
|
||||
None;midi:CC4=lua/x-touch/knob 4
|
||||
None;midi:CC5=lua/x-touch/knob 5
|
||||
None;midi:CC6=lua/x-touch/knob 6
|
||||
None;midi:CC7=lua/x-touch/knob 7
|
||||
None;midi:CC8=lua/x-touch/knob 8
|
||||
midi:E0=global/modifiers
|
||||
midi:F0=global/modifiers;ctrl
|
||||
midi:F#0=global/modifiers;alt
|
||||
midi:G#-1=iop/blend/tools/show and edit mask elements
|
||||
midi:A-1=iop/colorzones;focus
|
||||
midi:A#-1=iop/toneequal;focus
|
||||
midi:B-1=iop/colorbalancergb;focus
|
||||
midi:C0=iop/channelmixerrgb;focus
|
||||
midi:C#0=iop/colorequal;focus
|
||||
midi:D0=iop/colorequal/page;previous
|
||||
midi:D#0=iop/colorequal/page;next
|
||||
]]
|
||||
|
||||
local dt = require "darktable"
|
||||
local du = require "lib/dtutils"
|
||||
|
||||
du.check_min_api_version("9.2.0", "x-touch")
|
||||
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
local function _(msgid)
|
||||
return gettext(msgid)
|
||||
end
|
||||
|
||||
-- return data structure for script_manager
|
||||
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("x-touch"),
|
||||
purpose = _("example of how to control an x-touch midi device"),
|
||||
author = "Diederik ter Rahe",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/examples/x-touch"
|
||||
}
|
||||
|
||||
script_data.destroy = nil -- function to destory the script
|
||||
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet
|
||||
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
|
||||
script_data.show = nil -- only required for libs since the destroy_method only hides them
|
||||
|
||||
-- set up 8 mimic sliders with the same function
|
||||
for k = 1,8 do
|
||||
dt.gui.mimic("slider", "knob ".. k,
|
||||
function(action, element, effect, size)
|
||||
-- take the number from the mimic name
|
||||
local k = tonumber(action:sub(-1))
|
||||
|
||||
-- only operate in darkroom; return NAN otherwise
|
||||
if dt.gui.current_view() ~= dt.gui.views.darkroom then
|
||||
return 0/0
|
||||
end
|
||||
|
||||
local maskval = 0/0
|
||||
if k < 8 then
|
||||
-- first try if the mask slider at that position is active
|
||||
local s = { "opacity",
|
||||
"size",
|
||||
"feather",
|
||||
"hardness",
|
||||
"rotation",
|
||||
"curvature",
|
||||
"compression" }
|
||||
maskval = dt.gui.action("lib/masks/properties/" .. s[k],
|
||||
element, effect, size)
|
||||
end
|
||||
-- if a value different from NAN is returned, the slider was active
|
||||
if maskval == maskval then
|
||||
return maskval
|
||||
|
||||
-- try if colorzones module is focused; if so select element of graph
|
||||
elseif dt.gui.action("iop/colorzones", "focus") ~= 0 then
|
||||
which = "iop/colorzones/graph"
|
||||
local e = { "red",
|
||||
"orange",
|
||||
"yellow",
|
||||
"green",
|
||||
"aqua",
|
||||
"blue",
|
||||
"purple",
|
||||
"magenta" }
|
||||
element = e[k]
|
||||
|
||||
-- try if colorequalizer module is focused; if so select element of graph
|
||||
elseif dt.gui.action("iop/colorequal", "focus") ~= 0 then
|
||||
local e = { "red",
|
||||
"orange",
|
||||
"yellow",
|
||||
"green",
|
||||
"cyan",
|
||||
"blue",
|
||||
"lavender",
|
||||
"magenta" }
|
||||
which = "iop/colorequal/graph"
|
||||
element = e[k]
|
||||
|
||||
-- if the sigmoid rgb primaries is focused,
|
||||
-- check sliders
|
||||
elseif dt.gui.action("iop/sigmoid", "focus") ~= 0 and k <8 then
|
||||
local e = { "red attenuation", "red rotation", "green attenuation", "green rotation", "blue attenuation", "blue rotation", "recover purity" }
|
||||
which = "iop/sigmoid/primaries/"..e[k]
|
||||
|
||||
-- if the rgb primaries is focused,
|
||||
-- check sliders
|
||||
elseif dt.gui.action("iop/primaries", "focus") ~= 0 and k >=1 then
|
||||
local e = { "red hue", "red purity", "green hue", "green purity", "blue hue", "blue purity", "tint hue", "tint purity" }
|
||||
which = "iop/primaries/" ..e[k]
|
||||
|
||||
-- if the tone equalizer is focused,
|
||||
-- select one of the sliders in the "simple" tab
|
||||
elseif dt.gui.action("iop/toneequal", "focus") ~= 0 then
|
||||
which ="iop/toneequal/simple/"..(k-9).." EV"
|
||||
|
||||
-- if color calibration is focused,
|
||||
-- the last 4 knobs are sent there
|
||||
elseif dt.gui.action("iop/channelmixerrgb", "focus") ~= 0
|
||||
and k >= 5 then
|
||||
-- knob 5 selects the active tab; pressing it resets to CAT
|
||||
if k == 5 then
|
||||
which = "iop/channelmixerrgb/page"
|
||||
element = "CAT"
|
||||
-- since the tab action is not a slider,
|
||||
-- the effects need to be translated
|
||||
if effect == "up" then effect = "next"
|
||||
elseif effect == "down" then effect = "previous"
|
||||
else effect = "activate"
|
||||
end
|
||||
else
|
||||
-- knobs 6, 7 and 8 are for the three color sliders on each tab
|
||||
which = "iop/focus/sliders"
|
||||
local e = { "1st",
|
||||
"2nd",
|
||||
"3rd" }
|
||||
element = e[k - 5]
|
||||
end
|
||||
|
||||
-- the 4th knob is contrast;
|
||||
-- either colorbalance if it is focused, or filmic
|
||||
elseif dt.gui.action("iop/colorbalancergb", "focus") ~= 0
|
||||
and k == 4 then
|
||||
which = "iop/colorbalancergb/contrast"
|
||||
|
||||
-- in all other cases use a default selection
|
||||
else
|
||||
local s = { "iop/exposure/exposure",
|
||||
"iop/filmicrgb/white relative exposure",
|
||||
"iop/filmicrgb/black relative exposure",
|
||||
"iop/filmicrgb/contrast",
|
||||
"iop/crop/left",
|
||||
"iop/crop/right",
|
||||
"iop/crop/top",
|
||||
"iop/crop/bottom" }
|
||||
which = s[k]
|
||||
end
|
||||
|
||||
-- now pass the element/effect/size to the selected slider
|
||||
return dt.gui.action(which, element, effect, size)
|
||||
end)
|
||||
end
|
||||
|
||||
local function destroy()
|
||||
-- nothing to destroy
|
||||
end
|
||||
|
||||
script_data.destroy = destroy
|
||||
|
||||
return script_data
|
||||
115
lib/dtutils.lua
115
lib/dtutils.lua
@@ -61,14 +61,50 @@ dtutils.libdoc.functions["check_min_api_version"] = {
|
||||
|
||||
function dtutils.check_min_api_version(min_api, script_name)
|
||||
local current_api = dt.configuration.api_version_string
|
||||
if min_api > current_api then
|
||||
if dtutils.compare_api_versions(min_api, current_api) > 0 then
|
||||
dt.print_error("This application is written for lua api version " .. min_api .. " or later.")
|
||||
dt.print_error("The current lua api version is " .. current_api)
|
||||
dt.print("ERROR: " .. script_name .. " failed to load. Lua API version " .. min_api .. " or later required.")
|
||||
dt.control.sleep(2000) -- allow time for the error to display before script_manager writes it's error message
|
||||
error("Minimum API " .. min_api .. " not met for " .. script_name .. ".", 0)
|
||||
end
|
||||
end
|
||||
|
||||
dtutils.libdoc.functions["check_max_api_version"] = {
|
||||
Name = [[check_max_api_version]],
|
||||
Synopsis = [[check the maximum required api version against the current api version]],
|
||||
Usage = [[local du = require "lib/dtutils"
|
||||
|
||||
local result = du.check_max_api_version(max_api, script_name)
|
||||
max_api - string - the api version that the application was written for (example: "5.0.0")
|
||||
script_name - string - the name of the script]],
|
||||
Description = [[check_max_api_version compares the maximum api required for the appllication to
|
||||
run against the current api version. This function is used when a part of the Lua API that
|
||||
the script relies on is removed. If the maximum api version is not met, then an
|
||||
error message is printed saying the script_name failed to load, then an error is thrown causing the
|
||||
program to stop executing.]],
|
||||
Return_Value = [[result - true if the maximum api version is available, false if not.]],
|
||||
Limitations = [[When using the default handler on a script being executed from the luarc file, the error thrown
|
||||
will stop the luarc file from executing any remaining statements. This limitation does not apply to script_manger.]],
|
||||
Example = [[check_max_api_version("9.0.0") does nothing if the api is less than or equal to 9.0.0 otherwise an
|
||||
error message is printed and an error is thrown stopping execution of the script.]],
|
||||
See_Also = [[]],
|
||||
Reference = [[]],
|
||||
License = [[]],
|
||||
Copyright = [[]],
|
||||
}
|
||||
|
||||
function dtutils.check_max_api_version(max_api, script_name)
|
||||
local current_api = dt.configuration.api_version_string
|
||||
if dtutils.compare_api_versions(current_api, max_api) > 0 then
|
||||
dt.print_error("This application is written for lua api version " .. max_api .. " or earlier.")
|
||||
dt.print_error("The current lua api version is " .. current_api)
|
||||
dt.print("ERROR: " .. script_name .. " failed to load. Lua API version " .. max_api .. " or earlier required.")
|
||||
dt.control.sleep(2000) -- allow time for the error to display before script_manager writes it's error message
|
||||
error("Maximum API " .. max_api .. " not met for " .. script_name .. ".", 0)
|
||||
end
|
||||
end
|
||||
|
||||
dtutils.libdoc.functions["split"] = {
|
||||
Name = [[split]],
|
||||
Synopsis = [[split a string on a specified separator]],
|
||||
@@ -184,7 +220,8 @@ function dtutils.prequire(req_name)
|
||||
if status then
|
||||
log.msg(log.info, "Loaded " .. req_name)
|
||||
else
|
||||
log.msg(log.info, "Error loading " .. req_name)
|
||||
log.msg(log.error, "Error loading " .. req_name)
|
||||
log.msg(log.error, "Error returned is " .. lib)
|
||||
end
|
||||
return status, lib
|
||||
end
|
||||
@@ -337,7 +374,7 @@ dtutils.libdoc.functions["deprecated"] = {
|
||||
|
||||
du.deprecated(script_name, removal_string)
|
||||
script_name - name of the script being deprecated
|
||||
removal_strubg - a string explaining when the script will be removed]],
|
||||
removal_string - a string explaining when the script will be removed]],
|
||||
Description = [[deprecated prints an error message saying the script is deprecated and when it will be removed]],
|
||||
Return_Value = [[]],
|
||||
Limitations = [[]],
|
||||
@@ -354,5 +391,77 @@ function dtutils.deprecated(script_name, removal_string)
|
||||
dt.print_error("WARNING: " .. script_name .. " is deprecated and will be removed in " .. removal_string)
|
||||
end
|
||||
|
||||
dtutils.libdoc.functions["gen_uuid"] = {
|
||||
Name = [[gen_uuid]],
|
||||
Synopsis = [[generate a UUID string]],
|
||||
Usage = [[local du = require "lib/dtutils"
|
||||
|
||||
uuid = du.gen_uuid(case)
|
||||
case - "upper" or "lower" to specify the case of the UUID string]],
|
||||
Description = [[gen_uuid prints an error message saying the script is gen_uuid and when it will be removed]],
|
||||
Return_Value = [[uuid - string - a hexidecimal string representing the UUID in the requested case]],
|
||||
Limitations = [[]],
|
||||
Example = [[]],
|
||||
See_Also = [[]],
|
||||
Reference = [[https://gist.github.com/jrus/3197011]],
|
||||
License = [[]],
|
||||
Copyright = [[]],
|
||||
}
|
||||
|
||||
function dtutils.gen_uuid(case)
|
||||
local template = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'
|
||||
|
||||
-- seed with os.time in seconds and add an extra degree of random for multiple calls in the same second
|
||||
math.randomseed(os.time(), math.random(0, 65536))
|
||||
|
||||
local uuid = string.gsub(template, '[xy]', function (c)
|
||||
local v = (c == 'x') and math.random(0, 0xf) or math.random(8, 0xb)
|
||||
return string.format('%x', v)
|
||||
end
|
||||
)
|
||||
|
||||
if case and case == "upper" then
|
||||
uuid = string.upper(uuid)
|
||||
end
|
||||
|
||||
return uuid
|
||||
end
|
||||
|
||||
dtutils.libdoc.functions["compare_api_versions"] = {
|
||||
Name = [[compare_api_versions]],
|
||||
Synopsis = [[compare two API version strings]],
|
||||
Usage = [[local du = require "lib/dtutils"
|
||||
|
||||
local result = du.compare_api_versions(version1, version2)
|
||||
version1 - string - the first version string to compare (example: "5.0.0")
|
||||
version2 - string - the second version string to compare (example: "5.1.0")]],
|
||||
Description = [[compare_api_versions compares two version strings and returns 1 if version1 is greater,
|
||||
-1 if version2 is greater, and 0 if they are equal.]],
|
||||
Return_Value = [[result - 1 if version1 is greater, -1 if version2 is greater, 0 if they are equal.]],
|
||||
Limitations = [[]],
|
||||
Example = [[compare_api_versions("5.0.0", "5.1.0") returns -1]],
|
||||
See_Also = [[]],
|
||||
Reference = [[]],
|
||||
License = [[]],
|
||||
Copyright = [[]],
|
||||
}
|
||||
|
||||
function dtutils.compare_api_versions(version1, version2)
|
||||
local v1 = {}
|
||||
for num in version1:gmatch("%d+") do table.insert(v1, tonumber(num)) end
|
||||
local v2 = {}
|
||||
for num in version2:gmatch("%d+") do table.insert(v2, tonumber(num)) end
|
||||
|
||||
for i = 1, math.max(#v1, #v2) do
|
||||
local num1 = v1[i] or 0
|
||||
local num2 = v2[i] or 0
|
||||
if num1 > num2 then
|
||||
return 1
|
||||
elseif num1 < num2 then
|
||||
return -1
|
||||
end
|
||||
end
|
||||
return 0
|
||||
end
|
||||
|
||||
return dtutils
|
||||
|
||||
@@ -24,15 +24,12 @@ dtutils_file.libdoc = {
|
||||
functions = {}
|
||||
}
|
||||
|
||||
local gettext = dt.gettext
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
du.check_min_api_version("5.0.0", "dtutils.file")
|
||||
|
||||
-- Tell gettext where to find the .mo file translating messages for a particular domain
|
||||
gettext.bindtextdomain("dtutils.file",dt.configuration.config_dir.."/lua/locale/")
|
||||
|
||||
local function _(msgid)
|
||||
return gettext.dgettext("dtutils.file", msgid)
|
||||
return gettext(msgid)
|
||||
end
|
||||
|
||||
--[[
|
||||
@@ -522,9 +519,9 @@ function dtutils_file.file_copy(fromFile, toFile)
|
||||
local result = nil
|
||||
-- if cp exists, use it
|
||||
if dt.configuration.running_os == "windows" then
|
||||
result = os.execute('copy "' .. fromFile .. '" "' .. toFile .. '"')
|
||||
result = os.execute('copy ' .. dtutils_file.sanitize_filename(fromFile) .. ' ' .. dtutils_file.sanitize_filename(toFile))
|
||||
elseif dtutils_file.check_if_bin_exists("cp") then
|
||||
result = os.execute("cp '" .. fromFile .. "' '" .. toFile .. "'")
|
||||
result = os.execute("cp " .. dtutils_file.sanitize_filename(fromFile) .. ' ' .. dtutils_file.sanitize_filename(toFile))
|
||||
end
|
||||
|
||||
-- if cp was not present, or if cp failed, then a pure lua solution
|
||||
@@ -575,7 +572,7 @@ function dtutils_file.file_move(fromFile, toFile)
|
||||
if not success then
|
||||
-- an error occurred, so let's try using the operating system function
|
||||
if dtutils_file.check_if_bin_exists("mv") then
|
||||
success = os.execute("mv '" .. fromFile .. "' '" .. toFile .. "'")
|
||||
success = os.execute("mv " .. dtutils_file.sanitize_filename(fromFile) .. ' ' .. dtutils_file.sanitize_filename(toFile))
|
||||
end
|
||||
-- if the mv didn't exist or succeed, then...
|
||||
if not success then
|
||||
@@ -815,7 +812,7 @@ dtutils_file.libdoc.functions["mkdir"] = {
|
||||
function dtutils_file.mkdir(path)
|
||||
if not dtutils_file.check_if_file_exists(path) then
|
||||
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.." "..dtutils_file.sanitize_filename(path))
|
||||
else
|
||||
return 0
|
||||
end
|
||||
@@ -840,7 +837,7 @@ dtutils_file.libdoc.functions["rmdir"] = {
|
||||
|
||||
function dtutils_file.rmdir(path)
|
||||
local rm_cmd = dt.configuration.running_os == "windows" and "rmdir /S /Q" or "rm -r"
|
||||
return dsys.external_command(rm_cmd.." "..path)
|
||||
return dsys.external_command(rm_cmd.." "..dtutils_file.sanitize_filename(path))
|
||||
end
|
||||
|
||||
dtutils_file.libdoc.functions["create_tmp_file"] = {
|
||||
@@ -861,9 +858,6 @@ dtutils_file.libdoc.functions["create_tmp_file"] = {
|
||||
|
||||
function dtutils_file.create_tmp_file()
|
||||
local tmp_file = os.tmpname()
|
||||
if dt.configuration.running_os == "windows" then
|
||||
tmp_file = dt.configuration.tmp_dir .. tmp_file -- windows os.tmpname() defaults to root directory
|
||||
end
|
||||
|
||||
local f = io.open(tmp_file, "w")
|
||||
if not f then
|
||||
|
||||
@@ -199,7 +199,7 @@ function dtutils_log.msg(level, ...)
|
||||
table.remove(args, 1)
|
||||
end
|
||||
local log_msg = level.label
|
||||
if level.engine ~= dt_screen and call_level ~= 0 then
|
||||
if level.engine ~= dt_print and call_level ~= 0 then
|
||||
log_msg = log_msg .. dtutils_log.caller(call_level, level.caller_info) .. " "
|
||||
elseif log_msg:len() > 2 then
|
||||
log_msg = log_msg .. " "
|
||||
|
||||
@@ -1,6 +1,17 @@
|
||||
local dtutils_string = {}
|
||||
|
||||
local dt = require "darktable"
|
||||
local du = require "lib/dtutils"
|
||||
local log = require "lib/dtutils.log"
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
local DEFAULT_LOG_LEVEL = log.error
|
||||
|
||||
local function _(msg)
|
||||
return gettext(msg)
|
||||
end
|
||||
|
||||
dtutils_string.log_level = DEFAULT_LOG_LEVEL
|
||||
|
||||
dtutils_string.libdoc = {
|
||||
Name = [[dtutils.string]],
|
||||
@@ -48,6 +59,8 @@ dtutils_string.libdoc.functions["strip_accents"] = {
|
||||
}
|
||||
|
||||
function dtutils_string.strip_accents( str )
|
||||
local old_log_level = log.log_level()
|
||||
log.log_level(dtutils_string.log_level)
|
||||
local tableAccents = {}
|
||||
tableAccents["à"] = "a"
|
||||
tableAccents["á"] = "a"
|
||||
@@ -111,6 +124,7 @@ function dtutils_string.strip_accents( str )
|
||||
end
|
||||
end
|
||||
|
||||
log.log_level(old_log_level)
|
||||
return normalizedString
|
||||
|
||||
end
|
||||
@@ -136,6 +150,8 @@ dtutils_string.libdoc.functions["escape_xml_characters"] = {
|
||||
|
||||
-- Keep & first, otherwise it will double escape other characters
|
||||
function dtutils_string.escape_xml_characters( str )
|
||||
local old_log_level = log.log_level()
|
||||
log.log_level(dtutils_string.log_level)
|
||||
|
||||
str = string.gsub(str,"&", "&")
|
||||
str = string.gsub(str,"\"", """)
|
||||
@@ -143,6 +159,7 @@ function dtutils_string.escape_xml_characters( str )
|
||||
str = string.gsub(str,"<", "<")
|
||||
str = string.gsub(str,">", ">")
|
||||
|
||||
log.log_level(old_log_level)
|
||||
return str
|
||||
end
|
||||
|
||||
@@ -165,11 +182,14 @@ dtutils_string.libdoc.functions["urlencode"] = {
|
||||
}
|
||||
|
||||
function dtutils_string.urlencode(str)
|
||||
local old_log_level = log.log_level()
|
||||
log.log_level(dtutils_string.log_level)
|
||||
if (str) then
|
||||
str = string.gsub (str, "\n", "\r\n")
|
||||
str = string.gsub (str, "([^%w ])", function (c) return string.format ("%%%02X", string.byte(c)) end)
|
||||
str = string.gsub (str, " ", "+")
|
||||
end
|
||||
log.log_level(old_log_level)
|
||||
return str
|
||||
end
|
||||
|
||||
@@ -192,11 +212,15 @@ dtutils_string.libdoc.functions["is_not_sanitized"] = {
|
||||
}
|
||||
|
||||
local function _is_not_sanitized_posix(str)
|
||||
local old_log_level = log.log_level()
|
||||
log.log_level(dtutils_string.log_level)
|
||||
-- A sanitized string must be quoted.
|
||||
if not string.match(str, "^'.*'$") then
|
||||
log.log_level(old_log_level)
|
||||
return true
|
||||
-- A quoted string containing no quote characters within is sanitized.
|
||||
elseif string.match(str, "^'[^']*'$") then
|
||||
log.log_level(old_log_level)
|
||||
return false
|
||||
end
|
||||
|
||||
@@ -205,24 +229,34 @@ local function _is_not_sanitized_posix(str)
|
||||
local quotesStripped = string.sub(str, 2, -2)
|
||||
local escapedQuotesRemoved = string.gsub(quotesStripped, "'\\''", "")
|
||||
if string.find(escapedQuotesRemoved, "'") then
|
||||
log.log_level(old_log_level)
|
||||
return true
|
||||
else
|
||||
log.log_level(old_log_level)
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
local function _is_not_sanitized_windows(str)
|
||||
local old_log_level = log.log_level()
|
||||
log.log_level(dtutils_string.log_level)
|
||||
if not string.match(str, "^\".*\"$") then
|
||||
log.log_level(old_log_level)
|
||||
return true
|
||||
else
|
||||
log.log_level(old_log_level)
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
function dtutils_string.is_not_sanitized(str)
|
||||
local old_log_level = log.log_level()
|
||||
log.log_level(dtutils_string.log_level)
|
||||
if dt.configuration.running_os == "windows" then
|
||||
log.log_level(old_log_level)
|
||||
return _is_not_sanitized_windows(str)
|
||||
else
|
||||
log.log_level(old_log_level)
|
||||
return _is_not_sanitized_posix(str)
|
||||
end
|
||||
end
|
||||
@@ -246,27 +280,63 @@ dtutils_string.libdoc.functions["sanitize"] = {
|
||||
}
|
||||
|
||||
local function _sanitize_posix(str)
|
||||
local old_log_level = log.log_level()
|
||||
log.log_level(dtutils_string.log_level)
|
||||
if _is_not_sanitized_posix(str) then
|
||||
log.log_level(old_log_level)
|
||||
return "'" .. string.gsub(str, "'", "'\\''") .. "'"
|
||||
else
|
||||
log.log_level(old_log_level)
|
||||
return str
|
||||
end
|
||||
end
|
||||
|
||||
local function _sanitize_windows(str)
|
||||
local old_log_level = log.log_level()
|
||||
log.log_level(dtutils_string.log_level)
|
||||
if _is_not_sanitized_windows(str) then
|
||||
log.log_level(old_log_level)
|
||||
return "\"" .. string.gsub(str, "\"", "\"^\"\"") .. "\""
|
||||
else
|
||||
log.log_level(old_log_level)
|
||||
return str
|
||||
end
|
||||
end
|
||||
|
||||
function dtutils_string.sanitize(str)
|
||||
local function _should_be_sanitized(str)
|
||||
local old_log_level = log.log_level()
|
||||
local result = false
|
||||
local UNSAFE_POSIX_FILENAME_CHARS <const> = "[^%w/._%-]+"
|
||||
local UNSAFE_WIN_FILENAME_CHARS <const> = "[^%w\\._%-:]+"
|
||||
|
||||
local pattern = UNSAFE_POSIX_FILENAME_CHARS
|
||||
if dt.configuration.running_os == "windows" then
|
||||
return _sanitize_windows(str)
|
||||
else
|
||||
return _sanitize_posix(str)
|
||||
pattern = UNSAFE_WIN_FILENAME_CHARS
|
||||
end
|
||||
|
||||
log.log_level(dtutils_string.log_level)
|
||||
if string.match(str, pattern) then
|
||||
result = true
|
||||
end
|
||||
log.log_level(old_log_level)
|
||||
return result
|
||||
end
|
||||
|
||||
function dtutils_string.sanitize(str)
|
||||
local old_log_level = log.log_level()
|
||||
local sanitized_str = nil
|
||||
log.log_level(dtutils_string.log_level)
|
||||
if _should_be_sanitized(str) then
|
||||
if dt.configuration.running_os == "windows" then
|
||||
sanitized_str = _sanitize_windows(str)
|
||||
else
|
||||
sanitized_str = _sanitize_posix(str)
|
||||
end
|
||||
else
|
||||
sanitized_str = str
|
||||
end
|
||||
log.log_level(old_log_level)
|
||||
return sanitized_str
|
||||
end
|
||||
|
||||
dtutils_string.libdoc.functions["sanitize_lua"] = {
|
||||
@@ -288,9 +358,16 @@ dtutils_string.libdoc.functions["sanitize_lua"] = {
|
||||
}
|
||||
|
||||
function dtutils_string.sanitize_lua(str)
|
||||
local old_log_level = log.log_level()
|
||||
log.log_level(dtutils_string.log_level)
|
||||
str = string.gsub(str, "%%", "%%%%")
|
||||
str = string.gsub(str, "%-", "%%-")
|
||||
str = string.gsub(str, "%(", "%%(")
|
||||
str = string.gsub(str, "%)", "%%)")
|
||||
str = string.gsub(str, "%[", "%%[")
|
||||
str = string.gsub(str, "%]", "%%]")
|
||||
str = string.gsub(str, "+", "%%+")
|
||||
log.log_level(old_log_level)
|
||||
return str
|
||||
end
|
||||
|
||||
@@ -313,6 +390,8 @@ dtutils_string.libdoc.functions["split_filepath"] = {
|
||||
}
|
||||
|
||||
function dtutils_string.split_filepath(str)
|
||||
local old_log_level = log.log_level()
|
||||
log.log_level(dtutils_string.log_level)
|
||||
-- strip out single quotes from quoted pathnames
|
||||
str = string.gsub(str, "'", "")
|
||||
str = string.gsub(str, '"', '')
|
||||
@@ -323,6 +402,7 @@ function dtutils_string.split_filepath(str)
|
||||
result["basename"] = result["filetype"]
|
||||
result["filetype"] = ""
|
||||
end
|
||||
log.log_level(old_log_level)
|
||||
return result
|
||||
end
|
||||
|
||||
@@ -344,7 +424,10 @@ dtutils_string.libdoc.functions["get_path"] = {
|
||||
}
|
||||
|
||||
function dtutils_string.get_path(str)
|
||||
local old_log_level = log.log_level()
|
||||
log.log_level(dtutils_string.log_level)
|
||||
local parts = dtutils_string.split_filepath(str)
|
||||
log.log_level(old_log_level)
|
||||
return parts["path"]
|
||||
end
|
||||
|
||||
@@ -366,7 +449,10 @@ dtutils_string.libdoc.functions["get_filename"] = {
|
||||
}
|
||||
|
||||
function dtutils_string.get_filename(str)
|
||||
local old_log_level = log.log_level()
|
||||
log.log_level(dtutils_string.log_level)
|
||||
local parts = dtutils_string.split_filepath(str)
|
||||
log.log_level(old_log_level)
|
||||
return parts["filename"]
|
||||
end
|
||||
|
||||
@@ -389,7 +475,10 @@ dtutils_string.libdoc.functions["get_basename"] = {
|
||||
}
|
||||
|
||||
function dtutils_string.get_basename(str)
|
||||
local old_log_level = log.log_level()
|
||||
log.log_level(dtutils_string.log_level)
|
||||
local parts = dtutils_string.split_filepath(str)
|
||||
log.log_level(old_log_level)
|
||||
return parts["basename"]
|
||||
end
|
||||
|
||||
@@ -411,10 +500,732 @@ dtutils_string.libdoc.functions["get_filetype"] = {
|
||||
}
|
||||
|
||||
function dtutils_string.get_filetype(str)
|
||||
local old_log_level = log.log_level()
|
||||
log.log_level(dtutils_string.log_level)
|
||||
local parts = dtutils_string.split_filepath(str)
|
||||
log.log_level(old_log_level)
|
||||
return parts["filetype"]
|
||||
end
|
||||
|
||||
dtutils_string.libdoc.functions["build_substitute_list"] = {
|
||||
Name = [[build_substitute_list]],
|
||||
Synopsis = [[build a list of variable substitutions]],
|
||||
Usage = [[local ds = require "lib/dtutils.string"
|
||||
ds.build_substitute_list(image, sequence, variable_string, [username], [pic_folder], [home], [desktop])
|
||||
image - dt_lua_image_t - the image being processed
|
||||
sequence - integer - the sequence number of the image being processed (exported)
|
||||
variable_string - string - the substitution variable string
|
||||
[username] - string - optional - user name. Will be determined if not supplied
|
||||
[pic_folder] - string - optional - pictures folder name. Will be determined if not supplied
|
||||
[home] - string - optional - home directory. Will be determined if not supplied
|
||||
[desktop] - string - optional - desktop directory. Will be determined if not supplied]],
|
||||
Description = [[build_substitute_list populates variables with values from the arguments
|
||||
and determined from the system and darktable.]],
|
||||
Return_Value = [[]],
|
||||
Limitations = [[If the value for a variable can not be determined, or if it is not supported,
|
||||
then an empty string is used for the value.]],
|
||||
Example = [[]],
|
||||
See_Also = [[https://docs.darktable.org/usermanual/4.6/en/special-topics/variables/]],
|
||||
Reference = [[]],
|
||||
License = [[]],
|
||||
Copyright = [[]],
|
||||
}
|
||||
|
||||
local substitutes = {}
|
||||
local category_substitutes = {}
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- C O N S T A N T S
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
local PLACEHOLDERS = {"ROLL.NAME",
|
||||
"FILE.FOLDER",
|
||||
"FILE.NAME",
|
||||
"FILE.EXTENSION",
|
||||
"ID",
|
||||
"VERSION",
|
||||
"VERSION.IF.MULTI",
|
||||
"VERSION.NAME",
|
||||
"DARKTABLE.VERSION",
|
||||
"DARKTABLE.NAME", -- Not Implemented
|
||||
"SEQUENCE",
|
||||
"WIDTH.SENSOR",
|
||||
"HEIGHT.SENSOR",
|
||||
"WIDTH.RAW",
|
||||
"HEIGHT.RAW",
|
||||
"WIDTH.CROP",
|
||||
"HEIGHT.CROP",
|
||||
"WIDTH.EXPORT",
|
||||
"HEIGHT.EXPORT",
|
||||
"WIDTH.MAX", -- Not Implemented
|
||||
"HEIGHT.MAX", -- Not Implemented
|
||||
"YEAR",
|
||||
"YEAR.SHORT",
|
||||
"MONTH",
|
||||
"MONTH.LONG",
|
||||
"MONTH.SHORT",
|
||||
"DAY",
|
||||
"HOUR",
|
||||
"HOUR.AMPM", -- Not Implemented
|
||||
"MINUTE",
|
||||
"SECOND",
|
||||
"MSEC",
|
||||
"EXIF.YEAR",
|
||||
"EXIF.YEAR.SHORT",
|
||||
"EXIF.MONTH",
|
||||
"EXIF.MONTH.LONG",
|
||||
"EXIF.MONTH.SHORT",
|
||||
"EXIF.DAY",
|
||||
"EXIF.HOUR",
|
||||
"EXIF.HOUR.AMPM", -- Not Implemented
|
||||
"EXIF.MINUTE",
|
||||
"EXIF.SECOND",
|
||||
"EXIF.MSEC",
|
||||
"EXIF.DATE.REGIONAL", -- Not Implemented
|
||||
"EXIF.TIME.REGIONAL", -- Not Implemented
|
||||
"EXIF.ISO",
|
||||
"EXIF.EXPOSURE",
|
||||
"EXIF.EXPOSURE.BIAS",
|
||||
"EXIF.EXPOSURE.PROGRAM", -- Not Implemented
|
||||
"EXIF.APERTURE",
|
||||
"EXIF.CROP.FACTOR",
|
||||
"EXIF.FOCAL.LENGTH",
|
||||
"EXIF.FOCAL.LENGTH.EQUIV", -- Not Implemented
|
||||
"EXIF.FOCUS.DISTANCE",
|
||||
"EXIF.MAKER",
|
||||
"EXIF.MODEL",
|
||||
"EXIF.WHTIEBALANCE", -- Not Implemented
|
||||
"EXIF.METERING", -- Not Implemented
|
||||
"EXIF.LENS",
|
||||
"EXIF.FLASH.ICON", -- Not Implemented
|
||||
"EXIF.FLASH", -- Not Implemented
|
||||
"GPS.LONGITUDE", -- Not Implemented
|
||||
"GPS.LATITUDE", -- Not Implemented
|
||||
"GPS.ELEVATION", -- Not Implemented
|
||||
"GPS.LOCATION.ICON", -- Not Implemented
|
||||
"LONGITUDE",
|
||||
"LATITUDE",
|
||||
"ELEVATION",
|
||||
"GPS.LOCATION", -- Not Implemented
|
||||
"STARS",
|
||||
"RATING.ICONS", -- Not Implemented
|
||||
"LABELS",
|
||||
"LABELS.ICONS", -- Not Implemented
|
||||
"TITLE",
|
||||
"DESCRIPTION",
|
||||
"CREATOR",
|
||||
"PUBLISHER",
|
||||
"RIGHTS",
|
||||
"TAGS", -- Not Implemented
|
||||
"SIDECAR.TXT", -- Not Implemented
|
||||
"FOLDER.PICTURES",
|
||||
"FOLDER.HOME",
|
||||
"FOLDER.DESKTOP",
|
||||
"OPENCL.ACTIVATED", -- Not Implemented
|
||||
"USERNAME",
|
||||
"NL", -- Not Implemented
|
||||
"JOBCODE" -- Not Implemented
|
||||
}
|
||||
|
||||
local PS = dt.configuration.running_os == "windows" and "\\" or "/"
|
||||
local USER = os.getenv("USERNAME")
|
||||
local HOME = dt.configuration.running_os == "windows" and os.getenv("HOMEPATH") or os.getenv("HOME")
|
||||
local PICTURES = HOME .. PS .. (dt.configuration.running_os == "windows" and "My Pictures" or "Pictures")
|
||||
local DESKTOP = HOME .. PS .. "Desktop"
|
||||
|
||||
local function get_colorlabels(image)
|
||||
local old_log_level = log.log_level()
|
||||
log.log_level(dtutils_string.log_level)
|
||||
|
||||
local colorlabels = {}
|
||||
|
||||
if image.red then table.insert(colorlabels, "red") end
|
||||
if image.yellow then table.insert(colorlabels, "yellow") end
|
||||
if image.green then table.insert(colorlabels, "green") end
|
||||
if image.blue then table.insert(colorlabels, "blue") end
|
||||
if image.purple then table.insert(colorlabels, "purple") end
|
||||
|
||||
local labels = #colorlabels == 1 and colorlabels[1] or du.join(colorlabels, "_")
|
||||
|
||||
log.log_level(old_log_level)
|
||||
|
||||
return labels
|
||||
end
|
||||
|
||||
-- find the $CATEGORYn and $CATEGORY[n,m] requests and add them to the substitute list
|
||||
|
||||
local function build_category_substitution_list(image, variable_string)
|
||||
local old_log_level = log.log_level()
|
||||
log.log_level(dtutils_string.log_level)
|
||||
|
||||
for match in string.gmatch(variable_string, "%$%(.-%)?%)") do -- grab each complete variable
|
||||
log.msg(log.info, "match is " .. match)
|
||||
|
||||
local var = string.match(match, "%$%((.-%)?)%)") -- strip of the leading $( and trailing )
|
||||
log.msg(log.info, "var is " .. var)
|
||||
|
||||
if string.match(var, "CATEGORY%d") or string.match(var, "CATEGORY%[") then
|
||||
local element
|
||||
local tag
|
||||
|
||||
if string.match(var, "CATEGORY%d") then
|
||||
element, tag = string.match(var, "CATEGORY(%d)%((.-)%)") -- get the element number and the tag to match
|
||||
else
|
||||
element, tag = string.match(var, "%[(%d),(.-)%]") -- new syntax
|
||||
end
|
||||
|
||||
element = element + 1 -- add one to element since lua arrays are 1 based
|
||||
log.msg(log.debug, "element is " .. element .. " and tag is " .. tag)
|
||||
|
||||
local tags = image:get_tags()
|
||||
log.msg(log.debug, "got " .. #tags .. " from image " .. image.filename)
|
||||
|
||||
for _, image_tag in ipairs(tags) do
|
||||
log.msg(log.debug, "checking tag " .. image_tag.name)
|
||||
|
||||
if string.match(image_tag.name, tag) then
|
||||
fields = du.split(image_tag.name, "|")
|
||||
|
||||
if element <= #fields then
|
||||
substitutes[var] = fields[element]
|
||||
else
|
||||
substitutes[var] = ""
|
||||
log.msg(log.warn, "requested field for tag " .. tag .. " doesn't exist")
|
||||
end
|
||||
|
||||
log.msg(log.info, "set substitute for " .. var .. " to " .. fields[element])
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
log.log_level(old_log_level)
|
||||
end
|
||||
|
||||
-- convert image.exif_datetime_taken 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
|
||||
|
||||
-- build the argument substitution list from each image
|
||||
|
||||
function dtutils_string.build_substitute_list(image, sequence, variable_string, username, pic_folder, home, desktop)
|
||||
local old_log_level = log.log_level()
|
||||
log.log_level(dtutils_string.log_level)
|
||||
|
||||
-- is time millisecond aware? Implemented in API 9.1.0
|
||||
|
||||
local is_api_9_1 = true
|
||||
if dt.configuration.api_version_string < "9.1.0" then
|
||||
is_api_9_1 = false
|
||||
end
|
||||
|
||||
local is_api_9_4 = dt.configuration.api_version_string >= "9.4.0" and true or false
|
||||
|
||||
local datetime = os.date("*t")
|
||||
local long_month = os.date("%B")
|
||||
local short_month = os.date("%b")
|
||||
local user_name = username or USER
|
||||
local pictures_folder = pic_folder or PICTURES
|
||||
local home_folder = home or HOME
|
||||
local desktop_folder = desktop or DESKTOP
|
||||
|
||||
local labels = get_colorlabels(image)
|
||||
|
||||
local eyear, emon, eday, ehour, emin, esec, emsec
|
||||
if dt.preferences.read("darktable", "lighttable/ui/milliseconds", "bool") and is_api_9_1 then
|
||||
eyear, emon, eday, ehour, emin, esec, emsec =
|
||||
string.match(image.exif_datetime_taken, "(%d+):(%d+):(%d+) (%d+):(%d+):(%d+)%.(%d+)$")
|
||||
else
|
||||
emsec = "0"
|
||||
eyear, emon, eday, ehour, emin, esec =
|
||||
string.match(image.exif_datetime_taken, "(%d+):(%d+):(%d+) (%d+):(%d+):(%d+)$")
|
||||
end
|
||||
|
||||
local version_multi = #image:get_group_members() > 1 and image.duplicate_index or ""
|
||||
|
||||
local replacements = {dtutils_string.get_basename(image.film.path),-- ROLL.NAME
|
||||
image.path, -- FILE.FOLDER
|
||||
dtutils_string.get_basename(image.filename),-- FILE.NAME
|
||||
dtutils_string.get_filetype(image.filename),-- FILE.EXTENSION
|
||||
image.id, -- ID
|
||||
image.duplicate_index, -- VERSION
|
||||
version_multi, -- VERSION.IF_MULTI
|
||||
image.version_name, -- VERSION.NAME
|
||||
dt.configuration.version, -- DARKTABLE.VERSION
|
||||
"", -- DARKTABLE.NAME
|
||||
string.format("%04d", sequence), -- SEQUENCE
|
||||
image.width, -- WIDTH.SENSOR
|
||||
image.height, -- HEIGHT.SENSOR
|
||||
is_api_9_1 and image.p_width or "", -- WIDTH.RAW
|
||||
is_api_9_1 and image.p_height or "", -- HEIGHT.RAW
|
||||
is_api_9_1 and image.final_width or "", -- WIDTH.CROP
|
||||
is_api_9_1 and image.final_height or "", -- HEIGHT.CROP
|
||||
is_api_9_1 and image.final_width or "", -- WIDTH.EXPORT
|
||||
is_api_9_1 and image.final_height or "", -- HEIGHT.EXPORT
|
||||
"", -- WIDTH.MAX -- from export module
|
||||
"", -- HEIGHT.MAX -- from export module
|
||||
string.format("%4d", datetime.year), -- YEAR
|
||||
string.sub(datetime.year, 3), -- YEAR.SHORT
|
||||
string.format("%02d", datetime.month), -- MONTH
|
||||
long_month, -- MONTH.LONG
|
||||
short_month, -- MONTH.SHORT
|
||||
string.format("%02d", datetime.day), -- DAY
|
||||
string.format("%02d", datetime.hour), -- HOUR
|
||||
"", -- HOUR.AMPM
|
||||
string.format("%02d", datetime.min), -- MINUTE
|
||||
string.format("%02d", datetime.sec), -- SECOND
|
||||
0, -- MSEC
|
||||
eyear, -- EXIF.YEAR
|
||||
string.sub(eyear, 3), -- EXIF.YEAR.SHORT
|
||||
emon, -- EXIF.MONTH
|
||||
os.date("%B", exiftime2systime(image.exif_datetime_taken)), -- EXIF.MONTH.LONG
|
||||
os.date("%b", exiftime2systime(image.exif_datetime_taken)), -- EXIF.MONTH.SHORT
|
||||
eday, -- EXIF.DAY
|
||||
ehour, -- EXIF.HOUR
|
||||
"", -- EXIF.HOUR.AMPM
|
||||
emin, -- EXIF.MINUTE
|
||||
esec, -- EXIF.SECOND
|
||||
emsec, -- EXIF.MSEC
|
||||
"", -- EXIF.DATE.REGIONAL - wont be implemented
|
||||
"", -- EXIF.TIME.REGIONAL - wont be implemented
|
||||
string.format("%d", image.exif_iso), -- EXIF.ISO
|
||||
string.format("%.0f", 1./image.exif_exposure), -- EXIF.EXPOSURE
|
||||
image.exif_exposure_bias, -- EXIF.EXPOSURE.BIAS
|
||||
"", -- EXIF.EXPOSURE.PROGRAM
|
||||
string.format("%.01f", image.exif_aperture), -- EXIF.APERTURE
|
||||
string.format("%.01f", image.exif_crop),-- EXIF.CROP_FACTOR
|
||||
string.format("%.0f", image.exif_focal_length), -- EXIF.FOCAL.LENGTH
|
||||
string.format("%.0f", image.exif_focal_length * image.exif_crop), -- EXIF.FOCAL.LENGTH.EQUIV
|
||||
image.exif_focus_distance, -- EXIF.FOCUS.DISTANCE
|
||||
image.exif_maker, -- EXIF.MAKER
|
||||
image.exif_model, -- EXIF.MODEL
|
||||
is_api_9_4 and image.exif_whitebalance or "", -- EXIF.WHITEBALANCE
|
||||
is_api_9_4 and image.exif_metering_mode or "", -- EXIF.METERING
|
||||
image.exif_lens, -- LENS
|
||||
"", -- EXIF.FLASH.ICON
|
||||
is_api_9_4 and image.exif_flash or "", -- EXIF.FLASH
|
||||
"", -- GPS.LONGITUDE
|
||||
"", -- GPS.LATITUDE
|
||||
"", -- GPS.ELEVATION
|
||||
"", -- GPS.LOCATION.ICON
|
||||
image.longitude or "", -- LONGITUDE
|
||||
image.latitude or "", -- LATITUDE
|
||||
image.elevation or "", -- ELEVATION
|
||||
"", -- GPS.LOCATION - wont be implemented
|
||||
image.rating, -- STARS
|
||||
"", -- RATING.ICONS - wont be implemented
|
||||
labels, -- LABELS
|
||||
"", -- LABELS.ICONS - wont be implemented
|
||||
image.title, -- TITLE
|
||||
image.description, -- DESCRIPTION
|
||||
image.creator, -- CREATOR
|
||||
image.publisher, -- PUBLISHER
|
||||
image.rights, -- RIGHTS
|
||||
"", -- TAGS - wont be implemented
|
||||
"", -- SIDECAR.TXT - wont be implemented
|
||||
pictures_folder, -- FOLDER.PICTURES
|
||||
home_folder, -- FOLDER.HOME
|
||||
desktop_folder, -- FOLDER.DESKTOP
|
||||
"", -- OPENCL.ACTIVATED - wont be implemented
|
||||
user_name, -- USERNAME
|
||||
"", -- NL - wont be implemented
|
||||
"" -- JOBCODE - wont be implemented
|
||||
}
|
||||
|
||||
-- populate the substitution list
|
||||
|
||||
for i = 1, #PLACEHOLDERS, 1 do
|
||||
substitutes[PLACEHOLDERS[i]] = replacements[i]
|
||||
log.msg(log.info, "setting " .. PLACEHOLDERS[i] .. " to " .. tostring(replacements[i]))
|
||||
end
|
||||
|
||||
-- do category substitutions separately
|
||||
|
||||
build_category_substitution_list(image, variable_string)
|
||||
|
||||
log.log_level(old_log_level)
|
||||
end
|
||||
|
||||
dtutils_string.libdoc.functions["get_substitution_tooltip"] = {
|
||||
Name = [[get_substitution_tooltip]],
|
||||
Synopsis = [[get a tooltip that lists the substitution variables]],
|
||||
Usage = [[local ds = require "lib/dtutils.string"
|
||||
ds.get_substitution_tooltip()
|
||||
Description = [[get_substitution_tooltip lists the variables with brief explanations]],
|
||||
Return_Value = [[string - the tooltip]],
|
||||
Limitations = [[]],
|
||||
Example = [[]],
|
||||
See_Also = [[https://docs.darktable.org/usermanual/4.6/en/special-topics/variables/]],
|
||||
Reference = [[]],
|
||||
License = [[]],
|
||||
Copyright = [[]],
|
||||
}
|
||||
|
||||
function dtutils_string.get_substitution_tooltip()
|
||||
|
||||
return table.concat({
|
||||
_("$(ROLL.NAME) - roll of the input image"),
|
||||
_("$(FILE.FOLDER) - folder containing the input image"),
|
||||
_("$(FILE.NAME) - basename of the input image"),
|
||||
_("$(FILE.EXTENSION) - extension of the input image"),
|
||||
_("$(ID) - image ID"),
|
||||
_("$(VERSION) - duplicate version"),
|
||||
_("$(VERSION.IF_MULTI) - same as $(VERSION) but null string if only one version exists"),
|
||||
_("$(VERSION.NAME) - version name from metadata"),
|
||||
_("$(DARKTABLE.VERSION) - current darktable version"),
|
||||
-- _("$(DARKTABLE.NAME) - darktable name"), -- not implemented
|
||||
_("$(SEQUENCE[n,m]) - sequence number, n: number of digits, m: start number"),
|
||||
_("$(WIDTH.SENSOR) - image sensor width"),
|
||||
_("$(HEIGHT.SENSOR) - image sensor height"),
|
||||
_("$(WIDTH.RAW) - RAW image width"),
|
||||
_("$(HEIGHT.RAW) - RAW image height"),
|
||||
_("$(WIDTH.CROP) - image width after crop"),
|
||||
_("$(HEIGHT.CROP) - image height after crop"),
|
||||
_("$(WIDTH.EXPORT) - exported image width"),
|
||||
_("$(HEIGHT.EXPORT) - exported image height"),
|
||||
-- _("$(WIDTH.MAX) - maximum image export width"), -- not implemented
|
||||
-- _("$(HEIGHT.MAX) - maximum image export height"), -- not implemented
|
||||
_("$(YEAR) - year"),
|
||||
_("$(YEAR.SHORT) - year without century"),
|
||||
_("$(MONTH) - month"),
|
||||
_("$(MONTH.LONG) - full month name according to the current locale"),
|
||||
_("$(MONTH.SHORT) - abbreviated month name according to the current locale"),
|
||||
_("$(DAY) - day"),
|
||||
_("$(HOUR) - hour"),
|
||||
-- _("$(HOUR.AMPM) - hour, 12-hour clock"), -- not implemented
|
||||
_("$(MINUTE) - minute"),
|
||||
_("$(SECOND) - second"),
|
||||
_("$(MSEC) - millisecond"),
|
||||
_("$(EXIF.YEAR) - EXIF year"),
|
||||
_("$(EXIF.YEAR.SHORT) - EXIF year without century"),
|
||||
_("$(EXIF.MONTH) - EXIF month"),
|
||||
_("$(EXIF.MONTH.LONG) - full EXIF month name according to the current locale"),
|
||||
_("$(EXIF.MONTH.SHORT) - abbreviated EXIF month name according to the current locale"),
|
||||
_("$(EXIF.DAY) - EXIF day"),
|
||||
_("$(EXIF.HOUR) - EXIF hour"),
|
||||
-- _("$(EXIF.HOUR.AMPM) - EXIF hour, 12-hour clock") .. "\n" .. -- not implemented
|
||||
_("$(EXIF.MINUTE) - EXIF minute"),
|
||||
_("$(EXIF.SECOND) - EXIF second"),
|
||||
_("$(EXIF.MSEC) - EXIF millisecond"),
|
||||
-- _("$(EXIF.DATE.REGIONAL) - localized EXIF date"), -- not implemented
|
||||
-- _("$(EXIF.TIME.REGIONAL) - localized EXIF time"), -- not implemented
|
||||
_("$(EXIF.ISO) - ISO value"),
|
||||
_("$(EXIF.EXPOSURE) - EXIF exposure"),
|
||||
_("$(EXIF.EXPOSURE.BIAS) - EXIF exposure bias"),
|
||||
-- _("$(EXIF.EXPOSURE.PROGRAM) - EXIF exposure program"), -- not implemented
|
||||
_("$(EXIF.APERTURE) - EXIF aperture"),
|
||||
_("$(EXIF.CROP_FACTOR) - EXIF crop factor"),
|
||||
_("$(EXIF.FOCAL.LENGTH) - EXIF focal length"),
|
||||
_("$(EXIF.FOCAL.LENGTH.EQUIV) - EXIF 35 mm equivalent focal length"),
|
||||
_("$(EXIF.FOCUS.DISTANCE) - EXIF focal distance"),
|
||||
_("$(EXIF.MAKER) - camera maker") ..
|
||||
_("$(EXIF.MODEL) - camera model") ..
|
||||
_("$(EXIF.WHITEBALANCE) - EXIF selected white balance") .. -- not implemented
|
||||
_("$(EXIF.METERING) - EXIF exposure metering mode") .. -- not implemented
|
||||
_("$(EXIF.LENS) - lens") ..
|
||||
-- _("$(EXIF.FLASH.ICON) - icon indicating whether flash was used") .. -- not implemented
|
||||
_("$(EXIF.FLASH) - was flash used (yes/no/--)") .. -- not implemented
|
||||
-- _("$(GPS.LONGITUDE) - longitude"),-- not implemented
|
||||
-- _("$(GPS.LATITUDE) - latitude"),-- not implemented
|
||||
-- _("$(GPS.ELEVATION) - elevation"),-- not implemented
|
||||
-- _("$(GPS.LOCATION.ICON) - icon indicating whether GPS location is known"),-- not implemented
|
||||
_("$(LONGITUDE) - longitude"),
|
||||
_("$(LATITUDE) - latitude"),
|
||||
_("$(ELEVATION) - elevation"),
|
||||
_("$(STARS) - star rating as number (-1 for rejected)"),
|
||||
-- _("$(RATING.ICONS) - star/reject rating in icon form"),-- not implemented
|
||||
_("$(LABELS) - color labels as text"),
|
||||
-- _("$(LABELS.ICONS) - color labels as icons"),-- not implemented
|
||||
_("$(TITLE) - title from metadata"),
|
||||
_("$(DESCRIPTION) - description from metadata"),
|
||||
_("$(CREATOR) - creator from metadata"),
|
||||
_("$(PUBLISHER) - publisher from metadata"),
|
||||
_("$(RIGHTS) - rights from metadata"),
|
||||
--_("$(TAGS) - tags as set in metadata settings"),
|
||||
_("$(CATEGORY[n,category]) - subtag of level n in hierarchical tags"),
|
||||
_("$(SIDECAR_TXT) - contents of .txt sidecar file, if present"),
|
||||
_("$(FOLDER.PICTURES) - pictures folder"),
|
||||
_("$(FOLDER.HOME) - home folder"),
|
||||
_("$(FOLDER.DESKTOP) - desktop folder"),
|
||||
-- _("$(OPENCL.ACTIVATED) - whether OpenCL is activated"),
|
||||
_("$(USERNAME) - login name"),
|
||||
-- _("$(NL) - newline"),
|
||||
-- _("$(JOBCODE) - job code for import"),
|
||||
""}, "\n")
|
||||
end
|
||||
|
||||
-- handle different versions of names
|
||||
|
||||
local function check_legacy_vars(var_name)
|
||||
local var = var_name
|
||||
|
||||
if string.match(var, "_") then
|
||||
var = string.gsub(var, "_", ".")
|
||||
end
|
||||
|
||||
if string.match(var, "^HOME$") then var = "FOLDER.HOME" end
|
||||
if string.match(var, "^PICTURES.FOLDER$") then var = "FOLDER.PICTURES" end
|
||||
if string.match(var, "^DESKTOP$") then var = "FOLDER.DESKTOP" end
|
||||
|
||||
return var
|
||||
end
|
||||
|
||||
-- get the substitution and do any string manipulations requested
|
||||
|
||||
local function treat(var_string)
|
||||
local old_log_level = log.log_level()
|
||||
log.log_level(dtutils_string.log_level)
|
||||
|
||||
local ret_val = ""
|
||||
|
||||
-- remove the var from the string
|
||||
local var = string.match(var_string, "[%a%._]+")
|
||||
|
||||
var = check_legacy_vars(var)
|
||||
log.msg(log.info, "var_string is " .. tostring(var_string) .. " and var is " .. tostring(var))
|
||||
|
||||
if string.match(var_string, "CATEGORY%d") or string.match(var_string, "CATEGORY%[") then
|
||||
log.msg(log.info, "substituting for " .. var_string)
|
||||
ret_val = substitutes[var_string]
|
||||
if not ret_val then ret_val = "" end
|
||||
log.msg(log.info, "ret_val is " .. ret_val)
|
||||
|
||||
elseif string.match(var_string, "SEQUENCE%[") then
|
||||
local width, start = string.match(var_string, "(%d+),(%d)")
|
||||
local seq_val = tonumber(substitutes[var])
|
||||
local pat = "%0" .. width .. "d"
|
||||
substitutes[var_string] = string.format(pat, start + (seq_val - 1))
|
||||
ret_val = substitutes[var_string]
|
||||
|
||||
else
|
||||
ret_val = substitutes[var]
|
||||
end
|
||||
|
||||
local valid_var = false
|
||||
|
||||
if ret_val then
|
||||
valid_var = true
|
||||
end
|
||||
|
||||
if not valid_var then
|
||||
log.msg(log.error, "variable " .. var .. " is not an allowed variable, returning empty value")
|
||||
log.log_level(old_log_level)
|
||||
return ""
|
||||
end
|
||||
|
||||
-- string modifications
|
||||
|
||||
local args = string.gsub(var_string, var, "")
|
||||
log.msg(log.info, "args is " .. tostring(args))
|
||||
|
||||
if string.len(args) > 0 then
|
||||
|
||||
if string.match(args, '^%^%^') then
|
||||
ret_val = string.upper(ret_val)
|
||||
|
||||
elseif string.match(args, "^%^") then
|
||||
ret_val = string.gsub(ret_val, "^%a", string.upper, 1)
|
||||
|
||||
elseif string.match(args, "^,,") then
|
||||
ret_val = string.lower(ret_val)
|
||||
|
||||
elseif string.match(args, "^,") then
|
||||
ret_val = string.gsub(ret_val, "^%a", string.lower, 1)
|
||||
|
||||
elseif string.match(args, "^:%-?%d+:%-?%d+") then
|
||||
|
||||
local soffset, slen = string.match(args, ":(%-?%d+):(%-?%d+)")
|
||||
log.msg(log.info, "soffset is " .. soffset .. " and slen is " .. slen)
|
||||
|
||||
if tonumber(soffset) >= 0 then
|
||||
soffset = soffset + 1
|
||||
end
|
||||
log.msg(log.info, "soffset is " .. soffset .. " and slen is " .. slen)
|
||||
|
||||
if tonumber(soffset) < 0 and tonumber(slen) < 0 then
|
||||
local temp = soffset
|
||||
soffset = slen
|
||||
slen = temp
|
||||
end
|
||||
log.msg(log.info, "soffset is " .. soffset .. " and slen is " .. slen)
|
||||
|
||||
ret_val = string.sub(ret_val, soffset, slen)
|
||||
log.msg(log.info, "ret_val is " .. ret_val)
|
||||
|
||||
elseif string.match(args, "^:%-?%d+") then
|
||||
|
||||
local soffset= string.match(args, ":(%-?%d+)")
|
||||
if tonumber(soffset) >= 0 then
|
||||
soffset = soffset + 1
|
||||
end
|
||||
ret_val = string.sub(ret_val, soffset, -1)
|
||||
|
||||
elseif string.match(args, "^-%$%(.-%)") then
|
||||
|
||||
local replacement = string.match(args, "-%$%(([%a%._]+)%)")
|
||||
replacement = check_legacy_vars(replacement)
|
||||
if string.len(ret_val) == 0 then
|
||||
ret_val = substitutes[replacement]
|
||||
end
|
||||
|
||||
elseif string.match(args, "^-.+$") then
|
||||
|
||||
local replacement = string.match(args, "-(.+)$")
|
||||
if string.len(ret_val) == 0 then
|
||||
ret_val = replacement
|
||||
end
|
||||
|
||||
elseif string.match(args, "^+.+") then
|
||||
|
||||
local replacement = string.match(args, "+(.+)")
|
||||
if string.len(ret_val) > 0 then
|
||||
ret_val = replacement
|
||||
end
|
||||
|
||||
elseif string.match(args, "^#.+") then
|
||||
|
||||
local pattern = string.match(args, "#(.+)")
|
||||
log.msg(log.info, "pattern to remove is " .. tostring(pattern))
|
||||
ret_val = string.gsub(ret_val, "^" .. dtutils_string.sanitize_lua(pattern), "")
|
||||
|
||||
elseif string.match(args, "^%%.+") then
|
||||
|
||||
local pattern = string.match(args, "%%(.+)")
|
||||
ret_val = string.gsub(ret_val, pattern .. "$", "")
|
||||
|
||||
elseif string.match(args, "^//.-/.+") then
|
||||
|
||||
local pattern, replacement = string.match(args, "//(.-)/(.+)")
|
||||
ret_val = string.gsub(ret_val, pattern, replacement)
|
||||
|
||||
elseif string.match(args, "^/#.+/.+") then
|
||||
|
||||
local pattern, replacement = string.match(args, "/#(.+)/(.+)")
|
||||
ret_val = string.gsub(ret_val, "^" .. pattern, replacement, 1)
|
||||
|
||||
elseif string.match(args, "^/%%.-/.+") then
|
||||
|
||||
local pattern, replacement = string.match(args, "/%%(.-)/(.+)")
|
||||
ret_val = string.gsub(ret_val, pattern .. "$", replacement)
|
||||
|
||||
elseif string.match(args, "^/.-/.+") then
|
||||
|
||||
log.msg(log.info, "took replacement branch")
|
||||
local pattern, replacement = string.match(args, "/(.-)/(.+)")
|
||||
ret_val = string.gsub(ret_val, pattern, replacement, 1)
|
||||
end
|
||||
|
||||
end
|
||||
log.log_level(old_log_level)
|
||||
return ret_val
|
||||
end
|
||||
|
||||
dtutils_string.libdoc.functions["substitute_list"] = {
|
||||
Name = [[substitute_list]],
|
||||
Synopsis = [[Replace variables in a string with their computed values]],
|
||||
Usage = [[local ds = require "lib/dtutils.string"
|
||||
local result = ds.substitute_list(str)
|
||||
str - string - the string containing the variables to be substituted for]],
|
||||
Description = [[substitute_list replaces the variables in the supplied string with
|
||||
values computed in build_substitution_list().]],
|
||||
Return_Value = [[result - string - the input string with values substituted for the variables]],
|
||||
Limitations = [[]],
|
||||
Example = [[]],
|
||||
See_Also = [[https://docs.darktable.org/usermanual/4.6/en/special-topics/variables/]],
|
||||
Reference = [[]],
|
||||
License = [[]],
|
||||
Copyright = [[]],
|
||||
}
|
||||
|
||||
function dtutils_string.substitute_list(str)
|
||||
local old_log_level = log.log_level()
|
||||
log.log_level(dtutils_string.log_level)
|
||||
|
||||
-- replace the substitution variables in a string
|
||||
for match in string.gmatch(str, "%$%(.-%)?%)") do
|
||||
|
||||
local var = string.match(match, "%$%((.-%)?)%)")
|
||||
|
||||
local treated_var = treat(var)
|
||||
log.msg(log.info, "var is " .. var .. " and treated var is " .. tostring(treated_var))
|
||||
|
||||
str = string.gsub(str, "%$%(".. dtutils_string.sanitize_lua(var) .."%)", tostring(treated_var))
|
||||
log.msg(log.info, "str after replacement is " .. str)
|
||||
|
||||
end
|
||||
|
||||
log.log_level(old_log_level)
|
||||
|
||||
return str
|
||||
end
|
||||
|
||||
dtutils_string.libdoc.functions["clear_substitute_list"] = {
|
||||
Name = [[clear_substitute_list]],
|
||||
Synopsis = [[Clear the computed list of variable substitution values]],
|
||||
Usage = [[local ds = require "lib/dtutils.string"
|
||||
ds.clear_substitute_list()]],
|
||||
Description = [[clear_substitute_list resets the list of variable replacement values]],
|
||||
Return_Value = [[]],
|
||||
Limitations = [[]],
|
||||
Example = [[]],
|
||||
See_Also = [[]],
|
||||
Reference = [[]],
|
||||
License = [[]],
|
||||
Copyright = [[]],
|
||||
}
|
||||
|
||||
function dtutils_string.clear_substitute_list()
|
||||
local old_log_level = log.log_level()
|
||||
log.log_level(dtutils_string.log_level)
|
||||
|
||||
substitutes = {}
|
||||
category_substitutes = {}
|
||||
|
||||
log.log_level(old_log_level)
|
||||
end
|
||||
|
||||
dtutils_string.libdoc.functions["substitute"] = {
|
||||
Name = [[substitute]],
|
||||
Synopsis = [[Perform all the variable substitution steps with one function call]],
|
||||
Usage = [[local ds = require "lib/dtutils.string"
|
||||
ds.substitute(image, sequence, variable_string, [username], [pic_folder], [home], [desktop])
|
||||
image - dt_lua_image_t - the image being processed
|
||||
sequence - integer - the number of the image being processed (exported)
|
||||
variable_string - string - the substitution variable string
|
||||
[username] - string - optional - user name. Will be determined if not supplied
|
||||
[pic_folder] - string - optional - pictures folder name. Will be determined if not supplied
|
||||
[home] - string - optional - home directory. Will be determined if not supplied
|
||||
[desktop] - string - optional - desktop directory. Will be determined if not supplied]],
|
||||
Description = [[substitute initializes the substitution list by calling clear_substitute_list(),
|
||||
then builds the substitutions by calling build_substitute_list() and finally does the
|
||||
substitution by calling substitute_list(), then returns the result string.]],
|
||||
Return_Value = [[result - string - the input string with values substituted for the variables]],
|
||||
Limitations = [[]],
|
||||
Example = [[]],
|
||||
See_Also = [[https://docs.darktable.org/usermanual/4.6/en/special-topics/variables/]],
|
||||
Reference = [[]],
|
||||
License = [[]],
|
||||
Copyright = [[]],
|
||||
}
|
||||
|
||||
function dtutils_string.substitute(image, sequence, variable_string, username, pic_folder, home, desktop)
|
||||
local old_log_level = log.log_level()
|
||||
log.log_level(dtutils_string.log_level)
|
||||
|
||||
dtutils_string.clear_substitute_list()
|
||||
|
||||
dtutils_string.build_substitute_list(image, sequence, variable_string, username, pic_folder, home, desktop)
|
||||
|
||||
local str = dtutils_string.substitute_list(variable_string)
|
||||
|
||||
log.log_level(old_log_level)
|
||||
|
||||
return str
|
||||
end
|
||||
|
||||
|
||||
|
||||
return dtutils_string
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
local dtutils_system = {}
|
||||
|
||||
local dt = require "darktable"
|
||||
local ds = require "lib/dtutils.string"
|
||||
|
||||
dtutils_system.libdoc = {
|
||||
Name = [[dtutils.system]],
|
||||
@@ -85,8 +86,13 @@ function dtutils_system.windows_command(command)
|
||||
local file = io.open(fname, "w")
|
||||
if file then
|
||||
dt.print_log("opened file")
|
||||
command = string.gsub(command, "%%", "%%%%") -- escape % from windows shell
|
||||
file:write(command)
|
||||
file:write("@echo off\n")
|
||||
file:write('for /f "tokens=2 delims=:." %%x in (\'chcp\') do set cp=%%x\n')
|
||||
file:write("chcp 65001>nul\n") -- change the encoding of the terminal to handle non-english characters in path
|
||||
file:write("\n")
|
||||
file:write(command .. "\n")
|
||||
file:write("\n")
|
||||
file:write("chcp %cp%>nul\n")
|
||||
file:close()
|
||||
|
||||
result = dt.control.execute(fname)
|
||||
@@ -118,6 +124,7 @@ dtutils_system.libdoc.functions["launch_default_app"] = {
|
||||
License = [[]],
|
||||
Copyright = [[]],
|
||||
}
|
||||
|
||||
function dtutils_system.launch_default_app(path)
|
||||
local open_cmd = "xdg-open "
|
||||
if (dt.configuration.running_os == "windows") then
|
||||
@@ -128,5 +135,4 @@ function dtutils_system.launch_default_app(path)
|
||||
return dtutils_system.external_command(open_cmd .. path)
|
||||
end
|
||||
|
||||
|
||||
return dtutils_system
|
||||
|
||||
@@ -14,7 +14,7 @@ msgstr ""
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"Language: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=CHARSET\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: Poedit 1.5.4\n"
|
||||
"Language: de_DE\n"
|
||||
|
||||
12
locale/de_DE/LC_MESSAGES/select_non_existing.po
Normal file
12
locale/de_DE/LC_MESSAGES/select_non_existing.po
Normal file
@@ -0,0 +1,12 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
|
||||
msgid "select non existing images"
|
||||
msgstr "nicht vorhandene Bilder auswählen"
|
||||
|
||||
msgid "select non existing"
|
||||
msgstr "nicht vorhandene auswählen"
|
||||
|
||||
msgid "select all non-existing images in the current images"
|
||||
msgstr "alle nicht vorhandenen Bilder in den aktuellen Bildern auswählen"
|
||||
494
official/apply_camera_style.lua
Normal file
494
official/apply_camera_style.lua
Normal file
@@ -0,0 +1,494 @@
|
||||
--[[
|
||||
|
||||
apply_camera_style.lua - apply camera style to matching images
|
||||
|
||||
Copyright (C) 2024 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/>.
|
||||
]]
|
||||
--[[
|
||||
apply_camera_style - apply darktable camera style to matching images
|
||||
|
||||
apply a camera style corresponding to the camera used to
|
||||
take the image to provide a starting point for editing that
|
||||
is similar to the SOOC jpeg.
|
||||
|
||||
ADDITIONAL SOFTWARE NEEDED FOR THIS SCRIPT
|
||||
none
|
||||
|
||||
USAGE
|
||||
start the script from script_manager
|
||||
|
||||
BUGS, COMMENTS, SUGGESTIONS
|
||||
Bill Ferguson <wpferguson@gmail.com>
|
||||
|
||||
CHANGES
|
||||
]]
|
||||
|
||||
local dt = require "darktable"
|
||||
local du = require "lib/dtutils"
|
||||
-- local df = require "lib/dtutils.file"
|
||||
-- local ds = require "lib/dtutils.string"
|
||||
-- local dtsys = require "lib/dtutils.system"
|
||||
local log = require "lib/dtutils.log"
|
||||
-- local debug = require "darktable.debug"
|
||||
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- C O N S T A N T S
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
local MODULE <const> = "apply_camera_style"
|
||||
local DEFAULT_LOG_LEVEL <const> = log.info
|
||||
local TMP_DIR <const> = dt.configuration.tmp_dir
|
||||
local STYLE_PREFIX <const> = "_l10n_darktable camera styles|"
|
||||
|
||||
-- path separator
|
||||
local PS <const> = dt.configuration.running_os == "windows" and "\\" or "/"
|
||||
|
||||
-- command separator
|
||||
local CS <const> = dt.configuration.running_os == "windows" and "&" or ";"
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- A P I C H E C K
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
du.check_min_api_version("9.4.0", MODULE) -- camera styles added to darktable 5.0
|
||||
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- I 1 8 N
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
local function _(msgid)
|
||||
return gettext(msgid)
|
||||
end
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- S C R I P T M A N A G E R I N T E G R A T I O N
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
local script_data = {}
|
||||
|
||||
script_data.destroy = nil -- function to destory the script
|
||||
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet
|
||||
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
|
||||
script_data.show = nil -- only required for libs since the destroy_method only hides them
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("apply camera style"), -- name of script
|
||||
purpose = _("apply darktable camera style to matching images"), -- purpose of script
|
||||
author = "Bill Ferguson <wpferguson@gmail.com>", -- your name and optionally e-mail address
|
||||
help = "https://docs.darktable.org/lua/development/lua.scripts.manual/scripts/official/apply_camera_style/" -- URL to help/documentation
|
||||
}
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- L O G L E V E L
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
log.log_level(DEFAULT_LOG_LEVEL)
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- N A M E S P A C E
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
local apply_camera_style = {}
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- G L O B A L V A R I A B L E S
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
apply_camera_style.imported_images = {}
|
||||
apply_camera_style.styles = {}
|
||||
apply_camera_style.log_level = DEFAULT_LOG_LEVEL
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- P R E F E R E N C E S
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- A L I A S E S
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
local namespace = apply_camera_style
|
||||
local acs = apply_camera_style
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- F U N C T I O N S
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
-------------------
|
||||
-- helper functions
|
||||
-------------------
|
||||
|
||||
local function set_log_level(level)
|
||||
local old_log_level = log.log_level()
|
||||
log.log_level(level)
|
||||
return old_log_level
|
||||
end
|
||||
|
||||
local function restore_log_level(level)
|
||||
log.log_level(level)
|
||||
end
|
||||
|
||||
-------------------
|
||||
-- script functions
|
||||
-------------------
|
||||
|
||||
local function process_pattern(pattern)
|
||||
|
||||
local log_level = set_log_level(acs.log_level)
|
||||
|
||||
pattern = string.lower(pattern)
|
||||
-- strip off series
|
||||
pattern = string.gsub(pattern, " series$", "?")
|
||||
-- match a character
|
||||
if string.match(pattern, "?$") then
|
||||
-- handle EOS R case
|
||||
pattern = string.gsub(pattern, "?", ".?")
|
||||
else
|
||||
pattern = string.gsub(pattern, "?", ".")
|
||||
end
|
||||
pattern = string.gsub(pattern, " ", " ?")
|
||||
-- escape dashes
|
||||
pattern = string.gsub(pattern, "%-", "%%-")
|
||||
-- until we end up with a set, I'll defer set processing, i.e. [...]
|
||||
-- anchor the pattern to ensure we don't short match
|
||||
pattern = "^" .. pattern .. "$"
|
||||
|
||||
restore_log_level(log_level)
|
||||
|
||||
return pattern
|
||||
end
|
||||
|
||||
local function process_set(pattern_set)
|
||||
|
||||
local log_level = set_log_level(acs.log_level)
|
||||
|
||||
local to_process = {}
|
||||
local processed = {}
|
||||
|
||||
local base, set, tail
|
||||
|
||||
if string.match(pattern_set, "]$") then
|
||||
base, set = string.match(pattern_set, "(.+)%[(.+)%]")
|
||||
else
|
||||
base, set, tail = string.match(pattern_set, "(.+)%[(.+)%](.+)")
|
||||
end
|
||||
|
||||
log.msg(log.debug, "base is " .. base .. " and set is " .. set)
|
||||
|
||||
to_process = du.split(set, ",")
|
||||
|
||||
for _, item in ipairs(to_process) do
|
||||
local pat = base .. item
|
||||
if tail then
|
||||
pat = pat .. tail
|
||||
end
|
||||
table.insert(processed, process_pattern(pat))
|
||||
end
|
||||
|
||||
restore_log_level(log_level)
|
||||
|
||||
return processed
|
||||
end
|
||||
|
||||
local function get_camera_styles()
|
||||
|
||||
local log_level = set_log_level(acs.log_level)
|
||||
|
||||
-- separate the styles into
|
||||
--
|
||||
-- acs.styles -
|
||||
-- maker -
|
||||
-- styles {}
|
||||
-- patterns {}
|
||||
|
||||
for _, style in ipairs(dt.styles) do
|
||||
|
||||
if string.match(style.name, STYLE_PREFIX) then
|
||||
log.msg(log.debug, "got " .. style.name)
|
||||
|
||||
local parts = du.split(style.name, "|")
|
||||
parts[2] = string.lower(parts[2])
|
||||
log.msg(log.debug, "maker is " .. parts[2])
|
||||
|
||||
if not acs.styles[parts[2]] then
|
||||
acs.styles[parts[2]] = {}
|
||||
acs.styles[parts[2]]["styles"] = {}
|
||||
acs.styles[parts[2]]["patterns"] = {}
|
||||
end
|
||||
if parts[3] then
|
||||
if not string.match(parts[3], "]") then
|
||||
table.insert(acs.styles[parts[2]].styles, style)
|
||||
local processed_pattern = process_pattern(parts[#parts])
|
||||
table.insert(acs.styles[parts[2]].patterns, processed_pattern)
|
||||
log.msg(log.debug, "pattern for " .. style.name .. " is " .. processed_pattern)
|
||||
else
|
||||
local processed_patterns = process_set(parts[3])
|
||||
for _, pat in ipairs(processed_patterns) do
|
||||
table.insert(acs.styles[parts[2]].styles, style)
|
||||
table.insert(acs.styles[parts[2]].patterns, pat)
|
||||
log.msg(log.debug, "pattern for " .. style.name .. " is " .. pat)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
restore_log_level(log_level)
|
||||
|
||||
end
|
||||
|
||||
local function normalize_model(maker, model)
|
||||
|
||||
local log_level = set_log_level(acs.log_level)
|
||||
|
||||
model = string.lower(model)
|
||||
|
||||
-- strip off the maker name
|
||||
if maker == "canon" then
|
||||
model = string.gsub(model, "canon ", "")
|
||||
elseif maker == "hasselblad" then
|
||||
model = string.gsub(model, "hasselblad ", "")
|
||||
elseif maker == "leica" then
|
||||
model = string.gsub(model, "leica ", "")
|
||||
elseif maker == "lg" then
|
||||
model = string.gsub(model, "lg ", "")
|
||||
elseif maker == "nikon" then
|
||||
model = string.gsub(model, "nikon ", "")
|
||||
elseif maker == "nokia" then
|
||||
model = string.gsub(model, "nokia ", "")
|
||||
elseif maker == "oneplus" then
|
||||
model = string.gsub(model, "oneplus ", "")
|
||||
elseif maker == "pentax" then
|
||||
model = string.gsub(model, "pentax ", "")
|
||||
model = string.gsub(model, "ricoh ", "")
|
||||
end
|
||||
|
||||
restore_log_level(log_level)
|
||||
|
||||
return model
|
||||
end
|
||||
|
||||
local function normalize_maker(maker)
|
||||
|
||||
local log_level = set_log_level(acs.log_level)
|
||||
|
||||
maker = string.lower(maker)
|
||||
|
||||
if string.match(maker, "^fujifilm") then
|
||||
maker = "fujifilm"
|
||||
elseif string.match(maker, "^hmd ") then
|
||||
maker = "nokia"
|
||||
elseif string.match(maker, "^leica") then
|
||||
maker = "leica"
|
||||
elseif string.match(maker, "^minolta") then
|
||||
maker = "minolta"
|
||||
elseif string.match(maker, "^nikon") then
|
||||
maker = "nikon"
|
||||
elseif string.match(maker, "^om ") then
|
||||
maker = "om system"
|
||||
elseif string.match(maker, "^olympus") then
|
||||
maker = "olympus"
|
||||
elseif string.match(maker, "^pentax") or string.match(maker, "^ricoh") then
|
||||
maker = "pentax"
|
||||
end
|
||||
|
||||
restore_log_level(log_level)
|
||||
|
||||
return maker
|
||||
end
|
||||
|
||||
local function has_style_tag(image, tag_name)
|
||||
|
||||
local log_level = set_log_level(acs.log_level)
|
||||
|
||||
local result = false
|
||||
|
||||
log.msg(log.debug, "looking for tag " .. tag_name)
|
||||
|
||||
for _, tag in ipairs(image:get_tags()) do
|
||||
log.msg(log.debug, "checking against " .. tag.name)
|
||||
if tag.name == tag_name then
|
||||
log.msg(log.debug, "matched tag " .. tag_name)
|
||||
result = true
|
||||
end
|
||||
end
|
||||
|
||||
restore_log_level(log_level)
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
local function mangle_model(model)
|
||||
|
||||
local log_level = set_log_level(acs.log_level)
|
||||
|
||||
if string.match(model, "eos") then
|
||||
log.msg(log.debug, "mangle model got " .. model)
|
||||
model = string.gsub(model, "r6m2", "r6 mark ii")
|
||||
model = string.gsub(model, "eos 350d digital", "eos kiss digital n")
|
||||
model = string.gsub(model, "eos 500d", "eos rebel t1")
|
||||
model = string.gsub(model, "eos 550d", "eos rebel t2")
|
||||
model = string.gsub(model, "eos 600d", "eos rebel t3i")
|
||||
model = string.gsub(model, "eos 650d", "eos rebel t4i")
|
||||
model = string.gsub(model, "eos 700d", "eos rebel t5")
|
||||
model = string.gsub(model, "eos 750d", "eos rebel t6i")
|
||||
model = string.gsub(model, "eos 760d", "eos rebel t6s")
|
||||
model = string.gsub(model, "eos 100d", "eos rebel t6")
|
||||
model = string.gsub(model, "eos 1100d", "eos rebel t3")
|
||||
model = string.gsub(model, "eos 1200d", "eos rebel t5")
|
||||
model = string.gsub(model, "eos 1300d", "eos rebel t6")
|
||||
model = string.gsub(model, "eos 2000d", "eos rebel t7")
|
||||
log.msg(log.debug, "mandle model returning " .. model)
|
||||
end
|
||||
|
||||
restore_log_level(log_level)
|
||||
|
||||
return model
|
||||
end
|
||||
|
||||
local function stop_job()
|
||||
if acs.job then
|
||||
if acs.job.valid then
|
||||
acs.job.valid = false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function apply_style_to_images(images)
|
||||
|
||||
local log_level = set_log_level(acs.log_level)
|
||||
|
||||
acs.job = dt.gui.create_job(_("applying camera styles to images"), true, stop_job)
|
||||
|
||||
for count, image in ipairs(images) do
|
||||
local maker = normalize_maker(image.exif_maker)
|
||||
local model = normalize_model(maker, image.exif_model)
|
||||
model = mangle_model(model)
|
||||
log.msg(log.debug, "got maker " .. maker .. " and model " .. model .. " from image " .. image.filename)
|
||||
|
||||
if acs.styles[maker] then
|
||||
local no_match = true
|
||||
for i, pattern in ipairs(acs.styles[maker].patterns) do
|
||||
if string.match(model, pattern) or
|
||||
(i == #acs.styles[maker].patterns and string.match(pattern, "generic")) then
|
||||
local tag_name = "darktable|style|" .. acs.styles[maker].styles[i].name
|
||||
if not has_style_tag(image, tag_name) then
|
||||
image:apply_style(acs.styles[maker].styles[i])
|
||||
no_match = false
|
||||
log.msg(log.info, "applied style " .. acs.styles[maker].styles[i].name .. " to " .. image.filename)
|
||||
end
|
||||
log.log_level(loglevel)
|
||||
break
|
||||
end
|
||||
end
|
||||
if no_match then
|
||||
log.msg(log.info, "no style found for " .. maker .. " " .. model)
|
||||
end
|
||||
else
|
||||
log.msg(log.info, "no maker found for " .. image.filename)
|
||||
end
|
||||
if count % 10 == 0 then
|
||||
acs.job.percent = count / #images
|
||||
end
|
||||
if dt.control.ending then
|
||||
stop_job()
|
||||
end
|
||||
end
|
||||
|
||||
stop_job()
|
||||
|
||||
restore_log_level(log_level)
|
||||
|
||||
end
|
||||
|
||||
local function apply_camera_style(collection)
|
||||
|
||||
local log_level = set_log_level(acs.log_level)
|
||||
|
||||
local images = nil
|
||||
|
||||
if collection == true then
|
||||
images = dt.collection
|
||||
log.msg(log.info, "applying camera styles to collection")
|
||||
elseif collection == false then
|
||||
images = dt.gui.selection()
|
||||
if #images == 0 then
|
||||
images = dt.gui.action_images
|
||||
end
|
||||
log.msg(log.info, "applying camera styles to selection")
|
||||
end
|
||||
apply_style_to_images(images)
|
||||
|
||||
restore_log_level(log_level)
|
||||
|
||||
end
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- M A I N P R O G R A M
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
get_camera_styles()
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- U S E R I N T E R F A C E
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- D A R K T A B L E I N T E G R A T I O N
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
local function destroy()
|
||||
dt.destroy_event(MODULE, "post-import-image")
|
||||
dt.destroy_event(MODULE, "post-import-film")
|
||||
end
|
||||
|
||||
script_data.destroy = destroy
|
||||
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
-- E V E N T S
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
dt.register_event(MODULE, "shortcut",
|
||||
function(event, shortcut)
|
||||
apply_camera_style(true)
|
||||
end, _("apply darktable camera styles to collection")
|
||||
)
|
||||
|
||||
dt.register_event(MODULE, "shortcut",
|
||||
function(event, shortcut)
|
||||
apply_camera_style(false)
|
||||
end, _("apply darktable camera styles to selection")
|
||||
)
|
||||
|
||||
dt.register_event(MODULE, "post-import-image",
|
||||
function(event, image)
|
||||
if image.is_raw then
|
||||
table.insert(acs.imported_images, image)
|
||||
end
|
||||
end
|
||||
)
|
||||
|
||||
dt.register_event(MODULE, "post-import-film",
|
||||
function(event, film)
|
||||
apply_style_to_images(acs.imported_images)
|
||||
acs.imported_images = {}
|
||||
end
|
||||
)
|
||||
|
||||
return script_data
|
||||
@@ -21,7 +21,7 @@ a simple script that will automatically look for newer releases on github and in
|
||||
when there is something. it will only check on startup and only once a week.
|
||||
|
||||
USAGE
|
||||
* install luasec and cjson for Lua 5.2 on your system
|
||||
* install luasec and cjson for Lua 5.4 on your system
|
||||
* require this script from your main lua file
|
||||
* restart darktable
|
||||
|
||||
@@ -34,13 +34,27 @@ local cjson = require "cjson"
|
||||
|
||||
du.check_min_api_version("2.0.0", "check_for_updates")
|
||||
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
local function _(msg)
|
||||
return gettext(msg)
|
||||
end
|
||||
|
||||
-- return data structure for script_manager
|
||||
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("check for updates"),
|
||||
purpose = _("check for newer darktable releases"),
|
||||
author = "Tobias Ellinghaus",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/official/check_for_updates"
|
||||
}
|
||||
|
||||
script_data.destroy = nil -- function to destory the script
|
||||
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet
|
||||
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
|
||||
script_data.show = nil -- only required for libs since the destroy_method only hides them
|
||||
|
||||
-- compare two version strings of the form "major.minor.patch"
|
||||
-- returns -1, 0, 1 if the first version is smaller, equal, greater than the second version,
|
||||
|
||||
@@ -27,17 +27,29 @@ USAGE
|
||||
|
||||
local dt = require "darktable"
|
||||
local du = require "lib/dtutils"
|
||||
local gettext = dt.gettext
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
du.check_min_api_version("7.0.0", "copy_paste_metadata")
|
||||
|
||||
local function _(msgid)
|
||||
return gettext(msgid)
|
||||
end
|
||||
|
||||
-- return data structure for script_manager
|
||||
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("copy paste metadata"),
|
||||
purpose = _("adds keyboard shortcuts and buttons to copy/paste metadata between images"),
|
||||
author = "Tobias Ellinghaus",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/official/copy_paste_metadata"
|
||||
}
|
||||
|
||||
script_data.destroy = nil -- function to destory the script
|
||||
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet
|
||||
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
|
||||
script_data.show = nil -- only required for libs since the destroy_method only hides them
|
||||
|
||||
-- set this to "false" if you don't want to overwrite metadata fields
|
||||
-- (title, description, creator, publisher and rights) that are already set
|
||||
@@ -57,13 +69,6 @@ local publisher = ""
|
||||
local rights = ""
|
||||
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)
|
||||
if not image then
|
||||
have_data = false
|
||||
@@ -146,13 +151,13 @@ dt.gui.libs.image.register_action(
|
||||
dt.register_event(
|
||||
"capmd1", "shortcut",
|
||||
function(event, shortcut) copy(dt.gui.action_images[1]) end,
|
||||
"copy metadata"
|
||||
_("copy metadata")
|
||||
)
|
||||
|
||||
dt.register_event(
|
||||
"capmd2", "shortcut",
|
||||
function(event, shortcut) paste(dt.gui.action_images) end,
|
||||
"paste metadata"
|
||||
_("paste metadata")
|
||||
)
|
||||
|
||||
script_data.destroy = destroy
|
||||
|
||||
@@ -33,13 +33,27 @@ local du = require "lib/dtutils"
|
||||
|
||||
du.check_min_api_version("2.0.0", "delete_long_tags")
|
||||
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
local function _(msgid)
|
||||
return gettext(msgid)
|
||||
end
|
||||
|
||||
-- return data structure for script_manager
|
||||
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("delete long tags"),
|
||||
purpose = _("delete all tags longer than a set length"),
|
||||
author = "Tobias Ellinghaus",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/official/delete_long_tags"
|
||||
}
|
||||
|
||||
script_data.destroy = nil -- function to destory the script
|
||||
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet
|
||||
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
|
||||
script_data.show = nil -- only required for libs since the destroy_method only hides them
|
||||
|
||||
dt.preferences.register("delete_long_tags", "length", "integer",
|
||||
"maximum length of tags to keep",
|
||||
@@ -58,7 +72,7 @@ local long_tags = {}
|
||||
for _,t in ipairs(dt.tags) do
|
||||
local len = #t.name
|
||||
if len > max_length then
|
||||
print("deleting tag `"..t.name.."' (length: "..len..")")
|
||||
dt.print_log("deleting tag `"..t.name.."' (length: "..len..")")
|
||||
table.insert(long_tags, t.name)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -37,13 +37,27 @@ local function destroy()
|
||||
-- noting to destroy
|
||||
end
|
||||
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
local function _(msgid)
|
||||
return gettext(msgid)
|
||||
end
|
||||
|
||||
-- return data structure for script_manager
|
||||
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("delete unused tags"),
|
||||
purpose = _("delete unused tags"),
|
||||
author = "Tobias Ellinghaus",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/official/delete_unused_tags"
|
||||
}
|
||||
|
||||
script_data.destroy = nil -- function to destory the script
|
||||
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet
|
||||
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
|
||||
script_data.show = nil -- only required for libs since the destroy_method only hides them
|
||||
|
||||
-- deleting while iterating the tags list seems to break the iterator!
|
||||
local unused_tags = {}
|
||||
@@ -55,7 +69,7 @@ for _, t in ipairs(dt.tags) do
|
||||
end
|
||||
|
||||
for _,name in pairs(unused_tags) do
|
||||
print("deleting tag `" .. name .. "'")
|
||||
dt.print_log("deleting tag `" .. name .. "'")
|
||||
tag = dt.tags.find(name)
|
||||
tag:delete()
|
||||
end
|
||||
|
||||
@@ -39,35 +39,40 @@ local dtsys = require "lib/dtutils.system"
|
||||
|
||||
local PS = dt.configuration.running_os == "windows" and "\\" or "/"
|
||||
|
||||
local gettext = dt.gettext
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
du.check_min_api_version("7.0.0", "enfuse")
|
||||
|
||||
local function _(msgid)
|
||||
return gettext(msgid)
|
||||
end
|
||||
|
||||
-- return data structure for script_manager
|
||||
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("enfuse"),
|
||||
purpose = _("exposure blend images"),
|
||||
author = "Tobias Ellinghaus",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/official/enfuse"
|
||||
}
|
||||
|
||||
script_data.destroy = nil -- function to destory the script
|
||||
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet
|
||||
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
|
||||
|
||||
-- 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)
|
||||
script_data.show = nil -- only required for libs since the destroy_method only hides them
|
||||
|
||||
local enf = {}
|
||||
enf.event_registered = false
|
||||
enf.module_installed = false
|
||||
enf.lib_widgets = {}
|
||||
|
||||
local function _(msgid)
|
||||
return gettext.dgettext("enfuse", msgid)
|
||||
end
|
||||
|
||||
local function install_module()
|
||||
if not enf.module_installed then
|
||||
dt.register_lib(
|
||||
"enfuse", -- plugin name
|
||||
"enfuse", -- name
|
||||
_("enfuse"), -- name
|
||||
true, -- expandable
|
||||
false, -- resetable
|
||||
{[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, -- containers
|
||||
@@ -130,8 +135,8 @@ if enfuse_installed then
|
||||
if version < "4.2" then
|
||||
exposure_mu = dt.new_widget("slider")
|
||||
{
|
||||
label = "exposure mu",
|
||||
tooltip = "center also known as MEAN of Gaussian weighting function (0 <= MEAN <= 1); default: 0.5",
|
||||
label = _("exposure mu"),
|
||||
tooltip = _("center also known as mean of gaussian weighting function (0 <= mean <= 1); default: 0.5"),
|
||||
hard_min = 0,
|
||||
hard_max = 1,
|
||||
value = dt.preferences.read("enfuse", "exposure_mu", "float")
|
||||
@@ -139,8 +144,8 @@ if enfuse_installed then
|
||||
else
|
||||
exposure_mu = dt.new_widget("slider")
|
||||
{
|
||||
label = "exposure optimum",
|
||||
tooltip = "optimum exposure value, usually the maximum of the weighting function (0 <= OPTIMUM <=1); default 0.5",
|
||||
label = _("exposure optimum"),
|
||||
tooltip = _("optimum exposure value, usually the maximum of the weighting function (0 <= optimum <=1); default 0.5"),
|
||||
hard_min = 0,
|
||||
hard_max = 1,
|
||||
value = dt.preferences.read("enfuse", "exposure_optimum", "float")
|
||||
@@ -149,8 +154,8 @@ if enfuse_installed then
|
||||
|
||||
local depth = dt.new_widget("combobox")
|
||||
{
|
||||
label = "depth",
|
||||
tooltip = "the number of bits per channel of the output image",
|
||||
label = _("depth"),
|
||||
tooltip = _("the number of bits per channel of the output image"),
|
||||
value = dt.preferences.read("enfuse", "depth", "integer"),
|
||||
changed_callback = function(w) dt.preferences.write("enfuse", "depth", "integer", w.selected) end,
|
||||
"8", "16", "32"
|
||||
@@ -158,15 +163,15 @@ if enfuse_installed then
|
||||
|
||||
local blend_colorspace = dt.new_widget("combobox")
|
||||
{
|
||||
label = "blend colorspace",
|
||||
tooltip = "Force blending in selected colorspace",
|
||||
label = _("blend colorspace"),
|
||||
tooltip = _("force blending in selected colorspace"),
|
||||
changed_callback = function(w) dt.preferences.write("enfuse", "blend_colorspace", "string", w.selected) end,
|
||||
"", "identity", "ciecam"
|
||||
}
|
||||
|
||||
local enfuse_button = dt.new_widget("button")
|
||||
{
|
||||
label = enfuse_installed and "run enfuse" or "enfuse not installed",
|
||||
label = enfuse_installed and _("run enfuse") or _("enfuse not installed"),
|
||||
clicked_callback = function ()
|
||||
-- remember exposure_mu
|
||||
-- TODO: find a way to save it whenever the value changes
|
||||
@@ -184,7 +189,7 @@ if enfuse_installed then
|
||||
end
|
||||
local f = io.open(response_file, "w")
|
||||
if not f then
|
||||
dt.print(string.format(_("Error writing to `%s`"), response_file))
|
||||
dt.print(string.format(_("error writing to '%s'"), response_file))
|
||||
os.remove(response_file)
|
||||
return
|
||||
end
|
||||
@@ -207,9 +212,9 @@ if enfuse_installed then
|
||||
if dt.configuration.running_os == "windows" then
|
||||
tmp_exported = dt.configuration.tmp_dir .. tmp_exported -- windows os.tmpname() defaults to root directory
|
||||
end
|
||||
dt.print(string.format(_("Converting raw file '%s' to tiff..."), i.filename))
|
||||
dt.print(string.format(_("converting raw file '%s' to tiff..."), i.filename))
|
||||
tiff_exporter:write_image(i, tmp_exported, false)
|
||||
dt.print_log(string.format("Raw file '%s' converted to '%s'", i.filename, tmp_exported))
|
||||
dt.print_log(string.format("raw file '%s' converted to '%s'", i.filename, tmp_exported))
|
||||
|
||||
cnt = cnt + 1
|
||||
f:write(tmp_exported.."\n")
|
||||
@@ -217,14 +222,14 @@ if enfuse_installed then
|
||||
|
||||
-- other images will be skipped
|
||||
else
|
||||
dt.print(string.format(_("Skipping %s..."), i.filename))
|
||||
dt.print(string.format(_("skipping %s..."), i.filename))
|
||||
n_skipped = n_skipped + 1
|
||||
end
|
||||
end
|
||||
f:close()
|
||||
-- bail out if there is nothing to do
|
||||
if cnt == 0 then
|
||||
dt.print(_("No suitable images selected, nothing to do for enfuse"))
|
||||
dt.print(_("no suitable images selected, nothing to do for enfuse"))
|
||||
os.remove(response_file)
|
||||
return
|
||||
end
|
||||
@@ -250,7 +255,7 @@ if enfuse_installed then
|
||||
..blend_colorspace_option
|
||||
.." -o \""..output_image.."\" \"@"..response_file.."\""
|
||||
if dtsys.external_command( command) > 0 then
|
||||
dt.print(_("Enfuse failed, see terminal output for details"))
|
||||
dt.print(_("enfuse failed, see terminal output for details"))
|
||||
os.remove(response_file)
|
||||
return
|
||||
end
|
||||
@@ -298,7 +303,7 @@ if enfuse_installed then
|
||||
else
|
||||
dt.print_error("enfuse executable not found")
|
||||
error("enfuse executable not found")
|
||||
dt.print(_("Could not find enfuse executable. Not loading enfuse exporter..."))
|
||||
dt.print(_("could not find enfuse executable, not loading enfuse exporter..."))
|
||||
end
|
||||
|
||||
script_data.destroy = destroy
|
||||
|
||||
@@ -38,34 +38,48 @@ local dt = require "darktable"
|
||||
local du = require "lib/dtutils"
|
||||
require "darktable.debug"
|
||||
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
local function _(msg)
|
||||
return gettext(msg)
|
||||
end
|
||||
|
||||
du.check_min_api_version("7.0.0", "generate_image_txt")
|
||||
|
||||
-- return data structure for script_manager
|
||||
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("generate image text"),
|
||||
purpose = _("overlay metadata on the selected image(s)"),
|
||||
author = "Tobias Ellinghaus",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/official/generate_image_txt"
|
||||
}
|
||||
|
||||
script_data.destroy = nil -- function to destory the script
|
||||
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet
|
||||
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
|
||||
script_data.show = nil -- only required for libs since the destroy_method only hides them
|
||||
|
||||
dt.preferences.register("generate_image_txt",
|
||||
"enabled",
|
||||
"bool",
|
||||
"create txt sidecars to display with images",
|
||||
"the txt files created get shown when the lighttable is zoomed in to one image. also enable the txt overlay setting in the gui tab",
|
||||
_("create txt sidecars to display with images"),
|
||||
_("the txt files created get shown when the lighttable is zoomed in to one image. also enable the txt overlay setting in the gui tab"),
|
||||
false)
|
||||
|
||||
dt.preferences.register("generate_image_txt",
|
||||
"command",
|
||||
"string",
|
||||
"command to generate the txt sidecar",
|
||||
"the output of this command gets written to the txt file. use $(FILE_NAME) for the image file",
|
||||
_("command to generate the txt sidecar"),
|
||||
_("the output of this command gets written to the txt file. use $(FILE_NAME) for the image file"),
|
||||
"exiv2 $(FILE_NAME)")
|
||||
|
||||
|
||||
local check_command = function(command)
|
||||
if not command:find("$(FILE_NAME)", 1, true) then
|
||||
dt.print("the command for txt sidecars looks bad. better check the preferences")
|
||||
dt.print(_("the command for txt sidecars looks bad. better check the preferences"))
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -33,13 +33,27 @@ local du = require "lib/dtutils"
|
||||
|
||||
du.check_min_api_version("7.0.0", "image_path_in_ui")
|
||||
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
local function _(msgid)
|
||||
return gettext(msgid)
|
||||
end
|
||||
|
||||
-- return data structure for script_manager
|
||||
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("image path in UI"),
|
||||
purpose = _("print the image path in the UI"),
|
||||
author = "Jérémy Rosen",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/official/image_path_in_ui"
|
||||
}
|
||||
|
||||
script_data.destroy = nil -- function to destory the script
|
||||
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet
|
||||
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
|
||||
script_data.show = nil -- only required for libs since the destroy_method only hides them
|
||||
|
||||
local ipiu = {}
|
||||
ipiu.module_installed = false
|
||||
@@ -49,7 +63,7 @@ local main_label = dt.new_widget("label"){selectable = true, ellipsize = "middle
|
||||
|
||||
local function install_module()
|
||||
if not ipiu.module_installed then
|
||||
dt.register_lib("image_path_no_ui","selected images path",true,false,{
|
||||
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
|
||||
)
|
||||
|
||||
@@ -32,19 +32,40 @@ USAGE
|
||||
|
||||
local dt = require "darktable"
|
||||
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
local function _(msg)
|
||||
return gettext(msg)
|
||||
end
|
||||
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("import filter manager"),
|
||||
purpose = _("manage import filters"),
|
||||
author = "Tobias Ellinghaus",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/official/import_filter_manager"
|
||||
}
|
||||
|
||||
script_data.destroy = nil -- function to destory the script
|
||||
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet
|
||||
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
|
||||
script_data.show = nil -- only required for libs since the destroy_method only hides them
|
||||
|
||||
local import_filter_list = {}
|
||||
local n_import_filters = 1
|
||||
|
||||
-- allow changing the filter from the preferences
|
||||
dt.preferences.register("import_filter_manager", "active_filter", "string",
|
||||
"import filter", "the name of the filter used for importing images", "")
|
||||
_("import filter"), _("the name of the filter used for importing images"), "")
|
||||
|
||||
|
||||
-- the dropdown to select the active filter from the import dialog
|
||||
local filter_dropdown = dt.new_widget("combobox")
|
||||
{
|
||||
label = "import filter",
|
||||
label = _("import filter"),
|
||||
editable = false,
|
||||
tooltip = _("import filters are applied after completion of the import dialog"),
|
||||
|
||||
changed_callback = function(widget)
|
||||
dt.preferences.write("import_filter_manager", "active_filter", "string", widget.value)
|
||||
@@ -74,6 +95,12 @@ dt.register_import_filter = function(name, callback)
|
||||
if name == active_filter then filter_dropdown.value = n_import_filters end
|
||||
end
|
||||
|
||||
local function destroy()
|
||||
--noting to destroy
|
||||
end
|
||||
|
||||
script_data.destroy = destroy
|
||||
|
||||
return script_data
|
||||
-- vim: shiftwidth=2 expandtab tabstop=2 cindent
|
||||
-- kate: tab-indents: off; indent-width 2; replace-tabs on; remove-trailing-space on;
|
||||
|
||||
@@ -30,11 +30,31 @@ USAGE
|
||||
|
||||
local dt = require "darktable"
|
||||
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
local function _(msg)
|
||||
return gettext(msg)
|
||||
end
|
||||
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("import filters"),
|
||||
purpose = _("import filtering"),
|
||||
author = "Tobias Ellinghaus & Christian Mandel",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/official/import_filters"
|
||||
}
|
||||
|
||||
script_data.destroy = nil -- function to destory the script
|
||||
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet
|
||||
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
|
||||
script_data.show = nil -- only required for libs since the destroy_method only hides them
|
||||
|
||||
-- we get fed a sorted list of filenames. just setting images to ignore to nil is enough
|
||||
|
||||
-- ignore jpeg
|
||||
dt.register_import_filter("ignore jpegs", function(event, images)
|
||||
dt.print_error("ignoring all jpegs")
|
||||
dt.print_log("ignoring all jpegs")
|
||||
for i, img in ipairs(images) do
|
||||
local extension = img:match("[^.]*$"):upper()
|
||||
if (extension == "JPG") or (extension == "JPEG") then
|
||||
@@ -88,5 +108,13 @@ dt.register_import_filter("prefer raw over jpeg", function(event, images)
|
||||
|
||||
end)
|
||||
|
||||
local function destroy()
|
||||
-- nothing to destroy
|
||||
end
|
||||
|
||||
script_data.destroy = destroy
|
||||
|
||||
return script_data
|
||||
|
||||
-- vim: shiftwidth=2 expandtab tabstop=2 cindent
|
||||
-- kate: tab-indents: off; indent-width 2; replace-tabs on; remove-trailing-space on;
|
||||
|
||||
@@ -38,13 +38,27 @@ local du = require "lib/dtutils"
|
||||
|
||||
du.check_min_api_version("7.0.0", "save_selection")
|
||||
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
local function _(msg)
|
||||
return gettext(msg)
|
||||
end
|
||||
|
||||
-- return data structure for script_manager
|
||||
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("save selection"),
|
||||
purpose = _("shortcuts providing multiple selection buffers"),
|
||||
author = "Jérémy Rosen",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/official/save_selection"
|
||||
}
|
||||
|
||||
script_data.destroy = nil -- function to destory the script
|
||||
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet
|
||||
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
|
||||
script_data.show = nil -- only required for libs since the destroy_method only hides them
|
||||
|
||||
local buffer_count = 5
|
||||
|
||||
@@ -60,16 +74,16 @@ for i = 1, buffer_count do
|
||||
local saved_selection
|
||||
dt.register_event("save_selection save " .. i, "shortcut", function()
|
||||
saved_selection = dt.gui.selection()
|
||||
end, "save to buffer " .. i)
|
||||
end, string.format(_("save to buffer %d"), i))
|
||||
dt.register_event("save_selection restore " .. i, "shortcut", function()
|
||||
dt.gui.selection(saved_selection)
|
||||
end, "restore from buffer " .. i)
|
||||
end, string.format(_("restore from buffer %d"), i))
|
||||
end
|
||||
|
||||
local bounce_buffer = {}
|
||||
dt.register_event("save_selection switch", "shortcut", function()
|
||||
bounce_buffer = dt.gui.selection(bounce_buffer)
|
||||
end, "switch selection with temporary buffer")
|
||||
end, _("switch selection with temporary buffer"))
|
||||
|
||||
script_data.destroy = destroy
|
||||
|
||||
|
||||
@@ -38,26 +38,40 @@ local du = require "lib/dtutils"
|
||||
|
||||
du.check_min_api_version("7.0.0", "selection_to_pdf")
|
||||
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
local function _(msg)
|
||||
return gettext(msg)
|
||||
end
|
||||
|
||||
-- return data structure for script_manager
|
||||
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("selection to PDF"),
|
||||
purpose = _("generate a pdf file of selected images"),
|
||||
author = "Jérémy Rosen & Pascal Obry",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/official/selection_to_pdf"
|
||||
}
|
||||
|
||||
script_data.destroy = nil -- function to destory the script
|
||||
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet
|
||||
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
|
||||
script_data.show = nil -- only required for libs since the destroy_method only hides them
|
||||
|
||||
dt.preferences.register
|
||||
("selection_to_pdf","Open with","string",
|
||||
"a pdf viewer",
|
||||
"Can be an absolute pathname or the tool may be in the PATH",
|
||||
_("a pdf viewer"),
|
||||
_("can be an absolute pathname or the tool may be in the PATH"),
|
||||
"xdg-open")
|
||||
|
||||
local title_widget = dt.new_widget("entry") {
|
||||
placeholder="Title"
|
||||
placeholder = _("title")
|
||||
}
|
||||
local no_of_thumbs_widget = dt.new_widget("slider")
|
||||
{
|
||||
label = "Thumbs per Line",
|
||||
label = _("thumbs per line"),
|
||||
soft_min = 1, -- The soft minimum value for the slider, the slider can't go beyond this point
|
||||
soft_max = 10, -- The soft maximum value for the slider, the slider can't go beyond this point
|
||||
hard_min = 1, -- The hard minimum value for the slider, the user can't manually enter a value beyond this point
|
||||
@@ -65,10 +79,10 @@ local no_of_thumbs_widget = dt.new_widget("slider")
|
||||
value = 4 -- The current value of the slider
|
||||
}
|
||||
local widget = dt.new_widget("box") {
|
||||
orientation=horizontal,
|
||||
dt.new_widget("label"){label = "Title:"},
|
||||
orientation = horizontal,
|
||||
dt.new_widget("label"){label = _("title:")},
|
||||
title_widget,
|
||||
dt.new_widget("label"){label = "Thumbnails per row:"},
|
||||
dt.new_widget("label"){label = _("thumbnails per row:")},
|
||||
no_of_thumbs_widget
|
||||
}
|
||||
|
||||
@@ -115,7 +129,7 @@ local function destroy()
|
||||
dt.print_log("done destroying")
|
||||
end
|
||||
|
||||
dt.register_storage("export_pdf","Export thumbnails to pdf",
|
||||
dt.register_storage("export_pdf", _("export thumbnails to pdf"),
|
||||
nil,
|
||||
function(storage,image_table)
|
||||
local my_title = title_widget.text
|
||||
@@ -162,7 +176,7 @@ dt.register_storage("export_pdf","Export thumbnails to pdf",
|
||||
local command = "pdflatex -halt-on-error -output-directory "..dir.." "..locfile
|
||||
local result = dt.control.execute(command)
|
||||
if result ~= 0 then
|
||||
dt.print("Problem running pdflatex") -- this one is probably usefull to the user
|
||||
dt.print(_("problem running pdflatex")) -- this one is probably usefull to the user
|
||||
error("Problem running "..command)
|
||||
end
|
||||
|
||||
@@ -172,7 +186,7 @@ dt.register_storage("export_pdf","Export thumbnails to pdf",
|
||||
command = command.." "..pdffile
|
||||
local result = dt.control.execute(command)
|
||||
if result ~= 0 then
|
||||
dt.print("Problem running pdf viewer") -- this one is probably usefull to the user
|
||||
dt.print(_("problem running pdf viewer")) -- this one is probably usefull to the user
|
||||
error("Problem running "..command)
|
||||
end
|
||||
|
||||
|
||||
@@ -31,23 +31,34 @@
|
||||
local dt = require "darktable"
|
||||
local du = require "lib/dtutils"
|
||||
local df = require "lib/dtutils.file"
|
||||
local dtsys = require "lib/dtutils.system"
|
||||
|
||||
du.check_min_api_version("7.0.0", "executable_manager")
|
||||
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
local function _(msg)
|
||||
return gettext(msg)
|
||||
end
|
||||
|
||||
-- return data structure for script_manager
|
||||
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("executable manager"),
|
||||
purpose = _("manage the list of external executables used by the lua scripts"),
|
||||
author = "Bill Ferguson <wpferguson@gmail.com>",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/tools/executable_manager"
|
||||
}
|
||||
|
||||
script_data.destroy = nil -- function to destory the script
|
||||
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet
|
||||
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
|
||||
script_data.show = nil -- only required for libs since the destroy_method only hides them
|
||||
|
||||
local PS = dt.configuration.running_os == "windows" and "\\" or "/"
|
||||
|
||||
local gettext = dt.gettext
|
||||
|
||||
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
|
||||
@@ -56,10 +67,6 @@ exec_man.event_registered = false
|
||||
-- F U N C T I O N S
|
||||
-- - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
local function _(msg)
|
||||
return gettext.dgettext("executable_manager", msg)
|
||||
end
|
||||
|
||||
local function grep(file, pattern)
|
||||
|
||||
local result = {}
|
||||
@@ -99,13 +106,19 @@ local function update_combobox_choices(combobox, choice_table, selected)
|
||||
end
|
||||
|
||||
local function install_module()
|
||||
local panel = "DT_UI_CONTAINER_PANEL_LEFT_BOTTOM"
|
||||
local panel_pos = 600
|
||||
if dt.configuration.running_os == "windows" then
|
||||
panel = "DT_UI_CONTAINER_PANEL_LEFT_CENTER"
|
||||
panel_pos = 100
|
||||
end
|
||||
if not exec_man.module_installed then
|
||||
dt.register_lib(
|
||||
"executable_manager", -- Module name
|
||||
"executable manager", -- Visible name
|
||||
_("executables"), -- Visible name
|
||||
true, -- expandable
|
||||
false, -- resetable
|
||||
{[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_LEFT_BOTTOM", 100}}, -- containers
|
||||
{[dt.gui.views.lighttable] = {panel, panel_pos}}, -- containers
|
||||
dt.new_widget("box") -- widget
|
||||
{
|
||||
orientation = "vertical",
|
||||
@@ -141,7 +154,7 @@ local matches = grep(DARKTABLERC, "executable_paths")
|
||||
-- check if we have something to manage and exit if not
|
||||
|
||||
if #matches == 0 then
|
||||
dt.print(_("No executable paths found, exiting..."))
|
||||
dt.print(_("no executable paths found, exiting..."))
|
||||
return
|
||||
end
|
||||
|
||||
@@ -166,7 +179,7 @@ for i,exec in ipairs(exec_table) do
|
||||
editable = false
|
||||
}
|
||||
executable_path_widgets[exec] = dt.new_widget("file_chooser_button"){
|
||||
title = _("select ") .. exec .. _(" executable"),
|
||||
title = _(string.format("select %s executable", exec)),
|
||||
value = df.get_executable_path_preference(exec),
|
||||
is_directory = false,
|
||||
changed_callback = function(self)
|
||||
@@ -186,7 +199,7 @@ exec_man.stack = dt.new_widget("stack"){}
|
||||
-- create a combobox to for indexing into the stack of widgets
|
||||
|
||||
exec_man.selector = dt.new_widget("combobox"){
|
||||
label = "executable",
|
||||
label = _("executable"),
|
||||
tooltip = _("select executable to modify"),
|
||||
value = 1, "placeholder",
|
||||
changed_callback = function(self)
|
||||
@@ -209,7 +222,7 @@ for i,exec in ipairs(exec_table) do
|
||||
dt.new_widget("section_label"){label = _("reset")},
|
||||
dt.new_widget("button"){
|
||||
label = _("clear"),
|
||||
tooltip = _("Clear path for ") .. exec,
|
||||
tooltip = string.format(_("clear path for %s"), exec),
|
||||
clicked_callback = function()
|
||||
df.set_executable_path_preference(exec, "")
|
||||
executable_path_widgets[exec].value = ""
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
--[[
|
||||
gen_18n_mo.lua - generate .mo files from .po files and put them in the correct place
|
||||
|
||||
Copyright (C) 2016,2018 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/>.
|
||||
]]
|
||||
--[[
|
||||
gen_i18n_mo - generate translation files from the source and place them in the appropriate locale directory
|
||||
|
||||
gen_i18n_mo finds all the .po files scattered throughout the script tree, compiles them into
|
||||
.mo files and places them in the correct locale directory for use by the gettext tools.
|
||||
|
||||
]]
|
||||
|
||||
local dt = require "darktable"
|
||||
local du = require "lib/dtutils"
|
||||
local df = require "lib/dtutils.file"
|
||||
local log = require "lib/dtutils.log"
|
||||
local dtsys = require "lib/dtutils.system"
|
||||
|
||||
du.check_min_api_version("5.0.0", "gen_I18n_mo")
|
||||
|
||||
local function destroy()
|
||||
-- nothing to destroy
|
||||
end
|
||||
|
||||
-- figure out the path separator
|
||||
|
||||
local PS = dt.configuration.running_os == "windows" and "\\" or "/"
|
||||
|
||||
local LUA_DIR = dt.configuration.config_dir .. PS .. "lua" .. PS
|
||||
local LOCALE_DIR = dt.configuration.config_dir .. PS .. "lua" .. PS .. "locale" .. PS
|
||||
|
||||
-- check if we have msgfmt
|
||||
|
||||
local msgfmt_executable = df.check_if_bin_exists("msgfmt")
|
||||
|
||||
if msgfmt_executable then
|
||||
|
||||
-- find the .po files
|
||||
|
||||
local find_cmd = "find -L " .. LUA_DIR .. " -name \\*.po -print"
|
||||
if dt.configuration.running_os == "windows" then
|
||||
find_cmd = "dir /b/s " .. LUA_DIR .. "\\*.po"
|
||||
end
|
||||
|
||||
local output = io.popen(find_cmd)
|
||||
|
||||
-- for each .po file....
|
||||
|
||||
for line in output:lines() do
|
||||
local fname = df.get_filename(line)
|
||||
|
||||
-- get the language used... this depends on the file being named using
|
||||
-- the convention /..../lang/LC_MESSAGES/file.po where lang is de_DE, fr_FR, etc.
|
||||
|
||||
local path_parts = du.split(line, PS)
|
||||
local lang = path_parts[#path_parts - 2]
|
||||
|
||||
-- ensure there is a destination directory for them
|
||||
|
||||
local mkdir_cmd = "mkdir -p "
|
||||
if dt.configuration.running_os == "windows" then
|
||||
mkdir_cmd = "mkdir "
|
||||
end
|
||||
|
||||
if not df.check_if_file_exists(LOCALE_DIR .. lang .. PS .. "LC_MESSAGES") then
|
||||
log.msg(log.info, "Creating locale", lang)
|
||||
os.execute(mkdir_cmd .. LOCALE_DIR .. lang .. PS .. "LC_MESSAGES")
|
||||
end
|
||||
|
||||
-- generate the mo file
|
||||
|
||||
fname = string.gsub(fname, ".po$", ".mo")
|
||||
log.msg(log.info, "Compiling translation to", fname)
|
||||
local result = os.execute(msgfmt_executable .. " -o " .. LOCALE_DIR .. lang .. PS .. "LC_MESSAGES" .. PS .. fname .. " " .. line)
|
||||
end
|
||||
else
|
||||
log.msg(log.screen, "ERROR: msgfmt executable not found. Please install or specifiy location in preferences.")
|
||||
end
|
||||
dt.preferences.register("executable_paths", "msgfmt", -- name
|
||||
"file", -- type
|
||||
'gen_i18n_mo: msgfmt location', -- label
|
||||
'Install location of msgfmt. Requires restart to take effect.', -- tooltip
|
||||
"msgfmt", -- default
|
||||
dt.new_widget("file_chooser_button"){
|
||||
title = "Select msgfmt[.exe] file",
|
||||
value = "",
|
||||
is_directory = false,
|
||||
}
|
||||
)
|
||||
|
||||
local script_data = {}
|
||||
script_data.destroy = destroy
|
||||
|
||||
return script_data
|
||||
@@ -7,11 +7,18 @@
|
||||
local dt = require "darktable"
|
||||
local du = require "lib/dtutils"
|
||||
local df = require "lib/dtutils.file"
|
||||
local dtsys = require "lib/dtutils.system"
|
||||
local log = require "lib/dtutils.log"
|
||||
local libname = nil
|
||||
|
||||
du.check_min_api_version("3.0.0", "get_lib_manpages")
|
||||
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
local function _(msg)
|
||||
return gettext(msg)
|
||||
end
|
||||
|
||||
local function destroy()
|
||||
-- nothing to destroy
|
||||
end
|
||||
@@ -79,6 +86,14 @@ for line in output:lines() do
|
||||
end
|
||||
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("get library man pages"),
|
||||
purpose = _("output the internal library documentation as man pages"),
|
||||
author = "Bill Ferguson <wpferguson@gmail.com>",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/tools/get_lib_manpages"
|
||||
}
|
||||
|
||||
script_data.destroy = destroy
|
||||
|
||||
return script_data
|
||||
|
||||
@@ -6,9 +6,16 @@
|
||||
|
||||
local dt = require "darktable"
|
||||
local du = require "lib/dtutils"
|
||||
local dtsys = require "lib/dtutils.system"
|
||||
|
||||
du.check_min_api_version("3.0.0", "get_libdoc")
|
||||
|
||||
local gettext = dt.gettext.gettext
|
||||
|
||||
local function _(msg)
|
||||
return gettext(msg)
|
||||
end
|
||||
|
||||
local function destroy()
|
||||
-- nothing to destroy
|
||||
end
|
||||
@@ -53,6 +60,14 @@ for line in output:lines() do
|
||||
end
|
||||
|
||||
local script_data = {}
|
||||
|
||||
script_data.metadata = {
|
||||
name = _("get library docs"),
|
||||
purpose = _("retrieve and print the documentation to the console"),
|
||||
author = "Bill Ferguson <wpferguson@gmail.com>",
|
||||
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/tools/get_libdoc"
|
||||
}
|
||||
|
||||
script_data.destroy = destroy
|
||||
|
||||
return script_data
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user