Compare commits
116 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
97dd8a1257 | ||
|
|
83fc339c4b | ||
|
|
693c535428 | ||
|
|
d74f2eba92 | ||
|
|
d0ec941009 | ||
|
|
178528508b | ||
|
|
20a31b39e0 | ||
|
|
fc252d5e7e | ||
|
|
4090266989 | ||
|
|
19b7d29483 | ||
|
|
af4e3884bb | ||
|
|
d3742bb410 | ||
|
|
75cb1a5fdd | ||
|
|
8436c878e8 | ||
|
|
63d3a34f46 | ||
|
|
6cda97c335 | ||
|
|
a40d8b8bc5 | ||
|
|
15a492cfa3 | ||
|
|
445e882579 | ||
|
|
d4b155d0c2 | ||
|
|
65f4960302 | ||
|
|
dc9e8d406d | ||
|
|
4d76006c2d | ||
|
|
731a6d0410 | ||
|
|
e4542aa451 | ||
|
|
ecc4a29be4 | ||
|
|
0f0b3d6df5 | ||
|
|
a826c1725b | ||
|
|
4e3b461fd3 | ||
|
|
d8a9dfafb2 | ||
|
|
ede621bea7 | ||
|
|
2f7da8356f | ||
|
|
d555cb2c94 | ||
|
|
750d70bfff | ||
|
|
dcc205ec4f | ||
|
|
356756286e | ||
|
|
79511d9b42 | ||
|
|
bff2df018b | ||
|
|
2562a218a0 | ||
|
|
d46b7e4aaf | ||
|
|
dee7ee1dde | ||
|
|
01fc339da5 | ||
|
|
ef46cd9b45 | ||
|
|
ac3ccb287b | ||
|
|
f52292e8d1 | ||
|
|
693c9858c2 | ||
|
|
c8d5e9d9d2 | ||
|
|
50668817db | ||
|
|
91758b61c3 | ||
|
|
39ae92a0fa | ||
|
|
95c203793c | ||
|
|
c7ac974ab9 | ||
|
|
51931d2b01 | ||
|
|
d271f6d46d | ||
|
|
efcd48f1d9 | ||
|
|
76daa583b3 | ||
|
|
3425a85fd0 | ||
|
|
9a6c1510fd | ||
|
|
44c391cb5a | ||
|
|
6085be7589 | ||
|
|
7d9bf8c729 | ||
|
|
1d72457dc1 | ||
|
|
0e32d2b1b4 | ||
|
|
75165e8838 | ||
|
|
d9536f1294 | ||
|
|
44e4c3ddc5 | ||
|
|
f67755f3b5 | ||
|
|
68d768cbd3 | ||
|
|
0be268c01f | ||
|
|
1831db530d | ||
|
|
8a32bf21d0 | ||
|
|
81c5bb4d52 | ||
|
|
93796bf4a8 | ||
|
|
4c34113f78 | ||
|
|
e4b189a06e | ||
|
|
0ebc885eb1 | ||
|
|
b4658ddf76 | ||
|
|
b38e2964ca | ||
|
|
5021e512b9 | ||
|
|
6d927540c8 | ||
|
|
6168767766 | ||
|
|
5af200a29d | ||
|
|
8b333c1ab5 | ||
|
|
d1f34ec136 | ||
|
|
c887a0d2b5 | ||
|
|
1168ba4557 | ||
|
|
e389420f07 | ||
|
|
0590beb876 | ||
|
|
d30c0d0213 | ||
|
|
eb774d37c6 | ||
|
|
cade6d5e0b | ||
|
|
19b71c5782 | ||
|
|
5f802a8179 | ||
|
|
99e1141446 | ||
|
|
3bd76b4fb5 | ||
|
|
3fb4ef34f4 | ||
|
|
f7c2abdcd7 | ||
|
|
cc6006e226 | ||
|
|
2816c2bcf5 | ||
|
|
abc8061cd7 | ||
|
|
a30c4d6be5 | ||
|
|
0bd5b6ba5d | ||
|
|
4ea3a500e8 | ||
|
|
56925c1eed | ||
|
|
71e7269927 | ||
|
|
6babff1be1 | ||
|
|
fec000086f | ||
|
|
bddf4cedb4 | ||
|
|
91c62e208b | ||
|
|
1e0424a83f | ||
|
|
c74d29e020 | ||
|
|
eadfff9cd0 | ||
|
|
93e30a8542 | ||
|
|
ae8727ad96 | ||
|
|
de823f0430 | ||
|
|
c6ced0b1ea |
@@ -1,9 +1,9 @@
|
|||||||
lua-scripts
|
lua-scripts
|
||||||
===========
|
===========
|
||||||
|
|
||||||
The Lua scripts in this repository are meant to be used together with darktable. Either copy them individually to `~/.config/darktable/lua` (you might have to create that folder) or just copy/symlink the whole repository there. That allows to update all your scripts with a simple call to `git pull`.
|
The Lua scripts in this repository are meant to be used together with darktable. Either copy them individually to `~/.config/darktable/lua` (Linux/Unix) or `%LOCALAPPDATA%\darktable\lua` (Windows) (you might have to create that folder) or just copy/symlink the whole repository there. That allows to update all your scripts with a simple call to `git pull`.
|
||||||
|
|
||||||
To enable one of the scripts you have to add a line like `require "official/hello_world"` to your `~/.config/darktable/luarc` file which will enable the example script in `official/hello_world.lua` (note the lack of the `.lua` suffix).
|
To enable one of the scripts you have to add a line like `require "examples/hello_world"` to your: `~/.config/darktable/luarc` (Linux/Unix) or `%LOCALAPPDATA%\darktable\luarc` (Windows) file which will enable the example script in `examples/hello_world.lua` (note the lack of the `.lua` suffix).
|
||||||
|
|
||||||
Each script includes its own documentation and usage in its header, please refer to them.
|
Each script includes its own documentation and usage in its header, please refer to them.
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,8 @@ USAGE
|
|||||||
> exiftool -AutoDynamicRange XE021351.RAF
|
> exiftool -AutoDynamicRange XE021351.RAF
|
||||||
Auto Dynamic Range : 200%
|
Auto Dynamic Range : 200%
|
||||||
|
|
||||||
|
ADDITIONAL SOFTWARE NEEDED FOR THIS SCRIPT
|
||||||
|
* exiftool
|
||||||
|
|
||||||
LICENSE
|
LICENSE
|
||||||
GPLv2
|
GPLv2
|
||||||
@@ -41,7 +43,7 @@ local darktable = require "darktable"
|
|||||||
local autostyle_apply_one_image,autostyle_apply_one_image_event,autostyle_apply,exiftool_attribute,capture
|
local autostyle_apply_one_image,autostyle_apply_one_image_event,autostyle_apply,exiftool_attribute,capture
|
||||||
|
|
||||||
-- Tested it with darktable 1.6.1 and darktable git from 2014-01-25
|
-- Tested it with darktable 1.6.1 and darktable git from 2014-01-25
|
||||||
darktable.configuration.check_version(...,{2,0,2},{2,1,0},{3,0,0})
|
darktable.configuration.check_version(...,{2,0,2},{2,1,0},{3,0,0},{4,0,0},{5,0,0})
|
||||||
|
|
||||||
-- Receive the event triggered
|
-- Receive the event triggered
|
||||||
function autostyle_apply_one_image_event(event,image)
|
function autostyle_apply_one_image_event(event,image)
|
||||||
@@ -66,6 +68,10 @@ function autostyle_apply_one_image (image)
|
|||||||
darktable.print("style name not found in " .. darktable.preferences.read("autostyle","exif_tag","string"))
|
darktable.print("style name not found in " .. darktable.preferences.read("autostyle","exif_tag","string"))
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
if not checkIfBinExists("exiftool") then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
-- First find the style (we have its name)
|
-- First find the style (we have its name)
|
||||||
local styles= darktable.styles
|
local styles= darktable.styles
|
||||||
|
|||||||
@@ -1,106 +0,0 @@
|
|||||||
--[[
|
|
||||||
This file is part of darktable,
|
|
||||||
Copyright 2014-2016 by Tobias Jakobs.
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation; either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
]]
|
|
||||||
--[[
|
|
||||||
darktable calc distance script
|
|
||||||
|
|
||||||
This script calcs the distance between two images using the GPS data in the metadata
|
|
||||||
|
|
||||||
USAGE
|
|
||||||
* require this script from your main lua file
|
|
||||||
* register a shortcut
|
|
||||||
]]
|
|
||||||
|
|
||||||
local dt = require "darktable"
|
|
||||||
local gettext = dt.gettext
|
|
||||||
dt.configuration.check_version(...,{3,0,0})
|
|
||||||
|
|
||||||
-- Tell gettext where to find the .mo file translating messages for a particular domain
|
|
||||||
gettext.bindtextdomain("calcDistance",dt.configuration.config_dir.."/lua/")
|
|
||||||
|
|
||||||
local function _(msgid)
|
|
||||||
return gettext.dgettext("calcDistance", msgid)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function calcDistance()
|
|
||||||
local sel_images = dt.gui.selection()
|
|
||||||
|
|
||||||
local lat1 = 0;
|
|
||||||
local lon1 = 0;
|
|
||||||
local lat2 = 0;
|
|
||||||
local lon2 = 0;
|
|
||||||
local ele1 = 0;
|
|
||||||
local ele2 = 0;
|
|
||||||
|
|
||||||
local i = 0;
|
|
||||||
|
|
||||||
local sel_images = dt.gui.selection()
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
i = i + 1;
|
|
||||||
|
|
||||||
if (i == 1) then
|
|
||||||
lat1 = image.latitude;
|
|
||||||
lon1 = image.longitude;
|
|
||||||
ele1 = image.elevation;
|
|
||||||
end
|
|
||||||
|
|
||||||
lat2 = image.latitude;
|
|
||||||
lon2 = image.longitude;
|
|
||||||
ele2 = image.elevation;
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- I used code from here:
|
|
||||||
-- http://stackoverflow.com/questions/27928/how-do-i-calculate-distance-between-two-latitude-longitude-points
|
|
||||||
|
|
||||||
local earthRadius = 6371; -- Radius of the earth in km
|
|
||||||
local dLat = math.rad(lat2-lat1); -- deg2rad below
|
|
||||||
local dLon = math.rad(lon2-lon1);
|
|
||||||
local a =
|
|
||||||
math.sin(dLat/2) * math.sin(dLat/2) +
|
|
||||||
math.cos(math.rad(lat1)) * math.cos(math.rad(lat2)) *
|
|
||||||
math.sin(dLon/2) * math.sin(dLon/2)
|
|
||||||
;
|
|
||||||
local angle = 2 * math.atan2(math.sqrt(a), math.sqrt(1-a));
|
|
||||||
local distance = earthRadius * angle; -- Distance in km
|
|
||||||
|
|
||||||
-- Add the elevation to the calculation
|
|
||||||
local elevation = 0;
|
|
||||||
elevation = math.abs(ele1 - ele2) / 1000; --in km
|
|
||||||
distance = math.sqrt(math.pow(elevation,2) + math.pow(distance,2) );
|
|
||||||
|
|
||||||
local distanceUnit
|
|
||||||
if (distance < 1) then
|
|
||||||
distance = distance * 1000
|
|
||||||
distanceUnit = "m"
|
|
||||||
else
|
|
||||||
distanceUnit = "km"
|
|
||||||
end
|
|
||||||
dt.print(string.format("Distance: %.2f %s", distance, distanceUnit))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Register
|
|
||||||
dt.register_event("shortcut",calcDistance,_("Calculate the distance from latitude and longitude in km"))
|
|
||||||
@@ -42,11 +42,11 @@ local gettext = dt.gettext
|
|||||||
-- not a number
|
-- not a number
|
||||||
local NaN = 0/0
|
local NaN = 0/0
|
||||||
|
|
||||||
dt.configuration.check_version(...,{3,0,0})
|
dt.configuration.check_version(...,{3,0,0},{4,0,0})
|
||||||
|
|
||||||
|
|
||||||
-- Tell gettext where to find the .mo file translating messages for a particular domain
|
-- Tell gettext where to find the .mo file translating messages for a particular domain
|
||||||
gettext.bindtextdomain("clear_GPS",dt.configuration.config_dir.."/lua/")
|
gettext.bindtextdomain("clear_GPS",dt.configuration.config_dir.."/lua/locale/")
|
||||||
|
|
||||||
local function _(msgid)
|
local function _(msgid)
|
||||||
return gettext.dgettext("clear_GPS", msgid)
|
return gettext.dgettext("clear_GPS", msgid)
|
||||||
|
|||||||
@@ -33,15 +33,17 @@ USAGE
|
|||||||
darktable internal tags starting with 'darktable|' will not be touched
|
darktable internal tags starting with 'darktable|' will not be touched
|
||||||
* <your shortcut3> removes all expect darktable internal tags from selected images
|
* <your shortcut3> removes all expect darktable internal tags from selected images
|
||||||
* <your shortcut4> replaces all tags expect darktable internals
|
* <your shortcut4> replaces all tags expect darktable internals
|
||||||
|
* A module reset will empty the clipboard
|
||||||
]]
|
]]
|
||||||
|
|
||||||
local dt = require "darktable"
|
local dt = require "darktable"
|
||||||
|
local debug = require "darktable.debug"
|
||||||
|
|
||||||
local gettext = dt.gettext
|
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
|
-- Tell gettext where to find the .mo file translating messages for a particular domain
|
||||||
gettext.bindtextdomain("copy_attach_detach_tags",dt.configuration.config_dir.."/lua/")
|
gettext.bindtextdomain("copy_attach_detach_tags",dt.configuration.config_dir.."/lua/locale/")
|
||||||
|
|
||||||
local function _(msgid)
|
local function _(msgid)
|
||||||
return gettext.dgettext("copy_attach_detach_tags", msgid)
|
return gettext.dgettext("copy_attach_detach_tags", msgid)
|
||||||
@@ -156,43 +158,58 @@ end
|
|||||||
taglist_label.reset_callback = mcopy_tags
|
taglist_label.reset_callback = mcopy_tags
|
||||||
|
|
||||||
-- create buttons and elements
|
-- create buttons and elements
|
||||||
local mc_button = dt.new_widget("button") {
|
|
||||||
label = _('multi copy tags'),
|
|
||||||
clicked_callback = mcopy_tags}
|
|
||||||
|
|
||||||
local p_button = dt.new_widget("button") {
|
|
||||||
label = _('paste tags'),
|
|
||||||
clicked_callback = attach_tags}
|
|
||||||
|
|
||||||
local rep_button = dt.new_widget("button") {
|
|
||||||
label = _('replace tags'),
|
|
||||||
clicked_callback = replace_tags}
|
|
||||||
|
|
||||||
local rem_button = dt.new_widget("button") {
|
|
||||||
label = _('remove all tags'),
|
|
||||||
clicked_callback = detach_tags}
|
|
||||||
|
|
||||||
local taglabel = dt.new_widget("label") {
|
local taglabel = dt.new_widget("label") {
|
||||||
label = _('tag clipboard'),
|
label = _('tag clipboard'),
|
||||||
selectable = false,
|
selectable = false,
|
||||||
ellipsize = "middle",
|
ellipsize = "middle",
|
||||||
halign = "start"}
|
halign = "start"}
|
||||||
|
|
||||||
|
local box1 = dt.new_widget("box"){
|
||||||
|
orientation = "horizontal",
|
||||||
|
dt.new_widget("button") {
|
||||||
|
label = _('multi copy tags'),
|
||||||
|
clicked_callback = mcopy_tags},
|
||||||
|
dt.new_widget("button") {
|
||||||
|
label = _('paste tags'),
|
||||||
|
clicked_callback = attach_tags}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
local box2 = dt.new_widget("box"){
|
||||||
|
orientation = "horizontal",
|
||||||
|
dt.new_widget("button") {
|
||||||
|
label = _('replace tags'),
|
||||||
|
clicked_callback = replace_tags},
|
||||||
|
dt.new_widget("button") {
|
||||||
|
label = _('remove all tags'),
|
||||||
|
clicked_callback = detach_tags}
|
||||||
|
}
|
||||||
|
|
||||||
|
local sep = dt.new_widget("separator"){}
|
||||||
|
|
||||||
|
-- pack elements into widget table for a nicer layout
|
||||||
|
local widget_table = {}
|
||||||
|
|
||||||
|
widget_table[1] = box1
|
||||||
|
widget_table[#widget_table+1] = box2
|
||||||
|
|
||||||
|
widget_table[#widget_table+1] = sep
|
||||||
|
widget_table[#widget_table+1] = taglabel
|
||||||
|
widget_table[#widget_table+1] = taglist_label
|
||||||
|
|
||||||
|
|
||||||
-- create modul
|
-- create modul
|
||||||
dt.register_lib("tagging_addon","Tagging addon",true,false,{
|
dt.register_lib("tagging_addon","Tagging addon",true,true,{
|
||||||
[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER",500}
|
[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER",500}
|
||||||
},
|
},
|
||||||
dt.new_widget("box") {
|
dt.new_widget("box") {
|
||||||
orientation = "vertical",
|
-- orientation = "vertical",
|
||||||
mc_button,
|
reset_callback = function()
|
||||||
p_button,
|
taglist_label.label = ""
|
||||||
rep_button,
|
image_tags = {}
|
||||||
rem_button,
|
end,
|
||||||
taglabel,
|
table.unpack(widget_table),
|
||||||
dt.new_widget("separator"){},
|
},
|
||||||
taglist_label
|
|
||||||
},
|
|
||||||
nil,
|
nil,
|
||||||
nil
|
nil
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ USAGE
|
|||||||
local darktable = require "darktable"
|
local darktable = require "darktable"
|
||||||
|
|
||||||
-- Tested with darktable 2.0.1
|
-- Tested with darktable 2.0.1
|
||||||
darktable.configuration.check_version(...,{2,0,0},{3,0,0})
|
darktable.configuration.check_version(...,{2,0,0},{3,0,0},{4,0,0})
|
||||||
|
|
||||||
local queue = {}
|
local queue = {}
|
||||||
local processed_files = {}
|
local processed_files = {}
|
||||||
|
|||||||
70
contrib/fujifilm_ratings.lua
Normal file
70
contrib/fujifilm_ratings.lua
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
--[[ fujifilm_ratings-0.1
|
||||||
|
|
||||||
|
Support for importing Fujifilm in-camera ratings in darktable.
|
||||||
|
|
||||||
|
Copyright (C) 2017 Ben Mendis <ben.mendis@gmail.com>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
Dependencies:
|
||||||
|
- exiftool (https://www.sno.phy.queensu.ca/~phil/exiftool/)
|
||||||
|
|
||||||
|
--]]
|
||||||
|
|
||||||
|
local dt = require "darktable"
|
||||||
|
local df = require "lib/dtutils.file"
|
||||||
|
local gettext = dt.gettext
|
||||||
|
|
||||||
|
dt.configuration.check_version(..., {4,0,0})
|
||||||
|
|
||||||
|
gettext.bindtextdomain("fujifilm_ratings", dt.configuration.config_dir.."/lua/locale/")
|
||||||
|
|
||||||
|
local function _(msgid)
|
||||||
|
return gettext.dgettext("fujifilm_ratings", msgid)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function detect_rating(event, image)
|
||||||
|
if not df.check_if_bin_exists("exiftool") then
|
||||||
|
dt.print_error(_("exiftool not found"))
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local RAF_filename = tostring(image)
|
||||||
|
local JPEG_filename = string.gsub(RAF_filename, "%.RAF$", ".JPG")
|
||||||
|
local command = "exiftool -Rating " .. JPEG_filename
|
||||||
|
dt.print_error(command)
|
||||||
|
local output = io.popen(command)
|
||||||
|
local jpeg_result = output:read("*all")
|
||||||
|
output:close()
|
||||||
|
if string.len(jpeg_result) > 0 then
|
||||||
|
jpeg_result = string.gsub(jpeg_result, "^Rating.*(%d)", "%1")
|
||||||
|
image.rating = tonumber(jpeg_result)
|
||||||
|
dt.print_error(_("Using JPEG Rating: ") .. tostring(jpeg_result))
|
||||||
|
return
|
||||||
|
end
|
||||||
|
command = "exiftool -Rating " .. RAF_filename
|
||||||
|
dt.print_error(command)
|
||||||
|
output = io.popen(command)
|
||||||
|
local raf_result = output:read("*all")
|
||||||
|
output:close()
|
||||||
|
if string.len(raf_result) > 0 then
|
||||||
|
raf_result = string.gsub(raf_result, "^Rating.*(%d)", "%1")
|
||||||
|
image.rating = tonumber(raf_result)
|
||||||
|
dt.print_error(_("Using RAF Rating: ") .. tostring(raf_result))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
dt.register_event("post-import-image", detect_rating)
|
||||||
|
|
||||||
|
print(_("fujifilm_ratings loaded."))
|
||||||
@@ -33,13 +33,14 @@ USAGE
|
|||||||
]]
|
]]
|
||||||
|
|
||||||
local dt = require "darktable"
|
local dt = require "darktable"
|
||||||
|
local df = require "lib/dtutils.file"
|
||||||
require "official/yield"
|
require "official/yield"
|
||||||
|
|
||||||
local gettext = dt.gettext
|
local gettext = dt.gettext
|
||||||
dt.configuration.check_version(...,{3,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
|
-- Tell gettext where to find the .mo file translating messages for a particular domain
|
||||||
gettext.bindtextdomain("geoJSON_export",dt.configuration.config_dir.."/lua/")
|
gettext.bindtextdomain("geoJSON_export",dt.configuration.config_dir.."/lua/locale/")
|
||||||
|
|
||||||
local function _(msgid)
|
local function _(msgid)
|
||||||
return gettext.dgettext("geoJSON_export", msgid)
|
return gettext.dgettext("geoJSON_export", msgid)
|
||||||
@@ -73,37 +74,27 @@ local function show_status(storage, image, format, filename, number, total, high
|
|||||||
dt.print(string.format(_("Export Image %i/%i"), number, total))
|
dt.print(string.format(_("Export Image %i/%i"), number, total))
|
||||||
end
|
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)
|
local function create_geoJSON_file(storage, image_table, extra_data)
|
||||||
|
if not df.check_if_bin_exists("mkdir") then
|
||||||
if not checkIfBinExists("mkdir") then
|
dt.print_error(_("mkdir not found"))
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
if not checkIfBinExists("convert") then
|
if not df.check_if_bin_exists("convert") then
|
||||||
|
dt.print_error(_("convert not found"))
|
||||||
return
|
return
|
||||||
end
|
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
|
return
|
||||||
end
|
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
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
dt.print_error("Will try to export geoJSON file now")
|
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
|
-- Creates dir if not exsists
|
||||||
local imageFoldername = "files/"
|
local imageFoldername = "files/"
|
||||||
@@ -115,8 +106,8 @@ local function create_geoJSON_file(storage, image_table, extra_data)
|
|||||||
if ((image.longitude and image.latitude) and
|
if ((image.longitude and image.latitude) and
|
||||||
(image.longitude ~= 0 and image.latitude ~= 90) -- Sometimes the north-pole but most likely just wrong data
|
(image.longitude ~= 0 and image.latitude ~= 90) -- Sometimes the north-pole but most likely just wrong data
|
||||||
) then
|
) then
|
||||||
local path, filename, filetype = string.match(image, "(.-)([^\\/]-%.?([^%.\\/]*))$")
|
local path, filename, filetype = string.match(exported_image, "(.-)([^\\/]-%.?([^%.\\/]*))$")
|
||||||
filename = string.upper(string.gsub(filename,"%.", "_"))
|
filename = string.upper(string.gsub(filename,"%.%w*", ""))
|
||||||
|
|
||||||
-- convert -size 92x92 filename.jpg -resize 92x92 +profile "*" thumbnail.jpg
|
-- 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
|
-- In this example, '-size 120x120' gives a hint to the JPEG decoder that the image is going to be downscaled to
|
||||||
@@ -131,8 +122,8 @@ local function create_geoJSON_file(storage, image_table, extra_data)
|
|||||||
dt.control.execute( concertCommand)
|
dt.control.execute( concertCommand)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- delete the original image to not get into the kmz file
|
-- delete the original image
|
||||||
os.remove(image)
|
os.remove(exported_image)
|
||||||
|
|
||||||
local pattern = "[/]?([^/]+)$"
|
local pattern = "[/]?([^/]+)$"
|
||||||
filmName = string.match(image.film.path, pattern)
|
filmName = string.match(image.film.path, pattern)
|
||||||
@@ -149,11 +140,24 @@ local function create_geoJSON_file(storage, image_table, extra_data)
|
|||||||
]]
|
]]
|
||||||
|
|
||||||
for image,exported_image in pairs(image_table) do
|
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
|
if ((image.longitude and image.latitude) and
|
||||||
(image.longitude ~= 0 and image.latitude ~= 90) -- Sometimes the north-pole but most likely just wrong data
|
(image.longitude ~= 0 and image.latitude ~= 90) -- Sometimes the north-pole but most likely just wrong data
|
||||||
) then
|
) then
|
||||||
|
|
||||||
|
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..
|
geoJSON_file = geoJSON_file..
|
||||||
[[ {
|
[[ {
|
||||||
"type": "Feature",
|
"type": "Feature",
|
||||||
@@ -164,8 +168,8 @@ local function create_geoJSON_file(storage, image_table, extra_data)
|
|||||||
geoJSON_file = geoJSON_file..
|
geoJSON_file = geoJSON_file..
|
||||||
[[ },
|
[[ },
|
||||||
"properties": {
|
"properties": {
|
||||||
"title": "]]..image.title..[[",
|
"title": "]]..image_title..[[",
|
||||||
"description": "]]..image.description..[[",
|
"description": "]]..image_description..[[",
|
||||||
"image": "]]..imageFoldername..filename..[[.jpg",
|
"image": "]]..imageFoldername..filename..[[.jpg",
|
||||||
"icon": {
|
"icon": {
|
||||||
"iconUrl": "]]..imageFoldername.."thumb_"..filename..[[.jpg",
|
"iconUrl": "]]..imageFoldername.."thumb_"..filename..[[.jpg",
|
||||||
@@ -196,7 +200,7 @@ local function create_geoJSON_file(storage, image_table, extra_data)
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset=utf-8 />
|
<meta charset=utf-8 />
|
||||||
<title>2014-05-31 Rieselfelder</title>
|
<title>]]..filmName..[[</title>
|
||||||
<script src='https://api.tiles.mapbox.com/mapbox.js/v2.2.4/mapbox.js'></script>
|
<script src='https://api.tiles.mapbox.com/mapbox.js/v2.2.4/mapbox.js'></script>
|
||||||
<link href='https://api.tiles.mapbox.com/mapbox.js/v2.2.4/mapbox.css' rel='stylesheet' />
|
<link href='https://api.tiles.mapbox.com/mapbox.js/v2.2.4/mapbox.css' rel='stylesheet' />
|
||||||
<style>
|
<style>
|
||||||
@@ -310,6 +314,9 @@ dt.preferences.register("geoJSON_export",
|
|||||||
local handle = io.popen("xdg-user-dir DESKTOP")
|
local handle = io.popen("xdg-user-dir DESKTOP")
|
||||||
local result = handle:read()
|
local result = handle:read()
|
||||||
handle:close()
|
handle:close()
|
||||||
|
if (result == nil) then
|
||||||
|
result = ""
|
||||||
|
end
|
||||||
dt.preferences.register("geoJSON_export",
|
dt.preferences.register("geoJSON_export",
|
||||||
"ExportDirectory",
|
"ExportDirectory",
|
||||||
"directory",
|
"directory",
|
||||||
|
|||||||
687
contrib/geoToolbox.lua
Normal file
687
contrib/geoToolbox.lua
Normal file
@@ -0,0 +1,687 @@
|
|||||||
|
--[[
|
||||||
|
This file is part of darktable,
|
||||||
|
copyright (c) 2016 Tobias Jakobs
|
||||||
|
|
||||||
|
darktable is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
darktable is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with darktable. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
]]
|
||||||
|
--[[
|
||||||
|
|
||||||
|
USAGE
|
||||||
|
* require this script from your main lua file
|
||||||
|
To do this add this line to the file .config/darktable/luarc:
|
||||||
|
require "geoToolbox"
|
||||||
|
|
||||||
|
* it creates a new geoToolbox lighttable module
|
||||||
|
]]
|
||||||
|
|
||||||
|
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})
|
||||||
|
|
||||||
|
-- Tell gettext where to find the .mo file translating messages for a particular domain
|
||||||
|
gettext.bindtextdomain("geoToolbox",dt.configuration.config_dir.."/lua/locale/")
|
||||||
|
|
||||||
|
local function _(msgid)
|
||||||
|
return gettext.dgettext("geoToolbox", msgid)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- <GUI>
|
||||||
|
local labelDistance = dt.new_widget("label")
|
||||||
|
labelDistance.label = _("Distance:")
|
||||||
|
|
||||||
|
local label_copy_gps_lat = dt.new_widget("check_button")
|
||||||
|
{
|
||||||
|
label = _("latitude:"),
|
||||||
|
value = true
|
||||||
|
}
|
||||||
|
local label_copy_gps_lon = dt.new_widget("check_button")
|
||||||
|
{
|
||||||
|
label = _("longitude:"),
|
||||||
|
value = true
|
||||||
|
}
|
||||||
|
local label_copy_gps_ele = dt.new_widget("check_button")
|
||||||
|
{
|
||||||
|
label = _("elevation:"),
|
||||||
|
value = true
|
||||||
|
}
|
||||||
|
-- </GUI>
|
||||||
|
|
||||||
|
local function select_with_gps()
|
||||||
|
local selection = {}
|
||||||
|
job = dt.gui.create_job(_("GPS selection"), true, stop_selection)
|
||||||
|
|
||||||
|
for key,image in ipairs(dt.collection) do
|
||||||
|
if job.valid then
|
||||||
|
job.percent = (key-1)/#dt.collection
|
||||||
|
|
||||||
|
if (image.longitude and image.latitude) then
|
||||||
|
table.insert(selection,image)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
dt.gui.selection(selection)
|
||||||
|
job.valid = false
|
||||||
|
end
|
||||||
|
|
||||||
|
local function select_without_gps()
|
||||||
|
local selection = {}
|
||||||
|
job = dt.gui.create_job(_("GPS selection"), true, stop_selection)
|
||||||
|
|
||||||
|
for key,image in ipairs(dt.collection) do
|
||||||
|
if job.valid then
|
||||||
|
job.percent = (key-1)/#dt.collection
|
||||||
|
|
||||||
|
if (not image.longitude and not image.latitude) then
|
||||||
|
table.insert(selection,image)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
dt.gui.selection(selection)
|
||||||
|
job.valid = false
|
||||||
|
end
|
||||||
|
|
||||||
|
local function stop_selection(job)
|
||||||
|
job.valid = false
|
||||||
|
end
|
||||||
|
|
||||||
|
-- This is used for older images in the DB
|
||||||
|
function isnan(x) return x ~= x end
|
||||||
|
|
||||||
|
-- Function from:
|
||||||
|
-- https://forums.coronalabs.com/topic/29019-convert-string-to-date/
|
||||||
|
-- This looks much scarier than it really is. The goal is to turn that string
|
||||||
|
-- into a Unix timestamp (number of seconds since Jan 1, 1970, the standard
|
||||||
|
-- used by most systems). So we use the string.match() method to fetch the
|
||||||
|
-- various date and time parts into their own variables: xyear, xmonth,etc.
|
||||||
|
function make_time_stamp(dateString)
|
||||||
|
local convertedTimestamp
|
||||||
|
--dt.print_error(dateString)
|
||||||
|
if (dateString) then
|
||||||
|
local pattern = "(%d+)%:(%d+)%:(%d+) (%d+):(%d+):(%d+)"
|
||||||
|
local xyear, xmonth, xday, xhour, xminute, xseconds = dateString:match(pattern)
|
||||||
|
--dt.print_error(xyear)
|
||||||
|
convertedTimestamp = os.time({
|
||||||
|
year = xyear,
|
||||||
|
month = xmonth,
|
||||||
|
day = xday,
|
||||||
|
hour = xhour,
|
||||||
|
min = xminute,
|
||||||
|
sec = xseconds})
|
||||||
|
else
|
||||||
|
convertedTimestamp = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
return convertedTimestamp
|
||||||
|
end
|
||||||
|
|
||||||
|
local first_have_data = false
|
||||||
|
local first_latitude = ''
|
||||||
|
local first_longitude = ''
|
||||||
|
local first_elevation = ''
|
||||||
|
local first_image_date = 0
|
||||||
|
|
||||||
|
local function get_first_coordinate()
|
||||||
|
local sel_images = dt.gui.action_images
|
||||||
|
|
||||||
|
first_latitude = ''
|
||||||
|
first_longitude = ''
|
||||||
|
first_elevation = ''
|
||||||
|
first_image_date = 0
|
||||||
|
|
||||||
|
for _,image in ipairs(sel_images) do
|
||||||
|
if not image then
|
||||||
|
first_have_data = false
|
||||||
|
else
|
||||||
|
image_date = image.exif_datetime_taken
|
||||||
|
first_have_data = true
|
||||||
|
if (image.latitude) then
|
||||||
|
first_latitude = image.latitude
|
||||||
|
end
|
||||||
|
if (image.longitude) then
|
||||||
|
first_longitude = image.longitude
|
||||||
|
end
|
||||||
|
if (image.elevation) then
|
||||||
|
first_elevation = image.elevation
|
||||||
|
end
|
||||||
|
if (image.exif_datetime_taken) then
|
||||||
|
first_image_date = make_time_stamp(image.exif_datetime_taken)
|
||||||
|
--dt.print_error(image.exif_datetime_taken)
|
||||||
|
--dt.print_error(first_image_date)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local second_have_data = false
|
||||||
|
local second_latitude = ''
|
||||||
|
local second_longitude = ''
|
||||||
|
local second_elevation = ''
|
||||||
|
local second_image_date = 0
|
||||||
|
|
||||||
|
local function get_second_coordinate()
|
||||||
|
local sel_images = dt.gui.action_images
|
||||||
|
|
||||||
|
second_latitude = ''
|
||||||
|
second_longitude = ''
|
||||||
|
second_elevation = ''
|
||||||
|
second_image_date = 0
|
||||||
|
|
||||||
|
for _,image in ipairs(sel_images) do
|
||||||
|
if not image then
|
||||||
|
second_have_data = false
|
||||||
|
else
|
||||||
|
image_date = image.exif_datetime_taken
|
||||||
|
second_have_data = true
|
||||||
|
if (image.latitude) then
|
||||||
|
second_latitude = image.latitude
|
||||||
|
end
|
||||||
|
if (image.longitude) then
|
||||||
|
second_longitude = image.longitude
|
||||||
|
end
|
||||||
|
if (image.elevation) then
|
||||||
|
second_elevation = image.elevation
|
||||||
|
end
|
||||||
|
if (image.exif_datetime_taken) then
|
||||||
|
second_image_date = make_time_stamp(image.exif_datetime_taken)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local calc_in_between_slider = dt.new_widget("slider")
|
||||||
|
{
|
||||||
|
label = "Position between",
|
||||||
|
soft_min = 0, -- The soft minimum value for the slider, the slider can't go beyond this point
|
||||||
|
soft_max = 100, -- The soft maximum value for the slider, the slider can't go beyond this point
|
||||||
|
hard_min = -100, -- The hard minimum value for the slider, the user can't manually enter a value beyond this point
|
||||||
|
hard_max = 200, -- The hard maximum value for the slider, the user can't manually enter a value beyond this point
|
||||||
|
value = 50 -- The current value of the slider
|
||||||
|
}
|
||||||
|
|
||||||
|
--ToDo: this needs more love
|
||||||
|
local function calc_in_between()
|
||||||
|
local sel_images = dt.gui.action_images
|
||||||
|
for _,image in ipairs(sel_images) do
|
||||||
|
if image then
|
||||||
|
image_date = make_time_stamp(image.exif_datetime_taken)
|
||||||
|
if (first_have_data and second_have_data) then
|
||||||
|
local start_new = 0
|
||||||
|
local end_new = second_image_date - first_image_date
|
||||||
|
local image_date_new = image_date - first_image_date
|
||||||
|
|
||||||
|
local percent_in_between
|
||||||
|
if (end_new == 0) then
|
||||||
|
percent_in_between = 1
|
||||||
|
else
|
||||||
|
percent_in_between = image_date_new/end_new
|
||||||
|
end
|
||||||
|
calc_in_between_slider.value = percent_in_between * 100
|
||||||
|
dt.print_error(percent_in_between)
|
||||||
|
local in_between_latitude = first_latitude + (second_latitude - first_latitude) * percent_in_between
|
||||||
|
local in_between_longitude = first_longitude + (second_longitude - first_longitude) * percent_in_between
|
||||||
|
|
||||||
|
if (first_elevation and second_elevation) then
|
||||||
|
local in_between_elevation = first_elevation + (second_elevation - first_elevation) * percent_in_between
|
||||||
|
|
||||||
|
dt.print_error(first_image_date)
|
||||||
|
dt.print_error(second_image_date)
|
||||||
|
dt.print_error(image_date)
|
||||||
|
dt.print_error(first_elevation)
|
||||||
|
dt.print_error(second_elevation)
|
||||||
|
dt.print_error(in_between_elevation)
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local copy_gps_have_data = false
|
||||||
|
local copy_gps_latitude = ''
|
||||||
|
local copy_gps_longitude = ''
|
||||||
|
local copy_gps_elevation = ''
|
||||||
|
|
||||||
|
local function copy_gps()
|
||||||
|
local sel_images = dt.gui.action_images
|
||||||
|
|
||||||
|
copy_gps_latitude = ''
|
||||||
|
copy_gps_longitude = ''
|
||||||
|
copy_gps_elevation = ''
|
||||||
|
|
||||||
|
for _,image in ipairs(sel_images) do
|
||||||
|
if not image then
|
||||||
|
copy_gps_have_data = false
|
||||||
|
else
|
||||||
|
copy_gps_have_data = true
|
||||||
|
if (image.latitude and label_copy_gps_lat.value) then
|
||||||
|
copy_gps_latitude = image.latitude
|
||||||
|
end
|
||||||
|
if (image.longitude and label_copy_gps_lon.value) then
|
||||||
|
copy_gps_longitude = image.longitude
|
||||||
|
end
|
||||||
|
if (image.elevation and label_copy_gps_ele.value) then
|
||||||
|
copy_gps_elevation = image.elevation
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
label_copy_gps_lat.label = _("latitude: ") .. copy_gps_latitude
|
||||||
|
label_copy_gps_lon.label = _("longitude: ") ..copy_gps_longitude
|
||||||
|
label_copy_gps_ele.label = _("elevation: ") .. copy_gps_elevation
|
||||||
|
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function paste_gps(image)
|
||||||
|
local sel_images = dt.gui.action_images
|
||||||
|
|
||||||
|
for _,image in ipairs(sel_images) do
|
||||||
|
if (label_copy_gps_lat.value) then
|
||||||
|
image.latitude = copy_gps_latitude
|
||||||
|
end
|
||||||
|
if (label_copy_gps_lon.value) then
|
||||||
|
image.longitude = copy_gps_longitude
|
||||||
|
end
|
||||||
|
if (label_copy_gps_ele.value) then
|
||||||
|
image.elevation = copy_gps_elevation
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function open_location_in_gnome_maps()
|
||||||
|
|
||||||
|
if not df.check_if_bin_exists("gnome-maps") then
|
||||||
|
dt.print_error(_("gnome-maps not found"))
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local sel_images = dt.gui.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
|
||||||
|
startCommand = "gnome-maps \"geo:" .. lat1 .. "," .. lon1 .."\""
|
||||||
|
dt.print_error(startCommand)
|
||||||
|
|
||||||
|
dt.control.execute(startCommand)
|
||||||
|
|
||||||
|
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
|
||||||
|
local function get_distance(lat1, lon1, ele1, lat2, lon2, ele2)
|
||||||
|
|
||||||
|
local earthRadius = 6371; -- Radius of the earth in km
|
||||||
|
local dLat = math.rad(lat2-lat1); -- deg2rad below
|
||||||
|
local dLon = math.rad(lon2-lon1);
|
||||||
|
local a =
|
||||||
|
math.sin(dLat/2) * math.sin(dLat/2) +
|
||||||
|
math.cos(math.rad(lat1)) * math.cos(math.rad(lat2)) *
|
||||||
|
math.sin(dLon/2) * math.sin(dLon/2)
|
||||||
|
;
|
||||||
|
local angle = 2 * math.atan2(math.sqrt(a), math.sqrt(1-a));
|
||||||
|
local distance = earthRadius * angle; -- Distance in km
|
||||||
|
|
||||||
|
-- Add the elevation to the calculation
|
||||||
|
local elevation = 0
|
||||||
|
elevation = math.abs(ele1 - ele2) / 1000; --in km
|
||||||
|
|
||||||
|
if (elevation > 0) then
|
||||||
|
distance = math.sqrt(math.pow(elevation,2) + math.pow(distance,2) )
|
||||||
|
end
|
||||||
|
return distance
|
||||||
|
end
|
||||||
|
|
||||||
|
local function calc_distance()
|
||||||
|
|
||||||
|
local lat1 = 0;
|
||||||
|
local lon1 = 0;
|
||||||
|
local lat2 = 0;
|
||||||
|
local lon2 = 0;
|
||||||
|
local ele1 = 0;
|
||||||
|
local ele2 = 0;
|
||||||
|
local i = 0;
|
||||||
|
|
||||||
|
local sel_images = dt.gui.selection()
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
i = i + 1;
|
||||||
|
|
||||||
|
if (i == 1) then
|
||||||
|
lat1 = image.latitude
|
||||||
|
lon1 = image.longitude
|
||||||
|
if (image.elevation) then
|
||||||
|
ele1 = image.elevation
|
||||||
|
else
|
||||||
|
ele1 = 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
lat2 = image.latitude
|
||||||
|
lon2 = image.longitude
|
||||||
|
if (image.elevation) then
|
||||||
|
ele2 = image.elevation
|
||||||
|
else
|
||||||
|
ele2 = 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local distance = get_distance(lat1, lon1, ele1, lat2, lon2, ele2)
|
||||||
|
|
||||||
|
if (distance < 1) then
|
||||||
|
distance = distance * 1000
|
||||||
|
distanceUnit = _("m")
|
||||||
|
else
|
||||||
|
distanceUnit = _("km")
|
||||||
|
end
|
||||||
|
|
||||||
|
return string.format(_("Distance: %.2f %s"), distance, distanceUnit)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function print_calc_distance()
|
||||||
|
dt.print(calc_distance())
|
||||||
|
end
|
||||||
|
|
||||||
|
local function toolbox_calc_distance()
|
||||||
|
labelDistance.label = calc_distance()
|
||||||
|
end
|
||||||
|
|
||||||
|
local altitude_file_chooser_button = dt.new_widget("file_chooser_button")
|
||||||
|
{
|
||||||
|
title = _("export altitude CSV"), -- The title of the window when choosing a file
|
||||||
|
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",
|
||||||
|
placeholder = "altitude.csv",
|
||||||
|
editable = true,
|
||||||
|
tooltip = _("Name of the exported file"),
|
||||||
|
reset_callback = function(self) self.text = "text" end
|
||||||
|
}
|
||||||
|
|
||||||
|
local function altitude_profile()
|
||||||
|
dt.print(_("Start export"))
|
||||||
|
local sel_images = dt.gui.action_images
|
||||||
|
|
||||||
|
local lat1 = 0;
|
||||||
|
local lon1 = 0;
|
||||||
|
local lat2 = 0;
|
||||||
|
local lon2 = 0;
|
||||||
|
local ele1 = 0;
|
||||||
|
local ele2 = 0;
|
||||||
|
local i = 0;
|
||||||
|
local csv_file = '';
|
||||||
|
csv_file = "km;m".."\n";
|
||||||
|
|
||||||
|
local distance = 0;
|
||||||
|
local distanceFromStart = 0;
|
||||||
|
local elevation = 0;
|
||||||
|
local elevationAdd = 0;
|
||||||
|
|
||||||
|
local sel_images = dt.gui.action_images
|
||||||
|
for _,image in ipairs(sel_images) do
|
||||||
|
if ((not isnan(image.longitude) and not isnan(image.latitude) and not isnan(image.elevation) and image.elevation) and
|
||||||
|
(image.longitude ~= 0 and image.latitude ~= 90) -- Sometimes the north-pole but most likely just wrong data
|
||||||
|
) then
|
||||||
|
|
||||||
|
i = i + 1;
|
||||||
|
|
||||||
|
if (i == 1) then
|
||||||
|
lat1 = image.latitude
|
||||||
|
lon1 = image.longitude
|
||||||
|
ele1 = image.elevation
|
||||||
|
else
|
||||||
|
lat1 = lat2
|
||||||
|
lon1 = lon2
|
||||||
|
ele1 = ele2
|
||||||
|
end
|
||||||
|
|
||||||
|
lat2 = image.latitude
|
||||||
|
lon2 = image.longitude
|
||||||
|
ele2 = image.elevation
|
||||||
|
|
||||||
|
if (i == 1) then
|
||||||
|
distanceFromStart = 0
|
||||||
|
else
|
||||||
|
local distance = get_distance(lat1, lon1, ele1, lat2, lon2, ele2)
|
||||||
|
distanceFromStart = distanceFromStart + distance;
|
||||||
|
end
|
||||||
|
|
||||||
|
csv_file = csv_file .. distanceFromStart..";"..image.elevation.."\n";
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end --for
|
||||||
|
|
||||||
|
local exportDirectory = altitude_file_chooser_button.value
|
||||||
|
local exportFilename = altitude_filename.text
|
||||||
|
if (exportFilename == '') then
|
||||||
|
exportFilename = altitude_filename.placeholder
|
||||||
|
end
|
||||||
|
file = io.open(exportDirectory.."/"..exportFilename, "w")
|
||||||
|
file:write(csv_file)
|
||||||
|
file:close()
|
||||||
|
dt.print(_("File created in ")..exportDirectory)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
"geo toolbox", -- name
|
||||||
|
true, -- expandable
|
||||||
|
false, -- resetable
|
||||||
|
{[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, -- containers
|
||||||
|
dt.new_widget("box")
|
||||||
|
{
|
||||||
|
orientation = "vertical",
|
||||||
|
dt.new_widget("button")
|
||||||
|
{
|
||||||
|
label = _("select geo images"),
|
||||||
|
tooltip = _("Select all images with GPS information"),
|
||||||
|
clicked_callback = select_with_gps
|
||||||
|
},
|
||||||
|
dt.new_widget("button")
|
||||||
|
{
|
||||||
|
label = _("select non-geo images"),
|
||||||
|
tooltip = _("Select all images without GPS information"),
|
||||||
|
clicked_callback = select_without_gps
|
||||||
|
},
|
||||||
|
separator,--------------------------------------------------------
|
||||||
|
dt.new_widget("button")
|
||||||
|
{
|
||||||
|
label = _("copy GPS data"),
|
||||||
|
tooltip = _("Copy GPS data"),
|
||||||
|
clicked_callback = copy_gps
|
||||||
|
},
|
||||||
|
label_copy_gps_lat,
|
||||||
|
label_copy_gps_lon,
|
||||||
|
label_copy_gps_ele,
|
||||||
|
dt.new_widget("button")
|
||||||
|
{
|
||||||
|
label = _("paste GPS data"),
|
||||||
|
tooltip = _("Paste GPS data"),
|
||||||
|
clicked_callback = paste_gps
|
||||||
|
},
|
||||||
|
separator2,--------------------------------------------------------
|
||||||
|
--ToDo: This need a better UI
|
||||||
|
--[[
|
||||||
|
dt.new_widget("button")
|
||||||
|
{
|
||||||
|
label = "get 1st coordinate",
|
||||||
|
tooltip = "Select first image and click this button",
|
||||||
|
clicked_callback = get_first_coordinate
|
||||||
|
},
|
||||||
|
dt.new_widget("button")
|
||||||
|
{
|
||||||
|
label = "get 2nd coordinate",
|
||||||
|
tooltip = "Select second image and click this button",
|
||||||
|
clicked_callback = get_second_coordinate
|
||||||
|
},
|
||||||
|
dt.new_widget("button")
|
||||||
|
{
|
||||||
|
label = "calc in between",
|
||||||
|
tooltip = "Select third image and click this button",
|
||||||
|
clicked_callback = calc_in_between
|
||||||
|
},
|
||||||
|
calc_in_between_slider,
|
||||||
|
separator3,--------------------------------------------------------
|
||||||
|
]]
|
||||||
|
dt.new_widget("button")
|
||||||
|
{
|
||||||
|
label = _("open in Gnome Maps"),
|
||||||
|
tooltip = _("Open location in Gnome Maps"),
|
||||||
|
clicked_callback = open_location_in_gnome_maps
|
||||||
|
},
|
||||||
|
separator4,--------------------------------------------------------
|
||||||
|
dt.new_widget("button")
|
||||||
|
{
|
||||||
|
label = _("reverse geocode"),
|
||||||
|
tooltip = _("This just shows the name of the location, but doesn't add it as tag"),
|
||||||
|
clicked_callback = reverse_geocode
|
||||||
|
},
|
||||||
|
separator5,--------------------------------------------------------
|
||||||
|
dt.new_widget("label"){label = _("altitude CSV export")},
|
||||||
|
altitude_file_chooser_button,
|
||||||
|
altitude_filename,
|
||||||
|
dt.new_widget("button")
|
||||||
|
{
|
||||||
|
label = _("export altitude CSV file"),
|
||||||
|
tooltip = _("Create an altitude profile using the GPS data in the metadata"),
|
||||||
|
clicked_callback = altitude_profile
|
||||||
|
},
|
||||||
|
labelDistance
|
||||||
|
},
|
||||||
|
nil,-- view_enter
|
||||||
|
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"))
|
||||||
|
dt.register_event("mouse-over-image-changed", toolbox_calc_distance)
|
||||||
|
|
||||||
|
dt.register_event("shortcut", select_with_gps, _("Select all images with GPS information"))
|
||||||
|
dt.register_event("shortcut", select_without_gps, _("Select all images without GPS information"))
|
||||||
|
|
||||||
|
-- vim: shiftwidth=2 expandtab tabstop=2 cindent syntax=lua
|
||||||
|
-- kate: hl Lua;
|
||||||
@@ -1,89 +0,0 @@
|
|||||||
--[[
|
|
||||||
This file is part of darktable,
|
|
||||||
Copyright 2016 by Tobias Jakobs.
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation; either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
]]
|
|
||||||
--[[
|
|
||||||
darktable script to open a geo uri in gnome-maps
|
|
||||||
|
|
||||||
ADDITIANAL SOFTWARE NEEDED FOR THIS SCRIPT
|
|
||||||
* gnome-maps >= 3.20
|
|
||||||
|
|
||||||
USAGE
|
|
||||||
* require this script from your main lua file
|
|
||||||
* register a shortcut
|
|
||||||
]]
|
|
||||||
|
|
||||||
local dt = require "darktable"
|
|
||||||
require "official/yield"
|
|
||||||
|
|
||||||
local gettext = dt.gettext
|
|
||||||
dt.configuration.check_version(...,{3,0,0})
|
|
||||||
|
|
||||||
-- Tell gettext where to find the .mo file translating messages for a particular domain
|
|
||||||
gettext.bindtextdomain("geo_uri",dt.configuration.config_dir.."/lua/")
|
|
||||||
|
|
||||||
local function _(msgid)
|
|
||||||
return gettext.dgettext("geo_uri", 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 openLocationInGnomeMaps()
|
|
||||||
if not checkIfBinExists("gnome-maps") then
|
|
||||||
dt.print_error(_("gnome-maps not found"))
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local sel_images = dt.gui.selection()
|
|
||||||
|
|
||||||
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 = image.latitude;
|
|
||||||
lon1 = image.longitude;
|
|
||||||
break
|
|
||||||
end
|
|
||||||
|
|
||||||
local startCommand
|
|
||||||
startCommand = "gnome-maps \"geo:" .. lat1 .. "," .. lon1 .."\""
|
|
||||||
dt.print_error(startCommand)
|
|
||||||
|
|
||||||
if dt.control.execute( startCommand) then
|
|
||||||
dt.print(_("Command failed ..."))
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Register
|
|
||||||
dt.register_event("shortcut", openLocationInGnomeMaps, _("Open Location in Gnome Maps"))
|
|
||||||
@@ -64,14 +64,14 @@
|
|||||||
]]
|
]]
|
||||||
|
|
||||||
local dt = require "darktable"
|
local dt = require "darktable"
|
||||||
|
local df = require "lib/dtutils.file"
|
||||||
require "official/yield"
|
require "official/yield"
|
||||||
|
|
||||||
local gettext = dt.gettext
|
local gettext = dt.gettext
|
||||||
|
|
||||||
dt.configuration.check_version(...,{3,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
|
-- Tell gettext where to find the .mo file translating messages for a particular domain
|
||||||
gettext.bindtextdomain("gimp",dt.configuration.config_dir.."/lua/")
|
gettext.bindtextdomain("gimp",dt.configuration.config_dir.."/lua/locale/")
|
||||||
|
|
||||||
local function split_filepath(str)
|
local function split_filepath(str)
|
||||||
local result = {}
|
local result = {}
|
||||||
@@ -104,21 +104,6 @@ local function _(msgid)
|
|||||||
return gettext.dgettext("gimp", msgid)
|
return gettext.dgettext("gimp", msgid)
|
||||||
end
|
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
|
-- Thanks Tobias Jakobs for the idea and the correction
|
||||||
function checkIfFileExists(filepath)
|
function checkIfFileExists(filepath)
|
||||||
local file = io.open(filepath,"r")
|
local file = io.open(filepath,"r")
|
||||||
@@ -199,7 +184,7 @@ end
|
|||||||
local function fileCopy(fromFile, toFile)
|
local function fileCopy(fromFile, toFile)
|
||||||
local result = nil
|
local result = nil
|
||||||
-- if cp exists, use it
|
-- if cp exists, use it
|
||||||
if checkIfBinExists("cp") then
|
if df.check_if_bin_exists("cp") then
|
||||||
result = os.execute("cp '" .. fromFile .. "' '" .. toFile .. "'")
|
result = os.execute("cp '" .. fromFile .. "' '" .. toFile .. "'")
|
||||||
end
|
end
|
||||||
-- if cp was not present, or if cp failed, then a pure lua solution
|
-- if cp was not present, or if cp failed, then a pure lua solution
|
||||||
@@ -230,7 +215,7 @@ local function fileMove(fromFile, toFile)
|
|||||||
local success = os.rename(fromFile, toFile)
|
local success = os.rename(fromFile, toFile)
|
||||||
if not success then
|
if not success then
|
||||||
-- an error occurred, so let's try using the operating system function
|
-- an error occurred, so let's try using the operating system function
|
||||||
if checkIfBinExists("mv") then
|
if df.check_if_bin_exists("mv") then
|
||||||
success = os.execute("mv '" .. fromFile .. "' '" .. toFile .. "'")
|
success = os.execute("mv '" .. fromFile .. "' '" .. toFile .. "'")
|
||||||
end
|
end
|
||||||
-- if the mv didn't exist or succeed, then...
|
-- if the mv didn't exist or succeed, then...
|
||||||
@@ -249,7 +234,7 @@ local function fileMove(fromFile, toFile)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local function gimp_edit(storage, image_table, extra_data) --finalize
|
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"))
|
dt.print_error(_("GIMP not found"))
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
@@ -315,5 +300,3 @@ end
|
|||||||
dt.register_storage("module_gimp", _("Edit with GIMP"), show_status, gimp_edit)
|
dt.register_storage("module_gimp", _("Edit with GIMP"), show_status, gimp_edit)
|
||||||
|
|
||||||
--
|
--
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,60 +0,0 @@
|
|||||||
--[[
|
|
||||||
This file is part of darktable,
|
|
||||||
Copyright 2014 by Tobias Jakobs.
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation; either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
]]
|
|
||||||
--[[
|
|
||||||
darktable select images with or without GPS informations
|
|
||||||
|
|
||||||
USAGE
|
|
||||||
* require this script from your main lua file
|
|
||||||
* register a shortcuts
|
|
||||||
]]
|
|
||||||
|
|
||||||
local dt = require "darktable"
|
|
||||||
local gettext = dt.gettext
|
|
||||||
dt.configuration.check_version(...,{2,0,1},{3,0,0})
|
|
||||||
|
|
||||||
-- Tell gettext where to find the .mo file translating messages for a particular domain
|
|
||||||
gettext.bindtextdomain("gps_select",dt.configuration.config_dir.."/lua/")
|
|
||||||
|
|
||||||
local function _(msgid)
|
|
||||||
return gettext.dgettext("gps_select", msgid)
|
|
||||||
end
|
|
||||||
|
|
||||||
table = require "table"
|
|
||||||
|
|
||||||
local function selectWithGPS()
|
|
||||||
local selection = {}
|
|
||||||
for _,image in ipairs(dt.database) do
|
|
||||||
if (image.longitude and image.latitude) then
|
|
||||||
table.insert(selection,image)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
dt.gui.selection(selection)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function selectWithoutGPS()
|
|
||||||
local selection = {}
|
|
||||||
for _,image in ipairs(dt.database) do
|
|
||||||
if (not image.longitude and not image.latitude) then
|
|
||||||
table.insert(selection,image)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
dt.gui.selection(selection)
|
|
||||||
end
|
|
||||||
|
|
||||||
dt.register_event("shortcut", selectWithGPS, _("Select all images with GPS information"))
|
|
||||||
dt.register_event("shortcut", selectWithoutGPS, _("Select all images without GPS information"))
|
|
||||||
@@ -34,44 +34,27 @@ This plugin will add a new storage option and calls hugin after export.
|
|||||||
]]
|
]]
|
||||||
|
|
||||||
local dt = require "darktable"
|
local dt = require "darktable"
|
||||||
|
local df = require "lib/dtutils.file"
|
||||||
require "official/yield"
|
require "official/yield"
|
||||||
|
|
||||||
local gettext = dt.gettext
|
local gettext = dt.gettext
|
||||||
|
|
||||||
-- works with darktable API version 2.0.0 and 3.0.0
|
-- works with darktable API version from 2.0.0 to 5.0.0
|
||||||
dt.configuration.check_version(...,{2,0,0},{3,0,0})
|
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
|
-- Tell gettext where to find the .mo file translating messages for a particular domain
|
||||||
gettext.bindtextdomain("hugin",dt.configuration.config_dir.."/lua/")
|
gettext.bindtextdomain("hugin",dt.configuration.config_dir.."/lua/locale/")
|
||||||
|
|
||||||
local function _(msgid)
|
local function _(msgid)
|
||||||
return gettext.dgettext("hugin", msgid)
|
return gettext.dgettext("hugin", msgid)
|
||||||
end
|
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,
|
local function show_status(storage, image, format, filename,
|
||||||
number, total, high_quality, extra_data)
|
number, total, high_quality, extra_data)
|
||||||
dt.print("Export to Hugin "..tostring(number).."/"..tostring(total))
|
dt.print("Export to Hugin "..tostring(number).."/"..tostring(total))
|
||||||
end
|
end
|
||||||
|
|
||||||
local function create_panorama(storage, image_table, extra_data) --finalize
|
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"))
|
dt.print_error(_("hugin not found"))
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
@@ -82,7 +65,7 @@ local function create_panorama(storage, image_table, extra_data) --finalize
|
|||||||
-- http://hugin.sourceforge.net/docs/manual/Pto_gen.html
|
-- http://hugin.sourceforge.net/docs/manual/Pto_gen.html
|
||||||
|
|
||||||
local hugin_executor = false
|
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
|
hugin_executor = true
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -115,7 +98,7 @@ local function create_panorama(storage, image_table, extra_data) --finalize
|
|||||||
|
|
||||||
dt.print_error(huginStartCommand)
|
dt.print_error(huginStartCommand)
|
||||||
|
|
||||||
if dt.control.execute( huginStartCommand)
|
if not dt.control.execute(huginStartCommand)
|
||||||
then
|
then
|
||||||
dt.print(_("Command hugin failed ..."))
|
dt.print(_("Command hugin failed ..."))
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -37,13 +37,14 @@ USAGE
|
|||||||
]]
|
]]
|
||||||
|
|
||||||
local dt = require "darktable"
|
local dt = require "darktable"
|
||||||
|
local df = require "lib/dtutils.file"
|
||||||
require "official/yield"
|
require "official/yield"
|
||||||
|
|
||||||
local gettext = dt.gettext
|
local gettext = dt.gettext
|
||||||
dt.configuration.check_version(...,{3,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
|
-- Tell gettext where to find the .mo file translating messages for a particular domain
|
||||||
gettext.bindtextdomain("kml_export",dt.configuration.config_dir.."/lua/")
|
gettext.bindtextdomain("kml_export",dt.configuration.config_dir.."/lua/locale/")
|
||||||
|
|
||||||
local function _(msgid)
|
local function _(msgid)
|
||||||
return gettext.dgettext("kml_export", msgid)
|
return gettext.dgettext("kml_export", msgid)
|
||||||
@@ -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))
|
dt.print(string.format(_("Export Image %i/%i"), number, total))
|
||||||
end
|
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
|
-- Strip accents from a string
|
||||||
-- Copied from https://forums.coronalabs.com/topic/43048-remove-special-characters-from-string/
|
-- Copied from https://forums.coronalabs.com/topic/43048-remove-special-characters-from-string/
|
||||||
function string.stripAccents( str )
|
function string.stripAccents( str )
|
||||||
@@ -175,17 +163,20 @@ function string.escapeXmlCharacters( str )
|
|||||||
end
|
end
|
||||||
|
|
||||||
local function create_kml_file(storage, image_table, extra_data)
|
local function create_kml_file(storage, image_table, extra_data)
|
||||||
|
if not df.check_if_bin_exists("mkdir") then
|
||||||
if not checkIfBinExists("mkdir") then
|
dt.print_error(_("mkdir not found"))
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
if not checkIfBinExists("convert") then
|
if not df.check_if_bin_exists("convert") then
|
||||||
|
dt.print_error(_("convert not found"))
|
||||||
return
|
return
|
||||||
end
|
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
|
return
|
||||||
end
|
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
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -193,7 +184,8 @@ local function create_kml_file(storage, image_table, extra_data)
|
|||||||
|
|
||||||
local imageFoldername
|
local imageFoldername
|
||||||
if ( dt.preferences.read("kml_export","CreateKMZ","bool") == true ) then
|
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
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -364,13 +356,13 @@ local function create_kml_file(storage, image_table, extra_data)
|
|||||||
|
|
||||||
-- Open the file with the standard programm
|
-- Open the file with the standard programm
|
||||||
if ( dt.preferences.read("kml_export","OpenKmlFile","bool") == true ) then
|
if ( dt.preferences.read("kml_export","OpenKmlFile","bool") == true ) then
|
||||||
local kmlFileOpenCommand
|
local kmlFileOpenCommand
|
||||||
|
|
||||||
if ( dt.preferences.read("kml_export","CreateKMZ","bool") == true ) then
|
if ( dt.preferences.read("kml_export","CreateKMZ","bool") == true ) then
|
||||||
kmlFileOpenCommand = "xdg-open "..exportDirectory.."/\""..exportKMZFilename.."\""
|
kmlFileOpenCommand = "xdg-open "..exportDirectory.."/\""..exportKMZFilename.."\""
|
||||||
else
|
else
|
||||||
kmlFileOpenCommand = "xdg-open "..exportDirectory.."/\""..exportKMLFilename.."\""
|
kmlFileOpenCommand = "xdg-open "..exportDirectory.."/\""..exportKMLFilename.."\""
|
||||||
end
|
end
|
||||||
dt.control.execute(kmlFileOpenCommand)
|
dt.control.execute(kmlFileOpenCommand)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -387,6 +379,9 @@ dt.preferences.register("kml_export",
|
|||||||
|
|
||||||
local handle = io.popen("xdg-user-dir DESKTOP")
|
local handle = io.popen("xdg-user-dir DESKTOP")
|
||||||
local result = handle:read()
|
local result = handle:read()
|
||||||
|
if (result == nil) then
|
||||||
|
result = ""
|
||||||
|
end
|
||||||
handle:close()
|
handle:close()
|
||||||
dt.preferences.register("kml_export",
|
dt.preferences.register("kml_export",
|
||||||
"ExportDirectory",
|
"ExportDirectory",
|
||||||
|
|||||||
94
contrib/passport_guide.lua
Normal file
94
contrib/passport_guide.lua
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
--[[
|
||||||
|
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 <http://www.gnu.org/licenses/>.
|
||||||
|
]]
|
||||||
|
|
||||||
|
--[[
|
||||||
|
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.
|
||||||
|
|
||||||
|
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
|
||||||
|
]]
|
||||||
|
|
||||||
|
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)
|
||||||
|
local _width, _height
|
||||||
|
|
||||||
|
-- get the max 36x47 rectangle
|
||||||
|
local aspect_ratio = 47 / 36
|
||||||
|
if width * aspect_ratio > height then
|
||||||
|
_width = height / aspect_ratio
|
||||||
|
_height = height
|
||||||
|
else
|
||||||
|
_width = width
|
||||||
|
_height = width * aspect_ratio
|
||||||
|
end
|
||||||
|
|
||||||
|
cairo:save()
|
||||||
|
|
||||||
|
cairo:translate(x + (width - _width) / 2, y + (height - _height) / 2)
|
||||||
|
cairo:scale(_width / 36, _height / 47)
|
||||||
|
|
||||||
|
-- the outer rectangle
|
||||||
|
cairo:rectangle( 0, 0, 36, 47)
|
||||||
|
|
||||||
|
-- vertical bars
|
||||||
|
cairo:draw_line(16.5, 8, 16.5, 36)
|
||||||
|
cairo:draw_line(19.5, 8, 19.5, 36)
|
||||||
|
|
||||||
|
-- long horisontal bars
|
||||||
|
cairo:draw_line(6, 4, 30, 4)
|
||||||
|
cairo:draw_line(6, 40, 30, 40)
|
||||||
|
|
||||||
|
-- short horisontal bars
|
||||||
|
cairo:draw_line(9, 6, 27, 6)
|
||||||
|
cairo:draw_line(9, 38, 27, 38)
|
||||||
|
|
||||||
|
cairo: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
|
||||||
247
contrib/pdf_slideshow.lua
Normal file
247
contrib/pdf_slideshow.lua
Normal file
@@ -0,0 +1,247 @@
|
|||||||
|
--[[
|
||||||
|
This file is part of darktable,
|
||||||
|
copyright (c) 2017 Pascal Obry
|
||||||
|
|
||||||
|
darktable is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
darktable is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with darktable. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
]]
|
||||||
|
--[[
|
||||||
|
SELECTION_TO_PDF
|
||||||
|
Generates a PDF slideshow (via Latex) containing all selected images
|
||||||
|
one per slide.
|
||||||
|
|
||||||
|
ADDITIANAL SOFTWARE NEEDED FOR THIS SCRIPT
|
||||||
|
* a PDF-Viewer
|
||||||
|
* pdflatex (Latex)
|
||||||
|
|
||||||
|
USAGE
|
||||||
|
* require this file from your main lua config file:
|
||||||
|
|
||||||
|
This plugin will add a new exporter that will allow you to generate a pdf slideshow.
|
||||||
|
The interface will let you add:
|
||||||
|
- a global title for the slideshow (prefix in all slide label)
|
||||||
|
- a delay for the transition between each slide
|
||||||
|
|
||||||
|
Each slide will contain a single picture with a label at the bottom with the
|
||||||
|
format (all fields can be the empty string):
|
||||||
|
|
||||||
|
<global title> / <image creator> / <image title>
|
||||||
|
|
||||||
|
]]
|
||||||
|
local dt = require "darktable"
|
||||||
|
local df = require "lib/dtutils.file"
|
||||||
|
require "official/yield"
|
||||||
|
|
||||||
|
local gettext = dt.gettext
|
||||||
|
|
||||||
|
-- Tell gettext where to find the .mo file translating messages for a particular domain
|
||||||
|
gettext.bindtextdomain("pdf_slideshow",dt.configuration.config_dir.."/lua/locale/")
|
||||||
|
|
||||||
|
local function _(msgid)
|
||||||
|
return gettext.dgettext("pdf_slideshow", msgid)
|
||||||
|
end
|
||||||
|
|
||||||
|
if not df.check_if_bin_exists("pdflatex") then
|
||||||
|
dt.print_error(_("pdflatex not found"))
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
dt.configuration.check_version(...,{4,0,0},{5,0,0})
|
||||||
|
|
||||||
|
dt.preferences.register
|
||||||
|
("pdf_slideshow","open with","string",
|
||||||
|
_("a pdf viewer"),
|
||||||
|
_("can be an absolute pathname or the tool may be in the PATH"),
|
||||||
|
"xdg-open")
|
||||||
|
|
||||||
|
local title_widget = dt.new_widget("entry") {
|
||||||
|
placeholder=_("slideshow title")
|
||||||
|
}
|
||||||
|
local delay_widget = dt.new_widget("slider")
|
||||||
|
{
|
||||||
|
label = _("transition delay (s)"),
|
||||||
|
soft_min = 1, -- The soft minimum value for the slider, the slider can't go beyond this point
|
||||||
|
soft_max = 20, -- The soft maximum value for the slider, the slider can't go beyond this point
|
||||||
|
hard_min = 1, -- The hard minimum value for the slider, the user can't manually enter a value beyond this point
|
||||||
|
hard_max = 60, -- The hard maximum value for the slider, the user can't manually enter a value beyond this point
|
||||||
|
value = 5, -- The current value of the slider
|
||||||
|
step = 1,
|
||||||
|
digits = 0
|
||||||
|
}
|
||||||
|
local check_button_title = dt.new_widget("check_button")
|
||||||
|
{
|
||||||
|
label = _('include image title'),
|
||||||
|
value = true,
|
||||||
|
tooltip = _('whether to include the image title (if defined) into the slide')
|
||||||
|
}
|
||||||
|
local check_button_author = dt.new_widget("check_button")
|
||||||
|
{
|
||||||
|
label = _('include image author'),
|
||||||
|
value = true,
|
||||||
|
tooltip = _('whether to include the image author (if defined) into the slide')
|
||||||
|
}
|
||||||
|
local widget = dt.new_widget("box") {
|
||||||
|
orientation=horizontal,
|
||||||
|
dt.new_widget("label"){label = _("slideshow title")},
|
||||||
|
title_widget,
|
||||||
|
dt.new_widget("label"){label = ""},
|
||||||
|
delay_widget,
|
||||||
|
check_button_author,
|
||||||
|
check_button_title
|
||||||
|
}
|
||||||
|
|
||||||
|
local ending = [[
|
||||||
|
\end{document}
|
||||||
|
]]
|
||||||
|
|
||||||
|
-- only jpeg files are supported by latex
|
||||||
|
local function support_format(storage, format)
|
||||||
|
fmt = string.lower(format.name)
|
||||||
|
if string.match(fmt,"jpeg") ~= nil and string.match(fmt,"2000") == nil then
|
||||||
|
return true
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local filename =dt.configuration.tmp_dir.."/pdfout.tex"
|
||||||
|
|
||||||
|
local function my_write(latexfile,arg)
|
||||||
|
local res,errmsg = latexfile:write(arg)
|
||||||
|
if not res then
|
||||||
|
error(errmsg)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function img_filename(file,i)
|
||||||
|
local dir=string.gsub(file, "(.*)(%/.*%..*)", "%1")
|
||||||
|
local ext=string.gsub(file, "(.*)(%..*)", "%2")
|
||||||
|
local lfile = dir.."/slide"..i..ext
|
||||||
|
return lfile
|
||||||
|
end
|
||||||
|
|
||||||
|
local function slide(latexfile,i,image,file)
|
||||||
|
local title = ""
|
||||||
|
if title_widget.text ~= "" then
|
||||||
|
title = title_widget.text
|
||||||
|
end
|
||||||
|
if check_button_author.value == true and image.creator ~= "" then
|
||||||
|
if title ~= "" then
|
||||||
|
title = title.." / "
|
||||||
|
end
|
||||||
|
title = title..image.creator
|
||||||
|
end
|
||||||
|
if check_button_title.value == true and image.title ~= "" then
|
||||||
|
if title ~= "" then
|
||||||
|
title = title.." / "
|
||||||
|
end
|
||||||
|
title = title..image.title
|
||||||
|
end
|
||||||
|
|
||||||
|
-- make sure there is no non-printable characters in the title
|
||||||
|
title = string.gsub(title, "\n", "")
|
||||||
|
title = string.gsub(title, "\r", "")
|
||||||
|
title = string.gsub(title, "\t", "")
|
||||||
|
|
||||||
|
local lfile = img_filename(file,i)
|
||||||
|
os.rename(file, lfile)
|
||||||
|
|
||||||
|
my_write(latexfile,"\\begin{figure}\n")
|
||||||
|
my_write(latexfile,"\\begin{measuredfigure}\n")
|
||||||
|
my_write(latexfile,"\\includegraphics[height=0.92\\textheight]{"..lfile.."}\n")
|
||||||
|
my_write(latexfile,"\\end{measuredfigure}\n")
|
||||||
|
my_write(latexfile,"\\caption{{\\color{white}"..title.."}}\n")
|
||||||
|
my_write(latexfile,"\\end{figure}\n")
|
||||||
|
end
|
||||||
|
|
||||||
|
dt.register_storage("pdf_slideshow",_("pdf slideshow"),
|
||||||
|
nil,
|
||||||
|
function(storage,image_table)
|
||||||
|
|
||||||
|
local preamble = [[
|
||||||
|
\documentclass[a4paper,12pt,landscape]{beamer}
|
||||||
|
\usetheme{default}
|
||||||
|
\usepackage[utf8]{inputenc}
|
||||||
|
\usepackage{graphicx}
|
||||||
|
\usepackage{threeparttable}
|
||||||
|
\usepackage[space]{grffile} % needed to support filename with spaces
|
||||||
|
\pagestyle{empty}
|
||||||
|
\parindent0pt
|
||||||
|
\usepackage{geometry}
|
||||||
|
\usepackage{color}
|
||||||
|
\pagecolor{black!100}
|
||||||
|
\color{white}
|
||||||
|
\geometry{a4paper,landscape,left=2mm,right=2mm, top=2mm, bottom=2mm}
|
||||||
|
\mode<presentation>
|
||||||
|
\transduration{]]..string.gsub(delay_widget.value, ",", ".")..[[}
|
||||||
|
\setbeamertemplate{footline}{}
|
||||||
|
\setbeamertemplate{headline}{}
|
||||||
|
\setbeamertemplate{frametitle}{}
|
||||||
|
\setbeamertemplate{navigation symbols}{}
|
||||||
|
\setbeamercolor{background canvas}{fg=white,bg=black!100}
|
||||||
|
\setbeamercolor{normal text}{fg=white}
|
||||||
|
\hypersetup{pdfstartpage=1,pdfpagemode=FullScreen}
|
||||||
|
\setbeamertemplate{caption}{\insertcaption}
|
||||||
|
\begin{document}
|
||||||
|
]]
|
||||||
|
|
||||||
|
local errmsg
|
||||||
|
local latexfile
|
||||||
|
latexfile,errmsg=io.open(filename,"w")
|
||||||
|
if not latexfile then
|
||||||
|
error(errmsg)
|
||||||
|
end
|
||||||
|
my_write(latexfile,preamble)
|
||||||
|
local i = 1
|
||||||
|
for img,file in pairs(image_table) do
|
||||||
|
slide(latexfile,i,img,file)
|
||||||
|
my_write(latexfile,"\n\\bigskip\n")
|
||||||
|
i = i+1
|
||||||
|
end
|
||||||
|
my_write(latexfile,ending)
|
||||||
|
latexfile:close()
|
||||||
|
|
||||||
|
-- convert to PDF
|
||||||
|
local dir=string.gsub(filename, "(.*/)(.*)", "%1")
|
||||||
|
local locfile=string.gsub(filename, "(.*/)(.*)", "%2")
|
||||||
|
local command = "pdflatex -halt-on-error -output-directory "..dir.." "..locfile
|
||||||
|
local result = dt.control.execute(command)
|
||||||
|
if result ~= 0 then
|
||||||
|
dt.print(_("problem running pdflatex")) -- this one is probably usefull to the user
|
||||||
|
error(_("problem running ")..command)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- open the PDF
|
||||||
|
local pdffile=string.gsub(filename, ".tex", ".pdf")
|
||||||
|
command = dt.preferences.read("pdf_slideshow","open with","string")
|
||||||
|
command = command.." "..pdffile
|
||||||
|
local result = dt.control.execute(command)
|
||||||
|
if result ~= 0 then
|
||||||
|
dt.print(_("problem running pdf viewer")) -- this one is probably usefull to the user
|
||||||
|
error(_("problem running ")..command)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- finally do some clean-up
|
||||||
|
local i = 1
|
||||||
|
for img,file in pairs(image_table) do
|
||||||
|
local lfile = img_filename(file,i)
|
||||||
|
os.remove(lfile)
|
||||||
|
i = i+1
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
support_format,
|
||||||
|
nil,
|
||||||
|
widget)
|
||||||
|
|
||||||
|
--
|
||||||
|
-- vim: shiftwidth=2 expandtab tabstop=2 cindent syntax=lua
|
||||||
251
contrib/quicktag.lua
Normal file
251
contrib/quicktag.lua
Normal file
@@ -0,0 +1,251 @@
|
|||||||
|
--[[
|
||||||
|
This file is part of darktable,
|
||||||
|
Copyright (C) 2017 by Christian Kanzian
|
||||||
|
|
||||||
|
Thanks to
|
||||||
|
Copyright (C) 2016 Bill Ferguson
|
||||||
|
Copyright (C) 2017 Tobias Jakobs
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
]]
|
||||||
|
|
||||||
|
--[[
|
||||||
|
QUICKTAG
|
||||||
|
For faster attaching your favorite tags, the script adds shortcuts and
|
||||||
|
the module "quicktag" in lighttable mode with a changeable number of buttons.
|
||||||
|
To each button a tag can be assigned. If the tags do not exist in your database,
|
||||||
|
they are added to the database once they get the first time attached to an image.
|
||||||
|
|
||||||
|
The number of buttons/shortcuts can be changed in the lua preferences.
|
||||||
|
Changes in the number require a restart of darktable.
|
||||||
|
|
||||||
|
INSTALATION
|
||||||
|
* copy this file in $CONFIGDIR/lua/ where CONFIGDIR is your darktable configuration directory
|
||||||
|
* add the following line in the file $CONFIGDIR/luarc require "quicktag"
|
||||||
|
|
||||||
|
USAGE
|
||||||
|
* set the number of quicktags between 2 and 10 in the preferences dialog and restart darktable
|
||||||
|
* if wanted set the shortcuts in the preferences dialog
|
||||||
|
* to add or change a quicktag, first select the old tag with the combobox "old quicktag",
|
||||||
|
enter a new tag in the "new quicktag" filed and press "set quicktag"
|
||||||
|
* use a shortcut or button to attach the tag to selected images
|
||||||
|
]]
|
||||||
|
|
||||||
|
|
||||||
|
local dt = require "darktable"
|
||||||
|
local debug = require "darktable.debug"
|
||||||
|
|
||||||
|
|
||||||
|
local gettext = dt.gettext
|
||||||
|
|
||||||
|
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("quicktag",dt.configuration.config_dir.."/lua/locale/")
|
||||||
|
|
||||||
|
local function _(msgid)
|
||||||
|
return gettext.dgettext("quicktag", msgid)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- maximum length of button labels
|
||||||
|
dt.preferences.register("quickTag",
|
||||||
|
"labellength",
|
||||||
|
"integer", -- type
|
||||||
|
_("max. length of button labels"), -- label
|
||||||
|
_("may range from 15 to 60 - needs a restart"), -- tooltip
|
||||||
|
25, -- default
|
||||||
|
15, -- min
|
||||||
|
60)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
local max_label_length = dt.preferences.read("quickTag", "labellength", "integer")
|
||||||
|
|
||||||
|
-- register number of quicktags
|
||||||
|
dt.preferences.register("quickTag",
|
||||||
|
"quickTagnumber",
|
||||||
|
"integer", -- type
|
||||||
|
_("number of quicktag fields"), -- label
|
||||||
|
_("may range from 2 to 20 - needs a restart"), -- tooltip
|
||||||
|
5, -- default
|
||||||
|
2, -- min
|
||||||
|
20)
|
||||||
|
|
||||||
|
local qnr = dt.preferences.read("quickTag", "quickTagnumber", "integer")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- get quicktags from the preferences
|
||||||
|
local quicktag_table = {}
|
||||||
|
|
||||||
|
|
||||||
|
local function read_pref_tags()
|
||||||
|
for j=1,qnr do
|
||||||
|
quicktag_table[j] = dt.preferences.read("quickTag", "quicktag"..j, "string")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local quicktag_label = {}
|
||||||
|
|
||||||
|
|
||||||
|
local function abbrevate_tags(t)
|
||||||
|
for i=1,qnr do
|
||||||
|
local taglength = string.len(t[i])
|
||||||
|
if taglength > max_label_length then
|
||||||
|
local max_2 = math.floor(max_label_length/2)
|
||||||
|
quicktag_label[i] = string.sub(t[i],0,max_2).."..."..string.sub(t[i],taglength - max_2)
|
||||||
|
else
|
||||||
|
quicktag_label[i] = t[i]
|
||||||
|
end
|
||||||
|
-- print(quicktag_label[i])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- quicktag function to attach tags
|
||||||
|
local function tagattach(tag,qtagnr)
|
||||||
|
if tag == "" then
|
||||||
|
dt.print(string.format(_("quicktag %i is empty, please set a tag"), qtagnr))
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
local tagnr = dt.tags.find(tag)
|
||||||
|
|
||||||
|
--create tag if it does not exist
|
||||||
|
if tagnr == nil then
|
||||||
|
dt.tags.create(tag)
|
||||||
|
tagnr = dt.tags.find(tag)
|
||||||
|
end
|
||||||
|
|
||||||
|
local sel_images = dt.gui.action_images
|
||||||
|
|
||||||
|
if next(sel_images) == nil then
|
||||||
|
dt.print(_("no images selected"))
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
local counter = 0
|
||||||
|
|
||||||
|
for _,image in ipairs(sel_images) do
|
||||||
|
dt.tags.attach(tagnr,image)
|
||||||
|
counter = counter+1
|
||||||
|
end
|
||||||
|
dt.print(string.format(_("tag \"%s\" attached to %i image(s)"), tag, counter))
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- create quicktag module elements
|
||||||
|
-- read tags from preferences for initialization
|
||||||
|
read_pref_tags()
|
||||||
|
abbrevate_tags(quicktag_table)
|
||||||
|
|
||||||
|
|
||||||
|
local button = {}
|
||||||
|
|
||||||
|
-- function to create buttons with tags as labels
|
||||||
|
for j=1,qnr do
|
||||||
|
button[#button+1] = dt.new_widget("button") {
|
||||||
|
label = j..": "..quicktag_table[j],
|
||||||
|
clicked_callback = function() tagattach(tostring(quicktag_table[j]),j) end}
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local old_quicktag = dt.new_widget("combobox"){
|
||||||
|
label = _("old tag"),
|
||||||
|
tooltip = _("select the quicktag to replace")
|
||||||
|
}
|
||||||
|
|
||||||
|
local function update_quicktag_list()
|
||||||
|
-- abrevate long tags for the labels
|
||||||
|
abbrevate_tags(quicktag_table)
|
||||||
|
for j=1,qnr do
|
||||||
|
button[j].label = j..": "..quicktag_label[j]
|
||||||
|
old_quicktag[j] = j..": "..quicktag_table[j]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
update_quicktag_list()
|
||||||
|
|
||||||
|
local new_quicktag = dt.new_widget("entry"){
|
||||||
|
text = "",
|
||||||
|
placeholder = _("new tag"),
|
||||||
|
is_password = true,
|
||||||
|
editable = true,
|
||||||
|
tooltip = _("enter your tag here")
|
||||||
|
}
|
||||||
|
|
||||||
|
local set_quicktag_button = dt.new_widget("button") {
|
||||||
|
label = _("set tag"),
|
||||||
|
clicked_callback = function()
|
||||||
|
local old_tag = quicktag_table[old_quicktag.selected]
|
||||||
|
if new_quicktag.text == "" then
|
||||||
|
dt.print(_("new quicktag is empty!"))
|
||||||
|
else
|
||||||
|
quicktag_table[old_quicktag.selected] = new_quicktag.text
|
||||||
|
dt.preferences.write("quickTag", "quicktag"..old_quicktag.selected, "string", new_quicktag.text)
|
||||||
|
dt.print(string.format(_("quicktag \"%s\" replaced by \"%s\""), old_tag, new_quicktag.text))
|
||||||
|
update_quicktag_list()
|
||||||
|
new_quicktag.text = ""
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
}
|
||||||
|
|
||||||
|
local new_qt_widget = dt.new_widget ("box") {
|
||||||
|
orientation = "horizontal",
|
||||||
|
dt.new_widget("label") { label = _("new tag") },
|
||||||
|
new_quicktag,
|
||||||
|
set_quicktag_button
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
-- back UI elements in a table
|
||||||
|
-- thanks to wpferguson for the hint
|
||||||
|
local widget_table = {}
|
||||||
|
|
||||||
|
for i=1,qnr do
|
||||||
|
widget_table[#widget_table + 1] = button[i]
|
||||||
|
end
|
||||||
|
|
||||||
|
widget_table[#widget_table + 1] = dt.new_widget("separator"){}
|
||||||
|
widget_table[#widget_table + 1] = old_quicktag
|
||||||
|
widget_table[#widget_table + 1] = new_qt_widget
|
||||||
|
|
||||||
|
|
||||||
|
--create module
|
||||||
|
dt.register_lib(
|
||||||
|
"quicktag", -- Module name
|
||||||
|
"quicktag", -- name
|
||||||
|
true, -- expandable
|
||||||
|
false, -- resetable
|
||||||
|
{[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 490}},
|
||||||
|
|
||||||
|
dt.new_widget("box"){
|
||||||
|
orientation = "vertical",
|
||||||
|
table.unpack(widget_table),
|
||||||
|
|
||||||
|
},
|
||||||
|
nil,-- view_enter
|
||||||
|
nil -- view_leave
|
||||||
|
)
|
||||||
|
|
||||||
|
-- create shortcuts
|
||||||
|
for i=1,qnr do
|
||||||
|
dt.register_event("shortcut",
|
||||||
|
function(event, shortcut) tagattach(tostring(quicktag_table[i])) end,
|
||||||
|
string.format(_("quicktag %i"),i))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- vim: shiftwidth=2 expandtab tabstop=2 cindent syntax=lua
|
||||||
|
-- kate: tab-indents: off; indent-width 2; replace-tabs on; remove-trailing-space on;
|
||||||
@@ -40,6 +40,9 @@
|
|||||||
|
|
||||||
local dt = require "darktable"
|
local dt = require "darktable"
|
||||||
|
|
||||||
|
-- added version check
|
||||||
|
dt.configuration.check_version(...,{3,0,0},{4,0,0})
|
||||||
|
|
||||||
local function apply_rating(rating)
|
local function apply_rating(rating)
|
||||||
local images = dt.gui.action_images
|
local images = dt.gui.action_images
|
||||||
for _, i in ipairs(images) do
|
for _, i in ipairs(images) do
|
||||||
|
|||||||
114
contrib/rename-tags.lua
Normal file
114
contrib/rename-tags.lua
Normal file
@@ -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)
|
||||||
|
|
||||||
64
contrib/select_untagged.lua
Normal file
64
contrib/select_untagged.lua
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
--[[
|
||||||
|
This file is part of darktable,
|
||||||
|
copyright (c) 2017 Jannis_V
|
||||||
|
|
||||||
|
darktable is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
darktable is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with darktable. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
]]
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Enable selection of untagged images (darktable|* tags are ignored)
|
||||||
|
]]
|
||||||
|
|
||||||
|
local dt = require "darktable"
|
||||||
|
local gettext = dt.gettext
|
||||||
|
|
||||||
|
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("select_untagged",dt.configuration.config_dir.."/lua/locale/")
|
||||||
|
|
||||||
|
local function _(msgid)
|
||||||
|
return gettext.dgettext("select_untagged", msgid)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function stop_job(job)
|
||||||
|
job.valid = false
|
||||||
|
end
|
||||||
|
|
||||||
|
local function select_untagged_images()
|
||||||
|
job = dt.gui.create_job(_("select untagged images"), true, stop_job)
|
||||||
|
|
||||||
|
local selection = {}
|
||||||
|
|
||||||
|
for key,image in ipairs(dt.collection) do
|
||||||
|
if(job.valid) then
|
||||||
|
job.percent = (key-1)/#dt.collection
|
||||||
|
local tags = dt.tags.get_tags(image)
|
||||||
|
local hasTags = false
|
||||||
|
for _,tag in ipairs(tags) do
|
||||||
|
if not string.match(tag.name,"darktable|") then
|
||||||
|
hasTags = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if hasTags == false then
|
||||||
|
table.insert(selection,image)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
job.valid = false
|
||||||
|
dt.gui.selection(selection)
|
||||||
|
end
|
||||||
|
|
||||||
|
dt.gui.libs.select.register_selection(_("select untagged"),select_untagged_images,_("select all images containing no tags or only tags added by darktable"))
|
||||||
@@ -25,38 +25,27 @@ USAGE
|
|||||||
]]
|
]]
|
||||||
|
|
||||||
local dt = require "darktable"
|
local dt = require "darktable"
|
||||||
|
local df = require "lib/dtutils.file"
|
||||||
require "official/yield"
|
require "official/yield"
|
||||||
|
|
||||||
local gettext = dt.gettext
|
local gettext = dt.gettext
|
||||||
dt.configuration.check_version(...,{2,0,2},{3,0,0})
|
|
||||||
|
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
|
-- Tell gettext where to find the .mo file translating messages for a particular domain
|
||||||
gettext.bindtextdomain("slideshowMusic",dt.configuration.config_dir.."/lua/")
|
gettext.bindtextdomain("slideshowMusic",dt.configuration.config_dir.."/lua/locale/")
|
||||||
|
|
||||||
local function _(msgid)
|
local function _(msgid)
|
||||||
return gettext.dgettext("slideshowMusic", msgid)
|
return gettext.dgettext("slideshowMusic", msgid)
|
||||||
end
|
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 function playSlideshowMusic(_, old_view, new_view)
|
||||||
local filename, playMusic
|
local filename, playMusic
|
||||||
|
|
||||||
filename = dt.preferences.read("slideshowMusic","SlideshowMusic","string")
|
filename = dt.preferences.read("slideshowMusic","SlideshowMusic","string")
|
||||||
playMusic = dt.preferences.read("slideshowMusic","PlaySlideshowMusic","bool")
|
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
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -31,38 +31,34 @@ USAGE
|
|||||||
]]
|
]]
|
||||||
|
|
||||||
local dt = require "darktable"
|
local dt = require "darktable"
|
||||||
|
local df = require "lib/dtutils.file"
|
||||||
require "official/yield"
|
require "official/yield"
|
||||||
|
local gettext = dt.gettext
|
||||||
|
|
||||||
dt.configuration.check_version(...,{2,0,1})
|
dt.configuration.check_version(...,{2,0,1},{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("video_mencoder",dt.configuration.config_dir.."/lua/locale/")
|
||||||
|
|
||||||
|
local function _(msgid)
|
||||||
|
return gettext.dgettext("video_mencoder", msgid)
|
||||||
|
end
|
||||||
|
|
||||||
local function show_status(storage, image, format, filename, number, total, high_quality, extra_data)
|
local function show_status(storage, image, format, filename, number, total, high_quality, extra_data)
|
||||||
dt.print("Export Image "..tostring(number).."/"..tostring(total))
|
dt.print("Export Image "..tostring(number).."/"..tostring(total))
|
||||||
end
|
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 create_video_mencoder(storage, image_table, extra_data)
|
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
|
return
|
||||||
end
|
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
|
return
|
||||||
end
|
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
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -111,6 +107,9 @@ dt.preferences.register("video_mencoder", "OpenVideo", "bool", "Video exort (MEn
|
|||||||
local handle = io.popen("xdg-user-dir VIDEOS")
|
local handle = io.popen("xdg-user-dir VIDEOS")
|
||||||
local result = handle:read()
|
local result = handle:read()
|
||||||
handle:close()
|
handle:close()
|
||||||
|
if (result == nil) then
|
||||||
|
result = ""
|
||||||
|
end
|
||||||
dt.preferences.register("video_mencoder", "ExportDirectory", "directory", "Video exort (MEncoder): Video export directory","A directory that will be used to export a Video",result)
|
dt.preferences.register("video_mencoder", "ExportDirectory", "directory", "Video exort (MEncoder): Video export directory","A directory that will be used to export a Video",result)
|
||||||
|
|
||||||
-- Get the MEncoder codec list with: mencoder -ovc help
|
-- Get the MEncoder codec list with: mencoder -ovc help
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ LUA ERROR Hallo Welt!
|
|||||||
|
|
||||||
]]
|
]]
|
||||||
local dt = require "darktable"
|
local dt = require "darktable"
|
||||||
dt.configuration.check_version(...,{3,0,0})
|
dt.configuration.check_version(...,{3,0,0},{4,0,0},{5,0,0}))
|
||||||
|
|
||||||
-- Not translated Text
|
-- Not translated Text
|
||||||
dt.print_error("Hello World!")
|
dt.print_error("Hello World!")
|
||||||
@@ -64,7 +64,7 @@ dt.print_error(gettext.gettext("image"))
|
|||||||
|
|
||||||
-- Tell gettext where to find the .mo file translating messages for a particular domain
|
-- Tell gettext where to find the .mo file translating messages for a particular domain
|
||||||
|
|
||||||
gettext.bindtextdomain("gettextExample",dt.configuration.config_dir.."/lua/")
|
gettext.bindtextdomain("gettextExample",dt.configuration.config_dir.."/lua/locale/")
|
||||||
-- Translate a string using the specified textdomain
|
-- Translate a string using the specified textdomain
|
||||||
dt.print_error(gettext.dgettext("gettextExample", 'Hello World!'))
|
dt.print_error(gettext.dgettext("gettextExample", 'Hello World!'))
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ USAGE
|
|||||||
|
|
||||||
]]
|
]]
|
||||||
local dt = require "darktable"
|
local dt = require "darktable"
|
||||||
dt.configuration.check_version(...,{2,0,0},{3,0,0})
|
dt.configuration.check_version(...,{2,0,0},{3,0,0},{4,0,0},{5,0,0})
|
||||||
|
|
||||||
dt.print("hello, world")
|
dt.print("hello, world")
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ https://www.darktable.org/lua-api/index.html.php#darktable_new_widget
|
|||||||
|
|
||||||
local dt = require "darktable"
|
local dt = require "darktable"
|
||||||
|
|
||||||
dt.configuration.check_version(...,{3,0,0})
|
dt.configuration.check_version(...,{3,0,0},{4,0,0},{5,0,0})
|
||||||
|
|
||||||
-- add a new lib
|
-- add a new lib
|
||||||
local check_button = dt.new_widget("check_button"){label = "MyCheck_button", value = true}
|
local check_button = dt.new_widget("check_button"){label = "MyCheck_button", value = true}
|
||||||
@@ -70,33 +70,69 @@ local slider = dt.new_widget("slider")
|
|||||||
value = 52 -- The current value of the slider
|
value = 52 -- The current value of the slider
|
||||||
}
|
}
|
||||||
|
|
||||||
dt.register_lib(
|
if (dt.configuration.api_version_major >= 6) then
|
||||||
"exampleModule", -- Module name
|
local section_label = dt.new_widget("section_label")
|
||||||
"exampleModule", -- name
|
|
||||||
true, -- expandable
|
|
||||||
false, -- resetable
|
|
||||||
{[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, -- containers
|
|
||||||
dt.new_widget("box") -- widget
|
|
||||||
{
|
{
|
||||||
orientation = "vertical",
|
label = "MySectionLabel"
|
||||||
dt.new_widget("button")
|
}
|
||||||
|
|
||||||
|
dt.register_lib(
|
||||||
|
"exampleModule", -- Module name
|
||||||
|
"exampleModule", -- name
|
||||||
|
true, -- expandable
|
||||||
|
false, -- resetable
|
||||||
|
{[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, -- containers
|
||||||
|
dt.new_widget("box") -- widget
|
||||||
{
|
{
|
||||||
label = "MyButton",
|
orientation = "vertical",
|
||||||
clicked_callback = function (_)
|
dt.new_widget("button")
|
||||||
dt.print("Button clicked")
|
{
|
||||||
end
|
label = "MyButton",
|
||||||
|
clicked_callback = function (_)
|
||||||
|
dt.print("Button clicked")
|
||||||
|
end
|
||||||
|
},
|
||||||
|
check_button,
|
||||||
|
combobox,
|
||||||
|
entry,
|
||||||
|
file_chooser_button,
|
||||||
|
label,
|
||||||
|
separator,
|
||||||
|
slider,
|
||||||
|
section_label
|
||||||
},
|
},
|
||||||
check_button,
|
nil,-- view_enter
|
||||||
combobox,
|
nil -- view_leave
|
||||||
entry,
|
)
|
||||||
file_chooser_button,
|
else
|
||||||
label,
|
dt.register_lib(
|
||||||
separator,
|
"exampleModule", -- Module name
|
||||||
slider
|
"exampleModule", -- name
|
||||||
},
|
true, -- expandable
|
||||||
nil,-- view_enter
|
false, -- resetable
|
||||||
nil -- view_leave
|
{[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, -- containers
|
||||||
)
|
dt.new_widget("box") -- widget
|
||||||
|
{
|
||||||
|
orientation = "vertical",
|
||||||
|
dt.new_widget("button")
|
||||||
|
{
|
||||||
|
label = "MyButton",
|
||||||
|
clicked_callback = function (_)
|
||||||
|
dt.print("Button clicked")
|
||||||
|
end
|
||||||
|
},
|
||||||
|
check_button,
|
||||||
|
combobox,
|
||||||
|
entry,
|
||||||
|
file_chooser_button,
|
||||||
|
label,
|
||||||
|
separator,
|
||||||
|
slider
|
||||||
|
},
|
||||||
|
nil,-- view_enter
|
||||||
|
nil -- view_leave
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
-- vim: shiftwidth=2 expandtab tabstop=2 cindent syntax=lua
|
-- vim: shiftwidth=2 expandtab tabstop=2 cindent syntax=lua
|
||||||
-- kate: hl Lua;
|
-- kate: hl Lua;
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ USAGE
|
|||||||
* require this script from your main lua file
|
* require this script from your main lua file
|
||||||
]]
|
]]
|
||||||
local dt = require "darktable"
|
local dt = require "darktable"
|
||||||
dt.configuration.check_version(...,{2,0,1},{3,0,0})
|
dt.configuration.check_version(...,{2,0,1},{3,0,0},{4,0,0},{5,0,0})
|
||||||
|
|
||||||
dt.preferences.register("preferenceExamples", -- script: This is a string used to avoid name collision in preferences (i.e namespace). Set it to something unique, usually the name of the script handling the preference.
|
dt.preferences.register("preferenceExamples", -- script: This is a string used to avoid name collision in preferences (i.e namespace). Set it to something unique, usually the name of the script handling the preference.
|
||||||
"preferenceExamplesString", -- name
|
"preferenceExamplesString", -- name
|
||||||
|
|||||||
40
examples/printExamples.lua
Normal file
40
examples/printExamples.lua
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
--[[
|
||||||
|
This file is part of darktable,
|
||||||
|
copyright (c) 2017 Tobias Jakobs
|
||||||
|
darktable is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
darktable is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with darktable. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
]]
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Print Examples
|
||||||
|
prints "hello world when DT starts
|
||||||
|
USAGE
|
||||||
|
* require this file from your main lua config file:
|
||||||
|
]]
|
||||||
|
local dt = require "darktable"
|
||||||
|
dt.configuration.check_version(...,{5,0,0})
|
||||||
|
|
||||||
|
-- Will print a string to the darktable control log (the long
|
||||||
|
-- overlayed window that appears over the main panel).
|
||||||
|
dt.print("print")
|
||||||
|
|
||||||
|
-- This function will print its parameter if the Lua logdomain is
|
||||||
|
-- activated. Start darktable with the "-d lua" command line option
|
||||||
|
-- to enable the Lua logdomain.
|
||||||
|
dt.print_error("print error")
|
||||||
|
|
||||||
|
-- This function will print its parameter if the Lua logdomain is
|
||||||
|
-- activated. Start darktable with the "-d lua" command line option
|
||||||
|
-- to enable the Lua logdomain.
|
||||||
|
dt.print_log("print log")
|
||||||
|
|
||||||
|
--
|
||||||
|
-- vim: shiftwidth=2 expandtab tabstop=2 cindent syntax=lua
|
||||||
34
examples/running_os.lua
Normal file
34
examples/running_os.lua
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
--[[
|
||||||
|
This file is part of darktable,
|
||||||
|
copyright (c) 2017 Tobias Jakobs
|
||||||
|
|
||||||
|
darktable is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
darktable is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with darktable. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
]]
|
||||||
|
--[[
|
||||||
|
|
||||||
|
USAGE
|
||||||
|
* require this script from your main lua file
|
||||||
|
To do this add this line to the file .config/darktable/luarc:
|
||||||
|
require "running_os"
|
||||||
|
|
||||||
|
prints the operating system
|
||||||
|
|
||||||
|
]]
|
||||||
|
local dt = require "darktable"
|
||||||
|
dt.configuration.check_version(...,{5,0,0})
|
||||||
|
|
||||||
|
dt.print("You are running: "..dt.configuration.running_os)
|
||||||
|
|
||||||
|
--
|
||||||
|
-- vim: shiftwidth=2 expandtab tabstop=2 cindent syntax=lua
|
||||||
@@ -32,7 +32,7 @@ local dt = require "darktable"
|
|||||||
|
|
||||||
local log = require "lib/dtutils.log"
|
local log = require "lib/dtutils.log"
|
||||||
|
|
||||||
dt.configuration.check_version(...,{3,0,0})
|
dt.configuration.check_version(...,{3,0,0},{4,0,0},{5,0,0})
|
||||||
|
|
||||||
dtutils.libdoc.functions["split"] = {
|
dtutils.libdoc.functions["split"] = {
|
||||||
Name = [[split]],
|
Name = [[split]],
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ dtutils_file.libdoc = {
|
|||||||
|
|
||||||
local gettext = dt.gettext
|
local gettext = dt.gettext
|
||||||
|
|
||||||
dt.configuration.check_version(...,{3,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
|
-- Tell gettext where to find the .mo file translating messages for a particular domain
|
||||||
gettext.bindtextdomain("dtutils.file",dt.configuration.config_dir.."/lua/locale/")
|
gettext.bindtextdomain("dtutils.file",dt.configuration.config_dir.."/lua/locale/")
|
||||||
|
|||||||
84
locale/de_DE/LC_MESSAGES/quicktag.po
Normal file
84
locale/de_DE/LC_MESSAGES/quicktag.po
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||||
|
# This file is distributed under the same license as the PACKAGE package.
|
||||||
|
#
|
||||||
|
# Christian Kanzian <christian.kanzian@gmx.at>, 2017.
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: \n"
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"POT-Creation-Date: 2017-02-20 17:38+0100\n"
|
||||||
|
"PO-Revision-Date: 2017-02-20 17:50+0100\n"
|
||||||
|
"Last-Translator: Christian Kanzian <christian.kanzian@gmx.at>\n"
|
||||||
|
"Language-Team: German <kde-i18n-de@kde.org>\n"
|
||||||
|
"Language: de\n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
|
"X-Generator: Lokalize 1.5\n"
|
||||||
|
|
||||||
|
#: quicktag.lua:64
|
||||||
|
msgid "max. length of button labels"
|
||||||
|
msgstr "Max. Länge der Schaltflächen-Beschriftung"
|
||||||
|
|
||||||
|
#: quicktag.lua:65
|
||||||
|
msgid "may range from 15 to 60 - needs a restart"
|
||||||
|
msgstr "Bereich von 15 bis 60 möglich - Neustart erforderlich"
|
||||||
|
|
||||||
|
#: quicktag.lua:78
|
||||||
|
msgid "number of quicktag fields"
|
||||||
|
msgstr "Anzahl von quicktag Feldern"
|
||||||
|
|
||||||
|
#: quicktag.lua:79
|
||||||
|
msgid "may range from 2 to 20 - needs a restart"
|
||||||
|
msgstr "Bereich von 2 bis 20 möglich - Neustart erforderlich"
|
||||||
|
|
||||||
|
#: quicktag.lua:119
|
||||||
|
#, lua-format
|
||||||
|
msgid "quicktag %i is empty, please set a tag"
|
||||||
|
msgstr "quicktag %i ist leer - bitte Tag eingeben"
|
||||||
|
|
||||||
|
#: quicktag.lua:134
|
||||||
|
msgid "no images selected"
|
||||||
|
msgstr "keine Bilder ausgewählt"
|
||||||
|
|
||||||
|
#: quicktag.lua:144
|
||||||
|
#, lua-format
|
||||||
|
msgid "tag \"%s\" attached to %i image(s)"
|
||||||
|
msgstr "Tag \"%s\" an %i Bild(er) angehängt"
|
||||||
|
|
||||||
|
#: quicktag.lua:165
|
||||||
|
msgid "old quicktag"
|
||||||
|
msgstr "Alter quicktag"
|
||||||
|
|
||||||
|
#: quicktag.lua:166
|
||||||
|
msgid "select the quicktag to replace"
|
||||||
|
msgstr "Wähle den quicktag der ersetzt werden soll"
|
||||||
|
|
||||||
|
#: quicktag.lua:182 quicktag.lua:206
|
||||||
|
msgid "new quicktag"
|
||||||
|
msgstr "Neuer quicktag"
|
||||||
|
|
||||||
|
#: quicktag.lua:185
|
||||||
|
msgid "enter your tag here"
|
||||||
|
msgstr "Bitte Tag hier eingeben"
|
||||||
|
|
||||||
|
#: quicktag.lua:189
|
||||||
|
msgid "set quicktag"
|
||||||
|
msgstr "Setze Tag"
|
||||||
|
|
||||||
|
#: quicktag.lua:193
|
||||||
|
msgid "new quicktag is empty!"
|
||||||
|
msgstr "Neuer Tag ist leer!"
|
||||||
|
|
||||||
|
#: quicktag.lua:197
|
||||||
|
#, lua-format
|
||||||
|
msgid "quicktag \"%s\" replaced by \"%s\""
|
||||||
|
msgstr "quicktag \"%s\" ersetzt durch \"%s\" "
|
||||||
|
|
||||||
|
#: quicktag.lua:246
|
||||||
|
#, lua-format
|
||||||
|
msgid "quicktag %i"
|
||||||
|
msgstr "quicktag %i"
|
||||||
|
|
||||||
|
|
||||||
BIN
locale/de_DE/LC_MESSAGES/select_untagged.mo
Normal file
BIN
locale/de_DE/LC_MESSAGES/select_untagged.mo
Normal file
Binary file not shown.
27
locale/de_DE/LC_MESSAGES/select_untagged.po
Normal file
27
locale/de_DE/LC_MESSAGES/select_untagged.po
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: \n"
|
||||||
|
"POT-Creation-Date: 2017-09-14 12:18+0200\n"
|
||||||
|
"PO-Revision-Date: 2017-09-14 12:23+0200\n"
|
||||||
|
"Last-Translator: Jannis_V\n"
|
||||||
|
"Language-Team: \n"
|
||||||
|
"Language: de_DE\n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"X-Generator: Poedit 1.8.7.1\n"
|
||||||
|
"X-Poedit-Basepath: ../../../contrib\n"
|
||||||
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
|
"X-Poedit-SearchPath-0: select_untagged.lua\n"
|
||||||
|
|
||||||
|
#: select_untagged.lua:38
|
||||||
|
msgid "select untagged images"
|
||||||
|
msgstr "Auswahl von Bildern ohne Tags"
|
||||||
|
|
||||||
|
#: select_untagged.lua:64
|
||||||
|
msgid "select untagged"
|
||||||
|
msgstr "Ohne Tags"
|
||||||
|
|
||||||
|
#: select_untagged.lua:64
|
||||||
|
msgid "select all images containing no tags or only tags added by darktable"
|
||||||
|
msgstr "Wähle alle Bilder der aktuellen Sammlung aus, die keine Tags oder nur automatisch durch darktable erzeugte Tags enthalten"
|
||||||
70
locale/fr_FR/LC_MESSAGES/pdf_slideshow.po
Normal file
70
locale/fr_FR/LC_MESSAGES/pdf_slideshow.po
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
# SOME DESCRIPTIVE TITLE.
|
||||||
|
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||||
|
# This file is distributed under the same license as the PACKAGE package.
|
||||||
|
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||||
|
#
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: \n"
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"POT-Creation-Date: 2017-04-10 09:30+0200\n"
|
||||||
|
"PO-Revision-Date: 2017-04-10 09:48+0200\n"
|
||||||
|
"Language: fr_FR\n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"Last-Translator: Pascal Obry <pascal@obry.net>\n"
|
||||||
|
"Language-Team: \n"
|
||||||
|
"X-Generator: Poedit 1.8.11\n"
|
||||||
|
|
||||||
|
#: pdf_slideshow.lua:55
|
||||||
|
msgid "pdflatex not found"
|
||||||
|
msgstr "pdflatex non trouvé"
|
||||||
|
|
||||||
|
#: pdf_slideshow.lua:63
|
||||||
|
msgid "a pdf viewer"
|
||||||
|
msgstr "lecteur pdf"
|
||||||
|
|
||||||
|
#: pdf_slideshow.lua:64
|
||||||
|
msgid "can be an absolute pathname or the tool may be in the PATH"
|
||||||
|
msgstr "peut être un chemin absolu où l'outil peut être dans le chemin par défaut"
|
||||||
|
|
||||||
|
#: pdf_slideshow.lua:68 pdf_slideshow.lua:95
|
||||||
|
msgid "slideshow title"
|
||||||
|
msgstr "titre du diaporama"
|
||||||
|
|
||||||
|
#: pdf_slideshow.lua:72
|
||||||
|
msgid "transition delay (s)"
|
||||||
|
msgstr "temporisation (s) entre diapositives"
|
||||||
|
|
||||||
|
#: pdf_slideshow.lua:83
|
||||||
|
msgid "include image title"
|
||||||
|
msgstr "inclus le titre de l'image"
|
||||||
|
|
||||||
|
#: pdf_slideshow.lua:85
|
||||||
|
msgid "whether to include the image title (if defined) into the slide"
|
||||||
|
msgstr "indique si le titre de l'image (si défini) doit être inclus dans la diapositive"
|
||||||
|
|
||||||
|
#: pdf_slideshow.lua:89
|
||||||
|
msgid "include image author"
|
||||||
|
msgstr "inclus l'auteur de l'image"
|
||||||
|
|
||||||
|
#: pdf_slideshow.lua:91
|
||||||
|
msgid "whether to include the image author (if defined) into the slide"
|
||||||
|
msgstr "indique si l'auteur de l'image (si défini) doit être inclus dans la diapositive"
|
||||||
|
|
||||||
|
#: pdf_slideshow.lua:167
|
||||||
|
msgid "pdf slideshow"
|
||||||
|
msgstr "diaporama pdf"
|
||||||
|
|
||||||
|
#: pdf_slideshow.lua:220
|
||||||
|
msgid "problem running pdflatex"
|
||||||
|
msgstr "impossible d'exécuter pdflatex"
|
||||||
|
|
||||||
|
#: pdf_slideshow.lua:221 pdf_slideshow.lua:231
|
||||||
|
msgid "problem running "
|
||||||
|
msgstr "impossible d'exécuter "
|
||||||
|
|
||||||
|
#: pdf_slideshow.lua:230
|
||||||
|
msgid "problem running pdf viewer"
|
||||||
|
msgstr "impossible d'exécuter le lecteur pdf"
|
||||||
BIN
locale/fr_FR/LC_MESSAGES/select_untagged.mo
Normal file
BIN
locale/fr_FR/LC_MESSAGES/select_untagged.mo
Normal file
Binary file not shown.
27
locale/fr_FR/LC_MESSAGES/select_untagged.po
Normal file
27
locale/fr_FR/LC_MESSAGES/select_untagged.po
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: \n"
|
||||||
|
"POT-Creation-Date: 2017-09-14 15:42+0200\n"
|
||||||
|
"PO-Revision-Date: 2017-09-14 15:52+0200\n"
|
||||||
|
"Last-Translator: Jannis_V\n"
|
||||||
|
"Language-Team: \n"
|
||||||
|
"Language: fr_FR\n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"X-Generator: Poedit 1.8.7.1\n"
|
||||||
|
"X-Poedit-Basepath: ../../../contrib\n"
|
||||||
|
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||||
|
"X-Poedit-SearchPath-0: select_untagged.lua\n"
|
||||||
|
|
||||||
|
#: select_untagged.lua:38
|
||||||
|
msgid "select untagged images"
|
||||||
|
msgstr "sélection des images sans mots-clés"
|
||||||
|
|
||||||
|
#: select_untagged.lua:64
|
||||||
|
msgid "select untagged"
|
||||||
|
msgstr "sans mots-clés"
|
||||||
|
|
||||||
|
#: select_untagged.lua:64
|
||||||
|
msgid "select all images containing no tags or only tags added by darktable"
|
||||||
|
msgstr "sélection des images sans mots-clés ou seulement avec les mots-clés ajoutés par darktable"
|
||||||
@@ -31,7 +31,7 @@ local dt = require "darktable"
|
|||||||
local https = require "ssl.https"
|
local https = require "ssl.https"
|
||||||
local cjson = require "cjson"
|
local cjson = require "cjson"
|
||||||
|
|
||||||
dt.configuration.check_version(...,{2,0,0},{3,0,0})
|
dt.configuration.check_version(...,{2,0,0},{3,0,0},{4,0,0})
|
||||||
|
|
||||||
-- compare two version strings of the form "major.minor.patch"
|
-- compare two version strings of the form "major.minor.patch"
|
||||||
-- returns -1, 0, 1 if the first version is smaller, equal, greater than the second version,
|
-- returns -1, 0, 1 if the first version is smaller, equal, greater than the second version,
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ USAGE
|
|||||||
|
|
||||||
local dt = require "darktable"
|
local dt = require "darktable"
|
||||||
|
|
||||||
dt.configuration.check_version(...,{3,0,0})
|
dt.configuration.check_version(...,{3,0,0},{4,0,0})
|
||||||
|
|
||||||
-- set this to "false" if you don't want to overwrite metadata fields
|
-- set this to "false" if you don't want to overwrite metadata fields
|
||||||
-- (title, description, creator, publisher and rights) that are already set
|
-- (title, description, creator, publisher and rights) that are already set
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ all tags longer than the given length will be automatically deleted at every res
|
|||||||
]]
|
]]
|
||||||
|
|
||||||
local dt = require "darktable"
|
local dt = require "darktable"
|
||||||
dt.configuration.check_version(...,{2,0,0},{3,0,0})
|
dt.configuration.check_version(...,{2,0,0},{3,0,0},{4,0,0})
|
||||||
|
|
||||||
dt.preferences.register("delete_long_tags", "length", "integer",
|
dt.preferences.register("delete_long_tags", "length", "integer",
|
||||||
"maximum length of tags to keep",
|
"maximum length of tags to keep",
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
]]
|
]]
|
||||||
--[[
|
--[[
|
||||||
RUN ENFUSE ON THE SELECTED IMAGES
|
RUN ENFUSE ON THE SELECTED IMAGES
|
||||||
This script uses enfuse to merge the selected images into one HDR and imports the result.
|
This script uses enfuse to merge the selected images into one tonemapped image and imports the result.
|
||||||
It only works on ldr images (like, JPEG).
|
It only works on ldr images (like, JPEG).
|
||||||
|
|
||||||
USAGE
|
USAGE
|
||||||
@@ -33,30 +33,22 @@ TODO
|
|||||||
]]
|
]]
|
||||||
|
|
||||||
local dt = require "darktable"
|
local dt = require "darktable"
|
||||||
|
local df = require "lib/dtutils.file"
|
||||||
require "official/yield"
|
require "official/yield"
|
||||||
|
local gettext = dt.gettext
|
||||||
|
|
||||||
|
dt.configuration.check_version(...,{3,0,0},{4,0,0})
|
||||||
|
|
||||||
dt.configuration.check_version(...,{3,0,0})
|
-- Tell gettext where to find the .mo file translating messages for a particular domain
|
||||||
|
gettext.bindtextdomain("enfuse",dt.configuration.config_dir.."/lua/locale/")
|
||||||
|
|
||||||
-- thanks Tobias Jakobs for this function (taken from contrib/hugin.lua)
|
local function _(msgid)
|
||||||
local function checkIfBinExists(bin)
|
return gettext.dgettext("enfuse", msgid)
|
||||||
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
|
end
|
||||||
|
|
||||||
-- add a new lib
|
-- add a new lib
|
||||||
-- is enfuse installed?
|
-- 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)
|
-- 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
|
if dt.preferences.read("enfuse", "depth", "integer") == 0 then
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ local dt = require "darktable"
|
|||||||
require "darktable.debug"
|
require "darktable.debug"
|
||||||
require "official/yield"
|
require "official/yield"
|
||||||
|
|
||||||
dt.configuration.check_version(...,{2,1,0},{3,0,0})
|
dt.configuration.check_version(...,{2,1,0},{3,0,0},{4,0,0})
|
||||||
|
|
||||||
dt.preferences.register("generate_image_txt",
|
dt.preferences.register("generate_image_txt",
|
||||||
"enabled",
|
"enabled",
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ This plugin will add a widget at the bottom of the left column in lighttable mod
|
|||||||
|
|
||||||
]]
|
]]
|
||||||
local dt = require "darktable"
|
local dt = require "darktable"
|
||||||
dt.configuration.check_version(...,{2,0,0},{3,0,0})
|
dt.configuration.check_version(...,{2,0,0},{3,0,0},{4,0,0})
|
||||||
|
|
||||||
local main_label = dt.new_widget("label"){selectable = true, ellipsize = "middle", halign = "start"}
|
local main_label = dt.new_widget("label"){selectable = true, ellipsize = "middle", halign = "start"}
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ increase it if you need more temporary selection buffers
|
|||||||
|
|
||||||
]]
|
]]
|
||||||
local dt = require "darktable"
|
local dt = require "darktable"
|
||||||
dt.configuration.check_version(...,{2,0,0},{3,0,0})
|
dt.configuration.check_version(...,{2,0,0},{3,0,0},{4,0,0})
|
||||||
|
|
||||||
local buffer_count = 5
|
local buffer_count = 5
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ Plugin allows you to choose how many thumbnails you need per row
|
|||||||
local dt = require "darktable"
|
local dt = require "darktable"
|
||||||
require "official/yield"
|
require "official/yield"
|
||||||
|
|
||||||
dt.configuration.check_version(...,{2,0,0},{3,0,0})
|
dt.configuration.check_version(...,{2,0,0},{3,0,0},{4,0,0})
|
||||||
|
|
||||||
dt.preferences.register
|
dt.preferences.register
|
||||||
("selection_to_pdf","Open with","string",
|
("selection_to_pdf","Open with","string",
|
||||||
|
|||||||
@@ -25,21 +25,6 @@ USAGE
|
|||||||
local dt = require "darktable"
|
local dt = require "darktable"
|
||||||
local yield_orig = coroutine.yield
|
local yield_orig = coroutine.yield
|
||||||
|
|
||||||
-- ToDo: Test with dt master
|
|
||||||
--[[
|
|
||||||
if (dt.configuration.api_version_major >= 4) then
|
|
||||||
coroutine.yield = function(yield_type, command)
|
|
||||||
if (yield_type == "RUN_COMMAND") then
|
|
||||||
dt.control.execute(command)
|
|
||||||
elseif (yield_type == "FILE_READABLE") then
|
|
||||||
dt.control.read(command)
|
|
||||||
elseif (yield_type == "WAIT_MS") then
|
|
||||||
dt.control.sleep(command)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
]]
|
|
||||||
|
|
||||||
if (dt.configuration.api_version_major < 4) then
|
if (dt.configuration.api_version_major < 4) then
|
||||||
dt.control = {}
|
dt.control = {}
|
||||||
dt.control.execute = function(command)
|
dt.control.execute = function(command)
|
||||||
|
|||||||
Reference in New Issue
Block a user