Compare commits
362 Commits
API-8.0.0
...
17422_bund
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
77733b334e | ||
|
|
7f09e55525 | ||
|
|
f83ac1366a | ||
|
|
6cda27172e | ||
|
|
df78522a79 | ||
|
|
6e64d6db6f | ||
|
|
d75f00daa0 | ||
|
|
3e430ee2be | ||
|
|
3856ae3449 | ||
|
|
d54a9f8b7e | ||
|
|
8f6cc850fb | ||
|
|
e9f18a3d36 | ||
|
|
f3a89a89bd | ||
|
|
d075fb7128 | ||
|
|
e831f377bf | ||
|
|
d696e6e3f2 | ||
|
|
db505f1e0a | ||
|
|
57d15a3fa6 | ||
|
|
4d54b5eaba | ||
|
|
dbf0c5d853 | ||
|
|
193a615772 | ||
|
|
447980ddc4 | ||
|
|
8af5476f8d | ||
|
|
c95547caa7 | ||
|
|
b4d3b2901f | ||
|
|
cb6b3161d8 | ||
|
|
2d82eea237 | ||
|
|
3beee93af4 | ||
|
|
68291414f3 | ||
|
|
5662519314 | ||
|
|
28ab065293 | ||
|
|
aed3275943 | ||
|
|
d7aeb43340 | ||
|
|
ea79d10b11 | ||
|
|
e4001f984f | ||
|
|
453d744b69 | ||
|
|
b9cc0dccce | ||
|
|
84fea20ee5 | ||
|
|
e054bfc59d | ||
|
|
8cd10dce68 | ||
|
|
f8d49ccd01 | ||
|
|
25afb41924 | ||
|
|
3001a0dc1a | ||
|
|
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 | ||
|
|
b70fdc0ecf | ||
|
|
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
|
## 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**
|
**25 Mar 2023 - wpferguson**
|
||||||
* Added script_manager darktable shortcut integration
|
* Added script_manager darktable shortcut integration
|
||||||
* Moved filename/path/extension string functions to string library
|
* Moved filename/path/extension string functions to string library
|
||||||
|
|||||||
151
README.md
151
README.md
@@ -15,17 +15,17 @@ These scripts are written primarily by the darktable developers and maintained b
|
|||||||
|
|
||||||
Name|Standalone|OS |Purpose
|
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
|
[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://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
|
[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://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/official/delete_long_tags)|Yes|LMW|Delete all tags longer than a specified length
|
[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://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/official/delete_unused_tags)|Yes|LMW|Delete tags that have no associated images
|
[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://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/official/enfuse)|No|L|Exposure blend several images (HDR)
|
[enfuse](https://docs.darktable.org/lua/stable/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
|
[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://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/official/image_path_in_ui)|Yes|LMW|Plugin to display selected image path
|
[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://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/official/import_filter_manager)|Yes|LMW|Manager for import filters
|
[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://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/official/import_filters)|No|LMW|Two import filters for use with import_filter_manager
|
[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://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/official/save_selection)|Yes|LMW|Provide save and restore from multiple selection buffers
|
[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://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/official/selection_to_pdf)|No|L|Generate a PDF file from the selected images
|
[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
|
### Contributed Scripts
|
||||||
@@ -34,42 +34,51 @@ These scripts are contributed by users. They are meant to have an "owner", i.e.
|
|||||||
|
|
||||||
Name|Standalone|OS |Purpose
|
Name|Standalone|OS |Purpose
|
||||||
----|:--------:|:---:|-------
|
----|:--------:|:---:|-------
|
||||||
[AutoGrouper](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/autogrouper)|Yes|LMW|Group images together by time
|
[AutoGrouper](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/autogrouper)|Yes|LMW|Group images together by time
|
||||||
[autostyle](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/autostyle)|Yes|LMW|Automatically apply styles on import
|
[autostyle](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/autostyle)|Yes|LMW|Automatically apply styles on import
|
||||||
|
[auto_tag_modified](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/auto_tag_modified)|Yes|LMW|Automatically tag images which have been manually modified in the darkroom
|
||||||
change_group_leader|Yes|LMW|Change which image leads group
|
change_group_leader|Yes|LMW|Change which image leads group
|
||||||
[clear_GPS](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/clear_gps)|Yes|LMW|Reset GPS information for selected images
|
[clear_GPS](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/clear_gps)|Yes|LMW|Reset GPS information for selected images
|
||||||
[CollectHelper](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/collecthelper)|Yes|LMW|Add buttons to selected images module to manipulate the collection
|
[CollectHelper](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/collecthelper)|Yes|LMW|Add buttons to selected images module to manipulate the collection
|
||||||
[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
|
color_profile_manager|Yes|LMW|Manage darktable input and output color profiles
|
||||||
[cr2hdr](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/cr2hdr)|Yes|L|Process image created with Magic Lantern Dual ISO
|
[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
|
||||||
[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
|
[cr2hdr](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/cr2hdr)|Yes|L|Process image created with Magic Lantern Dual ISO
|
||||||
[exportLUT](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/exportlut)|Yes|LMW|Create a LUT from a style and export it
|
cycle_group_leader|Yes|LMW|cycle through images of a group making each the group leader in turn
|
||||||
[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
|
dbmaint|Yes|LMW|find and remove database entries for missing film rolls and images
|
||||||
[face_recognition](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/face_recognition)|No|LM|Identify and tag images using facial recognition
|
[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
|
||||||
[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
|
[exportLUT](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/exportlut)|Yes|LMW|Create a LUT from a style and export it
|
||||||
[fujifilm_ratings](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/fujifilm_ratings)|No|LM|Support importing Fujifilm ratings
|
[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
|
||||||
[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 ...
|
[face_recognition](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/face_recognition)|No|LM|Identify and tag images using facial recognition
|
||||||
[geoToolbox](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/geotoolbox)|No|LMW|A toolbox of geo functions
|
[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
|
||||||
[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
|
[fujifilm_ratings](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/fujifilm_ratings)|No|LM|Support importing Fujifilm ratings
|
||||||
[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
|
[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 ...
|
||||||
[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
|
[geoToolbox](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/geotoolbox)|No|LMW|A toolbox of geo functions
|
||||||
[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
|
[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
|
||||||
[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
|
[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
|
||||||
[image_time](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/image_time)|Yes|LMW|Adjust the EXIF image time
|
harmonic_armature|Yes|LMW|provide a harmonic armature guide
|
||||||
[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
|
hif_group_leader|Yes|LMW|change the group leader in a raw+heif image pair to the heif image
|
||||||
[LabelsToTags](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/labelstotags)|Yes|LMW|Apply tags based on color labels and ratings
|
[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
|
||||||
[OpenInExplorer](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/openinexplorer)|No|LMW|Open the selected images in the system file manager
|
[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
|
||||||
[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
|
[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
|
||||||
[pdf_slideshow](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/pdf_slideshow)|No|LM|Export images to a PDF slideshow
|
[image_time](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/image_time)|Yes|LMW|Adjust the EXIF image time
|
||||||
[photils](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/photils)|No|LM|Automatic tag suggestions for your images
|
jpg_group_leader|Yes|LMW|change the group leader for a raw+jpg pair to the jpg image
|
||||||
[quicktag](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/quicktag)|Yes|LMW|Create shortcuts for quickly applying tags
|
[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
|
||||||
[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
|
[LabelsToTags](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/labelstotags)|Yes|LMW|Apply tags based on color labels and ratings
|
||||||
[rename_images](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/rename_images)|Yes|LMW|Rename single or multiple images
|
[OpenInExplorer](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/openinexplorer)|No|LMW|Open the selected images in the system file manager
|
||||||
[rename-tags](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/rename-tags)|Yes|LMW|Change a tag name
|
[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
|
||||||
[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)
|
passport_guide_germany|Yes|LMW|Add passport cropping guide for German passports to darkroom crop tool
|
||||||
[select_untagged](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/select_untagged)|Yes|LMW|Enable selection of untagged images
|
[pdf_slideshow](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/pdf_slideshow)|No|LM|Export images to a PDF slideshow
|
||||||
[slideshowMusic](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/slideshowMusic)|No|L|Play music during a slideshow
|
[photils](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/photils)|No|LM|Automatic tag suggestions for your images
|
||||||
[transfer_hierarchy](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/transfer_hierarchy)|Yes|LMW|Image move/copy preserving directory hierarchy
|
[quicktag](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/quicktag)|Yes|LMW|Create shortcuts for quickly applying tags
|
||||||
[video_ffmpeg](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/contrib/video_ffmpeg)|No|LMW|Export video from darktable
|
[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
|
### Example Scripts
|
||||||
|
|
||||||
@@ -77,17 +86,19 @@ These scripts provide examples of how to use specific portions of the API. They
|
|||||||
|
|
||||||
Name|Standalone|OS |Purpose
|
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
|
[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://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/darkroom_demo)|Yes|LMW|Demonstrate changing images in darkoom
|
[darkroom_demo](https://docs.darktable.org/lua/stable/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
|
[gettextExample](https://docs.darktable.org/lua/stable/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
|
gui_actions|Yes|LMW|demonstrate controlling the GUI using darktable.gui.action calls
|
||||||
[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
|
[hello_world](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/examples/hello_world)|Yes|LMW|Prints hello world when darktable starts
|
||||||
[moduleExample](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/moduleexample)|Yes|LMW|How to create a lighttable module
|
[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
|
||||||
[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
|
[moduleExample](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/examples/moduleexample)|Yes|LMW|How to create a lighttable module
|
||||||
[panels_demo](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/panels_demo)|Yes|LMW|Demonstrate hiding and showing darktable panels
|
[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
|
||||||
[preferenceExamples](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/preferenceexamples)|Yes|LMW|How to use preferences in a script
|
[panels_demo](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/examples/panels_demo)|Yes|LMW|Demonstrate hiding and showing darktable panels
|
||||||
[printExamples](https://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/examples/printexamples)|Yes|LMW|How to use various print functions from a script
|
[preferenceExamples](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/examples/preferenceexamples)|Yes|LMW|How to use preferences in 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
|
[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
|
### Tools
|
||||||
|
|
||||||
@@ -95,11 +106,11 @@ Tool scripts perform functions relating to the repository, such as generating do
|
|||||||
|
|
||||||
Name|Standalone|OS |Purpose
|
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
|
[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://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/tools/gen_i18n_mo)|No|LMW|Generate compiled translation files (.mo) from source files (.po)
|
[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://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_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://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/tools/get_libdoc)|No|LMW|Retrieve the library documentation and output it as text
|
[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://darktable-org.github.io/luadocs/lua.scripts.manual/scripts/tools/script_manager)|No|LMW|Manage (install, update, enable, disable) the lua scripts
|
[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
|
### Related third-party projects
|
||||||
|
|
||||||
@@ -117,6 +128,8 @@ The following third-party projects are listed for information only. Think of thi
|
|||||||
* [nbremond77/darktable](https://github.com/nbremond77/darktable/tree/master/scripts)
|
* [nbremond77/darktable](https://github.com/nbremond77/darktable/tree/master/scripts)
|
||||||
* [s5k6/dtscripts](https://github.com/s5k6/dtscripts)
|
* [s5k6/dtscripts](https://github.com/s5k6/dtscripts)
|
||||||
* [ChristianBirzer/darktable_extra_scripts](https://github.com/ChristianBirzer/darktable_extra_scripts)
|
* [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
|
## Download and Install
|
||||||
|
|
||||||
@@ -166,7 +179,7 @@ If you don't have %LOCALAPPDATA%\darktable you have to start dartable at least o
|
|||||||
|
|
||||||
When darktable starts it looks for a file name `~/.config/darktable/luarc` (`%LOCALAPPDATA%\darktable\luarc` for windows) and reads it to see which scripts to include. The file is a plain text file with entries of the form `require "<directory>/<name>"` where directory is the directory containing the scripts, from the above list, and name is the name from the above list. To include GIMP the line would be `require "contrib/gimp"`.
|
When darktable starts it looks for a file name `~/.config/darktable/luarc` (`%LOCALAPPDATA%\darktable\luarc` for windows) and reads it to see which scripts to include. The file is a plain text file with entries of the form `require "<directory>/<name>"` where directory is the directory containing the scripts, from the above list, and name is the name from the above list. To include GIMP the line would be `require "contrib/gimp"`.
|
||||||
|
|
||||||
The recommended way to enable and disable specific scripts is using the script manager module. To use script manager do the following:
|
The recommended way to enable and disable specific scripts is using the [script manager](https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/tools/script_manager/) module. To use script manager do the following:
|
||||||
|
|
||||||
### Linux or MacOS
|
### Linux or MacOS
|
||||||
|
|
||||||
@@ -174,7 +187,7 @@ The recommended way to enable and disable specific scripts is using the script m
|
|||||||
|
|
||||||
### Windows
|
### Windows
|
||||||
|
|
||||||
echo "require 'tools/script_manager'" > %LOCALAPPDATA%\darktable\luarc
|
echo require "tools/script_manager" > %LOCALAPPDATA%\darktable\luarc
|
||||||
|
|
||||||
### Snap
|
### Snap
|
||||||
|
|
||||||
@@ -182,7 +195,7 @@ The recommended way to enable and disable specific scripts is using the script m
|
|||||||
|
|
||||||
### Flatpak
|
### 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:
|
You can also create or add lines to the luarc file from the command line:
|
||||||
|
|
||||||
@@ -225,18 +238,18 @@ To update the script repository, open a terminal or command prompt and do the fo
|
|||||||
|
|
||||||
## Documentation
|
## 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
|
for the scripts transcribed from the header comments. Each script also contains comments and usage instructions
|
||||||
in the header comments.
|
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
|
documentation of the libraries and functions. Lua-script libraries documentation may also be generated using
|
||||||
the tools in the tools/ directory.
|
the tools in the tools/ directory.
|
||||||
|
|
||||||
More information about the scripting with Lua can be found in the darktable user manual:
|
More information about the scripting with Lua can be found in the darktable user manual:
|
||||||
[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.
|
darktable Lua API.
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|||||||
@@ -1,218 +1,225 @@
|
|||||||
--[[AutoGrouper plugin for darktable
|
--[[AutoGrouper plugin for darktable
|
||||||
|
|
||||||
copyright (c) 2019 Kevin Ertel
|
copyright (c) 2019 Kevin Ertel
|
||||||
|
|
||||||
darktable is free software: you can redistribute it and/or modify
|
darktable is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
(at your option) any later version.
|
(at your option) any later version.
|
||||||
|
|
||||||
darktable is distributed in the hope that it will be useful,
|
darktable is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
GNU General Public License for more details.
|
GNU General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with darktable. If not, see <http://www.gnu.org/licenses/>.
|
along with darktable. If not, see <http://www.gnu.org/licenses/>.
|
||||||
]]
|
]]
|
||||||
|
|
||||||
--[[About this Plugin
|
--[[About this Plugin
|
||||||
This plugin adds the module "Auto Group" to darktable's lighttable view
|
This plugin adds the module "Auto Group" to darktable's lighttable view
|
||||||
|
|
||||||
----REQUIRED SOFTWARE----
|
----REQUIRED SOFTWARE----
|
||||||
None
|
None
|
||||||
|
|
||||||
----USAGE----
|
----USAGE----
|
||||||
Install: (see here for more detail: https://github.com/darktable-org/lua-scripts )
|
Install: (see here for more detail: https://github.com/darktable-org/lua-scripts )
|
||||||
1) Copy this file in to your "lua/contrib" folder where all other scripts reside.
|
1) Copy this file in to your "lua/contrib" folder where all other scripts reside.
|
||||||
2) Require this file in your luarc file, as with any other dt plug-in
|
2) Require this file in your luarc file, as with any other dt plug-in
|
||||||
|
|
||||||
Set a gap amount in second which will be used to determine when images should no
|
Set a gap amount in second which will be used to determine when images should no
|
||||||
longer be added to a group. If an image is more then the specified amount of time
|
longer be added to a group. If an image is more then the specified amount of time
|
||||||
from the last image in the group it will not be added. Images without timestamps
|
from the last image in the group it will not be added. Images without timestamps
|
||||||
in exif data will be ignored.
|
in exif data will be ignored.
|
||||||
|
|
||||||
There are two buttons. One allows the grouping to be performed only on the currently
|
There are two buttons. One allows the grouping to be performed only on the currently
|
||||||
selected images, the other button performs grouping on the entire active collection
|
selected images, the other button performs grouping on the entire active collection
|
||||||
]]
|
]]
|
||||||
|
|
||||||
local dt = require "darktable"
|
local dt = require "darktable"
|
||||||
local du = require "lib/dtutils"
|
local du = require "lib/dtutils"
|
||||||
|
|
||||||
du.check_min_api_version("7.0.0", "AutoGrouper")
|
du.check_min_api_version("7.0.0", "AutoGrouper")
|
||||||
|
|
||||||
local MOD = 'autogrouper'
|
local MOD = 'autogrouper'
|
||||||
|
|
||||||
-- return data structure for script_manager
|
local gettext = dt.gettext.gettext
|
||||||
|
|
||||||
local script_data = {}
|
local function _(msgid)
|
||||||
|
return gettext(msgid)
|
||||||
script_data.destroy = nil -- function to destory the script
|
end
|
||||||
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
|
-- return data structure for script_manager
|
||||||
|
|
||||||
local gettext = dt.gettext
|
local script_data = {}
|
||||||
-- Tell gettext where to find the .mo file translating messages for a particular domain
|
|
||||||
gettext.bindtextdomain("AutoGrouper",dt.configuration.config_dir.."/lua/locale/")
|
script_data.metadata = {
|
||||||
|
name = _("auto group"),
|
||||||
local function _(msgid)
|
purpose = _("automatically group images by time interval"),
|
||||||
return gettext.dgettext("AutoGrouper", msgid)
|
author = "Kevin Ertel",
|
||||||
end
|
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/AutoGrouper/"
|
||||||
|
}
|
||||||
local Ag = {}
|
|
||||||
Ag.module_installed = false
|
script_data.destroy = nil -- function to destory the script
|
||||||
Ag.event_registered = false
|
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 GUI = {
|
script_data.show = nil -- only required for libs since the destroy_method only hides them
|
||||||
gap = {},
|
|
||||||
selected = {},
|
local Ag = {}
|
||||||
collection = {}
|
Ag.module_installed = false
|
||||||
}
|
Ag.event_registered = false
|
||||||
|
|
||||||
|
local GUI = {
|
||||||
local function InRange(test, low, high) --tests if test value is within range of low and high (inclusive)
|
gap = {},
|
||||||
if test >= low and test <= high then
|
selected = {},
|
||||||
return true
|
collection = {}
|
||||||
else
|
}
|
||||||
return false
|
|
||||||
end
|
|
||||||
end
|
local function InRange(test, low, high) --tests if test value is within range of low and high (inclusive)
|
||||||
|
if test >= low and test <= high then
|
||||||
local function CompTime(first, second) --compares the timestamps and returns true if first was taken before second
|
return true
|
||||||
first_time = first.exif_datetime_taken
|
else
|
||||||
if string.match(first_time, '[0-9]') == nil then first_time = '9999:99:99 99:99:99' end
|
return false
|
||||||
first_time = tonumber(string.gsub(first_time, '[^0-9]*',''))
|
end
|
||||||
second_time = second.exif_datetime_taken
|
end
|
||||||
if string.match(second_time, '[0-9]') == nil then second_time = '9999:99:99 99:99:99' end
|
|
||||||
second_time = tonumber(string.gsub(second_time, '[^0-9]*',''))
|
local function CompTime(first, second) --compares the timestamps and returns true if first was taken before second
|
||||||
return first_time < second_time
|
first_time = first.exif_datetime_taken
|
||||||
end
|
if string.match(first_time, '[0-9]') == nil then first_time = '9999:99:99 99:99:99' end
|
||||||
|
first_time = tonumber(string.gsub(first_time, '[^0-9]*',''))
|
||||||
local function SeperateTime(str) --seperates the timestamp into individual components for used with OS.time operations
|
second_time = second.exif_datetime_taken
|
||||||
local cleaned = string.gsub(str, '[^%d]',':')
|
if string.match(second_time, '[0-9]') == nil then second_time = '9999:99:99 99:99:99' end
|
||||||
cleaned = string.gsub(cleaned, '::*',':') --YYYY:MM:DD:hh:mm:ss
|
second_time = tonumber(string.gsub(second_time, '[^0-9]*',''))
|
||||||
local year = string.sub(cleaned,1,4)
|
return first_time < second_time
|
||||||
local month = string.sub(cleaned,6,7)
|
end
|
||||||
local day = string.sub(cleaned,9,10)
|
|
||||||
local hour = string.sub(cleaned,12,13)
|
local function SeperateTime(str) --seperates the timestamp into individual components for used with OS.time operations
|
||||||
local min = string.sub(cleaned,15,16)
|
local cleaned = string.gsub(str, '[^%d]',':')
|
||||||
local sec = string.sub(cleaned,18,19)
|
cleaned = string.gsub(cleaned, '::*',':') --YYYY:MM:DD:hh:mm:ss
|
||||||
return {year = year, month = month, day = day, hour = hour, min = min, sec = sec}
|
local year = string.sub(cleaned,1,4)
|
||||||
end
|
local month = string.sub(cleaned,6,7)
|
||||||
|
local day = string.sub(cleaned,9,10)
|
||||||
local function GetTimeDiff(curr_image, prev_image) --returns the time difference (in sec.) from current image and the previous image
|
local hour = string.sub(cleaned,12,13)
|
||||||
local curr_time = SeperateTime(curr_image.exif_datetime_taken)
|
local min = string.sub(cleaned,15,16)
|
||||||
local prev_time = SeperateTime(prev_image.exif_datetime_taken)
|
local sec = string.sub(cleaned,18,19)
|
||||||
return os.time(curr_time)-os.time(prev_time)
|
return {year = year, month = month, day = day, hour = hour, min = min, sec = sec}
|
||||||
end
|
end
|
||||||
|
|
||||||
local function main(on_collection)
|
local function GetTimeDiff(curr_image, prev_image) --returns the time difference (in sec.) from current image and the previous image
|
||||||
local images = {}
|
local curr_time = SeperateTime(curr_image.exif_datetime_taken)
|
||||||
if on_collection then
|
local prev_time = SeperateTime(prev_image.exif_datetime_taken)
|
||||||
local col_images = dt.collection
|
return os.time(curr_time)-os.time(prev_time)
|
||||||
for i,image in ipairs(col_images) do --copy images to a standard table, table.sort barfs on type dt_lua_singleton_image_collection
|
end
|
||||||
table.insert(images,i,image)
|
|
||||||
end
|
local function main(on_collection)
|
||||||
else
|
local images = {}
|
||||||
images = dt.gui.selection()
|
if on_collection then
|
||||||
end
|
local col_images = dt.collection
|
||||||
dt.preferences.write(MOD, 'active_gap', 'integer', GUI.gap.value)
|
for i,image in ipairs(col_images) do --copy images to a standard table, table.sort barfs on type dt_lua_singleton_image_collection
|
||||||
if #images < 2 then
|
table.insert(images,i,image)
|
||||||
dt.print('please select at least 2 images')
|
end
|
||||||
return
|
else
|
||||||
end
|
images = dt.gui.selection()
|
||||||
table.sort(images, function(first, second) return CompTime(first,second) end) --sort images by timestamp
|
end
|
||||||
|
dt.preferences.write(MOD, 'active_gap', 'integer', GUI.gap.value)
|
||||||
for i, image in ipairs(images) do
|
if #images < 2 then
|
||||||
if i == 1 then
|
dt.print('please select at least 2 images')
|
||||||
prev_image = image
|
return
|
||||||
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
|
end
|
||||||
local curr_image = image
|
table.sort(images, function(first, second) return CompTime(first,second) end) --sort images by timestamp
|
||||||
if GetTimeDiff(curr_image, prev_image) <= GUI.gap.value then
|
|
||||||
images[i]:group_with(images[i-1])
|
for i, image in ipairs(images) do
|
||||||
end
|
if i == 1 then
|
||||||
prev_image = curr_image
|
prev_image = image
|
||||||
end
|
image:make_group_leader()
|
||||||
end
|
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
|
||||||
end
|
local curr_image = image
|
||||||
|
if GetTimeDiff(curr_image, prev_image) <= GUI.gap.value then
|
||||||
local function install_module()
|
images[i]:group_with(images[i-1].group_leader)
|
||||||
if not Ag.module_installed then
|
end
|
||||||
dt.print_log("installing module")
|
prev_image = curr_image
|
||||||
dt.register_lib(
|
end
|
||||||
MOD, -- Module name
|
end
|
||||||
_('auto group'), -- name
|
end
|
||||||
true, -- expandable
|
|
||||||
true, -- resetable
|
local function install_module()
|
||||||
{[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 99}}, -- containers
|
if not Ag.module_installed then
|
||||||
dt.new_widget("box"){
|
dt.print_log("installing module")
|
||||||
orientation = "vertical",
|
dt.register_lib(
|
||||||
GUI.gap,
|
MOD, -- Module name
|
||||||
GUI.selected,
|
_('auto group'), -- name
|
||||||
GUI.collection
|
true, -- expandable
|
||||||
}
|
true, -- resetable
|
||||||
)
|
{[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 99}}, -- containers
|
||||||
Ag.module_installed = true
|
dt.new_widget("box"){
|
||||||
dt.print_log("module installed")
|
orientation = "vertical",
|
||||||
dt.print_log("styles module visibility is " .. tostring(dt.gui.libs["styles"].visible))
|
GUI.gap,
|
||||||
end
|
GUI.selected,
|
||||||
end
|
GUI.collection
|
||||||
|
}
|
||||||
local function destroy()
|
)
|
||||||
dt.gui.libs[MOD].visible = false
|
Ag.module_installed = true
|
||||||
end
|
dt.print_log("module installed")
|
||||||
|
dt.print_log("styles module visibility is " .. tostring(dt.gui.libs["styles"].visible))
|
||||||
local function restart()
|
end
|
||||||
dt.gui.libs[MOD].visible = true
|
end
|
||||||
end
|
|
||||||
|
local function destroy()
|
||||||
-- GUI --
|
dt.gui.libs[MOD].visible = false
|
||||||
temp = dt.preferences.read(MOD, 'active_gap', 'integer')
|
end
|
||||||
if not InRange(temp, 1, 86400) then temp = 3 end
|
|
||||||
GUI.gap = dt.new_widget('slider'){
|
local function restart()
|
||||||
label = _('group gap [sec.]'),
|
dt.gui.libs[MOD].visible = true
|
||||||
tooltip = _('minimum gap, in seconds, between groups'),
|
end
|
||||||
soft_min = 1,
|
|
||||||
soft_max = 60,
|
-- GUI --
|
||||||
hard_min = 1,
|
temp = dt.preferences.read(MOD, 'active_gap', 'integer')
|
||||||
hard_max = 86400,
|
if not InRange(temp, 1, 86400) then temp = 3 end
|
||||||
step = 1,
|
GUI.gap = dt.new_widget('slider'){
|
||||||
digits = 0,
|
label = _('group gap [sec.]'),
|
||||||
value = temp,
|
tooltip = _('minimum gap, in seconds, between groups'),
|
||||||
reset_callback = function(self)
|
soft_min = 1,
|
||||||
self.value = 3
|
soft_max = 60,
|
||||||
end
|
hard_min = 1,
|
||||||
}
|
hard_max = 86400,
|
||||||
GUI.selected = dt.new_widget("button"){
|
step = 1,
|
||||||
label = _('auto group: selected'),
|
digits = 0,
|
||||||
tooltip =_('auto group selected images'),
|
value = temp,
|
||||||
clicked_callback = function() main(false) end
|
reset_callback = function(self)
|
||||||
}
|
self.value = 3
|
||||||
GUI.collection = dt.new_widget("button"){
|
end
|
||||||
label = _('auto group: collection'),
|
}
|
||||||
tooltip =_('auto group the entire collection'),
|
GUI.selected = dt.new_widget("button"){
|
||||||
clicked_callback = function() main(true) end
|
label = _('auto group: selected'),
|
||||||
}
|
tooltip =_('auto group selected images'),
|
||||||
|
clicked_callback = function() main(false) end
|
||||||
if dt.gui.current_view().id == "lighttable" then
|
}
|
||||||
install_module()
|
GUI.collection = dt.new_widget("button"){
|
||||||
else
|
label = _('auto group: collection'),
|
||||||
if not Ag.event_registered then
|
tooltip =_('auto group the entire collection'),
|
||||||
dt.register_event(
|
clicked_callback = function() main(true) end
|
||||||
"AutoGrouper", "view-changed",
|
}
|
||||||
function(event, old_view, new_view)
|
|
||||||
if new_view.name == "lighttable" and old_view.name == "darkroom" then
|
if dt.gui.current_view().id == "lighttable" then
|
||||||
install_module()
|
install_module()
|
||||||
end
|
else
|
||||||
end
|
if not Ag.event_registered then
|
||||||
)
|
dt.register_event(
|
||||||
Ag.event_registered = true
|
"AutoGrouper", "view-changed",
|
||||||
end
|
function(event, old_view, new_view)
|
||||||
end
|
if new_view.name == "lighttable" and old_view.name == "darkroom" then
|
||||||
|
install_module()
|
||||||
script_data.destroy = destroy
|
end
|
||||||
script_data.destroy_method = "hide"
|
end
|
||||||
script_data.restart = restart
|
)
|
||||||
script_data.show = restart
|
Ag.event_registered = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
script_data.destroy = destroy
|
||||||
|
script_data.destroy_method = "hide"
|
||||||
|
script_data.restart = restart
|
||||||
|
script_data.show = restart
|
||||||
|
|
||||||
return script_data
|
return script_data
|
||||||
|
|||||||
@@ -1,253 +1,258 @@
|
|||||||
--[[Collect Helper plugin for darktable
|
--[[Collect Helper plugin for darktable
|
||||||
|
|
||||||
copyright (c) 2019 Kevin Ertel
|
copyright (c) 2019 Kevin Ertel
|
||||||
|
|
||||||
darktable is free software: you can redistribute it and/or modify
|
darktable is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
(at your option) any later version.
|
(at your option) any later version.
|
||||||
|
|
||||||
darktable is distributed in the hope that it will be useful,
|
darktable is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
GNU General Public License for more details.
|
GNU General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with darktable. If not, see <http://www.gnu.org/licenses/>.
|
along with darktable. If not, see <http://www.gnu.org/licenses/>.
|
||||||
]]
|
]]
|
||||||
|
|
||||||
--[[About this plugin
|
--[[About this plugin
|
||||||
This plugin adds the button(s) to the "Selected Images" module:
|
This plugin adds the button(s) to the "Selected Images" module:
|
||||||
1) Return to Previous Collection
|
1) Return to Previous Collection
|
||||||
2) Collect on image's Folder
|
2) Collect on image's Folder
|
||||||
3) Collect on image's Color Label(s)
|
3) Collect on image's Color Label(s)
|
||||||
4) Collect on All (AND)
|
4) Collect on All (AND)
|
||||||
|
|
||||||
It also adds 3 preferences to the lua options dialog box which allow the user to activate/deactivate the 3 "Collect on" buttons.
|
It also adds 3 preferences to the lua options dialog box which allow the user to activate/deactivate the 3 "Collect on" buttons.
|
||||||
|
|
||||||
Button Behavior:
|
Button Behavior:
|
||||||
1) Return to Previous Collection - Will reset the collect parameters to the previously active settings
|
1) Return to Previous Collection - Will reset the collect parameters to the previously active settings
|
||||||
2) Collect on image's Folder - Will change the collect parameters to be "Folder" with a value of the selected image's folder location
|
2) Collect on image's Folder - Will change the collect parameters to be "Folder" with a value of the selected image's folder location
|
||||||
3) Collect on image's Color Label(s) - Will change the collect parameter to be "Color" with a value of the selected images color labels, will apply multiple parameters with AND logic if multiple exist
|
3) Collect on image's Color Label(s) - Will change the collect parameter to be "Color" with a value of the selected images color labels, will apply multiple parameters with AND logic if multiple exist
|
||||||
4) Collect on All (AND) - Will collect on all parameters activated by the preferences dialog, as such this button is redundant if you only have one of the two other options enabled
|
4) Collect on All (AND) - Will collect on all parameters activated by the preferences dialog, as such this button is redundant if you only have one of the two other options enabled
|
||||||
|
|
||||||
----REQUIRED SOFTWARE----
|
----REQUIRED SOFTWARE----
|
||||||
NA
|
NA
|
||||||
|
|
||||||
----USAGE----
|
----USAGE----
|
||||||
Install: (see here for more detail: https://github.com/darktable-org/lua-scripts )
|
Install: (see here for more detail: https://github.com/darktable-org/lua-scripts )
|
||||||
1) Copy this file in to your "lua/contrib" folder where all other scripts reside.
|
1) Copy this file in to your "lua/contrib" folder where all other scripts reside.
|
||||||
2) Require this file in your luarc file, as with any other dt plug-in
|
2) Require this file in your luarc file, as with any other dt plug-in
|
||||||
|
|
||||||
Select the photo you wish to change you collection based on.
|
Select the photo you wish to change you collection based on.
|
||||||
In the "Selected Images" module click on "Collect on this Image"
|
In the "Selected Images" module click on "Collect on this Image"
|
||||||
|
|
||||||
----KNOWN ISSUES----
|
----KNOWN ISSUES----
|
||||||
]]
|
]]
|
||||||
|
|
||||||
local dt = require "darktable"
|
local dt = require "darktable"
|
||||||
local du = require "lib/dtutils"
|
local du = require "lib/dtutils"
|
||||||
local gettext = dt.gettext
|
local gettext = dt.gettext.gettext
|
||||||
local previous = nil
|
local previous = nil
|
||||||
local all_active = false
|
local all_active = false
|
||||||
|
|
||||||
-- Tell gettext where to find the .mo file translating messages for a particular domain
|
du.check_min_api_version("7.0.0", "CollectHelper")
|
||||||
gettext.bindtextdomain("CollectHelper",dt.configuration.config_dir.."/lua/locale/")
|
|
||||||
|
local function _(msgid)
|
||||||
du.check_min_api_version("7.0.0", "CollectHelper")
|
return gettext(msgid)
|
||||||
|
end
|
||||||
-- return data structure for script_manager
|
|
||||||
|
-- return data structure for script_manager
|
||||||
local script_data = {}
|
|
||||||
|
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, otherwise leave as nil
|
script_data.metadata = {
|
||||||
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
|
name = _("collection helper"),
|
||||||
|
purpose = _("add collection helper buttons"),
|
||||||
local function _(msgid)
|
author = "Kevin Ertel",
|
||||||
return gettext.dgettext("CollectHelper", msgid)
|
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/CollectHelper/"
|
||||||
end
|
}
|
||||||
|
|
||||||
-- FUNCTION --
|
script_data.destroy = nil -- function to destory the script
|
||||||
local function CheckSingleImage(selection)
|
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil
|
||||||
if #selection ~= 1 then
|
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
|
||||||
dt.print(_("Please select a single image"))
|
script_data.show = nil -- only required for libs since the destroy_method only hides them
|
||||||
return true
|
|
||||||
end
|
-- FUNCTION --
|
||||||
return false
|
local function CheckSingleImage(selection)
|
||||||
end
|
if #selection ~= 1 then
|
||||||
|
dt.print(_("please select a single image"))
|
||||||
local function CheckHasColorLabel(selection)
|
return true
|
||||||
local ret = false
|
end
|
||||||
for _,image in pairs(selection) do
|
return false
|
||||||
if image.red then ret = true end
|
end
|
||||||
if image.blue then ret = true end
|
|
||||||
if image.green then ret = true end
|
local function CheckHasColorLabel(selection)
|
||||||
if image.yellow then ret = true end
|
local ret = false
|
||||||
if image.purple then ret = true end
|
for _,image in pairs(selection) do
|
||||||
end
|
if image.red then ret = true end
|
||||||
return ret
|
if image.blue then ret = true end
|
||||||
end
|
if image.green then ret = true end
|
||||||
local function PreviousCollection()
|
if image.yellow then ret = true end
|
||||||
if previous ~= nil then
|
if image.purple then ret = true end
|
||||||
previous = dt.gui.libs.collect.filter(previous)
|
end
|
||||||
end
|
return ret
|
||||||
end
|
end
|
||||||
|
local function PreviousCollection()
|
||||||
local function CollectOnFolder(all_rules, all_active)
|
if previous ~= nil then
|
||||||
local images = dt.gui.selection()
|
previous = dt.gui.libs.collect.filter(previous)
|
||||||
if CheckSingleImage(images) then
|
end
|
||||||
return
|
end
|
||||||
end
|
|
||||||
local rules = {}
|
local function CollectOnFolder(all_rules, all_active)
|
||||||
local rule = dt.gui.libs.collect.new_rule()
|
local images = dt.gui.selection()
|
||||||
rule.mode = "DT_LIB_COLLECT_MODE_AND"
|
if CheckSingleImage(images) then
|
||||||
rule.data = images[1].path
|
return
|
||||||
rule.item = "DT_COLLECTION_PROP_FOLDERS"
|
end
|
||||||
table.insert(rules, rule)
|
local rules = {}
|
||||||
if all_active then
|
local rule = dt.gui.libs.collect.new_rule()
|
||||||
for _,active_rule in pairs(rules) do
|
rule.mode = "DT_LIB_COLLECT_MODE_AND"
|
||||||
table.insert(all_rules, active_rule)
|
rule.data = images[1].path
|
||||||
end
|
rule.item = "DT_COLLECTION_PROP_FOLDERS"
|
||||||
return all_rules
|
table.insert(rules, rule)
|
||||||
else
|
if all_active then
|
||||||
previous = dt.gui.libs.collect.filter(rules)
|
for _,active_rule in pairs(rules) do
|
||||||
end
|
table.insert(all_rules, active_rule)
|
||||||
end
|
end
|
||||||
|
return all_rules
|
||||||
local function CollectOnColors(all_rules, all_active)
|
else
|
||||||
local images = dt.gui.selection()
|
previous = dt.gui.libs.collect.filter(rules)
|
||||||
if CheckSingleImage(images) then
|
end
|
||||||
return
|
end
|
||||||
end
|
|
||||||
if not CheckHasColorLabel(images) then
|
local function CollectOnColors(all_rules, all_active)
|
||||||
dt.print(_('select an image with an active color label'))
|
local images = dt.gui.selection()
|
||||||
return
|
if CheckSingleImage(images) then
|
||||||
end
|
return
|
||||||
for _,image in pairs(images) do
|
end
|
||||||
local rules = {}
|
if not CheckHasColorLabel(images) then
|
||||||
if image.red then
|
dt.print(_('select an image with an active color label'))
|
||||||
local red_rule = dt.gui.libs.collect.new_rule()
|
return
|
||||||
red_rule.mode = "DT_LIB_COLLECT_MODE_AND"
|
end
|
||||||
red_rule.data = "red"
|
for _,image in pairs(images) do
|
||||||
red_rule.item = "DT_COLLECTION_PROP_COLORLABEL"
|
local rules = {}
|
||||||
table.insert(rules, red_rule)
|
if image.red then
|
||||||
end
|
local red_rule = dt.gui.libs.collect.new_rule()
|
||||||
if image.blue then
|
red_rule.mode = "DT_LIB_COLLECT_MODE_AND"
|
||||||
local blue_rule = dt.gui.libs.collect.new_rule()
|
red_rule.data = "red"
|
||||||
blue_rule.mode = "DT_LIB_COLLECT_MODE_AND"
|
red_rule.item = "DT_COLLECTION_PROP_COLORLABEL"
|
||||||
blue_rule.data = "blue"
|
table.insert(rules, red_rule)
|
||||||
blue_rule.item = "DT_COLLECTION_PROP_COLORLABEL"
|
end
|
||||||
table.insert(rules, blue_rule)
|
if image.blue then
|
||||||
end
|
local blue_rule = dt.gui.libs.collect.new_rule()
|
||||||
if image.green then
|
blue_rule.mode = "DT_LIB_COLLECT_MODE_AND"
|
||||||
local green_rule = dt.gui.libs.collect.new_rule()
|
blue_rule.data = "blue"
|
||||||
green_rule.mode = "DT_LIB_COLLECT_MODE_AND"
|
blue_rule.item = "DT_COLLECTION_PROP_COLORLABEL"
|
||||||
green_rule.data = "green"
|
table.insert(rules, blue_rule)
|
||||||
green_rule.item = "DT_COLLECTION_PROP_COLORLABEL"
|
end
|
||||||
table.insert(rules, green_rule)
|
if image.green then
|
||||||
end
|
local green_rule = dt.gui.libs.collect.new_rule()
|
||||||
if image.yellow then
|
green_rule.mode = "DT_LIB_COLLECT_MODE_AND"
|
||||||
local yellow_rule = dt.gui.libs.collect.new_rule()
|
green_rule.data = "green"
|
||||||
yellow_rule.mode = "DT_LIB_COLLECT_MODE_AND"
|
green_rule.item = "DT_COLLECTION_PROP_COLORLABEL"
|
||||||
yellow_rule.data = "yellow"
|
table.insert(rules, green_rule)
|
||||||
yellow_rule.item = "DT_COLLECTION_PROP_COLORLABEL"
|
end
|
||||||
table.insert(rules, yellow_rule)
|
if image.yellow then
|
||||||
end
|
local yellow_rule = dt.gui.libs.collect.new_rule()
|
||||||
if image.purple then
|
yellow_rule.mode = "DT_LIB_COLLECT_MODE_AND"
|
||||||
local purple_rule = dt.gui.libs.collect.new_rule()
|
yellow_rule.data = "yellow"
|
||||||
purple_rule.mode = "DT_LIB_COLLECT_MODE_AND"
|
yellow_rule.item = "DT_COLLECTION_PROP_COLORLABEL"
|
||||||
purple_rule.data = "purple"
|
table.insert(rules, yellow_rule)
|
||||||
purple_rule.item = "DT_COLLECTION_PROP_COLORLABEL"
|
end
|
||||||
table.insert(rules, purple_rule)
|
if image.purple then
|
||||||
end
|
local purple_rule = dt.gui.libs.collect.new_rule()
|
||||||
if all_active then
|
purple_rule.mode = "DT_LIB_COLLECT_MODE_AND"
|
||||||
for _,active_rule in pairs(rules) do
|
purple_rule.data = "purple"
|
||||||
table.insert(all_rules, active_rule)
|
purple_rule.item = "DT_COLLECTION_PROP_COLORLABEL"
|
||||||
end
|
table.insert(rules, purple_rule)
|
||||||
return all_rules
|
end
|
||||||
else
|
if all_active then
|
||||||
previous = dt.gui.libs.collect.filter(rules)
|
for _,active_rule in pairs(rules) do
|
||||||
end
|
table.insert(all_rules, active_rule)
|
||||||
end
|
end
|
||||||
end
|
return all_rules
|
||||||
|
else
|
||||||
local function CollectOnAll_AND()
|
previous = dt.gui.libs.collect.filter(rules)
|
||||||
local images = dt.gui.selection()
|
end
|
||||||
if CheckSingleImage(images) then
|
end
|
||||||
return
|
end
|
||||||
end
|
|
||||||
local rules = {}
|
local function CollectOnAll_AND()
|
||||||
if dt.preferences.read('module_CollectHelper','folder','bool') then
|
local images = dt.gui.selection()
|
||||||
rules = CollectOnFolder(rules, true)
|
if CheckSingleImage(images) then
|
||||||
end
|
return
|
||||||
if dt.preferences.read('module_CollectHelper','colors','bool') then
|
end
|
||||||
rules = CollectOnColors(rules, true)
|
local rules = {}
|
||||||
end
|
if dt.preferences.read('module_CollectHelper','folder','bool') then
|
||||||
previous = dt.gui.libs.collect.filter(rules)
|
rules = CollectOnFolder(rules, true)
|
||||||
end
|
end
|
||||||
|
if dt.preferences.read('module_CollectHelper','colors','bool') then
|
||||||
local function destroy()
|
rules = CollectOnColors(rules, true)
|
||||||
dt.gui.libs.image.destroy_action("CollectHelper_prev")
|
end
|
||||||
if dt.preferences.read('module_CollectHelper','folder','bool') then
|
previous = dt.gui.libs.collect.filter(rules)
|
||||||
dt.gui.libs.image.destroy_action("CollectHelper_folder")
|
end
|
||||||
end
|
|
||||||
if dt.preferences.read('module_CollectHelper','colors','bool') then
|
local function destroy()
|
||||||
dt.gui.libs.image.destroy_action("CollectHelper_labels")
|
dt.gui.libs.image.destroy_action("CollectHelper_prev")
|
||||||
end
|
if dt.preferences.read('module_CollectHelper','folder','bool') then
|
||||||
if dt.preferences.read('module_CollectHelper','all_and','bool') then
|
dt.gui.libs.image.destroy_action("CollectHelper_folder")
|
||||||
dt.gui.libs.image.destroy_action("CollectHelper_and")
|
end
|
||||||
end
|
if dt.preferences.read('module_CollectHelper','colors','bool') then
|
||||||
end
|
dt.gui.libs.image.destroy_action("CollectHelper_labels")
|
||||||
|
end
|
||||||
-- GUI --
|
if dt.preferences.read('module_CollectHelper','all_and','bool') then
|
||||||
dt.gui.libs.image.register_action(
|
dt.gui.libs.image.destroy_action("CollectHelper_and")
|
||||||
"CollectHelper_prev", _("collect: previous"),
|
end
|
||||||
function() PreviousCollection() end,
|
end
|
||||||
_("Sets the Collect parameters to be the previously active parameters")
|
|
||||||
)
|
-- GUI --
|
||||||
if dt.preferences.read('module_CollectHelper','folder','bool') then
|
dt.gui.libs.image.register_action(
|
||||||
dt.gui.libs.image.register_action(
|
"CollectHelper_prev", _("collect: previous"),
|
||||||
"CollectHelper_folder", _("collect: folder"),
|
function() PreviousCollection() end,
|
||||||
function() CollectOnFolder(_ , false) end,
|
_("sets the collect parameters to be the previously active parameters")
|
||||||
_("Sets the Collect parameters to be the selected images's folder")
|
)
|
||||||
)
|
if dt.preferences.read('module_CollectHelper','folder','bool') then
|
||||||
end
|
dt.gui.libs.image.register_action(
|
||||||
if dt.preferences.read('module_CollectHelper','colors','bool') then
|
"CollectHelper_folder", _("collect: folder"),
|
||||||
dt.gui.libs.image.register_action(
|
function() CollectOnFolder(_ , false) end,
|
||||||
"CollectHelper_labels", _("collect: color label(s)"),
|
_("sets the collect parameters to be the selected images's folder")
|
||||||
function() CollectOnColors(_ , false) end,
|
)
|
||||||
_("Sets the Collect parameters to be the selected images's color label(s)")
|
end
|
||||||
)
|
if dt.preferences.read('module_CollectHelper','colors','bool') then
|
||||||
end
|
dt.gui.libs.image.register_action(
|
||||||
if dt.preferences.read('module_CollectHelper','all_and','bool') then
|
"CollectHelper_labels", _("collect: color label(s)"),
|
||||||
dt.gui.libs.image.register_action(
|
function() CollectOnColors(_ , false) end,
|
||||||
"CollectHelper_and", _("collect: all (AND)"),
|
_("sets the collect parameters to be the selected images's color label(s)")
|
||||||
function() CollectOnAll_AND() end,
|
)
|
||||||
_("Sets the Collect parameters based on all activated CollectHelper options")
|
end
|
||||||
)
|
if dt.preferences.read('module_CollectHelper','all_and','bool') then
|
||||||
end
|
dt.gui.libs.image.register_action(
|
||||||
|
"CollectHelper_and", _("collect: all (AND)"),
|
||||||
-- PREFERENCES --
|
function() CollectOnAll_AND() end,
|
||||||
dt.preferences.register("module_CollectHelper", "all_and", -- name
|
_("sets the collect parameters based on all activated CollectHelper options")
|
||||||
"bool", -- type
|
)
|
||||||
_('CollectHelper: All'), -- label
|
end
|
||||||
_('Will create a collect parameter set that utilizes all enabled CollectHelper types (AND)'), -- tooltip
|
|
||||||
true -- default
|
-- PREFERENCES --
|
||||||
)
|
dt.preferences.register("module_CollectHelper", "all_and", -- name
|
||||||
dt.preferences.register("module_CollectHelper", "colors", -- name
|
"bool", -- type
|
||||||
"bool", -- type
|
_('CollectHelper: all'), -- label
|
||||||
_('CollectHelper: Color Label(s)'), -- label
|
_('creates a collect parameter set that utilizes all enabled CollectHelper types (and)'), -- tooltip
|
||||||
_('Enable the button that allows you to swap to a collection based on selected image\'s COLOR LABEL(S)'), -- tooltip
|
true -- default
|
||||||
true -- default
|
)
|
||||||
)
|
dt.preferences.register("module_CollectHelper", "colors", -- name
|
||||||
dt.preferences.register("module_CollectHelper", "folder", -- name
|
"bool", -- type
|
||||||
"bool", -- type
|
_('CollectHelper: color label(s)'), -- label
|
||||||
_('CollectHelper: Folder'), -- label
|
_('enable the button that allows you to swap to a collection based on selected image\'s color label(s)'), -- tooltip
|
||||||
_('Enable the button that allows you to swap to a collection based on selected image\'s FOLDER location'), -- tooltip
|
true -- default
|
||||||
true -- default
|
)
|
||||||
)
|
dt.preferences.register("module_CollectHelper", "folder", -- name
|
||||||
|
"bool", -- type
|
||||||
script_data.destroy = destroy
|
_('CollectHelper: folder'), -- label
|
||||||
|
_('enable the button that allows you to swap to a collection based on selected image\'s folder location'), -- tooltip
|
||||||
return script_data
|
true -- default
|
||||||
|
)
|
||||||
|
|
||||||
|
script_data.destroy = destroy
|
||||||
|
|
||||||
|
return script_data
|
||||||
|
|||||||
@@ -1,478 +1,486 @@
|
|||||||
--[[HDRMerge plugin for darktable
|
--[[HDRMerge plugin for darktable
|
||||||
|
|
||||||
copyright (c) 2018 Kevin Ertel
|
copyright (c) 2018 Kevin Ertel
|
||||||
|
|
||||||
darktable is free software: you can redistribute it and/or modify
|
darktable is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
(at your option) any later version.
|
(at your option) any later version.
|
||||||
|
|
||||||
darktable is distributed in the hope that it will be useful,
|
darktable is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
GNU General Public License for more details.
|
GNU General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with darktable. If not, see <http://www.gnu.org/licenses/>.
|
along with darktable. If not, see <http://www.gnu.org/licenses/>.
|
||||||
]]
|
]]
|
||||||
|
|
||||||
--[[About this Plugin
|
--[[About this Plugin
|
||||||
This plugin adds the module 'HDRMerge' to darktable's lighttable view
|
This plugin adds the module 'HDRMerge' to darktable's lighttable view
|
||||||
|
|
||||||
----REQUIRED SOFTWARE----
|
----REQUIRED SOFTWARE----
|
||||||
HDRMerge ver. 4.5 or greater
|
HDRMerge ver. 4.5 or greater
|
||||||
|
|
||||||
----USAGE----
|
----USAGE----
|
||||||
Install: (see here for more detail: https://github.com/darktable-org/lua-scripts )
|
Install: (see here for more detail: https://github.com/darktable-org/lua-scripts )
|
||||||
1) Copy this file in to your 'lua/contrib' folder where all other scripts reside.
|
1) Copy this file in to your 'lua/contrib' folder where all other scripts reside.
|
||||||
2) Require this file in your luarc file, as with any other dt plug-in
|
2) Require this file in your luarc file, as with any other dt plug-in
|
||||||
On the initial startup go to darktable settings > lua options and set your executable paths and other preferences, then restart darktable
|
On the initial startup go to darktable settings > lua options and set your executable paths and other preferences, then restart darktable
|
||||||
|
|
||||||
Select bracketed images and press the Run HDRMerge button. The resulting DNG will be auto-imported into darktable.
|
Select bracketed images and press the Run HDRMerge button. The resulting DNG will be auto-imported into darktable.
|
||||||
Additional tags or style can be applied on auto import as well, if you desire.
|
Additional tags or style can be applied on auto import as well, if you desire.
|
||||||
|
|
||||||
Base Options:
|
Base Options:
|
||||||
Select your desired BPS (bits per sample and Embedded Preview Size.
|
Select your desired BPS (bits per sample and Embedded Preview Size.
|
||||||
|
|
||||||
Batch Options:
|
Batch Options:
|
||||||
Select if you want to run in batch mode or not
|
Select if you want to run in batch mode or not
|
||||||
Select the gap, in seconds, between images for auto grouping in batch mode
|
Select the gap, in seconds, between images for auto grouping in batch mode
|
||||||
|
|
||||||
See HDRMerge manual for further detail: http://jcelaya.github.io/hdrmerge/documentation/2014/07/11/user-manual.html
|
See HDRMerge manual for further detail: http://jcelaya.github.io/hdrmerge/documentation/2014/07/11/user-manual.html
|
||||||
|
|
||||||
Auto-import Options:
|
Auto-import Options:
|
||||||
Select a style, whether you want tags to be copied from the original, and any additional tags you desire added when the new image is auto-imported
|
Select a style, whether you want tags to be copied from the original, and any additional tags you desire added when the new image is auto-imported
|
||||||
]]
|
]]
|
||||||
|
|
||||||
local dt = require 'darktable'
|
local dt = require 'darktable'
|
||||||
local du = require "lib/dtutils"
|
local du = require "lib/dtutils"
|
||||||
local df = require 'lib/dtutils.file'
|
local df = require 'lib/dtutils.file'
|
||||||
local dsys = require 'lib/dtutils.system'
|
local dsys = require 'lib/dtutils.system'
|
||||||
|
|
||||||
du.check_min_api_version("7.0.0", "HDRmerge")
|
du.check_min_api_version("7.0.0", "HDRmerge")
|
||||||
|
|
||||||
-- return data structure for script_manager
|
-- Tell gettext where to find the .mo file translating messages for a particular domain
|
||||||
|
local gettext = dt.gettext.gettext
|
||||||
local script_data = {}
|
|
||||||
|
local function _(msgid)
|
||||||
script_data.destroy = nil -- function to destory the script
|
return gettext(msgid)
|
||||||
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet, otherwise leave as nil
|
end
|
||||||
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
|
|
||||||
|
-- return data structure for script_manager
|
||||||
|
|
||||||
local mod = 'module_HDRMerge'
|
local script_data = {}
|
||||||
local os_path_seperator = '/'
|
|
||||||
if dt.configuration.running_os == 'windows' then os_path_seperator = '\\' end
|
script_data.metadata = {
|
||||||
local CURR_API_STRING = dt.configuration.api_version_string
|
name = _("HDR merge"),
|
||||||
|
purpose = _("merge bracketed images into an HDR DNG image"),
|
||||||
-- Tell gettext where to find the .mo file translating messages for a particular domain
|
author = "Kevin Ertel",
|
||||||
local gettext = dt.gettext
|
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/HDRmerge"
|
||||||
gettext.bindtextdomain('HDRMerge', dt.configuration.config_dir..'/lua/locale/')
|
}
|
||||||
local function _(msgid)
|
|
||||||
return gettext.dgettext('HDRMerge', msgid)
|
script_data.destroy = nil -- function to destory the script
|
||||||
end
|
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 temp
|
script_data.show = nil -- only required for libs since the destroy_method only hides them
|
||||||
local HDRM = { --HDRMerge Program Table
|
|
||||||
name = 'HDRMerge',
|
|
||||||
bin = '',
|
local mod = 'module_HDRMerge'
|
||||||
first_run = true,
|
local os_path_seperator = '/'
|
||||||
install_error = false,
|
if dt.configuration.running_os == 'windows' then os_path_seperator = '\\' end
|
||||||
arg_string = '',
|
local CURR_API_STRING = dt.configuration.api_version_string
|
||||||
images_string = '',
|
|
||||||
args = {
|
local temp
|
||||||
bps = {text = '-b ', style = 'integer'},
|
local HDRM = { --HDRMerge Program Table
|
||||||
size = {text = '-p ', style = 'string'},
|
name = 'HDRMerge',
|
||||||
batch = {text = '-B ', style = 'bool'},
|
bin = '',
|
||||||
gap = {text = '-g ', style = 'integer'}
|
first_run = true,
|
||||||
}
|
install_error = false,
|
||||||
}
|
arg_string = '',
|
||||||
local GUI = { --GUI Elements Table
|
images_string = '',
|
||||||
HDR = {
|
args = {
|
||||||
bps ={},
|
bps = {text = '-b ', style = 'integer'},
|
||||||
size ={},
|
size = {text = '-p ', style = 'string'},
|
||||||
batch ={},
|
batch = {text = '-B ', style = 'bool'},
|
||||||
gap ={}
|
gap = {text = '-g ', style = 'integer'}
|
||||||
},
|
}
|
||||||
Target = {
|
}
|
||||||
style ={},
|
local GUI = { --GUI Elements Table
|
||||||
copy_tags ={},
|
HDR = {
|
||||||
add_tags ={}
|
bps ={},
|
||||||
},
|
size ={},
|
||||||
run = {},
|
batch ={},
|
||||||
stack = {},
|
gap ={}
|
||||||
options = {},
|
},
|
||||||
exes = {
|
Target = {
|
||||||
HDRMerge = {},
|
style ={},
|
||||||
update = {},
|
copy_tags ={},
|
||||||
}
|
add_tags ={}
|
||||||
}
|
},
|
||||||
|
run = {},
|
||||||
HDRM.module_installed = false
|
stack = {},
|
||||||
HDRM.event_registered = false
|
options = {},
|
||||||
|
exes = {
|
||||||
|
HDRMerge = {},
|
||||||
--Detect User Styles--
|
update = {},
|
||||||
local styles = dt.styles
|
}
|
||||||
local styles_count = 1 -- 'none' = 1
|
}
|
||||||
for _,i in pairs(dt.styles) do
|
|
||||||
if type(i) == 'userdata' then styles_count = styles_count + 1 end
|
HDRM.module_installed = false
|
||||||
end
|
HDRM.event_registered = false
|
||||||
|
|
||||||
local function InRange(test, low, high) --tests if test value is within range of low and high (inclusive)
|
|
||||||
if test >= low and test <= high then
|
--Detect User Styles--
|
||||||
return true
|
local styles = dt.styles
|
||||||
else
|
local styles_count = 1 -- 'none' = 1
|
||||||
return false
|
for _,i in pairs(dt.styles) do
|
||||||
end
|
if type(i) == 'userdata' then styles_count = styles_count + 1 end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function GetFileName(full_path) --Parses a full path (path/filename_identifier.extension) into individual parts
|
local function InRange(test, low, high) --tests if test value is within range of low and high (inclusive)
|
||||||
--[[Input: Folder1/Folder2/Folder3/Img_0001.CR2
|
if test >= low and test <= high then
|
||||||
|
return true
|
||||||
Returns:
|
else
|
||||||
path: Folder1/Folder2/Folder3/
|
return false
|
||||||
filename: Img_0001
|
end
|
||||||
identifier: 0001
|
end
|
||||||
extension: .CR2
|
|
||||||
|
local function GetFileName(full_path) --Parses a full path (path/filename_identifier.extension) into individual parts
|
||||||
EX:
|
--[[Input: Folder1/Folder2/Folder3/Img_0001.CR2
|
||||||
path_1, file_1, id_1, ext_1 = GetFileName(full_path_1)
|
|
||||||
]]
|
Returns:
|
||||||
local path = string.match(full_path, '.*[\\/]')
|
path: Folder1/Folder2/Folder3/
|
||||||
local filename = string.gsub(string.match(full_path, '[%w-_]*%.') , '%.' , '' )
|
filename: Img_0001
|
||||||
local identifier = string.match(filename, '%d*$')
|
identifier: 0001
|
||||||
local extension = string.match(full_path, '%.%w*')
|
extension: .CR2
|
||||||
return path, filename, identifier, extension
|
|
||||||
end
|
EX:
|
||||||
|
path_1, file_1, id_1, ext_1 = GetFileName(full_path_1)
|
||||||
local function CleanSpaces(text) --removes spaces from the front and back of passed in text
|
]]
|
||||||
text = string.gsub(text,'^%s*','')
|
local path = string.match(full_path, '.*[\\/]')
|
||||||
text = string.gsub(text,'%s*$','')
|
local filename = string.gsub(string.match(full_path, '[%w-_]*%.') , '%.' , '' )
|
||||||
return text
|
local identifier = string.match(filename, '%d*$')
|
||||||
end
|
local extension = string.match(full_path, '%.%w*')
|
||||||
|
return path, filename, identifier, extension
|
||||||
local function BuildExecuteCmd(prog_table) --creates a program command using elements of the passed in program table
|
end
|
||||||
local result = CleanSpaces(prog_table.bin)..' '..CleanSpaces(prog_table.arg_string)..' '..CleanSpaces(prog_table.images_string)
|
|
||||||
return result
|
local function CleanSpaces(text) --removes spaces from the front and back of passed in text
|
||||||
end
|
text = string.gsub(text,'^%s*','')
|
||||||
|
text = string.gsub(text,'%s*$','')
|
||||||
local function PreCall(prog_tbl) --looks to see if this is the first call, if so checks to see if program is installed properly
|
return text
|
||||||
for _,prog in pairs(prog_tbl) do
|
end
|
||||||
if prog.first_run then
|
|
||||||
prog.bin = df.check_if_bin_exists(prog.name)
|
local function BuildExecuteCmd(prog_table) --creates a program command using elements of the passed in program table
|
||||||
if not prog.bin then
|
local result = CleanSpaces(prog_table.bin)..' '..CleanSpaces(prog_table.arg_string)..' '..CleanSpaces(prog_table.images_string)
|
||||||
prog.install_error = true
|
return result
|
||||||
dt.preferences.write(mod, 'bin_exists', 'bool', false)
|
end
|
||||||
else
|
|
||||||
prog.bin = CleanSpaces(prog.bin)
|
local function PreCall(prog_tbl) --looks to see if this is the first call, if so checks to see if program is installed properly
|
||||||
end
|
for _,prog in pairs(prog_tbl) do
|
||||||
prog.first_run = false
|
if prog.first_run then
|
||||||
end
|
prog.bin = df.check_if_bin_exists(prog.name)
|
||||||
end
|
if not prog.bin then
|
||||||
if not dt.preferences.read(mod, 'bin_exists', 'bool') then
|
prog.install_error = true
|
||||||
GUI.stack.active = 2
|
dt.preferences.write(mod, 'bin_exists', 'bool', false)
|
||||||
dt.print(_('please update you binary location'))
|
else
|
||||||
end
|
prog.bin = CleanSpaces(prog.bin)
|
||||||
end
|
end
|
||||||
|
prog.first_run = false
|
||||||
local function ExeUpdate(prog_tbl)
|
end
|
||||||
dt.preferences.write(mod, 'bin_exists', 'bool', true)
|
end
|
||||||
for _,prog in pairs(prog_tbl) do
|
if not dt.preferences.read(mod, 'bin_exists', 'bool') then
|
||||||
dt.preferences.write('executable_paths', prog.name, 'string', GUI.exes[prog.name].value)
|
GUI.stack.active = 2
|
||||||
prog.bin = df.check_if_bin_exists(prog.name)
|
dt.print(_('please update you binary location'))
|
||||||
if not prog.bin then
|
end
|
||||||
prog.install_error = true
|
end
|
||||||
dt.preferences.write(mod, 'bin_exists', 'bool', false)
|
|
||||||
else
|
local function ExeUpdate(prog_tbl)
|
||||||
prog.bin = CleanSpaces(prog.bin)
|
dt.preferences.write(mod, 'bin_exists', 'bool', true)
|
||||||
end
|
for _,prog in pairs(prog_tbl) do
|
||||||
prog.first_run = false
|
dt.preferences.write('executable_paths', prog.name, 'string', GUI.exes[prog.name].value)
|
||||||
end
|
prog.bin = df.check_if_bin_exists(prog.name)
|
||||||
if dt.preferences.read(mod, 'bin_exists', 'bool') then
|
if not prog.bin then
|
||||||
GUI.stack.active = 1
|
prog.install_error = true
|
||||||
dt.print(_('update successful'))
|
dt.preferences.write(mod, 'bin_exists', 'bool', false)
|
||||||
else
|
else
|
||||||
dt.print(_('update unsuccessful, please try again'))
|
prog.bin = CleanSpaces(prog.bin)
|
||||||
end
|
end
|
||||||
end
|
prog.first_run = false
|
||||||
|
end
|
||||||
local function UpdateActivePreference() --sliders & entry boxes do not have a click/changed callback, so their values must be saved to the active preference
|
if dt.preferences.read(mod, 'bin_exists', 'bool') then
|
||||||
temp = GUI.HDR.gap.value
|
GUI.stack.active = 1
|
||||||
dt.preferences.write(mod, 'active_gap', 'integer', temp)
|
dt.print(_('update successful'))
|
||||||
temp = GUI.Target.add_tags.text
|
else
|
||||||
dt.preferences.write(mod, 'active_add_tags', 'string', temp)
|
dt.print(_('update unsuccessful, please try again'))
|
||||||
end
|
end
|
||||||
|
end
|
||||||
local function main()
|
|
||||||
PreCall({HDRM}) --check if furst run then check if install OK
|
local function UpdateActivePreference() --sliders & entry boxes do not have a click/changed callback, so their values must be saved to the active preference
|
||||||
if HDRM.install_error then
|
temp = GUI.HDR.gap.value
|
||||||
dt.print_error(_('HDRMerge install issue'))
|
dt.preferences.write(mod, 'active_gap', 'integer', temp)
|
||||||
dt.print(_('HDRMerge install issue, please ensure the binary path is proper'))
|
temp = GUI.Target.add_tags.text
|
||||||
return
|
dt.preferences.write(mod, 'active_add_tags', 'string', temp)
|
||||||
end
|
end
|
||||||
images = dt.gui.selection() --get selected images
|
|
||||||
if #images < 2 then --ensure enough images selected
|
local function main()
|
||||||
dt.print(_('not enough images selected, select at least 2 images to merge'))
|
PreCall({HDRM}) --check if furst run then check if install OK
|
||||||
return
|
if HDRM.install_error then
|
||||||
end
|
dt.print_error('HDRMerge install issue')
|
||||||
|
dt.print(_('HDRMerge install issue, please ensure the binary path is correct'))
|
||||||
UpdateActivePreference() --save current gui elements to active preference so those values will be pre-loaded at next startup
|
return
|
||||||
|
end
|
||||||
--create image string and output path
|
images = dt.gui.selection() --get selected images
|
||||||
HDRM.images_string = ''
|
if #images < 2 then --ensure enough images selected
|
||||||
local out_path = ''
|
dt.print(_('not enough images selected, select at least 2 images to merge'))
|
||||||
local smallest_id = math.huge
|
return
|
||||||
local smallest_name = ''
|
end
|
||||||
local largest_id = 0
|
|
||||||
local source_raw = {}
|
UpdateActivePreference() --save current gui elements to active preference so those values will be pre-loaded at next startup
|
||||||
for _,image in pairs(images) do --loop to concat the images string, also track the image indexes for use in creating the final image name (eg; IMG_1034-1037.dng)
|
|
||||||
local curr_image = image.path..os_path_seperator..image.filename
|
--create image string and output path
|
||||||
HDRM.images_string = HDRM.images_string..df.sanitize_filename(curr_image)..' '
|
HDRM.images_string = ''
|
||||||
out_path = image.path
|
local out_path = ''
|
||||||
_unused, source_name, source_id = GetFileName(image.filename)
|
local smallest_id = math.huge
|
||||||
source_id = tonumber(source_id) or 0
|
local smallest_name = ''
|
||||||
if source_id < smallest_id then
|
local largest_id = 0
|
||||||
smallest_id = source_id
|
local source_raw = {}
|
||||||
smallest_name = source_name
|
for _,image in pairs(images) do --loop to concat the images string, also track the image indexes for use in creating the final image name (eg; IMG_1034-1037.dng)
|
||||||
source_raw = image
|
local curr_image = image.path..os_path_seperator..image.filename
|
||||||
end
|
HDRM.images_string = HDRM.images_string..df.sanitize_filename(curr_image)..' '
|
||||||
if source_id > largest_id then largest_id = source_id end
|
out_path = image.path
|
||||||
end
|
_unused, source_name, source_id = GetFileName(image.filename)
|
||||||
out_path = out_path..os_path_seperator..smallest_name..'-'..largest_id..'.dng'
|
source_id = tonumber(source_id) or 0
|
||||||
out_path = df.create_unique_filename(out_path)
|
if source_id < smallest_id then
|
||||||
|
smallest_id = source_id
|
||||||
--create argument string
|
smallest_name = source_name
|
||||||
HDRM.arg_string = HDRM.args.bps.text..GUI.HDR.bps.value..' '..HDRM.args.size.text..GUI.HDR.size.value..' '
|
source_raw = image
|
||||||
if GUI.HDR.batch.value then
|
end
|
||||||
HDRM.arg_string = HDRM.arg_string..HDRM.args.batch.text..HDRM.args.gap.text..math.floor(GUI.HDR.gap.value)..' -a'
|
if source_id > largest_id then largest_id = source_id end
|
||||||
else
|
end
|
||||||
HDRM.arg_string = HDRM.arg_string..'-o '..df.sanitize_filename(out_path)
|
out_path = out_path..os_path_seperator..smallest_name..'-'..largest_id..'.dng'
|
||||||
end
|
out_path = df.create_unique_filename(out_path)
|
||||||
|
|
||||||
-- create run command and execute
|
--create argument string
|
||||||
local run_cmd = BuildExecuteCmd(HDRM)
|
HDRM.arg_string = HDRM.args.bps.text..GUI.HDR.bps.value..' '..HDRM.args.size.text..GUI.HDR.size.value..' '
|
||||||
resp = dsys.external_command(run_cmd)
|
if GUI.HDR.batch.value then
|
||||||
|
HDRM.arg_string = HDRM.arg_string..HDRM.args.batch.text..HDRM.args.gap.text..math.floor(GUI.HDR.gap.value)..' -a'
|
||||||
if resp == 0 and not GUI.HDR.batch.value then
|
else
|
||||||
local imported = dt.database.import(out_path) -- import the new file
|
HDRM.arg_string = HDRM.arg_string..'-o '..df.sanitize_filename(out_path)
|
||||||
if GUI.Target.style.selected > 1 then -- apply selected style
|
end
|
||||||
local set_style = styles[GUI.Target.style.selected - 1]
|
|
||||||
dt.styles.apply(set_style , imported)
|
-- create run command and execute
|
||||||
end
|
local run_cmd = BuildExecuteCmd(HDRM)
|
||||||
if GUI.Target.copy_tags.value then -- copy tags from the original file (ignore 'darktable' generated tags)
|
resp = dsys.external_command(run_cmd)
|
||||||
local all_tags = dt.tags.get_tags(source_raw)
|
|
||||||
for _,tag in pairs(all_tags) do
|
if resp == 0 and not GUI.HDR.batch.value then
|
||||||
if string.match(tag.name, 'darktable|') == nil then dt.tags.attach(tag, imported) end
|
local imported = dt.database.import(out_path) -- import the new file
|
||||||
end
|
if GUI.Target.style.selected > 1 then -- apply selected style
|
||||||
end
|
local set_style = styles[GUI.Target.style.selected - 1]
|
||||||
local set_tag = GUI.Target.add_tags.text
|
dt.styles.apply(set_style , imported)
|
||||||
if set_tag ~= nil then -- add additional user-specified tags
|
end
|
||||||
for tag in string.gmatch(set_tag, '[^,]+') do
|
if GUI.Target.copy_tags.value then -- copy tags from the original file (ignore 'darktable' generated tags)
|
||||||
tag = CleanSpaces(tag)
|
local all_tags = dt.tags.get_tags(source_raw)
|
||||||
tag = dt.tags.create(tag)
|
for _,tag in pairs(all_tags) do
|
||||||
dt.tags.attach(tag, imported)
|
if string.match(tag.name, 'darktable|') == nil then dt.tags.attach(tag, imported) end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
dt.print(_('HDRMerge completed successfully'))
|
local set_tag = GUI.Target.add_tags.text
|
||||||
else
|
if set_tag ~= nil then -- add additional user-specified tags
|
||||||
dt.print_error(_('HDRMerge failed'))
|
for tag in string.gmatch(set_tag, '[^,]+') do
|
||||||
dt.print(_('HDRMerge failed'))
|
tag = CleanSpaces(tag)
|
||||||
end
|
tag = dt.tags.create(tag)
|
||||||
|
dt.tags.attach(tag, imported)
|
||||||
end
|
end
|
||||||
|
end
|
||||||
local function install_module()
|
dt.print(_('HDRMerge completed successfully'))
|
||||||
if not HDRM.module_installed then
|
else
|
||||||
dt.register_lib( -- register HDRMerge module
|
dt.print_error('HDRMerge failed')
|
||||||
'HDRMerge_Lib', -- Module name
|
dt.print(_('HDRMerge failed'))
|
||||||
_('HDRMerge'), -- name
|
end
|
||||||
true, -- expandable
|
|
||||||
true, -- resetable
|
end
|
||||||
{[dt.gui.views.lighttable] = {'DT_UI_CONTAINER_PANEL_RIGHT_CENTER', 99}}, -- containers
|
|
||||||
dt.new_widget('box'){
|
local function install_module()
|
||||||
orientation = 'vertical',
|
if not HDRM.module_installed then
|
||||||
GUI.stack
|
dt.register_lib( -- register HDRMerge module
|
||||||
}
|
'HDRMerge_Lib', -- Module name
|
||||||
)
|
_('HDRMerge'), -- name
|
||||||
HDRM.module_installed = true
|
true, -- expandable
|
||||||
end
|
true, -- resetable
|
||||||
end
|
{[dt.gui.views.lighttable] = {'DT_UI_CONTAINER_PANEL_RIGHT_CENTER', 99}}, -- containers
|
||||||
|
dt.new_widget('box'){
|
||||||
local function destroy()
|
orientation = 'vertical',
|
||||||
dt.gui.libs["HDRMerge_Lib"].visible = false
|
GUI.stack
|
||||||
end
|
}
|
||||||
|
)
|
||||||
local function restart()
|
HDRM.module_installed = true
|
||||||
dt.gui.libs["HDRMerge_Lib"].visible = true
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- GUI Elements --
|
local function destroy()
|
||||||
local lbl_hdr = dt.new_widget('section_label'){
|
dt.gui.libs["HDRMerge_Lib"].visible = false
|
||||||
label = _('HDRMerge options')
|
end
|
||||||
}
|
|
||||||
temp = dt.preferences.read(mod, 'active_bps_ind', 'integer')
|
local function restart()
|
||||||
if not InRange(temp, 1, 3) then temp = 3 end
|
dt.gui.libs["HDRMerge_Lib"].visible = true
|
||||||
GUI.HDR.bps = dt.new_widget('combobox'){
|
end
|
||||||
label = _('bits per sample'),
|
|
||||||
tooltip =_('number of bits per sample in the output image'),
|
-- GUI Elements --
|
||||||
selected = temp,
|
local lbl_hdr = dt.new_widget('section_label'){
|
||||||
'16','24','32',
|
label = _('HDRMerge options')
|
||||||
changed_callback = function(self)
|
}
|
||||||
dt.preferences.write(mod, 'active_bps', 'integer', self.value)
|
temp = dt.preferences.read(mod, 'active_bps_ind', 'integer')
|
||||||
dt.preferences.write(mod, 'active_bps_ind', 'integer', self.selected)
|
if not InRange(temp, 1, 3) then temp = 3 end
|
||||||
end,
|
GUI.HDR.bps = dt.new_widget('combobox'){
|
||||||
reset_callback = function(self)
|
label = _('bits per sample'),
|
||||||
self.selected = 3
|
tooltip =_('number of bits per sample in the output image'),
|
||||||
dt.preferences.write(mod, 'active_bps', 'integer', self.value)
|
selected = temp,
|
||||||
dt.preferences.write(mod, 'active_bps_ind', 'integer', self.selected)
|
'16','24','32',
|
||||||
end
|
changed_callback = function(self)
|
||||||
}
|
dt.preferences.write(mod, 'active_bps', 'integer', self.value)
|
||||||
temp = dt.preferences.read(mod, 'active_size_ind', 'integer')
|
dt.preferences.write(mod, 'active_bps_ind', 'integer', self.selected)
|
||||||
if not InRange(temp, 1, 3) then temp = 2 end
|
end,
|
||||||
GUI.HDR.size = dt.new_widget('combobox'){
|
reset_callback = function(self)
|
||||||
label = _('embedded preview size'),
|
self.selected = 3
|
||||||
tooltip =_('size of the embedded preview in output image'),
|
dt.preferences.write(mod, 'active_bps', 'integer', self.value)
|
||||||
selected = temp,
|
dt.preferences.write(mod, 'active_bps_ind', 'integer', self.selected)
|
||||||
_('none'),_('half'),_('full'),
|
end
|
||||||
changed_callback = function(self)
|
}
|
||||||
dt.preferences.write(mod, 'active_size', 'string', self.value)
|
temp = dt.preferences.read(mod, 'active_size_ind', 'integer')
|
||||||
dt.preferences.write(mod, 'active_size_ind', 'integer', self.selected)
|
if not InRange(temp, 1, 3) then temp = 2 end
|
||||||
end,
|
GUI.HDR.size = dt.new_widget('combobox'){
|
||||||
reset_callback = function(self)
|
label = _('embedded preview size'),
|
||||||
self.selected = 2
|
tooltip =_('size of the embedded preview in output image'),
|
||||||
dt.preferences.write(mod, 'active_size', 'string', self.value)
|
selected = temp,
|
||||||
dt.preferences.write(mod, 'active_size_ind', 'integer', self.selected)
|
_('none'),_('half'),_('full'),
|
||||||
end
|
changed_callback = function(self)
|
||||||
}
|
dt.preferences.write(mod, 'active_size', 'string', self.value)
|
||||||
GUI.HDR.batch = dt.new_widget('check_button'){
|
dt.preferences.write(mod, 'active_size_ind', 'integer', self.selected)
|
||||||
label = _('batch mode'),
|
end,
|
||||||
value = dt.preferences.read(mod, 'active_batch', 'bool'),
|
reset_callback = function(self)
|
||||||
tooltip = _('enable batch mode operation \nNOTE: resultant files will NOT be auto-imported'),
|
self.selected = 2
|
||||||
clicked_callback = function(self)
|
dt.preferences.write(mod, 'active_size', 'string', self.value)
|
||||||
dt.preferences.write(mod, 'active_batch', 'bool', self.value)
|
dt.preferences.write(mod, 'active_size_ind', 'integer', self.selected)
|
||||||
GUI.HDR.gap.sensitive = self.value
|
end
|
||||||
end,
|
}
|
||||||
reset_callback = function(self) self.value = false end
|
GUI.HDR.batch = dt.new_widget('check_button'){
|
||||||
}
|
label = _('batch mode'),
|
||||||
temp = dt.preferences.read(mod, 'active_gap', 'integer')
|
value = dt.preferences.read(mod, 'active_batch', 'bool'),
|
||||||
if not InRange(temp, 1, 3600) then temp = 3 end
|
tooltip = _('enable batch mode operation \nNOTE: resultant files will NOT be auto-imported'),
|
||||||
GUI.HDR.gap = dt.new_widget('slider'){
|
clicked_callback = function(self)
|
||||||
label = _('batch gap [sec.]'),
|
dt.preferences.write(mod, 'active_batch', 'bool', self.value)
|
||||||
tooltip = _('gap, in seconds, between batch mode groups'),
|
GUI.HDR.gap.sensitive = self.value
|
||||||
soft_min = 1,
|
end,
|
||||||
soft_max = 30,
|
reset_callback = function(self) self.value = false end
|
||||||
hard_min = 1,
|
}
|
||||||
hard_max = 3600,
|
temp = dt.preferences.read(mod, 'active_gap', 'integer')
|
||||||
step = 1,
|
if not InRange(temp, 1, 3600) then temp = 3 end
|
||||||
digits = 0,
|
GUI.HDR.gap = dt.new_widget('slider'){
|
||||||
value = temp,
|
label = _('batch gap [sec.]'),
|
||||||
sensitive = GUI.HDR.batch.value,
|
tooltip = _('gap, in seconds, between batch mode groups'),
|
||||||
reset_callback = function(self)
|
soft_min = 1,
|
||||||
self.value = 3
|
soft_max = 30,
|
||||||
end
|
hard_min = 1,
|
||||||
}
|
hard_max = 3600,
|
||||||
local lbl_import = dt.new_widget('section_label'){
|
step = 1,
|
||||||
label = _('import options')
|
digits = 0,
|
||||||
}
|
value = temp,
|
||||||
GUI.Target.style = dt.new_widget('combobox'){
|
sensitive = GUI.HDR.batch.value,
|
||||||
label = _('apply style on import'),
|
reset_callback = function(self)
|
||||||
tooltip = _('Apply selected style on auto-import to newly created image'),
|
self.value = 3
|
||||||
selected = 1,
|
end
|
||||||
_('none'),
|
}
|
||||||
changed_callback = function(self)
|
local lbl_import = dt.new_widget('section_label'){
|
||||||
dt.preferences.write(mod, 'active_style', 'string', self.value)
|
label = _('import options')
|
||||||
dt.preferences.write(mod, 'active_style_ind', 'integer', self.selected)
|
}
|
||||||
end,
|
GUI.Target.style = dt.new_widget('combobox'){
|
||||||
reset_callback = function(self)
|
label = _('apply style on import'),
|
||||||
self.selected = 1
|
tooltip = _('apply selected style on auto-import to newly created image'),
|
||||||
dt.preferences.write(mod, 'active_style', 'string', self.value)
|
selected = 1,
|
||||||
dt.preferences.write(mod, 'active_style_ind', 'integer', self.selected)
|
_('none'),
|
||||||
end
|
changed_callback = function(self)
|
||||||
}
|
dt.preferences.write(mod, 'active_style', 'string', self.value)
|
||||||
for k=1, (styles_count-1) do
|
dt.preferences.write(mod, 'active_style_ind', 'integer', self.selected)
|
||||||
GUI.Target.style[k+1] = styles[k].name
|
end,
|
||||||
end
|
reset_callback = function(self)
|
||||||
temp = dt.preferences.read(mod, 'active_style_ind', 'integer')
|
self.selected = 1
|
||||||
if not InRange(temp, 1, styles_count) then temp = 1 end
|
dt.preferences.write(mod, 'active_style', 'string', self.value)
|
||||||
GUI.Target.style.selected = temp
|
dt.preferences.write(mod, 'active_style_ind', 'integer', self.selected)
|
||||||
GUI.Target.copy_tags = dt.new_widget('check_button'){
|
end
|
||||||
label = _('copy tags'),
|
}
|
||||||
value = dt.preferences.read(mod, 'active_copy_tags', 'bool'),
|
for k=1, (styles_count-1) do
|
||||||
tooltip = _('copy tags from first source image'),
|
GUI.Target.style[k+1] = styles[k].name
|
||||||
clicked_callback = function(self) dt.preferences.write(mod, 'active_copy_tags', 'bool', self.value) end,
|
end
|
||||||
reset_callback = function(self) self.value = true end
|
temp = dt.preferences.read(mod, 'active_style_ind', 'integer')
|
||||||
}
|
if not InRange(temp, 1, styles_count) then temp = 1 end
|
||||||
temp = dt.preferences.read(mod, 'active_add_tags', 'string')
|
GUI.Target.style.selected = temp
|
||||||
if temp == '' then temp = nil end
|
GUI.Target.copy_tags = dt.new_widget('check_button'){
|
||||||
GUI.Target.add_tags = dt.new_widget('entry'){
|
label = _('copy tags'),
|
||||||
tooltip = _('Additional tags to be added on import. Seperate with commas, all spaces will be removed'),
|
value = dt.preferences.read(mod, 'active_copy_tags', 'bool'),
|
||||||
text = temp,
|
tooltip = _('copy tags from first source image'),
|
||||||
placeholder = _('Enter tags, seperated by commas'),
|
clicked_callback = function(self) dt.preferences.write(mod, 'active_copy_tags', 'bool', self.value) end,
|
||||||
editable = true
|
reset_callback = function(self) self.value = true end
|
||||||
}
|
}
|
||||||
GUI.run = dt.new_widget('button'){
|
temp = dt.preferences.read(mod, 'active_add_tags', 'string')
|
||||||
label = _('merge'),
|
if temp == '' then temp = nil end
|
||||||
tooltip =_('run HDRMerge with the above specified settings'),
|
GUI.Target.add_tags = dt.new_widget('entry'){
|
||||||
clicked_callback = function() main() end
|
tooltip = _('additional tags to be added on import, separate with commas, all spaces will be removed'),
|
||||||
}
|
text = temp,
|
||||||
GUI.exes.HDRMerge = dt.new_widget('file_chooser_button'){
|
placeholder = _('enter tags, separated by commas'),
|
||||||
title = _('Select HDRmerge executable'),
|
editable = true
|
||||||
value = df.get_executable_path_preference(HDRM.name),
|
}
|
||||||
is_directory = false
|
GUI.run = dt.new_widget('button'){
|
||||||
}
|
label = _('merge'),
|
||||||
GUI.exes.update = dt.new_widget('button'){
|
tooltip =_('run HDRMerge with the above settings'),
|
||||||
label = _('update'),
|
clicked_callback = function() main() end
|
||||||
tooltip =_('update the binary path with current value'),
|
}
|
||||||
clicked_callback = function() ExeUpdate({HDRM}) end
|
GUI.exes.HDRMerge = dt.new_widget('file_chooser_button'){
|
||||||
}
|
title = _('select HDRmerge executable'),
|
||||||
GUI.options = dt.new_widget('box'){
|
value = df.get_executable_path_preference(HDRM.name),
|
||||||
orientation = 'vertical',
|
is_directory = false
|
||||||
lbl_hdr,
|
}
|
||||||
GUI.HDR.bps,
|
GUI.exes.update = dt.new_widget('button'){
|
||||||
GUI.HDR.size,
|
label = _('update'),
|
||||||
GUI.HDR.batch,
|
tooltip =_('update the binary path with current value'),
|
||||||
GUI.HDR.gap,
|
clicked_callback = function() ExeUpdate({HDRM}) end
|
||||||
lbl_import,
|
}
|
||||||
GUI.Target.style,
|
GUI.options = dt.new_widget('box'){
|
||||||
GUI.Target.copy_tags,
|
orientation = 'vertical',
|
||||||
GUI.Target.add_tags,
|
lbl_hdr,
|
||||||
GUI.run
|
GUI.HDR.bps,
|
||||||
}
|
GUI.HDR.size,
|
||||||
local exes_box = dt.new_widget('box'){
|
GUI.HDR.batch,
|
||||||
orientation = 'vertical',
|
GUI.HDR.gap,
|
||||||
GUI.exes.HDRMerge,
|
lbl_import,
|
||||||
GUI.exes.update
|
GUI.Target.style,
|
||||||
}
|
GUI.Target.copy_tags,
|
||||||
GUI.stack = dt.new_widget('stack'){
|
GUI.Target.add_tags,
|
||||||
GUI.options,
|
GUI.run
|
||||||
exes_box
|
}
|
||||||
}
|
local exes_box = dt.new_widget('box'){
|
||||||
if dt.preferences.read(mod, 'bin_exists', 'bool') then
|
orientation = 'vertical',
|
||||||
GUI.stack.active = 1
|
GUI.exes.HDRMerge,
|
||||||
else
|
GUI.exes.update
|
||||||
GUI.stack.active = 2
|
}
|
||||||
end
|
GUI.stack = dt.new_widget('stack'){
|
||||||
|
GUI.options,
|
||||||
if dt.gui.current_view().id == "lighttable" then
|
exes_box
|
||||||
install_module()
|
}
|
||||||
else
|
if dt.preferences.read(mod, 'bin_exists', 'bool') then
|
||||||
if not HDRM.event_registered then
|
GUI.stack.active = 1
|
||||||
dt.register_event(
|
else
|
||||||
"HDRmerge", "view-changed",
|
GUI.stack.active = 2
|
||||||
function(event, old_view, new_view)
|
end
|
||||||
if new_view.name == "lighttable" and old_view.name == "darkroom" then
|
|
||||||
install_module()
|
if dt.gui.current_view().id == "lighttable" then
|
||||||
end
|
install_module()
|
||||||
end
|
else
|
||||||
)
|
if not HDRM.event_registered then
|
||||||
HDRM.event_registered = true
|
dt.register_event(
|
||||||
end
|
"HDRmerge", "view-changed",
|
||||||
end
|
function(event, old_view, new_view)
|
||||||
|
if new_view.name == "lighttable" and old_view.name == "darkroom" then
|
||||||
script_data.destroy = destroy
|
install_module()
|
||||||
script_data.restart = restart
|
end
|
||||||
script_data.destroy_method = "hide"
|
end
|
||||||
script_data.show = restart
|
)
|
||||||
|
HDRM.event_registered = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
script_data.destroy = destroy
|
||||||
|
script_data.restart = restart
|
||||||
|
script_data.destroy_method = "hide"
|
||||||
|
script_data.show = restart
|
||||||
|
|
||||||
return script_data
|
return script_data
|
||||||
@@ -52,13 +52,27 @@ local du = require "lib/dtutils"
|
|||||||
|
|
||||||
du.check_min_api_version("7.0.0", "LabelsToTags")
|
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
|
-- return data structure for script_manager
|
||||||
|
|
||||||
local script_data = {}
|
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 = 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.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.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"
|
-- Lua 5.3 no longer has "unpack" but "table.unpack"
|
||||||
unpack = unpack or table.unpack
|
unpack = unpack or table.unpack
|
||||||
@@ -67,7 +81,7 @@ local ltt = {}
|
|||||||
ltt.module_installed = false
|
ltt.module_installed = false
|
||||||
ltt.event_registered = false
|
ltt.event_registered = false
|
||||||
|
|
||||||
local LIB_ID = "LabelsToTags"
|
local LIB_ID = _("LabelsToTags")
|
||||||
|
|
||||||
-- Helper functions: BEGIN
|
-- Helper functions: BEGIN
|
||||||
|
|
||||||
@@ -108,23 +122,23 @@ end
|
|||||||
|
|
||||||
|
|
||||||
local initialAvailableMappings = {
|
local initialAvailableMappings = {
|
||||||
["Colors"] = { ["+*****"] = { "Red" },
|
[_("colors")] = { ["+*****"] = { _("red") },
|
||||||
["*+****"] = { "Yellow" },
|
["*+****"] = { _("yellow") },
|
||||||
["**+***"] = { "Green" },
|
["**+***"] = { _("green") },
|
||||||
["***+**"] = { "Blue" },
|
["***+**"] = { _("blue") },
|
||||||
["****+*"] = { "Purple" } },
|
["****+*"] = { _("purple") } },
|
||||||
["Single colors"] = { ["+----*"] = { "Red", "Only red" },
|
[_("single colors")] = { ["+----*"] = { _("red"), _("only red") },
|
||||||
["-+---*"] = { "Yellow", "Only yellow" },
|
["-+---*"] = { _("yellow"), _("only yellow") },
|
||||||
["--+--*"] = { "Green", "Only green" },
|
["--+--*"] = { _("green"), _("only green") },
|
||||||
["---+-*"] = { "Blue", "Only blue" },
|
["---+-*"] = { _("blue"), _("only blue") },
|
||||||
["----+*"] = { "Purple", "Only purple" } },
|
["----+*"] = { _("purple"), _("only purple") } },
|
||||||
["Ratings"] = { ["*****0"] = { "No stars", "Not rejected" },
|
[_("ratings")] = { ["*****0"] = { _("no stars"), _("not rejected") },
|
||||||
["*****1"] = { "One star", "Not rejected" },
|
["*****1"] = { _("one star"), _("not rejected") },
|
||||||
["*****2"] = { "Two stars", "Not rejected" },
|
["*****2"] = { _("two stars"), _("not rejected") },
|
||||||
["*****3"] = { "Three stars", "Not rejected" },
|
["*****3"] = { _("three stars"), _("not rejected") },
|
||||||
["*****4"] = { "Four stars", "Not rejected" },
|
["*****4"] = { _("four stars"), _("not rejected") },
|
||||||
["*****5"] = { "Five stars", "Not rejected" },
|
["*****5"] = { _("five stars"), _("not rejected") },
|
||||||
["*****R"] = { "Rejected" } }
|
["*****R"] = { _("rejected") } }
|
||||||
}
|
}
|
||||||
|
|
||||||
local availableMappings = {}
|
local availableMappings = {}
|
||||||
@@ -139,14 +153,14 @@ end
|
|||||||
|
|
||||||
local function getComboboxTooltip()
|
local function getComboboxTooltip()
|
||||||
if availableMappings == nil or next(availableMappings) == nil then
|
if availableMappings == nil or next(availableMappings) == nil then
|
||||||
return("No registered mappings -- using defaults")
|
return(_("no registered mappings -- using defaults"))
|
||||||
else
|
else
|
||||||
return("Select a label-to-tag mapping")
|
return(_("select a label-to-tag mapping"))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local mappingComboBox = darktable.new_widget("combobox"){
|
local mappingComboBox = darktable.new_widget("combobox"){
|
||||||
label = "mapping",
|
label = _("mapping"),
|
||||||
value = 1,
|
value = 1,
|
||||||
tooltip = getComboboxTooltip(),
|
tooltip = getComboboxTooltip(),
|
||||||
reset_callback = function(selfC)
|
reset_callback = function(selfC)
|
||||||
@@ -169,7 +183,7 @@ local mappingComboBox = darktable.new_widget("combobox"){
|
|||||||
}
|
}
|
||||||
|
|
||||||
local function doTagging(selfC)
|
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
|
job.percent = 0.0
|
||||||
local pctIncrement = 1.0 / #(darktable.gui.action_images)
|
local pctIncrement = 1.0 / #(darktable.gui.action_images)
|
||||||
|
|
||||||
@@ -200,8 +214,8 @@ ltt.my_widget = darktable.new_widget("box") {
|
|||||||
orientation = "vertical",
|
orientation = "vertical",
|
||||||
mappingComboBox,
|
mappingComboBox,
|
||||||
darktable.new_widget("button") {
|
darktable.new_widget("button") {
|
||||||
label = "start",
|
label = _("start"),
|
||||||
tooltip = "Tag all selected images",
|
tooltip = _("tag all selected images"),
|
||||||
clicked_callback = doTagging
|
clicked_callback = doTagging
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -231,7 +245,7 @@ end
|
|||||||
|
|
||||||
local function install_module()
|
local function install_module()
|
||||||
if not ltt.module_installed then
|
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},
|
[darktable.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER",20},
|
||||||
},ltt.my_widget,nil,nil)
|
},ltt.my_widget,nil,nil)
|
||||||
ltt.module_installed = true
|
ltt.module_installed = true
|
||||||
|
|||||||
@@ -1,237 +1,261 @@
|
|||||||
--[[
|
--[[
|
||||||
OpenInExplorer plugin for darktable
|
OpenInExplorer plugin for darktable
|
||||||
|
|
||||||
copyright (c) 2018 Kevin Ertel
|
copyright (c) 2018 Kevin Ertel
|
||||||
Update 2020 and macOS support by Volker Lenhardt
|
Update 2020 and macOS support by Volker Lenhardt
|
||||||
Linux support 2020 by Bill Ferguson
|
Linux support 2020 by Bill Ferguson
|
||||||
|
|
||||||
darktable is free software: you can redistribute it and/or modify
|
darktable is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
(at your option) any later version.
|
(at your option) any later version.
|
||||||
|
|
||||||
darktable is distributed in the hope that it will be useful,
|
darktable is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
GNU General Public License for more details.
|
GNU General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with darktable. If not, see <http://www.gnu.org/licenses/>.
|
along with darktable. If not, see <http://www.gnu.org/licenses/>.
|
||||||
]]
|
]]
|
||||||
|
|
||||||
--[[About this plugin
|
--[[About this plugin
|
||||||
This plugin adds the module "OpenInExplorer" to darktable's lighttable view.
|
This plugin adds the module "OpenInExplorer" to darktable's lighttable view.
|
||||||
|
|
||||||
----REQUIRED SOFTWARE----
|
----REQUIRED SOFTWARE----
|
||||||
Apple macOS, Microsoft Windows or Linux
|
Apple macOS, Microsoft Windows or Linux
|
||||||
|
|
||||||
----USAGE----
|
----USAGE----
|
||||||
Install: (see here for more detail: https://github.com/darktable-org/lua-scripts )
|
Install: (see here for more detail: https://github.com/darktable-org/lua-scripts )
|
||||||
1) Copy this file into your "lua/contrib" folder where all other scripts reside.
|
1) Copy this file into your "lua/contrib" folder where all other scripts reside.
|
||||||
2) Require this file in your luarc file, as with any other dt plug-in
|
2) Require this file in your luarc file, as with any other dt plug-in
|
||||||
|
|
||||||
Select the photo(s) you wish to find in your operating system's file manager and press "show in file explorer" in the "selected images" section.
|
Select the photo(s) you wish to find in your operating system's file manager and press "show in file explorer" in the "selected images" section.
|
||||||
|
|
||||||
- Nautilus (Linux), Explorer (Windows), and Finder (macOS prior to Mojave) will open one window for each selected image at the file's location. The file name will be highlighted.
|
- Nautilus (Linux), Explorer (Windows), and Finder (macOS prior to Mojave) will open one window for each selected image at the file's location. The file name will be highlighted.
|
||||||
|
|
||||||
- On macOS Mojave and Catalina the Finder will open one window for each different directory. In these windows only the last one of the corresponding files will be highlighted (bug or feature?).
|
- On macOS Mojave and Catalina the Finder will open one window for each different directory. In these windows only the last one of the corresponding files will be highlighted (bug or feature?).
|
||||||
|
|
||||||
- Dolphin (Linux) will open one window with tabs for the different directories. All the selected images' file names are highlighted in their respective directories.
|
- Dolphin (Linux) will open one window with tabs for the different directories. All the selected images' file names are highlighted in their respective directories.
|
||||||
|
|
||||||
As an alternative option you can choose to show the image file names as symbolic links in an arbitrary directory. Go to preferences|Lua options. This option is not available for Windows users as on Windows solely admins are allowed to create links.
|
As an alternative option you can choose to show the image file names as symbolic links in an arbitrary directory. Go to preferences|Lua options. This option is not available for Windows users as on Windows solely admins are allowed to create links.
|
||||||
|
|
||||||
- Pros: You do not clutter up your display with multiple windows. So there is no need to limit the number of selections.
|
- Pros: You do not clutter up your display with multiple windows. So there is no need to limit the number of selections.
|
||||||
|
|
||||||
- Cons: If you want to work with the files you are one step behind the original data.
|
- Cons: If you want to work with the files you are one step behind the original data.
|
||||||
|
|
||||||
----KNOWN ISSUES----
|
----KNOWN ISSUES----
|
||||||
]]
|
]]
|
||||||
|
|
||||||
local dt = require "darktable"
|
local dt = require "darktable"
|
||||||
local du = require "lib/dtutils"
|
local du = require "lib/dtutils"
|
||||||
local df = require "lib/dtutils.file"
|
local df = require "lib/dtutils.file"
|
||||||
local dsys = require "lib/dtutils.system"
|
local dsys = require "lib/dtutils.system"
|
||||||
local gettext = dt.gettext
|
local gettext = dt.gettext.gettext
|
||||||
|
|
||||||
--Check API version
|
--Check API version
|
||||||
du.check_min_api_version("7.0.0", "OpenInExplorer")
|
du.check_min_api_version("7.0.0", "OpenInExplorer")
|
||||||
|
|
||||||
-- return data structure for script_manager
|
local function _(msgid)
|
||||||
|
return gettext(msgid)
|
||||||
local script_data = {}
|
end
|
||||||
|
|
||||||
script_data.destroy = nil -- function to destory the script
|
-- return data structure for script_manager
|
||||||
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 script_data = {}
|
||||||
|
|
||||||
-- Tell gettext where to find the .mo file translating messages for a particular domain
|
script_data.metadata = {
|
||||||
gettext.bindtextdomain("OpenInExplorer",dt.configuration.config_dir.."/lua/locale/")
|
name = _("open in explorer"),
|
||||||
|
purpose = _("open a selected file in the system file manager"),
|
||||||
local function _(msgid)
|
author = "Kevin Ertel",
|
||||||
return gettext.dgettext("OpenInExplorer", msgid)
|
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/OpenInExplorer"
|
||||||
end
|
}
|
||||||
|
|
||||||
local act_os = dt.configuration.running_os
|
script_data.destroy = nil -- function to destory the script
|
||||||
local PS = act_os == "windows" and "\\" or "/"
|
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
|
||||||
--Detect OS and quit if it is not supported.
|
script_data.show = nil -- only required for libs since the destroy_method only hides them
|
||||||
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"))
|
local act_os = dt.configuration.running_os
|
||||||
dt.print_error("OpenInExplorer plug-in only supports Linux, macOS, and Windows at this time")
|
local PS = act_os == "windows" and "\\" or "/"
|
||||||
return
|
|
||||||
end
|
--Detect OS and quit if it is not supported.
|
||||||
|
if act_os ~= "macos" and act_os ~= "windows" and act_os ~= "linux" then
|
||||||
local use_links, links_dir = false, ""
|
dt.print(_("OpenInExplorer plug-in only supports linux, macos, and windows at this time"))
|
||||||
if act_os ~= "windows" then
|
dt.print_error("OpenInExplorer plug-in only supports Linux, macOS, and Windows at this time")
|
||||||
use_links = dt.preferences.read("OpenInExplorer", "use_links", "bool")
|
return
|
||||||
links_dir = dt.preferences.read("OpenInExplorer", "linked_image_files_dir", "string")
|
end
|
||||||
end
|
|
||||||
|
local use_links, links_dir = false, ""
|
||||||
--Check if the directory exists that was chosen for the file links. Return boolean.
|
if act_os ~= "windows" then
|
||||||
local function check_if_links_dir_exists()
|
use_links = dt.preferences.read("OpenInExplorer", "use_links", "bool")
|
||||||
local dir_exists = true
|
links_dir = dt.preferences.read("OpenInExplorer", "linked_image_files_dir", "string")
|
||||||
if not links_dir then
|
end
|
||||||
--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)"))
|
--Check if the directory exists that was chosen for the file links. Return boolean.
|
||||||
dt.print_error("OpenInExplorer: No links directory selected")
|
local function check_if_links_dir_exists()
|
||||||
dir_exists = false
|
local dir_exists = true
|
||||||
elseif not df.check_if_file_exists(links_dir) then
|
if not links_dir then
|
||||||
dt.print(string.format(_("Links directory '%s' not found.\nPlease check the dt preferences (lua options)"), links_dir))
|
--Just for paranoic reasons. I tried, but I couldn't devise a setting for a nil value.
|
||||||
dt.print_error(string.format("OpenInExplorer: Links directory '%s' not found", links_dir))
|
dt.print(_("no links directory selected\nplease check the dt preferences (lua options)"))
|
||||||
dir_exists = false
|
dt.print_error("OpenInExplorer: No links directory selected")
|
||||||
end
|
dir_exists = false
|
||||||
return dir_exists
|
elseif not df.check_if_file_exists(links_dir) then
|
||||||
end
|
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))
|
||||||
--Format strings for the commands to open the corresponding OS's file manager.
|
dir_exists = false
|
||||||
local open_dir = {}
|
end
|
||||||
open_dir.windows = "explorer.exe /n, %s"
|
return dir_exists
|
||||||
open_dir.macos = "open %s"
|
end
|
||||||
open_dir.linux = [[busctl --user call org.freedesktop.FileManager1 /org/freedesktop/FileManager1 org.freedesktop.FileManager1 ShowFolders ass 1 %s ""]]
|
|
||||||
|
--Format strings for the commands to open the corresponding OS's file manager.
|
||||||
local open_files = {}
|
local open_dir = {}
|
||||||
open_files.windows = "explorer.exe /select, %s"
|
open_dir.windows = "explorer.exe /n, %s"
|
||||||
open_files.macos = "open -Rn %s"
|
open_dir.macos = "open %s"
|
||||||
open_files.linux = [[busctl --user call org.freedesktop.FileManager1 /org/freedesktop/FileManager1 org.freedesktop.FileManager1 ShowItems ass %d %s ""]]
|
open_dir.linux = [[busctl --user call org.freedesktop.FileManager1 /org/freedesktop/FileManager1 org.freedesktop.FileManager1 ShowFolders ass 1 %s ""]]
|
||||||
|
|
||||||
--Call the file mangager for each selected image on Linux.
|
local open_files = {}
|
||||||
--There is one call to busctl containing a list of all the image file names.
|
open_files.windows = "explorer.exe /select, %s"
|
||||||
local function call_list_of_files(selected_images)
|
open_files.macos = "osascript -e 'tell application \"Finder\" to (reveal {%s}) activate'"
|
||||||
local current_image, file_uris, run_cmd = "", "", ""
|
open_files.linux = [[busctl --user call org.freedesktop.FileManager1 /org/freedesktop/FileManager1 org.freedesktop.FileManager1 ShowItems ass %d %s ""]]
|
||||||
for _, image in pairs(selected_images) do
|
|
||||||
current_image = image.path..PS..image.filename
|
reveal_file_osx_cmd = "\"%s\" as POSIX file"
|
||||||
file_uris = file_uris .. df.sanitize_filename("file://" .. current_image) .. " "
|
|
||||||
dt.print_log("file_uris is " .. file_uris)
|
--Call the osx Finder with each selected image selected.
|
||||||
end
|
--For images in multiple folders, Finder will open a separate window for each
|
||||||
run_cmd = string.format(open_files.linux, #selected_images, file_uris)
|
local function call_list_of_files_osx(selected_images)
|
||||||
dt.print_log("OpenInExplorer run_cmd = "..run_cmd)
|
local cmds = {}
|
||||||
dsys.external_command(run_cmd)
|
for _, image in pairs(selected_images) do
|
||||||
end
|
current_image = image.path..PS..image.filename
|
||||||
|
-- AppleScript needs double quoted strings, and the whole command is wrapped in single quotes.
|
||||||
--Call the file manager for each selected image on Windows and macOS.
|
table.insert(cmds, string.format(reveal_file_osx_cmd, string.gsub(string.gsub(current_image, "\"", "\\\""), "'", "'\"'\"'")))
|
||||||
local function call_file_by_file(selected_images)
|
end
|
||||||
local current_image, run_cmd = "", ""
|
reveal_cmd = table.concat(cmds, ",")
|
||||||
for _, image in pairs(selected_images) do
|
run_cmd = string.format(open_files.macos, reveal_cmd)
|
||||||
current_image = image.path..PS..image.filename
|
dt.print_log("OSX run_cmd = "..run_cmd)
|
||||||
run_cmd = string.format(open_files[act_os], df.sanitize_filename(current_image))
|
dsys.external_command(run_cmd)
|
||||||
dt.print_log("OpenInExplorer run_cmd = "..run_cmd)
|
end
|
||||||
dsys.external_command(run_cmd)
|
|
||||||
end
|
--Call the file mangager for each selected image on Linux.
|
||||||
end
|
--There is one call to busctl containing a list of all the image file names.
|
||||||
|
local function call_list_of_files(selected_images)
|
||||||
--Create a link for each selected image, and finally call the file manager.
|
local current_image, file_uris, run_cmd = "", "", ""
|
||||||
local function set_links(selected_images)
|
for _, image in pairs(selected_images) do
|
||||||
local current_image, link_target, run_cmd, k = "", "", "", nil
|
current_image = image.path..PS..image.filename
|
||||||
for k, image in pairs(selected_images) do
|
file_uris = file_uris .. df.sanitize_filename("file://" .. current_image) .. " "
|
||||||
current_image = image.path..PS..image.filename
|
dt.print_log("file_uris is " .. file_uris)
|
||||||
link_target = df.create_unique_filename(links_dir .. PS .. image.filename)
|
end
|
||||||
run_cmd = string.format("ln -s %s %s", df.sanitize_filename(current_image), df.sanitize_filename(link_target))
|
run_cmd = string.format(open_files.linux, #selected_images, file_uris)
|
||||||
--[[
|
dt.print_log("OpenInExplorer run_cmd = "..run_cmd)
|
||||||
In case Windows will allow normal users to create soft links:
|
dsys.external_command(run_cmd)
|
||||||
if act_os == "windows" then
|
end
|
||||||
run_cmd = string.format("mklink %s %s", df.sanitize_filename(link_target), df.sanitize_filename(current_image))
|
|
||||||
end
|
--Call the file manager for each selected image on Windows and macOS.
|
||||||
]]
|
local function call_file_by_file(selected_images)
|
||||||
if dsys.external_command(run_cmd) ~= 0 then
|
local current_image, run_cmd = "", ""
|
||||||
dt.print(_("Failed to create links. Missing rights?"))
|
for _, image in pairs(selected_images) do
|
||||||
dt.print_error("OpenInExplorer: Failed to create links")
|
current_image = image.path..PS..image.filename
|
||||||
return
|
run_cmd = string.format(open_files[act_os], df.sanitize_filename(current_image))
|
||||||
end
|
dt.print_log("OpenInExplorer run_cmd = "..run_cmd)
|
||||||
end
|
dsys.external_command(run_cmd)
|
||||||
--The URI format is necessary only for the Linux busctl command.
|
end
|
||||||
--But it is accepted by the Windows Explorer and macOS's Finder all the same.
|
end
|
||||||
run_cmd = string.format(open_dir[act_os], df.sanitize_filename("file://"..links_dir))
|
|
||||||
dt.print_log("OpenInExplorer run_cmd = "..run_cmd)
|
--Create a link for each selected image, and finally call the file manager.
|
||||||
dsys.external_command(run_cmd)
|
local function set_links(selected_images)
|
||||||
end
|
local current_image, link_target, run_cmd, k = "", "", "", nil
|
||||||
|
for k, image in pairs(selected_images) do
|
||||||
--The working function that starts the particular task.
|
current_image = image.path..PS..image.filename
|
||||||
local function open_in_fmanager()
|
link_target = df.create_unique_filename(links_dir .. PS .. image.filename)
|
||||||
local images = dt.gui.selection()
|
run_cmd = string.format("ln -s %s %s", df.sanitize_filename(current_image), df.sanitize_filename(link_target))
|
||||||
if #images == 0 then
|
--[[
|
||||||
dt.print(_("Please select an image"))
|
In case Windows will allow normal users to create soft links:
|
||||||
else
|
if act_os == "windows" then
|
||||||
if use_links and not check_if_links_dir_exists() then
|
run_cmd = string.format("mklink %s %s", df.sanitize_filename(link_target), df.sanitize_filename(current_image))
|
||||||
return
|
end
|
||||||
end
|
]]
|
||||||
if #images > 15 and not use_links then
|
if dsys.external_command(run_cmd) ~= 0 then
|
||||||
dt.print(_("Please select fewer images (max. 15)"))
|
dt.print(_("failed to create links, missing rights?"))
|
||||||
elseif use_links then
|
dt.print_error("OpenInExplorer: Failed to create links")
|
||||||
set_links(images)
|
return
|
||||||
else
|
end
|
||||||
if act_os == "linux" then
|
end
|
||||||
call_list_of_files(images)
|
--The URI format is necessary only for the Linux busctl command.
|
||||||
else
|
--But it is accepted by the Windows Explorer and macOS's Finder all the same.
|
||||||
call_file_by_file(images)
|
run_cmd = string.format(open_dir[act_os], df.sanitize_filename("file://"..links_dir))
|
||||||
end
|
dt.print_log("OpenInExplorer run_cmd = "..run_cmd)
|
||||||
end
|
dsys.external_command(run_cmd)
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
--The working function that starts the particular task.
|
||||||
local function destroy()
|
local function open_in_fmanager()
|
||||||
dt.gui.libs.image.destroy_action("OpenInExplorer")
|
local images = dt.gui.selection()
|
||||||
dt.destroy_event("OpenInExplorer", "shortcut")
|
if #images == 0 then
|
||||||
if act_os ~= "windows" then
|
dt.print(_("please select an image"))
|
||||||
dt.preferences.destroy("OpenInExplorer", "linked_image_files_dir")
|
else
|
||||||
end
|
if use_links and not check_if_links_dir_exists() then
|
||||||
dt.preferences.destroy("OpenInExplorer", "use_links")
|
return
|
||||||
end
|
end
|
||||||
|
if #images > 15 and not use_links then
|
||||||
|
dt.print(_("please select fewer images (max. 15)"))
|
||||||
-- GUI --
|
elseif use_links then
|
||||||
dt.gui.libs.image.register_action(
|
set_links(images)
|
||||||
"OpenInExplorer", _("show in file explorer"),
|
else
|
||||||
function() open_in_fmanager() end,
|
if act_os == "linux" then
|
||||||
_("Open the file manager at the selected image's location")
|
call_list_of_files(images)
|
||||||
)
|
elseif act_os == "macos" then
|
||||||
|
call_list_of_files_osx(images)
|
||||||
|
else
|
||||||
if act_os ~= "windows" then
|
call_file_by_file(images)
|
||||||
dt.preferences.register("OpenInExplorer", "linked_image_files_dir", -- name
|
end
|
||||||
"directory", -- type
|
end
|
||||||
_("OpenInExplorer: linked files directory"), -- label
|
end
|
||||||
_("Directory to store the links to the file names. Requires restart to take effect"), -- tooltip
|
end
|
||||||
"Links to image files", -- default
|
|
||||||
dt.new_widget("file_chooser_button"){
|
local function destroy()
|
||||||
title = _("Select directory"),
|
dt.gui.libs.image.destroy_action("OpenInExplorer")
|
||||||
is_directory = true,
|
dt.destroy_event("OpenInExplorer", "shortcut")
|
||||||
}
|
if act_os ~= "windows" then
|
||||||
)
|
dt.preferences.destroy("OpenInExplorer", "linked_image_files_dir")
|
||||||
dt.preferences.register("OpenInExplorer", "use_links", -- name
|
end
|
||||||
"bool", -- type
|
dt.preferences.destroy("OpenInExplorer", "use_links")
|
||||||
_("OpenInExplorer: use links"), -- label
|
end
|
||||||
_("Use links instead of multiple windows. Requires restart to take effect"), -- tooltip
|
|
||||||
false, -- default
|
|
||||||
""
|
-- GUI --
|
||||||
)
|
dt.gui.libs.image.register_action(
|
||||||
end
|
"OpenInExplorer", _("show in file explorer"),
|
||||||
|
function() open_in_fmanager() end,
|
||||||
dt.register_event(
|
_("open the file manager at the selected image's location")
|
||||||
"OpenInExplorer", "shortcut",
|
)
|
||||||
function(event, shortcut) open_in_fmanager() end,
|
|
||||||
"OpenInExplorer"
|
|
||||||
)
|
if act_os ~= "windows" then
|
||||||
|
dt.preferences.register("OpenInExplorer", "linked_image_files_dir", -- name
|
||||||
script_data.destroy = destroy
|
"directory", -- type
|
||||||
|
_("OpenInExplorer: linked files directory"), -- label
|
||||||
return script_data
|
_("directory to store the links to the file names, requires restart to take effect"), -- tooltip
|
||||||
|
"Links to image files", -- default
|
||||||
|
dt.new_widget("file_chooser_button"){
|
||||||
|
title = _("select directory"),
|
||||||
|
is_directory = true,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
dt.preferences.register("OpenInExplorer", "use_links", -- name
|
||||||
|
"bool", -- type
|
||||||
|
_("OpenInExplorer: use links"), -- label
|
||||||
|
_("use links instead of multiple windows, requires restart to take effect"), -- tooltip
|
||||||
|
false, -- default
|
||||||
|
""
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
dt.register_event(
|
||||||
|
"OpenInExplorer", "shortcut",
|
||||||
|
function(event, shortcut) open_in_fmanager() end,
|
||||||
|
"OpenInExplorer"
|
||||||
|
)
|
||||||
|
|
||||||
|
script_data.destroy = destroy
|
||||||
|
|
||||||
|
return script_data
|
||||||
|
|||||||
@@ -65,31 +65,50 @@ local MODULE_NAME = "RL_out_sharp"
|
|||||||
-- check API version
|
-- check API version
|
||||||
du.check_min_api_version("7.0.0", MODULE_NAME)
|
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
|
-- return data structure for script_manager
|
||||||
|
|
||||||
local script_data = {}
|
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 = 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.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.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
|
-- OS compatibility
|
||||||
local PS = dt.configuration.running_os == "windows" and "\\" or "/"
|
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
|
-- initialize module preferences
|
||||||
if not dt.preferences.read(MODULE_NAME, "initialized", "bool") then
|
if not dt.preferences.read(MODULE_NAME, "initialized", "bool") then
|
||||||
dt.preferences.write(MODULE_NAME, "sigma", "string", "0.7")
|
dt.preferences.write(MODULE_NAME, "sigma", "string", "0.7")
|
||||||
dt.preferences.write(MODULE_NAME, "iterations", "string", "10")
|
dt.preferences.write(MODULE_NAME, "iterations", "string", "10")
|
||||||
dt.preferences.write(MODULE_NAME, "jpg_quality", "string", "95")
|
dt.preferences.write(MODULE_NAME, "jpg_quality", "string", "95")
|
||||||
dt.preferences.write(MODULE_NAME, "initialized", "bool", true)
|
dt.preferences.write(MODULE_NAME, "initialized", "bool", true)
|
||||||
end
|
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_NAME .. " exiftool not found, metadata not preserved")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
-- setup export ---------------------------------------------------------------
|
-- setup export ---------------------------------------------------------------
|
||||||
@@ -136,7 +155,7 @@ local function export2RL(storage, image_table, extra_data)
|
|||||||
for image, temp_name in pairs(image_table) do
|
for image, temp_name in pairs(image_table) do
|
||||||
|
|
||||||
i = i + 1
|
i = i + 1
|
||||||
dt.print(_("sharpening image ")..i.." ...")
|
dt.print(string.format(_("sharpening image %d ..."), i))
|
||||||
-- create unique filename
|
-- create unique filename
|
||||||
new_name = output_folder..PS..df.get_basename(temp_name)..".jpg"
|
new_name = output_folder..PS..df.get_basename(temp_name)..".jpg"
|
||||||
new_name = df.create_unique_filename(new_name)
|
new_name = df.create_unique_filename(new_name)
|
||||||
@@ -153,7 +172,10 @@ local function export2RL(storage, image_table, extra_data)
|
|||||||
if result ~= 0 then
|
if result ~= 0 then
|
||||||
dt.print(_("sharpening error"))
|
dt.print(_("sharpening error"))
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- copy metadata from input_file to output_file
|
||||||
|
preserve_metadata(input_file, output_file)
|
||||||
|
|
||||||
-- delete temp image
|
-- delete temp image
|
||||||
os.remove(temp_name)
|
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
|
||||||
129
contrib/auto_tag_modified.lua
Normal file
129
contrib/auto_tag_modified.lua
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
--[[
|
||||||
|
|
||||||
|
auto_tag_modified.lua - automatically tag an image when it has been manually modified in darkroom
|
||||||
|
|
||||||
|
Copyright (C) 2025 Michael Reiger <michael@rauschpfeife.net>, modeled after auto_snapshot.lua by Bill Ferguson <wpferguson@gamil.com>.
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
]]
|
||||||
|
--[[
|
||||||
|
auto_tag_modified -
|
||||||
|
|
||||||
|
automatically tag an image when it has been manually modified in the darkroom, that is if its history has changed at the time it is closed from the darkroom.
|
||||||
|
(This will not catch applying styles from the light table though.)
|
||||||
|
|
||||||
|
ADDITIONAL SOFTWARE NEEDED FOR THIS SCRIPT
|
||||||
|
None
|
||||||
|
|
||||||
|
USAGE
|
||||||
|
* start the script from script_manager
|
||||||
|
* open an image in darkroom, and close it after making an operation that changes the history
|
||||||
|
|
||||||
|
BUGS, COMMENTS, SUGGESTIONS
|
||||||
|
Michael Reiger <michael@rauschpfeife.net>
|
||||||
|
|
||||||
|
CHANGES
|
||||||
|
]]
|
||||||
|
|
||||||
|
local dt = require "darktable"
|
||||||
|
local du = require "lib/dtutils"
|
||||||
|
local log = require "lib/dtutils.log"
|
||||||
|
|
||||||
|
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
-- C O N S T A N T S
|
||||||
|
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
|
local MODULE <const> = "auto_tag_modified"
|
||||||
|
local DEFAULT_TAG_NAME <const> = "darktable manually modified"
|
||||||
|
local DEFAULT_LOG_LEVEL <const> = log.error
|
||||||
|
|
||||||
|
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
-- A P I C H E C K
|
||||||
|
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
|
du.check_min_api_version("7.0.0", MODULE) -- choose the minimum version that contains the features you need
|
||||||
|
|
||||||
|
|
||||||
|
-- - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
-- I 1 8 N
|
||||||
|
-- - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
|
local gettext = dt.gettext.gettext
|
||||||
|
|
||||||
|
local function _(msgid)
|
||||||
|
return gettext(msgid)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
-- S C R I P T M A N A G E R I N T E G R A T I O N
|
||||||
|
-- - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
|
local script_data = {}
|
||||||
|
|
||||||
|
script_data.destroy = nil -- function to destory the script
|
||||||
|
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet
|
||||||
|
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
|
||||||
|
script_data.show = nil -- only required for libs since the destroy_method only hides them
|
||||||
|
|
||||||
|
script_data.metadata = {
|
||||||
|
name = _("auto tag modified"), -- name of script
|
||||||
|
purpose = _("automatically tag an image when it has been manually modified in darkroom"), -- purpose of script
|
||||||
|
author = "Michael Reiger <michael@rauschpfeife.net>", -- your name and optionally e-mail address
|
||||||
|
help = "https://docs.darktable.org/lua/stable/lua.scripts.manual/scripts/contrib/auto_tag_modified/" -- URL to help/documentation
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
-- L O G L E V E L
|
||||||
|
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
|
log.log_level(DEFAULT_LOG_LEVEL)
|
||||||
|
|
||||||
|
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
-- N A M E S P A C E
|
||||||
|
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
|
local auto_tag_modified = {}
|
||||||
|
|
||||||
|
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
-- P R E F E R E N C E S
|
||||||
|
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
|
dt.preferences.register(MODULE, "auto_modified_tag_name", "string", "auto_tag_modified - " .. _("tag name to use for auto tagging modified images"),
|
||||||
|
_("tag name to use for auto tagging modified images"), DEFAULT_TAG_NAME)
|
||||||
|
|
||||||
|
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
-- D A R K T A B L E I N T E G R A T I O N
|
||||||
|
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
|
local function destroy()
|
||||||
|
dt.destroy_event(MODULE, "darkroom-image-history-changed")
|
||||||
|
end
|
||||||
|
|
||||||
|
script_data.destroy = destroy
|
||||||
|
|
||||||
|
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
-- E V E N T S
|
||||||
|
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
|
dt.register_event(MODULE, "darkroom-image-history-changed",
|
||||||
|
function(event, image)
|
||||||
|
local tag_name = dt.preferences.read(MODULE, "auto_modified_tag_name", "string")
|
||||||
|
local tag = dt.tags.create(tag_name)
|
||||||
|
dt.tags.attach(tag, image)
|
||||||
|
end
|
||||||
|
)
|
||||||
|
|
||||||
|
return script_data
|
||||||
@@ -39,16 +39,33 @@ GPLv2
|
|||||||
local darktable = require "darktable"
|
local darktable = require "darktable"
|
||||||
local du = require "lib/dtutils"
|
local du = require "lib/dtutils"
|
||||||
local filelib = require "lib/dtutils.file"
|
local filelib = require "lib/dtutils.file"
|
||||||
|
local syslib = require "lib/dtutils.system"
|
||||||
|
|
||||||
du.check_min_api_version("7.0.0", "autostyle")
|
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
|
-- return data structure for script_manager
|
||||||
|
|
||||||
local script_data = {}
|
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 = 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.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.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
|
-- run command and retrieve stdout
|
||||||
local function get_stdout(cmd)
|
local function get_stdout(cmd)
|
||||||
@@ -86,56 +103,62 @@ end
|
|||||||
local function autostyle_apply_one_image (image)
|
local function autostyle_apply_one_image (image)
|
||||||
|
|
||||||
local pref = darktable.preferences.read("autostyle", "exif_tag", "string")
|
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
|
-- 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)
|
-- check they all exist (correct syntax)
|
||||||
if (not tag) then
|
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
|
return 0
|
||||||
end
|
end
|
||||||
if (not value) then
|
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
|
return 0
|
||||||
end
|
end
|
||||||
if (not style_name) then
|
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
|
return 0
|
||||||
end
|
end
|
||||||
if not filelib.check_if_bin_exists("exiftool") then
|
if not filelib.check_if_bin_exists("exiftool") then
|
||||||
darktable.print("Can't find exiftool")
|
darktable.print(_("can't find exiftool"))
|
||||||
return 0
|
return 0
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- First find the style (we have its name)
|
-- First find the style (we have its name)
|
||||||
local styles = darktable.styles
|
local styles = darktable.styles
|
||||||
local style
|
local style
|
||||||
for _, s in ipairs(styles) do
|
for _, s in ipairs(styles) do
|
||||||
if s.name == style_name then
|
if s.name == style_name then
|
||||||
style = s
|
style = s
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if (not style) then
|
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
|
return 0
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Apply the style to image, if it is tagged
|
-- Apply the style to image, if it is tagged
|
||||||
local ok, auto_dr_attr = pcall(exiftool_attribute, image.path .. '/' .. image.filename,tag)
|
local ok, auto_dr_attr = pcall(exiftool_attribute, image.path .. '/' .. image.filename,tag)
|
||||||
--darktable.print_error("dr_attr:" .. auto_dr_attr)
|
--darktable.print_error("dr_attr:" .. auto_dr_attr)
|
||||||
-- If the lookup fails, stop here
|
-- If the lookup fails, stop here
|
||||||
if (not ok) then
|
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
|
return 0
|
||||||
end
|
end
|
||||||
if auto_dr_attr == value then
|
if auto_dr_attr == value then
|
||||||
darktable.print_log("Image " .. image.filename .. ": autostyle automatically applied " .. pref)
|
darktable.print_log("Image " .. image.filename .. ": autostyle automatically applied " .. pref)
|
||||||
darktable.styles.apply(style,image)
|
darktable.styles.apply(style,image)
|
||||||
return 1
|
return 1
|
||||||
else
|
else
|
||||||
darktable.print_log("Image " .. image.filename .. ": autostyle not applied, exif tag " .. pref .. " not matched: " .. auto_dr_attr)
|
darktable.print_log("Image " .. image.filename .. ": autostyle not applied, exif tag " .. pref .. " not matched: " .. auto_dr_attr)
|
||||||
return 0
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -153,7 +176,7 @@ local function autostyle_apply(shortcut)
|
|||||||
images_submitted = images_submitted + 1
|
images_submitted = images_submitted + 1
|
||||||
images_processed = images_processed + autostyle_apply_one_image(image)
|
images_processed = images_processed + autostyle_apply_one_image(image)
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
local function destroy()
|
local function destroy()
|
||||||
@@ -163,13 +186,15 @@ end
|
|||||||
|
|
||||||
-- Registering events
|
-- Registering events
|
||||||
darktable.register_event("autostyle", "shortcut", autostyle_apply,
|
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",
|
darktable.register_event("autostyle", "post-import-image",
|
||||||
autostyle_apply_one_image_event)
|
autostyle_apply_one_image_event)
|
||||||
|
|
||||||
|
|
||||||
script_data.destroy = destroy
|
script_data.destroy = destroy
|
||||||
return script_data
|
return script_data
|
||||||
|
|||||||
@@ -36,29 +36,34 @@ USAGE
|
|||||||
local dt = require "darktable"
|
local dt = require "darktable"
|
||||||
local du = require "lib/dtutils"
|
local du = require "lib/dtutils"
|
||||||
|
|
||||||
local gettext = dt.gettext
|
local gettext = dt.gettext.gettext
|
||||||
|
|
||||||
local MODULE = "change_group_leader"
|
local MODULE = "change_group_leader"
|
||||||
|
|
||||||
du.check_min_api_version("3.0.0", MODULE)
|
du.check_min_api_version("3.0.0", MODULE)
|
||||||
|
|
||||||
|
local function _(msgid)
|
||||||
|
return gettext(msgid)
|
||||||
|
end
|
||||||
|
|
||||||
-- return data structure for script_manager
|
-- return data structure for script_manager
|
||||||
|
|
||||||
local script_data = {}
|
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 = 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.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.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(MODULE, dt.configuration.config_dir.."/lua/locale/")
|
|
||||||
|
|
||||||
local function _(msgid)
|
|
||||||
return gettext.dgettext(MODULE, msgid)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- create a namespace to contain persistent data and widgets
|
-- create a namespace to contain persistent data and widgets
|
||||||
chg_grp_ldr = {}
|
local chg_grp_ldr = {}
|
||||||
|
|
||||||
local cgl = chg_grp_ldr
|
local cgl = chg_grp_ldr
|
||||||
|
|
||||||
@@ -75,7 +80,7 @@ local function install_module()
|
|||||||
if not cgl.module_installed then
|
if not cgl.module_installed then
|
||||||
dt.register_lib(
|
dt.register_lib(
|
||||||
MODULE, -- Module name
|
MODULE, -- Module name
|
||||||
_("change_group_leader"), -- Visible name
|
_("change group leader"), -- Visible name
|
||||||
true, -- expandable
|
true, -- expandable
|
||||||
false, -- resetable
|
false, -- resetable
|
||||||
{[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 700}}, -- containers
|
{[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 700}}, -- containers
|
||||||
@@ -120,7 +125,7 @@ end
|
|||||||
|
|
||||||
local function process_image_groups(images)
|
local function process_image_groups(images)
|
||||||
if #images < 1 then
|
if #images < 1 then
|
||||||
dt.print(_("No images selected."))
|
dt.print(_("no images selected"))
|
||||||
dt.print_log(MODULE .. "no images seletected, returning...")
|
dt.print_log(MODULE .. "no images seletected, returning...")
|
||||||
else
|
else
|
||||||
local mode = cgl.widgets.mode.value
|
local mode = cgl.widgets.mode.value
|
||||||
@@ -160,7 +165,7 @@ cgl.widgets.mode = dt.new_widget("combobox"){
|
|||||||
}
|
}
|
||||||
|
|
||||||
cgl.widgets.execute = dt.new_widget("button"){
|
cgl.widgets.execute = dt.new_widget("button"){
|
||||||
label = _("Execute"),
|
label = _("execute"),
|
||||||
clicked_callback = function()
|
clicked_callback = function()
|
||||||
process_image_groups(dt.gui.action_images)
|
process_image_groups(dt.gui.action_images)
|
||||||
end
|
end
|
||||||
@@ -197,4 +202,4 @@ script_data.restart = restart
|
|||||||
script_data.destroy_method = "hide"
|
script_data.destroy_method = "hide"
|
||||||
script_data.show = restart
|
script_data.show = restart
|
||||||
|
|
||||||
return script_data
|
return script_data
|
||||||
|
|||||||
@@ -39,28 +39,33 @@
|
|||||||
local dt = require "darktable"
|
local dt = require "darktable"
|
||||||
local du = require "lib/dtutils"
|
local du = require "lib/dtutils"
|
||||||
|
|
||||||
|
local gettext = dt.gettext.gettext
|
||||||
|
|
||||||
|
local function _(msgid)
|
||||||
|
return gettext(msgid)
|
||||||
|
end
|
||||||
|
|
||||||
-- return data structure for script_manager
|
-- return data structure for script_manager
|
||||||
|
|
||||||
local script_data = {}
|
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 = 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.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.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 gettext = dt.gettext
|
|
||||||
|
|
||||||
-- not a number
|
-- not a number
|
||||||
local NaN = 0/0
|
local NaN = 0/0
|
||||||
|
|
||||||
du.check_min_api_version("7.0.0", "clear_GPS")
|
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)
|
local function clear_GPS(images)
|
||||||
for _, image in ipairs(images) do
|
for _, image in ipairs(images) do
|
||||||
-- set the location information to Not a Number (NaN) so it displays correctly
|
-- 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(
|
dt.gui.libs.image.register_action(
|
||||||
"clear_GPS", _("clear GPS data"),
|
"clear_GPS", _("clear GPS data"),
|
||||||
function(event, images) clear_GPS(images) end,
|
function(event, images) clear_GPS(images) end,
|
||||||
_("Clear GPS data from selected images")
|
_("clear GPS data from selected images")
|
||||||
)
|
)
|
||||||
|
|
||||||
dt.register_event(
|
dt.register_event(
|
||||||
"clear_GPS", "shortcut",
|
"clear_GPS", "shortcut",
|
||||||
function(event, shortcut) clear_GPS(dt.gui.action_images) end,
|
function(event, shortcut) clear_GPS(dt.gui.action_images) end,
|
||||||
_("Clear GPS data")
|
_("clear GPS data from selected images")
|
||||||
)
|
)
|
||||||
|
|
||||||
return script_data
|
return script_data
|
||||||
|
|||||||
@@ -45,6 +45,7 @@
|
|||||||
local dt = require "darktable"
|
local dt = require "darktable"
|
||||||
local du = require "lib/dtutils"
|
local du = require "lib/dtutils"
|
||||||
local df = require "lib/dtutils.file"
|
local df = require "lib/dtutils.file"
|
||||||
|
local dtsys = require "lib/dtutils.system"
|
||||||
|
|
||||||
du.check_min_api_version("7.0.0", "color_profile_manager")
|
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
|
-- L O C A L I Z A T I O N
|
||||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
local gettext = dt.gettext
|
local gettext = dt.gettext.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 function _(msgid)
|
local function _(msgid)
|
||||||
return gettext.dgettext("color_profile_manager", msgid)
|
return gettext(msgid)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
@@ -119,13 +117,13 @@ end
|
|||||||
|
|
||||||
local function add_profile(file, dir)
|
local function add_profile(file, dir)
|
||||||
df.file_copy(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)
|
dt.print_log("color profile " .. file .. " added to " .. dir)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function remove_profile(file, dir)
|
local function remove_profile(file, dir)
|
||||||
os.remove(dir .. PS .. file)
|
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)
|
dt.print_log("color profile " .. file .. " removed from " .. dir)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -364,6 +362,13 @@ end
|
|||||||
|
|
||||||
local script_data = {}
|
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.destroy = destroy
|
||||||
script_data.restart = restart
|
script_data.restart = restart
|
||||||
script_data.destroy_method = "hide"
|
script_data.destroy_method = "hide"
|
||||||
|
|||||||
@@ -40,24 +40,29 @@ local dt = require "darktable"
|
|||||||
local du = require "lib/dtutils"
|
local du = require "lib/dtutils"
|
||||||
local debug = require "darktable.debug"
|
local debug = require "darktable.debug"
|
||||||
|
|
||||||
local gettext = dt.gettext
|
local gettext = dt.gettext.gettext
|
||||||
|
|
||||||
du.check_min_api_version("7.0.0", "copy_attach_detach_tags")
|
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
|
-- return data structure for script_manager
|
||||||
|
|
||||||
local script_data = {}
|
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 = 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.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.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("copy_attach_detach_tags",dt.configuration.config_dir.."/lua/locale/")
|
|
||||||
|
|
||||||
local function _(msgid)
|
|
||||||
return gettext.dgettext("copy_attach_detach_tags", msgid)
|
|
||||||
end
|
|
||||||
|
|
||||||
local cadt = {}
|
local cadt = {}
|
||||||
cadt.module_installed = false
|
cadt.module_installed = false
|
||||||
@@ -98,7 +103,7 @@ local function mcopy_tags()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
dt.print(_('Image tags copied ...'))
|
dt.print(_('image tags copied ...'))
|
||||||
|
|
||||||
--create UI tag list
|
--create UI tag list
|
||||||
local taglist = ""
|
local taglist = ""
|
||||||
@@ -120,7 +125,7 @@ local function mcopy_tags()
|
|||||||
local function attach_tags()
|
local function attach_tags()
|
||||||
|
|
||||||
if next(image_tags) == nil then
|
if next(image_tags) == nil then
|
||||||
dt.print(_('No tag to attach, please copy tags first.'))
|
dt.print(_('no tag to attach, please copy tags first.'))
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -144,7 +149,7 @@ local function attach_tags()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
dt.print(_('Tags attached ...'))
|
dt.print(_('tags attached ...'))
|
||||||
end
|
end
|
||||||
|
|
||||||
local function detach_tags()
|
local function detach_tags()
|
||||||
@@ -160,13 +165,13 @@ local function detach_tags()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
dt.print(_('Tags removed from image(s).'))
|
dt.print(_('tags removed from image(s).'))
|
||||||
end
|
end
|
||||||
|
|
||||||
local function replace_tags()
|
local function replace_tags()
|
||||||
detach_tags()
|
detach_tags()
|
||||||
attach_tags()
|
attach_tags()
|
||||||
dt.print(_('Tags replaced'))
|
dt.print(_('tags replaced'))
|
||||||
end
|
end
|
||||||
|
|
||||||
local function install_module()
|
local function install_module()
|
||||||
|
|||||||
@@ -37,13 +37,27 @@ local du = require "lib/dtutils"
|
|||||||
|
|
||||||
du.check_min_api_version("7.0.0", "cr2hdr")
|
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
|
-- return data structure for script_manager
|
||||||
|
|
||||||
local script_data = {}
|
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 = 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.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.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 queue = {}
|
||||||
local processed_files = {}
|
local processed_files = {}
|
||||||
@@ -86,7 +100,7 @@ end
|
|||||||
local function convert_images()
|
local function convert_images()
|
||||||
if next(queue) == nil then return end
|
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
|
for key,image in pairs(queue) do
|
||||||
if job.valid then
|
if job.valid then
|
||||||
job.percent = (key-1)/#queue
|
job.percent = (key-1)/#queue
|
||||||
@@ -97,7 +111,7 @@ local function convert_images()
|
|||||||
end
|
end
|
||||||
local success_count = 0
|
local success_count = 0
|
||||||
for _ in pairs(processed_files) do success_count = success_count + 1 end
|
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
|
job.valid = false
|
||||||
processed_files = {}
|
processed_files = {}
|
||||||
queue = {}
|
queue = {}
|
||||||
@@ -121,13 +135,13 @@ local function destroy()
|
|||||||
end
|
end
|
||||||
|
|
||||||
darktable.register_event("cr2hdr", "shortcut",
|
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",
|
darktable.register_event("cr2hdr", "post-import-image",
|
||||||
file_imported)
|
file_imported)
|
||||||
darktable.register_event("cr2hdr", "post-import-film",
|
darktable.register_event("cr2hdr", "post-import-film",
|
||||||
film_imported)
|
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
|
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")
|
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
|
-- return data structure for script_manager
|
||||||
|
|
||||||
local script_data = {}
|
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 = 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.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.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
|
|
||||||
local gettext = dt.gettext
|
|
||||||
gettext.bindtextdomain('enfuseAdvanced',dt.configuration.config_dir..'/lua/locale/')
|
|
||||||
local function _(msgid)
|
|
||||||
return gettext.dgettext('enfuseAdvanced', msgid)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- INITS --
|
-- INITS --
|
||||||
local AIS = {
|
local AIS = {
|
||||||
@@ -259,7 +267,7 @@ local function ExeUpdate(prog_tbl) --updates executable paths and verifies them
|
|||||||
if not prog.bin then
|
if not prog.bin then
|
||||||
prog.install_error = true
|
prog.install_error = true
|
||||||
dt.preferences.write(mod, 'bin_exists', 'bool', false)
|
dt.preferences.write(mod, 'bin_exists', 'bool', false)
|
||||||
dt.print(_('issue with ')..prog.name.._(' executable'))
|
dt.print(string.format(_("issue with %s executable"), prog.name))
|
||||||
else
|
else
|
||||||
prog.bin = CleanSpaces(prog.bin)
|
prog.bin = CleanSpaces(prog.bin)
|
||||||
end
|
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)
|
dt.preferences.write(mod, preset..argument, arg_data.style, temp)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
dt.print(_('saved to ')..preset)
|
dt.print(string.format(_("saved to %s"), preset))
|
||||||
end
|
end
|
||||||
|
|
||||||
local function LoadFromPreference(preset) --load values from the specified 'preset' into the GUI elements
|
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)
|
dt.preferences.write(mod, 'active_'..argument, arg_data.style, temp)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
dt.print(_('loaded from ')..preset)
|
dt.print(string.format(_("loaded from %s"), preset))
|
||||||
end
|
end
|
||||||
|
|
||||||
local function remove_temp_files(images_to_remove) --deletes all files specified by the input string
|
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
|
end
|
||||||
|
|
||||||
local function show_status(storage, image, format, filename, number, total, high_quality, extra_data) --outputs message to user showing script export status
|
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
|
end
|
||||||
|
|
||||||
local function main(storage, image_table, extra_data)
|
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'))
|
dt.print(_('too few images selected, please select at least 2 images'))
|
||||||
return
|
return
|
||||||
elseif extra_data[1] == 2 then
|
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
|
return
|
||||||
end
|
end
|
||||||
local images_to_remove = ''
|
local images_to_remove = ''
|
||||||
@@ -455,8 +463,8 @@ local function main(storage, image_table, extra_data)
|
|||||||
job.valid = false
|
job.valid = false
|
||||||
if resp ~= 0 then
|
if resp ~= 0 then
|
||||||
remove_temp_files(images_to_remove)
|
remove_temp_files(images_to_remove)
|
||||||
dt.print_error(AIS.name.._(' failed'))
|
dt.print(string.format(_("%s failed"), AIS.name))
|
||||||
dt.print(AIS.name.._(' failed'))
|
dt.print_error(AIS.name .. ' failed')
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -482,8 +490,8 @@ local function main(storage, image_table, extra_data)
|
|||||||
local resp = dsys.external_command(run_cmd)
|
local resp = dsys.external_command(run_cmd)
|
||||||
if resp ~= 0 then
|
if resp ~= 0 then
|
||||||
remove_temp_files(images_to_remove)
|
remove_temp_files(images_to_remove)
|
||||||
dt.print_error(ENF.name.._(' failed'))
|
dt.print_error(ENF.name..' failed')
|
||||||
dt.print(ENF.name.._(' failed'))
|
dt.print(string.format(_("%s failed"), ENF.name))
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -728,7 +736,7 @@ GUI.ENF.hard_masks = dt.new_widget('check_button'){
|
|||||||
GUI.ENF.save_masks = dt.new_widget('check_button'){
|
GUI.ENF.save_masks = dt.new_widget('check_button'){
|
||||||
label = _('save masks'),
|
label = _('save masks'),
|
||||||
value = dt.preferences.read(mod, 'active_save_masks', 'bool'),
|
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,
|
clicked_callback = function(self) dt.preferences.write(mod, 'active_save_masks', 'bool', self.value) end,
|
||||||
reset_callback = function(self) self.value = false 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'){
|
GUI.Target.source_location = dt.new_widget('check_button'){
|
||||||
label = _('save to source image location'),
|
label = _('save to source image location'),
|
||||||
value = dt.preferences.read(mod, 'active_source_location', 'bool'),
|
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,
|
clicked_callback = function(self) dt.preferences.write(mod, 'active_source_location', 'bool', self.value) end,
|
||||||
reset_callback = function(self) self.value = true 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')
|
temp = dt.preferences.read(mod, 'active_apply_style_ind', 'integer')
|
||||||
GUI.Target.apply_style = dt.new_widget('combobox'){
|
GUI.Target.apply_style = dt.new_widget('combobox'){
|
||||||
label = _('Apply Style on Import'),
|
label = _('apply style on Import'),
|
||||||
tooltip = _('Apply selected style on auto-import to newly created blended image'),
|
tooltip = _('apply selected style on auto-import to newly created blended image'),
|
||||||
selected = 1,
|
selected = 1,
|
||||||
'none',
|
'none',
|
||||||
changed_callback = function(self)
|
changed_callback = function(self)
|
||||||
@@ -937,16 +945,16 @@ GUI.Target.apply_style.selected = temp
|
|||||||
GUI.Target.copy_tags = dt.new_widget('check_button'){
|
GUI.Target.copy_tags = dt.new_widget('check_button'){
|
||||||
label = _('copy tags'),
|
label = _('copy tags'),
|
||||||
value = dt.preferences.read(mod, 'active_copy_tags', 'bool'),
|
value = dt.preferences.read(mod, 'active_copy_tags', 'bool'),
|
||||||
tooltip = _('Copy tags from first image.'),
|
tooltip = _('copy tags from first image.'),
|
||||||
clicked_callback = function(self) dt.preferences.write(mod, 'active_copy_tags', 'bool', self.value) end,
|
clicked_callback = function(self) dt.preferences.write(mod, 'active_copy_tags', 'bool', self.value) end,
|
||||||
reset_callback = function(self) self.value = true end
|
reset_callback = function(self) self.value = true end
|
||||||
}
|
}
|
||||||
temp = dt.preferences.read(mod, 'active_add_tags', 'string')
|
temp = dt.preferences.read(mod, 'active_add_tags', 'string')
|
||||||
if temp == '' then temp = nil end
|
if temp == '' then temp = nil end
|
||||||
GUI.Target.add_tags = dt.new_widget('entry'){
|
GUI.Target.add_tags = dt.new_widget('entry'){
|
||||||
tooltip = _('Additional tags to be added on import. Seperate with commas, all spaces will be removed'),
|
tooltip = _('additional tags to be added on import, seperate with commas, all spaces will be removed'),
|
||||||
text = temp,
|
text = temp,
|
||||||
placeholder = 'Enter tags, seperated by commas',
|
placeholder = _('enter tags, separated by commas'),
|
||||||
editable = true
|
editable = true
|
||||||
}
|
}
|
||||||
temp = dt.preferences.read(mod, 'active_current_preset_ind', 'integer')
|
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
|
GUI.Presets.variants_type.sensitive = GUI.Presets.variants.value
|
||||||
temp = df.get_executable_path_preference(AIS.name)
|
temp = df.get_executable_path_preference(AIS.name)
|
||||||
GUI.exes.align_image_stack = dt.new_widget('file_chooser_button'){
|
GUI.exes.align_image_stack = dt.new_widget('file_chooser_button'){
|
||||||
title = 'AIS binary path',
|
title = 'align_image_stack ' .. _('binary path'),
|
||||||
value = temp,
|
value = temp,
|
||||||
tooltip = temp,
|
tooltip = temp,
|
||||||
is_directory = false,
|
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)
|
temp = df.get_executable_path_preference(ENF.name)
|
||||||
GUI.exes.enfuse = dt.new_widget('file_chooser_button'){
|
GUI.exes.enfuse = dt.new_widget('file_chooser_button'){
|
||||||
title = 'enfuse binary path',
|
title = 'enfuse ' .. _('binary path'),
|
||||||
value = temp,
|
value = temp,
|
||||||
tooltip = temp,
|
tooltip = temp,
|
||||||
is_directory = false,
|
is_directory = false,
|
||||||
@@ -1029,7 +1037,7 @@ GUI.exes.enfuse = dt.new_widget('file_chooser_button'){
|
|||||||
}
|
}
|
||||||
temp = df.get_executable_path_preference(EXF.name)
|
temp = df.get_executable_path_preference(EXF.name)
|
||||||
GUI.exes.exiftool = dt.new_widget('file_chooser_button'){
|
GUI.exes.exiftool = dt.new_widget('file_chooser_button'){
|
||||||
title = 'Exiftool binary path',
|
title = 'exiftool ' .. _('binary path'),
|
||||||
value = temp,
|
value = temp,
|
||||||
tooltip = temp,
|
tooltip = temp,
|
||||||
is_directory = false,
|
is_directory = false,
|
||||||
|
|||||||
@@ -33,21 +33,27 @@ local ds = require("lib/dtutils.system")
|
|||||||
|
|
||||||
du.check_min_api_version("7.0.0", "exportLUT")
|
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
|
-- return data structure for script_manager
|
||||||
|
|
||||||
local script_data = {}
|
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 = 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.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.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 gettext = dt.gettext
|
|
||||||
|
|
||||||
gettext.bindtextdomain("exportLUT",dt.configuration.config_dir.."/lua/locale/")
|
|
||||||
|
|
||||||
local function _(msgid)
|
|
||||||
return gettext.dgettext("exportLUT", msgid)
|
|
||||||
end
|
|
||||||
|
|
||||||
du.check_min_api_version("5.0.0", "exportLUT")
|
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
|
if dt.configuration.running_os == 'windows' then mkdir_command = 'mkdir ' end
|
||||||
|
|
||||||
local file_chooser_button = dt.new_widget("file_chooser_button"){
|
local file_chooser_button = dt.new_widget("file_chooser_button"){
|
||||||
title = _("Identity_file_chooser"),
|
title = _("choose the identity file"),
|
||||||
value = "",
|
value = "",
|
||||||
is_directory = false
|
is_directory = false
|
||||||
}
|
}
|
||||||
|
|
||||||
local export_chooser_button = dt.new_widget("file_chooser_button"){
|
local export_chooser_button = dt.new_widget("file_chooser_button"){
|
||||||
title = _("Export_location_chooser"),
|
title = _("choose the export location"),
|
||||||
value = "",
|
value = "",
|
||||||
is_directory = true
|
is_directory = true
|
||||||
}
|
}
|
||||||
@@ -105,9 +111,9 @@ end
|
|||||||
local function export_luts()
|
local function export_luts()
|
||||||
local identity = dt.database.import(file_chooser_button.value)
|
local identity = dt.database.import(file_chooser_button.value)
|
||||||
if(type(identity) ~= "userdata") then
|
if(type(identity) ~= "userdata") then
|
||||||
dt.print(_("Invalid identity lut file"))
|
dt.print(_("invalid identity lut file"))
|
||||||
else
|
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
|
local size = 1
|
||||||
|
|
||||||
@@ -126,9 +132,9 @@ local function export_luts()
|
|||||||
io_lut:write_image(identity, output_path(style.name, job))
|
io_lut:write_image(identity, output_path(style.name, job))
|
||||||
count = count + 1
|
count = count + 1
|
||||||
job.percent = count / size
|
job.percent = count / size
|
||||||
dt.print(_("Exported: ") .. output_path(style.name, job))
|
dt.print(string.format(_("exported: %s"), output_path(style.name, job)))
|
||||||
end
|
end
|
||||||
dt.print(_("Done exporting haldCLUTs"))
|
dt.print(_("done exporting haldCLUTs"))
|
||||||
job.valid = false
|
job.valid = false
|
||||||
identity:reset()
|
identity:reset()
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -75,13 +75,28 @@ local dtsys = require "lib/dtutils.system"
|
|||||||
local MODULE_NAME = "ext_editor"
|
local MODULE_NAME = "ext_editor"
|
||||||
du.check_min_api_version("7.0.0", MODULE_NAME)
|
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
|
-- return data structure for script_manager
|
||||||
|
|
||||||
local script_data = {}
|
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 = 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.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.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
|
-- OS compatibility
|
||||||
local PS = dt.configuration.running_os == "windows" and "\\" or "/"
|
local PS = dt.configuration.running_os == "windows" and "\\" or "/"
|
||||||
@@ -93,13 +108,6 @@ ee.event_registered = false
|
|||||||
ee.widgets = {}
|
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
|
-- maximum number of external programs, can be increased to necessity
|
||||||
local MAX_EDITORS = 9
|
local MAX_EDITORS = 9
|
||||||
|
|
||||||
@@ -155,7 +163,7 @@ local function UpdateProgramList(combobox, button_edit, button_edit_copy, update
|
|||||||
button_edit.sensitive = active
|
button_edit.sensitive = active
|
||||||
button_edit_copy.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
|
end
|
||||||
|
|
||||||
|
|
||||||
@@ -222,17 +230,17 @@ local function OpenWith(images, choice, copy)
|
|||||||
-- physical copy, check result, return if error
|
-- physical copy, check result, return if error
|
||||||
local copy_success = df.file_copy(name, new_name)
|
local copy_success = df.file_copy(name, new_name)
|
||||||
if not copy_success then
|
if not copy_success then
|
||||||
dt.print(_("error copying file ")..name)
|
dt.print(string.format(_("error copying file %s"), name))
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- launch the external editor, check result, return if error
|
-- launch the external editor, check result, return if error
|
||||||
local run_cmd = bin.." "..df.sanitize_filename(new_name)
|
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)
|
local result = dtsys.external_command(run_cmd)
|
||||||
if result ~= 0 then
|
if result ~= 0 then
|
||||||
dt.print(_("error launching ")..friendly_name)
|
dt.print(string.format(_("error launching %s"), friendly_name))
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -320,12 +328,12 @@ local function export2collection(storage, image_table, extra_data)
|
|||||||
|
|
||||||
-- create unique filename
|
-- create unique filename
|
||||||
new_name = image.path..PS..df.get_filename(temp_name)
|
new_name = image.path..PS..df.get_filename(temp_name)
|
||||||
new_name = df.create_unique_filename(new_name)
|
new_name = df.sanitize_filename(df.create_unique_filename(new_name))
|
||||||
|
|
||||||
-- move image to collection folder, check result, return if error
|
-- move image to collection folder, check result, return if error
|
||||||
move_success = df.file_move(temp_name, new_name)
|
move_success = df.file_move(temp_name, new_name)
|
||||||
if not move_success then
|
if not move_success then
|
||||||
dt.print(_("error moving file ")..temp_name)
|
dt.print(string.format(_("error moving file %s"), temp_name))
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -377,7 +385,7 @@ end
|
|||||||
local function restart()
|
local function restart()
|
||||||
for i = 1, MAX_EDITORS do
|
for i = 1, MAX_EDITORS do
|
||||||
dt.register_event(MODULE_NAME .. i, "shortcut",
|
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
|
end
|
||||||
dt.register_storage("exp2coll", _("collection"), nil, export2collection)
|
dt.register_storage("exp2coll", _("collection"), nil, export2collection)
|
||||||
dt.gui.libs[MODULE_NAME].visible = true
|
dt.gui.libs[MODULE_NAME].visible = true
|
||||||
@@ -475,11 +483,11 @@ dt.register_storage("exp2coll", _("collection"), nil, export2collection)
|
|||||||
-- register the new preferences -----------------------------------------------
|
-- register the new preferences -----------------------------------------------
|
||||||
for i = MAX_EDITORS, 1, -1 do
|
for i = MAX_EDITORS, 1, -1 do
|
||||||
dt.preferences.register(MODULE_NAME, "program_path_"..i, "file",
|
dt.preferences.register(MODULE_NAME, "program_path_"..i, "file",
|
||||||
_("executable for external editor ")..i,
|
string.format(_("executable for external editor %d"), i),
|
||||||
_("select executable for external editor") , _("(None)"))
|
_("select executable for external editor") , _("(none)"))
|
||||||
|
|
||||||
dt.preferences.register(MODULE_NAME, "program_name_"..i, "string",
|
dt.preferences.register(MODULE_NAME, "program_name_"..i, "string",
|
||||||
_("name of external editor ")..i,
|
string.format(_("name of external editor %d"), i),
|
||||||
_("friendly name of external editor"), "")
|
_("friendly name of external editor"), "")
|
||||||
end
|
end
|
||||||
dt.preferences.register(MODULE_NAME, "show_in_darkrooom", "bool",
|
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 -------------------------------------------------
|
-- register the new shortcuts -------------------------------------------------
|
||||||
for i = 1, MAX_EDITORS do
|
for i = 1, MAX_EDITORS do
|
||||||
dt.register_event(MODULE_NAME .. i, "shortcut",
|
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
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ local dt = require "darktable"
|
|||||||
local du = require "lib/dtutils"
|
local du = require "lib/dtutils"
|
||||||
local df = require "lib/dtutils.file"
|
local df = require "lib/dtutils.file"
|
||||||
local dtsys = require "lib/dtutils.system"
|
local dtsys = require "lib/dtutils.system"
|
||||||
local gettext = dt.gettext
|
local gettext = dt.gettext.gettext
|
||||||
|
|
||||||
-- constants
|
-- constants
|
||||||
|
|
||||||
@@ -54,13 +54,25 @@ local OUTPUT = dt.configuration.tmp_dir .. PS .. "facerecognition.txt"
|
|||||||
|
|
||||||
du.check_min_api_version("7.0.0", MODULE)
|
du.check_min_api_version("7.0.0", MODULE)
|
||||||
|
|
||||||
|
local function _(msgid)
|
||||||
|
return gettext(msgid)
|
||||||
|
end
|
||||||
|
|
||||||
-- return data structure for script_manager
|
-- return data structure for script_manager
|
||||||
|
|
||||||
local script_data = {}
|
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 = 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.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.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
|
-- namespace
|
||||||
|
|
||||||
@@ -68,13 +80,6 @@ local fc = {}
|
|||||||
fc.module_installed = false
|
fc.module_installed = false
|
||||||
fc.event_registered = 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 function build_image_table(images)
|
||||||
local image_table = {}
|
local image_table = {}
|
||||||
local file_extension = ""
|
local file_extension = ""
|
||||||
@@ -134,7 +139,7 @@ local function do_export(img_tbl, images)
|
|||||||
job.percent = 0.0
|
job.percent = 0.0
|
||||||
for export,img in pairs(img_tbl) do
|
for export,img in pairs(img_tbl) do
|
||||||
exp_cnt = exp_cnt + 1
|
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)
|
exporter:write_image(img, export, upsize)
|
||||||
job.percent = job.percent + percent_step
|
job.percent = job.percent + percent_step
|
||||||
end
|
end
|
||||||
@@ -204,7 +209,7 @@ local function face_recognition ()
|
|||||||
local bin_path = df.check_if_bin_exists("face_recognition")
|
local bin_path = df.check_if_bin_exists("face_recognition")
|
||||||
|
|
||||||
if not bin_path then
|
if not bin_path then
|
||||||
dt.print(_("Face recognition not found"))
|
dt.print(_("face recognition not found"))
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -256,7 +261,7 @@ local function face_recognition ()
|
|||||||
local command = bin_path .. " --cpus " .. nrCores .. " --tolerance " .. tolerance .. " " .. knownPath .. " " .. path .. " > " .. OUTPUT
|
local command = bin_path .. " --cpus " .. nrCores .. " --tolerance " .. tolerance .. " " .. knownPath .. " " .. path .. " > " .. OUTPUT
|
||||||
os.setlocale()
|
os.setlocale()
|
||||||
dt.print_log("Face recognition: Running command: " .. command)
|
dt.print_log("Face recognition: Running command: " .. command)
|
||||||
dt.print(_("Starting face recognition..."))
|
dt.print(_("starting face recognition..."))
|
||||||
|
|
||||||
dtsys.external_command(command)
|
dtsys.external_command(command)
|
||||||
|
|
||||||
@@ -264,9 +269,9 @@ local function face_recognition ()
|
|||||||
local f = io.open(OUTPUT, "rb")
|
local f = io.open(OUTPUT, "rb")
|
||||||
|
|
||||||
if not f then
|
if not f then
|
||||||
dt.print(_("Face recognition failed"))
|
dt.print(_("face recognition failed"))
|
||||||
else
|
else
|
||||||
dt.print(_("Face recognition finished"))
|
dt.print(_("face recognition finished"))
|
||||||
f:close ()
|
f:close ()
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -398,7 +403,7 @@ fc.category_tags = dt.new_widget("entry"){
|
|||||||
|
|
||||||
fc.tolerance = dt.new_widget("slider"){
|
fc.tolerance = dt.new_widget("slider"){
|
||||||
label = _("tolerance"),
|
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,
|
soft_min = 0.0,
|
||||||
hard_min = 0.0,
|
hard_min = 0.0,
|
||||||
soft_max = 1.0,
|
soft_max = 1.0,
|
||||||
@@ -481,12 +486,12 @@ table.insert(widgets, fc.num_cores)
|
|||||||
table.insert(widgets, fc.export_format)
|
table.insert(widgets, fc.export_format)
|
||||||
table.insert(widgets, dt.new_widget("box"){
|
table.insert(widgets, dt.new_widget("box"){
|
||||||
orientation = "horizontal",
|
orientation = "horizontal",
|
||||||
dt.new_widget("label"){ label = _("width ")},
|
dt.new_widget("label"){ label = _("width")},
|
||||||
fc.width,
|
fc.width,
|
||||||
})
|
})
|
||||||
table.insert(widgets, dt.new_widget("box"){
|
table.insert(widgets, dt.new_widget("box"){
|
||||||
orientation = "horizontal",
|
orientation = "horizontal",
|
||||||
dt.new_widget("label"){ label = _("height ")},
|
dt.new_widget("label"){ label = _("height")},
|
||||||
fc.height,
|
fc.height,
|
||||||
})
|
})
|
||||||
table.insert(widgets, fc.execute)
|
table.insert(widgets, fc.execute)
|
||||||
|
|||||||
@@ -60,16 +60,30 @@ cameras may behave in other ways.
|
|||||||
local dt = require "darktable"
|
local dt = require "darktable"
|
||||||
local du = require "lib/dtutils"
|
local du = require "lib/dtutils"
|
||||||
local df = require "lib/dtutils.file"
|
local df = require "lib/dtutils.file"
|
||||||
|
local dtsys = require "lib/dtutils.system"
|
||||||
|
local gettext = dt.gettext.gettext
|
||||||
|
|
||||||
du.check_min_api_version("7.0.0", "fujifilm_dynamic_range")
|
du.check_min_api_version("7.0.0", "fujifilm_dynamic_range")
|
||||||
|
|
||||||
|
local function _(msgid)
|
||||||
|
return gettext(msgid)
|
||||||
|
end
|
||||||
|
|
||||||
-- return data structure for script_manager
|
-- return data structure for script_manager
|
||||||
|
|
||||||
local script_data = {}
|
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 = 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.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.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)
|
local function detect_dynamic_range(event, image)
|
||||||
if image.exif_maker ~= "FUJIFILM" then
|
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
|
-- 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)
|
image.exif_exposure_bias = image.exif_exposure_bias + tonumber(raf_result)
|
||||||
dt.print_log("[fujifilm_dynamic_range] raw exposure bias " .. tostring(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
|
end
|
||||||
|
|
||||||
local function destroy()
|
local function destroy()
|
||||||
|
|||||||
@@ -26,51 +26,61 @@ Dependencies:
|
|||||||
local dt = require "darktable"
|
local dt = require "darktable"
|
||||||
local du = require "lib/dtutils"
|
local du = require "lib/dtutils"
|
||||||
local df = require "lib/dtutils.file"
|
local df = require "lib/dtutils.file"
|
||||||
local gettext = dt.gettext
|
local dtsys = require "lib/dtutils.system"
|
||||||
|
local gettext = dt.gettext.gettext
|
||||||
|
|
||||||
du.check_min_api_version("7.0.0", "fujifilm_ratings")
|
du.check_min_api_version("7.0.0", "fujifilm_ratings")
|
||||||
|
|
||||||
|
local function _(msgid)
|
||||||
|
return gettext(msgid)
|
||||||
|
end
|
||||||
|
|
||||||
-- return data structure for script_manager
|
-- return data structure for script_manager
|
||||||
|
|
||||||
local script_data = {}
|
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 = 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.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.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
|
||||||
gettext.bindtextdomain("fujifilm_ratings", dt.configuration.config_dir.."/lua/locale/")
|
|
||||||
|
|
||||||
local function _(msgid)
|
|
||||||
return gettext.dgettext("fujifilm_ratings", msgid)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function detect_rating(event, image)
|
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
|
if not df.check_if_bin_exists("exiftool") then
|
||||||
dt.print_error(_("exiftool not found"))
|
dt.print_error("exiftool not found")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
local RAF_filename = df.sanitize_filename(tostring(image))
|
local RAF_filename = df.sanitize_filename(tostring(image))
|
||||||
local JPEG_filename = string.gsub(RAF_filename, "%.RAF$", ".JPG")
|
local JPEG_filename = string.gsub(RAF_filename, "%.RAF$", ".JPG")
|
||||||
local command = "exiftool -Rating " .. JPEG_filename
|
local command = "exiftool -Rating " .. JPEG_filename
|
||||||
dt.print_error(command)
|
dt.print_log(command)
|
||||||
local output = io.popen(command)
|
local output = io.popen(command)
|
||||||
local jpeg_result = output:read("*all")
|
local jpeg_result = output:read("*all")
|
||||||
output:close()
|
output:close()
|
||||||
if string.len(jpeg_result) > 0 then
|
if string.len(jpeg_result) > 0 then
|
||||||
jpeg_result = string.gsub(jpeg_result, "^Rating.*(%d)", "%1")
|
jpeg_result = string.gsub(jpeg_result, "^Rating.*(%d)", "%1")
|
||||||
image.rating = tonumber(jpeg_result)
|
image.rating = tonumber(jpeg_result)
|
||||||
dt.print_error(_("Using JPEG Rating: ") .. tostring(jpeg_result))
|
dt.print_log("using JPEG rating: " .. jpeg_result)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
command = "exiftool -Rating " .. RAF_filename
|
command = "exiftool -Rating " .. RAF_filename
|
||||||
dt.print_error(command)
|
dt.print_log(command)
|
||||||
output = io.popen(command)
|
output = io.popen(command)
|
||||||
local raf_result = output:read("*all")
|
local raf_result = output:read("*all")
|
||||||
output:close()
|
output:close()
|
||||||
if string.len(raf_result) > 0 then
|
if string.len(raf_result) > 0 then
|
||||||
raf_result = string.gsub(raf_result, "^Rating.*(%d)", "%1")
|
raf_result = string.gsub(raf_result, "^Rating.*(%d)", "%1")
|
||||||
image.rating = tonumber(raf_result)
|
image.rating = tonumber(raf_result)
|
||||||
dt.print_error(_("Using RAF Rating: ") .. tostring(raf_result))
|
dt.print_log("using RAF rating: " .. raf_result)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -35,24 +35,30 @@ USAGE
|
|||||||
local dt = require "darktable"
|
local dt = require "darktable"
|
||||||
local du = require "lib/dtutils"
|
local du = require "lib/dtutils"
|
||||||
local df = require "lib/dtutils.file"
|
local df = require "lib/dtutils.file"
|
||||||
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")
|
du.check_min_api_version("7.0.0", "geoJSON_export")
|
||||||
|
|
||||||
|
local function _(msgid)
|
||||||
|
return gettext(msgid)
|
||||||
|
end
|
||||||
|
|
||||||
-- return data structure for script_manager
|
-- return data structure for script_manager
|
||||||
|
|
||||||
local script_data = {}
|
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 = 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.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.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("geoJSON_export",dt.configuration.config_dir.."/lua/locale/")
|
|
||||||
|
|
||||||
local function _(msgid)
|
|
||||||
return gettext.dgettext("geoJSON_export", msgid)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Sort a table
|
-- Sort a table
|
||||||
local function spairs(_table, order) -- Code copied from http://stackoverflow.com/questions/15706270/sort-a-table-in-lua
|
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
|
end
|
||||||
|
|
||||||
local function show_status(storage, image, format, filename, number, total, high_quality, extra_data)
|
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
|
end
|
||||||
|
|
||||||
local function create_geoJSON_file(storage, image_table, extra_data)
|
local function create_geoJSON_file(storage, image_table, extra_data)
|
||||||
if not df.check_if_bin_exists("mkdir") then
|
if not df.check_if_bin_exists("mkdir") then
|
||||||
dt.print_error(_("mkdir not found"))
|
dt.print_error("mkdir not found")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
if not df.check_if_bin_exists("convert") then
|
if not df.check_if_bin_exists("convert") then
|
||||||
dt.print_error(_("convert not found"))
|
dt.print_error("convert not found")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
if not df.check_if_bin_exists("xdg-open") then
|
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
|
return
|
||||||
end
|
end
|
||||||
if not df.check_if_bin_exists("xdg-user-dir") 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
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -287,7 +293,7 @@ local function create_geoJSON_file(storage, image_table, extra_data)
|
|||||||
file:write(geoJSON_file)
|
file:write(geoJSON_file)
|
||||||
file:close()
|
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
|
-- Open the file with the standard programm
|
||||||
if ( dt.preferences.read("geoJSON_export","OpengeoJSONFile","bool") == true ) then
|
if ( dt.preferences.read("geoJSON_export","OpengeoJSONFile","bool") == true ) then
|
||||||
@@ -307,20 +313,20 @@ end
|
|||||||
dt.preferences.register("geoJSON_export",
|
dt.preferences.register("geoJSON_export",
|
||||||
"CreateMapBoxHTMLFile",
|
"CreateMapBoxHTMLFile",
|
||||||
"bool",
|
"bool",
|
||||||
_("geoJSON export: Create an additional HTML file"),
|
"geoJSON export: ".._("Create an additional HTML file"),
|
||||||
_("Creates a HTML file, that loads the geoJASON file. (Needs a MapBox key"),
|
_("creates an HTML file that loads the geoJSON file. (needs a MapBox key"),
|
||||||
false )
|
false )
|
||||||
dt.preferences.register("geoJSON_export",
|
dt.preferences.register("geoJSON_export",
|
||||||
"mapBoxKey",
|
"mapBoxKey",
|
||||||
"string",
|
"string",
|
||||||
_("geoJSON export: MapBox Key"),
|
"geoJSON export: MapBox " .. _("key"),
|
||||||
_("https://www.mapbox.com/studio/account/tokens"),
|
"https://www.mapbox.com/studio/account/tokens",
|
||||||
'' )
|
'' )
|
||||||
dt.preferences.register("geoJSON_export",
|
dt.preferences.register("geoJSON_export",
|
||||||
"OpengeoJSONFile",
|
"OpengeoJSONFile",
|
||||||
"bool",
|
"bool",
|
||||||
_("geoJSON export: Open geoJSON file after export"),
|
"geoJSON export: " .. _("open geoJSON file after export"),
|
||||||
_("Opens the geoJSON file after the export with the standard program for geoJSON files"),
|
_("opens the geoJSON file after the export with the standard program for geoJSON files"),
|
||||||
false )
|
false )
|
||||||
|
|
||||||
local handle = io.popen("xdg-user-dir DESKTOP")
|
local handle = io.popen("xdg-user-dir DESKTOP")
|
||||||
@@ -332,8 +338,8 @@ end
|
|||||||
dt.preferences.register("geoJSON_export",
|
dt.preferences.register("geoJSON_export",
|
||||||
"ExportDirectory",
|
"ExportDirectory",
|
||||||
"directory",
|
"directory",
|
||||||
_("geoJSON export: Export directory"),
|
_("geoJSON export: export directory"),
|
||||||
_("A directory that will be used to export the geoJSON files"),
|
_("a directory that will be used to export the geoJSON files"),
|
||||||
result )
|
result )
|
||||||
|
|
||||||
-- Register
|
-- Register
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
--[[
|
--[[
|
||||||
This file is part of darktable,
|
This file is part of darktable,
|
||||||
copyright (c) 2016 Tobias Jakobs
|
copyright (c) 2016 Tobias Jakobs
|
||||||
|
copyright (c) 2025 Balázs Dura-Kovács
|
||||||
|
|
||||||
darktable is free software: you can redistribute it and/or modify
|
darktable is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -28,24 +29,30 @@ require "geoToolbox"
|
|||||||
local dt = require "darktable"
|
local dt = require "darktable"
|
||||||
local du = require "lib/dtutils"
|
local du = require "lib/dtutils"
|
||||||
local df = require "lib/dtutils.file"
|
local df = require "lib/dtutils.file"
|
||||||
local gettext = dt.gettext
|
local dtsys = require "lib/dtutils.system"
|
||||||
|
local gettext = dt.gettext.gettext
|
||||||
|
|
||||||
du.check_min_api_version("7.0.0", "geoToolbox")
|
du.check_min_api_version("7.0.0", "geoToolbox")
|
||||||
|
|
||||||
|
local function _(msgid)
|
||||||
|
return gettext(msgid)
|
||||||
|
end
|
||||||
|
|
||||||
-- return data structure for script_manager
|
-- return data structure for script_manager
|
||||||
|
|
||||||
local script_data = {}
|
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 = 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.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.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("geoToolbox",dt.configuration.config_dir.."/lua/locale/")
|
|
||||||
|
|
||||||
local function _(msgid)
|
|
||||||
return gettext.dgettext("geoToolbox", msgid)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
local gT = {}
|
local gT = {}
|
||||||
@@ -55,23 +62,35 @@ gT.event_registered = false
|
|||||||
|
|
||||||
-- <GUI>
|
-- <GUI>
|
||||||
local labelDistance = dt.new_widget("label")
|
local labelDistance = dt.new_widget("label")
|
||||||
labelDistance.label = _("Distance:")
|
labelDistance.label = _("distance:")
|
||||||
|
|
||||||
local label_copy_gps_lat = dt.new_widget("check_button")
|
local checkbox_copy_gps_lat = dt.new_widget("check_button")
|
||||||
{
|
{
|
||||||
label = _("latitude:"),
|
|
||||||
value = true
|
value = true
|
||||||
}
|
}
|
||||||
local label_copy_gps_lon = dt.new_widget("check_button")
|
local entry_gps_lat = dt.new_widget("entry")
|
||||||
|
{
|
||||||
|
tooltip = _("latitude (editable)"),
|
||||||
|
placeholder = _("latitude")
|
||||||
|
}
|
||||||
|
local checkbox_copy_gps_lon = dt.new_widget("check_button")
|
||||||
{
|
{
|
||||||
label = _("longitude:"),
|
|
||||||
value = true
|
value = true
|
||||||
}
|
}
|
||||||
local label_copy_gps_ele = dt.new_widget("check_button")
|
local entry_gps_lon = dt.new_widget("entry")
|
||||||
|
{
|
||||||
|
tooltip = _("longitude (editable)"),
|
||||||
|
placeholder = _("longitude")
|
||||||
|
}
|
||||||
|
local checkbox_copy_gps_ele = dt.new_widget("check_button")
|
||||||
{
|
{
|
||||||
label = _("elevation:"),
|
|
||||||
value = true
|
value = true
|
||||||
}
|
}
|
||||||
|
local entry_gps_ele = dt.new_widget("entry")
|
||||||
|
{
|
||||||
|
tooltip = _("elevation (editable)"),
|
||||||
|
placeholder = _("elevation")
|
||||||
|
}
|
||||||
-- </GUI>
|
-- </GUI>
|
||||||
|
|
||||||
local function select_with_gps()
|
local function select_with_gps()
|
||||||
@@ -161,7 +180,7 @@ local function get_first_coordinate()
|
|||||||
first_elevation = ''
|
first_elevation = ''
|
||||||
first_image_date = 0
|
first_image_date = 0
|
||||||
|
|
||||||
for _,image in ipairs(sel_images) do
|
for jj,image in ipairs(sel_images) do
|
||||||
if not image then
|
if not image then
|
||||||
first_have_data = false
|
first_have_data = false
|
||||||
else
|
else
|
||||||
@@ -200,7 +219,7 @@ local function get_second_coordinate()
|
|||||||
second_elevation = ''
|
second_elevation = ''
|
||||||
second_image_date = 0
|
second_image_date = 0
|
||||||
|
|
||||||
for _,image in ipairs(sel_images) do
|
for jj,image in ipairs(sel_images) do
|
||||||
if not image then
|
if not image then
|
||||||
second_have_data = false
|
second_have_data = false
|
||||||
else
|
else
|
||||||
@@ -236,7 +255,7 @@ local calc_in_between_slider = dt.new_widget("slider")
|
|||||||
--ToDo: this needs more love
|
--ToDo: this needs more love
|
||||||
local function calc_in_between()
|
local function calc_in_between()
|
||||||
local sel_images = dt.gui.action_images
|
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
|
if image then
|
||||||
image_date = make_time_stamp(image.exif_datetime_taken)
|
image_date = make_time_stamp(image.exif_datetime_taken)
|
||||||
if (first_have_data and second_have_data) then
|
if (first_have_data and second_have_data) then
|
||||||
@@ -283,25 +302,25 @@ local function copy_gps()
|
|||||||
copy_gps_longitude = ''
|
copy_gps_longitude = ''
|
||||||
copy_gps_elevation = ''
|
copy_gps_elevation = ''
|
||||||
|
|
||||||
for _,image in ipairs(sel_images) do
|
for jj,image in ipairs(sel_images) do
|
||||||
if not image then
|
if not image then
|
||||||
copy_gps_have_data = false
|
copy_gps_have_data = false
|
||||||
else
|
else
|
||||||
copy_gps_have_data = true
|
copy_gps_have_data = true
|
||||||
if (image.latitude and label_copy_gps_lat.value) then
|
if (image.latitude and checkbox_copy_gps_lat.value) then
|
||||||
copy_gps_latitude = image.latitude
|
copy_gps_latitude = image.latitude
|
||||||
end
|
end
|
||||||
if (image.longitude and label_copy_gps_lon.value) then
|
if (image.longitude and checkbox_copy_gps_lon.value) then
|
||||||
copy_gps_longitude = image.longitude
|
copy_gps_longitude = image.longitude
|
||||||
end
|
end
|
||||||
if (image.elevation and label_copy_gps_ele.value) then
|
if (image.elevation and checkbox_copy_gps_ele.value) then
|
||||||
copy_gps_elevation = image.elevation
|
copy_gps_elevation = image.elevation
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
label_copy_gps_lat.label = _("latitude: ") .. copy_gps_latitude
|
entry_gps_lat.text = copy_gps_latitude
|
||||||
label_copy_gps_lon.label = _("longitude: ") ..copy_gps_longitude
|
entry_gps_lon.text = copy_gps_longitude
|
||||||
label_copy_gps_ele.label = _("elevation: ") .. copy_gps_elevation
|
entry_gps_ele.text = copy_gps_elevation
|
||||||
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
@@ -310,15 +329,15 @@ end
|
|||||||
local function paste_gps(image)
|
local function paste_gps(image)
|
||||||
local sel_images = dt.gui.action_images
|
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
|
if (checkbox_copy_gps_lat.value) then
|
||||||
image.latitude = copy_gps_latitude
|
image.latitude = entry_gps_lat.text
|
||||||
end
|
end
|
||||||
if (label_copy_gps_lon.value) then
|
if (checkbox_copy_gps_lon.value) then
|
||||||
image.longitude = copy_gps_longitude
|
image.longitude = entry_gps_lon.text
|
||||||
end
|
end
|
||||||
if (label_copy_gps_ele.value) then
|
if (checkbox_copy_gps_ele.value) then
|
||||||
image.elevation = copy_gps_elevation
|
image.elevation = entry_gps_ele.text
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -337,7 +356,7 @@ local function open_location_in_gnome_maps()
|
|||||||
local i = 0;
|
local i = 0;
|
||||||
|
|
||||||
-- Use the first image with geo information
|
-- 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
|
if ((image.longitude and image.latitude) and
|
||||||
(image.longitude ~= 0 and image.latitude ~= 90) -- Sometimes the north-pole but most likely just wrong data
|
(image.longitude ~= 0 and image.latitude ~= 90) -- Sometimes the north-pole but most likely just wrong data
|
||||||
) then
|
) then
|
||||||
@@ -364,12 +383,12 @@ end
|
|||||||
local function reverse_geocode()
|
local function reverse_geocode()
|
||||||
|
|
||||||
if not df.check_if_bin_exists("curl") then
|
if not df.check_if_bin_exists("curl") then
|
||||||
dt.print_error(_("curl not found"))
|
dt.print_error("curl not found")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
if not df.check_if_bin_exists("jq") then
|
if not df.check_if_bin_exists("jq") then
|
||||||
dt.print_error(_("jq not found"))
|
dt.print_error("jq not found")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -380,7 +399,7 @@ local function reverse_geocode()
|
|||||||
local i = 0;
|
local i = 0;
|
||||||
|
|
||||||
-- Use the first image with geo information
|
-- 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
|
if ((image.longitude and image.latitude) and
|
||||||
(image.longitude ~= 0 and image.latitude ~= 90) -- Sometimes the north-pole but most likely just wrong data
|
(image.longitude ~= 0 and image.latitude ~= 90) -- Sometimes the north-pole but most likely just wrong data
|
||||||
) then
|
) then
|
||||||
@@ -455,7 +474,7 @@ local function calc_distance()
|
|||||||
|
|
||||||
local sel_images = dt.gui.selection()
|
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
|
if ((image.longitude and image.latitude) and
|
||||||
(image.longitude ~= 0 and image.latitude ~= 90) -- Sometimes the north-pole but most likely just wrong data
|
(image.longitude ~= 0 and image.latitude ~= 90) -- Sometimes the north-pole but most likely just wrong data
|
||||||
) then
|
) then
|
||||||
@@ -487,12 +506,12 @@ local function calc_distance()
|
|||||||
|
|
||||||
if (distance < 1) then
|
if (distance < 1) then
|
||||||
distance = distance * 1000
|
distance = distance * 1000
|
||||||
distanceUnit = _("m")
|
distanceUnit = "m"
|
||||||
else
|
else
|
||||||
distanceUnit = _("km")
|
distanceUnit = "km"
|
||||||
end
|
end
|
||||||
|
|
||||||
return string.format(_("Distance: %.2f %s"), distance, distanceUnit)
|
return string.format(_("distance: %.2f %s"), distance, distanceUnit)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function print_calc_distance()
|
local function print_calc_distance()
|
||||||
@@ -515,12 +534,12 @@ local altitude_filename = dt.new_widget("entry")
|
|||||||
text = "altitude.csv",
|
text = "altitude.csv",
|
||||||
placeholder = "altitude.csv",
|
placeholder = "altitude.csv",
|
||||||
editable = true,
|
editable = true,
|
||||||
tooltip = _("Name of the exported file"),
|
tooltip = _("name of the exported file"),
|
||||||
reset_callback = function(self) self.text = "text" end
|
reset_callback = function(self) self.text = "text" end
|
||||||
}
|
}
|
||||||
|
|
||||||
local function altitude_profile()
|
local function altitude_profile()
|
||||||
dt.print(_("Start export"))
|
dt.print(_("start export"))
|
||||||
local sel_images = dt.gui.action_images
|
local sel_images = dt.gui.action_images
|
||||||
|
|
||||||
local lat1 = 0;
|
local lat1 = 0;
|
||||||
@@ -539,7 +558,7 @@ local function altitude_profile()
|
|||||||
local elevationAdd = 0;
|
local elevationAdd = 0;
|
||||||
|
|
||||||
local sel_images = dt.gui.action_images
|
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
|
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
|
(image.longitude ~= 0 and image.latitude ~= 90) -- Sometimes the north-pole but most likely just wrong data
|
||||||
) then
|
) then
|
||||||
@@ -581,7 +600,7 @@ local function altitude_profile()
|
|||||||
file = io.open(exportDirectory.."/"..exportFilename, "w")
|
file = io.open(exportDirectory.."/"..exportFilename, "w")
|
||||||
file:write(csv_file)
|
file:write(csv_file)
|
||||||
file:close()
|
file:close()
|
||||||
dt.print(_("File created in ")..exportDirectory)
|
dt.print(string.format(_("file created in %s"), exportDirectory))
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -589,7 +608,7 @@ local function install_module()
|
|||||||
if not gT.module_installed then
|
if not gT.module_installed then
|
||||||
dt.register_lib(
|
dt.register_lib(
|
||||||
"geoToolbox", -- Module name
|
"geoToolbox", -- Module name
|
||||||
"geo toolbox", -- name
|
_("geo toolbox"), -- name
|
||||||
true, -- expandable
|
true, -- expandable
|
||||||
false, -- resetable
|
false, -- resetable
|
||||||
{[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, -- containers
|
{[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, -- containers
|
||||||
@@ -611,14 +630,14 @@ end
|
|||||||
|
|
||||||
local function restart()
|
local function restart()
|
||||||
dt.register_event("geoToolbox_cd", "shortcut",
|
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",
|
dt.register_event("geoToolbox", "mouse-over-image-changed",
|
||||||
toolbox_calc_distance)
|
toolbox_calc_distance)
|
||||||
|
|
||||||
dt.register_event("geoToolbox_wg", "shortcut",
|
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",
|
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
|
dt.gui.libs["geoToolbox"].visible = true
|
||||||
end
|
end
|
||||||
@@ -641,29 +660,41 @@ gT.widget = dt.new_widget("box")
|
|||||||
dt.new_widget("button")
|
dt.new_widget("button")
|
||||||
{
|
{
|
||||||
label = _("select geo images"),
|
label = _("select geo images"),
|
||||||
tooltip = _("Select all images with GPS information"),
|
tooltip = _("select all images with GPS information"),
|
||||||
clicked_callback = select_with_gps
|
clicked_callback = select_with_gps
|
||||||
},
|
},
|
||||||
dt.new_widget("button")
|
dt.new_widget("button")
|
||||||
{
|
{
|
||||||
label = _("select non-geo images"),
|
label = _("select non-geo images"),
|
||||||
tooltip = _("Select all images without GPS information"),
|
tooltip = _("select all images without GPS information"),
|
||||||
clicked_callback = select_without_gps
|
clicked_callback = select_without_gps
|
||||||
},
|
},
|
||||||
separator,--------------------------------------------------------
|
separator,--------------------------------------------------------
|
||||||
dt.new_widget("button")
|
dt.new_widget("button")
|
||||||
{
|
{
|
||||||
label = _("copy GPS data"),
|
label = _("copy GPS data"),
|
||||||
tooltip = _("Copy GPS data"),
|
tooltip = _("copy GPS data"),
|
||||||
clicked_callback = copy_gps
|
clicked_callback = copy_gps
|
||||||
},
|
},
|
||||||
label_copy_gps_lat,
|
dt.new_widget("box"){
|
||||||
label_copy_gps_lon,
|
orientation = "horizontal",
|
||||||
label_copy_gps_ele,
|
checkbox_copy_gps_lat,
|
||||||
|
entry_gps_lat
|
||||||
|
},
|
||||||
|
dt.new_widget("box"){
|
||||||
|
orientation = "horizontal",
|
||||||
|
checkbox_copy_gps_lon,
|
||||||
|
entry_gps_lon
|
||||||
|
},
|
||||||
|
dt.new_widget("box"){
|
||||||
|
orientation = "horizontal",
|
||||||
|
checkbox_copy_gps_ele,
|
||||||
|
entry_gps_ele
|
||||||
|
},
|
||||||
dt.new_widget("button")
|
dt.new_widget("button")
|
||||||
{
|
{
|
||||||
label = _("paste GPS data"),
|
label = _("apply GPS data to image"),
|
||||||
tooltip = _("Paste GPS data"),
|
tooltip = _("apply GPS data to image"),
|
||||||
clicked_callback = paste_gps
|
clicked_callback = paste_gps
|
||||||
},
|
},
|
||||||
separator2,--------------------------------------------------------
|
separator2,--------------------------------------------------------
|
||||||
@@ -693,14 +724,14 @@ gT.widget = dt.new_widget("box")
|
|||||||
dt.new_widget("button")
|
dt.new_widget("button")
|
||||||
{
|
{
|
||||||
label = _("open in Gnome Maps"),
|
label = _("open in Gnome Maps"),
|
||||||
tooltip = _("Open location in Gnome Maps"),
|
tooltip = _("open location in Gnome Maps"),
|
||||||
clicked_callback = open_location_in_gnome_maps
|
clicked_callback = open_location_in_gnome_maps
|
||||||
},
|
},
|
||||||
separator4,--------------------------------------------------------
|
separator4,--------------------------------------------------------
|
||||||
dt.new_widget("button")
|
dt.new_widget("button")
|
||||||
{
|
{
|
||||||
label = _("reverse geocode"),
|
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
|
clicked_callback = reverse_geocode
|
||||||
},
|
},
|
||||||
separator5,--------------------------------------------------------
|
separator5,--------------------------------------------------------
|
||||||
@@ -710,7 +741,7 @@ gT.widget = dt.new_widget("box")
|
|||||||
dt.new_widget("button")
|
dt.new_widget("button")
|
||||||
{
|
{
|
||||||
label = _("export altitude CSV file"),
|
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
|
clicked_callback = altitude_profile
|
||||||
},
|
},
|
||||||
labelDistance
|
labelDistance
|
||||||
@@ -738,19 +769,19 @@ dt.preferences.register("geoToolbox",
|
|||||||
"mapBoxKey",
|
"mapBoxKey",
|
||||||
"string",
|
"string",
|
||||||
_("geoToolbox export: MapBox Key"),
|
_("geoToolbox export: MapBox Key"),
|
||||||
_("https://www.mapbox.com/studio/account/tokens"),
|
"https://www.mapbox.com/studio/account/tokens",
|
||||||
'' )
|
'' )
|
||||||
|
|
||||||
-- Register
|
-- Register
|
||||||
dt.register_event("geoToolbox_cd", "shortcut",
|
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",
|
dt.register_event("geoToolbox", "mouse-over-image-changed",
|
||||||
toolbox_calc_distance)
|
toolbox_calc_distance)
|
||||||
|
|
||||||
dt.register_event("geoToolbox_wg", "shortcut",
|
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",
|
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.destroy = destroy
|
||||||
script_data.restart = restart
|
script_data.restart = restart
|
||||||
|
|||||||
@@ -69,25 +69,30 @@ local dt = require "darktable"
|
|||||||
local du = require "lib/dtutils"
|
local du = require "lib/dtutils"
|
||||||
local df = require "lib/dtutils.file"
|
local df = require "lib/dtutils.file"
|
||||||
local dtsys = require "lib/dtutils.system"
|
local dtsys = require "lib/dtutils.system"
|
||||||
local gettext = dt.gettext
|
local gettext = dt.gettext.gettext
|
||||||
local gimp_widget = nil
|
local gimp_widget = nil
|
||||||
|
|
||||||
du.check_min_api_version("7.0.0", "gimp")
|
du.check_min_api_version("7.0.0", "gimp")
|
||||||
|
|
||||||
|
local function _(msgid)
|
||||||
|
return gettext(msgid)
|
||||||
|
end
|
||||||
|
|
||||||
-- return data structure for script_manager
|
-- return data structure for script_manager
|
||||||
|
|
||||||
local script_data = {}
|
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 = 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.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.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("gimp",dt.configuration.config_dir.."/lua/locale/")
|
|
||||||
|
|
||||||
local function _(msgid)
|
|
||||||
return gettext.dgettext("gimp", msgid)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function group_if_not_member(img, new_img)
|
local function group_if_not_member(img, new_img)
|
||||||
local image_table = img:get_group_members()
|
local image_table = img:get_group_members()
|
||||||
@@ -108,7 +113,7 @@ end
|
|||||||
|
|
||||||
local function show_status(storage, image, format, filename,
|
local function show_status(storage, image, format, filename,
|
||||||
number, total, high_quality, extra_data)
|
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
|
end
|
||||||
|
|
||||||
local function gimp_edit(storage, image_table, extra_data) --finalize
|
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")
|
local gimp_executable = df.check_if_bin_exists("gimp")
|
||||||
|
|
||||||
if not gimp_executable then
|
if not gimp_executable then
|
||||||
dt.print_error(_("GIMP not found"))
|
dt.print_error("GIMP not found")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -141,7 +146,7 @@ local function gimp_edit(storage, image_table, extra_data) --finalize
|
|||||||
img_list = img_list ..exp_img.. " "
|
img_list = img_list ..exp_img.. " "
|
||||||
end
|
end
|
||||||
|
|
||||||
dt.print(_("Launching GIMP..."))
|
dt.print(_("launching GIMP..."))
|
||||||
|
|
||||||
local gimpStartCommand
|
local gimpStartCommand
|
||||||
gimpStartCommand = gimp_executable .. " " .. img_list
|
gimpStartCommand = gimp_executable .. " " .. img_list
|
||||||
@@ -212,7 +217,7 @@ gimp_widget = dt.new_widget("check_button"){
|
|||||||
end
|
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
|
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 dt = require "darktable"
|
||||||
local df = require "lib/dtutils.file"
|
local df = require "lib/dtutils.file"
|
||||||
local dl = require "lib/dtutils"
|
local dl = require "lib/dtutils"
|
||||||
local gettext = dt.gettext
|
local gettext = dt.gettext.gettext
|
||||||
|
|
||||||
dl.check_min_api_version("7.0.0", "gpx_export")
|
dl.check_min_api_version("7.0.0", "gpx_export")
|
||||||
|
|
||||||
|
local function _(msgid)
|
||||||
|
return gettext(msgid)
|
||||||
|
end
|
||||||
|
|
||||||
-- return data structure for script_manager
|
-- return data structure for script_manager
|
||||||
|
|
||||||
local script_data = {}
|
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 = 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.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.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("gpx_export",dt.configuration.config_dir.."/lua/locale/")
|
|
||||||
|
|
||||||
local function _(msgid)
|
|
||||||
return gettext.dgettext("gpx_export", msgid)
|
|
||||||
end
|
|
||||||
|
|
||||||
local gpx = {}
|
local gpx = {}
|
||||||
gpx.module_installed = false
|
gpx.module_installed = false
|
||||||
@@ -131,11 +136,11 @@ local function create_gpx_file()
|
|||||||
|
|
||||||
local file = io.open(path, "w")
|
local file = io.open(path, "w")
|
||||||
if (file == nil) then
|
if (file == nil) then
|
||||||
dt.print(_("invalid path: ")..path)
|
dt.print(string.format(_("invalid path: %s"), path))
|
||||||
else
|
else
|
||||||
file:write(gpx_file)
|
file:write(gpx_file)
|
||||||
file:close()
|
file:close()
|
||||||
dt.print(_("gpx file created: ")..path)
|
dt.print(string.format(_("gpx file created: "), path))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -143,7 +148,7 @@ local function install_module()
|
|||||||
if not gpx.module_installed then
|
if not gpx.module_installed then
|
||||||
dt.register_lib(
|
dt.register_lib(
|
||||||
"gpx_exporter",
|
"gpx_exporter",
|
||||||
"gpx export",
|
_("gpx export"),
|
||||||
true, -- expandable
|
true, -- expandable
|
||||||
true, -- resetable
|
true, -- resetable
|
||||||
{[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, -- containers
|
{[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, -- containers
|
||||||
@@ -203,5 +208,6 @@ end
|
|||||||
script_data.destroy = destroy
|
script_data.destroy = destroy
|
||||||
script_data.restart = restart
|
script_data.restart = restart
|
||||||
script_data.destroy_method = "hide"
|
script_data.destroy_method = "hide"
|
||||||
|
script_data.show = restart
|
||||||
|
|
||||||
return script_data
|
return script_data
|
||||||
|
|||||||
@@ -32,17 +32,28 @@ USAGE
|
|||||||
|
|
||||||
local dt = require "darktable"
|
local dt = require "darktable"
|
||||||
local du = require "lib/dtutils"
|
local du = require "lib/dtutils"
|
||||||
local gettext = dt.gettext
|
local gettext = dt.gettext.gettext
|
||||||
|
|
||||||
du.check_min_api_version("2.0.0", "harmonic_armature_guide")
|
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)
|
local function _(msgid)
|
||||||
return gettext.dgettext("harmonic_armature_guide", msgid)
|
return gettext(msgid)
|
||||||
end
|
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",
|
dt.guides.register_guide("harmonic armature",
|
||||||
-- draw
|
-- draw
|
||||||
function(cairo, x, y, width, height, zoom_scale)
|
function(cairo, x, y, width, height, zoom_scale)
|
||||||
@@ -75,4 +86,12 @@ end,
|
|||||||
function()
|
function()
|
||||||
return dt.new_widget("label"){label = _("harmonic armature"), halign = "start"}
|
return dt.new_widget("label"){label = _("harmonic armature"), halign = "start"}
|
||||||
end
|
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 df = require "lib/dtutils.file"
|
||||||
local log = require "lib/dtutils.log"
|
local log = require "lib/dtutils.log"
|
||||||
local dtsys = require "lib/dtutils.system"
|
local dtsys = require "lib/dtutils.system"
|
||||||
local gettext = dt.gettext
|
local gettext = dt.gettext.gettext
|
||||||
|
|
||||||
local namespace = 'module_hugin'
|
local namespace = 'module_hugin'
|
||||||
local user_pref_str = 'prefer_gui'
|
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
|
-- works with darktable API version from 5.0.0 on
|
||||||
du.check_min_api_version("7.0.0", "hugin")
|
du.check_min_api_version("7.0.0", "hugin")
|
||||||
|
|
||||||
|
local function _(msgid)
|
||||||
|
return gettext(msgid)
|
||||||
|
end
|
||||||
|
|
||||||
-- return data structure for script_manager
|
-- return data structure for script_manager
|
||||||
|
|
||||||
local script_data = {}
|
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 = 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.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.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("hugin",dt.configuration.config_dir.."/lua/locale/")
|
|
||||||
|
|
||||||
local function _(msgid)
|
|
||||||
return gettext.dgettext("hugin", msgid)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function user_preference_changed(widget)
|
local function user_preference_changed(widget)
|
||||||
user_prefer_gui = widget.value
|
user_prefer_gui = widget.value
|
||||||
@@ -78,7 +83,7 @@ end
|
|||||||
|
|
||||||
local function show_status(storage, image, format, filename,
|
local function show_status(storage, image, format, filename,
|
||||||
number, total, high_quality, extra_data)
|
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
|
end
|
||||||
|
|
||||||
local function create_panorama(storage, image_table, extra_data) --finalize
|
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
|
end
|
||||||
|
|
||||||
if first_file == nil then
|
if first_file == nil then
|
||||||
dt.print("no file selected")
|
dt.print(_("no file selected"))
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -200,7 +205,7 @@ local function create_panorama(storage, image_table, extra_data) --finalize
|
|||||||
if df.check_if_file_exists(src_path) then
|
if df.check_if_file_exists(src_path) then
|
||||||
log.msg(log.debug, "found ", src_path, " importing to ", dst_path)
|
log.msg(log.debug, "found ", src_path, " importing to ", dst_path)
|
||||||
df.file_move(src_path, 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)
|
dt.database.import(dst_path)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -226,7 +231,7 @@ hugin_widget = dt.new_widget("box") {
|
|||||||
orientation = "vertical",
|
orientation = "vertical",
|
||||||
dt.new_widget("check_button")
|
dt.new_widget("check_button")
|
||||||
{
|
{
|
||||||
label = _(" launch hugin gui"),
|
label = _("launch hugin gui"),
|
||||||
value = user_prefer_gui,
|
value = user_prefer_gui,
|
||||||
tooltip = _('launch hugin in gui mode'),
|
tooltip = _('launch hugin in gui mode'),
|
||||||
clicked_callback = user_preference_changed
|
clicked_callback = user_preference_changed
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ local dt = require "darktable"
|
|||||||
local du = require "lib/dtutils"
|
local du = require "lib/dtutils"
|
||||||
local df = require "lib/dtutils.file"
|
local df = require "lib/dtutils.file"
|
||||||
local dtsys = require "lib/dtutils.system"
|
local dtsys = require "lib/dtutils.system"
|
||||||
local gettext = dt.gettext
|
local gettext = dt.gettext.gettext
|
||||||
local job = nil
|
local job = nil
|
||||||
|
|
||||||
-- path separator constant
|
-- path separator constant
|
||||||
@@ -73,20 +73,25 @@ local PS = dt.configuration.running_os == "windows" and "\\" or "/"
|
|||||||
-- works with LUA API version 5.0.0
|
-- works with LUA API version 5.0.0
|
||||||
du.check_min_api_version("7.0.0", "image_stack")
|
du.check_min_api_version("7.0.0", "image_stack")
|
||||||
|
|
||||||
|
local function _(msgid)
|
||||||
|
return gettext(msgid)
|
||||||
|
end
|
||||||
|
|
||||||
-- return data structure for script_manager
|
-- return data structure for script_manager
|
||||||
|
|
||||||
local script_data = {}
|
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 = 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.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.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_stack",dt.configuration.config_dir.."/lua/locale/")
|
|
||||||
|
|
||||||
local function _(msgid)
|
|
||||||
return gettext.dgettext("image_stack", msgid)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
-- GUI definitions
|
-- GUI definitions
|
||||||
@@ -134,19 +139,19 @@ local chkbtn_will_align = dt.new_widget("check_button"){
|
|||||||
local chkbtn_radial_distortion = dt.new_widget("check_button"){
|
local chkbtn_radial_distortion = dt.new_widget("check_button"){
|
||||||
label = _('optimize radial distortion for all images'),
|
label = _('optimize radial distortion for all images'),
|
||||||
value = dt.preferences.read("align_image_stack", "def_radial_distortion", "bool"),
|
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"){
|
local chkbtn_optimize_field = dt.new_widget("check_button"){
|
||||||
label = _('optimize field of view for all images'),
|
label = _('optimize field of view for all images'),
|
||||||
value = dt.preferences.read("align_image_stack", "def_optimize_field", "bool"),
|
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"){
|
local chkbtn_optimize_image_center = dt.new_widget("check_button"){
|
||||||
label = _('optimize image center shift for all images'),
|
label = _('optimize image center shift for all images'),
|
||||||
value = dt.preferences.read("align_image_stack", "def_optimize_image_center", "bool"),
|
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"){
|
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)
|
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
|
end
|
||||||
|
|
||||||
-- read the gui and populate the align_image_stack arguments
|
-- 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.rights = from.rights
|
||||||
to.description = from.description
|
to.description = from.description
|
||||||
else
|
else
|
||||||
dt.print_error(_("Unrecognized option to copy_image_attributes: " .. arg))
|
dt.print_error("Unrecognized option to copy_image_attributes: " .. arg)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -495,11 +500,11 @@ local function image_stack(storage, image_table, extra_data)
|
|||||||
|
|
||||||
if image_count < 2 then
|
if image_count < 2 then
|
||||||
dt.print(_("ERROR: at least 2 images required for image stacking, exiting..."))
|
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
|
return
|
||||||
end
|
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
|
job.percent = job.percent + percent_step
|
||||||
|
|
||||||
-- align images if requested
|
-- align images if requested
|
||||||
@@ -519,13 +524,13 @@ local function image_stack(storage, image_table, extra_data)
|
|||||||
job.percent = job.percent + percent_step
|
job.percent = job.percent + percent_step
|
||||||
else
|
else
|
||||||
dt.print(_("ERROR: image alignment failed"))
|
dt.print(_("ERROR: image alignment failed"))
|
||||||
dt.print_error(_("image alignment failed"))
|
dt.print_error("image alignment failed")
|
||||||
cleanup(img_list)
|
cleanup(img_list)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
else
|
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"))
|
dt.print_error("align_image_stack not found")
|
||||||
cleanup(img_list)
|
cleanup(img_list)
|
||||||
return
|
return
|
||||||
end
|
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 "
|
local ignore_tif_tags = " -quiet -define tiff:ignore-tags=40965,42032,42033,42034,42036,18246,18249,36867,34864,34866 "
|
||||||
if convert_executable then
|
if convert_executable then
|
||||||
local convert_command = convert_executable .. ignore_tif_tags .. convert_arguments
|
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"))
|
dt.print(_("processing image stack"))
|
||||||
local result = dtsys.external_command(convert_command)
|
local result = dtsys.external_command(convert_command)
|
||||||
if result == 0 then
|
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))
|
local import_filename = df.create_unique_filename(film_roll_path .. PS .. df.get_filename(output_filename))
|
||||||
df.file_move(output_filename, import_filename)
|
df.file_move(output_filename, import_filename)
|
||||||
imported_image = dt.database.import(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)
|
dt.tags.attach(created_tag, imported_image)
|
||||||
-- all the images are the same except for time, so just copy the attributes
|
-- all the images are the same except for time, so just copy the attributes
|
||||||
-- from the first
|
-- from the first
|
||||||
@@ -567,7 +572,7 @@ local function image_stack(storage, image_table, extra_data)
|
|||||||
|
|
||||||
if tag_source then
|
if tag_source then
|
||||||
dt.print(_("tagging source images"))
|
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
|
for img, _ in pairs(image_table) do
|
||||||
dt.tags.attach(source_tag, img)
|
dt.tags.attach(source_tag, img)
|
||||||
end
|
end
|
||||||
@@ -579,7 +584,7 @@ local function image_stack(storage, image_table, extra_data)
|
|||||||
end
|
end
|
||||||
else
|
else
|
||||||
dt.print(_("ERROR: convert executable not found"))
|
dt.print(_("ERROR: convert executable not found"))
|
||||||
dt.print_error(_("convert executable not found"))
|
dt.print_error("convert executable not found")
|
||||||
cleanup(img_list)
|
cleanup(img_list)
|
||||||
end
|
end
|
||||||
job.valid = false
|
job.valid = false
|
||||||
@@ -591,7 +596,7 @@ end
|
|||||||
|
|
||||||
dt.preferences.register("align_image_stack", "align_use_gpu", -- name
|
dt.preferences.register("align_image_stack", "align_use_gpu", -- name
|
||||||
"bool", -- type
|
"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
|
_('set the GPU remapping for image align'), -- tooltip
|
||||||
false)
|
false)
|
||||||
|
|
||||||
|
|||||||
@@ -107,7 +107,8 @@ local dt = require "darktable"
|
|||||||
local du = require "lib/dtutils"
|
local du = require "lib/dtutils"
|
||||||
local df = require "lib/dtutils.file"
|
local df = require "lib/dtutils.file"
|
||||||
local ds = require "lib/dtutils.string"
|
local ds = require "lib/dtutils.string"
|
||||||
local gettext = dt.gettext
|
local dtsys = require "lib/dtutils.system"
|
||||||
|
local gettext = dt.gettext.gettext
|
||||||
|
|
||||||
local img_time = {}
|
local img_time = {}
|
||||||
img_time.module_installed = false
|
img_time.module_installed = false
|
||||||
@@ -115,21 +116,27 @@ img_time.event_registered = false
|
|||||||
|
|
||||||
du.check_min_api_version("7.0.0", "image_time")
|
du.check_min_api_version("7.0.0", "image_time")
|
||||||
|
|
||||||
|
local function _(msgid)
|
||||||
|
return gettext(msgid)
|
||||||
|
end
|
||||||
|
|
||||||
-- return data structure for script_manager
|
-- return data structure for script_manager
|
||||||
|
|
||||||
local script_data = {}
|
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 = 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.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.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 PS = dt.configuration.runnin_os == "windows" and "\\" or "/"
|
||||||
local ERROR = -1
|
local ERROR = -1
|
||||||
@@ -147,12 +154,12 @@ local function systime2exiftime(systime)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local function vars2exiftime(year, month, day, hour, min, sec)
|
local function vars2exiftime(year, month, day, hour, min, sec)
|
||||||
local y = tonumber(year) and string.format("%4d", year) or " "
|
local y = tonumber(year) and string.format("%4d", year) or "0000"
|
||||||
local mo = tonumber(month) and string.format("%02d", month) or " "
|
local mo = tonumber(month) and string.format("%02d", month) or "00"
|
||||||
local d = tonumber(day) and string.format("%02d", day) or " "
|
local d = tonumber(day) and string.format("%02d", day) or "00"
|
||||||
local h = tonumber(hour) and string.format("%02d", hour) or " "
|
local h = tonumber(hour) and string.format("%02d", hour) or "00"
|
||||||
local m = tonumber(min) and string.format("%02d", min) or " "
|
local m = tonumber(min) and string.format("%02d", min) or "00"
|
||||||
local s = tonumber(sec) and string.format("%02d", sec) or " "
|
local s = tonumber(sec) and string.format("%02d", sec) or "00"
|
||||||
return(y .. ":" .. mo .. ":" .. d .. " " .. h .. ":" .. m .. ":" .. s)
|
return(y .. ":" .. mo .. ":" .. d .. " " .. h .. ":" .. m .. ":" .. s)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -174,7 +181,7 @@ local function calculate_difference(images)
|
|||||||
img_time.diff_entry.text = calc_time_difference(images[1], images[2])
|
img_time.diff_entry.text = calc_time_difference(images[1], images[2])
|
||||||
img_time.btn.sensitive = true
|
img_time.btn.sensitive = true
|
||||||
else
|
else
|
||||||
dt.print(_("Error: 2 images must be selected"))
|
dt.print(_("ERROR: 2 images must be selected"))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -186,7 +193,7 @@ end
|
|||||||
|
|
||||||
local function synchronize_time(images)
|
local function synchronize_time(images)
|
||||||
local sign = 1
|
local sign = 1
|
||||||
if img_time.sdir.value == "subtract" then
|
if img_time.sdir.value == _("subtract") then
|
||||||
sign = -1
|
sign = -1
|
||||||
end
|
end
|
||||||
synchronize_times(images, tonumber(img_time.diff_entry.text) * sign)
|
synchronize_times(images, tonumber(img_time.diff_entry.text) * sign)
|
||||||
@@ -248,7 +255,7 @@ local function _get_windows_image_file_creation_time(image)
|
|||||||
end
|
end
|
||||||
p:close()
|
p:close()
|
||||||
else
|
else
|
||||||
dt.print(_("unable to get information for ") .. image.filename)
|
dt.print(string.format(_("unable to get information for %s"), image.filename))
|
||||||
datetime = ERROR
|
datetime = ERROR
|
||||||
end
|
end
|
||||||
return datetime
|
return datetime
|
||||||
@@ -265,7 +272,7 @@ local function _get_nix_image_file_creation_time(image)
|
|||||||
end
|
end
|
||||||
p:close()
|
p:close()
|
||||||
else
|
else
|
||||||
dt.print(_("unable to get information for ") .. image.filename)
|
dt.print(string.format(_("unable to get information for %s"), image.filename))
|
||||||
datetime = ERROR
|
datetime = ERROR
|
||||||
end
|
end
|
||||||
return datetime
|
return datetime
|
||||||
@@ -313,7 +320,7 @@ local function reset_time(images)
|
|||||||
image.exif_datetime_taken = get_original_image_time(image)
|
image.exif_datetime_taken = get_original_image_time(image)
|
||||||
end
|
end
|
||||||
else
|
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"))
|
dt.print(_("please select the images that need their time reset"))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -429,8 +436,8 @@ end
|
|||||||
img_time.widgets = {
|
img_time.widgets = {
|
||||||
-- name, type, tooltip, placeholder,
|
-- name, type, tooltip, placeholder,
|
||||||
{"ayr", "combobox", _("years"), _("years to adjust by, 0 - ?"), {seq(0,20)}, 1},
|
{"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},
|
{"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},
|
{"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},
|
{"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},
|
{"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},
|
{"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.syr.selected = #img_time.syr
|
||||||
|
|
||||||
img_time.diff_entry = dt.new_widget("entry"){
|
img_time.diff_entry = dt.new_widget("entry"){
|
||||||
tooltip = _("Time difference between images in seconds"),
|
tooltip = _("time difference between images in seconds"),
|
||||||
placeholder = _("Select 2 images and use the calculate button"),
|
placeholder = _("select 2 images and use the calculate button"),
|
||||||
text = "",
|
text = "",
|
||||||
}
|
}
|
||||||
|
|
||||||
img_time.calc_btn = dt.new_widget("button"){
|
img_time.calc_btn = dt.new_widget("button"){
|
||||||
label = _("Calculate"),
|
label = _("calculate"),
|
||||||
tooltip = _("calculate time difference between 2 images"),
|
tooltip = _("calculate time difference between 2 images"),
|
||||||
clicked_callback = function()
|
clicked_callback = function()
|
||||||
calculate_difference(dt.gui.action_images)
|
calculate_difference(dt.gui.action_images)
|
||||||
@@ -502,7 +509,7 @@ img_time.stack = dt.new_widget("stack"){
|
|||||||
dt.new_widget("box"){
|
dt.new_widget("box"){
|
||||||
orientation = "vertical",
|
orientation = "vertical",
|
||||||
dt.new_widget("label"){label = _("set time")},
|
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.sdy,
|
||||||
img_time.smo,
|
img_time.smo,
|
||||||
img_time.syr,
|
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 ds = require "lib/dtutils.string"
|
||||||
local dsys = require "lib/dtutils.system"
|
local dsys = require "lib/dtutils.system"
|
||||||
|
|
||||||
local gettext = dt.gettext
|
local gettext = dt.gettext.gettext
|
||||||
|
|
||||||
local PS = dt.configuration.running_os == "windows" and "\\" or "/"
|
local PS = dt.configuration.running_os == "windows" and "\\" or "/"
|
||||||
|
|
||||||
du.check_min_api_version("7.0.0", "kml_export")
|
du.check_min_api_version("7.0.0", "kml_export")
|
||||||
|
|
||||||
|
local function _(msgid)
|
||||||
|
return gettext(msgid)
|
||||||
|
end
|
||||||
|
|
||||||
-- return data structure for script_manager
|
-- return data structure for script_manager
|
||||||
|
|
||||||
local script_data = {}
|
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 = 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.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.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("kml_export",dt.configuration.config_dir.."/lua/locale/")
|
|
||||||
|
|
||||||
local function _(msgid)
|
|
||||||
return gettext.dgettext("kml_export", msgid)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function show_status(storage, image, format, filename, number, total, high_quality, extra_data)
|
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
|
end
|
||||||
|
|
||||||
-- Add duplicate index to filename
|
-- Add duplicate index to filename
|
||||||
@@ -88,12 +93,12 @@ local function create_kml_file(storage, image_table, extra_data)
|
|||||||
end
|
end
|
||||||
|
|
||||||
if not df.check_if_bin_exists(magickPath) then
|
if not df.check_if_bin_exists(magickPath) then
|
||||||
dt.print_error(_("magick not found"))
|
dt.print_error("magick not found")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
if dt.configuration.running_os == "linux" then
|
if dt.configuration.running_os == "linux" then
|
||||||
if not df.check_if_bin_exists("xdg-user-dir") 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
|
return
|
||||||
end
|
end
|
||||||
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
|
if ( dt.preferences.read("kml_export","CreateKMZ","bool") == true
|
||||||
and dt.configuration.running_os == "linux") then
|
and dt.configuration.running_os == "linux") then
|
||||||
if not df.check_if_bin_exists("zip") then
|
if not df.check_if_bin_exists("zip") then
|
||||||
dt.print_error(_("zip not found"))
|
dt.print_error("zip not found")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
exportDirectory = dt.configuration.tmp_dir
|
exportDirectory = dt.configuration.tmp_dir
|
||||||
@@ -319,14 +324,14 @@ if dt.configuration.running_os == "windows" then
|
|||||||
"OpenKmlFile",
|
"OpenKmlFile",
|
||||||
"bool",
|
"bool",
|
||||||
_("KML export: Open KML file after export"),
|
_("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 )
|
false )
|
||||||
else
|
else
|
||||||
dt.preferences.register("kml_export",
|
dt.preferences.register("kml_export",
|
||||||
"OpenKmlFile",
|
"OpenKmlFile",
|
||||||
"bool",
|
"bool",
|
||||||
_("KML export: Open KML/KMZ file after export"),
|
_("KML export: open KML/KMZ 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 )
|
false )
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -345,23 +350,23 @@ end
|
|||||||
dt.preferences.register("kml_export",
|
dt.preferences.register("kml_export",
|
||||||
"ExportDirectory",
|
"ExportDirectory",
|
||||||
"directory",
|
"directory",
|
||||||
_("KML export: Export directory"),
|
_("KML export: export directory"),
|
||||||
_("A directory that will be used to export the KML/KMZ files"),
|
_("a directory that will be used to export the KML/KMZ files"),
|
||||||
defaultDir )
|
defaultDir )
|
||||||
|
|
||||||
if dt.configuration.running_os ~= "linux" then
|
if dt.configuration.running_os ~= "linux" then
|
||||||
dt.preferences.register("kml_export",
|
dt.preferences.register("kml_export",
|
||||||
"magickPath", -- name
|
"magickPath", -- name
|
||||||
"file", -- type
|
"file", -- type
|
||||||
_("KML export: ImageMagick binary Location"), -- label
|
_("KML export: ImageMagick binary location"), -- label
|
||||||
_("Install location of magick[.exe]. Requires restart to take effect."), -- tooltip
|
_("install location of magick[.exe], requires restart to take effect"), -- tooltip
|
||||||
"magick") -- default
|
"magick") -- default
|
||||||
end
|
end
|
||||||
|
|
||||||
dt.preferences.register("kml_export",
|
dt.preferences.register("kml_export",
|
||||||
"CreatePath",
|
"CreatePath",
|
||||||
"bool",
|
"bool",
|
||||||
_("KML export: Connect images with path"),
|
_("KML export: connect images with path"),
|
||||||
_("connect all images with a path"),
|
_("connect all images with a path"),
|
||||||
false )
|
false )
|
||||||
|
|
||||||
@@ -369,16 +374,16 @@ if dt.configuration.running_os == "linux" then
|
|||||||
dt.preferences.register("kml_export",
|
dt.preferences.register("kml_export",
|
||||||
"CreateKMZ",
|
"CreateKMZ",
|
||||||
"bool",
|
"bool",
|
||||||
_("KML export: Create KMZ file"),
|
_("KML export: create KMZ file"),
|
||||||
_("Compress all imeges to one KMZ file"),
|
_("compress all imeges to one KMZ file"),
|
||||||
true )
|
true )
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Register
|
-- Register
|
||||||
if dt.configuration.running_os == "windows" then
|
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
|
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
|
end
|
||||||
|
|
||||||
script_data.destroy = destroy
|
script_data.destroy = destroy
|
||||||
|
|||||||
@@ -37,17 +37,28 @@ USAGE
|
|||||||
|
|
||||||
local dt = require "darktable"
|
local dt = require "darktable"
|
||||||
local du = require "lib/dtutils"
|
local du = require "lib/dtutils"
|
||||||
local gettext = dt.gettext
|
local gettext = dt.gettext.gettext
|
||||||
|
|
||||||
du.check_min_api_version("2.0.0", "passport_guide")
|
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)
|
local function _(msgid)
|
||||||
return gettext.dgettext("passport_guide", msgid)
|
return gettext(msgid)
|
||||||
end
|
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",
|
dt.guides.register_guide("passport",
|
||||||
-- draw
|
-- draw
|
||||||
function(cairo, x, y, width, height, zoom_scale)
|
function(cairo, x, y, width, height, zoom_scale)
|
||||||
@@ -91,5 +102,13 @@ function()
|
|||||||
end
|
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;
|
-- 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
|
-- 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 du = require "lib/dtutils"
|
||||||
local df = require "lib/dtutils.file"
|
local df = require "lib/dtutils.file"
|
||||||
|
|
||||||
local gettext = dt.gettext
|
local gettext = dt.gettext.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 function _(msgid)
|
local function _(msgid)
|
||||||
return gettext.dgettext("pdf_slideshow", msgid)
|
return gettext(msgid)
|
||||||
end
|
end
|
||||||
|
|
||||||
if not df.check_if_bin_exists("pdflatex") then
|
if not df.check_if_bin_exists("pdflatex") then
|
||||||
dt.print_error(_("pdflatex not found"))
|
dt.print_error("pdflatex not found")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -62,9 +59,17 @@ du.check_min_api_version("7.0.0", "pdf_slideshow")
|
|||||||
|
|
||||||
local script_data = {}
|
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 = 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.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.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
|
dt.preferences.register
|
||||||
("pdf_slideshow","open with","string",
|
("pdf_slideshow","open with","string",
|
||||||
@@ -230,7 +235,7 @@ dt.register_storage("pdf_slideshow",_("pdf slideshow"),
|
|||||||
local result = dt.control.execute(command)
|
local result = dt.control.execute(command)
|
||||||
if result ~= 0 then
|
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)
|
error("problem running "..command)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- open the PDF
|
-- open the PDF
|
||||||
@@ -240,7 +245,7 @@ dt.register_storage("pdf_slideshow",_("pdf slideshow"),
|
|||||||
local result = dt.control.execute(command)
|
local result = dt.control.execute(command)
|
||||||
if result ~= 0 then
|
if result ~= 0 then
|
||||||
dt.print(_("problem running pdf viewer")) -- this one is probably usefull to the user
|
dt.print(_("problem running pdf viewer")) -- this one is probably usefull to the user
|
||||||
error(_("problem running ")..command)
|
error("problem running "..command)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- finally do some clean-up
|
-- finally do some clean-up
|
||||||
|
|||||||
@@ -44,19 +44,30 @@ local dtsys = require "lib/dtutils.system"
|
|||||||
local MODULE_NAME = "photils"
|
local MODULE_NAME = "photils"
|
||||||
du.check_min_api_version("7.0.0", MODULE_NAME)
|
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
|
-- return data structure for script_manager
|
||||||
|
|
||||||
local script_data = {}
|
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 = 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.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.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 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")
|
local exporter = dt.new_format("jpeg")
|
||||||
exporter.quality = 80
|
exporter.quality = 80
|
||||||
@@ -65,10 +76,6 @@ exporter.max_width = 224
|
|||||||
|
|
||||||
-- helper functions
|
-- helper functions
|
||||||
|
|
||||||
local function _(msgid)
|
|
||||||
return gettext.dgettext(MODULE_NAME, msgid)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function num_keys(tbl)
|
local function num_keys(tbl)
|
||||||
local num = 0
|
local num = 0
|
||||||
for _ in pairs(tbl) do num = num + 1 end
|
for _ in pairs(tbl) do num = num + 1 end
|
||||||
@@ -177,7 +184,7 @@ function PHOTILS.image_changed()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function PHOTILS.tagged_image_has_changed()
|
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
|
end
|
||||||
|
|
||||||
function PHOTILS.paginate()
|
function PHOTILS.paginate()
|
||||||
@@ -234,7 +241,7 @@ end
|
|||||||
|
|
||||||
function PHOTILS.attach_tags()
|
function PHOTILS.attach_tags()
|
||||||
local num_selected = #dt.gui.selection()
|
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
|
for i = 1, num_selected, 1 do
|
||||||
local image = dt.gui.selection()[i]
|
local image = dt.gui.selection()[i]
|
||||||
@@ -246,7 +253,7 @@ function PHOTILS.attach_tags()
|
|||||||
job.percent = i / num_selected
|
job.percent = i / num_selected
|
||||||
end
|
end
|
||||||
|
|
||||||
dt.print(_("Tags successfully attached to image"))
|
dt.print(_("tags successfully attached to image"))
|
||||||
job.valid = false
|
job.valid = false
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -312,11 +319,11 @@ function PHOTILS.on_tags_clicked()
|
|||||||
local images = dt.gui.selection()
|
local images = dt.gui.selection()
|
||||||
|
|
||||||
if #images == 0 then
|
if #images == 0 then
|
||||||
dt.print(_("No image selected."))
|
dt.print(_("no image selected."))
|
||||||
dt.control.sleep(2000)
|
dt.control.sleep(2000)
|
||||||
else
|
else
|
||||||
if #images > 1 then
|
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.gui.selection({images[1]})
|
||||||
dt.control.sleep(2000)
|
dt.control.sleep(2000)
|
||||||
end
|
end
|
||||||
@@ -331,7 +338,7 @@ function PHOTILS.on_tags_clicked()
|
|||||||
end
|
end
|
||||||
|
|
||||||
if #PHOTILS.tags == 0 then
|
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.warning_label.label = msg
|
||||||
GUI.stack.active = GUI.error_view
|
GUI.stack.active = GUI.error_view
|
||||||
return
|
return
|
||||||
@@ -386,7 +393,7 @@ end
|
|||||||
local function install_module()
|
local function install_module()
|
||||||
if not PHOTILS.module_installed then
|
if not PHOTILS.module_installed then
|
||||||
dt.register_lib(MODULE_NAME,
|
dt.register_lib(MODULE_NAME,
|
||||||
"photils autotagger",
|
_("photils auto-tagger"),
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
PHOTILS.plugin_display_views,
|
PHOTILS.plugin_display_views,
|
||||||
@@ -427,9 +434,9 @@ end
|
|||||||
|
|
||||||
if not photils_installed then
|
if not photils_installed then
|
||||||
GUI.warning_label.label = _("photils-cli not found")
|
GUI.warning_label.label = _("photils-cli not found")
|
||||||
dt.print_log(_("photils-cli not found"))
|
dt.print_log("photils-cli not found")
|
||||||
else
|
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
|
end
|
||||||
|
|
||||||
GUI.pagination = dt.new_widget("box") {
|
GUI.pagination = dt.new_widget("box") {
|
||||||
@@ -472,9 +479,9 @@ dt.preferences.register(MODULE_NAME,
|
|||||||
"export_image_before_for_tags",
|
"export_image_before_for_tags",
|
||||||
"bool",
|
"bool",
|
||||||
_("photils: use exported image for tag request"),
|
_("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. " ..
|
_("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." ..
|
"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."),
|
"the embedded thumbnail could speedup the tag suggestion but can fail if the RAW file is not supported."),
|
||||||
true)
|
true)
|
||||||
|
|
||||||
dt.register_event("photils", "mouse-over-image-changed",
|
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")
|
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
|
-- return data structure for script_manager
|
||||||
|
|
||||||
local script_data = {}
|
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 = 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.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.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.event_registered = false
|
||||||
qt.widget_table = {}
|
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
|
-- maximum length of button labels
|
||||||
dt.preferences.register("quickTag",
|
dt.preferences.register("quickTag",
|
||||||
"labellength",
|
"labellength",
|
||||||
@@ -193,7 +197,7 @@ local function install_module()
|
|||||||
if not qt.module_installed then
|
if not qt.module_installed then
|
||||||
dt.register_lib(
|
dt.register_lib(
|
||||||
"quicktag", -- Module name
|
"quicktag", -- Module name
|
||||||
"quicktag", -- name
|
_("quick tag"), -- name
|
||||||
true, -- expandable
|
true, -- expandable
|
||||||
false, -- resetable
|
false, -- resetable
|
||||||
{[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 490}},
|
{[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 490}},
|
||||||
@@ -300,7 +304,7 @@ end
|
|||||||
for i=1,qnr do
|
for i=1,qnr do
|
||||||
dt.register_event("quicktag " .. tostring(i), "shortcut",
|
dt.register_event("quicktag " .. tostring(i), "shortcut",
|
||||||
function(event, shortcut) tagattach(tostring(quicktag_table[i])) end,
|
function(event, shortcut) tagattach(tostring(quicktag_table[i])) end,
|
||||||
string.format(_("quicktag %i"),i))
|
string.format(_("quick tag %i"),i))
|
||||||
end
|
end
|
||||||
|
|
||||||
script_data.destroy = destroy
|
script_data.destroy = destroy
|
||||||
|
|||||||
@@ -44,13 +44,27 @@ local du = require "lib/dtutils"
|
|||||||
-- added version check
|
-- added version check
|
||||||
du.check_min_api_version("7.0.0", "rate_group")
|
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
|
-- return data structure for script_manager
|
||||||
|
|
||||||
local script_data = {}
|
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 = 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.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.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 function apply_rating(rating)
|
||||||
local images = dt.gui.action_images
|
local images = dt.gui.action_images
|
||||||
@@ -61,9 +75,9 @@ local function apply_rating(rating)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
if rating < 0 then
|
if rating < 0 then
|
||||||
dt.print("rejecting group(s)")
|
dt.print(_("rejecting group(s)"))
|
||||||
else
|
else
|
||||||
dt.print("applying rating " ..rating.. " to group(s)")
|
dt.print(string.format(_("applying rating %d to group(s)"), rating))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -80,37 +94,38 @@ end
|
|||||||
dt.register_event("rg_reject", "shortcut",
|
dt.register_event("rg_reject", "shortcut",
|
||||||
function(event, shortcut)
|
function(event, shortcut)
|
||||||
apply_rating(-1)
|
apply_rating(-1)
|
||||||
end, "Reject group")
|
end, _("reject group"))
|
||||||
|
|
||||||
dt.register_event("rg0", "shortcut",
|
dt.register_event("rg0", "shortcut",
|
||||||
function(event, shortcut)
|
function(event, shortcut)
|
||||||
apply_rating(0)
|
apply_rating(0)
|
||||||
end, "Rate group 0")
|
end, string.format(_("rate group %d"), 0)
|
||||||
|
)
|
||||||
|
|
||||||
dt.register_event("rg1", "shortcut",
|
dt.register_event("rg1", "shortcut",
|
||||||
function(event, shortcut)
|
function(event, shortcut)
|
||||||
apply_rating(1)
|
apply_rating(1)
|
||||||
end, "Rate group 1")
|
end, string.format(_("rate group %d"), 1))
|
||||||
|
|
||||||
dt.register_event("rg2", "shortcut",
|
dt.register_event("rg2", "shortcut",
|
||||||
function(event, shortcut)
|
function(event, shortcut)
|
||||||
apply_rating(2)
|
apply_rating(2)
|
||||||
end, "Rate group 2")
|
end, string.format(_("rate group %d"), 2))
|
||||||
|
|
||||||
dt.register_event("rg3", "shortcut",
|
dt.register_event("rg3", "shortcut",
|
||||||
function(event, shortcut)
|
function(event, shortcut)
|
||||||
apply_rating(3)
|
apply_rating(3)
|
||||||
end, "Rate group 3")
|
end, string.format(_("rate group %d"), 3))
|
||||||
|
|
||||||
dt.register_event("rg4", "shortcut",
|
dt.register_event("rg4", "shortcut",
|
||||||
function(event, shortcut)
|
function(event, shortcut)
|
||||||
apply_rating(4)
|
apply_rating(4)
|
||||||
end, "Rate group 4")
|
end, string.format(_("rate group %d"), 4))
|
||||||
|
|
||||||
dt.register_event("rg5", "shortcut",
|
dt.register_event("rg5", "shortcut",
|
||||||
function(event, shortcut)
|
function(event, shortcut)
|
||||||
apply_rating(5)
|
apply_rating(5)
|
||||||
end, "Rate group 5")
|
end, string.format(_("rate group %d"), 5))
|
||||||
|
|
||||||
script_data.destroy = destroy
|
script_data.destroy = destroy
|
||||||
|
|
||||||
|
|||||||
@@ -36,21 +36,35 @@ local debug = require "darktable.debug"
|
|||||||
du.check_min_api_version("7.0.0", "rename-tags")
|
du.check_min_api_version("7.0.0", "rename-tags")
|
||||||
du.deprecated("contrib/rename-tags.lua","darktable release 4.0")
|
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
|
-- return data structure for script_manager
|
||||||
|
|
||||||
local script_data = {}
|
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 = 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.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.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 = {}
|
local rt = {}
|
||||||
rt.module_installed = false
|
rt.module_installed = false
|
||||||
rt.event_registered = false
|
rt.event_registered = false
|
||||||
|
|
||||||
-- GUI entries
|
-- GUI entries
|
||||||
local old_tag = darktable.new_widget("entry") { tooltip = "Enter old tag" }
|
local old_tag = darktable.new_widget("entry") { tooltip = _("enter old tag") }
|
||||||
local new_tag = darktable.new_widget("entry") { tooltip = "Enter new tag" }
|
local new_tag = darktable.new_widget("entry") { tooltip = _("enter new tag") }
|
||||||
|
|
||||||
local function rename_reset()
|
local function rename_reset()
|
||||||
old_tag.text = ''
|
old_tag.text = ''
|
||||||
@@ -61,11 +75,11 @@ end
|
|||||||
local function rename_tags()
|
local function rename_tags()
|
||||||
-- If entries are empty, return
|
-- If entries are empty, return
|
||||||
if old_tag.text == '' then
|
if old_tag.text == '' then
|
||||||
darktable.print ("Old tag can't be empty")
|
darktable.print (_("old tag can't be empty"))
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
if new_tag.text == '' then
|
if new_tag.text == '' then
|
||||||
darktable.print ("New tag can't be empty")
|
darktable.print (_("new tag can't be empty"))
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -75,12 +89,12 @@ local function rename_tags()
|
|||||||
local ot = darktable.tags.find (old_tag.text)
|
local ot = darktable.tags.find (old_tag.text)
|
||||||
|
|
||||||
if not ot then
|
if not ot then
|
||||||
darktable.print ("Old tag does not exist")
|
darktable.print (_("old tag does not exist"))
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Show job
|
-- Show job
|
||||||
local job = darktable.gui.create_job ("Renaming tag", true)
|
local job = darktable.gui.create_job (_("renaming tag"), true)
|
||||||
|
|
||||||
old_tag.editable = false
|
old_tag.editable = false
|
||||||
new_tag.editable = false
|
new_tag.editable = false
|
||||||
@@ -103,7 +117,7 @@ local function rename_tags()
|
|||||||
darktable.tags.delete (ot)
|
darktable.tags.delete (ot)
|
||||||
|
|
||||||
job.valid = false
|
job.valid = false
|
||||||
darktable.print ("Renamed tags for " .. count .. " images")
|
darktable.print (string.format(_("renamed tags for %d images"), count))
|
||||||
old_tag.editable = true
|
old_tag.editable = true
|
||||||
new_tag.editable = true
|
new_tag.editable = true
|
||||||
|
|
||||||
@@ -114,7 +128,7 @@ end
|
|||||||
|
|
||||||
local function install_module()
|
local function install_module()
|
||||||
if not rt.module_installed then
|
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
|
rt.module_installed = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -130,13 +144,13 @@ end
|
|||||||
-- GUI
|
-- GUI
|
||||||
local old_widget = darktable.new_widget ("box") {
|
local old_widget = darktable.new_widget ("box") {
|
||||||
orientation = "horizontal",
|
orientation = "horizontal",
|
||||||
darktable.new_widget("label") { label = "Old tag" },
|
darktable.new_widget("label") { label = _("old tag") },
|
||||||
old_tag
|
old_tag
|
||||||
}
|
}
|
||||||
|
|
||||||
local new_widget = darktable.new_widget ("box") {
|
local new_widget = darktable.new_widget ("box") {
|
||||||
orientation = "horizontal",
|
orientation = "horizontal",
|
||||||
darktable.new_widget("label") { label = "New tag" },
|
darktable.new_widget("label") { label = _("new tag") },
|
||||||
new_tag
|
new_tag
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,7 +159,7 @@ rt.rename_widget = darktable.new_widget ("box") {
|
|||||||
reset_callback = rename_reset,
|
reset_callback = rename_reset,
|
||||||
old_widget,
|
old_widget,
|
||||||
new_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
|
if darktable.gui.current_view().id == "lighttable" then
|
||||||
|
|||||||
@@ -43,27 +43,19 @@
|
|||||||
local dt = require "darktable"
|
local dt = require "darktable"
|
||||||
local du = require "lib/dtutils"
|
local du = require "lib/dtutils"
|
||||||
local df = require "lib/dtutils.file"
|
local df = require "lib/dtutils.file"
|
||||||
|
local ds = require "lib/dtutils.string"
|
||||||
|
|
||||||
du.check_min_api_version("7.0.0", "rename_images")
|
du.check_min_api_version("7.0.0", "rename_images")
|
||||||
|
|
||||||
local gettext = dt.gettext
|
local gettext = dt.gettext.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 function _(msgid)
|
local function _(msgid)
|
||||||
return gettext.dgettext("rename_images", msgid)
|
return gettext(msgid)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- namespace variable
|
-- namespace variable
|
||||||
local rename = {
|
local rename = {
|
||||||
presets = {},
|
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 = {},
|
widgets = {},
|
||||||
}
|
}
|
||||||
rename.module_installed = false
|
rename.module_installed = false
|
||||||
@@ -72,9 +64,17 @@ rename.event_registered = false
|
|||||||
-- script_manager integration
|
-- script_manager integration
|
||||||
local script_data = {}
|
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 = 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.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.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 PS = dt.configuration.running_os == "windows" and "\\" or "/"
|
||||||
local USER = os.getenv("USERNAME")
|
local USER = os.getenv("USERNAME")
|
||||||
local HOME = os.getenv(dt.configuration.running_os == "windows" and "HOMEPATH" or "HOME")
|
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"
|
local DESKTOP = HOME .. PS .. "Desktop"
|
||||||
|
|
||||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
-- F U N C T I O N S
|
-- 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)
|
local function stop_job(job)
|
||||||
job.valid = false
|
job.valid = false
|
||||||
end
|
end
|
||||||
@@ -207,9 +130,10 @@ end
|
|||||||
|
|
||||||
local function do_rename(images)
|
local function do_rename(images)
|
||||||
if #images > 0 then
|
if #images > 0 then
|
||||||
|
local first_image = images[1]
|
||||||
local pattern = rename.widgets.pattern.text
|
local pattern = rename.widgets.pattern.text
|
||||||
dt.preferences.write(MODULE_NAME, "pattern", "string", pattern)
|
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
|
if string.len(pattern) > 0 then
|
||||||
local datetime = os.date("*t")
|
local datetime = os.date("*t")
|
||||||
|
|
||||||
@@ -217,14 +141,14 @@ local function do_rename(images)
|
|||||||
for i, image in ipairs(images) do
|
for i, image in ipairs(images) do
|
||||||
if job.valid then
|
if job.valid then
|
||||||
job.percent = i / #images
|
job.percent = i / #images
|
||||||
build_substitution_list(image, i, datetime, USER, PICTURES, HOME, DESKTOP)
|
ds.build_substitute_list(image, i, pattern, USER, PICTURES, HOME, DESKTOP)
|
||||||
local new_name = substitute_list(pattern)
|
local new_name = ds.substitute_list(pattern)
|
||||||
if new_name == -1 then
|
if new_name == -1 then
|
||||||
dt.print(_("unable to do variable substitution, exiting..."))
|
dt.print(_("unable to do variable substitution, exiting..."))
|
||||||
stop_job(job)
|
stop_job(job)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
clear_substitute_list()
|
ds.clear_substitute_list()
|
||||||
local args = {}
|
local args = {}
|
||||||
local path = string.sub(df.get_path(new_name), 1, -2)
|
local path = string.sub(df.get_path(new_name), 1, -2)
|
||||||
if string.len(path) == 0 then
|
if string.len(path) == 0 then
|
||||||
@@ -249,7 +173,8 @@ local function do_rename(images)
|
|||||||
stop_job(job)
|
stop_job(job)
|
||||||
local collect_rules = dt.gui.libs.collect.filter()
|
local collect_rules = dt.gui.libs.collect.filter()
|
||||||
dt.gui.libs.collect.filter(collect_rules)
|
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
|
else -- pattern length
|
||||||
dt.print_error("no pattern supplied, returning...")
|
dt.print_error("no pattern supplied, returning...")
|
||||||
dt.print(_("please enter the new name or pattern"))
|
dt.print(_("please enter the new name or pattern"))
|
||||||
@@ -269,50 +194,8 @@ end
|
|||||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
rename.widgets.pattern = dt.new_widget("entry"){
|
rename.widgets.pattern = dt.new_widget("entry"){
|
||||||
tooltip = _("$(ROLL_NAME) - film roll name\n") ..
|
tooltip = ds.get_substitution_tooltip(),
|
||||||
_("$(FILE_FOLDER) - image file folder\n") ..
|
placeholder = _("enter pattern") .. "$(FILE_FOLDER)/$(FILE_NAME)",
|
||||||
_("$(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)"),
|
|
||||||
text = ""
|
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 dt = require "darktable"
|
||||||
local du = require "lib/dtutils"
|
local du = require "lib/dtutils"
|
||||||
local gettext = dt.gettext
|
local gettext = dt.gettext.gettext
|
||||||
|
|
||||||
du.check_min_api_version("7.0.0", "select_untagged")
|
du.check_min_api_version("7.0.0", "select_untagged")
|
||||||
|
|
||||||
|
local function _(msgid)
|
||||||
|
return gettext(msgid)
|
||||||
|
end
|
||||||
|
|
||||||
-- return data structure for script_manager
|
-- return data structure for script_manager
|
||||||
|
|
||||||
local script_data = {}
|
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 = 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.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.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("select_untagged",dt.configuration.config_dir.."/lua/locale/")
|
|
||||||
|
|
||||||
local function _(msgid)
|
|
||||||
return gettext.dgettext("select_untagged", msgid)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function stop_job(job)
|
local function stop_job(job)
|
||||||
job.valid = false
|
job.valid = false
|
||||||
|
|||||||
@@ -27,24 +27,29 @@ USAGE
|
|||||||
local dt = require "darktable"
|
local dt = require "darktable"
|
||||||
local du = require "lib/dtutils"
|
local du = require "lib/dtutils"
|
||||||
local df = require "lib/dtutils.file"
|
local df = require "lib/dtutils.file"
|
||||||
local gettext = dt.gettext
|
local gettext = dt.gettext.gettext
|
||||||
|
|
||||||
du.check_min_api_version("7.0.0", "slideshowMusic")
|
du.check_min_api_version("7.0.0", "slideshowMusic")
|
||||||
|
|
||||||
|
local function _(msgid)
|
||||||
|
return gettext(msgid)
|
||||||
|
end
|
||||||
|
|
||||||
-- return data structure for script_manager
|
-- return data structure for script_manager
|
||||||
|
|
||||||
local script_data = {}
|
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 = 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.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.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("slideshowMusic",dt.configuration.config_dir.."/lua/locale/")
|
|
||||||
|
|
||||||
local function _(msgid)
|
|
||||||
return gettext.dgettext("slideshowMusic", msgid)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function playSlideshowMusic(_, old_view, new_view)
|
local function playSlideshowMusic(_, old_view, new_view)
|
||||||
local filename, playMusic
|
local filename, playMusic
|
||||||
@@ -53,7 +58,7 @@ local function playSlideshowMusic(_, old_view, new_view)
|
|||||||
playMusic = dt.preferences.read("slideshowMusic","PlaySlideshowMusic","bool")
|
playMusic = dt.preferences.read("slideshowMusic","PlaySlideshowMusic","bool")
|
||||||
|
|
||||||
if not df.check_if_bin_exists("rhythmbox-client") then
|
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
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -69,7 +74,7 @@ local function playSlideshowMusic(_, old_view, new_view)
|
|||||||
if (old_view and old_view.id == "slideshow") then
|
if (old_view and old_view.id == "slideshow") then
|
||||||
stopCommand = "rhythmbox-client --pause"
|
stopCommand = "rhythmbox-client --pause"
|
||||||
--dt.print_error(stopCommand)
|
--dt.print_error(stopCommand)
|
||||||
dt.control.execute( stopCommand)
|
dt.control.execute(stopCommand)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -82,12 +87,12 @@ function destroy()
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Preferences
|
-- 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",
|
dt.preferences.register("slideshowMusic",
|
||||||
"PlaySlideshowMusic",
|
"PlaySlideshowMusic",
|
||||||
"bool",
|
"bool",
|
||||||
_("Play slideshow background music"),
|
_("play slideshow background music"),
|
||||||
_("Plays music with rhythmbox if a slideshow starts"),
|
_("plays music with rhythmbox if a slideshow starts"),
|
||||||
true)
|
true)
|
||||||
-- Register
|
-- Register
|
||||||
dt.register_event("slideshow_music", "view-changed",
|
dt.register_event("slideshow_music", "view-changed",
|
||||||
|
|||||||
@@ -76,17 +76,30 @@ local darktable = require("darktable")
|
|||||||
local dtutils = require("lib/dtutils")
|
local dtutils = require("lib/dtutils")
|
||||||
local dtutils_file = require("lib/dtutils.file")
|
local dtutils_file = require("lib/dtutils.file")
|
||||||
local dtutils_system = require("lib/dtutils.system")
|
local dtutils_system = require("lib/dtutils.system")
|
||||||
|
local gettext = darktable.gettext.gettext
|
||||||
|
|
||||||
local LIB_ID = "transfer_hierarchy"
|
local LIB_ID = "transfer_hierarchy"
|
||||||
dtutils.check_min_api_version("7.0.0", LIB_ID)
|
dtutils.check_min_api_version("7.0.0", LIB_ID)
|
||||||
|
|
||||||
|
local function _(msgid)
|
||||||
|
return gettext(msgid)
|
||||||
|
end
|
||||||
|
|
||||||
-- return data structure for script_manager
|
-- return data structure for script_manager
|
||||||
|
|
||||||
local script_data = {}
|
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 = 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.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.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 MKDIR_COMMAND = darktable.configuration.running_os == "windows" and "mkdir " or "mkdir -p "
|
||||||
local PATH_SEPARATOR = darktable.configuration.running_os == "windows" and "\\\\" or "/"
|
local PATH_SEPARATOR = darktable.configuration.running_os == "windows" and "\\\\" or "/"
|
||||||
@@ -95,12 +108,6 @@ local PATH_SEGMENT_REGEX = "(" .. PATH_SEPARATOR .. "?)([^" .. PATH_SEPARATOR ..
|
|||||||
unpack = unpack or table.unpack
|
unpack = unpack or table.unpack
|
||||||
gmatch = string.gfind or string.gmatch
|
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
|
-- Header material: END
|
||||||
|
|
||||||
|
|
||||||
@@ -137,7 +144,7 @@ end
|
|||||||
local function install_module()
|
local function install_module()
|
||||||
if not th.module_installed then
|
if not th.module_installed then
|
||||||
darktable.register_lib(LIB_ID,
|
darktable.register_lib(LIB_ID,
|
||||||
"transfer hierarchy", true, true, {
|
_("transfer hierarchy"), true, true, {
|
||||||
[darktable.gui.views.lighttable] = { "DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 700 }
|
[darktable.gui.views.lighttable] = { "DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 700 }
|
||||||
}, th.transfer_widget, nil, nil)
|
}, th.transfer_widget, nil, nil)
|
||||||
th.module_installed = true
|
th.module_installed = true
|
||||||
@@ -150,7 +157,7 @@ end
|
|||||||
-- Widgets and business logic: BEGIN
|
-- Widgets and business logic: BEGIN
|
||||||
|
|
||||||
local sourceTextBox = darktable.new_widget("entry") {
|
local sourceTextBox = darktable.new_widget("entry") {
|
||||||
tooltip = _("Lowest directory containing all selected images"),
|
tooltip = _("lowest directory containing all selected images"),
|
||||||
editable = false
|
editable = false
|
||||||
}
|
}
|
||||||
sourceTextBox.reset_callback = function() sourceTextBox.text = "" end
|
sourceTextBox.reset_callback = function() sourceTextBox.text = "" end
|
||||||
@@ -267,17 +274,17 @@ local function doTransfer(transferFunc)
|
|||||||
films[film] = destBase .. string.sub(film.path, #sourceBase+1)
|
films[film] = destBase .. string.sub(film.path, #sourceBase+1)
|
||||||
if not pathExists(films[film]) then
|
if not pathExists(films[film]) then
|
||||||
if createDirectory(films[film]) == nil 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
|
return
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if not pathIsDirectory(films[film]) then
|
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
|
return
|
||||||
end
|
end
|
||||||
destFilms[film] = darktable.films.new(films[film])
|
destFilms[film] = darktable.films.new(films[film])
|
||||||
if destFilms[film] == nil then
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -286,7 +293,7 @@ local function doTransfer(transferFunc)
|
|||||||
srcFilms[img] = img.film
|
srcFilms[img] = img.film
|
||||||
end
|
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
|
job.percent = 0.0
|
||||||
local pctIncrement = 1.0 / #(darktable.gui.action_images)
|
local pctIncrement = 1.0 / #(darktable.gui.action_images)
|
||||||
for _,img in ipairs(darktable.gui.action_images) do
|
for _,img in ipairs(darktable.gui.action_images) do
|
||||||
@@ -344,7 +351,7 @@ th.transfer_widget = darktable.new_widget("box") {
|
|||||||
},
|
},
|
||||||
darktable.new_widget("button") {
|
darktable.new_widget("button") {
|
||||||
label = _("copy"),
|
label = _("copy"),
|
||||||
tooltip = _("Copy all selected images"),
|
tooltip = _("copy all selected images"),
|
||||||
clicked_callback = doCopy
|
clicked_callback = doCopy
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -398,4 +405,4 @@ script_data.restart = restart
|
|||||||
script_data.destroy_method = "hide"
|
script_data.destroy_method = "hide"
|
||||||
script_data.show = restart
|
script_data.show = restart
|
||||||
|
|
||||||
return script_data
|
return script_data
|
||||||
|
|||||||
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 du = require "lib/dtutils"
|
||||||
local df = require "lib/dtutils.file"
|
local df = require "lib/dtutils.file"
|
||||||
local dsys = require "lib/dtutils.system"
|
local dsys = require "lib/dtutils.system"
|
||||||
local gettext = dt.gettext
|
local gettext = dt.gettext.gettext
|
||||||
|
|
||||||
du.check_min_api_version("7.0.0", "video_ffmpeg")
|
du.check_min_api_version("7.0.0", "video_ffmpeg")
|
||||||
|
|
||||||
|
local function _(msgid)
|
||||||
|
return gettext(msgid)
|
||||||
|
end
|
||||||
|
|
||||||
-- return data structure for script_manager
|
-- return data structure for script_manager
|
||||||
|
|
||||||
local script_data = {}
|
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 = 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.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.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 MODULE_NAME = "video_ffmpeg"
|
||||||
|
|
||||||
local PS = dt.configuration.running_os == "windows" and "\\" or "/"
|
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
|
---- DECLARATIONS
|
||||||
|
|
||||||
@@ -240,8 +246,8 @@ local function string_pref_write(name, widget_attribute)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local framerates_selector = dt.new_widget("combobox"){
|
local framerates_selector = dt.new_widget("combobox"){
|
||||||
label = _("framerate"),
|
label = _("frame rate"),
|
||||||
tooltip = _("select framerate of output video"),
|
tooltip = _("select frame rate of output video"),
|
||||||
value = combobox_pref_read("framerate", framerates),
|
value = combobox_pref_read("framerate", framerates),
|
||||||
changed_callback = combobox_pref_write("framerate"),
|
changed_callback = combobox_pref_write("framerate"),
|
||||||
table.unpack(framerates)
|
table.unpack(framerates)
|
||||||
@@ -293,7 +299,7 @@ else
|
|||||||
end
|
end
|
||||||
|
|
||||||
local output_directory_chooser = dt.new_widget("file_chooser_button"){
|
local output_directory_chooser = dt.new_widget("file_chooser_button"){
|
||||||
title = _("Select export path"),
|
title = _("select export path"),
|
||||||
is_directory = true,
|
is_directory = true,
|
||||||
tooltip =_("select the target directory for the timelapse. \nthe filename is created automatically."),
|
tooltip =_("select the target directory for the timelapse. \nthe filename is created automatically."),
|
||||||
value = string_pref_read("export_path", defaultVideoDir),
|
value = string_pref_read("export_path", defaultVideoDir),
|
||||||
@@ -374,7 +380,7 @@ local module_widget = dt.new_widget("box") {
|
|||||||
---- EXPORT & REGISTRATION
|
---- EXPORT & REGISTRATION
|
||||||
|
|
||||||
local function show_status(enf_storage, image, format, filename, number, total, high_quality, extra_data)
|
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
|
end
|
||||||
|
|
||||||
local function init_export(storage, img_format, images, high_quality, extra_data)
|
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")
|
local ffmpeg_path = df.check_if_bin_exists("ffmpeg")
|
||||||
if not ffmpeg_path then
|
if not ffmpeg_path then
|
||||||
dt.print_error("ffmpeg not found")
|
dt.print_error("ffmpeg not found")
|
||||||
dt.print("ERROR - ffmpeg not found")
|
dt.print(_("ERROR - ffmpeg not found"))
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
local dir = extra_data["tmp_dir"]
|
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)
|
dt.print_error(filename, file.filename)
|
||||||
df.file_move(filename, tmp_dir .. PS .. i .. extra_data["img_ext"])
|
df.file_move(filename, tmp_dir .. PS .. i .. extra_data["img_ext"])
|
||||||
end
|
end
|
||||||
dt.print("Start video building...")
|
dt.print(_("start video building..."))
|
||||||
local result, path = export(extra_data)
|
local result, path = export(extra_data)
|
||||||
if result ~= 0 then
|
if result ~= 0 then
|
||||||
dt.print(_("ERROR: cannot build image, see console for more info"))
|
dt.print(_("ERROR: cannot build image, see console for more info"))
|
||||||
@@ -464,7 +470,7 @@ end
|
|||||||
|
|
||||||
dt.register_storage(
|
dt.register_storage(
|
||||||
"module_video_ffmpeg",
|
"module_video_ffmpeg",
|
||||||
_(MODULE_NAME),
|
_("video ffmpeg"),
|
||||||
show_status,
|
show_status,
|
||||||
finalize_export,
|
finalize_export,
|
||||||
nil,
|
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"
|
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
|
-- script_manager integration to allow a script to be removed
|
||||||
-- without restarting darktable
|
-- without restarting darktable
|
||||||
local function destroy()
|
local function destroy()
|
||||||
@@ -30,12 +38,21 @@ local function destroy()
|
|||||||
end
|
end
|
||||||
|
|
||||||
local result = dt.configuration.api_version_string
|
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
|
-- 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
|
-- it's time to destroy the script and then return the data to
|
||||||
-- script_manager
|
-- script_manager
|
||||||
local script_data = {}
|
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
|
script_data.destroy = destroy
|
||||||
|
|
||||||
return script_data
|
return script_data
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ local du = require "lib/dtutils"
|
|||||||
-- V E R S I O N C H E C K
|
-- 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
|
-- script_manager integration to allow a script to be removed
|
||||||
-- without restarting darktable
|
-- without restarting darktable
|
||||||
@@ -52,17 +52,16 @@ end
|
|||||||
-- C O N S T A N T S
|
-- 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 "/"
|
local PS = dt.configuration.running_os == "windows" and "\\" or "/"
|
||||||
|
|
||||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
-- T R A N S L A T I O N S
|
-- T R A N S L A T I O N S
|
||||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
local gettext = dt.gettext
|
local gettext = dt.gettext.gettext
|
||||||
gettext.bindtextdomain(MODULE_NAME, dt.configuration.config_dir..PS.."lua"..PS.."locale"..PS)
|
|
||||||
|
|
||||||
local function _(msgid)
|
local function _(msgid)
|
||||||
return gettext.dgettext(MODULE_NAME, msgid)
|
return gettext(msgid)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
@@ -92,13 +91,13 @@ dt.gui.current_view(dt.gui.views.darkroom)
|
|||||||
|
|
||||||
local max_images = 10
|
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)
|
sleep(1500)
|
||||||
|
|
||||||
-- display first 10 images of collection pausing for a second between each
|
-- display first 10 images of collection pausing for a second between each
|
||||||
|
|
||||||
for i, img in ipairs(dt.collection) do
|
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)
|
dt.gui.views.darkroom.display_image(img)
|
||||||
sleep(1500)
|
sleep(1500)
|
||||||
if i == max_images then
|
if i == max_images then
|
||||||
@@ -108,7 +107,7 @@ end
|
|||||||
|
|
||||||
-- return to lighttable view
|
-- return to lighttable view
|
||||||
|
|
||||||
dt.print(_("Restoring view"))
|
dt.print(_("restoring view"))
|
||||||
sleep(1500)
|
sleep(1500)
|
||||||
dt.gui.current_view(current_view)
|
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
|
-- it's time to destroy the script and then return the data to
|
||||||
-- script_manager
|
-- script_manager
|
||||||
local script_data = {}
|
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
|
script_data.destroy = destroy
|
||||||
|
|
||||||
return script_data
|
return script_data
|
||||||
|
|||||||
@@ -67,27 +67,31 @@ end
|
|||||||
-- Not translated Text
|
-- Not translated Text
|
||||||
dt.print_error("Hello World!")
|
dt.print_error("Hello World!")
|
||||||
|
|
||||||
local gettext = dt.gettext
|
local gettext = dt.gettext.gettext
|
||||||
|
|
||||||
-- Translate a string using the darktable textdomain
|
-- Translate a string using the darktable textdomain
|
||||||
dt.print_error(gettext.gettext("image"))
|
dt.print_error(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!'))
|
|
||||||
|
|
||||||
-- Define a local function called _ to make the code more readable and have it call dgettext
|
-- Define a local function called _ to make the code more readable and have it call dgettext
|
||||||
-- with the proper domain.
|
-- with the proper domain.
|
||||||
local function _(msgid)
|
local function _(msgid)
|
||||||
return gettext.dgettext("gettextExample", msgid)
|
return gettext(msgid)
|
||||||
end
|
end
|
||||||
dt.print_error(_('Hello World!'))
|
|
||||||
|
dt.print_error(_("hello world!"))
|
||||||
|
|
||||||
-- set the destroy routine so that script_manager can call it when
|
-- 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
|
-- it's time to destroy the script and then return the data to
|
||||||
-- script_manager
|
-- script_manager
|
||||||
local script_data = {}
|
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
|
script_data.destroy = destroy
|
||||||
|
|
||||||
return script_data
|
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 dt = require "darktable"
|
||||||
local du = require "lib/dtutils"
|
local du = require "lib/dtutils"
|
||||||
|
|
||||||
|
-- translation facilities
|
||||||
|
|
||||||
du.check_min_api_version("2.0.0", "hello_world")
|
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
|
-- script_manager integration to allow a script to be removed
|
||||||
-- without restarting darktable
|
-- without restarting darktable
|
||||||
local function destroy()
|
local function destroy()
|
||||||
-- nothing to destroy
|
-- nothing to destroy
|
||||||
end
|
end
|
||||||
|
|
||||||
dt.print("hello, world")
|
dt.print(_("hello, world"))
|
||||||
|
|
||||||
-- set the destroy routine so that script_manager can call it when
|
-- 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
|
-- it's time to destroy the script and then return the data to
|
||||||
-- script_manager
|
-- script_manager
|
||||||
local script_data = {}
|
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
|
script_data.destroy = destroy
|
||||||
|
|
||||||
return script_data
|
return script_data
|
||||||
|
|||||||
@@ -59,11 +59,12 @@ end
|
|||||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
-- T R A N S L A T I O N S
|
-- T R A N S L A T I O N S
|
||||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
local gettext = dt.gettext
|
local gettext = dt.gettext.gettext
|
||||||
gettext.bindtextdomain(MODULE_NAME, dt.configuration.config_dir..PS.."lua"..PS.."locale"..PS)
|
|
||||||
|
dt.gettext.bindtextdomain("lighttable_demo", dt.configuration.config_dir .."/lua/locale/")
|
||||||
|
|
||||||
local function _(msgid)
|
local function _(msgid)
|
||||||
return gettext.dgettext(MODULE_NAME, msgid)
|
return gettext(msgid)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
@@ -145,17 +146,17 @@ sleep(2000)
|
|||||||
|
|
||||||
for n, layout in ipairs(layouts) do
|
for n, layout in ipairs(layouts) do
|
||||||
dt.gui.libs.lighttable_mode.layout(layout)
|
dt.gui.libs.lighttable_mode.layout(layout)
|
||||||
dt.print(_("set lighttable layout to " .. layout))
|
dt.print(string.format(_("set lighttable layout to %s"), layout))
|
||||||
dt.print_log(_("set lighttable layout to " .. layout))
|
dt.print_log("set lighttable layout to " .. layout)
|
||||||
sleep(1500)
|
sleep(1500)
|
||||||
for i = 1, 10 do
|
for i = 1, 10 do
|
||||||
dt.gui.libs.lighttable_mode.zoom_level(i)
|
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)
|
sleep(1500)
|
||||||
end
|
end
|
||||||
for i = 9, 1, -1 do
|
for i = 9, 1, -1 do
|
||||||
dt.gui.libs.lighttable_mode.zoom_level(i)
|
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)
|
sleep(1500)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -174,12 +175,12 @@ dt.print_log("starting sorts")
|
|||||||
|
|
||||||
for n, sort in ipairs(sorts) do
|
for n, sort in ipairs(sorts) do
|
||||||
dt.gui.libs.filter.sort(sort)
|
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)
|
sleep(1500)
|
||||||
|
|
||||||
for m, sort_order in ipairs(sort_orders) do
|
for m, sort_order in ipairs(sort_orders) do
|
||||||
dt.gui.libs.filter.sort_order(sort_order)
|
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)
|
sleep(1500)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -190,12 +191,12 @@ dt.print(_("lighttable filtering demonstration"))
|
|||||||
|
|
||||||
for n, rating in ipairs(ratings) do
|
for n, rating in ipairs(ratings) do
|
||||||
dt.gui.libs.filter.rating(rating)
|
dt.gui.libs.filter.rating(rating)
|
||||||
dt.print(_("set filter to " .. rating))
|
dt.print(string.format(_("set filter to %s"), rating))
|
||||||
sleep(1500)
|
sleep(1500)
|
||||||
|
|
||||||
for m, rating_comparator in ipairs(rating_comparators) do
|
for m, rating_comparator in ipairs(rating_comparators) do
|
||||||
dt.gui.libs.filter.rating_comparator(rating_comparator)
|
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)
|
sleep(1500)
|
||||||
end
|
end
|
||||||
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
|
-- it's time to destroy the script and then return the data to
|
||||||
-- script_manager
|
-- script_manager
|
||||||
local script_data = {}
|
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
|
script_data.destroy = destroy
|
||||||
|
|
||||||
return script_data
|
return script_data
|
||||||
|
|||||||
@@ -35,25 +35,31 @@ local du = require "lib/dtutils"
|
|||||||
|
|
||||||
du.check_min_api_version("7.0.0", "moduleExample")
|
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
|
-- return data structure for script_manager
|
||||||
|
|
||||||
local script_data = {}
|
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 = 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.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.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
|
-- 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
|
-- declare a local namespace and a couple of variables we'll need to install the module
|
||||||
local mE = {}
|
local mE = {}
|
||||||
mE.widgets = {}
|
mE.widgets = {}
|
||||||
@@ -69,7 +75,7 @@ local function install_module()
|
|||||||
-- https://www.darktable.org/lua-api/index.html#darktable_register_lib
|
-- https://www.darktable.org/lua-api/index.html#darktable_register_lib
|
||||||
dt.register_lib(
|
dt.register_lib(
|
||||||
"exampleModule", -- Module name
|
"exampleModule", -- Module name
|
||||||
"exampleModule", -- name
|
_("example module"), -- name
|
||||||
true, -- expandable
|
true, -- expandable
|
||||||
false, -- resetable
|
false, -- resetable
|
||||||
{[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, -- containers
|
{[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, -- containers
|
||||||
@@ -79,9 +85,9 @@ local function install_module()
|
|||||||
orientation = "vertical",
|
orientation = "vertical",
|
||||||
dt.new_widget("button")
|
dt.new_widget("button")
|
||||||
{
|
{
|
||||||
label = _("MyButton"),
|
label = _("my ") .. "button",
|
||||||
clicked_callback = function (_)
|
clicked_callback = function (_)
|
||||||
dt.print(_("Button clicked"))
|
dt.print(_("button clicked"))
|
||||||
end
|
end
|
||||||
},
|
},
|
||||||
table.unpack(mE.widgets),
|
table.unpack(mE.widgets),
|
||||||
@@ -104,10 +110,10 @@ local function restart()
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- https://www.darktable.org/lua-api/types_lua_check_button.html
|
-- https://www.darktable.org/lua-api/types_lua_check_button.html
|
||||||
local check_button = dt.new_widget("check_button"){label = _("MyCheck_button"), value = true}
|
local check_button = dt.new_widget("check_button"){label = _("my ") .. "check_button", value = true}
|
||||||
|
|
||||||
-- https://www.darktable.org/lua-api/types_lua_combobox.html
|
-- 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
|
-- https://www.darktable.org/lua-api/types_lua_entry.html
|
||||||
local entry = dt.new_widget("entry")
|
local entry = dt.new_widget("entry")
|
||||||
@@ -116,21 +122,21 @@ local entry = dt.new_widget("entry")
|
|||||||
placeholder = _("placeholder"),
|
placeholder = _("placeholder"),
|
||||||
is_password = false,
|
is_password = false,
|
||||||
editable = true,
|
editable = true,
|
||||||
tooltip = _("Tooltip Text"),
|
tooltip = _("tooltip text"),
|
||||||
reset_callback = function(self) self.text = "text" end
|
reset_callback = function(self) self.text = "text" end
|
||||||
}
|
}
|
||||||
|
|
||||||
-- https://www.darktable.org/lua-api/types_lua_file_chooser_button.html
|
-- https://www.darktable.org/lua-api/types_lua_file_chooser_button.html
|
||||||
local file_chooser_button = dt.new_widget("file_chooser_button")
|
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
|
value = "", -- The currently selected file
|
||||||
is_directory = false -- True if the file chooser button only allows directories to be selecte
|
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
|
-- https://www.darktable.org/lua-api/types_lua_label.html
|
||||||
local label = dt.new_widget("label")
|
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
|
-- https://www.darktable.org/lua-api/types_lua_separator.html
|
||||||
local separator = dt.new_widget("separator"){}
|
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
|
-- https://www.darktable.org/lua-api/types_lua_slider.html
|
||||||
local slider = dt.new_widget("slider")
|
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_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
|
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
|
hard_min = 0, -- The hard minimum value for the slider, the user can't manually enter a value beyond this point
|
||||||
|
|||||||
@@ -29,8 +29,7 @@
|
|||||||
by hovering over the image and pressing the key combination.
|
by hovering over the image and pressing the key combination.
|
||||||
|
|
||||||
ADDITIONAL SOFTWARE NEEDED FOR THIS SCRIPT
|
ADDITIONAL SOFTWARE NEEDED FOR THIS SCRIPT
|
||||||
* ufraw-batch - https://ufraw.sourceforge.net
|
* exiftool - https://exiftool.org
|
||||||
MacOS - install with homebrew
|
|
||||||
|
|
||||||
USAGE
|
USAGE
|
||||||
* require this script from your main lua file
|
* require this script from your main lua file
|
||||||
@@ -44,6 +43,7 @@
|
|||||||
* Send to Bill Ferguson, wpferguson@gmail.com
|
* Send to Bill Ferguson, wpferguson@gmail.com
|
||||||
|
|
||||||
CHANGES
|
CHANGES
|
||||||
|
20251205 - replaced ufraw-batch with exiftool
|
||||||
]]
|
]]
|
||||||
|
|
||||||
--[[
|
--[[
|
||||||
@@ -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.
|
translations, inserting this lays the groundwork for anyone who wants to translate the strings.
|
||||||
]]
|
]]
|
||||||
|
|
||||||
local gettext = dt.gettext
|
local gettext = dt.gettext.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 function _(msgid)
|
local function _(msgid)
|
||||||
return gettext.dgettext("multi_os", msgid)
|
return gettext(msgid)
|
||||||
end
|
end
|
||||||
|
|
||||||
--[[
|
--[[
|
||||||
@@ -142,6 +139,36 @@ local function copy_image_attributes(from, to, ...)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function check_file_size(img_name)
|
||||||
|
local result = 0
|
||||||
|
|
||||||
|
if dt.configuration.running_os == "windows" then
|
||||||
|
local path = df.get_path(img_name)
|
||||||
|
local fname = df.get_filename(img_name)
|
||||||
|
|
||||||
|
local p = io.open("forfiles /P " .. path .. " /M " .. fname .. " /C \"cmd /c echo $fsize\"")
|
||||||
|
|
||||||
|
if p then
|
||||||
|
for line in p:lines() do
|
||||||
|
if line:length() > 5 then
|
||||||
|
result = tonumber(line)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
p:close()
|
||||||
|
end
|
||||||
|
else
|
||||||
|
local p = io.popen("ls -s " .. img_name)
|
||||||
|
|
||||||
|
if p then
|
||||||
|
local line = p:read("*a")
|
||||||
|
result = tonumber(du.split(line, " ")[1])
|
||||||
|
p:close()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
|
||||||
--[[
|
--[[
|
||||||
The main function called from the button or the shortcut. It takes one or more raw files, passed
|
The main function called from the button or the shortcut. It takes one or more raw files, passed
|
||||||
in a table and extracts the embedded jpeg images
|
in a table and extracts the embedded jpeg images
|
||||||
@@ -155,11 +182,12 @@ local function extract_embedded_jpeg(images)
|
|||||||
in the user's path. When it finds the executable, it returns the command to run it.
|
in the user's path. When it finds the executable, it returns the command to run it.
|
||||||
]]
|
]]
|
||||||
|
|
||||||
local ufraw_executable = df.check_if_bin_exists("ufraw-batch")
|
local exiftool_executable = df.check_if_bin_exists("exiftool")
|
||||||
if ufraw_executable then
|
if exiftool_executable then
|
||||||
for _, image in ipairs(images) do
|
for _, image in ipairs(images) do
|
||||||
if image.is_raw then
|
if image.is_raw then
|
||||||
local img_file = du.join({image.path, image.filename}, "/")
|
local img_file = tostring(image)
|
||||||
|
local jpg_img_file = string.gsub(img_file, "%....$", ".jpg")
|
||||||
|
|
||||||
--[[
|
--[[
|
||||||
dtsys.external_command() is operating system aware and formats the command as necessary.
|
dtsys.external_command() is operating system aware and formats the command as necessary.
|
||||||
@@ -167,8 +195,12 @@ local function extract_embedded_jpeg(images)
|
|||||||
operating system aware and uses the corresponding quotes.
|
operating system aware and uses the corresponding quotes.
|
||||||
]]
|
]]
|
||||||
|
|
||||||
if dtsys.external_command(ufraw_executable .. " --silent --embedded-image " .. df.sanitize_filename(img_file)) then
|
if dtsys.external_command(exiftool_executable .. " -b -JpgFromRaw " .. df.sanitize_filename(img_file) .. " > " .. df.sanitize_filename(jpg_img_file)) then
|
||||||
local jpg_img_file = df.chop_filetype(img_file) .. ".embedded.jpg"
|
dt.print_log("created jpg from raw")
|
||||||
|
if check_file_size(df.sanitize_filename(jpg_img_file)) == 0 then
|
||||||
|
dt.print_log("using preview")
|
||||||
|
dtsys.external_command(exiftool_executable .. " -b -PreviewImage " .. df.sanitize_filename(img_file) .. " > " .. df.sanitize_filename(jpg_img_file))
|
||||||
|
end
|
||||||
dt.print_log("jpg_img_file set to ", jpg_img_file) -- print a debugging message
|
dt.print_log("jpg_img_file set to ", jpg_img_file) -- print a debugging message
|
||||||
local myimage = dt.database.import(jpg_img_file)
|
local myimage = dt.database.import(jpg_img_file)
|
||||||
myimage:group_with(image.group_leader)
|
myimage:group_with(image.group_leader)
|
||||||
@@ -187,12 +219,12 @@ local function extract_embedded_jpeg(images)
|
|||||||
end
|
end
|
||||||
else
|
else
|
||||||
dt.print_error(image.filename .. " is not a raw file. No image can be extracted") -- print debugging error message
|
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
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
dt.print_error("ufraw-batch not found. Exiting...") -- print debugging error message
|
dt.print_error("exiftool not found. Exiting...") -- print debugging error message
|
||||||
dt.print("ufraw-batch not found. Exiting...") -- print the error to the screen
|
dt.print("exiftool not found, exiting...") -- print the error to the screen
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -216,7 +248,7 @@ end
|
|||||||
if dt.configuration.running_os ~= "linux" then
|
if dt.configuration.running_os ~= "linux" then
|
||||||
local executable = "ufraw-batch"
|
local executable = "ufraw-batch"
|
||||||
local ufraw_batch_path_widget = dt.new_widget("file_chooser_button"){
|
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),
|
value = df.get_executable_path_preference(executable),
|
||||||
is_directory = false,
|
is_directory = false,
|
||||||
changed_callback = function(self)
|
changed_callback = function(self)
|
||||||
@@ -227,8 +259,8 @@ if dt.configuration.running_os ~= "linux" then
|
|||||||
}
|
}
|
||||||
dt.preferences.register("executable_paths", "ufraw-batch", -- name
|
dt.preferences.register("executable_paths", "ufraw-batch", -- name
|
||||||
"file", -- type
|
"file", -- type
|
||||||
_('multi_os: ufraw-batch location'), -- label
|
'multi_os: ufraw-batch ' .. _('location'), -- label
|
||||||
_('Installed location of ufraw-batch. Requires restart to take effect.'), -- tooltip
|
_('installed location of ufraw-batch, requires restart to take effect.'), -- tooltip
|
||||||
"ufraw-batch", -- default
|
"ufraw-batch", -- default
|
||||||
ufraw_batch_path_widget
|
ufraw_batch_path_widget
|
||||||
)
|
)
|
||||||
@@ -241,7 +273,7 @@ end
|
|||||||
dt.gui.libs.image.register_action(
|
dt.gui.libs.image.register_action(
|
||||||
"multi_os", _("extract embedded jpeg"),
|
"multi_os", _("extract embedded jpeg"),
|
||||||
function(event, images) extract_embedded_jpeg(images) end,
|
function(event, images) extract_embedded_jpeg(images) end,
|
||||||
"extract embedded jpeg"
|
_("extract embedded jpeg")
|
||||||
)
|
)
|
||||||
|
|
||||||
--[[
|
--[[
|
||||||
@@ -251,7 +283,7 @@ dt.gui.libs.image.register_action(
|
|||||||
dt.register_event(
|
dt.register_event(
|
||||||
"multi_os", "shortcut",
|
"multi_os", "shortcut",
|
||||||
function(event, shortcut) extract_embedded_jpeg(dt.gui.action_images) end,
|
function(event, shortcut) extract_embedded_jpeg(dt.gui.action_images) end,
|
||||||
"extract embedded jpeg"
|
_("extract embedded jpeg")
|
||||||
)
|
)
|
||||||
|
|
||||||
--[[
|
--[[
|
||||||
@@ -261,6 +293,14 @@ dt.register_event(
|
|||||||
]]
|
]]
|
||||||
|
|
||||||
local script_data = {}
|
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
|
script_data.destroy = destroy
|
||||||
|
|
||||||
return script_data
|
return script_data
|
||||||
|
|||||||
@@ -53,17 +53,16 @@ end
|
|||||||
-- C O N S T A N T S
|
-- 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 "/"
|
local PS = dt.configuration.running_os == "windows" and "\\" or "/"
|
||||||
|
|
||||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
-- T R A N S L A T I O N S
|
-- T R A N S L A T I O N S
|
||||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
local gettext = dt.gettext
|
local gettext = dt.gettext.gettext
|
||||||
gettext.bindtextdomain(MODULE_NAME, dt.configuration.config_dir..PS.."lua"..PS.."locale"..PS)
|
|
||||||
|
|
||||||
local function _(msgid)
|
local function _(msgid)
|
||||||
return gettext.dgettext(MODULE_NAME, msgid)
|
return gettext(msgid)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- - - - - - - - - - - - - - - - - - - - - - - -
|
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
@@ -94,29 +93,29 @@ dt.gui.panel_show_all()
|
|||||||
|
|
||||||
-- hide center_top, center_bottom, left, top, right, bottom in order
|
-- 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)
|
sleep(1500)
|
||||||
|
|
||||||
for i = 1, #panels do
|
for i = 1, #panels do
|
||||||
dt.print(_("Hiding " .. panels[i]))
|
dt.print(string.format(_("hiding %s"), panels[i]))
|
||||||
dt.gui.panel_hide(panels[i])
|
dt.gui.panel_hide(panels[i])
|
||||||
sleep(1500)
|
sleep(1500)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- display left, then top, then right, then bottom
|
-- 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)
|
sleep(1500)
|
||||||
|
|
||||||
for i = #panels, 1, -1 do
|
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])
|
dt.gui.panel_show(panels[i])
|
||||||
sleep(1500)
|
sleep(1500)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- hide all
|
-- hide all
|
||||||
|
|
||||||
dt.print(_("Hiding all panels"))
|
dt.print(_("hiding all panels"))
|
||||||
sleep(1500)
|
sleep(1500)
|
||||||
|
|
||||||
dt.gui.panel_hide_all()
|
dt.gui.panel_hide_all()
|
||||||
@@ -124,7 +123,7 @@ sleep(1500)
|
|||||||
|
|
||||||
-- show all
|
-- show all
|
||||||
|
|
||||||
dt.print(_("Showing all panels"))
|
dt.print(_("showing all panels"))
|
||||||
sleep(1500)
|
sleep(1500)
|
||||||
|
|
||||||
dt.gui.panel_show_all()
|
dt.gui.panel_show_all()
|
||||||
@@ -132,7 +131,7 @@ sleep(1500)
|
|||||||
|
|
||||||
-- restore
|
-- restore
|
||||||
|
|
||||||
dt.print(_("Restoring panels to starting configuration"))
|
dt.print(_("restoring panels to starting configuration"))
|
||||||
for i = 1, #panels do
|
for i = 1, #panels do
|
||||||
if panel_status[i] then
|
if panel_status[i] then
|
||||||
dt.gui.panel_show(panels[i])
|
dt.gui.panel_show(panels[i])
|
||||||
@@ -145,6 +144,14 @@ end
|
|||||||
-- it's time to destroy the script and then return the data to
|
-- it's time to destroy the script and then return the data to
|
||||||
-- script_manager
|
-- script_manager
|
||||||
local script_data = {}
|
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
|
script_data.destroy = destroy
|
||||||
|
|
||||||
return script_data
|
return script_data
|
||||||
|
|||||||
@@ -24,28 +24,45 @@ USAGE
|
|||||||
local dt = require "darktable"
|
local dt = require "darktable"
|
||||||
local du = require "lib/dtutils"
|
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")
|
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.
|
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
|
"preferenceExamplesString", -- name
|
||||||
"string", -- type
|
"string", -- type
|
||||||
"Example String", -- label
|
_("example") .. " string", -- label
|
||||||
"Example String Tooltip", -- tooltip
|
_("example") .. " string " .. _("tooltip"), -- tooltip
|
||||||
"String") -- default
|
"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.
|
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
|
"preferenceExamplesBool", -- name
|
||||||
"bool", -- type
|
"bool", -- type
|
||||||
"Example Boolean", -- label
|
_("example") .. " boolean", -- label
|
||||||
"Example Boolean Tooltip", -- tooltip
|
_("example") .. " boolean " .. _("tooltip"), -- tooltip
|
||||||
true) -- default
|
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.
|
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
|
"preferenceExamplesInteger", -- name
|
||||||
"integer", -- type
|
"integer", -- type
|
||||||
"Example Integer", -- label
|
_("example") .. " integer", -- label
|
||||||
"Example Integer Tooltip", -- tooltip
|
_("example") .. " integer " .. _("tooltip"), -- tooltip
|
||||||
2, -- default
|
2, -- default
|
||||||
1, -- min
|
1, -- min
|
||||||
99) -- max
|
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.
|
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
|
"preferenceExamplesFloat", -- name
|
||||||
"float", -- type
|
"float", -- type
|
||||||
"Example Float", -- label
|
_("example") .. " float", -- label
|
||||||
"Example Float Tooltip", -- tooltip
|
_("example") .. " float " .. _("tooltip"), -- tooltip
|
||||||
1.3, -- default
|
1.3, -- default
|
||||||
1, -- min
|
1, -- min
|
||||||
99, -- max
|
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.
|
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
|
"preferenceExamplesFile", -- name
|
||||||
"file", -- type
|
"file", -- type
|
||||||
"Example File", -- label
|
_("example") .. " file", -- label
|
||||||
"Example File Tooltip", -- tooltip
|
_("example") .. " file " .. _("tooltip"), -- tooltip
|
||||||
"") -- default
|
"") -- 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.
|
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
|
"preferenceExamplesDirectory", -- name
|
||||||
"directory", -- type
|
"directory", -- type
|
||||||
"Example Directory", -- label
|
_("example") .. " directory", -- label
|
||||||
"Example Directory Tooltip", -- tooltip
|
_("example") .. " directory " .. _("tooltip"), -- tooltip
|
||||||
"") -- default
|
"") -- 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.
|
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
|
"preferenceExamplesEnum", -- name
|
||||||
"enum", -- type
|
"enum", -- type
|
||||||
"Example Enum", -- label
|
_("example") .. " enum", -- label
|
||||||
"Example Enum Tooltip", -- tooltip
|
_("example") .. " enum " .. _("tooltip"), -- tooltip
|
||||||
"Enum 1", -- default
|
"Enum 1", -- default
|
||||||
"Enum 1", "Enum 2") -- values
|
"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")
|
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
|
-- script_manager integration to allow a script to be removed
|
||||||
-- without restarting darktable
|
-- without restarting darktable
|
||||||
local function destroy()
|
local function destroy()
|
||||||
@@ -32,7 +40,7 @@ end
|
|||||||
|
|
||||||
-- Will print a string to the darktable control log (the long
|
-- Will print a string to the darktable control log (the long
|
||||||
-- overlayed window that appears over the main panel).
|
-- 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
|
-- This function will print its parameter if the Lua logdomain is
|
||||||
-- activated. Start darktable with the "-d lua" command line option
|
-- 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
|
-- it's time to destroy the script and then return the data to
|
||||||
-- script_manager
|
-- script_manager
|
||||||
local script_data = {}
|
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
|
script_data.destroy = destroy
|
||||||
|
|
||||||
return script_data
|
return script_data
|
||||||
|
|||||||
@@ -30,18 +30,34 @@ local du = require "lib/dtutils"
|
|||||||
|
|
||||||
du.check_min_api_version("5.0.0", "running_os")
|
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
|
-- script_manager integration to allow a script to be removed
|
||||||
-- without restarting darktable
|
-- without restarting darktable
|
||||||
local function destroy()
|
local function destroy()
|
||||||
-- nothing to destroy
|
-- nothing to destroy
|
||||||
end
|
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
|
-- 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
|
-- it's time to destroy the script and then return the data to
|
||||||
-- script_manager
|
-- script_manager
|
||||||
local script_data = {}
|
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
|
script_data.destroy = destroy
|
||||||
|
|
||||||
return script_data
|
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)
|
function dtutils.check_min_api_version(min_api, script_name)
|
||||||
local current_api = dt.configuration.api_version_string
|
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("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("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.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)
|
error("Minimum API " .. min_api .. " not met for " .. script_name .. ".", 0)
|
||||||
end
|
end
|
||||||
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"] = {
|
dtutils.libdoc.functions["split"] = {
|
||||||
Name = [[split]],
|
Name = [[split]],
|
||||||
Synopsis = [[split a string on a specified separator]],
|
Synopsis = [[split a string on a specified separator]],
|
||||||
@@ -184,7 +220,8 @@ function dtutils.prequire(req_name)
|
|||||||
if status then
|
if status then
|
||||||
log.msg(log.info, "Loaded " .. req_name)
|
log.msg(log.info, "Loaded " .. req_name)
|
||||||
else
|
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
|
end
|
||||||
return status, lib
|
return status, lib
|
||||||
end
|
end
|
||||||
@@ -337,7 +374,7 @@ dtutils.libdoc.functions["deprecated"] = {
|
|||||||
|
|
||||||
du.deprecated(script_name, removal_string)
|
du.deprecated(script_name, removal_string)
|
||||||
script_name - name of the script being deprecated
|
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]],
|
Description = [[deprecated prints an error message saying the script is deprecated and when it will be removed]],
|
||||||
Return_Value = [[]],
|
Return_Value = [[]],
|
||||||
Limitations = [[]],
|
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)
|
dt.print_error("WARNING: " .. script_name .. " is deprecated and will be removed in " .. removal_string)
|
||||||
end
|
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
|
return dtutils
|
||||||
|
|||||||
@@ -24,15 +24,12 @@ dtutils_file.libdoc = {
|
|||||||
functions = {}
|
functions = {}
|
||||||
}
|
}
|
||||||
|
|
||||||
local gettext = dt.gettext
|
local gettext = dt.gettext.gettext
|
||||||
|
|
||||||
du.check_min_api_version("5.0.0", "dtutils.file")
|
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)
|
local function _(msgid)
|
||||||
return gettext.dgettext("dtutils.file", msgid)
|
return gettext(msgid)
|
||||||
end
|
end
|
||||||
|
|
||||||
--[[
|
--[[
|
||||||
@@ -522,9 +519,9 @@ function dtutils_file.file_copy(fromFile, toFile)
|
|||||||
local result = nil
|
local result = nil
|
||||||
-- if cp exists, use it
|
-- if cp exists, use it
|
||||||
if dt.configuration.running_os == "windows" then
|
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
|
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
|
end
|
||||||
|
|
||||||
-- if cp was not present, or if cp failed, then a pure lua solution
|
-- 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
|
if not success then
|
||||||
-- an error occurred, so let's try using the operating system function
|
-- an error occurred, so let's try using the operating system function
|
||||||
if dtutils_file.check_if_bin_exists("mv") then
|
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
|
end
|
||||||
-- if the mv didn't exist or succeed, then...
|
-- if the mv didn't exist or succeed, then...
|
||||||
if not success then
|
if not success then
|
||||||
@@ -815,7 +812,7 @@ dtutils_file.libdoc.functions["mkdir"] = {
|
|||||||
function dtutils_file.mkdir(path)
|
function dtutils_file.mkdir(path)
|
||||||
if not dtutils_file.check_if_file_exists(path) then
|
if not dtutils_file.check_if_file_exists(path) then
|
||||||
local mkdir_cmd = dt.configuration.running_os == "windows" and "mkdir" or "mkdir -p"
|
local mkdir_cmd = dt.configuration.running_os == "windows" and "mkdir" or "mkdir -p"
|
||||||
return dsys.external_command(mkdir_cmd.." "..path)
|
return dsys.external_command(mkdir_cmd.." "..dtutils_file.sanitize_filename(path))
|
||||||
else
|
else
|
||||||
return 0
|
return 0
|
||||||
end
|
end
|
||||||
@@ -840,7 +837,7 @@ dtutils_file.libdoc.functions["rmdir"] = {
|
|||||||
|
|
||||||
function dtutils_file.rmdir(path)
|
function dtutils_file.rmdir(path)
|
||||||
local rm_cmd = dt.configuration.running_os == "windows" and "rmdir /S /Q" or "rm -r"
|
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
|
end
|
||||||
|
|
||||||
dtutils_file.libdoc.functions["create_tmp_file"] = {
|
dtutils_file.libdoc.functions["create_tmp_file"] = {
|
||||||
@@ -861,9 +858,6 @@ dtutils_file.libdoc.functions["create_tmp_file"] = {
|
|||||||
|
|
||||||
function dtutils_file.create_tmp_file()
|
function dtutils_file.create_tmp_file()
|
||||||
local tmp_file = os.tmpname()
|
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")
|
local f = io.open(tmp_file, "w")
|
||||||
if not f then
|
if not f then
|
||||||
|
|||||||
@@ -199,7 +199,7 @@ function dtutils_log.msg(level, ...)
|
|||||||
table.remove(args, 1)
|
table.remove(args, 1)
|
||||||
end
|
end
|
||||||
local log_msg = level.label
|
local log_msg = level.label
|
||||||
if level.engine ~= dt_screen and call_level ~= 0 then
|
if level.engine ~= dt_print and call_level ~= 0 then
|
||||||
log_msg = log_msg .. dtutils_log.caller(call_level, level.caller_info) .. " "
|
log_msg = log_msg .. dtutils_log.caller(call_level, level.caller_info) .. " "
|
||||||
elseif log_msg:len() > 2 then
|
elseif log_msg:len() > 2 then
|
||||||
log_msg = log_msg .. " "
|
log_msg = log_msg .. " "
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,7 @@
|
|||||||
local dtutils_system = {}
|
local dtutils_system = {}
|
||||||
|
|
||||||
local dt = require "darktable"
|
local dt = require "darktable"
|
||||||
|
local ds = require "lib/dtutils.string"
|
||||||
|
|
||||||
dtutils_system.libdoc = {
|
dtutils_system.libdoc = {
|
||||||
Name = [[dtutils.system]],
|
Name = [[dtutils.system]],
|
||||||
@@ -85,8 +86,13 @@ function dtutils_system.windows_command(command)
|
|||||||
local file = io.open(fname, "w")
|
local file = io.open(fname, "w")
|
||||||
if file then
|
if file then
|
||||||
dt.print_log("opened file")
|
dt.print_log("opened file")
|
||||||
command = string.gsub(command, "%%", "%%%%") -- escape % from windows shell
|
file:write("@echo off\n")
|
||||||
file:write(command)
|
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()
|
file:close()
|
||||||
|
|
||||||
result = dt.control.execute(fname)
|
result = dt.control.execute(fname)
|
||||||
@@ -118,6 +124,7 @@ dtutils_system.libdoc.functions["launch_default_app"] = {
|
|||||||
License = [[]],
|
License = [[]],
|
||||||
Copyright = [[]],
|
Copyright = [[]],
|
||||||
}
|
}
|
||||||
|
|
||||||
function dtutils_system.launch_default_app(path)
|
function dtutils_system.launch_default_app(path)
|
||||||
local open_cmd = "xdg-open "
|
local open_cmd = "xdg-open "
|
||||||
if (dt.configuration.running_os == "windows") then
|
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)
|
return dtutils_system.external_command(open_cmd .. path)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
return dtutils_system
|
return dtutils_system
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ msgstr ""
|
|||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
"Language: \n"
|
"Language: \n"
|
||||||
"MIME-Version: 1.0\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"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Generator: Poedit 1.5.4\n"
|
"X-Generator: Poedit 1.5.4\n"
|
||||||
"Language: de_DE\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"
|
||||||
514
official/apply_camera_style.lua
Normal file
514
official/apply_camera_style.lua
Normal file
@@ -0,0 +1,514 @@
|
|||||||
|
--[[
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
20251202 - fixed pattern matching bugs affecting Canon EOS R? series
|
||||||
|
styles and styles being applied twice if images are reimported
|
||||||
|
|
||||||
|
Added more debugging statements to pattern matching functions
|
||||||
|
]]
|
||||||
|
|
||||||
|
local dt = require "darktable"
|
||||||
|
local du = require "lib/dtutils"
|
||||||
|
-- local df = require "lib/dtutils.file"
|
||||||
|
local ds = require "lib/dtutils.string"
|
||||||
|
-- local 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.warn
|
||||||
|
local TMP_DIR <const> = dt.configuration.tmp_dir
|
||||||
|
local STYLE_PREFIX <const> = "_l10n_darktable|_l10n_camera styles|"
|
||||||
|
local MAKER = 3
|
||||||
|
local STYLE = 4
|
||||||
|
|
||||||
|
-- path separator
|
||||||
|
local PS <const> = dt.configuration.running_os == "windows" and "\\" or "/"
|
||||||
|
|
||||||
|
-- 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)
|
||||||
|
|
||||||
|
log.msg(log.debug, "input pattern is " .. pattern)
|
||||||
|
|
||||||
|
pattern = string.lower(pattern)
|
||||||
|
log.msg(log.debug, "lower case pattern is " .. pattern)
|
||||||
|
-- strip off series
|
||||||
|
pattern = string.gsub(pattern, " series$", "?")
|
||||||
|
log.msg(log.debug, "series stripped off pattern is " .. pattern)
|
||||||
|
-- match a character
|
||||||
|
if string.match(pattern, "r%?%?$") then
|
||||||
|
-- handle EOS R case
|
||||||
|
pattern = string.gsub(pattern, "%?%?", ".?")
|
||||||
|
log.msg(log.debug, "matched EOS R pattern is " .. pattern)
|
||||||
|
else
|
||||||
|
pattern = string.gsub(pattern, "?", ".")
|
||||||
|
log.msg(log.debug, "didn't match EOS R pattern is " .. pattern)
|
||||||
|
end
|
||||||
|
-- escape dashes
|
||||||
|
pattern = string.gsub(pattern, "%-", "%%-")
|
||||||
|
log.msg(log.debug, "escape dashes conditional pattern is " .. pattern)
|
||||||
|
-- make spaces optional
|
||||||
|
pattern = string.gsub(pattern, " ", " ?")
|
||||||
|
-- until we end up with a set, I'll defer set processing, i.e. [...]
|
||||||
|
--log.msg(log.debug, "make spaces conditional again? pattern is " .. pattern)
|
||||||
|
-- anchor the pattern to ensure we don't short match
|
||||||
|
pattern = "^" .. pattern .. "$"
|
||||||
|
log.msg(log.debug, "anchored pattern is " .. pattern)
|
||||||
|
|
||||||
|
restore_log_level(log_level)
|
||||||
|
|
||||||
|
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[MAKER] = string.lower(parts[MAKER])
|
||||||
|
log.msg(log.debug, "maker is " .. parts[MAKER])
|
||||||
|
|
||||||
|
if not acs.styles[parts[MAKER]] then
|
||||||
|
acs.styles[parts[MAKER]] = {}
|
||||||
|
acs.styles[parts[MAKER]]["styles"] = {}
|
||||||
|
acs.styles[parts[MAKER]]["patterns"] = {}
|
||||||
|
end
|
||||||
|
if parts[STYLE] then
|
||||||
|
if not string.match(parts[STYLE], "]") then
|
||||||
|
table.insert(acs.styles[parts[MAKER]].styles, style)
|
||||||
|
local processed_pattern = process_pattern(parts[#parts])
|
||||||
|
table.insert(acs.styles[parts[MAKER]].patterns, processed_pattern)
|
||||||
|
log.msg(log.debug, "pattern for " .. style.name .. " is " .. processed_pattern)
|
||||||
|
else
|
||||||
|
local processed_patterns = process_set(parts[STYLE])
|
||||||
|
for _, pat in ipairs(processed_patterns) do
|
||||||
|
table.insert(acs.styles[parts[MAKER]].styles, style)
|
||||||
|
table.insert(acs.styles[parts[MAKER]].patterns, pat)
|
||||||
|
log.msg(log.debug, "pattern for " .. style.name .. " is " .. pat)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
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, "got attached tag " .. tag.name)
|
||||||
|
local cleaned_tag_name = string.gsub(tag_name, "_l10n_", "")
|
||||||
|
log.msg(log.debug, "checking against " .. cleaned_tag_name)
|
||||||
|
if ds.sanitize_lua(tag.name) == cleaned_tag_name then
|
||||||
|
log.msg(log.debug, "matched tag " .. cleaned_tag_name)
|
||||||
|
result = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
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, "mangle 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
|
||||||
|
log.msg(log.debug, "pattern is " .. pattern)
|
||||||
|
if string.match(model, pattern) or
|
||||||
|
(i == #acs.styles[maker].patterns and string.match(pattern, "generic")) then
|
||||||
|
local tag_name = "darktable|style|" .. acs.styles[maker].styles[i].name
|
||||||
|
if not has_style_tag(image, tag_name) then
|
||||||
|
image:apply_style(acs.styles[maker].styles[i])
|
||||||
|
log.msg(log.info, "applied style " .. acs.styles[maker].styles[i].name .. " to " .. image.filename)
|
||||||
|
end
|
||||||
|
no_match = false
|
||||||
|
log.log_level(loglevel)
|
||||||
|
break
|
||||||
|
end
|
||||||
|
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.
|
when there is something. it will only check on startup and only once a week.
|
||||||
|
|
||||||
USAGE
|
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
|
* require this script from your main lua file
|
||||||
* restart darktable
|
* restart darktable
|
||||||
|
|
||||||
@@ -34,13 +34,27 @@ local cjson = require "cjson"
|
|||||||
|
|
||||||
du.check_min_api_version("2.0.0", "check_for_updates")
|
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
|
-- return data structure for script_manager
|
||||||
|
|
||||||
local script_data = {}
|
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 = 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.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.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"
|
-- 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,
|
-- 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 dt = require "darktable"
|
||||||
local du = require "lib/dtutils"
|
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")
|
du.check_min_api_version("7.0.0", "copy_paste_metadata")
|
||||||
|
|
||||||
|
local function _(msgid)
|
||||||
|
return gettext(msgid)
|
||||||
|
end
|
||||||
|
|
||||||
-- return data structure for script_manager
|
-- return data structure for script_manager
|
||||||
|
|
||||||
local script_data = {}
|
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 = 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.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.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
|
-- set this to "false" if you don't want to overwrite metadata fields
|
||||||
-- (title, description, creator, publisher and rights) that are already set
|
-- (title, description, creator, publisher and rights) that are already set
|
||||||
@@ -57,13 +69,6 @@ local publisher = ""
|
|||||||
local rights = ""
|
local rights = ""
|
||||||
local tags = {}
|
local tags = {}
|
||||||
|
|
||||||
-- Tell gettext where to find the .mo file translating messages for a particular domain
|
|
||||||
gettext.bindtextdomain("copy_paste_metadata",dt.configuration.config_dir.."/lua/locale/")
|
|
||||||
|
|
||||||
local function _(msgid)
|
|
||||||
return gettext.dgettext("copy_paste_metadata", msgid)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function copy(image)
|
local function copy(image)
|
||||||
if not image then
|
if not image then
|
||||||
have_data = false
|
have_data = false
|
||||||
@@ -146,13 +151,13 @@ dt.gui.libs.image.register_action(
|
|||||||
dt.register_event(
|
dt.register_event(
|
||||||
"capmd1", "shortcut",
|
"capmd1", "shortcut",
|
||||||
function(event, shortcut) copy(dt.gui.action_images[1]) end,
|
function(event, shortcut) copy(dt.gui.action_images[1]) end,
|
||||||
"copy metadata"
|
_("copy metadata")
|
||||||
)
|
)
|
||||||
|
|
||||||
dt.register_event(
|
dt.register_event(
|
||||||
"capmd2", "shortcut",
|
"capmd2", "shortcut",
|
||||||
function(event, shortcut) paste(dt.gui.action_images) end,
|
function(event, shortcut) paste(dt.gui.action_images) end,
|
||||||
"paste metadata"
|
_("paste metadata")
|
||||||
)
|
)
|
||||||
|
|
||||||
script_data.destroy = destroy
|
script_data.destroy = destroy
|
||||||
|
|||||||
@@ -33,13 +33,27 @@ local du = require "lib/dtutils"
|
|||||||
|
|
||||||
du.check_min_api_version("2.0.0", "delete_long_tags")
|
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
|
-- return data structure for script_manager
|
||||||
|
|
||||||
local script_data = {}
|
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 = 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.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.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",
|
dt.preferences.register("delete_long_tags", "length", "integer",
|
||||||
"maximum length of tags to keep",
|
"maximum length of tags to keep",
|
||||||
@@ -58,7 +72,7 @@ local long_tags = {}
|
|||||||
for _,t in ipairs(dt.tags) do
|
for _,t in ipairs(dt.tags) do
|
||||||
local len = #t.name
|
local len = #t.name
|
||||||
if len > max_length then
|
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)
|
table.insert(long_tags, t.name)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -37,13 +37,27 @@ local function destroy()
|
|||||||
-- noting to destroy
|
-- noting to destroy
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local gettext = dt.gettext.gettext
|
||||||
|
|
||||||
|
local function _(msgid)
|
||||||
|
return gettext(msgid)
|
||||||
|
end
|
||||||
|
|
||||||
-- return data structure for script_manager
|
-- return data structure for script_manager
|
||||||
|
|
||||||
local script_data = {}
|
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 = 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.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.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!
|
-- deleting while iterating the tags list seems to break the iterator!
|
||||||
local unused_tags = {}
|
local unused_tags = {}
|
||||||
@@ -55,7 +69,7 @@ for _, t in ipairs(dt.tags) do
|
|||||||
end
|
end
|
||||||
|
|
||||||
for _,name in pairs(unused_tags) do
|
for _,name in pairs(unused_tags) do
|
||||||
print("deleting tag `" .. name .. "'")
|
dt.print_log("deleting tag `" .. name .. "'")
|
||||||
tag = dt.tags.find(name)
|
tag = dt.tags.find(name)
|
||||||
tag:delete()
|
tag:delete()
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -39,35 +39,40 @@ local dtsys = require "lib/dtutils.system"
|
|||||||
|
|
||||||
local PS = dt.configuration.running_os == "windows" and "\\" or "/"
|
local PS = dt.configuration.running_os == "windows" and "\\" or "/"
|
||||||
|
|
||||||
local gettext = dt.gettext
|
local gettext = dt.gettext.gettext
|
||||||
|
|
||||||
du.check_min_api_version("7.0.0", "enfuse")
|
du.check_min_api_version("7.0.0", "enfuse")
|
||||||
|
|
||||||
|
local function _(msgid)
|
||||||
|
return gettext(msgid)
|
||||||
|
end
|
||||||
|
|
||||||
-- return data structure for script_manager
|
-- return data structure for script_manager
|
||||||
|
|
||||||
local script_data = {}
|
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 = 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.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.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("enfuse",dt.configuration.config_dir..PS .. "lua" .. PS .. "locale" .. PS)
|
|
||||||
|
|
||||||
local enf = {}
|
local enf = {}
|
||||||
enf.event_registered = false
|
enf.event_registered = false
|
||||||
enf.module_installed = false
|
enf.module_installed = false
|
||||||
enf.lib_widgets = {}
|
enf.lib_widgets = {}
|
||||||
|
|
||||||
local function _(msgid)
|
|
||||||
return gettext.dgettext("enfuse", msgid)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function install_module()
|
local function install_module()
|
||||||
if not enf.module_installed then
|
if not enf.module_installed then
|
||||||
dt.register_lib(
|
dt.register_lib(
|
||||||
"enfuse", -- plugin name
|
"enfuse", -- plugin name
|
||||||
"enfuse", -- name
|
_("enfuse"), -- name
|
||||||
true, -- expandable
|
true, -- expandable
|
||||||
false, -- resetable
|
false, -- resetable
|
||||||
{[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, -- containers
|
{[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
|
if version < "4.2" then
|
||||||
exposure_mu = dt.new_widget("slider")
|
exposure_mu = dt.new_widget("slider")
|
||||||
{
|
{
|
||||||
label = "exposure mu",
|
label = _("exposure mu"),
|
||||||
tooltip = "center also known as MEAN of Gaussian weighting function (0 <= MEAN <= 1); default: 0.5",
|
tooltip = _("center also known as mean of gaussian weighting function (0 <= mean <= 1); default: 0.5"),
|
||||||
hard_min = 0,
|
hard_min = 0,
|
||||||
hard_max = 1,
|
hard_max = 1,
|
||||||
value = dt.preferences.read("enfuse", "exposure_mu", "float")
|
value = dt.preferences.read("enfuse", "exposure_mu", "float")
|
||||||
@@ -139,8 +144,8 @@ if enfuse_installed then
|
|||||||
else
|
else
|
||||||
exposure_mu = dt.new_widget("slider")
|
exposure_mu = dt.new_widget("slider")
|
||||||
{
|
{
|
||||||
label = "exposure optimum",
|
label = _("exposure optimum"),
|
||||||
tooltip = "optimum exposure value, usually the maximum of the weighting function (0 <= OPTIMUM <=1); default 0.5",
|
tooltip = _("optimum exposure value, usually the maximum of the weighting function (0 <= optimum <=1); default 0.5"),
|
||||||
hard_min = 0,
|
hard_min = 0,
|
||||||
hard_max = 1,
|
hard_max = 1,
|
||||||
value = dt.preferences.read("enfuse", "exposure_optimum", "float")
|
value = dt.preferences.read("enfuse", "exposure_optimum", "float")
|
||||||
@@ -149,8 +154,8 @@ if enfuse_installed then
|
|||||||
|
|
||||||
local depth = dt.new_widget("combobox")
|
local depth = dt.new_widget("combobox")
|
||||||
{
|
{
|
||||||
label = "depth",
|
label = _("depth"),
|
||||||
tooltip = "the number of bits per channel of the output image",
|
tooltip = _("the number of bits per channel of the output image"),
|
||||||
value = dt.preferences.read("enfuse", "depth", "integer"),
|
value = dt.preferences.read("enfuse", "depth", "integer"),
|
||||||
changed_callback = function(w) dt.preferences.write("enfuse", "depth", "integer", w.selected) end,
|
changed_callback = function(w) dt.preferences.write("enfuse", "depth", "integer", w.selected) end,
|
||||||
"8", "16", "32"
|
"8", "16", "32"
|
||||||
@@ -158,15 +163,15 @@ if enfuse_installed then
|
|||||||
|
|
||||||
local blend_colorspace = dt.new_widget("combobox")
|
local blend_colorspace = dt.new_widget("combobox")
|
||||||
{
|
{
|
||||||
label = "blend colorspace",
|
label = _("blend colorspace"),
|
||||||
tooltip = "Force blending in selected colorspace",
|
tooltip = _("force blending in selected colorspace"),
|
||||||
changed_callback = function(w) dt.preferences.write("enfuse", "blend_colorspace", "string", w.selected) end,
|
changed_callback = function(w) dt.preferences.write("enfuse", "blend_colorspace", "string", w.selected) end,
|
||||||
"", "identity", "ciecam"
|
"", "identity", "ciecam"
|
||||||
}
|
}
|
||||||
|
|
||||||
local enfuse_button = dt.new_widget("button")
|
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 ()
|
clicked_callback = function ()
|
||||||
-- remember exposure_mu
|
-- remember exposure_mu
|
||||||
-- TODO: find a way to save it whenever the value changes
|
-- TODO: find a way to save it whenever the value changes
|
||||||
@@ -184,7 +189,7 @@ if enfuse_installed then
|
|||||||
end
|
end
|
||||||
local f = io.open(response_file, "w")
|
local f = io.open(response_file, "w")
|
||||||
if not f then
|
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)
|
os.remove(response_file)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
@@ -207,9 +212,9 @@ if enfuse_installed then
|
|||||||
if dt.configuration.running_os == "windows" then
|
if dt.configuration.running_os == "windows" then
|
||||||
tmp_exported = dt.configuration.tmp_dir .. tmp_exported -- windows os.tmpname() defaults to root directory
|
tmp_exported = dt.configuration.tmp_dir .. tmp_exported -- windows os.tmpname() defaults to root directory
|
||||||
end
|
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)
|
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
|
cnt = cnt + 1
|
||||||
f:write(tmp_exported.."\n")
|
f:write(tmp_exported.."\n")
|
||||||
@@ -217,14 +222,14 @@ if enfuse_installed then
|
|||||||
|
|
||||||
-- other images will be skipped
|
-- other images will be skipped
|
||||||
else
|
else
|
||||||
dt.print(string.format(_("Skipping %s..."), i.filename))
|
dt.print(string.format(_("skipping %s..."), i.filename))
|
||||||
n_skipped = n_skipped + 1
|
n_skipped = n_skipped + 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
f:close()
|
f:close()
|
||||||
-- bail out if there is nothing to do
|
-- bail out if there is nothing to do
|
||||||
if cnt == 0 then
|
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)
|
os.remove(response_file)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
@@ -250,7 +255,7 @@ if enfuse_installed then
|
|||||||
..blend_colorspace_option
|
..blend_colorspace_option
|
||||||
.." -o \""..output_image.."\" \"@"..response_file.."\""
|
.." -o \""..output_image.."\" \"@"..response_file.."\""
|
||||||
if dtsys.external_command( command) > 0 then
|
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)
|
os.remove(response_file)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
@@ -298,7 +303,7 @@ if enfuse_installed then
|
|||||||
else
|
else
|
||||||
dt.print_error("enfuse executable not found")
|
dt.print_error("enfuse executable not found")
|
||||||
error("enfuse executable not found")
|
error("enfuse executable not found")
|
||||||
dt.print(_("Could not find enfuse executable. Not loading enfuse exporter..."))
|
dt.print(_("could not find enfuse executable, not loading enfuse exporter..."))
|
||||||
end
|
end
|
||||||
|
|
||||||
script_data.destroy = destroy
|
script_data.destroy = destroy
|
||||||
|
|||||||
@@ -38,34 +38,48 @@ local dt = require "darktable"
|
|||||||
local du = require "lib/dtutils"
|
local du = require "lib/dtutils"
|
||||||
require "darktable.debug"
|
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")
|
du.check_min_api_version("7.0.0", "generate_image_txt")
|
||||||
|
|
||||||
-- return data structure for script_manager
|
-- return data structure for script_manager
|
||||||
|
|
||||||
local script_data = {}
|
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 = 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.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.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",
|
dt.preferences.register("generate_image_txt",
|
||||||
"enabled",
|
"enabled",
|
||||||
"bool",
|
"bool",
|
||||||
"create txt sidecars to display with images",
|
_("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",
|
_("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)
|
false)
|
||||||
|
|
||||||
dt.preferences.register("generate_image_txt",
|
dt.preferences.register("generate_image_txt",
|
||||||
"command",
|
"command",
|
||||||
"string",
|
"string",
|
||||||
"command to generate the txt sidecar",
|
_("command to generate the txt sidecar"),
|
||||||
"the output of this command gets written to the txt file. use $(FILE_NAME) for the image file",
|
_("the output of this command gets written to the txt file. use $(FILE_NAME) for the image file"),
|
||||||
"exiv2 $(FILE_NAME)")
|
"exiv2 $(FILE_NAME)")
|
||||||
|
|
||||||
|
|
||||||
local check_command = function(command)
|
local check_command = function(command)
|
||||||
if not command:find("$(FILE_NAME)", 1, true) then
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -33,13 +33,27 @@ local du = require "lib/dtutils"
|
|||||||
|
|
||||||
du.check_min_api_version("7.0.0", "image_path_in_ui")
|
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
|
-- return data structure for script_manager
|
||||||
|
|
||||||
local script_data = {}
|
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 = 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.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.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 = {}
|
local ipiu = {}
|
||||||
ipiu.module_installed = false
|
ipiu.module_installed = false
|
||||||
@@ -49,7 +63,7 @@ local main_label = dt.new_widget("label"){selectable = true, ellipsize = "middle
|
|||||||
|
|
||||||
local function install_module()
|
local function install_module()
|
||||||
if not ipiu.module_installed then
|
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}
|
[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_LEFT_CENTER",300}
|
||||||
}, main_label
|
}, main_label
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -32,19 +32,40 @@ USAGE
|
|||||||
|
|
||||||
local dt = require "darktable"
|
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 import_filter_list = {}
|
||||||
local n_import_filters = 1
|
local n_import_filters = 1
|
||||||
|
|
||||||
-- allow changing the filter from the preferences
|
-- allow changing the filter from the preferences
|
||||||
dt.preferences.register("import_filter_manager", "active_filter", "string",
|
dt.preferences.register("import_filter_manager", "active_filter", "string",
|
||||||
"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
|
-- the dropdown to select the active filter from the import dialog
|
||||||
local filter_dropdown = dt.new_widget("combobox")
|
local filter_dropdown = dt.new_widget("combobox")
|
||||||
{
|
{
|
||||||
label = "import filter",
|
label = _("import filter"),
|
||||||
editable = false,
|
editable = false,
|
||||||
|
tooltip = _("import filters are applied after completion of the import dialog"),
|
||||||
|
|
||||||
changed_callback = function(widget)
|
changed_callback = function(widget)
|
||||||
dt.preferences.write("import_filter_manager", "active_filter", "string", widget.value)
|
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
|
if name == active_filter then filter_dropdown.value = n_import_filters end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function destroy()
|
||||||
|
--noting to destroy
|
||||||
|
end
|
||||||
|
|
||||||
|
script_data.destroy = destroy
|
||||||
|
|
||||||
|
return script_data
|
||||||
-- vim: shiftwidth=2 expandtab tabstop=2 cindent
|
-- vim: shiftwidth=2 expandtab tabstop=2 cindent
|
||||||
-- kate: tab-indents: off; indent-width 2; replace-tabs on; remove-trailing-space on;
|
-- kate: tab-indents: off; indent-width 2; replace-tabs on; remove-trailing-space on;
|
||||||
|
|||||||
@@ -30,11 +30,31 @@ USAGE
|
|||||||
|
|
||||||
local dt = require "darktable"
|
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
|
-- we get fed a sorted list of filenames. just setting images to ignore to nil is enough
|
||||||
|
|
||||||
-- ignore jpeg
|
-- ignore jpeg
|
||||||
dt.register_import_filter("ignore jpegs", function(event, images)
|
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
|
for i, img in ipairs(images) do
|
||||||
local extension = img:match("[^.]*$"):upper()
|
local extension = img:match("[^.]*$"):upper()
|
||||||
if (extension == "JPG") or (extension == "JPEG") then
|
if (extension == "JPG") or (extension == "JPEG") then
|
||||||
@@ -88,5 +108,13 @@ dt.register_import_filter("prefer raw over jpeg", function(event, images)
|
|||||||
|
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
local function destroy()
|
||||||
|
-- nothing to destroy
|
||||||
|
end
|
||||||
|
|
||||||
|
script_data.destroy = destroy
|
||||||
|
|
||||||
|
return script_data
|
||||||
|
|
||||||
-- vim: shiftwidth=2 expandtab tabstop=2 cindent
|
-- vim: shiftwidth=2 expandtab tabstop=2 cindent
|
||||||
-- kate: tab-indents: off; indent-width 2; replace-tabs on; remove-trailing-space on;
|
-- kate: tab-indents: off; indent-width 2; replace-tabs on; remove-trailing-space on;
|
||||||
|
|||||||
267
official/regenerate_thumbnails.lua
Normal file
267
official/regenerate_thumbnails.lua
Normal file
@@ -0,0 +1,267 @@
|
|||||||
|
--[[
|
||||||
|
|
||||||
|
regenerate_thumbnails.lua - regenerate mipmap cache for selected images
|
||||||
|
|
||||||
|
Copyright (C) 2025 Bill Ferguson <wpferguson@gmail.com>.
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
]]
|
||||||
|
--[[
|
||||||
|
regenerate_thumbnails - regenerate mipmap cache for selected images
|
||||||
|
|
||||||
|
regenerate_thumbnails drops the cached thumbnail for each selected image
|
||||||
|
and generates a new thumbnail.
|
||||||
|
|
||||||
|
ADDITIONAL SOFTWARE NEEDED FOR THIS SCRIPT
|
||||||
|
None
|
||||||
|
|
||||||
|
USAGE
|
||||||
|
* enable the script in script_manager
|
||||||
|
* assign a shortcut, if desired, to apply the script by hovering
|
||||||
|
over a skull and using the shortcut to regenerate the thumbnail
|
||||||
|
|
||||||
|
BUGS, COMMENTS, SUGGESTIONS
|
||||||
|
Bill Ferguson <wpferguson@gmail.com>
|
||||||
|
|
||||||
|
CHANGES
|
||||||
|
]]
|
||||||
|
|
||||||
|
local dt = require "darktable"
|
||||||
|
local du = require "lib/dtutils"
|
||||||
|
-- local df = require "lib/dtutils.file"
|
||||||
|
-- local ds = require "lib/dtutils.string"
|
||||||
|
-- local dtsys = require "lib/dtutils.system"
|
||||||
|
local log = require "lib/dtutils.log"
|
||||||
|
-- local debug = require "darktable.debug"
|
||||||
|
|
||||||
|
|
||||||
|
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
-- A P I C H E C K
|
||||||
|
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
|
du.check_min_api_version("7.0.0", MODULE) -- choose the minimum version that contains the features you need
|
||||||
|
|
||||||
|
|
||||||
|
-- - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
-- I 1 8 N
|
||||||
|
-- - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
|
local gettext = dt.gettext.gettext
|
||||||
|
|
||||||
|
local function _(msgid)
|
||||||
|
return gettext(msgid)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
-- S C R I P T M A N A G E R I N T E G R A T I O N
|
||||||
|
-- - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
|
local script_data = {}
|
||||||
|
|
||||||
|
script_data.destroy = nil -- function to destory the script
|
||||||
|
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them commpletely yet
|
||||||
|
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again
|
||||||
|
script_data.show = nil -- only required for libs since the destroy_method only hides them
|
||||||
|
|
||||||
|
script_data.metadata = {
|
||||||
|
name = _("regenerate_thumbnails"), -- visible name of script
|
||||||
|
purpose = _("regenerate mipmap cache for selected images"), -- purpose of script
|
||||||
|
author = "Bill Ferguson <wpferguson@gmail.com>", -- your name and optionally e-mail address
|
||||||
|
help = "https://docs.darktable.org/lua/development/lua.scripts.manual/scripts/official/regenerate_thumbnails" -- URL to help/documentation
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
-- C O N S T A N T S
|
||||||
|
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
|
local MODULE <const> = "regenerate_thumbnails"
|
||||||
|
local DEFAULT_LOG_LEVEL <const> = log.info
|
||||||
|
local TMP_DIR <const> = dt.configuration.tmp_dir
|
||||||
|
|
||||||
|
-- path separator
|
||||||
|
local PS <const> = dt.configuration.running_os == "windows" and "\\" or "/"
|
||||||
|
|
||||||
|
-- command separator
|
||||||
|
local CS <const> = dt.configuration.running_os == "windows" and "&" or ";"
|
||||||
|
|
||||||
|
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
-- L O G L E V E L
|
||||||
|
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
|
log.log_level(DEFAULT_LOG_LEVEL)
|
||||||
|
|
||||||
|
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
-- N A M E S P A C E
|
||||||
|
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
|
local regenerate_thumbnails = {}
|
||||||
|
|
||||||
|
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
-- G L O B A L V A R I A B L E S
|
||||||
|
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
|
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
-- P R E F E R E N C E S
|
||||||
|
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
|
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
-- A L I A S E S
|
||||||
|
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
|
local namespace = regenerate_thumbnails
|
||||||
|
local rt = regenerate_thumbnails
|
||||||
|
|
||||||
|
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
-- F U N C T I O N S
|
||||||
|
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
|
-------------------
|
||||||
|
-- helper functions
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
local function set_log_level(level)
|
||||||
|
local old_log_level = log.log_level()
|
||||||
|
log.log_level(level)
|
||||||
|
return old_log_level
|
||||||
|
end
|
||||||
|
|
||||||
|
local function restore_log_level(level)
|
||||||
|
log.log_level(level)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function pref_read(name, pref_type)
|
||||||
|
local old_log_level = set_log_level(sm.log_level)
|
||||||
|
|
||||||
|
log.msg(log.debug, "name is " .. name .. " and type is " .. pref_type)
|
||||||
|
|
||||||
|
local val = dt.preferences.read(MODULE, name, pref_type)
|
||||||
|
|
||||||
|
log.msg(log.debug, "read value " .. tostring(val))
|
||||||
|
|
||||||
|
restore_log_level(old_log_level)
|
||||||
|
return val
|
||||||
|
end
|
||||||
|
|
||||||
|
local function pref_write(name, pref_type, value)
|
||||||
|
local old_log_level = set_log_level(sm.log_level)
|
||||||
|
|
||||||
|
log.msg(log.debug, "writing value " .. tostring(value) .. " for name " .. name)
|
||||||
|
|
||||||
|
dt.preferences.write(MODULE, name, pref_type, value)
|
||||||
|
|
||||||
|
restore_log_level(old_log_level)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function stop_job()
|
||||||
|
rt.job.valid = false
|
||||||
|
end
|
||||||
|
|
||||||
|
local function generate_thumbnails(images)
|
||||||
|
local has_job = false
|
||||||
|
|
||||||
|
if #images > 50 then
|
||||||
|
rt.job = dt.gui.create_job("regenerating thumbnails", true, stop_job)
|
||||||
|
has_job = true
|
||||||
|
end
|
||||||
|
|
||||||
|
for count, image in ipairs(images) do
|
||||||
|
image:drop_cache()
|
||||||
|
image:generate_cache(true, 1, 3)
|
||||||
|
if has_job then
|
||||||
|
if not rt.job.valid then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if count % 10 == 0 then
|
||||||
|
rt.job.percent = count / #images
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if has_job then
|
||||||
|
rt.job.valid = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function update_button_sensitivity()
|
||||||
|
if #dt.gui.action_images > 0 then
|
||||||
|
dt.gui.libs.image.set_sensitive(MODULE, true)
|
||||||
|
else
|
||||||
|
dt.gui.libs.image.set_sensitive(MODULE, false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
-- M A I N P R O G R A M
|
||||||
|
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
|
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
-- U S E R I N T E R F A C E
|
||||||
|
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
|
dt.gui.libs.image.register_action(
|
||||||
|
MODULE,
|
||||||
|
_("generate thumbnails"),
|
||||||
|
function(event, images)
|
||||||
|
generate_thumbnails(images)
|
||||||
|
end,
|
||||||
|
_("generate thumbnails")
|
||||||
|
)
|
||||||
|
|
||||||
|
update_button_sensitivity()
|
||||||
|
|
||||||
|
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
-- D A R K T A B L E I N T E G R A T I O N
|
||||||
|
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
|
local function destroy()
|
||||||
|
dt.destroy_event(MODULE, "selection-changed")
|
||||||
|
dt.destroy_event(MODULE, "mouse-over-image-changed")
|
||||||
|
dt.gui.libs.image.destroy_action(MODULE, "regenerate thumbnails")
|
||||||
|
end
|
||||||
|
|
||||||
|
script_data.destroy = destroy
|
||||||
|
|
||||||
|
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
-- E V E N T S
|
||||||
|
-- - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
|
dt.register_event(MODULE, "shortcut",
|
||||||
|
function(event, shortcut)
|
||||||
|
local images = dt.gui.action_images
|
||||||
|
if images then
|
||||||
|
generate_thumbnails(images)
|
||||||
|
end
|
||||||
|
end, "regenerate thumbnails"
|
||||||
|
)
|
||||||
|
|
||||||
|
dt.register_event(MODULE, "selection-changed",
|
||||||
|
function(event)
|
||||||
|
update_button_sensitivity()
|
||||||
|
end
|
||||||
|
)
|
||||||
|
|
||||||
|
dt.register_event(MODULE, "mouse-over-image-changed",
|
||||||
|
function(event, image)
|
||||||
|
if #dt.gui.selection() < 1 then
|
||||||
|
if image then
|
||||||
|
dt.gui.libs.image.set_sensitive(MODULE, true)
|
||||||
|
else
|
||||||
|
dt.gui.libs.image.set_sensitive(MODULE, false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
)
|
||||||
|
|
||||||
|
return script_data
|
||||||
@@ -38,13 +38,27 @@ local du = require "lib/dtutils"
|
|||||||
|
|
||||||
du.check_min_api_version("7.0.0", "save_selection")
|
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
|
-- return data structure for script_manager
|
||||||
|
|
||||||
local script_data = {}
|
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 = 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.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.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
|
local buffer_count = 5
|
||||||
|
|
||||||
@@ -60,16 +74,16 @@ for i = 1, buffer_count do
|
|||||||
local saved_selection
|
local saved_selection
|
||||||
dt.register_event("save_selection save " .. i, "shortcut", function()
|
dt.register_event("save_selection save " .. i, "shortcut", function()
|
||||||
saved_selection = dt.gui.selection()
|
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.register_event("save_selection restore " .. i, "shortcut", function()
|
||||||
dt.gui.selection(saved_selection)
|
dt.gui.selection(saved_selection)
|
||||||
end, "restore from buffer " .. i)
|
end, string.format(_("restore from buffer %d"), i))
|
||||||
end
|
end
|
||||||
|
|
||||||
local bounce_buffer = {}
|
local bounce_buffer = {}
|
||||||
dt.register_event("save_selection switch", "shortcut", function()
|
dt.register_event("save_selection switch", "shortcut", function()
|
||||||
bounce_buffer = dt.gui.selection(bounce_buffer)
|
bounce_buffer = dt.gui.selection(bounce_buffer)
|
||||||
end, "switch selection with temporary buffer")
|
end, _("switch selection with temporary buffer"))
|
||||||
|
|
||||||
script_data.destroy = destroy
|
script_data.destroy = destroy
|
||||||
|
|
||||||
|
|||||||
@@ -38,26 +38,44 @@ local du = require "lib/dtutils"
|
|||||||
|
|
||||||
du.check_min_api_version("7.0.0", "selection_to_pdf")
|
du.check_min_api_version("7.0.0", "selection_to_pdf")
|
||||||
|
|
||||||
|
local gettext = dt.gettext.gettext
|
||||||
|
|
||||||
|
local function _(msg)
|
||||||
|
return gettext(msg)
|
||||||
|
end
|
||||||
|
|
||||||
|
local NIX_OPEN <const> = "xdg-open "
|
||||||
|
local MAC_OPEN <const> = "open "
|
||||||
|
local WIN_OPEN <const> = "start "
|
||||||
|
|
||||||
-- return data structure for script_manager
|
-- return data structure for script_manager
|
||||||
|
|
||||||
local script_data = {}
|
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 = 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.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.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
|
dt.preferences.register
|
||||||
("selection_to_pdf","Open with","string",
|
("selection_to_pdf","Open with","string",
|
||||||
"a pdf viewer",
|
_("a pdf viewer"),
|
||||||
"Can be an absolute pathname or the tool may be in the PATH",
|
_("can be an absolute pathname or the tool may be in the PATH\nif not specified the system default will be used to open the pdf"),
|
||||||
"xdg-open")
|
"")
|
||||||
|
|
||||||
local title_widget = dt.new_widget("entry") {
|
local title_widget = dt.new_widget("entry") {
|
||||||
placeholder="Title"
|
placeholder = _("title")
|
||||||
}
|
}
|
||||||
local no_of_thumbs_widget = dt.new_widget("slider")
|
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_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
|
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
|
hard_min = 1, -- The hard minimum value for the slider, the user can't manually enter a value beyond this point
|
||||||
@@ -65,10 +83,10 @@ local no_of_thumbs_widget = dt.new_widget("slider")
|
|||||||
value = 4 -- The current value of the slider
|
value = 4 -- The current value of the slider
|
||||||
}
|
}
|
||||||
local widget = dt.new_widget("box") {
|
local widget = dt.new_widget("box") {
|
||||||
orientation=horizontal,
|
orientation = horizontal,
|
||||||
dt.new_widget("label"){label = "Title:"},
|
dt.new_widget("label"){label = _("title:")},
|
||||||
title_widget,
|
title_widget,
|
||||||
dt.new_widget("label"){label = "Thumbnails per row:"},
|
dt.new_widget("label"){label = _("thumbnails per row:")},
|
||||||
no_of_thumbs_widget
|
no_of_thumbs_widget
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,8 +119,9 @@ local function thumbnail(latexfile,i,image,file)
|
|||||||
-- fact is that latex will get confused if the filename has multiple dots.
|
-- fact is that latex will get confused if the filename has multiple dots.
|
||||||
-- so \includegraphics{file.01.jpg} wont work. We need to output the filename
|
-- so \includegraphics{file.01.jpg} wont work. We need to output the filename
|
||||||
-- and extention separated, e.g: \includegraphics{{file.01}.jpg}
|
-- and extention separated, e.g: \includegraphics{{file.01}.jpg}
|
||||||
local filenoext=string.gsub(file, "(.*)(%..*)", "%1")
|
|
||||||
local ext=string.gsub(file, "(.*)(%..*)", "%2")
|
local filenoext = string.gsub(file, "(.*)(%..*)", "%1")
|
||||||
|
local ext = string.gsub(file, "(.*)(%..*)", "%2")
|
||||||
my_write(latexfile,"\\begin{minipage}[b]{"..width.."\\textwidth}\n")
|
my_write(latexfile,"\\begin{minipage}[b]{"..width.."\\textwidth}\n")
|
||||||
my_write(latexfile,"\\includegraphics[width=\\textwidth]{{"..filenoext.."}"..ext.."}\\newline\n")
|
my_write(latexfile,"\\includegraphics[width=\\textwidth]{{"..filenoext.."}"..ext.."}\\newline\n")
|
||||||
my_write(latexfile,"\\centering{"..i..": \\verb|"..title.."|}\n")
|
my_write(latexfile,"\\centering{"..i..": \\verb|"..title.."|}\n")
|
||||||
@@ -115,7 +134,7 @@ local function destroy()
|
|||||||
dt.print_log("done destroying")
|
dt.print_log("done destroying")
|
||||||
end
|
end
|
||||||
|
|
||||||
dt.register_storage("export_pdf","Export thumbnails to pdf",
|
dt.register_storage("export_pdf", _("export thumbnails to pdf"),
|
||||||
nil,
|
nil,
|
||||||
function(storage,image_table)
|
function(storage,image_table)
|
||||||
local my_title = title_widget.text
|
local my_title = title_widget.text
|
||||||
@@ -124,7 +143,7 @@ dt.register_storage("export_pdf","Export thumbnails to pdf",
|
|||||||
end
|
end
|
||||||
local thumbs_per_line = no_of_thumbs_widget.value
|
local thumbs_per_line = no_of_thumbs_widget.value
|
||||||
thumbs_per_line = tonumber(thumbs_per_line)
|
thumbs_per_line = tonumber(thumbs_per_line)
|
||||||
width = (1/thumbs_per_line) - 0.01
|
width = (1 / thumbs_per_line) - 0.01
|
||||||
|
|
||||||
local preamble = [[
|
local preamble = [[
|
||||||
\documentclass[a4paper,10pt]{article}
|
\documentclass[a4paper,10pt]{article}
|
||||||
@@ -134,45 +153,54 @@ dt.register_storage("export_pdf","Export thumbnails to pdf",
|
|||||||
\usepackage{geometry}
|
\usepackage{geometry}
|
||||||
\geometry{a4paper,left=5mm,right=5mm, top=5mm, bottom=5mm}
|
\geometry{a4paper,left=5mm,right=5mm, top=5mm, bottom=5mm}
|
||||||
\begin{document}
|
\begin{document}
|
||||||
{\Large\bfseries ]]..my_title..[[} \\
|
{\Large\bfseries ]] .. my_title .. [[} \\
|
||||||
\bigskip\bigskip
|
\bigskip\bigskip
|
||||||
]]
|
]]
|
||||||
|
|
||||||
local errmsg
|
local errmsg
|
||||||
local latexfile
|
local latexfile
|
||||||
latexfile,errmsg=io.open(filename,"w")
|
latexfile,errmsg = io.open(filename, "w")
|
||||||
if not latexfile then
|
if not latexfile then
|
||||||
error(errmsg)
|
error(errmsg)
|
||||||
end
|
end
|
||||||
my_write(latexfile,preamble)
|
my_write(latexfile, preamble)
|
||||||
local i = 1
|
local i = 1
|
||||||
for img,file in pairs(image_table) do
|
for img, file in pairs(image_table) do
|
||||||
thumbnail(latexfile,i,img,file)
|
thumbnail(latexfile, i, img, file)
|
||||||
if i % thumbs_per_line == 0 then
|
if i % thumbs_per_line == 0 then
|
||||||
my_write(latexfile,"\n\\bigskip\n")
|
my_write(latexfile, "\n\\bigskip\n")
|
||||||
end
|
end
|
||||||
i = i+1
|
i = i + 1
|
||||||
end
|
end
|
||||||
my_write(latexfile,ending)
|
my_write(latexfile,ending)
|
||||||
latexfile:close()
|
latexfile:close()
|
||||||
|
|
||||||
-- convert to PDF
|
-- convert to PDF
|
||||||
local dir=string.gsub(filename, "(.*/)(.*)", "%1")
|
local dir = string.gsub(filename, "(.*/)(.*)", "%1")
|
||||||
local locfile=string.gsub(filename, "(.*/)(.*)", "%2")
|
local locfile = string.gsub(filename, "(.*/)(.*)", "%2")
|
||||||
local command = "pdflatex -halt-on-error -output-directory "..dir.." "..locfile
|
local command = "pdflatex -halt-on-error -output-directory "..dir.." "..locfile
|
||||||
local result = dt.control.execute(command)
|
local result = dt.control.execute(command)
|
||||||
if result ~= 0 then
|
if result ~= 0 then
|
||||||
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)
|
error("Problem running "..command)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- open the PDF
|
-- open the PDF
|
||||||
local pdffile=string.gsub(filename, ".tex", ".pdf")
|
local pdffile = string.gsub(filename, ".tex", ".pdf")
|
||||||
command = dt.preferences.read("selection_to_pdf","Open with","string")
|
command = dt.preferences.read("selection_to_pdf","Open with","string")
|
||||||
command = command.." "..pdffile
|
if command == "" then
|
||||||
|
if dt.configuration.running_os == "windows" then
|
||||||
|
command = WIN_OPEN
|
||||||
|
elseif dt.configuration.running_os == "macos" then
|
||||||
|
command = MAC_OPEN
|
||||||
|
else
|
||||||
|
command = NIX_OPEN
|
||||||
|
end
|
||||||
|
end
|
||||||
|
command = command .. " " .. pdffile
|
||||||
local result = dt.control.execute(command)
|
local result = dt.control.execute(command)
|
||||||
if result ~= 0 then
|
if result ~= 0 then
|
||||||
dt.print("Problem running pdf viewer") -- this one is probably usefull to the user
|
dt.print(_("problem running pdf viewer")) -- this one is probably usefull to the user
|
||||||
error("Problem running "..command)
|
error("Problem running "..command)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -31,23 +31,34 @@
|
|||||||
local dt = require "darktable"
|
local dt = require "darktable"
|
||||||
local du = require "lib/dtutils"
|
local du = require "lib/dtutils"
|
||||||
local df = require "lib/dtutils.file"
|
local df = require "lib/dtutils.file"
|
||||||
|
local dtsys = require "lib/dtutils.system"
|
||||||
|
|
||||||
du.check_min_api_version("7.0.0", "executable_manager")
|
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
|
-- return data structure for script_manager
|
||||||
|
|
||||||
local script_data = {}
|
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 = 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.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.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 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
|
local exec_man = {} -- our own namespace
|
||||||
exec_man.module_installed = false
|
exec_man.module_installed = false
|
||||||
exec_man.event_registered = false
|
exec_man.event_registered = false
|
||||||
@@ -56,10 +67,6 @@ exec_man.event_registered = false
|
|||||||
-- F U N C T I O N S
|
-- 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 function grep(file, pattern)
|
||||||
|
|
||||||
local result = {}
|
local result = {}
|
||||||
@@ -99,13 +106,19 @@ local function update_combobox_choices(combobox, choice_table, selected)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local function install_module()
|
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
|
if not exec_man.module_installed then
|
||||||
dt.register_lib(
|
dt.register_lib(
|
||||||
"executable_manager", -- Module name
|
"executable_manager", -- Module name
|
||||||
"executable manager", -- Visible name
|
_("executables"), -- Visible name
|
||||||
true, -- expandable
|
true, -- expandable
|
||||||
false, -- resetable
|
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
|
dt.new_widget("box") -- widget
|
||||||
{
|
{
|
||||||
orientation = "vertical",
|
orientation = "vertical",
|
||||||
@@ -141,7 +154,7 @@ local matches = grep(DARKTABLERC, "executable_paths")
|
|||||||
-- check if we have something to manage and exit if not
|
-- check if we have something to manage and exit if not
|
||||||
|
|
||||||
if #matches == 0 then
|
if #matches == 0 then
|
||||||
dt.print(_("No executable paths found, exiting..."))
|
dt.print(_("no executable paths found, exiting..."))
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -166,7 +179,7 @@ for i,exec in ipairs(exec_table) do
|
|||||||
editable = false
|
editable = false
|
||||||
}
|
}
|
||||||
executable_path_widgets[exec] = dt.new_widget("file_chooser_button"){
|
executable_path_widgets[exec] = dt.new_widget("file_chooser_button"){
|
||||||
title = _("select ") .. exec .. _(" executable"),
|
title = _(string.format("select %s executable", exec)),
|
||||||
value = df.get_executable_path_preference(exec),
|
value = df.get_executable_path_preference(exec),
|
||||||
is_directory = false,
|
is_directory = false,
|
||||||
changed_callback = function(self)
|
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
|
-- create a combobox to for indexing into the stack of widgets
|
||||||
|
|
||||||
exec_man.selector = dt.new_widget("combobox"){
|
exec_man.selector = dt.new_widget("combobox"){
|
||||||
label = "executable",
|
label = _("executable"),
|
||||||
tooltip = _("select executable to modify"),
|
tooltip = _("select executable to modify"),
|
||||||
value = 1, "placeholder",
|
value = 1, "placeholder",
|
||||||
changed_callback = function(self)
|
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("section_label"){label = _("reset")},
|
||||||
dt.new_widget("button"){
|
dt.new_widget("button"){
|
||||||
label = _("clear"),
|
label = _("clear"),
|
||||||
tooltip = _("Clear path for ") .. exec,
|
tooltip = string.format(_("clear path for %s"), exec),
|
||||||
clicked_callback = function()
|
clicked_callback = function()
|
||||||
df.set_executable_path_preference(exec, "")
|
df.set_executable_path_preference(exec, "")
|
||||||
executable_path_widgets[exec].value = ""
|
executable_path_widgets[exec].value = ""
|
||||||
|
|||||||
@@ -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 dt = require "darktable"
|
||||||
local du = require "lib/dtutils"
|
local du = require "lib/dtutils"
|
||||||
local df = require "lib/dtutils.file"
|
local df = require "lib/dtutils.file"
|
||||||
|
local dtsys = require "lib/dtutils.system"
|
||||||
local log = require "lib/dtutils.log"
|
local log = require "lib/dtutils.log"
|
||||||
local libname = nil
|
local libname = nil
|
||||||
|
|
||||||
du.check_min_api_version("3.0.0", "get_lib_manpages")
|
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()
|
local function destroy()
|
||||||
-- nothing to destroy
|
-- nothing to destroy
|
||||||
end
|
end
|
||||||
@@ -79,6 +86,14 @@ for line in output:lines() do
|
|||||||
end
|
end
|
||||||
|
|
||||||
local script_data = {}
|
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
|
script_data.destroy = destroy
|
||||||
|
|
||||||
return script_data
|
return script_data
|
||||||
|
|||||||
@@ -6,9 +6,16 @@
|
|||||||
|
|
||||||
local dt = require "darktable"
|
local dt = require "darktable"
|
||||||
local du = require "lib/dtutils"
|
local du = require "lib/dtutils"
|
||||||
|
local dtsys = require "lib/dtutils.system"
|
||||||
|
|
||||||
du.check_min_api_version("3.0.0", "get_libdoc")
|
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()
|
local function destroy()
|
||||||
-- nothing to destroy
|
-- nothing to destroy
|
||||||
end
|
end
|
||||||
@@ -53,6 +60,14 @@ for line in output:lines() do
|
|||||||
end
|
end
|
||||||
|
|
||||||
local script_data = {}
|
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
|
script_data.destroy = destroy
|
||||||
|
|
||||||
return script_data
|
return script_data
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user