From 11607e7e7db86da3a5acc4b5eb1fc33c411cdbc2 Mon Sep 17 00:00:00 2001 From: Simon Legner Date: Tue, 18 Sep 2018 10:26:40 +0200 Subject: [PATCH 01/10] Delete compiled .mo files --- locale/de_DE/LC_MESSAGES/select_untagged.mo | Bin 785 -> 0 bytes locale/fr_FR/LC_MESSAGES/select_untagged.mo | Bin 769 -> 0 bytes 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 locale/de_DE/LC_MESSAGES/select_untagged.mo delete mode 100644 locale/fr_FR/LC_MESSAGES/select_untagged.mo diff --git a/locale/de_DE/LC_MESSAGES/select_untagged.mo b/locale/de_DE/LC_MESSAGES/select_untagged.mo deleted file mode 100644 index 340ba90447fac80fea4888a0ce5e3962919feabd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 785 zcmZva&2G~`5P%Jo1HK?}-~`fe1Hrm>Kx%Nvfi@{BYSoB_!U3t8*n_=fvm5rOkUj+$ z-hgM|1(0|PxO3(O7{>{b5G#Kk&(7@3cxHdz*!mpt+G1`oPnfIB8>U%vX285>t}|bm zo6L9S)1@f-!SaI9m!s$!%U>*Sv;57H%@K>`y29@!N90IR;Q^HbIm3z^6h?cLTIve4 z0gsgfW5H;(Xca6=Dq*sK67AIEMA14(;Dc2~<-htWax}8$9VZh9r8p()q|rIVqvNsI zvxJ^iF+fi_bkb}`q>n}R2(nI|b?>L0G-XHeg3e`g?7x1UhppcsIxof+wNvPg&EYv} zE#28^e2BUV{EuQxIOEi7J%^Ic2E+L1;Apt1EKAaOk9$Fy!!71qm#2?@d#<=SJt%6l zj(q>+cwclkeofl9WW`VyrsNjp(49yhzZTC(lWpr687ifREa@gYNyfHzL+qlXIr=(> zB-w7CW)@aX;*km#mDo3S=5o;UrRw^f9<-nRyBhBFA-mVxggYU$MLptxBF&+l^Vxbt zi3%7;ufBb$6*a>r*p;dz%bl=*Qy+-;G@RgUrUKst4DJDxl3+?w6O5O)qVd&%{ew3% u9-u2~C<7wQ6t(2igV|wIV8^;sA;!_SSJ(@0#6pMZSU) zAJHG+2P$#l6A*k0&vl{{#DS5Y$Fuu(W_F%`-QD;Sz&3#Uz*FEh@D6CL2KIoDz#ZT# za1Zzfe7+F`KjGg4)y;1IJNyI0Kj5()z+KrbyxSUqlS*cuSScziE~KN(XwRiCbwS#Y z=faV(WVBjz0q42QX||x8?FY{@C09ur94rc%{~a$g2V-l_P)r=;;zU|k8l6%&el-!h zROGEoaSWn3mgi-A?4P{tCGU`(7Zc0cDfY&u^pdqM z-Si|pWL-44qnJppPlKF~XGkv(kre#S5vW?fMxTnU|iDs2}Y_3HG`L@tmEk+0Rpo zqRsAUwXo$Z9IM8%5+h?Pmy)ipLO1LUsQVl~)bxy!M}u{?*OF~EA0wZLQ|e@%t`v$? z!(reqFIw?2P|6|vQh$dlP-VOmnYz4y_zg}sN>&&I@wv=Mfqad?XQuHjvu1n!r}#6^ I|5Xcq1G;nS^#A|> From 7ee140c8c8e42876ea8f5b5c1024683f1a1cc65e Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Thu, 19 Dec 2019 13:38:25 -0500 Subject: [PATCH 02/10] created 3 demonstration scripts of the dt3.0 lua API additions --- examples/darkroom_demo.lua | 98 +++++++++++++++++ examples/lighttable_demo.lua | 198 +++++++++++++++++++++++++++++++++++ examples/panels_demo.lua | 136 ++++++++++++++++++++++++ 3 files changed, 432 insertions(+) create mode 100644 examples/darkroom_demo.lua create mode 100644 examples/lighttable_demo.lua create mode 100644 examples/panels_demo.lua diff --git a/examples/darkroom_demo.lua b/examples/darkroom_demo.lua new file mode 100644 index 0000000..e0e4052 --- /dev/null +++ b/examples/darkroom_demo.lua @@ -0,0 +1,98 @@ +--[[ + This file is part of darktable, + copyright (c) 2019 Bill Ferguson + + 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 . +]] +--[[ + darkroom_demo - an example script demonstrating how to control image display in darkroom mode + + darkroom_demo is an example script showing how to control the currently displayed image in + darkroom mode using lua. + + ADDITIONAL SOFTWARE NEEDED FOR THIS SCRIPT + * none + + USAGE + * require this script from your main lua file + + BUGS, COMMENTS, SUGGESTIONS + * Send to Bill Ferguson, wpferguson@gmail.com + + CHANGES +]] + +local dt = require "darktable" +local du = require "lib/dtutils" + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- V E R S I O N C H E C K +-- - - - - - - - - - - - - - - - - - - - - - - - + +du.check_min_api_version("5.0.2", "darkroom_mode") -- darktable 3.0 + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- C O N S T A N T S +-- - - - - - - - - - - - - - - - - - - - - - - - + +local MODULE_NAME = "darkroom" +local PS = dt.configuration.running_os == "windows" and "\\" or "/" + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- T R A N S L A T I O N S +-- - - - - - - - - - - - - - - - - - - - - - - - +local gettext = dt.gettext +gettext.bindtextdomain(MODULE_NAME, dt.configuration.config_dir..PS.."lua"..PS.."locale"..PS) + +local function _(msgid) + return gettext.dgettext(MODULE_NAME, msgid) +end + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- M A I N +-- - - - - - - - - - - - - - - - - - - - - - - - + +-- alias dt.control.sleep to sleep +local sleep = dt.control.sleep + +-- save the configuration + +local current_view = dt.gui.current_view() + +-- enter darkroom view + +dt.gui.current_view(dt.gui.views.darkroom) + +local max_images = 10 + +dt.print(_("Showing images, with a pause in between each")) +sleep(1500) + +-- display first 10 images of collection pausing for a second between each + +for i, img in ipairs(dt.collection) do + dt.print(_("Displaying image " .. i)) + dt.gui.views.darkroom.display_image(img) + sleep(1500) + if i == max_images then + break + end +end + +-- return to lighttable view + +dt.print(_("Restoring view")) +sleep(1500) +dt.gui.current_view(current_view) + diff --git a/examples/lighttable_demo.lua b/examples/lighttable_demo.lua new file mode 100644 index 0000000..c3629ba --- /dev/null +++ b/examples/lighttable_demo.lua @@ -0,0 +1,198 @@ +--[[ + This file is part of darktable, + copyright (c) 2019 Bill Ferguson + + 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 . +]] +--[[ + lighttable_demo - an example script demonstrating how to control lighttable display modes + + lighttable_demo is an example script showing how to control lighttable layout, sorting, and + filtering from a lua script. If the selected directory has different ratings, color labels, etc, + then the sorting and filtering display is a little clearer. + + ADDITIONAL SOFTWARE NEEDED FOR THIS SCRIPT + * none + + USAGE + * require this script from your main lua file + + BUGS, COMMENTS, SUGGESTIONS + * Send to Bill Ferguson, wpferguson@gmail.com + + CHANGES +]] + +local dt = require "darktable" +local du = require "lib/dtutils" + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- V E R S I O N C H E C K +-- - - - - - - - - - - - - - - - - - - - - - - - + +du.check_min_api_version("5.0.2", "lighttable_demo") -- darktable 3.0 + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- C O N S T A N T S +-- - - - - - - - - - - - - - - - - - - - - - - - + +local MODULE_NAME = "lighttable" +local PS = dt.configuration.running_os == "windows" and "\\" or "/" + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- T R A N S L A T I O N S +-- - - - - - - - - - - - - - - - - - - - - - - - +local gettext = dt.gettext +gettext.bindtextdomain(MODULE_NAME, dt.configuration.config_dir..PS.."lua"..PS.."locale"..PS) + +local function _(msgid) + return gettext.dgettext(MODULE_NAME, msgid) +end + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- F U N C T I O N S +-- - - - - - - - - - - - - - - - - - - - - - - - + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- M A I N +-- - - - - - - - - - - - - - - - - - - - - - - - + +-- alias dt.control.sleep to sleep +local sleep = dt.control.sleep + +local layouts = { + "DT_LIGHTTABLE_LAYOUT_ZOOMABLE", + "DT_LIGHTTABLE_LAYOUT_FILEMANAGER", + "DT_LIGHTTABLE_LAYOUT_CULLING", +} + +local sorts = { + "DT_COLLECTION_SORT_NONE", + "DT_COLLECTION_SORT_FILENAME", + "DT_COLLECTION_SORT_DATETIME", + "DT_COLLECTION_SORT_RATING", + "DT_COLLECTION_SORT_ID", + "DT_COLLECTION_SORT_COLOR", + "DT_COLLECTION_SORT_GROUP", + "DT_COLLECTION_SORT_PATH", + "DT_COLLECTION_SORT_CUSTOM_ORDER", + "DT_COLLECTION_SORT_TITLE", + "DT_COLLECTION_SORT_DESCRIPTION", + "DT_COLLECTION_SORT_ASPECT_RATIO", + "DT_COLLECTION_SORT_SHUFFLE" +} + +local sort_orders = { + "DT_COLLECTION_SORT_ORDER_ASCENDING", + "DT_COLLECTION_SORT_ORDER_DESCENDING" +} + +local ratings = { + "DT_COLLECTION_FILTER_ALL", + "DT_COLLECTION_FILTER_STAR_NO", + "DT_COLLECTION_FILTER_STAR_1", + "DT_COLLECTION_FILTER_STAR_2", + "DT_COLLECTION_FILTER_STAR_3", + "DT_COLLECTION_FILTER_STAR_4", + "DT_COLLECTION_FILTER_STAR_5", + "DT_COLLECTION_FILTER_REJECT", + "DT_COLLECTION_FILTER_NOT_REJECT" +} + +local rating_comparators = { + "DT_COLLECTION_RATING_COMP_LT", + "DT_COLLECTION_RATING_COMP_LEQ", + "DT_COLLECTION_RATING_COMP_EQ", + "DT_COLLECTION_RATING_COMP_GEQ", + "DT_COLLECTION_RATING_COMP_GT", + "DT_COLLECTION_RATING_COMP_NE" +} + +local zoom_levels = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10} + + +-- save filter, view, and collection parameters + +local current_layout = dt.gui.libs.lighttable_mode.layout() +local current_zoom_level = dt.gui.libs.lighttable_mode.zoom_level() +local current_rating = dt.gui.libs.filter.rating() +local current_rating_comparator = dt.gui.libs.filter.rating_comparator() +local current_sort = dt.gui.libs.filter.sort() +local current_sort_order = dt.gui.libs.filter.sort_order() + +-- cycle through layouts and zooms + +dt.print(_("lighttable layout and zoom level demonstration")) +sleep(2000) + +for n, layout in ipairs(layouts) do + dt.gui.libs.lighttable_mode.layout(layout) + dt.print(_("set lighttable layout to " .. layout)) + sleep(1500) + for i = 1, 10 do + dt.gui.libs.lighttable_mode.zoom_level(i) + dt.print(_("Set zoom level to " .. i)) + sleep(1500) + end + for i = 9, 1, -1 do + dt.gui.libs.lighttable_mode.zoom_level(i) + dt.print(_("Set zoom level to " .. i)) + sleep(1500) + end +end + +-- cycle through sorts + +dt.print(_("lighttable sorting demonstration")) +dt.gui.libs.lighttable_mode.layout("DT_LIGHTTABLE_LAYOUT_FILEMANAGER") +dt.gui.libs.lighttable_mode.zoom_level(5) + +for n, sort in ipairs(sorts) do + dt.gui.libs.filter.sort(sort) + dt.print(_("set lighttable sort to " .. sort)) + sleep(1500) + + for m, sort_order in ipairs(sort_orders) do + dt.gui.libs.filter.sort_order(sort_order) + dt.print(_("sort order set to " .. sort_order)) + sleep(1500) + end +end + +-- cycle through filters + +dt.print(_("lighttable filtering demonstration")) + +for n, rating in ipairs(ratings) do + dt.gui.libs.filter.rating(rating) + dt.print(_("set filter to " .. rating)) + sleep(1500) + + for m, rating_comparator in ipairs(rating_comparators) do + dt.gui.libs.filter.rating_comparator(rating_comparator) + dt.print(_("set rating comparator to " .. rating_comparator)) + sleep(1500) + end +end + +-- restore settings + +dt.print(_("restoring settings")) + +current_layout = dt.gui.libs.lighttable_mode.layout(current_layout) +current_zoom_level = dt.gui.libs.lighttable_mode.zoom_level(current_zoom_level) +current_rating = dt.gui.libs.filter.rating(current_rating) +current_rating_comparator = dt.gui.libs.filter.rating_comparator(current_rating_comparator) +current_sort =dt.gui.libs.filter.sort(current_sort) +current_sort_order = dt.gui.libs.filter.sort_order(current_sort_order) diff --git a/examples/panels_demo.lua b/examples/panels_demo.lua new file mode 100644 index 0000000..edab6ae --- /dev/null +++ b/examples/panels_demo.lua @@ -0,0 +1,136 @@ +--[[ + This file is part of darktable, + copyright (c) 2019 Bill Ferguson + + 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 . +]] +--[[ + panels_demo - an example script demonstrating how to contol panel visibility + + panels_demo is an example script showing how to control panel visibility. It cycles + through the panels hiding them one by one, then showing them one by one, then + hiding all, then showing all. Finally, the original panel visibility is restored. + + ADDITIONAL SOFTWARE NEEDED FOR THIS SCRIPT + * none + + USAGE + * require this script from your main lua file + + BUGS, COMMENTS, SUGGESTIONS + * Send to Bill Ferguson, wpferguson@gmail.com + + CHANGES +]] + +local dt = require "darktable" +local du = require "lib/dtutils" + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- V E R S I O N C H E C K +-- - - - - - - - - - - - - - - - - - - - - - - - + +du.check_min_api_version("5.0.2", "panels_demo") -- darktable 3.0 + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- C O N S T A N T S +-- - - - - - - - - - - - - - - - - - - - - - - - + +local MODULE_NAME = "panels" +local PS = dt.configuration.running_os == "windows" and "\\" or "/" + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- T R A N S L A T I O N S +-- - - - - - - - - - - - - - - - - - - - - - - - +local gettext = dt.gettext +gettext.bindtextdomain(MODULE_NAME, dt.configuration.config_dir..PS.."lua"..PS.."locale"..PS) + +local function _(msgid) + return gettext.dgettext(MODULE_NAME, msgid) +end + +-- - - - - - - - - - - - - - - - - - - - - - - - +-- M A I N +-- - - - - - - - - - - - - - - - - - - - - - - - + +-- alias dt.control.sleep to sleep +local sleep = dt.control.sleep + +local panels = {"DT_UI_PANEL_CENTER_TOP", -- center top panel + "DT_UI_PANEL_CENTER_BOTTOM", -- center bottom panel + "DT_UI_PANEL_TOP", -- complete top panel + "DT_UI_PANEL_LEFT", -- left panel + "DT_UI_PANEL_RIGHT", -- right panel + "DT_UI_PANEL_BOTTOM"} -- complete bottom panel + +local panel_status = {} + +-- save panel visibility + +for i = 1,#panels do + panel_status[i] = dt.gui.panel_visible(panels[i]) +end + +-- show all just in case + +dt.gui.panel_show_all() + +-- hide center_top, center_bottom, left, top, right, bottom in order + +dt.print(_("Hiding all panels, one at a tme")) +sleep(1500) + +for i = 1, #panels do + dt.print(_("Hiding " .. panels[i])) + dt.gui.panel_hide(panels[i]) + sleep(1500) +end + +-- display left, then top, then right, then bottom + + dt.print(_("Make panels visible, one at a time")) + sleep(1500) + + for i = #panels, 1, -1 do + dt.print(_("Showing " .. panels[i])) + dt.gui.panel_show(panels[i]) + sleep(1500) + end + +-- hide all + +dt.print(_("Hiding all panels")) +sleep(1500) + +dt.gui.panel_hide_all() +sleep(1500) + +-- show all + +dt.print(_("Showing all panels")) +sleep(1500) + +dt.gui.panel_show_all() +sleep(1500) + +-- restore + +dt.print(_("Restoring panels to starting configuration")) +for i = 1, #panels do + if panel_status[i] then + dt.gui.panel_show(panels[i]) + else + dt.gui.panel_hide(panels[i]) + end +end From 3d3ad89fba13c0fa10e83e288375dd88cddc6a83 Mon Sep 17 00:00:00 2001 From: "U-DESKTOP-HQME86J\\marco" Date: Fri, 20 Dec 2019 23:00:57 +0100 Subject: [PATCH 03/10] Add ext_editor.lua to contrib --- contrib/ext_editor.lua | 255 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 255 insertions(+) create mode 100644 contrib/ext_editor.lua diff --git a/contrib/ext_editor.lua b/contrib/ext_editor.lua new file mode 100644 index 0000000..c7b464b --- /dev/null +++ b/contrib/ext_editor.lua @@ -0,0 +1,255 @@ +--[[ + + DESCRIPTION + ext_editor.lua - edit images with external editors - for Windows only at the moment + + This script provides helpers to edit image files with programs extenal to darktable. + It adds: + - a new target storage "collection". Image exported will be reimported to collection for + further edit with external programs + - a new lighttable module "external editors", to select a program from a list of up to + - 9 external editors and run it on a selected image + - a set of lua preferences in order to configure name and path of up to 9 external editors + - a set of lua shortcuts in order to quick launch the external editors + + USAGE + * require this script from main lua file + + * in "preferences / lua options" configure name and path of external programs + * in "preferences / shortcuts / lua" configure shortcuts for external programs (optional) + + * in the export dialog choose "collection" and select the format and bit depth for the + exported image + * press "export" + * the exported image will be imported into collection and grouped with the original image + + * select an image for editing with en external program + * in lighttable / external editors, select program and press "edit with external program" + * edit the image with the external editor, overwite the file, quit the external program + * lighttable will be updated + + CAVEATS + * currently developed and tested only for Windows + + BUGS, COMMENTS, SUGGESTIONS + * send to Marco Carrarini, marco.carrarini@gmail.com + + CHANGES + * 20191220 - initial version + +]] + +local dt = require "darktable" +local df = require "lib/dtutils.file" +local dtsys = require "lib/dtutils.system" + +dt.preferences.register("ext_editor","program_path_9", "string","path to external editor 9", "path to external editor","") +dt.preferences.register("ext_editor","program_name_9", "string","name of external editor 9", "name of external editor","") + +dt.preferences.register("ext_editor","program_path_8", "string","path to external editor 8", "path to external editor","") +dt.preferences.register("ext_editor","program_name_8", "string","name of external editor 8", "name of external editor","") + +dt.preferences.register("ext_editor","program_path_7", "string","path to external editor 7", "path to external editor","") +dt.preferences.register("ext_editor","program_name_7", "string","name of external editor 7", "name of external editor","") + +dt.preferences.register("ext_editor","program_path_6", "string","path to external editor 6", "path to external editor","") +dt.preferences.register("ext_editor","program_name_6", "string","name of external editor 6", "name of external editor","") + +dt.preferences.register("ext_editor","program_path_5", "string","path to external editor 5", "path to external editor","") +dt.preferences.register("ext_editor","program_name_5", "string","name of external editor 5", "name of external editor","") + +dt.preferences.register("ext_editor","program_path_4", "string","path to external editor 4", "path to external editor","") +dt.preferences.register("ext_editor","program_name_4", "string","name of external editor 4", "name of external editor","") + +dt.preferences.register("ext_editor","program_path_3", "string","path to external editor 3", "path to external editor","") +dt.preferences.register("ext_editor","program_name_3", "string","name of external editor 3", "name of external editor","") + +dt.preferences.register("ext_editor","program_path_2", "string","path to external editor 2", "path to external editor","") +dt.preferences.register("ext_editor","program_name_2", "string","name of external editor 2", "name of external editor","") + +dt.preferences.register("ext_editor","program_path_1", "string","path to external editor 1", "path to external editor","") +dt.preferences.register("ext_editor","program_name_1", "string","name of external editor 1", "name of external editor","") + +local programs = { + [1] = dt.preferences.read("ext_editor","program_path_1", "string"), + [2] = dt.preferences.read("ext_editor","program_path_2", "string"), + [3] = dt.preferences.read("ext_editor","program_path_3", "string"), + [4] = dt.preferences.read("ext_editor","program_path_4", "string"), + [5] = dt.preferences.read("ext_editor","program_path_5", "string"), + [6] = dt.preferences.read("ext_editor","program_path_6", "string"), + [7] = dt.preferences.read("ext_editor","program_path_7", "string"), + [8] = dt.preferences.read("ext_editor","program_path_8", "string"), + [9] = dt.preferences.read("ext_editor","program_path_9", "string") + } + +local names = { + [1] = dt.preferences.read("ext_editor","program_name_1", "string"), + [2] = dt.preferences.read("ext_editor","program_name_2", "string"), + [3] = dt.preferences.read("ext_editor","program_name_3", "string"), + [4] = dt.preferences.read("ext_editor","program_name_4", "string"), + [5] = dt.preferences.read("ext_editor","program_name_5", "string"), + [6] = dt.preferences.read("ext_editor","program_name_6", "string"), + [7] = dt.preferences.read("ext_editor","program_name_7", "string"), + [8] = dt.preferences.read("ext_editor","program_name_8", "string"), + [9] = dt.preferences.read("ext_editor","program_name_9", "string") + } + +if not (dt.preferences.read("ext_editor","initialized", "bool")) then + dt.preferences.write("ext_editor","lastchoice", "integer", 1) + dt.preferences.write("ext_editor","initialized", "bool", true) + end + +local lastchoice = dt.preferences.read("ext_editor","lastchoice", "integer") + +local combobox = dt.new_widget("combobox") + { + label = "choose program", + value = lastchoice, -- remember status, + names[1], + names[2], + names[3], + names[4], + names[5], + names[6], + names[7], + names[8], + names[9] + } + + +local function OpenWith(choice) + + local images = dt.gui.selection() + local curr_image = "" + + if #images == 1 then + for _,image in pairs(images) do + curr_image = image.path.."\\"..image.filename + local run_cmd = '"'..programs[choice]..'" "'..curr_image..'"' --additional quotes for spaces in filename + dt.print("Launching "..names[choice].."...") + dtsys.external_command(run_cmd) + --image:drop_cache() *** it doesn't work! why ? Delete and Import instead *** + image:delete() + local myimage = dt.database.import(curr_image) + dt.preferences.write("ext_editor","lastchoice", "integer", choice) + end + else + dt.print('please select one image') + end + + end + +local button1 = dt.new_widget("button") + { + label = "edit with external program", + clicked_callback = function (_) + local choice = combobox.selected + OpenWith(choice) + end + } + + +local function group_if_not_member(img, new_img) + local image_table = img:get_group_members() + local is_member = false + for _,image in ipairs(image_table) do + if image.filename == new_img.filename then + is_member = true + end + end + if not is_member then + new_img:group_with(img.group_leader) + end + end + + +local function show_status(storage, image, format, filename, + number, total, high_quality, extra_data) + dt.print(string.format(_("Export Image %i/%i"), number, total)) + end + + +local function export2collection(storage, image_table, extra_data) + + -- list of exported images + local img_list + + -- reset and create image list + img_list = "" + + for _,exp_img in pairs(image_table) do + exp_img = df.sanitize_filename(exp_img) + img_list = img_list ..exp_img.. " " + end + +--[[ + for each of the image, exported image pairs + move the exported image into the directory with the original + then import the image into the database which will group it with the original + and then copy over any tags other than darktable tags +]] + for image,exported_image in pairs(image_table) do + + local myimage_name = image.path .. "/" .. df.get_filename(exported_image) + + while df.check_if_file_exists(myimage_name) do + myimage_name = df.filename_increment(myimage_name) + -- limit to 99 more exports of the original export + if string.match(df.get_basename(myimage_name), "_(d-)$") == "99" then + break + end + end + + local result = df.file_move(exported_image, myimage_name) + + if result then + local myimage = dt.database.import(myimage_name) + + group_if_not_member(image, myimage) + + for _,tag in pairs(dt.tags.get_tags(image)) do + if not (string.sub(tag.name,1,9) == "darktable") then + dt.tags.attach(tag,myimage) + end + end + end + end + end + + +local function program_shortcut(event, shortcut) + local choice = tonumber(string.sub(shortcut, -1)) + OpenWith(choice) +end + + +dt.register_storage("exp2coll", "collection", show_status, export2collection) + +dt.register_lib( + "ext_editor", -- module name + "external editors", -- name + true, -- expandable + false, -- resetable + {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, -- containers + dt.new_widget("box") -- widget + { + orientation = "vertical", + combobox, + button1 + }, + nil,-- view_enter + nil -- view_leave + ) + +dt.register_event("shortcut", program_shortcut, "edit with program 1") +dt.register_event("shortcut", program_shortcut, "edit with program 2") +dt.register_event("shortcut", program_shortcut, "edit with program 3") +dt.register_event("shortcut", program_shortcut, "edit with program 4") +dt.register_event("shortcut", program_shortcut, "edit with program 5") +dt.register_event("shortcut", program_shortcut, "edit with program 6") +dt.register_event("shortcut", program_shortcut, "edit with program 7") +dt.register_event("shortcut", program_shortcut, "edit with program 8") +dt.register_event("shortcut", program_shortcut, "edit with program 9") + +-- vim: shiftwidth=2 expandtab tabstop=2 cindent syntax=lua +-- kate: hl Lua; From 54ff56b02136f52e8e642cf215dac58d050f652b Mon Sep 17 00:00:00 2001 From: "U-DESKTOP-HQME86J\\marco" Date: Sat, 21 Dec 2019 21:12:46 +0100 Subject: [PATCH 04/10] added copy and edit button + code cleaning --- contrib/ext_editor.lua | 436 +++++++++++++++++++++++++---------------- 1 file changed, 265 insertions(+), 171 deletions(-) diff --git a/contrib/ext_editor.lua b/contrib/ext_editor.lua index c7b464b..5d934a3 100644 --- a/contrib/ext_editor.lua +++ b/contrib/ext_editor.lua @@ -30,19 +30,282 @@ CAVEATS * currently developed and tested only for Windows + * button are not equal in size and centered BUGS, COMMENTS, SUGGESTIONS * send to Marco Carrarini, marco.carrarini@gmail.com CHANGES - * 20191220 - initial version + * 20191220 - initial version, PR done + * 20191221 - reworked, cleaned, added "copy and edit" ]] + local dt = require "darktable" local df = require "lib/dtutils.file" local dtsys = require "lib/dtutils.system" + +-- executables of the external editors +local program_paths = { + [1] = dt.preferences.read("ext_editor","program_path_1", "string"), + [2] = dt.preferences.read("ext_editor","program_path_2", "string"), + [3] = dt.preferences.read("ext_editor","program_path_3", "string"), + [4] = dt.preferences.read("ext_editor","program_path_4", "string"), + [5] = dt.preferences.read("ext_editor","program_path_5", "string"), + [6] = dt.preferences.read("ext_editor","program_path_6", "string"), + [7] = dt.preferences.read("ext_editor","program_path_7", "string"), + [8] = dt.preferences.read("ext_editor","program_path_8", "string"), + [9] = dt.preferences.read("ext_editor","program_path_9", "string") + } + + +-- friendly name of the external editors +local program_names = { + [1] = dt.preferences.read("ext_editor","program_name_1", "string"), + [2] = dt.preferences.read("ext_editor","program_name_2", "string"), + [3] = dt.preferences.read("ext_editor","program_name_3", "string"), + [4] = dt.preferences.read("ext_editor","program_name_4", "string"), + [5] = dt.preferences.read("ext_editor","program_name_5", "string"), + [6] = dt.preferences.read("ext_editor","program_name_6", "string"), + [7] = dt.preferences.read("ext_editor","program_name_7", "string"), + [8] = dt.preferences.read("ext_editor","program_name_8", "string"), + [9] = dt.preferences.read("ext_editor","program_name_9", "string") + } + + +-- last used editor +if not (dt.preferences.read("ext_editor","initialized", "bool")) then + dt.preferences.write("ext_editor","lastchoice", "integer", 1) + dt.preferences.write("ext_editor","initialized", "bool", true) + end +local lastchoice = dt.preferences.read("ext_editor","lastchoice", "integer") + + +-- combobox +local combobox = dt.new_widget("combobox") + { + label = "choose program", + tooltip = "select the external editor from the list", + value = lastchoice, -- remember status, + program_names[1], + program_names[2], + program_names[3], + program_names[4], + program_names[5], + program_names[6], + program_names[7], + program_names[8], + program_names[9] + } + + +-- group image with leader image +local function group_if_not_member(img, new_img) + local image_table = img:get_group_members() + local is_member = false + for _,image in ipairs(image_table) do + if image.filename == new_img.filename then + is_member = true + end + end + if not is_member then + new_img:group_with(img.group_leader) + end + end + + +-- shows export progress +local function show_status(storage, image, format, filename, + number, total, high_quality, extra_data) + dt.print(string.format(_("Export Image %i/%i"), number, total)) + end + + +-- callback for button "edit" +local function OpenWith(choice) + + local images = dt.gui.selection() + + if #images == 1 then + for _, image in pairs(images) do + + -- image to be edited + name = image.path.."\\"..image.filename + + -- launch the external editor + local run_cmd = '"'..program_paths[choice]..'" "'..name..'"' + dt.print("Launching "..program_names[choice].."...") + dtsys.external_command(run_cmd) + + -- refresh image cache + image:drop_cache() + + -- remember the last editor used + dt.preferences.write("ext_editor","lastchoice", "integer", choice) + end + else + dt.print('please select one image') + end + + end + + +-- callback for button "copy and edit" +local function CopyAndOpenWith(choice) + + local images = dt.gui.selection() + + if #images == 1 then + for _,image in pairs(images) do + + -- image to be copied and edited + local name = image.path.."\\"..image.filename + local new_name = name + + -- create unique filename + while df.check_if_file_exists(new_name) do + new_name = df.filename_increment(new_name) + end + + -- limit to 99 more exports of the original export + if string.match(df.get_basename(new_name), "_(d-)$") == "99" then + break + end + + -- physical copy + local result = df.file_copy(name, new_name) + + if result then + -- launch the external editor + local run_cmd = '"'..program_paths[choice]..'" "'..new_name..'"' + dt.print("Launching "..program_names[choice].."...") + dtsys.external_command(run_cmd) + + -- import in database and group + local new_image = dt.database.import(new_name) + group_if_not_member(image, new_image) + + -- copy image tags + for _,tag in pairs(dt.tags.get_tags(image)) do + if not (string.sub(tag.name,1,9) == "darktable") then + dt.tags.attach(tag, new_image) + end + end + + -- remember the last editor used + dt.preferences.write("ext_editor","lastchoice", "integer", choice) + end + end + else + dt.print('please select one image') + end + + + end + + +-- button edit +local button1 = dt.new_widget("button") + { + label = "edit", + tooltip = "open the selected image in external editor", + dt_lua_align_t = center, + clicked_callback = function (_) + local choice = combobox.selected + OpenWith(choice) + end + } + + +-- button copy and edit +local button2 = dt.new_widget("button") + { + label = "edit a copy", + tooltip = "create a copy of the selected image and open it in external editor", + clicked_callback = function (_) + local choice = combobox.selected + CopyAndOpenWith(choice) + end + } + + +-- box for the two buttons +local box1 = dt.new_widget ("box") { + orientation = "horizontal", + button1, + button2 +} + + +-- export images and reimport in collection +local function export2collection(storage, image_table, extra_data) + + for image, temp_name in pairs(image_table) do + + -- images are first exported in temp folder + -- create unique filename + local new_name = image.path .."\\"..df.get_filename(temp_name) + while df.check_if_file_exists(new_name) do + new_name = df.filename_increment(new_name) + + -- limit to 99 more exports of the original export + if string.match(df.get_basename(new_name), "_(d-)$") == "99" then + break + end + end + + -- image moved to collection folder + local result = df.file_move(temp_name, new_name) + + if result then + + -- import in database and group + local new_image = dt.database.import(new_name) + group_if_not_member(image, new_image) + + -- copy image tags + for _,tag in pairs(dt.tags.get_tags(image)) do + if not (string.sub(tag.name,1,9) == "darktable") then + dt.tags.attach(tag, new_image) + end + end + end + end + end + + +-- callback function for shortcuts +local function program_shortcut(event, shortcut) + local choice = tonumber(string.sub(shortcut, -1)) + OpenWith(choice) +end + + +-- register new storage +dt.register_storage("exp2coll", "collection", show_status, export2collection) + + +-- register new lighttable module +dt.register_lib( + "ext_editor", -- module name + "external editors", -- name + true, -- expandable + false, -- resetable + {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, + dt.new_widget("box") -- widget + { + orientation = "vertical", + combobox, + box1 + }, + nil,-- view_enter + nil -- view_leave + ) + + +-- register new preferences dt.preferences.register("ext_editor","program_path_9", "string","path to external editor 9", "path to external editor","") dt.preferences.register("ext_editor","program_name_9", "string","name of external editor 9", "name of external editor","") @@ -70,177 +333,8 @@ dt.preferences.register("ext_editor","program_name_2", "string","name of externa dt.preferences.register("ext_editor","program_path_1", "string","path to external editor 1", "path to external editor","") dt.preferences.register("ext_editor","program_name_1", "string","name of external editor 1", "name of external editor","") -local programs = { - [1] = dt.preferences.read("ext_editor","program_path_1", "string"), - [2] = dt.preferences.read("ext_editor","program_path_2", "string"), - [3] = dt.preferences.read("ext_editor","program_path_3", "string"), - [4] = dt.preferences.read("ext_editor","program_path_4", "string"), - [5] = dt.preferences.read("ext_editor","program_path_5", "string"), - [6] = dt.preferences.read("ext_editor","program_path_6", "string"), - [7] = dt.preferences.read("ext_editor","program_path_7", "string"), - [8] = dt.preferences.read("ext_editor","program_path_8", "string"), - [9] = dt.preferences.read("ext_editor","program_path_9", "string") - } -local names = { - [1] = dt.preferences.read("ext_editor","program_name_1", "string"), - [2] = dt.preferences.read("ext_editor","program_name_2", "string"), - [3] = dt.preferences.read("ext_editor","program_name_3", "string"), - [4] = dt.preferences.read("ext_editor","program_name_4", "string"), - [5] = dt.preferences.read("ext_editor","program_name_5", "string"), - [6] = dt.preferences.read("ext_editor","program_name_6", "string"), - [7] = dt.preferences.read("ext_editor","program_name_7", "string"), - [8] = dt.preferences.read("ext_editor","program_name_8", "string"), - [9] = dt.preferences.read("ext_editor","program_name_9", "string") - } - -if not (dt.preferences.read("ext_editor","initialized", "bool")) then - dt.preferences.write("ext_editor","lastchoice", "integer", 1) - dt.preferences.write("ext_editor","initialized", "bool", true) - end - -local lastchoice = dt.preferences.read("ext_editor","lastchoice", "integer") - -local combobox = dt.new_widget("combobox") - { - label = "choose program", - value = lastchoice, -- remember status, - names[1], - names[2], - names[3], - names[4], - names[5], - names[6], - names[7], - names[8], - names[9] - } - - -local function OpenWith(choice) - - local images = dt.gui.selection() - local curr_image = "" - - if #images == 1 then - for _,image in pairs(images) do - curr_image = image.path.."\\"..image.filename - local run_cmd = '"'..programs[choice]..'" "'..curr_image..'"' --additional quotes for spaces in filename - dt.print("Launching "..names[choice].."...") - dtsys.external_command(run_cmd) - --image:drop_cache() *** it doesn't work! why ? Delete and Import instead *** - image:delete() - local myimage = dt.database.import(curr_image) - dt.preferences.write("ext_editor","lastchoice", "integer", choice) - end - else - dt.print('please select one image') - end - - end - -local button1 = dt.new_widget("button") - { - label = "edit with external program", - clicked_callback = function (_) - local choice = combobox.selected - OpenWith(choice) - end - } - - -local function group_if_not_member(img, new_img) - local image_table = img:get_group_members() - local is_member = false - for _,image in ipairs(image_table) do - if image.filename == new_img.filename then - is_member = true - end - end - if not is_member then - new_img:group_with(img.group_leader) - end - end - - -local function show_status(storage, image, format, filename, - number, total, high_quality, extra_data) - dt.print(string.format(_("Export Image %i/%i"), number, total)) - end - - -local function export2collection(storage, image_table, extra_data) - - -- list of exported images - local img_list - - -- reset and create image list - img_list = "" - - for _,exp_img in pairs(image_table) do - exp_img = df.sanitize_filename(exp_img) - img_list = img_list ..exp_img.. " " - end - ---[[ - for each of the image, exported image pairs - move the exported image into the directory with the original - then import the image into the database which will group it with the original - and then copy over any tags other than darktable tags -]] - for image,exported_image in pairs(image_table) do - - local myimage_name = image.path .. "/" .. df.get_filename(exported_image) - - while df.check_if_file_exists(myimage_name) do - myimage_name = df.filename_increment(myimage_name) - -- limit to 99 more exports of the original export - if string.match(df.get_basename(myimage_name), "_(d-)$") == "99" then - break - end - end - - local result = df.file_move(exported_image, myimage_name) - - if result then - local myimage = dt.database.import(myimage_name) - - group_if_not_member(image, myimage) - - for _,tag in pairs(dt.tags.get_tags(image)) do - if not (string.sub(tag.name,1,9) == "darktable") then - dt.tags.attach(tag,myimage) - end - end - end - end - end - - -local function program_shortcut(event, shortcut) - local choice = tonumber(string.sub(shortcut, -1)) - OpenWith(choice) -end - - -dt.register_storage("exp2coll", "collection", show_status, export2collection) - -dt.register_lib( - "ext_editor", -- module name - "external editors", -- name - true, -- expandable - false, -- resetable - {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, -- containers - dt.new_widget("box") -- widget - { - orientation = "vertical", - combobox, - button1 - }, - nil,-- view_enter - nil -- view_leave - ) - +-- register new shortcuts dt.register_event("shortcut", program_shortcut, "edit with program 1") dt.register_event("shortcut", program_shortcut, "edit with program 2") dt.register_event("shortcut", program_shortcut, "edit with program 3") From 64c8f8fc3e78b03dd1d764d1eb16ea7a551e99ac Mon Sep 17 00:00:00 2001 From: "U-DESKTOP-HQME86J\\marco" Date: Sun, 22 Dec 2019 21:08:32 +0100 Subject: [PATCH 05/10] added darkroom mode --- contrib/ext_editor.lua | 192 +++++++++++++++++++++++------------------ 1 file changed, 110 insertions(+), 82 deletions(-) diff --git a/contrib/ext_editor.lua b/contrib/ext_editor.lua index 5d934a3..9ca7d4c 100644 --- a/contrib/ext_editor.lua +++ b/contrib/ext_editor.lua @@ -3,7 +3,7 @@ DESCRIPTION ext_editor.lua - edit images with external editors - for Windows only at the moment - This script provides helpers to edit image files with programs extenal to darktable. + This script provides helpers to edit image files with programs external to darktable. It adds: - a new target storage "collection". Image exported will be reimported to collection for further edit with external programs @@ -24,20 +24,40 @@ * the exported image will be imported into collection and grouped with the original image * select an image for editing with en external program - * in lighttable / external editors, select program and press "edit with external program" - * edit the image with the external editor, overwite the file, quit the external program - * lighttable will be updated + * in lighttable / external editors, select program and press "edit" + * edit the image with the external editor, overwite the file, quit the external program + * the selected image will be updated + or + * in lighttable / external editors, select program and press "edit a copy" + * edit the image with the external editor, overwite the file, quit the external program + * a copy of the selected image will be created and updated + or + * in lighttable select target storage "collection" + * enter in darkroom + * to create an export or a copy press CRTL+E + * use the shortcut to edit the current image with the corresponding external editor + * overwite the file, quit the external program + * the darkroom view will be updated + + * warning: mouseover on lighttable / filmstrip will prevail on current image + * this is the default DT behavior, not a bug of this script CAVEATS * currently developed and tested only for Windows - * button are not equal in size and centered - + + TODO + * localization + * check min API version + * support other OS + * buttons are not equal in size and centered + BUGS, COMMENTS, SUGGESTIONS * send to Marco Carrarini, marco.carrarini@gmail.com CHANGES * 20191220 - initial version, PR done * 20191221 - reworked, cleaned, added "copy and edit" + * 20191222 - added darkroom mode ]] @@ -83,24 +103,6 @@ if not (dt.preferences.read("ext_editor","initialized", "bool")) then local lastchoice = dt.preferences.read("ext_editor","lastchoice", "integer") --- combobox -local combobox = dt.new_widget("combobox") - { - label = "choose program", - tooltip = "select the external editor from the list", - value = lastchoice, -- remember status, - program_names[1], - program_names[2], - program_names[3], - program_names[4], - program_names[5], - program_names[6], - program_names[7], - program_names[8], - program_names[9] - } - - -- group image with leader image local function group_if_not_member(img, new_img) local image_table = img:get_group_members() @@ -119,15 +121,13 @@ local function group_if_not_member(img, new_img) -- shows export progress 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("Exporting Image %i/%i ...", number, total)) end -- callback for button "edit" -local function OpenWith(choice) - - local images = dt.gui.selection() - +local function OpenWith(images, choice) + if #images == 1 then for _, image in pairs(images) do @@ -139,11 +139,29 @@ local function OpenWith(choice) dt.print("Launching "..program_names[choice].."...") dtsys.external_command(run_cmd) - -- refresh image cache - image:drop_cache() + -- refresh the image view + -- note that only image:drop_cache() is not enough to refresh view in darkroom mode + -- therefore image must be deleted and reimported to force refresh + + local image_leader = image.group_leader + image:delete () + local new_image = dt.database.import(name) + new_image:group_with(image_leader) + + -- copy tags from image leader + for _,tag in pairs(dt.tags.get_tags(image_leader)) do + if not (string.sub(tag.name,1,9) == "darktable") then + dt.tags.attach(tag, new_image) + end + end -- remember the last editor used dt.preferences.write("ext_editor","lastchoice", "integer", choice) + + -- refresh darkroom view + if dt.gui.current_view () == dt.gui.views.darkroom then + dt.gui.views.darkroom.display_image(new_image) + end end else dt.print('please select one image') @@ -153,9 +171,7 @@ local function OpenWith(choice) -- callback for button "copy and edit" -local function CopyAndOpenWith(choice) - - local images = dt.gui.selection() +local function CopyAndOpenWith(images, choice) if #images == 1 then for _,image in pairs(images) do @@ -206,37 +222,11 @@ local function CopyAndOpenWith(choice) end --- button edit -local button1 = dt.new_widget("button") - { - label = "edit", - tooltip = "open the selected image in external editor", - dt_lua_align_t = center, - clicked_callback = function (_) - local choice = combobox.selected - OpenWith(choice) - end - } - - --- button copy and edit -local button2 = dt.new_widget("button") - { - label = "edit a copy", - tooltip = "create a copy of the selected image and open it in external editor", - clicked_callback = function (_) - local choice = combobox.selected - CopyAndOpenWith(choice) - end - } - - --- box for the two buttons -local box1 = dt.new_widget ("box") { - orientation = "horizontal", - button1, - button2 -} +-- callback function for shortcuts +local function program_shortcut(event, shortcut) + local choice = tonumber(string.sub(shortcut, -1)) + OpenWith(dt.gui.action_images, choice) + end -- export images and reimport in collection @@ -260,31 +250,63 @@ local function export2collection(storage, image_table, extra_data) local result = df.file_move(temp_name, new_name) if result then - -- import in database and group local new_image = dt.database.import(new_name) group_if_not_member(image, new_image) - - -- copy image tags - for _,tag in pairs(dt.tags.get_tags(image)) do - if not (string.sub(tag.name,1,9) == "darktable") then - dt.tags.attach(tag, new_image) - end - end end end end --- callback function for shortcuts -local function program_shortcut(event, shortcut) - local choice = tonumber(string.sub(shortcut, -1)) - OpenWith(choice) -end +-- combobox +local combobox = dt.new_widget("combobox") + { + label = "choose program", + tooltip = "select the external editor from the list", + value = lastchoice, -- remember status, + program_names[1], + program_names[2], + program_names[3], + program_names[4], + program_names[5], + program_names[6], + program_names[7], + program_names[8], + program_names[9] + } --- register new storage -dt.register_storage("exp2coll", "collection", show_status, export2collection) +-- button edit +local button1 = dt.new_widget("button") + { + label = " edit ", + tooltip = "open the selected image in external editor", + dt_lua_align_t = center, + clicked_callback = function (_) + local choice = combobox.selected + OpenWith(dt.gui.action_images, choice) + end + } + + +-- button edit a copy +local button2 = dt.new_widget("button") + { + label = " edit a copy ", + tooltip = "create a copy of the selected image and open it in external editor", + clicked_callback = function (_) + local choice = combobox.selected + CopyAndOpenWith(dt.gui.action_images, choice) + end + } + + +-- box for the two buttons +local box1 = dt.new_widget ("box") { + orientation = "horizontal", + button1, + button2 +} -- register new lighttable module @@ -305,7 +327,11 @@ dt.register_lib( ) --- register new preferences +-- register new storage +dt.register_storage("exp2coll", "collection", show_status, export2collection) + + +-- register the new preferences dt.preferences.register("ext_editor","program_path_9", "string","path to external editor 9", "path to external editor","") dt.preferences.register("ext_editor","program_name_9", "string","name of external editor 9", "name of external editor","") @@ -334,7 +360,7 @@ dt.preferences.register("ext_editor","program_path_1", "string","path to externa dt.preferences.register("ext_editor","program_name_1", "string","name of external editor 1", "name of external editor","") --- register new shortcuts +-- register the new shortcuts dt.register_event("shortcut", program_shortcut, "edit with program 1") dt.register_event("shortcut", program_shortcut, "edit with program 2") dt.register_event("shortcut", program_shortcut, "edit with program 3") @@ -345,5 +371,7 @@ dt.register_event("shortcut", program_shortcut, "edit with program 7") dt.register_event("shortcut", program_shortcut, "edit with program 8") dt.register_event("shortcut", program_shortcut, "edit with program 9") +-- end of script + -- vim: shiftwidth=2 expandtab tabstop=2 cindent syntax=lua -- kate: hl Lua; From 6a89357b547aea10c8d595762c79d889dac091dd Mon Sep 17 00:00:00 2001 From: "U-DESKTOP-HQME86J\\marco" Date: Mon, 23 Dec 2019 11:34:01 +0100 Subject: [PATCH 06/10] compatibility with Linux --- contrib/ext_editor.lua | 44 ++++++++++++++++++------------------------ 1 file changed, 19 insertions(+), 25 deletions(-) diff --git a/contrib/ext_editor.lua b/contrib/ext_editor.lua index 9ca7d4c..63f7b93 100644 --- a/contrib/ext_editor.lua +++ b/contrib/ext_editor.lua @@ -1,7 +1,7 @@ --[[ DESCRIPTION - ext_editor.lua - edit images with external editors - for Windows only at the moment + ext_editor.lua - edit images with external editors This script provides helpers to edit image files with programs external to darktable. It adds: @@ -15,7 +15,7 @@ USAGE * require this script from main lua file - * in "preferences / lua options" configure name and path of external programs + * in "preferences / lua options" configure name and command/path of external programs * in "preferences / shortcuts / lua" configure shortcuts for external programs (optional) * in the export dialog choose "collection" and select the format and bit depth for the @@ -43,12 +43,11 @@ * this is the default DT behavior, not a bug of this script CAVEATS - * currently developed and tested only for Windows + * tested with DT 3.0 in Windows and Ubuntu + * MAC compatibility not tested TODO * localization - * check min API version - * support other OS * buttons are not equal in size and centered BUGS, COMMENTS, SUGGESTIONS @@ -58,15 +57,25 @@ * 20191220 - initial version, PR done * 20191221 - reworked, cleaned, added "copy and edit" * 20191222 - added darkroom mode + * 20191223 - check API version, OS compatibility ]] local dt = require "darktable" +local du = require "lib/dtutils" local df = require "lib/dtutils.file" local dtsys = require "lib/dtutils.system" +-- check API version +du.check_min_api_version("5.0.2", "ext_editor") -- darktable 3.0 + + +-- OS compatibility +local PS = dt.configuration.running_os == "windows" and "\\" or "/" + + -- executables of the external editors local program_paths = { [1] = dt.preferences.read("ext_editor","program_path_1", "string"), @@ -103,21 +112,6 @@ if not (dt.preferences.read("ext_editor","initialized", "bool")) then local lastchoice = dt.preferences.read("ext_editor","lastchoice", "integer") --- group image with leader image -local function group_if_not_member(img, new_img) - local image_table = img:get_group_members() - local is_member = false - for _,image in ipairs(image_table) do - if image.filename == new_img.filename then - is_member = true - end - end - if not is_member then - new_img:group_with(img.group_leader) - end - end - - -- shows export progress local function show_status(storage, image, format, filename, number, total, high_quality, extra_data) @@ -132,7 +126,7 @@ local function OpenWith(images, choice) for _, image in pairs(images) do -- image to be edited - name = image.path.."\\"..image.filename + name = image.path..PS..image.filename -- launch the external editor local run_cmd = '"'..program_paths[choice]..'" "'..name..'"' @@ -177,7 +171,7 @@ local function CopyAndOpenWith(images, choice) for _,image in pairs(images) do -- image to be copied and edited - local name = image.path.."\\"..image.filename + local name = image.path..PS..image.filename local new_name = name -- create unique filename @@ -201,7 +195,7 @@ local function CopyAndOpenWith(images, choice) -- import in database and group local new_image = dt.database.import(new_name) - group_if_not_member(image, new_image) + new_image:group_with(image.group_leader) -- copy image tags for _,tag in pairs(dt.tags.get_tags(image)) do @@ -236,7 +230,7 @@ local function export2collection(storage, image_table, extra_data) -- images are first exported in temp folder -- create unique filename - local new_name = image.path .."\\"..df.get_filename(temp_name) + local new_name = image.path ..PS..df.get_filename(temp_name) while df.check_if_file_exists(new_name) do new_name = df.filename_increment(new_name) @@ -252,7 +246,7 @@ local function export2collection(storage, image_table, extra_data) if result then -- import in database and group local new_image = dt.database.import(new_name) - group_if_not_member(image, new_image) + new_image:group_with(image.group_leader) end end end From 944087649fafe775831b3288c3d8b051b6f51792 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Tue, 24 Dec 2019 11:43:01 -0500 Subject: [PATCH 07/10] removed deprecated contrib/video_mencoder.lua --- contrib/video_mencoder.lua | 124 ------------------------------------- 1 file changed, 124 deletions(-) delete mode 100644 contrib/video_mencoder.lua diff --git a/contrib/video_mencoder.lua b/contrib/video_mencoder.lua deleted file mode 100644 index 71c8a4d..0000000 --- a/contrib/video_mencoder.lua +++ /dev/null @@ -1,124 +0,0 @@ ---[[ - This file is part of darktable, - Copyright 2014 by Tobias Jakobs. - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -]] ---[[ -darktable video export script - -ADDITIONAL SOFTWARE NEEDED FOR THIS SCRIPT -* mencoder (MEncoder is from the MPlayer Team) -* xdg-open -* xdg-user-dir - -WARNING -This script is only tested with Linux - -USAGE -* require this script from your main lua file -]] - -local dt = require "darktable" -local du = require "lib/dtutils" -local df = require "lib/dtutils.file" -require "official/yield" -local gettext = dt.gettext - -du.check_min_api_version("2.0.1", "video_mencoder") - --- Tell gettext where to find the .mo file translating messages for a particular domain -gettext.bindtextdomain("video_mencoder",dt.configuration.config_dir.."/lua/locale/") - -local function _(msgid) - return gettext.dgettext("video_mencoder", msgid) -end - -local function show_status(storage, image, format, filename, number, total, high_quality, extra_data) - dt.print("Export Image "..tostring(number).."/"..tostring(total)) -end - -local function create_video_mencoder(storage, image_table, extra_data) - dt.print("video_mencoder is deprecated. Please use video_ffmpeg instead. Please see the log for more details.") - dt.print_log("The mencoder executable is no longer distributed as part of most distributions,") - dt.print_log("therefore video_mencoder is deprecated. video_ffmpeg should be used in it's place. video_mencoder") - dt.print_log("will be removed when darktable 2.8 is released.") - if not df.check_if_bin_exists("mencoder") then - dt.print_error(_("mencoder not found")) - return - end - if not df.check_if_bin_exists("xdg-open") then - dt.print_error(_("xdg-open not found")) - return - end - if not df.check_if_bin_exists("xdg-user-dir") then - dt.print_error(_("xdg-user-dir not found")) - return - end - - exportDirectory = dt.preferences.read("video_mencoder","ExportDirectory","string") - exportFilename = "output.avi" - framsePerSecond = dt.preferences.read("video_mencoder","FramesPerSecond","integer") - - dt.print_error("Will try to create video now") - -- Set the codec - local codec = "" - local codecPreferences = "" - - codecPreferences = dt.preferences.read("video_mencoder","Codec","string") - if (codecPreferences == "H.264 encoding") then - codec = 'x264' - end - if (codecPreferences == "XviD encoding") then - codec = 'xvid' - end - if not codecPreferences then - codec = 'x264' - end - - -- Create the command - local command = "mencoder -idx -nosound -noskip -ovc "..codec.." -lavcopts vcodec=mjpeg -o "..exportDirectory.."/"..exportFilename.." -mf fps="..framsePerSecond .." mf://" - - for _,v in pairs(image_table) do - command = command..v.."," - end - - dt.print_error("this is the command: "..command) - dt.control.execute( command) - - dt.print("Video created in "..exportDirectory) - - if ( dt.preferences.read("video_mencoder","OpenVideo","bool") == true ) then - local playVideoCommand = "xdg-open "..exportDirectory.."/"..exportFilename - dt.control.execute( playVideoCommand) - end -end - --- Preferences -dt.preferences.register("video_mencoder", "FramesPerSecond", "float", "Video exort (MEncoder): Frames per second", "Frames per Second in the Video export", 15, 1, 99, 0.1 ) -dt.preferences.register("video_mencoder", "OpenVideo", "bool", "Video exort (MEncoder): Open video after export", "Opens the Video after the export with the standard video player", false ) - -local handle = io.popen("xdg-user-dir VIDEOS") -local result = handle:read() -handle:close() -if (result == nil) then - result = "" -end -dt.preferences.register("video_mencoder", "ExportDirectory", "directory", "Video exort (MEncoder): Video export directory","A directory that will be used to export a Video",result) - --- Get the MEncoder codec list with: mencoder -ovc help -dt.preferences.register("video_mencoder", "Codec", "enum", "Video exort (MEncoder): Codec","Video codec","H.264 encoding","H.264 encoding","XviD encoding") - --- Register -dt.register_storage("video_mencoder", "Video Export (MEncoder)", show_status, create_video) From 252965a5d99383917eead9d106bb07db7b7ca918 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Tue, 24 Dec 2019 11:52:56 -0500 Subject: [PATCH 08/10] Updated README.md to reflect latest changes --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 2eb1620..b7c77fa 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,6 @@ rename-tags|Yes|LMW|Change a tag name select_untagged|Yes|LMW|Enable selection of untagged images slideshowMusic|No|L|Play music during a slideshow video_ffmpeg|No|LMW|Export video from darktable -video_mencoder|No|L|Export video from darktable ### Example Scripts @@ -68,10 +67,13 @@ These scripts provide examples of how to use specific portions of the API. They Name|Standalone|OS |Purpose ----|:--------:|:---:|------- api_version|Yes|LMW|Print the current API version +darkroom_demo|Yes|LMW|Demonstrate changing images in darkoom gettextExample|Yes|LM|How to use translation hello_world|Yes|LMW|Prints hello world when darktable starts +lighttable_demo|Yes|LMW|Demonstrate controlling lighttable mode, zoom, sorting and filtering moduleExample|Yes|LMW|How to create a lighttable module multi_os|No|LMW|How to create a cross platform script that calls an external executable +panels_demo|Yes|LMW|Demonstrate hiding and showing darktable panels preferenceExamples|Yes|LMW|How to use preferences in a script printExamples|Yes|LMW|How to use various print functions from a script running_os|Yes|LMW|Print out the running operating system From 5d7a60206ed4ff3591316e711ba023d59c3830e9 Mon Sep 17 00:00:00 2001 From: "U-DESKTOP-HQME86J\\marco" Date: Wed, 25 Dec 2019 16:02:53 +0100 Subject: [PATCH 09/10] requested updates --- README.md | 1 + contrib/ext_editor.lua | 371 ----------------------------------------- 2 files changed, 1 insertion(+), 371 deletions(-) delete mode 100644 contrib/ext_editor.lua diff --git a/README.md b/README.md index 2eb1620..2c49299 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,7 @@ CollectHelper|Yes|LMW|Add buttons to selected images module to manipulate the co copy_attach_detach_tags|Yes|LMW|Copy and paste tags from/to images cr2hdr|Yes|L|Process image created with Magic Lantern Dual ISO enfuseAdvanced|No|LMW|Merge multiple images into Dynamic Range Increase (DRI) or Depth From Focus (DFF) images +ext_editor|No|LW|Export pictures to collection and edit them with up to nine user-defined external editors face_recognition|No|LM|Identify and tag images using facial recognition fujifilm_ratings|No|LM|Support importing Fujifilm ratings geoJSON_export|No|L|Create a geo JSON script with thumbnails for use in ... diff --git a/contrib/ext_editor.lua b/contrib/ext_editor.lua deleted file mode 100644 index 63f7b93..0000000 --- a/contrib/ext_editor.lua +++ /dev/null @@ -1,371 +0,0 @@ ---[[ - - DESCRIPTION - ext_editor.lua - edit images with external editors - - This script provides helpers to edit image files with programs external to darktable. - It adds: - - a new target storage "collection". Image exported will be reimported to collection for - further edit with external programs - - a new lighttable module "external editors", to select a program from a list of up to - - 9 external editors and run it on a selected image - - a set of lua preferences in order to configure name and path of up to 9 external editors - - a set of lua shortcuts in order to quick launch the external editors - - USAGE - * require this script from main lua file - - * in "preferences / lua options" configure name and command/path of external programs - * in "preferences / shortcuts / lua" configure shortcuts for external programs (optional) - - * in the export dialog choose "collection" and select the format and bit depth for the - exported image - * press "export" - * the exported image will be imported into collection and grouped with the original image - - * select an image for editing with en external program - * in lighttable / external editors, select program and press "edit" - * edit the image with the external editor, overwite the file, quit the external program - * the selected image will be updated - or - * in lighttable / external editors, select program and press "edit a copy" - * edit the image with the external editor, overwite the file, quit the external program - * a copy of the selected image will be created and updated - or - * in lighttable select target storage "collection" - * enter in darkroom - * to create an export or a copy press CRTL+E - * use the shortcut to edit the current image with the corresponding external editor - * overwite the file, quit the external program - * the darkroom view will be updated - - * warning: mouseover on lighttable / filmstrip will prevail on current image - * this is the default DT behavior, not a bug of this script - - CAVEATS - * tested with DT 3.0 in Windows and Ubuntu - * MAC compatibility not tested - - TODO - * localization - * buttons are not equal in size and centered - - BUGS, COMMENTS, SUGGESTIONS - * send to Marco Carrarini, marco.carrarini@gmail.com - - CHANGES - * 20191220 - initial version, PR done - * 20191221 - reworked, cleaned, added "copy and edit" - * 20191222 - added darkroom mode - * 20191223 - check API version, OS compatibility - -]] - - -local dt = require "darktable" -local du = require "lib/dtutils" -local df = require "lib/dtutils.file" -local dtsys = require "lib/dtutils.system" - - --- check API version -du.check_min_api_version("5.0.2", "ext_editor") -- darktable 3.0 - - --- OS compatibility -local PS = dt.configuration.running_os == "windows" and "\\" or "/" - - --- executables of the external editors -local program_paths = { - [1] = dt.preferences.read("ext_editor","program_path_1", "string"), - [2] = dt.preferences.read("ext_editor","program_path_2", "string"), - [3] = dt.preferences.read("ext_editor","program_path_3", "string"), - [4] = dt.preferences.read("ext_editor","program_path_4", "string"), - [5] = dt.preferences.read("ext_editor","program_path_5", "string"), - [6] = dt.preferences.read("ext_editor","program_path_6", "string"), - [7] = dt.preferences.read("ext_editor","program_path_7", "string"), - [8] = dt.preferences.read("ext_editor","program_path_8", "string"), - [9] = dt.preferences.read("ext_editor","program_path_9", "string") - } - - --- friendly name of the external editors -local program_names = { - [1] = dt.preferences.read("ext_editor","program_name_1", "string"), - [2] = dt.preferences.read("ext_editor","program_name_2", "string"), - [3] = dt.preferences.read("ext_editor","program_name_3", "string"), - [4] = dt.preferences.read("ext_editor","program_name_4", "string"), - [5] = dt.preferences.read("ext_editor","program_name_5", "string"), - [6] = dt.preferences.read("ext_editor","program_name_6", "string"), - [7] = dt.preferences.read("ext_editor","program_name_7", "string"), - [8] = dt.preferences.read("ext_editor","program_name_8", "string"), - [9] = dt.preferences.read("ext_editor","program_name_9", "string") - } - - --- last used editor -if not (dt.preferences.read("ext_editor","initialized", "bool")) then - dt.preferences.write("ext_editor","lastchoice", "integer", 1) - dt.preferences.write("ext_editor","initialized", "bool", true) - end -local lastchoice = dt.preferences.read("ext_editor","lastchoice", "integer") - - --- shows export progress -local function show_status(storage, image, format, filename, - number, total, high_quality, extra_data) - dt.print(string.format("Exporting Image %i/%i ...", number, total)) - end - - --- callback for button "edit" -local function OpenWith(images, choice) - - if #images == 1 then - for _, image in pairs(images) do - - -- image to be edited - name = image.path..PS..image.filename - - -- launch the external editor - local run_cmd = '"'..program_paths[choice]..'" "'..name..'"' - dt.print("Launching "..program_names[choice].."...") - dtsys.external_command(run_cmd) - - -- refresh the image view - -- note that only image:drop_cache() is not enough to refresh view in darkroom mode - -- therefore image must be deleted and reimported to force refresh - - local image_leader = image.group_leader - image:delete () - local new_image = dt.database.import(name) - new_image:group_with(image_leader) - - -- copy tags from image leader - for _,tag in pairs(dt.tags.get_tags(image_leader)) do - if not (string.sub(tag.name,1,9) == "darktable") then - dt.tags.attach(tag, new_image) - end - end - - -- remember the last editor used - dt.preferences.write("ext_editor","lastchoice", "integer", choice) - - -- refresh darkroom view - if dt.gui.current_view () == dt.gui.views.darkroom then - dt.gui.views.darkroom.display_image(new_image) - end - end - else - dt.print('please select one image') - end - - end - - --- callback for button "copy and edit" -local function CopyAndOpenWith(images, choice) - - if #images == 1 then - for _,image in pairs(images) do - - -- image to be copied and edited - local name = image.path..PS..image.filename - local new_name = name - - -- create unique filename - while df.check_if_file_exists(new_name) do - new_name = df.filename_increment(new_name) - end - - -- limit to 99 more exports of the original export - if string.match(df.get_basename(new_name), "_(d-)$") == "99" then - break - end - - -- physical copy - local result = df.file_copy(name, new_name) - - if result then - -- launch the external editor - local run_cmd = '"'..program_paths[choice]..'" "'..new_name..'"' - dt.print("Launching "..program_names[choice].."...") - dtsys.external_command(run_cmd) - - -- import in database and group - local new_image = dt.database.import(new_name) - new_image:group_with(image.group_leader) - - -- copy image tags - for _,tag in pairs(dt.tags.get_tags(image)) do - if not (string.sub(tag.name,1,9) == "darktable") then - dt.tags.attach(tag, new_image) - end - end - - -- remember the last editor used - dt.preferences.write("ext_editor","lastchoice", "integer", choice) - end - end - else - dt.print('please select one image') - end - - - end - - --- callback function for shortcuts -local function program_shortcut(event, shortcut) - local choice = tonumber(string.sub(shortcut, -1)) - OpenWith(dt.gui.action_images, choice) - end - - --- export images and reimport in collection -local function export2collection(storage, image_table, extra_data) - - for image, temp_name in pairs(image_table) do - - -- images are first exported in temp folder - -- create unique filename - local new_name = image.path ..PS..df.get_filename(temp_name) - while df.check_if_file_exists(new_name) do - new_name = df.filename_increment(new_name) - - -- limit to 99 more exports of the original export - if string.match(df.get_basename(new_name), "_(d-)$") == "99" then - break - end - end - - -- image moved to collection folder - local result = df.file_move(temp_name, new_name) - - if result then - -- import in database and group - local new_image = dt.database.import(new_name) - new_image:group_with(image.group_leader) - end - end - end - - --- combobox -local combobox = dt.new_widget("combobox") - { - label = "choose program", - tooltip = "select the external editor from the list", - value = lastchoice, -- remember status, - program_names[1], - program_names[2], - program_names[3], - program_names[4], - program_names[5], - program_names[6], - program_names[7], - program_names[8], - program_names[9] - } - - --- button edit -local button1 = dt.new_widget("button") - { - label = " edit ", - tooltip = "open the selected image in external editor", - dt_lua_align_t = center, - clicked_callback = function (_) - local choice = combobox.selected - OpenWith(dt.gui.action_images, choice) - end - } - - --- button edit a copy -local button2 = dt.new_widget("button") - { - label = " edit a copy ", - tooltip = "create a copy of the selected image and open it in external editor", - clicked_callback = function (_) - local choice = combobox.selected - CopyAndOpenWith(dt.gui.action_images, choice) - end - } - - --- box for the two buttons -local box1 = dt.new_widget ("box") { - orientation = "horizontal", - button1, - button2 -} - - --- register new lighttable module -dt.register_lib( - "ext_editor", -- module name - "external editors", -- name - true, -- expandable - false, -- resetable - {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, - dt.new_widget("box") -- widget - { - orientation = "vertical", - combobox, - box1 - }, - nil,-- view_enter - nil -- view_leave - ) - - --- register new storage -dt.register_storage("exp2coll", "collection", show_status, export2collection) - - --- register the new preferences -dt.preferences.register("ext_editor","program_path_9", "string","path to external editor 9", "path to external editor","") -dt.preferences.register("ext_editor","program_name_9", "string","name of external editor 9", "name of external editor","") - -dt.preferences.register("ext_editor","program_path_8", "string","path to external editor 8", "path to external editor","") -dt.preferences.register("ext_editor","program_name_8", "string","name of external editor 8", "name of external editor","") - -dt.preferences.register("ext_editor","program_path_7", "string","path to external editor 7", "path to external editor","") -dt.preferences.register("ext_editor","program_name_7", "string","name of external editor 7", "name of external editor","") - -dt.preferences.register("ext_editor","program_path_6", "string","path to external editor 6", "path to external editor","") -dt.preferences.register("ext_editor","program_name_6", "string","name of external editor 6", "name of external editor","") - -dt.preferences.register("ext_editor","program_path_5", "string","path to external editor 5", "path to external editor","") -dt.preferences.register("ext_editor","program_name_5", "string","name of external editor 5", "name of external editor","") - -dt.preferences.register("ext_editor","program_path_4", "string","path to external editor 4", "path to external editor","") -dt.preferences.register("ext_editor","program_name_4", "string","name of external editor 4", "name of external editor","") - -dt.preferences.register("ext_editor","program_path_3", "string","path to external editor 3", "path to external editor","") -dt.preferences.register("ext_editor","program_name_3", "string","name of external editor 3", "name of external editor","") - -dt.preferences.register("ext_editor","program_path_2", "string","path to external editor 2", "path to external editor","") -dt.preferences.register("ext_editor","program_name_2", "string","name of external editor 2", "name of external editor","") - -dt.preferences.register("ext_editor","program_path_1", "string","path to external editor 1", "path to external editor","") -dt.preferences.register("ext_editor","program_name_1", "string","name of external editor 1", "name of external editor","") - - --- register the new shortcuts -dt.register_event("shortcut", program_shortcut, "edit with program 1") -dt.register_event("shortcut", program_shortcut, "edit with program 2") -dt.register_event("shortcut", program_shortcut, "edit with program 3") -dt.register_event("shortcut", program_shortcut, "edit with program 4") -dt.register_event("shortcut", program_shortcut, "edit with program 5") -dt.register_event("shortcut", program_shortcut, "edit with program 6") -dt.register_event("shortcut", program_shortcut, "edit with program 7") -dt.register_event("shortcut", program_shortcut, "edit with program 8") -dt.register_event("shortcut", program_shortcut, "edit with program 9") - --- end of script - --- vim: shiftwidth=2 expandtab tabstop=2 cindent syntax=lua --- kate: hl Lua; From cfa71927de1434478e393205e0ed12f2e46261c7 Mon Sep 17 00:00:00 2001 From: "U-DESKTOP-HQME86J\\marco" Date: Wed, 25 Dec 2019 16:16:44 +0100 Subject: [PATCH 10/10] requested updates --- contrib/ext_editor.lua | 371 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 371 insertions(+) create mode 100644 contrib/ext_editor.lua diff --git a/contrib/ext_editor.lua b/contrib/ext_editor.lua new file mode 100644 index 0000000..0b5054b --- /dev/null +++ b/contrib/ext_editor.lua @@ -0,0 +1,371 @@ +--[[ + + DESCRIPTION + ext_editor.lua - edit images with external editors + + This script provides helpers to edit image files with programs external to darktable. + It adds: + - a new target storage "collection". Image exported will be reimported to collection for + further edit with external programs + - a new lighttable module "external editors", to select a program from a list of up to + - 9 external editors and run it on a selected image + - a set of lua preferences in order to configure name and path of up to 9 external editors + - a set of lua shortcuts in order to quick launch the external editors + + USAGE + * require this script from main lua file + + * in "preferences / lua options" configure name and path/command of external programs + * in "preferences / shortcuts / lua" configure shortcuts for external programs (optional) + + * in the export dialog choose "collection" and select the format and bit depth for the + exported image + * press "export" + * the exported image will be imported into collection and grouped with the original image + + * select an image for editing with en external program + * in lighttable / external editors, select program and press "edit" + * edit the image with the external editor, overwite the file, quit the external program + * the selected image will be updated + or + * in lighttable / external editors, select program and press "edit a copy" + * edit the image with the external editor, overwite the file, quit the external program + * a copy of the selected image will be created and updated + or + * in lighttable select target storage "collection" + * enter in darkroom + * to create an export or a copy press CRTL+E + * use the shortcut to edit the current image with the corresponding external editor + * overwite the file, quit the external program + * the darkroom view will be updated + + * warning: mouseover on lighttable / filmstrip will prevail on current image + * this is the default DT behavior, not a bug of this script + + CAVEATS + * tested with DT 3.0 in Windows and Ubuntu + * MAC compatibility not tested + + TODO + * localization + * buttons are not equal in size and centered + + BUGS, COMMENTS, SUGGESTIONS + * send to Marco Carrarini, marco.carrarini@gmail.com + + CHANGES + * 20191220 - initial version, PR done + * 20191221 - reworked, cleaned, added "copy and edit" + * 20191222 - added darkroom mode + * 20191223 - check API version, OS compatibility + +]] + + +local dt = require "darktable" +local du = require "lib/dtutils" +local df = require "lib/dtutils.file" +local dtsys = require "lib/dtutils.system" + + +-- check API version +du.check_min_api_version("5.0.2", "ext_editor") -- darktable 3.0 + + +-- OS compatibility +local PS = dt.configuration.running_os == "windows" and "\\" or "/" + + +-- executables of the external editors +local program_paths = { + [1] = dt.preferences.read("ext_editor","program_path_1", "string"), + [2] = dt.preferences.read("ext_editor","program_path_2", "string"), + [3] = dt.preferences.read("ext_editor","program_path_3", "string"), + [4] = dt.preferences.read("ext_editor","program_path_4", "string"), + [5] = dt.preferences.read("ext_editor","program_path_5", "string"), + [6] = dt.preferences.read("ext_editor","program_path_6", "string"), + [7] = dt.preferences.read("ext_editor","program_path_7", "string"), + [8] = dt.preferences.read("ext_editor","program_path_8", "string"), + [9] = dt.preferences.read("ext_editor","program_path_9", "string") + } + + +-- friendly names of the external editors +local program_names = { + [1] = dt.preferences.read("ext_editor","program_name_1", "string"), + [2] = dt.preferences.read("ext_editor","program_name_2", "string"), + [3] = dt.preferences.read("ext_editor","program_name_3", "string"), + [4] = dt.preferences.read("ext_editor","program_name_4", "string"), + [5] = dt.preferences.read("ext_editor","program_name_5", "string"), + [6] = dt.preferences.read("ext_editor","program_name_6", "string"), + [7] = dt.preferences.read("ext_editor","program_name_7", "string"), + [8] = dt.preferences.read("ext_editor","program_name_8", "string"), + [9] = dt.preferences.read("ext_editor","program_name_9", "string") + } + + +-- last used editor +if not (dt.preferences.read("ext_editor","initialized", "bool")) then + dt.preferences.write("ext_editor","lastchoice", "integer", 1) + dt.preferences.write("ext_editor","initialized", "bool", true) + end +local lastchoice = dt.preferences.read("ext_editor","lastchoice", "integer") + + +-- shows export progress +local function show_status(storage, image, format, filename, + number, total, high_quality, extra_data) + dt.print(string.format("Exporting Image %i/%i ...", number, total)) + end + + +-- callback for button "edit" +local function OpenWith(images, choice) + + if #images == 1 then + for _, image in pairs(images) do + + -- image to be edited + name = image.path..PS..image.filename + + -- launch the external editor + local run_cmd = df.sanitize_filename(program_paths[choice]).." "..df.sanitize_filename(name) + dt.print("Launching "..program_names[choice].."...") + dtsys.external_command(run_cmd) + + -- refresh the image view + -- note that only image:drop_cache() is not enough to refresh view in darkroom mode + -- therefore image must be deleted and reimported to force refresh + + local image_leader = image.group_leader + image:delete () + local new_image = dt.database.import(name) + new_image:group_with(image_leader) + + -- copy tags from image leader + for _,tag in pairs(dt.tags.get_tags(image_leader)) do + if not (string.sub(tag.name,1,9) == "darktable") then + dt.tags.attach(tag, new_image) + end + end + + -- remember the last editor used + dt.preferences.write("ext_editor","lastchoice", "integer", choice) + + -- refresh darkroom view + if dt.gui.current_view () == dt.gui.views.darkroom then + dt.gui.views.darkroom.display_image(new_image) + end + end + else + dt.print('please select one image') + end + + end + + +-- callback for button "copy and edit" +local function CopyAndOpenWith(images, choice) + + if #images == 1 then + for _,image in pairs(images) do + + -- image to be copied and edited + local name = image.path..PS..image.filename + local new_name = name + + -- create unique filename + while df.check_if_file_exists(new_name) do + new_name = df.filename_increment(new_name) + end + + -- limit to 99 more exports of the original export + if string.match(df.get_basename(new_name), "_(d-)$") == "99" then + break + end + + -- physical copy + local result = df.file_copy(name, new_name) + + if result then + -- launch the external editor + local run_cmd = df.sanitize_filename(program_paths[choice]).." "..df.sanitize_filename(new_name) + dt.print("Launching "..program_names[choice].."...") + dtsys.external_command(run_cmd) + + -- import in database and group + local new_image = dt.database.import(new_name) + new_image:group_with(image.group_leader) + + -- copy image tags + for _,tag in pairs(dt.tags.get_tags(image)) do + if not (string.sub(tag.name,1,9) == "darktable") then + dt.tags.attach(tag, new_image) + end + end + + -- remember the last editor used + dt.preferences.write("ext_editor","lastchoice", "integer", choice) + end + end + else + dt.print('please select one image') + end + + + end + + +-- callback function for shortcuts +local function program_shortcut(event, shortcut) + local choice = tonumber(string.sub(shortcut, -1)) + OpenWith(dt.gui.action_images, choice) + end + + +-- export images and reimport in collection +local function export2collection(storage, image_table, extra_data) + + for image, temp_name in pairs(image_table) do + + -- images are first exported in temp folder + -- create unique filename + local new_name = image.path ..PS..df.get_filename(temp_name) + while df.check_if_file_exists(new_name) do + new_name = df.filename_increment(new_name) + + -- limit to 99 more exports of the original export + if string.match(df.get_basename(new_name), "_(d-)$") == "99" then + break + end + end + + -- image moved to collection folder + local result = df.file_move(temp_name, new_name) + + if result then + -- import in database and group + local new_image = dt.database.import(new_name) + new_image:group_with(image.group_leader) + end + end + end + + +-- combobox +local combobox = dt.new_widget("combobox") + { + label = "choose program", + tooltip = "select the external editor from the list", + value = lastchoice, -- remember status, + program_names[1], + program_names[2], + program_names[3], + program_names[4], + program_names[5], + program_names[6], + program_names[7], + program_names[8], + program_names[9] + } + + +-- button edit +local button1 = dt.new_widget("button") + { + label = "edit", + tooltip = "open the selected image in external editor", + dt_lua_align_t = center, + clicked_callback = function (_) + local choice = combobox.selected + OpenWith(dt.gui.action_images, choice) + end + } + + +-- button edit a copy +local button2 = dt.new_widget("button") + { + label = "edit a copy", + tooltip = "create a copy of the selected image and open it in external editor", + clicked_callback = function (_) + local choice = combobox.selected + CopyAndOpenWith(dt.gui.action_images, choice) + end + } + + +-- box for the two buttons +local box1 = dt.new_widget ("box") { + orientation = "horizontal", + button1, + button2 +} + + +-- register new lighttable module +dt.register_lib( + "ext_editor", -- module name + "external editors", -- name + true, -- expandable + false, -- resetable + {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, + dt.new_widget("box") -- widget + { + orientation = "vertical", + combobox, + box1 + }, + nil,-- view_enter + nil -- view_leave + ) + + +-- register new storage +dt.register_storage("exp2coll", "collection", show_status, export2collection) + + +-- register the new preferences +dt.preferences.register("ext_editor","program_path_9", "string","command for external editor 9", "command for external editor, including full path if needed","") +dt.preferences.register("ext_editor","program_name_9", "string","friendly name of external editor 9", "friendly name of external editor","") + +dt.preferences.register("ext_editor","program_path_8", "string","command for external editor 8", "command for external editor, including full path if needed","") +dt.preferences.register("ext_editor","program_name_8", "string","friendly name of external editor 8", "friendly name of external editor","") + +dt.preferences.register("ext_editor","program_path_7", "string","command for external editor 7", "command for external editor, including full path if needed","") +dt.preferences.register("ext_editor","program_name_7", "string","friendly name of external editor 7", "friendly name of external editor","") + +dt.preferences.register("ext_editor","program_path_6", "string","command for external editor 6", "command for external editor, including full path if needed","") +dt.preferences.register("ext_editor","program_name_6", "string","friendly name of external editor 6", "friendly name of external editor","") + +dt.preferences.register("ext_editor","program_path_5", "string","command for external editor 5", "command for external editor, including full path if needed","") +dt.preferences.register("ext_editor","program_name_5", "string","friendly name of external editor 5", "friendly name of external editor","") + +dt.preferences.register("ext_editor","program_path_4", "string","command for external editor 4", "command for external editor, including full path if needed","") +dt.preferences.register("ext_editor","program_name_4", "string","friendly name of external editor 4", "friendly name of external editor","") + +dt.preferences.register("ext_editor","program_path_3", "string","command for external editor 3", "command for external editor, including full path if needed","") +dt.preferences.register("ext_editor","program_name_3", "string","friendly name of external editor 3", "friendly name of external editor","") + +dt.preferences.register("ext_editor","program_path_2", "string","command for external editor 2", "command for external editor, including full path if needed","") +dt.preferences.register("ext_editor","program_name_2", "string","friendly name of external editor 2", "friendly name of external editor","") + +dt.preferences.register("ext_editor","program_path_1", "string","command for external editor 1", "command for external editor, including full path if needed","") +dt.preferences.register("ext_editor","program_name_1", "string","friendly name of external editor 1", "friendly name of external editor","") + + +-- register the new shortcuts +dt.register_event("shortcut", program_shortcut, "edit with program 1") +dt.register_event("shortcut", program_shortcut, "edit with program 2") +dt.register_event("shortcut", program_shortcut, "edit with program 3") +dt.register_event("shortcut", program_shortcut, "edit with program 4") +dt.register_event("shortcut", program_shortcut, "edit with program 5") +dt.register_event("shortcut", program_shortcut, "edit with program 6") +dt.register_event("shortcut", program_shortcut, "edit with program 7") +dt.register_event("shortcut", program_shortcut, "edit with program 8") +dt.register_event("shortcut", program_shortcut, "edit with program 9") + +-- end of script + +-- vim: shiftwidth=2 expandtab tabstop=2 cindent syntax=lua +-- kate: hl Lua;