From c74d29e02013950c81e9db283b406b3763641324 Mon Sep 17 00:00:00 2001 From: GHswitt Date: Wed, 14 Dec 2016 01:08:10 +0100 Subject: [PATCH 001/679] Add new GUI entry in lighttable for renaming tags Rename tag: A new tag is added to all images containing old tag. After that, the old tag is removed from all images (and removed from tags). The GUI entry has two entries: Old tag, New tag and a Go button. --- contrib/rename-tags.lua | 114 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 contrib/rename-tags.lua diff --git a/contrib/rename-tags.lua b/contrib/rename-tags.lua new file mode 100644 index 00000000..69c6e0a8 --- /dev/null +++ b/contrib/rename-tags.lua @@ -0,0 +1,114 @@ +--[[ +Rename tags + +AUTHOR +Sebastian Witt (se.witt@gmx.net) + +INSTALLATION +* copy this file in $CONFIGDIR/lua/ where CONFIGDIR +is your darktable configuration directory +* add the following line in the file $CONFIGDIR/luarc + require "rename-tags" + +USAGE +* In lighttable there is a new entry: 'rename tag' +* Enter old tag (this one gets deleted!) +* Enter new tag name + +LICENSE +GPLv2 + +]] + +local darktable = require "darktable" +local debug = require "darktable.debug" + +-- GUI entries +local old_tag = darktable.new_widget("entry") { tooltip = "Enter old tag" } +local new_tag = darktable.new_widget("entry") { tooltip = "Enter new tag" } + +-- This function does the renaming +local function rename_tags(widget) + -- If entries are empty, return + if old_tag.text == '' then + darktable.print ("Old tag can't be empty") + return + end + if new_tag.text == '' then + darktable.print ("New tag can't be empty") + return + end + + local Count = 0 + + -- Check if old tag exists + local ot = darktable.tags.find (old_tag.text) + + if not ot then + darktable.print ("Old tag does not exist") + return + end + + -- Show job + local job = darktable.gui.create_job ("Renaming tag", true) + + old_tag.editable = false + new_tag.editable = false + + -- Create if it does not exists + local nt = darktable.tags.create (new_tag.text) + + -- Search images for old tag + dbcount = #darktable.database + for i,image in ipairs(darktable.database) do + -- Update progress bar + job.percent = i / dbcount + + local tags = image:get_tags () + for _,t in ipairs (tags) do + if t.name == old_tag.text then + -- Found it, attach new tag + image:attach_tag (nt) + Count = Count + 1 + end + end + end + + -- Delete old tag, this removes it from all images + darktable.tags.delete (ot) + + job.valid = false + darktable.print ("Renamed tags for " .. Count .. " images") + old_tag.editable = true + new_tag.editable = true +end + +-- GUI +local old_widget = darktable.new_widget ("box") { + orientation = "horizontal", + darktable.new_widget("label") { label = "Old tag" }, + old_tag +} + +local new_widget = darktable.new_widget ("box") { + orientation = "horizontal", + darktable.new_widget("label") { label = "New tag" }, + new_tag +} + +local function rename_reset(widget) + old_tag.text = '' + new_tag.text = '' +end + +local rename_widget = darktable.new_widget ("box") { + orientation = "vertical", + reset_callback = rename_reset, + old_widget, + new_widget, + darktable.new_widget("button") { label = "Go", clicked_callback = rename_tags } +} + + +darktable.register_lib ("rename_tags", "rename tag", true, true, {[darktable.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 20},}, rename_widget, nil, nil) + From 39ae92a0fa805f82d0053e6fcf18690b785ed5e1 Mon Sep 17 00:00:00 2001 From: supertobi Date: Tue, 18 Apr 2017 22:31:49 +0200 Subject: [PATCH 002/679] Update geoToolbox.lua fix open with gnome-maps --- contrib/geoToolbox.lua | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/contrib/geoToolbox.lua b/contrib/geoToolbox.lua index e6e02fb5..4b484319 100644 --- a/contrib/geoToolbox.lua +++ b/contrib/geoToolbox.lua @@ -27,6 +27,7 @@ require "geoToolbox" local dt = require "darktable" local df = require "lib/dtutils.file" +require "official/yield" local gettext = dt.gettext dt.configuration.check_version(...,{3,0,0},{4,0,0}) @@ -326,20 +327,17 @@ local function open_location_in_gnome_maps() if ((image.longitude and image.latitude) and (image.longitude ~= 0 and image.latitude ~= 90) -- Sometimes the north-pole but most likely just wrong data ) then - lat1 = image.latitude; - lon1 = image.longitude; + lat1 = string.gsub(image.latitude, ",", "."); + lon1 = string.gsub(image.longitude, ",", "."); break end + end - local startCommand - startCommand = "gnome-maps \"geo:" .. lat1 .. "," .. lon1 .."\"" - dt.print_error(startCommand) - - if coroutine.yield("RUN_COMMAND", startCommand) then - dt.print(_("Command failed ...")) - end + local startCommand + startCommand = "gnome-maps \"geo:" .. lat1 .. "," .. lon1 .."\"" + dt.print_error(startCommand) - end + dt.control.execute(startCommand) end From 91758b61c3bf988578df38f6186084cf9404d10b Mon Sep 17 00:00:00 2001 From: khampf Date: Fri, 21 Apr 2017 13:51:40 +0300 Subject: [PATCH 003/679] ISO 19794-5/ICAO 9303 clipping guide as contrib/passport_guide.lua --- contrib/passport_guide.lua | 73 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 contrib/passport_guide.lua diff --git a/contrib/passport_guide.lua b/contrib/passport_guide.lua new file mode 100644 index 00000000..0e894f27 --- /dev/null +++ b/contrib/passport_guide.lua @@ -0,0 +1,73 @@ +--[[ +PASSPORT CROPPING GUIDE +guides for cropping passport photos based on documents from the Finnish police +(https://www.poliisi.fi/instancedata/prime_product_julkaisu/intermin/embeds/poliisiwwwstructure/38462_Passikuvaohje_EN.pdf) describing passport photo dimensions of 47x36 mm and 500x653 px for digital biometric data stored in passports. They use ISO 19794-5 standard based on ICAO 9303 regulations which should also be compliant for all of Europe. + +AUTHOR +Kåre Hampf (k.hampf@gmail.com) + +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" +* (optional) add the line: + "plugins/darkroom/clipping/extra_aspect_ratios/passport 36x47mm=47:36" + to $CONFIGDIR/darktablerc + +USAGE +* when using the cropping tool, select "passport" as guide and if you added the line in yout rc + select "passport 36x47mm" as aspect + +LICENSE +GPLv2 + +]] + +local dt = require "darktable" +dt.configuration.check_version(...,{2,0,0},{3,0,0},{4,0,0}) + +dt.guides.register_guide("passport", +-- draw +function(cr, x, y, w, h, zoom_scale) + local _w, _h + + -- get the max 36x47 rectangle + local aspect_ratio = 47 / 36 + if w * aspect_ratio > h then + _w = h / aspect_ratio + _h = h + else + _w = w + _h = w * aspect_ratio + end + + cr:save() + + cr:translate(x + (w - _w) / 2, y + (h - _h) / 2) + cr:scale(_w / 36, _h / 47) + + -- the outer rectangle + cr:rectangle( 0, 0, 36, 47) + + -- vertical bars + cr:draw_line(16.5, 8, 16.5, 36) + cr:draw_line(19.5, 8, 19.5, 36) + + -- long horisontal bars + cr:draw_line(6, 4, 30, 4) + cr:draw_line(6, 40, 30, 40) + + -- short horisontal bars + cr:draw_line(9, 6, 27, 6) + cr:draw_line(9, 38, 27, 38) + + cr:restore() +end, +-- gui +function() + return dt.new_widget("label"){label = "ISO 19794-5/ICAO 9309 passport", halign = "start"} +end +) + +-- 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 From 50668817dbf915d46fc66e6d23ae2ba032112692 Mon Sep 17 00:00:00 2001 From: khampf Date: Fri, 21 Apr 2017 21:43:02 +0300 Subject: [PATCH 004/679] added API 5 to version check --- contrib/passport_guide.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/passport_guide.lua b/contrib/passport_guide.lua index 0e894f27..ea9b04f4 100644 --- a/contrib/passport_guide.lua +++ b/contrib/passport_guide.lua @@ -24,7 +24,7 @@ GPLv2 ]] local dt = require "darktable" -dt.configuration.check_version(...,{2,0,0},{3,0,0},{4,0,0}) +dt.configuration.check_version(...,{2,0,0},{3,0,0},{4,0,0},{5,0,0}) dt.guides.register_guide("passport", -- draw From c8d5e9d9d2b9537865dc5c43f41033a4e793e7be Mon Sep 17 00:00:00 2001 From: khampf Date: Sat, 22 Apr 2017 22:06:55 +0300 Subject: [PATCH 005/679] Longer version of GPL text --- contrib/passport_guide.lua | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/contrib/passport_guide.lua b/contrib/passport_guide.lua index ea9b04f4..ef68b13b 100644 --- a/contrib/passport_guide.lua +++ b/contrib/passport_guide.lua @@ -1,3 +1,22 @@ +--[[ + Passport cropping guide for darktable + + copyright (c) 2017 Kåre Hampf + + 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 . +]] + --[[ PASSPORT CROPPING GUIDE guides for cropping passport photos based on documents from the Finnish police @@ -17,10 +36,6 @@ INSTALLATION USAGE * when using the cropping tool, select "passport" as guide and if you added the line in yout rc select "passport 36x47mm" as aspect - -LICENSE -GPLv2 - ]] local dt = require "darktable" From 693c9858c2f0cd9d7cd02b6b33621c1867a2efac Mon Sep 17 00:00:00 2001 From: khampf Date: Sat, 22 Apr 2017 23:24:43 +0300 Subject: [PATCH 006/679] variables renamed for clarity (local functions tested without success) --- contrib/passport_guide.lua | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/contrib/passport_guide.lua b/contrib/passport_guide.lua index ef68b13b..6f00b2b3 100644 --- a/contrib/passport_guide.lua +++ b/contrib/passport_guide.lua @@ -43,40 +43,40 @@ dt.configuration.check_version(...,{2,0,0},{3,0,0},{4,0,0},{5,0,0}) dt.guides.register_guide("passport", -- draw -function(cr, x, y, w, h, zoom_scale) - local _w, _h +function(cairo, x, y, width, height, zoom_scale) + local _width, _height -- get the max 36x47 rectangle local aspect_ratio = 47 / 36 - if w * aspect_ratio > h then - _w = h / aspect_ratio - _h = h + if width * aspect_ratio > height then + _width = height / aspect_ratio + _height = height else - _w = w - _h = w * aspect_ratio + _width = width + _height = width * aspect_ratio end - cr:save() + cairo:save() - cr:translate(x + (w - _w) / 2, y + (h - _h) / 2) - cr:scale(_w / 36, _h / 47) + cairo:translate(x + (width - _width) / 2, y + (height - _height) / 2) + cairo:scale(_width / 36, _height / 47) -- the outer rectangle - cr:rectangle( 0, 0, 36, 47) + cairo:rectangle( 0, 0, 36, 47) -- vertical bars - cr:draw_line(16.5, 8, 16.5, 36) - cr:draw_line(19.5, 8, 19.5, 36) + cairo:draw_line(16.5, 8, 16.5, 36) + cairo:draw_line(19.5, 8, 19.5, 36) -- long horisontal bars - cr:draw_line(6, 4, 30, 4) - cr:draw_line(6, 40, 30, 40) + cairo:draw_line(6, 4, 30, 4) + cairo:draw_line(6, 40, 30, 40) -- short horisontal bars - cr:draw_line(9, 6, 27, 6) - cr:draw_line(9, 38, 27, 38) + cairo:draw_line(9, 6, 27, 6) + cairo:draw_line(9, 38, 27, 38) - cr:restore() + cairo:restore() end, -- gui function() From f52292e8d11f428c59e049d4cfd136e9f30478d7 Mon Sep 17 00:00:00 2001 From: khampf Date: Sat, 22 Apr 2017 23:34:55 +0300 Subject: [PATCH 007/679] Translatable by using gettext --- contrib/passport_guide.lua | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/contrib/passport_guide.lua b/contrib/passport_guide.lua index 6f00b2b3..48ae64f6 100644 --- a/contrib/passport_guide.lua +++ b/contrib/passport_guide.lua @@ -22,9 +22,6 @@ PASSPORT CROPPING GUIDE guides for cropping passport photos based on documents from the Finnish police (https://www.poliisi.fi/instancedata/prime_product_julkaisu/intermin/embeds/poliisiwwwstructure/38462_Passikuvaohje_EN.pdf) describing passport photo dimensions of 47x36 mm and 500x653 px for digital biometric data stored in passports. They use ISO 19794-5 standard based on ICAO 9303 regulations which should also be compliant for all of Europe. -AUTHOR -Kåre Hampf (k.hampf@gmail.com) - INSTALLATION * copy this file in $CONFIGDIR/lua/ where CONFIGDIR is your darktable configuration directory * add the following line in the file $CONFIGDIR/luarc @@ -39,8 +36,17 @@ USAGE ]] local dt = require "darktable" +local gettext = dt.gettext + dt.configuration.check_version(...,{2,0,0},{3,0,0},{4,0,0},{5,0,0}) +-- Tell gettext where to find the .mo file translating messages for a particular domain +gettext.bindtextdomain("passport_guide",dt.configuration.config_dir.."/lua/locale/") + +local function _(msgid) + return gettext.dgettext("passport_guide", msgid) +end + dt.guides.register_guide("passport", -- draw function(cairo, x, y, width, height, zoom_scale) @@ -80,7 +86,7 @@ function(cairo, x, y, width, height, zoom_scale) end, -- gui function() - return dt.new_widget("label"){label = "ISO 19794-5/ICAO 9309 passport", halign = "start"} + return dt.new_widget("label"){label = _("ISO 19794-5/ICAO 9309 passport"), halign = "start"} end ) From ef46cd9b455600acf7e993bad0502a8097d5bf6d Mon Sep 17 00:00:00 2001 From: supertobi Date: Thu, 27 Apr 2017 20:20:29 +0200 Subject: [PATCH 008/679] Update geoToolbox.lua reverse geocodeing start --- contrib/geoToolbox.lua | 78 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/contrib/geoToolbox.lua b/contrib/geoToolbox.lua index 4b484319..3bcae3b1 100644 --- a/contrib/geoToolbox.lua +++ b/contrib/geoToolbox.lua @@ -341,6 +341,68 @@ local function open_location_in_gnome_maps() end +-- Trim Funktion from: http://lua-users.org/wiki/StringTrim +local function trim12(s) + local from = s:match"^%s*()" + return from > #s and "" or s:match(".*%S", from) +end + +local function reverse_geocode() + + if not df.check_if_bin_exists("curl") then + dt.print_error(_("curl not found")) + return + end + + if not df.check_if_bin_exists("jq") then + dt.print_error(_("jq not found")) + return + end + + local sel_images = dt.gui.selection() --action_images + + local lat1 = 0; + local lon1 = 0; + local i = 0; + + -- Use the first image with geo information + for _,image in ipairs(sel_images) do + if ((image.longitude and image.latitude) and + (image.longitude ~= 0 and image.latitude ~= 90) -- Sometimes the north-pole but most likely just wrong data + ) then + lat1 = string.gsub(image.latitude, ",", "."); + lon1 = string.gsub(image.longitude, ",", "."); + break + end + end + + local startCommand + + local tokan = dt.preferences.read("geoToolbox","mapBoxKey","string") + local types = "country"; + local types = "region"; + local types = "place"; + local types = "poi"; + + -- MapBox documentation + -- https://www.mapbox.com/api-documentation/#retrieve-places-near-a-location + -- curl -s, --silent Silent mode (don't output anything) + -- jq could be replaced with a Lua JSON parser + startCommand = string.format("curl --silent \"https://api.mapbox.com/geocoding/v5/mapbox.places/%s,%s.json?types=%s&access_token=%s\" | jq '.features | .[0] | '.text''", lon1, lat1, types, tokan) + + local handle = io.popen(startCommand) + local result = trim12(handle:read("*a")) + handle:close() + + -- Errorhandling would be nice + --dt.print_error("startCommand: "..startCommand) + --dt.print_error("result: '"..result.."'") + + if (result ~= "null") then + dt.print(string.sub(result, 2, string.len(result)-2)) + end + +end -- I used code from here: -- http://stackoverflow.com/questions/27928/how-do-i-calculate-distance-between-two-latitude-longitude-points @@ -433,6 +495,7 @@ local altitude_file_chooser_button = dt.new_widget("file_chooser_button") value = "", -- The currently selected file is_directory = true -- True if the file chooser button only allows directories to be selecte } + local altitude_filename = dt.new_widget("entry") { text = "altitude.csv", @@ -513,6 +576,7 @@ local separator = dt.new_widget("separator"){} local separator2 = dt.new_widget("separator"){} local separator3 = dt.new_widget("separator"){} local separator4 = dt.new_widget("separator"){} +local separator5 = dt.new_widget("separator"){} dt.register_lib( "geoToolbox", -- Module name @@ -582,6 +646,13 @@ dt.register_lib( clicked_callback = open_location_in_gnome_maps }, separator4,-------------------------------------------------------- + dt.new_widget("button") + { + label = _("reverse geocode"), + tooltip = _("This just shows the name of the location, but doesn't add it as tag"), + clicked_callback = reverse_geocode + }, + separator5,-------------------------------------------------------- dt.new_widget("label"){label = _("altitude CSV export")}, altitude_file_chooser_button, altitude_filename, @@ -597,6 +668,13 @@ dt.register_lib( nil -- view_leave ) +-- Preferences +dt.preferences.register("geoToolbox", + "mapBoxKey", + "string", + _("geoToolbox export: MapBox Key"), + _("https://www.mapbox.com/studio/account/tokens"), + '' ) -- Register dt.register_event("shortcut", print_calc_distance, _("Calculate the distance from latitude and longitude in km")) From 01fc339da531cb120741acea5ff5d3ec3de16778 Mon Sep 17 00:00:00 2001 From: supertobi Date: Thu, 27 Apr 2017 21:46:30 +0200 Subject: [PATCH 009/679] Update video_mencoder.lua use "lib/dtutils.file" and gettext --- contrib/video_mencoder.lua | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/contrib/video_mencoder.lua b/contrib/video_mencoder.lua index db095b58..e834f67f 100644 --- a/contrib/video_mencoder.lua +++ b/contrib/video_mencoder.lua @@ -31,38 +31,34 @@ USAGE ]] local dt = require "darktable" +local df = require "lib/dtutils.file" require "official/yield" +local gettext = dt.gettext dt.configuration.check_version(...,{2,0,1},{3,0,0},{4,0,0}) -local function show_status(storage, image, format, filename, number, total, high_quality, extra_data) - dt.print("Export Image "..tostring(number).."/"..tostring(total)) +-- 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 checkIfBinExists(bin) - local handle = io.popen("which "..bin) - local result = handle:read() - local ret - handle:close() - if (result) then - --dt.print_error("true checkIfBinExists: "..bin) - ret = true - else - dt.print_error(bin.." not found") - ret = false - end - - return ret +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) - if not checkIfBinExists("mencoder") then + if not df.check_if_bin_exists("mencoder") then + dt.print_error(_("mencoder not found")) return end - if not checkIfBinExists("xdg-open") then + if not df.check_if_bin_exists("xdg-open") then + dt.print_error(_("xdg-open not found")) return end - if not checkIfBinExists("xdg-user-dir") then + if not df.check_if_bin_exists("xdg-user-dir") then + dt.print_error(_("xdg-user-dir not found")) return end From dee7ee1dde0058ff492c80382b23901da227d333 Mon Sep 17 00:00:00 2001 From: supertobi Date: Thu, 27 Apr 2017 21:51:29 +0200 Subject: [PATCH 010/679] Update hugin.lua use "lib/dtutils.file" --- contrib/hugin.lua | 25 ++++--------------------- 1 file changed, 4 insertions(+), 21 deletions(-) diff --git a/contrib/hugin.lua b/contrib/hugin.lua index 5099b100..6ae1d12c 100644 --- a/contrib/hugin.lua +++ b/contrib/hugin.lua @@ -33,11 +33,11 @@ USAGE This plugin will add a new storage option and calls hugin after export. ]] +local gettext = dt.gettext local dt = require "darktable" +local df = require "lib/dtutils.file" require "official/yield" -local gettext = dt.gettext - -- works with darktable API version from 2.0.0 to 5.0.0 dt.configuration.check_version(...,{2,0,0},{3,0,0},{4,0,0},{5,0,0}) @@ -48,30 +48,13 @@ local function _(msgid) return gettext.dgettext("hugin", msgid) end -local function checkIfBinExists(bin) - local handle = io.popen("which "..bin) - local result = handle:read() - local ret - handle:close() - if (result) then - dt.print_error("true checkIfBinExists: "..bin) - ret = true - else - dt.print_error(bin.." not found") - ret = false - end - - - return ret -end - local function show_status(storage, image, format, filename, number, total, high_quality, extra_data) dt.print("Export to Hugin "..tostring(number).."/"..tostring(total)) end local function create_panorama(storage, image_table, extra_data) --finalize - if not checkIfBinExists("hugin") then + if not df.check_if_bin_exists("hugin") then dt.print_error(_("hugin not found")) return end @@ -82,7 +65,7 @@ local function create_panorama(storage, image_table, extra_data) --finalize -- http://hugin.sourceforge.net/docs/manual/Pto_gen.html local hugin_executor = false - if (checkIfBinExists("hugin_executor") and checkIfBinExists("pto_gen")) then + if (df.check_if_bin_exists("hugin_executor") and df.check_if_bin_exists("pto_gen")) then hugin_executor = true end From d46b7e4aafcaeaec6e9c0eb47323e4f266274933 Mon Sep 17 00:00:00 2001 From: supertobi Date: Thu, 27 Apr 2017 21:55:19 +0200 Subject: [PATCH 011/679] Update slideshowMusic.lua use "lib/dtutils.file" --- contrib/slideshowMusic.lua | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/contrib/slideshowMusic.lua b/contrib/slideshowMusic.lua index fff276c6..f96383d2 100644 --- a/contrib/slideshowMusic.lua +++ b/contrib/slideshowMusic.lua @@ -25,9 +25,10 @@ USAGE ]] local dt = require "darktable" +local df = require "lib/dtutils.file" require "official/yield" - local gettext = dt.gettext + dt.configuration.check_version(...,{2,0,2},{3,0,0},{4,0,0}) -- Tell gettext where to find the .mo file translating messages for a particular domain @@ -37,26 +38,14 @@ local function _(msgid) return gettext.dgettext("slideshowMusic", msgid) end -local function checkIfBinExists(bin) - local handle = io.popen("which "..bin) - local result = handle:read() - local ret - handle:close() - if (not result) then - dt.print_error(bin.." not found") - ret = false - end - ret = true - return ret -end - local function playSlideshowMusic(_, old_view, new_view) local filename, playMusic filename = dt.preferences.read("slideshowMusic","SlideshowMusic","string") playMusic = dt.preferences.read("slideshowMusic","PlaySlideshowMusic","bool") - if not checkIfBinExists("rhythmbox-client") then + if not df.check_if_bin_exists("rhythmbox-client") then + dt.print_error(_("rhythmbox-client not found")) return end From 2562a218a08b5c6feece123ae85f21575cf7dab2 Mon Sep 17 00:00:00 2001 From: supertobi Date: Thu, 27 Apr 2017 22:04:15 +0200 Subject: [PATCH 012/679] Update kml_export.lua use "lib/dtutils.file" --- contrib/kml_export.lua | 31 ++++++++++++------------------- 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/contrib/kml_export.lua b/contrib/kml_export.lua index 569bc4d1..f9e92f8b 100644 --- a/contrib/kml_export.lua +++ b/contrib/kml_export.lua @@ -37,9 +37,10 @@ USAGE ]] local dt = require "darktable" +local df = require "lib/dtutils.file" require "official/yield" - local gettext = dt.gettext + dt.configuration.check_version(...,{3,0,0},{4,0,0}) -- Tell gettext where to find the .mo file translating messages for a particular domain @@ -77,19 +78,6 @@ local function show_status(storage, image, format, filename, number, total, high dt.print(string.format(_("Export Image %i/%i"), number, total)) end -local function checkIfBinExists(bin) - local handle = io.popen("which "..bin) - local result = handle:read() - local ret - handle:close() - if (not result) then - dt.print_error(bin.." not found") - ret = false - end - ret = true - return ret -end - -- Strip accents from a string -- Copied from https://forums.coronalabs.com/topic/43048-remove-special-characters-from-string/ function string.stripAccents( str ) @@ -176,16 +164,20 @@ end local function create_kml_file(storage, image_table, extra_data) - if not checkIfBinExists("mkdir") then + if not df.check_if_bin_exists("mkdir") then + dt.print_error(_("mkdir not found")) return end - if not checkIfBinExists("convert") then + if not df.check_if_bin_exists("convert") then + dt.print_error(_("convert not found")) return end - if not checkIfBinExists("xdg-open") then + if not df.check_if_bin_exists("xdg-open"") then + dt.print_error(_("xdg-open" not found")) return end - if not checkIfBinExists("xdg-user-dir") then + if not df.check_if_bin_exists("xdg-user-dir") then + dt.print_error(_("xdg-user-dir not found")) return end @@ -193,7 +185,8 @@ local function create_kml_file(storage, image_table, extra_data) local imageFoldername if ( dt.preferences.read("kml_export","CreateKMZ","bool") == true ) then - if not checkIfBinExists("zip") then + if not df.check_if_bin_exists("zip") then + dt.print_error(_("zip not found")) return end From bff2df018bf5fc95f05ecd3705609c723525c2aa Mon Sep 17 00:00:00 2001 From: supertobi Date: Thu, 27 Apr 2017 22:07:23 +0200 Subject: [PATCH 013/679] Update enfuse.lua use "lib/dtutils.file" --- official/enfuse.lua | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/official/enfuse.lua b/official/enfuse.lua index 61b8c695..d6ded05f 100644 --- a/official/enfuse.lua +++ b/official/enfuse.lua @@ -33,30 +33,22 @@ TODO ]] local dt = require "darktable" +local df = require "lib/dtutils.file" require "official/yield" - +local gettext = dt.gettext dt.configuration.check_version(...,{3,0,0},{4,0,0}) --- thanks Tobias Jakobs for this function (taken from contrib/hugin.lua) -local function checkIfBinExists(bin) - local handle = io.popen("which "..bin) - local result = handle:read() - local ret - handle:close() - if (result) then - dt.print_error("true checkIfBinExists: "..bin) - ret = true - else - dt.print_error(bin.." not found") - ret = false - end - return ret +-- Tell gettext where to find the .mo file translating messages for a particular domain +gettext.bindtextdomain("enfuse",dt.configuration.config_dir.."/lua/locale/") + +local function _(msgid) + return gettext.dgettext("enfuse", msgid) end -- add a new lib -- is enfuse installed? -local enfuse_installed = checkIfBinExists("enfuse") +local enfuse_installed = df.check_if_bin_exists("enfuse") -- initialize exposure_mu value and depth setting in config to sane defaults (would be 0 otherwise) if dt.preferences.read("enfuse", "depth", "integer") == 0 then From 79511d9b42b7f25982435360d3d89f3c400d5c8d Mon Sep 17 00:00:00 2001 From: supertobi Date: Thu, 27 Apr 2017 22:12:34 +0200 Subject: [PATCH 014/679] Update geoJSON_export.lua use "lib/dtutils.file" --- contrib/geoJSON_export.lua | 29 ++++++++++------------------- 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/contrib/geoJSON_export.lua b/contrib/geoJSON_export.lua index 7ae81598..90bb16f8 100644 --- a/contrib/geoJSON_export.lua +++ b/contrib/geoJSON_export.lua @@ -33,9 +33,10 @@ USAGE ]] local dt = require "darktable" +local df = require "lib/dtutils.file" require "official/yield" - local gettext = dt.gettext + dt.configuration.check_version(...,{3,0,0},{4,0,0}) -- Tell gettext where to find the .mo file translating messages for a particular domain @@ -73,31 +74,21 @@ local function show_status(storage, image, format, filename, number, total, high dt.print(string.format(_("Export Image %i/%i"), number, total)) end -local function checkIfBinExists(bin) - local handle = io.popen("which "..bin) - local result = handle:read() - local ret - handle:close() - if (not result) then - dt.print_error(bin.." not found") - ret = false - end - ret = true - return ret -end - local function create_geoJSON_file(storage, image_table, extra_data) - - if not checkIfBinExists("mkdir") then + if not df.check_if_bin_exists("mkdir") then + dt.print_error(_("mkdir not found")) return end - if not checkIfBinExists("convert") then + if not df.check_if_bin_exists("convert") then + dt.print_error(_("convert not found")) return end - if not checkIfBinExists("xdg-open") then + if not df.check_if_bin_exists("xdg-open") then + dt.print_error(_("xdg-open not found")) return end - if not checkIfBinExists("xdg-user-dir") then + if not df.check_if_bin_exists("xdg-user-dir") then + dt.print_error(_("xdg-user-dir not found")) return end From 356756286e07f369147904492b9f16b9df7045c6 Mon Sep 17 00:00:00 2001 From: supertobi Date: Thu, 27 Apr 2017 22:19:00 +0200 Subject: [PATCH 015/679] Update gimp.lua use "lib/dtutils.file" --- contrib/gimp.lua | 23 ++++------------------- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/contrib/gimp.lua b/contrib/gimp.lua index 13a31c6b..f8472c75 100644 --- a/contrib/gimp.lua +++ b/contrib/gimp.lua @@ -64,8 +64,8 @@ ]] local dt = require "darktable" +local df = require "lib/dtutils.file" require "official/yield" - local gettext = dt.gettext dt.configuration.check_version(...,{3,0,0},{4,0,0},{5,0,0}) @@ -104,21 +104,6 @@ local function _(msgid) return gettext.dgettext("gimp", msgid) end -local function checkIfBinExists(bin) - local handle = io.popen("which "..bin) - local result = handle:read() - local ret - handle:close() - if (result) then - dt.print_error("true checkIfBinExists: "..bin) - ret = true - else - dt.print_error(bin.." not found") - ret = false - end - return ret -end - -- Thanks Tobias Jakobs for the idea and the correction function checkIfFileExists(filepath) local file = io.open(filepath,"r") @@ -199,7 +184,7 @@ end local function fileCopy(fromFile, toFile) local result = nil -- if cp exists, use it - if checkIfBinExists("cp") then + if df.check_if_bin_exists("cp") then result = os.execute("cp '" .. fromFile .. "' '" .. toFile .. "'") end -- if cp was not present, or if cp failed, then a pure lua solution @@ -230,7 +215,7 @@ local function fileMove(fromFile, toFile) local success = os.rename(fromFile, toFile) if not success then -- an error occurred, so let's try using the operating system function - if checkIfBinExists("mv") then + if df.check_if_bin_exists("mv") then success = os.execute("mv '" .. fromFile .. "' '" .. toFile .. "'") end -- if the mv didn't exist or succeed, then... @@ -249,7 +234,7 @@ local function fileMove(fromFile, toFile) end local function gimp_edit(storage, image_table, extra_data) --finalize - if not checkIfBinExists("gimp") then + if not df.check_if_bin_exists("gimp") then dt.print_error(_("GIMP not found")) return end From dcc205ec4fa3c57c9491cb160fa7e85efbbd622c Mon Sep 17 00:00:00 2001 From: supertobi Date: Sat, 29 Apr 2017 08:05:19 +0200 Subject: [PATCH 016/679] Update kml_export.lua check_version 5 --- contrib/kml_export.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/kml_export.lua b/contrib/kml_export.lua index f9e92f8b..1684d209 100644 --- a/contrib/kml_export.lua +++ b/contrib/kml_export.lua @@ -41,7 +41,7 @@ local df = require "lib/dtutils.file" require "official/yield" local gettext = dt.gettext -dt.configuration.check_version(...,{3,0,0},{4,0,0}) +dt.configuration.check_version(...,{3,0,0},{4,0,0},{5,0,0}) -- Tell gettext where to find the .mo file translating messages for a particular domain gettext.bindtextdomain("kml_export",dt.configuration.config_dir.."/lua/locale/") From 750d70bfffc88ad48d587e7c0bd30270b924b440 Mon Sep 17 00:00:00 2001 From: supertobi Date: Sat, 29 Apr 2017 08:06:15 +0200 Subject: [PATCH 017/679] Update geoJSON_export.lua check_version 5 --- contrib/geoJSON_export.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/geoJSON_export.lua b/contrib/geoJSON_export.lua index 90bb16f8..95b39763 100644 --- a/contrib/geoJSON_export.lua +++ b/contrib/geoJSON_export.lua @@ -37,7 +37,7 @@ local df = require "lib/dtutils.file" require "official/yield" local gettext = dt.gettext -dt.configuration.check_version(...,{3,0,0},{4,0,0}) +dt.configuration.check_version(...,{3,0,0},{4,0,0},{5,0,0}) -- Tell gettext where to find the .mo file translating messages for a particular domain gettext.bindtextdomain("geoJSON_export",dt.configuration.config_dir.."/lua/locale/") From d555cb2c94770936d4887513f1db83e47ebdc904 Mon Sep 17 00:00:00 2001 From: supertobi Date: Sat, 29 Apr 2017 09:03:43 +0200 Subject: [PATCH 018/679] Update geoJSON_export.lua cleanup --- contrib/geoJSON_export.lua | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/contrib/geoJSON_export.lua b/contrib/geoJSON_export.lua index 95b39763..38f4be08 100644 --- a/contrib/geoJSON_export.lua +++ b/contrib/geoJSON_export.lua @@ -94,7 +94,7 @@ local function create_geoJSON_file(storage, image_table, extra_data) dt.print_error("Will try to export geoJSON file now") - local xportDirectory = dt.preferences.read("geoJSON_export","ExportDirectory","string") + local exportDirectory = dt.preferences.read("geoJSON_export","ExportDirectory","string") -- Creates dir if not exsists local imageFoldername = "files/" @@ -106,8 +106,8 @@ local function create_geoJSON_file(storage, image_table, extra_data) if ((image.longitude and image.latitude) and (image.longitude ~= 0 and image.latitude ~= 90) -- Sometimes the north-pole but most likely just wrong data ) then - local path, filename, filetype = string.match(image, "(.-)([^\\/]-%.?([^%.\\/]*))$") - filename = string.upper(string.gsub(filename,"%.", "_")) + local path, filename, filetype = string.match(exported_image, "(.-)([^\\/]-%.?([^%.\\/]*))$") + filename = string.upper(string.gsub(filename,"%.%w*", "")) -- convert -size 92x92 filename.jpg -resize 92x92 +profile "*" thumbnail.jpg -- In this example, '-size 120x120' gives a hint to the JPEG decoder that the image is going to be downscaled to @@ -123,7 +123,7 @@ local function create_geoJSON_file(storage, image_table, extra_data) end -- delete the original image to not get into the kmz file - os.remove(image) + os.remove(exported_image) local pattern = "[/]?([^/]+)$" filmName = string.match(image.film.path, pattern) @@ -140,11 +140,24 @@ local function create_geoJSON_file(storage, image_table, extra_data) ]] for image,exported_image in pairs(image_table) do - filename = string.upper(string.gsub(image.filename,"%.", "_")) + --filename = string.upper(string.gsub(image.filename,"%.", "_")) + -- Extract filename, e.g DSC9784.ARW -> DSC9784 + filename = string.upper(string.gsub(image.filename,"%.%w*", "")) + -- Extract extension from exported image (user can choose JPG or PNG), e.g DSC9784.JPG -> .JPG + extension = string.match(exported_image,"%.%w*$") if ((image.longitude and image.latitude) and (image.longitude ~= 0 and image.latitude ~= 90) -- Sometimes the north-pole but most likely just wrong data ) then + + local image_title, image_description + if (image.title and image.title ~= "") then + image_title = image.title + else + image_title = image.filename + end + image_description = image.description + geoJSON_file = geoJSON_file.. [[ { "type": "Feature", @@ -155,8 +168,8 @@ local function create_geoJSON_file(storage, image_table, extra_data) geoJSON_file = geoJSON_file.. [[ }, "properties": { - "title": "]]..image.title..[[", - "description": "]]..image.description..[[", + "title": "]]..image_title..[[", + "description": "]]..image_description..[[", "image": "]]..imageFoldername..filename..[[.jpg", "icon": { "iconUrl": "]]..imageFoldername.."thumb_"..filename..[[.jpg", @@ -187,7 +200,7 @@ local function create_geoJSON_file(storage, image_table, extra_data) - 2014-05-31 Rieselfelder + ]]..filmName..[[ \n" - - kml_file = kml_file.." \n" - kml_file = kml_file.." \n" - - for image,exported_image in spairs(image_table, function(t,a,b) return b.exif_datetime_taken > a.exif_datetime_taken end) do - if ((image.longitude and image.latitude) and - (image.longitude ~= 0 and image.latitude ~= 90) -- Sometimes the north-pole but most likely just wrong data - ) then - local altitude = 0; - if (image.elevation) then - altitude = image.elevation; - end - kml_file = kml_file.." "..string.gsub(tostring(image.longitude),",", ".")..","..string.gsub(tostring(image.latitude),",", ".")..",altitude\n" - end - end - kml_file = kml_file.." \n" - kml_file = kml_file.." \n" - - kml_file = kml_file.." \n" + kml_file = kml_file.." \n" + kml_file = kml_file.." Path\n" -- ToDo: I think a better name would be nice + --kml_file = kml_file.." \n" + + kml_file = kml_file.." \n" + + kml_file = kml_file.." \n" + kml_file = kml_file.." \n" + + for image,exported_image in spairs(image_table, function(t,a,b) return b.exif_datetime_taken > a.exif_datetime_taken end) do + if ((image.longitude and image.latitude) and + (image.longitude ~= 0 and image.latitude ~= 90) -- Sometimes the north-pole but most likely just wrong data + ) then + local altitude = 0; + if (image.elevation) then + altitude = image.elevation; + end + + kml_file = kml_file.." "..string.gsub(tostring(image.longitude),",", ".")..","..string.gsub(tostring(image.latitude),",", ".")..",altitude\n" + end + end + + kml_file = kml_file.." \n" + kml_file = kml_file.." \n" + + kml_file = kml_file.." \n" end kml_file = kml_file.."\n" @@ -399,77 +399,79 @@ local function create_kml_file(storage, image_table, extra_data) dt.print("KML file created in "..exportDirectory) --- Compress the files to create a KMZ file + -- Compress the files to create a KMZ file if ( dt.preferences.read("kml_export","CreateKMZ","bool") == true ) then - exportDirectory = dt.preferences.read("kml_export","ExportDirectory","string") + exportDirectory = dt.preferences.read("kml_export","ExportDirectory","string") local createKMZCommand = "zip --test --move --junk-paths " createKMZCommand = createKMZCommand .."\""..exportDirectory.."/"..exportKMZFilename.."\" " -- KMZ filename createKMZCommand = createKMZCommand .."\""..dt.configuration.tmp_dir.."/"..exportKMLFilename.."\" " -- KML file for image,exported_image in pairs(image_table) do - if ((image.longitude and image.latitude) and - (image.longitude ~= 0 and image.latitude ~= 90) -- Sometimes the north-pole but most likely just wrong data - ) then - local filename = string.upper(string.gsub(image.filename,"%.%w*", "")) - -- Handle duplicates - filename = addDuplicateIndex( image.duplicate_index, filename ) - createKMZCommand = createKMZCommand .."\""..dt.configuration.tmp_dir.."/"..imageFoldername.."thumb_"..filename..".jpg\" " -- thumbnails - createKMZCommand = createKMZCommand .."\""..exported_image.."\" " -- images - end + if ((image.longitude and image.latitude) and + (image.longitude ~= 0 and image.latitude ~= 90) -- Sometimes the north-pole but most likely just wrong data + ) then + local filename = string.upper(string.gsub(image.filename,"%.%w*", "")) + -- Handle duplicates + filename = addDuplicateIndex( image.duplicate_index, filename ) + + createKMZCommand = createKMZCommand .."\""..dt.configuration.tmp_dir.."/"..imageFoldername.."thumb_"..filename..".jpg\" " -- thumbnails + createKMZCommand = createKMZCommand .."\""..exported_image.."\" " -- images + end end - dt.control.execute(createKMZCommand) + dt.control.execute(createKMZCommand) end --- Open the file with the standard programm + -- Open the file with the standard programm if ( dt.preferences.read("kml_export","OpenKmlFile","bool") == true ) then - local kmlFileOpenCommand + local kmlFileOpenCommand if ( dt.preferences.read("kml_export","CreateKMZ","bool") == true ) then kmlFileOpenCommand = "xdg-open "..exportDirectory.."/\""..exportKMZFilename.."\"" else kmlFileOpenCommand = "xdg-open "..exportDirectory.."/\""..exportKMLFilename.."\"" - end + end dt.control.execute(kmlFileOpenCommand) end - end -- Preferences dt.preferences.register("kml_export", - "OpenKmlFile", - "bool", - _("KML export: Open KML/KMZ file after export"), - _("Opens the KML file after the export with the standard program for KML files"), - false ) + "OpenKmlFile", + "bool", + _("KML export: Open KML/KMZ file after export"), + _("Opens the KML file after the export with the standard program for KML files"), + false ) local handle = io.popen("xdg-user-dir DESKTOP") local result = handle:read() if (result == nil) then - result = "" + result = "" end handle:close() + dt.preferences.register("kml_export", - "ExportDirectory", - "directory", - _("KML export: Export directory"), - _("A directory that will be used to export the KML/KMZ files"), - result ) + "ExportDirectory", + "directory", + _("KML export: Export directory"), + _("A directory that will be used to export the KML/KMZ files"), + result ) dt.preferences.register("kml_export", - "CreatePath", - "bool", - _("KML export: Connect images with path"), - _("connect all images with a path"), - false ) + "CreatePath", + "bool", + _("KML export: Connect images with path"), + _("connect all images with a path"), + false ) + dt.preferences.register("kml_export", - "CreateKMZ", - "bool", - _("KML export: Create KMZ file"), - _("Compress all imeges to one KMZ file"), - true ) + "CreateKMZ", + "bool", + _("KML export: Create KMZ file"), + _("Compress all imeges to one KMZ file"), + true ) -- Register dt.register_storage("kml_export", _("KML/KMZ Export"), nil, create_kml_file) From f86b16735b3d4aa3d1a283dc0028f795832af994 Mon Sep 17 00:00:00 2001 From: Elman Date: Mon, 15 Jan 2018 22:54:22 +0100 Subject: [PATCH 070/679] Formatted code to follow project settings --- contrib/kml_export.lua | 739 +++++++++++++++++++++-------------------- 1 file changed, 371 insertions(+), 368 deletions(-) diff --git a/contrib/kml_export.lua b/contrib/kml_export.lua index 58e0a15a..070a02fa 100644 --- a/contrib/kml_export.lua +++ b/contrib/kml_export.lua @@ -1,20 +1,20 @@ --[[ - This file is part of darktable, - Copyright 2018 by Tobias Jakobs. - Copyright 2018 by Erik Augustin. - - 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 . + This file is part of darktable, + Copyright 2018 by Tobias Jakobs. + Copyright 2018 by Erik Augustin. + + 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 KML export script @@ -47,155 +47,155 @@ dt.configuration.check_version(...,{3,0,0},{4,0,0},{5,0,0}) gettext.bindtextdomain("kml_export",dt.configuration.config_dir.."/lua/locale/") local function _(msgid) - return gettext.dgettext("kml_export", msgid) + return gettext.dgettext("kml_export", msgid) end -- Sort a table local function spairs(_table, order) -- Code copied from http://stackoverflow.com/questions/15706270/sort-a-table-in-lua - -- collect the keys - local keys = {} - for _key in pairs(_table) do keys[#keys + 1] = _key end - - -- if order function given, sort by it by passing the table and keys a, b, - -- otherwise just sort the keys - if order then - table.sort(keys, function(a,b) return order(_table, a, b) end) - else - table.sort(keys) - end - - -- return the iterator function - local i = 0 - return function() - i = i + 1 - if keys[i] then - return keys[i], _table[keys[i]] - end + -- collect the keys + local keys = {} + for _key in pairs(_table) do keys[#keys + 1] = _key end + + -- if order function given, sort by it by passing the table and keys a, b, + -- otherwise just sort the keys + if order then + table.sort(keys, function(a,b) return order(_table, a, b) end) + else + table.sort(keys) + end + + -- return the iterator function + local i = 0 + return function() + i = i + 1 + if keys[i] then + return keys[i], _table[keys[i]] end + 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)) + dt.print(string.format(_("Export Image %i/%i"), number, total)) end -- Strip accents from a string -- Copied from https://forums.coronalabs.com/topic/43048-remove-special-characters-from-string/ function string.stripAccents( str ) - local tableAccents = {} - -- A - tableAccents["à"] = "a" - tableAccents["À"] = "A" - tableAccents["á"] = "a" - tableAccents["Á"] = "A" - tableAccents["â"] = "a" - tableAccents["Â"] = "A" - tableAccents["ã"] = "a" - tableAccents["Ã"] = "A" - tableAccents["ä"] = "a" - tableAccents["Ä"] = "A" - -- B - -- C - tableAccents["ç"] = "c" - tableAccents["Ç"] = "C" - tableAccents["č"] = "c" - tableAccents["Č"] = "C" - -- D - tableAccents["ď"] = "d" - tableAccents["Ď"] = "d" - -- E - tableAccents["è"] = "e" - tableAccents["È"] = "E" - tableAccents["é"] = "e" - tableAccents["É"] = "E" - tableAccents["ê"] = "e" - tableAccents["Ê"] = "E" - tableAccents["ë"] = "e" - tableAccents["Ë"] = "E" - tableAccents["ě"] = "e" - tableAccents["Ě"] = "E" - -- F - -- G - -- H - -- I - tableAccents["ì"] = "i" - tableAccents["Ì"] = "I" - tableAccents["í"] = "i" - tableAccents["Í"] = "I" - tableAccents["î"] = "i" - tableAccents["Î"] = "I" - tableAccents["ï"] = "i" - tableAccents["Ï"] = "I" - -- J - -- K - -- L - tableAccents["ĺ"] = "l" - tableAccents["Ĺ"] = "L" - tableAccents["ľ"] = "l" - tableAccents["Ľ"] = "L" - -- M - -- N - tableAccents["ñ"] = "n" - tableAccents["Ñ"] = "N" - tableAccents["ň"] = "n" - tableAccents["Ň"] = "N" - -- O - tableAccents["ò"] = "o" - tableAccents["Ò"] = "O" - tableAccents["ó"] = "o" - tableAccents["Ó"] = "O" - tableAccents["ô"] = "o" - tableAccents["Ô"] = "O" - tableAccents["õ"] = "o" - tableAccents["Õ"] = "O" - tableAccents["ö"] = "o" - tableAccents["Ö"] = "O" - -- P - -- Q - -- R - tableAccents["ŕ"] = "r" - tableAccents["Ŕ"] = "R" - tableAccents["ř"] = "r" - tableAccents["Ř"] = "R" - -- S - tableAccents["š"] = "s" - tableAccents["Š"] = "S" - -- T - tableAccents["ť"] = "t" - tableAccents["Ť"] = "T" - -- U - tableAccents["ù"] = "u" - tableAccents["Ù"] = "U" - tableAccents["ú"] = "u" - tableAccents["Ú"] = "U" - tableAccents["û"] = "u" - tableAccents["Û"] = "U" - tableAccents["ü"] = "u" - tableAccents["Ü"] = "U" - tableAccents["ů"] = "u" - tableAccents["Ů"] = "U" - -- V - -- W - -- X - -- Y - tableAccents["ý"] = "y" - tableAccents["Ý"] = "Y" - tableAccents["ÿ"] = "y" - tableAccents["Ÿ"] = "Y" - -- Z - tableAccents["ž"] = "z" - tableAccents["Ž"] = "Z" - - local normalizedString = "" - - for strChar in string.gmatch(str, "([%z\1-\127\194-\244][\128-\191]*)") do - if tableAccents[strChar] ~= nil then - normalizedString = normalizedString..tableAccents[strChar] - else - normalizedString = normalizedString..strChar - end + local tableAccents = {} + -- A + tableAccents["à"] = "a" + tableAccents["À"] = "A" + tableAccents["á"] = "a" + tableAccents["Á"] = "A" + tableAccents["â"] = "a" + tableAccents["Â"] = "A" + tableAccents["ã"] = "a" + tableAccents["Ã"] = "A" + tableAccents["ä"] = "a" + tableAccents["Ä"] = "A" + -- B + -- C + tableAccents["ç"] = "c" + tableAccents["Ç"] = "C" + tableAccents["č"] = "c" + tableAccents["Č"] = "C" + -- D + tableAccents["ď"] = "d" + tableAccents["Ď"] = "d" + -- E + tableAccents["è"] = "e" + tableAccents["È"] = "E" + tableAccents["é"] = "e" + tableAccents["É"] = "E" + tableAccents["ê"] = "e" + tableAccents["Ê"] = "E" + tableAccents["ë"] = "e" + tableAccents["Ë"] = "E" + tableAccents["ě"] = "e" + tableAccents["Ě"] = "E" + -- F + -- G + -- H + -- I + tableAccents["ì"] = "i" + tableAccents["Ì"] = "I" + tableAccents["í"] = "i" + tableAccents["Í"] = "I" + tableAccents["î"] = "i" + tableAccents["Î"] = "I" + tableAccents["ï"] = "i" + tableAccents["Ï"] = "I" + -- J + -- K + -- L + tableAccents["ĺ"] = "l" + tableAccents["Ĺ"] = "L" + tableAccents["ľ"] = "l" + tableAccents["Ľ"] = "L" + -- M + -- N + tableAccents["ñ"] = "n" + tableAccents["Ñ"] = "N" + tableAccents["ň"] = "n" + tableAccents["Ň"] = "N" + -- O + tableAccents["ò"] = "o" + tableAccents["Ò"] = "O" + tableAccents["ó"] = "o" + tableAccents["Ó"] = "O" + tableAccents["ô"] = "o" + tableAccents["Ô"] = "O" + tableAccents["õ"] = "o" + tableAccents["Õ"] = "O" + tableAccents["ö"] = "o" + tableAccents["Ö"] = "O" + -- P + -- Q + -- R + tableAccents["ŕ"] = "r" + tableAccents["Ŕ"] = "R" + tableAccents["ř"] = "r" + tableAccents["Ř"] = "R" + -- S + tableAccents["š"] = "s" + tableAccents["Š"] = "S" + -- T + tableAccents["ť"] = "t" + tableAccents["Ť"] = "T" + -- U + tableAccents["ù"] = "u" + tableAccents["Ù"] = "U" + tableAccents["ú"] = "u" + tableAccents["Ú"] = "U" + tableAccents["û"] = "u" + tableAccents["Û"] = "U" + tableAccents["ü"] = "u" + tableAccents["Ü"] = "U" + tableAccents["ů"] = "u" + tableAccents["Ů"] = "U" + -- V + -- W + -- X + -- Y + tableAccents["ý"] = "y" + tableAccents["Ý"] = "Y" + tableAccents["ÿ"] = "y" + tableAccents["Ÿ"] = "Y" + -- Z + tableAccents["ž"] = "z" + tableAccents["Ž"] = "Z" + + local normalizedString = "" + + for strChar in string.gmatch(str, "([%z\1-\127\194-\244][\128-\191]*)") do + if tableAccents[strChar] ~= nil then + normalizedString = normalizedString..tableAccents[strChar] + else + normalizedString = normalizedString..strChar end + end - return normalizedString + return normalizedString end -- Escape XML characters @@ -203,275 +203,278 @@ end -- https://stackoverflow.com/questions/1091945/what-characters-do-i-need-to-escape-in-xml-documents function string.escapeXmlCharacters( str ) - str = string.gsub(str,"&", "&") - str = string.gsub(str,"\"", """) - str = string.gsub(str,"'", "'") - str = string.gsub(str,"<", "<") - str = string.gsub(str,">", ">") + str = string.gsub(str,"&", "&") + str = string.gsub(str,"\"", """) + str = string.gsub(str,"'", "'") + str = string.gsub(str,"<", "<") + str = string.gsub(str,">", ">") - return str + return str end -- Add duplicate index to filename -- image.filename does not have index, exported_image has index function addDuplicateIndex( index, filename ) - if index > 0 then - filename = filename.."_" - if index < 10 then - filename = filename.."0" - end - filename = filename..index + if index > 0 then + filename = filename.."_" + if index < 10 then + filename = filename.."0" end + filename = filename..index + end - return filename + return filename end local function create_kml_file(storage, image_table, extra_data) - if not df.check_if_bin_exists("mkdir") then - dt.print_error(_("mkdir not found")) - return - end - if not df.check_if_bin_exists("convert") then - dt.print_error(_("convert not found")) - return - end - if not df.check_if_bin_exists("xdg-open") then - dt.print_error(_("xdg-open not found")) - return - end - if not df.check_if_bin_exists("xdg-user-dir") then - dt.print_error(_("xdg-user-dir not found")) - return + if not df.check_if_bin_exists("mkdir") then + dt.print_error(_("mkdir not found")) + return + end + if not df.check_if_bin_exists("convert") then + dt.print_error(_("convert not found")) + return + end + if not df.check_if_bin_exists("xdg-open") then + dt.print_error(_("xdg-open not found")) + return + end + if not df.check_if_bin_exists("xdg-user-dir") then + dt.print_error(_("xdg-user-dir not found")) + return + end + + dt.print_error("Will try to export KML file now") + + local imageFoldername + if ( dt.preferences.read("kml_export","CreateKMZ","bool") == true ) then + if not df.check_if_bin_exists("zip") then + dt.print_error(_("zip not found")) + return end - dt.print_log("Will try to export KML file now") + exportDirectory = dt.configuration.tmp_dir + imageFoldername = "" + else + exportDirectory = dt.preferences.read("kml_export","ExportDirectory","string") + + -- Creates dir if not exsists + imageFoldername = "files/" + local mkdirCommand = "mkdir -p "..exportDirectory.."/"..imageFoldername + dt.control.execute(mkdirCommand) + end + + -- Create the thumbnails + for image,exported_image in pairs(image_table) do + if ((image.longitude and image.latitude) and + (image.longitude ~= 0 and image.latitude ~= 90) -- Sometimes the north-pole but most likely just wrong data + ) then + local path, filename, filetype = string.match(exported_image, "(.-)([^\\/]-%.?([^%.\\/]*))$") + filename = string.upper(string.gsub(filename,"%.%w*", "")) + + -- convert -size 92x92 filename.jpg -resize 92x92 +profile "*" thumbnail.jpg + -- In this example, '-size 120x120' gives a hint to the JPEG decoder that the image is going to be downscaled to + -- 120x120, allowing it to run faster by avoiding returning full-resolution images to GraphicsMagick for the + -- subsequent resizing operation. The '-resize 120x120' specifies the desired dimensions of the output image. It + -- will be scaled so its largest dimension is 120 pixels. The '+profile "*"' removes any ICM, EXIF, IPTC, or other + -- profiles that might be present in the input and aren't needed in the thumbnail. + + local convertToThumbCommand = "convert -size 96x96 "..exported_image.." -resize 92x92 -mattecolor \"#FFFFFF\" -frame 2x2 +profile \"*\" "..exportDirectory.."/"..imageFoldername.."thumb_"..filename..".jpg" + dt.control.execute(convertToThumbCommand) + else + -- Remove exported image if it has no GPS data + os.remove(exported_image) + end - local imageFoldername - if ( dt.preferences.read("kml_export","CreateKMZ","bool") == true ) then - if not df.check_if_bin_exists("zip") then - dt.print_error(_("zip not found")) - return + local pattern = "[/]?([^/]+)$" + filmName = string.match(image.film.path, pattern) + + -- Strip accents from the filename, because GoogleEarth can't open them + -- https://github.com/darktable-org/lua-scripts/issues/54 + filmName = string.stripAccents(filmName) + end + + exportKMLFilename = filmName..".kml" + exportKMZFilename = filmName..".kmz" + + -- Create the KML file + local kml_file = "\n" + kml_file = kml_file.."\n" + kml_file = kml_file.."\n" + + --image_table = dt.gui.selection(); + kml_file = kml_file..""..filmName.."\n" + kml_file = kml_file.." Exported from darktable\n" + + for image,exported_image in pairs(image_table) do + -- Extract filename, e.g DSC9784.ARW -> DSC9784 + filename = string.upper(string.gsub(image.filename,"%.%w*", "")) + -- Handle duplicates + filename = addDuplicateIndex( image.duplicate_index, filename ) + -- Extract extension from exported image (user can choose JPG or PNG), e.g DSC9784.JPG -> .JPG + extension = string.match(exported_image,"%.%w*$") + + if ((image.longitude and image.latitude) and + (image.longitude ~= 0 and image.latitude ~= 90) -- Sometimes the north-pole but most likely just wrong data + ) then + kml_file = kml_file.." \n" + + local image_title, image_description + if (image.title and image.title ~= "") then + image_title = string.escapeXmlCharacters(image.title) + else + image_title = filename..extension + end + -- Characters should not be escaped in CDATA, but we are using HTML fragment, so we must escape them + image_description = string.escapeXmlCharacters(image.description) + + kml_file = kml_file.." "..image_title.."\n" + kml_file = kml_file.." "..image_description.."\n" + kml_file = kml_file.." \n" + + kml_file = kml_file.." \n" + kml_file = kml_file.." 1\n" + kml_file = kml_file.." "..string.gsub(tostring(image.longitude),",", ".")..","..string.gsub(tostring(image.latitude),",", ".")..",0\n" + kml_file = kml_file.." \n" + kml_file = kml_file.." "..string.gsub(image.exif_datetime_taken," ", "T").."Z".."\n" + kml_file = kml_file.." \n" + kml_file = kml_file.." \n" + + kml_file = kml_file.." \n" + end + end + + -- Connects all images with an path + if ( dt.preferences.read("kml_export","CreatePath","bool") == true ) then + kml_file = kml_file.." \n" + kml_file = kml_file.." Path\n" -- ToDo: I think a better name would be nice + --kml_file = kml_file.." \n" + + kml_file = kml_file.." \n" + + kml_file = kml_file.." \n" + kml_file = kml_file.." \n" + + for image,exported_image in spairs(image_table, function(t,a,b) return b.exif_datetime_taken > a.exif_datetime_taken end) do + if ((image.longitude and image.latitude) and + (image.longitude ~= 0 and image.latitude ~= 90) -- Sometimes the north-pole but most likely just wrong data + ) then + local altitude = 0; + if (image.elevation) then + altitude = image.elevation; end - exportDirectory = dt.configuration.tmp_dir - imageFoldername = "" - else - exportDirectory = dt.preferences.read("kml_export","ExportDirectory","string") - - -- Creates dir if not exsists - imageFoldername = "files/" - local mkdirCommand = "mkdir -p "..exportDirectory.."/"..imageFoldername - dt.control.execute(mkdirCommand) + kml_file = kml_file.." "..string.gsub(tostring(image.longitude),",", ".")..","..string.gsub(tostring(image.latitude),",", ".")..",altitude\n" + end end - -- Create the thumbnails - for image,exported_image in pairs(image_table) do - if ((image.longitude and image.latitude) and - (image.longitude ~= 0 and image.latitude ~= 90) -- Sometimes the north-pole but most likely just wrong data - ) then - local path, filename, filetype = string.match(exported_image, "(.-)([^\\/]-%.?([^%.\\/]*))$") - filename = string.upper(string.gsub(filename,"%.%w*", "")) - - -- convert -size 92x92 filename.jpg -resize 92x92 +profile "*" thumbnail.jpg - -- In this example, '-size 120x120' gives a hint to the JPEG decoder that the image is going to be downscaled to - -- 120x120, allowing it to run faster by avoiding returning full-resolution images to GraphicsMagick for the - -- subsequent resizing operation. The '-resize 120x120' specifies the desired dimensions of the output image. It - -- will be scaled so its largest dimension is 120 pixels. The '+profile "*"' removes any ICM, EXIF, IPTC, or other - -- profiles that might be present in the input and aren't needed in the thumbnail. - - local convertToThumbCommand = "convert -size 96x96 "..exported_image.." -resize 92x92 -mattecolor \"#FFFFFF\" -frame 2x2 +profile \"*\" "..exportDirectory.."/"..imageFoldername.."thumb_"..filename..".jpg" - dt.control.execute(convertToThumbCommand) - else - -- Remove exported image if it has no GPS data - os.remove(exported_image) - end + kml_file = kml_file.." \n" + kml_file = kml_file.." \n" - local pattern = "[/]?([^/]+)$" - filmName = string.match(image.film.path, pattern) + kml_file = kml_file.." \n" + end - -- Strip accents from the filename, because GoogleEarth can't open them - -- https://github.com/darktable-org/lua-scripts/issues/54 - filmName = string.stripAccents(filmName) - end + kml_file = kml_file.."\n" + kml_file = kml_file.."" + + local file = io.open(exportDirectory.."/"..exportKMLFilename, "w") + file:write(kml_file) + file:close() - exportKMLFilename = filmName..".kml" - exportKMZFilename = filmName..".kmz" + dt.print("KML file created in "..exportDirectory) - -- Create the KML file - local kml_file = "\n" - kml_file = kml_file.."\n" - kml_file = kml_file.."\n" + -- Compress the files to create a KMZ file + if ( dt.preferences.read("kml_export","CreateKMZ","bool") == true ) then + exportDirectory = dt.preferences.read("kml_export","ExportDirectory","string") - --image_table = dt.gui.selection(); - kml_file = kml_file..""..filmName.."\n" - kml_file = kml_file.." Exported from darktable\n" + local createKMZCommand = "zip --test --move --junk-paths " + createKMZCommand = createKMZCommand .."\""..exportDirectory.."/"..exportKMZFilename.."\" " -- KMZ filename + createKMZCommand = createKMZCommand .."\""..dt.configuration.tmp_dir.."/"..exportKMLFilename.."\" " -- KML file for image,exported_image in pairs(image_table) do - -- Extract filename, e.g DSC9784.ARW -> DSC9784 - filename = string.upper(string.gsub(image.filename,"%.%w*", "")) + if ((image.longitude and image.latitude) and + (image.longitude ~= 0 and image.latitude ~= 90) -- Sometimes the north-pole but most likely just wrong data + ) then + local filename = string.upper(string.gsub(image.filename,"%.%w*", "")) -- Handle duplicates filename = addDuplicateIndex( image.duplicate_index, filename ) - -- Extract extension from exported image (user can choose JPG or PNG), e.g DSC9784.JPG -> .JPG - extension = string.match(exported_image,"%.%w*$") - - if ((image.longitude and image.latitude) and - (image.longitude ~= 0 and image.latitude ~= 90) -- Sometimes the north-pole but most likely just wrong data - ) then - kml_file = kml_file.." \n" - - local image_title, image_description - if (image.title and image.title ~= "") then - image_title = string.escapeXmlCharacters(image.title) - else - image_title = filename..extension - end - -- Characters should not be escaped in CDATA, but we are using HTML fragment, so we must escape them - image_description = string.escapeXmlCharacters(image.description) - - kml_file = kml_file.." "..image_title.."\n" - kml_file = kml_file.." "..image_description.."\n" - kml_file = kml_file.." \n" - - kml_file = kml_file.." \n" - kml_file = kml_file.." 1\n" - kml_file = kml_file.." "..string.gsub(tostring(image.longitude),",", ".")..","..string.gsub(tostring(image.latitude),",", ".")..",0\n" - kml_file = kml_file.." \n" - kml_file = kml_file.." "..string.gsub(image.exif_datetime_taken," ", "T").."Z".."\n" - kml_file = kml_file.." \n" - kml_file = kml_file.." \n" - - kml_file = kml_file.." \n" - end - end - -- Connects all images with an path - if ( dt.preferences.read("kml_export","CreatePath","bool") == true ) then - kml_file = kml_file.." \n" - kml_file = kml_file.." Path\n" -- ToDo: I think a better name would be nice - --kml_file = kml_file.." \n" - - kml_file = kml_file.." \n" - - kml_file = kml_file.." \n" - kml_file = kml_file.." \n" - - for image,exported_image in spairs(image_table, function(t,a,b) return b.exif_datetime_taken > a.exif_datetime_taken end) do - if ((image.longitude and image.latitude) and - (image.longitude ~= 0 and image.latitude ~= 90) -- Sometimes the north-pole but most likely just wrong data - ) then - local altitude = 0; - if (image.elevation) then - altitude = image.elevation; - end - - kml_file = kml_file.." "..string.gsub(tostring(image.longitude),",", ".")..","..string.gsub(tostring(image.latitude),",", ".")..",altitude\n" - end - end - - kml_file = kml_file.." \n" - kml_file = kml_file.." \n" - - kml_file = kml_file.." \n" + createKMZCommand = createKMZCommand .."\""..dt.configuration.tmp_dir.."/"..imageFoldername.."thumb_"..filename..".jpg\" " -- thumbnails + createKMZCommand = createKMZCommand .."\""..exported_image.."\" " -- images + end end - kml_file = kml_file.."\n" - kml_file = kml_file.."" - - local file = io.open(exportDirectory.."/"..exportKMLFilename, "w") - file:write(kml_file) - file:close() + dt.control.execute(createKMZCommand) + end - dt.print("KML file created in "..exportDirectory) + -- Open the file with the standard programm + if ( dt.preferences.read("kml_export","OpenKmlFile","bool") == true ) then + local kmlFileOpenCommand - -- Compress the files to create a KMZ file if ( dt.preferences.read("kml_export","CreateKMZ","bool") == true ) then - exportDirectory = dt.preferences.read("kml_export","ExportDirectory","string") - - local createKMZCommand = "zip --test --move --junk-paths " - createKMZCommand = createKMZCommand .."\""..exportDirectory.."/"..exportKMZFilename.."\" " -- KMZ filename - createKMZCommand = createKMZCommand .."\""..dt.configuration.tmp_dir.."/"..exportKMLFilename.."\" " -- KML file - - for image,exported_image in pairs(image_table) do - if ((image.longitude and image.latitude) and - (image.longitude ~= 0 and image.latitude ~= 90) -- Sometimes the north-pole but most likely just wrong data - ) then - local filename = string.upper(string.gsub(image.filename,"%.%w*", "")) - -- Handle duplicates - filename = addDuplicateIndex( image.duplicate_index, filename ) - - createKMZCommand = createKMZCommand .."\""..dt.configuration.tmp_dir.."/"..imageFoldername.."thumb_"..filename..".jpg\" " -- thumbnails - createKMZCommand = createKMZCommand .."\""..exported_image.."\" " -- images - end - end - - dt.control.execute(createKMZCommand) - end - - -- Open the file with the standard programm - if ( dt.preferences.read("kml_export","OpenKmlFile","bool") == true ) then - local kmlFileOpenCommand - - if ( dt.preferences.read("kml_export","CreateKMZ","bool") == true ) then - kmlFileOpenCommand = "xdg-open "..exportDirectory.."/\""..exportKMZFilename.."\"" - else - kmlFileOpenCommand = "xdg-open "..exportDirectory.."/\""..exportKMLFilename.."\"" - end - dt.control.execute(kmlFileOpenCommand) + kmlFileOpenCommand = "xdg-open "..exportDirectory.."/\""..exportKMZFilename.."\"" + else + kmlFileOpenCommand = "xdg-open "..exportDirectory.."/\""..exportKMLFilename.."\"" end + dt.control.execute(kmlFileOpenCommand) + end end -- Preferences dt.preferences.register("kml_export", - "OpenKmlFile", - "bool", - _("KML export: Open KML/KMZ file after export"), - _("Opens the KML file after the export with the standard program for KML files"), - false ) + "OpenKmlFile", + "bool", + _("KML export: Open KML/KMZ file after export"), + _("Opens the KML file after the export with the standard program for KML files"), + false ) local handle = io.popen("xdg-user-dir DESKTOP") local result = handle:read() if (result == nil) then - result = "" + result = "" end handle:close() dt.preferences.register("kml_export", - "ExportDirectory", - "directory", - _("KML export: Export directory"), - _("A directory that will be used to export the KML/KMZ files"), - result ) + "ExportDirectory", + "directory", + _("KML export: Export directory"), + _("A directory that will be used to export the KML/KMZ files"), + result ) dt.preferences.register("kml_export", - "CreatePath", - "bool", - _("KML export: Connect images with path"), - _("connect all images with a path"), - false ) + "CreatePath", + "bool", + _("KML export: Connect images with path"), + _("connect all images with a path"), + false ) dt.preferences.register("kml_export", - "CreateKMZ", - "bool", - _("KML export: Create KMZ file"), - _("Compress all imeges to one KMZ file"), - true ) + "CreateKMZ", + "bool", + _("KML export: Create KMZ file"), + _("Compress all imeges to one KMZ file"), + true ) -- Register dt.register_storage("kml_export", _("KML/KMZ Export"), nil, create_kml_file) + +-- vim: shiftwidth=2 expandtab tabstop=2 cindent syntax=lua +-- kate: hl Lua; From 493dcc7ef7131b2b75111011a4e0060edf4f9c77 Mon Sep 17 00:00:00 2001 From: Tobias Ellinghaus Date: Wed, 17 Jan 2018 10:41:55 +0100 Subject: [PATCH 071/679] Don't delete tags while iterating --- official/delete_long_tags.lua | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/official/delete_long_tags.lua b/official/delete_long_tags.lua index 3e2378b7..5a2da73c 100644 --- a/official/delete_long_tags.lua +++ b/official/delete_long_tags.lua @@ -1,6 +1,6 @@ --[[ This file is part of darktable, - copyright (c) 2014 Tobias Ellinghaus + copyright (c) 2014--2018 Tobias Ellinghaus darktable is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -17,7 +17,7 @@ ]] --[[ DELETE LONG TAGS -A simple script that will automatically delete all tag longer than a set length +A simple script that will automatically delete all tags longer than a set length USAGE * require this script from your main lua file @@ -38,10 +38,18 @@ dt.preferences.register("delete_long_tags", "length", "integer", local max_length = dt.preferences.read("delete_long_tags", "length", "integer") +-- deleting while iterating the tags list seems to break the iterator! +local long_tags = {} + for _,t in ipairs(dt.tags) do local len = #t.name if len > max_length then print("deleting tag `"..t.name.."' (length: "..len..")") - t:delete() + table.insert(long_tags, t.name) end end + +for _,name in pairs(long_tags) do + tag = dt.tags.find(name) + tag:delete() +end From 95077f639b0345f35f8fb810190202b86c55e88b Mon Sep 17 00:00:00 2001 From: Tobias Ellinghaus Date: Wed, 17 Jan 2018 10:42:44 +0100 Subject: [PATCH 072/679] New script to delete unused tags on startup --- official/delete_unused_tags.lua | 46 +++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 official/delete_unused_tags.lua diff --git a/official/delete_unused_tags.lua b/official/delete_unused_tags.lua new file mode 100644 index 00000000..337f5f64 --- /dev/null +++ b/official/delete_unused_tags.lua @@ -0,0 +1,46 @@ +--[[ + This file is part of darktable, + copyright (c) 2018 Tobias Ellinghaus + + 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 . +]] +--[[ +DELETE UNUSED TAGS +A simple script that will automatically delete all tags that are not attached to any images + +USAGE +* require this script from your main lua file +* restart darktable + +all tags that are not used will be automatically deleted at every restart +]] + +local dt = require "darktable" + +dt.configuration.check_version(...,{5,0,0}) + +-- deleting while iterating the tags list seems to break the iterator! +local unused_tags = {} + +for _, t in ipairs(dt.tags) do + if #t == 0 then + table.insert(unused_tags, t.name) + end +end + +for _,name in pairs(unused_tags) do + print("deleting tag `" .. name .. "'") + tag = dt.tags.find(name) + tag:delete() +end From 54572de8d9dfb4b618ee39ebde358b09b9714878 Mon Sep 17 00:00:00 2001 From: Tobias Ellinghaus Date: Tue, 23 Jan 2018 11:28:45 +0100 Subject: [PATCH 073/679] Fix LabelsToTags for Lua 5.3 Fixes #106 --- contrib/LabelsToTags.lua | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/contrib/LabelsToTags.lua b/contrib/LabelsToTags.lua index 1135a96b..431760e5 100644 --- a/contrib/LabelsToTags.lua +++ b/contrib/LabelsToTags.lua @@ -43,9 +43,13 @@ LGPLv2+ ]] + local darktable = require("darktable") darktable.configuration.check_version(...,{3,0,0},{4,0,0},{5,0,0}) +-- Lua 5.3 no longer has "unpack" but "table.unpack" +unpack = unpack or table.unpack + local LIB_ID = "LabelsToTags" -- Helper functions: BEGIN @@ -151,7 +155,7 @@ 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) job.percent = 0.0 local pctIncrement = 1.0 / #(darktable.gui.action_images) - + local availableMappings = getAvailableMappings() local memoizedTags = {} for _,img in ipairs(darktable.gui.action_images) do From 5d57347730a1278f89bfabba2c7acec96e2e208b Mon Sep 17 00:00:00 2001 From: Andy Chien Date: Thu, 22 Feb 2018 16:01:54 -0800 Subject: [PATCH 074/679] fixed a couple dtutils_file functions for windows platform --- lib/dtutils/file.lua | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/lib/dtutils/file.lua b/lib/dtutils/file.lua index 617234b5..bc215e3c 100644 --- a/lib/dtutils/file.lua +++ b/lib/dtutils/file.lua @@ -51,7 +51,13 @@ dtutils_file.libdoc.functions["check_if_bin_exists"] = { } function dtutils_file.check_if_bin_exists(bin) - local result = os.execute("which " .. bin) + local cmd + if package.config:sub(1,1) == '/' then + cmd = 'which ' + else + cmd = 'where ' + end + local result = os.execute(cmd .. bin) if not result then result = false end @@ -194,10 +200,13 @@ dtutils_file.libdoc.functions["check_if_file_exists"] = { } function dtutils_file.check_if_file_exists(filepath) - local result = os.execute("test -e " .. filepath) - if not result then - result = false + local file = io.open(filepath, "r") + local result = false + if file then + result = true + file:close() end + return result end @@ -384,7 +393,7 @@ function dtutils_file.create_unique_filename(filepath) while dtutils_file.check_if_file_exists(filepath) do filepath = dtutils_file.filename_increment(filepath) -- limit to 99 more exports of the original export - if string.match(dtfileutils.get_basename(filepath), "_(d-)$") == "99" then + if string.match(dtutils_file.get_basename(filepath), "_(d-)$") == "99" then break end end From 4ad9e77a7e0a0c86a9837e1212c7fd6ecdfe4787 Mon Sep 17 00:00:00 2001 From: Andy Chien Date: Thu, 22 Feb 2018 16:07:28 -0800 Subject: [PATCH 075/679] improved a few aspects of the hugin script: * handle stiching all from hugin_executor without the gui * automatically create the panorama file name based on first selected file plus _pano * automatically detects if output file exists, if so use an unique name * delete temporarily exported file --- contrib/hugin.lua | 51 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 36 insertions(+), 15 deletions(-) diff --git a/contrib/hugin.lua b/contrib/hugin.lua index d69a8ad7..9008b157 100644 --- a/contrib/hugin.lua +++ b/contrib/hugin.lua @@ -71,38 +71,59 @@ local function create_panorama(storage, image_table, extra_data) --finalize -- list of exported images local img_list + local img_set = {} -- reset and create image list img_list = "" - - for _,v in pairs(image_table) do + for k,v in pairs(image_table) do img_list = img_list ..v.. " " + table.insert(img_set, k) end - dt.print(_("Will try to stitch now")) + -- use first file as basename + table.sort(img_set, function(a,b) return a.filename Date: Fri, 23 Feb 2018 18:14:24 -0800 Subject: [PATCH 076/679] platform dependent implementation of check_if_bin_exists and check_if_file_exists --- lib/dtutils/file.lua | 38 +++++++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/lib/dtutils/file.lua b/lib/dtutils/file.lua index bc215e3c..22cd5e56 100644 --- a/lib/dtutils/file.lua +++ b/lib/dtutils/file.lua @@ -51,16 +51,17 @@ dtutils_file.libdoc.functions["check_if_bin_exists"] = { } function dtutils_file.check_if_bin_exists(bin) - local cmd - if package.config:sub(1,1) == '/' then - cmd = 'which ' + local result + if (dt.configuration.running_os == 'linux') then + result = os.execute("which "..bin) else - cmd = 'where ' + result = dtutils_file.check_if_file_exists(bin) end - local result = os.execute(cmd .. bin) + if not result then result = false end + return result end @@ -200,11 +201,26 @@ dtutils_file.libdoc.functions["check_if_file_exists"] = { } function dtutils_file.check_if_file_exists(filepath) - local file = io.open(filepath, "r") - local result = false - if file then - result = true - file:close() + local result + if (dt.configuration.running_os == 'windows') then + filepath = string.gsub(filepath, '[\\/]+', '\\') + result = os.execute('if exist "'..filepath..'" (cmd /c exit 0) else (cmd /c exit 1)') + if not result then + result = false + end + elseif (dt.configuration.running_os == "linux") then + result = os.execute('test -e ' .. filepath) + if not result then + result = false + end + else + local file = io.open(filepath, "r") + if file then + result = true + file:close() + else + result = false + end end return result @@ -400,4 +416,4 @@ function dtutils_file.create_unique_filename(filepath) return filepath end -return dtutils_file +return dtutils_file \ No newline at end of file From fe942100a40691d3b2250b5125b9984e3231dca5 Mon Sep 17 00:00:00 2001 From: Andy Chien Date: Fri, 23 Feb 2018 10:07:45 -0800 Subject: [PATCH 077/679] hugin plugin improvements * added preference requiring user to specify the paths for hugin, hugin_executor and pto_gen needed for this plguin * added preference to allow user to choose to launch hugin in GUI mode * minor fix to the way files are handled; due to some versions of hugin_executor not writing out to the path specified in --prefix, assume we are working in the tmp directory and then move the file afterwards --- contrib/hugin.lua | 111 ++++++++++++++++++++++++++++------------------ 1 file changed, 69 insertions(+), 42 deletions(-) diff --git a/contrib/hugin.lua b/contrib/hugin.lua index 9008b157..477e5060 100644 --- a/contrib/hugin.lua +++ b/contrib/hugin.lua @@ -28,7 +28,9 @@ ADDITIONAL SOFTWARE NEEDED FOR THIS SCRIPT * hugin USAGE -* require this file from your main luarc config file. +* require this file from your main luarc config file +* set the hugin tool paths in preferences +* if hugin gui mode is used, save the final result in the tmp directory with the first file name and _pano as suffix for the image to be automatically imported to DT afterwards This plugin will add a new storage option and calls hugin after export. ]] @@ -37,6 +39,7 @@ local dt = require "darktable" local df = require "lib/dtutils.file" require "official/yield" local gettext = dt.gettext +local namespace = 'module_hugin' -- works with darktable API version from 2.0.0 to 5.0.0 dt.configuration.check_version(...,{2,0,0},{3,0,0},{4,0,0},{5,0,0}) @@ -45,28 +48,33 @@ dt.configuration.check_version(...,{2,0,0},{3,0,0},{4,0,0},{5,0,0}) gettext.bindtextdomain("hugin",dt.configuration.config_dir.."/lua/locale/") local function _(msgid) - return gettext.dgettext("hugin", msgid) + return gettext.dgettext("hugin", msgid) end local function show_status(storage, image, format, filename, number, total, high_quality, extra_data) - dt.print("Export to Hugin "..tostring(number).."/"..tostring(total)) + dt.print("exporting to Hugin: "..tostring(number).."/"..tostring(total)) end local function create_panorama(storage, image_table, extra_data) --finalize - if not df.check_if_bin_exists("hugin") then - dt.print_error(_("hugin not found")) - return - end - -- Since Hugin 2015.0.0 hugin provides a command line tool to start the assistant -- http://wiki.panotools.org/Hugin_executor -- We need pto_gen to create pto file for hugin_executor -- http://hugin.sourceforge.net/docs/manual/Pto_gen.html - local hugin_executor = false - if (df.check_if_bin_exists("hugin_executor") and df.check_if_bin_exists("pto_gen")) then - hugin_executor = true + local hugin = '"'..dt.preferences.read(namespace, "hugin", "file")..'"' + local hugin_executor = '"'..dt.preferences.read(namespace, "hugin_executor", "file")..'"' + local pto_gen = '"'..dt.preferences.read(namespace, "pto_gen", "file")..'"' + local user_prefer_gui = dt.preferences.read(namespace, "hugin_prefer_gui", "bool") + + local cmd_line_available = false + if df.check_if_bin_exists(hugin_executor) and df.check_if_bin_exists(pto_gen) then + cmd_line_available = true + end + + local gui_available = false + if df.check_if_bin_exists(hugin) then + gui_available = true end -- list of exported images @@ -76,58 +84,77 @@ local function create_panorama(storage, image_table, extra_data) --finalize -- reset and create image list img_list = "" for k,v in pairs(image_table) do - img_list = img_list ..v.. " " - table.insert(img_set, k) + img_list = img_list..v..' ' + table.insert(img_set, k) end - -- use first file as basename + -- use first file as basename for output file table.sort(img_set, function(a,b) return a.filename Date: Fri, 2 Mar 2018 14:07:29 -0500 Subject: [PATCH 078/679] Added windows and macOS external executable compatibility. Added functions set_executable_path_preference(), get_executable_path_preference(), and executable_path_widget() to lib/dtutils/file.lua to get, set and retrieve the location of executables on windows and macOS systems. Modified check_if_bin_exists to use the path preferences so executables can be found on windows and macOS systems as well as linux. Modified contrib/gimp.lua to use the new functions, thus making it usable on windows and macOS too. --- contrib/gimp.lua | 177 ++++++++----------------------------------- lib/dtutils/file.lua | 133 +++++++++++++++++++++++++++++--- 2 files changed, 153 insertions(+), 157 deletions(-) diff --git a/contrib/gimp.lua b/contrib/gimp.lua index f8472c75..c0fba7ec 100644 --- a/contrib/gimp.lua +++ b/contrib/gimp.lua @@ -67,109 +67,38 @@ local dt = require "darktable" local df = require "lib/dtutils.file" require "official/yield" local gettext = dt.gettext +local gimp_widget = nil -dt.configuration.check_version(...,{3,0,0},{4,0,0},{5,0,0}) +dt.configuration.check_version(...,{5,0,0}) -- 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 split_filepath(str) - local result = {} - -- Thank you Tobias Jakobs for the awesome regular expression, which I tweaked a little - result["path"], result["filename"], result["basename"], result["filetype"] = string.match(str, "(.-)(([^\\/]-)%.?([^%.\\/]*))$") - return result -end - -local function get_path(str) - local parts = split_filepath(str) - return parts["path"] -end - -local function get_filename(str) - local parts = split_filepath(str) - return parts["filename"] -end - -local function get_basename(str) - local parts = split_filepath(str) - return parts["basename"] -end - -local function get_filetype(str) - local parts = split_filepath(str) - return parts["filetype"] -end - local function _(msgid) return gettext.dgettext("gimp", msgid) end --- Thanks Tobias Jakobs for the idea and the correction -function checkIfFileExists(filepath) - local file = io.open(filepath,"r") - local ret - if file ~= nil then - io.close(file) - dt.print_error("true checkIfFileExists: "..filepath) - ret = true - else - dt.print_error(filepath.." not found") - ret = false - end - return ret -end - -local function filename_increment(filepath) - - -- break up the filepath into parts - local path = get_path(filepath) - local basename = get_basename(filepath) - local filetype = get_filetype(filepath) - - -- check to see if we've incremented before - local increment = string.match(basename, "_(%d-)$") - - if increment then - -- we do 2 digit increments so make sure we didn't grab part of the filename - if string.len(increment) > 2 then - -- we got the filename so set the increment to 01 - increment = "01" - else - increment = string.format("%02d", tonumber(increment) + 1) - basename = string.gsub(basename, "_(%d-)$", "") - end - else - increment = "01" - end - local incremented_filepath = path .. basename .. "_" .. increment .. "." .. filetype - - dt.print_error("original file was " .. filepath) - dt.print_error("incremented file is " .. incremented_filepath) - - return incremented_filepath -end - -local function groupIfNotMember(img, new_img) +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 - dt.print_error(image.filename .. " is a member") + dt.print_log(image.filename .. " is a member") if image.filename == new_img.filename then is_member = true - dt.print_error("Already in group") + dt.print_log("Already in group") end end if not is_member then - dt.print_error("group leader is "..img.group_leader.filename) + dt.print_log("group leader is "..img.group_leader.filename) new_img:group_with(img.group_leader) - dt.print_error("Added to group") + dt.print_log("Added to group") end end local function sanitize_filename(filepath) - local path = get_path(filepath) - local basename = get_basename(filepath) - local filetype = get_filetype(filepath) + local path = df.get_path(filepath) + local basename = df.get_basename(filepath) + local filetype = df.get_filetype(filepath) local sanitized = string.gsub(basename, " ", "\\ ") @@ -181,60 +110,11 @@ local function show_status(storage, image, format, filename, dt.print(string.format(_("Export Image %i/%i"), number, total)) end -local function fileCopy(fromFile, toFile) - local result = nil - -- if cp exists, use it - if df.check_if_bin_exists("cp") then - result = os.execute("cp '" .. fromFile .. "' '" .. toFile .. "'") - end - -- if cp was not present, or if cp failed, then a pure lua solution - if not result then - local fileIn, err = io.open(fromFile, 'rb') - if fileIn then - local fileOut, errr = io.open(toFile, 'w') - if fileOut then - local content = fileIn:read(4096) - while content do - fileOut:write(content) - content = fileIn:read(4096) - end - result = true - fileIn:close() - fileOut:close() - else - dt.print_error("fileCopy Error: " .. errr) - end - else - dt.print_error("fileCopy Error: " .. err) - end - end - return result -end +local function gimp_edit(storage, image_table, extra_data) --finalize -local function fileMove(fromFile, toFile) - local success = os.rename(fromFile, toFile) - if not success then - -- an error occurred, so let's try using the operating system function - if df.check_if_bin_exists("mv") then - success = os.execute("mv '" .. fromFile .. "' '" .. toFile .. "'") - end - -- if the mv didn't exist or succeed, then... - if not success then - -- pure lua solution - success = fileCopy(fromFile, toFile) - if success then - os.remove(fromFile) - else - dt.print_error("fileMove Error: Unable to move " .. fromFile .. " to " .. toFile .. ". Leaving " .. fromFile .. " in place.") - dt.print(string.format(_("Unable to move edited file into collection. Leaving it as %s"), fromFile)) - end - end - end - return success -- nil on error, some value if success -end + local gimp_executable = df.check_if_bin_exists("gimp") -local function gimp_edit(storage, image_table, extra_data) --finalize - if not df.check_if_bin_exists("gimp") then + if not gimp_executable then dt.print_error(_("GIMP not found")) return end @@ -253,9 +133,9 @@ local function gimp_edit(storage, image_table, extra_data) --finalize dt.print(_("Launching GIMP...")) local gimpStartCommand - gimpStartCommand = "gimp "..img_list + gimpStartCommand = gimp_executable .. " " .. img_list - dt.print_error(gimpStartCommand) + dt.print_log(gimpStartCommand) dt.control.execute( gimpStartCommand) @@ -266,28 +146,28 @@ local function gimp_edit(storage, image_table, extra_data) --finalize for image,exported_image in pairs(image_table) do - local myimage_name = image.path .. "/" .. get_filename(exported_image) + local myimage_name = image.path .. "/" .. df.get_filename(exported_image) - while checkIfFileExists(myimage_name) do - myimage_name = filename_increment(myimage_name) + 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(get_basename(myimage_name), "_(d-)$") == "99" then + if string.match(df.get_basename(myimage_name), "_(d-)$") == "99" then break end end - dt.print_error("moving " .. exported_image .. " to " .. myimage_name) - local result = fileMove(exported_image, myimage_name) + dt.print_log("moving " .. exported_image .. " to " .. myimage_name) + local result = df.file_move(exported_image, myimage_name) if result then - dt.print_error("importing file") + dt.print_log("importing file") local myimage = dt.database.import(myimage_name) - groupIfNotMember(image, myimage) + 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.print_error("attaching tag") + dt.print_log("attaching tag") dt.tags.attach(tag,myimage) end end @@ -297,6 +177,13 @@ local function gimp_edit(storage, image_table, extra_data) --finalize end -- Register -dt.register_storage("module_gimp", _("Edit with GIMP"), show_status, gimp_edit) + +local executables = {"gimp"} + +if dt.configuration.running_os ~= "linux" then + gimp_widget = df.executable_path_widget(executables) +end + +dt.register_storage("module_gimp", _("Edit with GIMP"), show_status, gimp_edit, nil, nil, gimp_widget) -- diff --git a/lib/dtutils/file.lua b/lib/dtutils/file.lua index 22cd5e56..696cdbc6 100644 --- a/lib/dtutils/file.lua +++ b/lib/dtutils/file.lua @@ -23,7 +23,7 @@ dtutils_file.libdoc = { local gettext = dt.gettext -dt.configuration.check_version(...,{3,0,0},{4,0,0},{5,0,0}) +dt.configuration.check_version(...,{5,0,0}) -- Tell gettext where to find the .mo file translating messages for a particular domain gettext.bindtextdomain("dtutils.file",dt.configuration.config_dir.."/lua/locale/") @@ -34,14 +34,18 @@ end dtutils_file.libdoc.functions["check_if_bin_exists"] = { Name = [[check_if_bin_exists]], - Synopsis = [[check if an executable is in the path]], + Synopsis = [[check if an executable exists]], Usage = [[local df = require "lib/dtutils.file" local result = df.check_if_bin_exists(bin) bin - string - the binary to check for]], - Description = [[check_if_bin_exists checks to see if the specified binary executable is - in the path.]], - Return_Value = [[result - boolean - true if the executable was found, false if not]], + Description = [[check_if_bin_exists checks to see if the specified binary exists. + check_if_bin_exists first checks to see if a preference for the binary has been + registered and uses that if found. The presence of the file is verified, then + quoted and returned. If no preference is specified and the operating system is + linux then the which command is used to check for a binary in the path. If found + that path is returned. If no binary is found, false is returned.]], + Return_Value = [[result - string - the path of the binary, false if not found]], Limitations = [[]], Example = [[]], See_Also = [[]], @@ -51,17 +55,27 @@ dtutils_file.libdoc.functions["check_if_bin_exists"] = { } function dtutils_file.check_if_bin_exists(bin) - local result - if (dt.configuration.running_os == 'linux') then - result = os.execute("which "..bin) + local result = false + local path = nil + + if string.match(bin, "/") or string.match(bin, "\\") then + path = bin else - result = dtutils_file.check_if_file_exists(bin) + path = dtutils_file.get_executable_path_preference(bin) end - if not result then - result = false + if string.len(path) > 0 then + if dtutils_file.check_if_file_exists(path) then + result = "\"" .. path .. "\"" + end + elseif dt.configuration.running_os == "linux" then + local p = io.popen("which " .. bin) + local output = p:read("*a") + p:close() + if string.len(output) > 0 then + result = output:sub(1,-2) + end end - return result end @@ -416,4 +430,99 @@ function dtutils_file.create_unique_filename(filepath) return filepath end + +dtutils_file.libdoc.functions["set_executable_path_preference"] = { + Name = [[set_executable_path_preference]], + Synopsis = [[set a preference for the path to an executable]], + Usage = [[local df = require "lib/dtutils.file" + + df.set_executable_path_preference(executable, path) + executable - string - the name of the executable to set the path for + path - string - the path to the binary]], + Description = [[set_executable_path_preference takes an executable name and path to the + executable and registers the preference for later use.]], + Return_Value = [[]], + Limitations = [[]], + Example = [[]], + See_Also = [[]], + Reference = [[]], + License = [[]], + Copyright = [[]], +} + +function dtutils_file.set_executable_path_preference(executable, path) + dt.preferences.write("executable_paths", executable, "string", path) +end + + +dtutils_file.libdoc.functions["get_executable_path_preference"] = { + Name = [[get_executable_path_preference]], + Synopsis = [[return the path to an executable from a preference]], + Usage = [[local df = require "lib/dtutils.file" + + local result = df.get_executable_path_preference(executable) + executable - string - the name of the executable to get the path for]], + Description = [[get_executable_path_preference returns the path preference to + the requested executable.]], + Return_Value = [[result - string - path to the executable]], + Limitations = [[executable should be the basename of the executable without extensions]], + Example = [[]], + See_Also = [[]], + Reference = [[]], + License = [[]], + Copyright = [[]], +} + +function dtutils_file.get_executable_path_preference(executable) + return dt.preferences.read("executable_paths", executable, "string") +end + + +dtutils_file.libdoc.functions["executable_path_widget"] = { + Name = [[executable_path_widget]], + Synopsis = [[create a widget to get executable path preferences]], + Usage = [[local df = require "lib/dtutils.file" + + local widget = df.executable_path_widget(executables) + executables - table - a table of strings that are executable names]], + Description = [[executable_path_widget takes a table of executable names + and builds a set of file selector widgets to get the path to the executable. + The resulting widgets are wrapped in a box widget and returned.]], + Return_Value = [[widget - widget - a widget containing a file selector widget for + each executable.]], + Limitations = [[]], + Example = [[]], + See_Also = [[]], + Reference = [[]], + License = [[]], + Copyright = [[]], +} + +function dtutils_file.executable_path_widget(executables) + local box_widgets = {} + table.insert(box_widgets, dt.new_widget("section_label"){label = "select executable(s)"}) + for _, executable in pairs(executables) do + table.insert(box_widgets, dt.new_widget("label"){label = "select " .. executable .. " executable"}) + local path = dtutils_file.get_executable_path_preference(executable) + if not path then + path = "" + end + table.insert(box_widgets, dt.new_widget("file_chooser_button"){ + title = "select " .. executable .. " executable", + value = path, + is_directory = false, + changed_callback = function(self) + if dtutils_file.check_if_bin_exists(self.value) then + dtutils_file.set_executable_path_preference(executable, self.value) + end + end} + ) + end + local box = dt.new_widget("box"){ + orientation = "vertical", + table.unpack(box_widgets) + } + return box +end + return dtutils_file \ No newline at end of file From c073ecf0dd10f05b26b904e2d56d22e8fa845126 Mon Sep 17 00:00:00 2001 From: Bill Ferguson Date: Sat, 3 Mar 2018 20:22:47 -0500 Subject: [PATCH 079/679] Added check_os to lib/dtutils.lua so that scripts can check compatibility with the current operating system --- lib/dtutils.lua | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/lib/dtutils.lua b/lib/dtutils.lua index 02888a8e..abe51d64 100644 --- a/lib/dtutils.lua +++ b/lib/dtutils.lua @@ -32,7 +32,7 @@ local dt = require "darktable" local log = require "lib/dtutils.log" -dt.configuration.check_version(...,{3,0,0},{4,0,0},{5,0,0}) +dt.configuration.check_version(...,{5,0,0}) dtutils.libdoc.functions["split"] = { Name = [[split]], @@ -215,4 +215,37 @@ function dtutils.spairs(_table, order) -- Code copied from http://stackoverflow. end end +dtutils.libdoc.functions["check_os"] = { + Name = [[check_os]], + Synopsis = [[check that the operating system is supported]], + Usage = [[local du = require "lib/dtutils" + + local result = du.check_os(operating_systems) + operating_systems - a table of operating system names such as {"windows","linux","macos","unix"}]], + Description = [[check_os checks a supplied table of operating systems against the operating system the + script is running on and returns true if the OS is in the list, otherwise false]], + Return_Value = [[result - boolean - true if the operating system is supported, false if not.]], + Limitations = [[]], + Example = [[local du = require "lib/dtutils" + if du.check_os({"windows"}) then + -- run the script + else + dt.print("Script