diff --git a/contrib/kml_export.lua b/contrib/kml_export.lua
new file mode 100644
index 0000000..b00b030
--- /dev/null
+++ b/contrib/kml_export.lua
@@ -0,0 +1,231 @@
+--[[
+ This file is part of darktable,
+ Copyright 2014 by Tobias Jakobs.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+]]
+--[[
+darktable KML export script
+
+ADDITIANAL SOFTWARE NEEDED FOR THIS SCRIPT
+* mkdir
+* zip (only if you create KMZ files)
+* convert (ImageMagick)
+* xdg-open
+* xdg-user-dir
+
+WARNING
+This script is only testet with Linux
+
+USAGE
+* require this script from your main lua file
+]]
+
+dt = require "darktable"
+dt.configuration.check_version(...,{2,0,1})
+
+function isnan(x) return x ~= x end
+
+function spairs(_table, order) -- Code copied from http://stackoverflow.com/questions/15706270/sort-a-table-in-lua
+ -- collect the keys
+ local keys = {}
+ for _key in pairs(_table) do keys[#keys + 1] = _key end
+
+ -- if order function given, sort by it by passing the table and keys a, b,
+ -- otherwise just sort the keys
+ if order then
+ table.sort(keys, function(a,b) return order(_table, a, b) end)
+ else
+ table.sort(keys)
+ end
+
+ -- return the iterator function
+ local i = 0
+ return function()
+ i = i + 1
+ if keys[i] then
+ return keys[i], _table[keys[i]]
+ end
+ end
+end
+
+local function show_status(storage, image, format, filename, number, total, high_quality, extra_data)
+ dt.print("Export Image "..tostring(number).."/"..tostring(total))
+end
+
+local function create_kml_file(storage, image_table, extra_data)
+
+
+
+ dt.print_error("Will try to export KML file now")
+
+ if ( dt.preferences.read("kml_export","CreateKMZ","bool") == true ) then
+ exportDirectory = dt.configuration.tmp_dir
+ imageFoldername = ""
+ else
+ exportDirectory = dt.preferences.read("kml_export","ExportDirectory","string")
+
+ -- Creates dir if not exsists
+ imageFoldername = "files/"
+ local mkdirCommand = "mkdir -p "..exportDirectory.."/"..imageFoldername
+ coroutine.yield("run_command", mkdirCommand)
+ end
+
+
+ -- Create the thumbnails
+ for _,image in pairs(image_table) do
+ local path, filename, filetype = string.match(image, "(.-)([^\\/]-%.?([^%.\\/]*))$")
+ filename = string.upper(string.gsub(filename,"%.", "_"))
+
+ -- convert -size 92x92 filename.jpg -resize 92x92 +profile "*" thumbnail.jpg
+ -- In this example, '-size 120x120' gives a hint to the JPEG decoder that the image is going to be downscaled to
+ -- 120x120, allowing it to run faster by avoiding returning full-resolution images to GraphicsMagick for the
+ -- subsequent resizing operation. The '-resize 120x120' specifies the desired dimensions of the output image. It
+ -- will be scaled so its largest dimension is 120 pixels. The '+profile "*"' removes any ICM, EXIF, IPTC, or other
+ -- profiles that might be present in the input and aren't needed in the thumbnail.
+
+ local concertToThumbCommand = "convert -size 96x96 "..image.." -resize 92x92 -mattecolor \"#FFFFFF\" -frame 2x2 +profile \"*\" "..exportDirectory.."/"..imageFoldername.."thumb_"..filename..".jpg"
+ -- USE coroutine.yield. It does not block the UI
+ coroutine.yield("run_command", concertToThumbCommand)
+ local concertCommand = "convert -size 438x438 "..image.." -resize 438x438 +profile \"*\" "..exportDirectory.."/"..imageFoldername..filename..".jpg"
+ coroutine.yield("run_command", concertCommand)
+
+ local pattern = "[/]?([^/]+)$"
+ filmName = string.match(_.film.path, pattern)
+ end
+
+ exportKMLFilename = filmName..".kml"
+ exportKMZFilename = filmName..".kmz"
+
+ -- Create the KML file
+ kml_file = "\n"
+ kml_file = kml_file.."\n"
+ kml_file = kml_file.."\n"
+
+ --image_table = dt.gui.selection();
+ kml_file = kml_file..""..filmName.."\n"
+ kml_file = kml_file.." Exported from darktable\n"
+
+ for image,_ in pairs(image_table) do
+ filename = string.upper(string.gsub(image.filename,"%.", "_"))
+
+ if ((not isnan(image.longitude) and not isnan(image.latitude)) and
+ (image.longitude ~= 0 and image.latitude ~= 90) -- Sometimes the north-pole but most likely just wrong data
+ ) then
+ kml_file = kml_file.." \n"
+ kml_file = kml_file.." "..image.filename.."\n"
+ --kml_file = kml_file.." \n"
+
+ kml_file = kml_file.." \n"
+
+ kml_file = kml_file.." \n"
+ kml_file = kml_file.." 1\n"
+ kml_file = kml_file.." "..string.gsub(tostring(image.longitude),",", ".")..","..string.gsub(tostring(image.latitude),",", ".")..",0\n"
+ kml_file = kml_file.." \n"
+ kml_file = kml_file.." "..string.gsub(image.exif_datetime_taken," ", "T").."Z".."\n"
+ kml_file = kml_file.." \n"
+ kml_file = kml_file.." \n"
+
+ kml_file = kml_file.." \n"
+ end
+ end
+
+-- Connects all images with an path
+ if ( dt.preferences.read("kml_export","CreatePath","bool") == true ) then
+ kml_file = kml_file.." \n"
+ kml_file = kml_file.." Path\n" -- ToDo: I think a better name would be nice
+ --kml_file = kml_file.." \n"
+
+ kml_file = kml_file.." \n"
+
+ kml_file = kml_file.." \n"
+ kml_file = kml_file.." \n"
+
+ for image,_ in spairs(image_table, function(t,a,b) return t[b] < t[a] end) do
+ if ((not isnan(image.longitude) and not isnan(image.latitude)) and
+ (image.longitude ~= 0 and image.latitude ~= 90) -- Sometimes the north-pole but most likely just wrong data
+ ) then
+ kml_file = kml_file.." "..string.gsub(tostring(image.longitude),",", ".")..","..string.gsub(tostring(image.latitude),",", ".")..",0\n"
+ end
+ end
+ kml_file = kml_file.." \n"
+ kml_file = kml_file.." \n"
+
+ kml_file = kml_file.." \n"
+ end
+
+ kml_file = kml_file.."\n"
+ kml_file = kml_file..""
+
+ file = io.open(exportDirectory.."/"..exportKMLFilename, "w")
+ file:write(kml_file)
+ file:close()
+
+ dt.print("KML file created in "..exportDirectory)
+
+-- Compress the files to create a KMZ file
+ if ( dt.preferences.read("kml_export","CreateKMZ","bool") == true ) then
+ exportDirectory = dt.preferences.read("kml_export","ExportDirectory","string")
+ -- USE coroutine.yield. It does not block the UI
+ local createKMZCommand = "zip --test --move --junk-paths "
+ createKMZCommand = createKMZCommand .."\""..exportDirectory.."/"..exportKMZFilename.."\" "
+ createKMZCommand = createKMZCommand .."\""..dt.configuration.tmp_dir.."/"..exportKMLFilename.."\" \""..dt.configuration.tmp_dir.."/"..imageFoldername.."\"*"
+ coroutine.yield("run_command", createKMZCommand)
+ end
+
+-- Open the file with the standard programm
+ if ( dt.preferences.read("kml_export","OpenKmlFile","bool") == true ) then
+ local kmlFileOpenCommand
+
+ if ( dt.preferences.read("kml_export","CreateKMZ","bool") == true ) then
+ kmlFileOpenCommand = "xdg-open "..exportDirectory.."/\""..exportKMZFilename.."\""
+ else
+ kmlFileOpenCommand = "xdg-open "..exportDirectory.."/\""..exportKMLFilename.."\""
+ end
+ coroutine.yield("run_command", kmlFileOpenCommand)
+ end
+
+
+end
+
+-- Preferences
+dt.preferences.register("kml_export", "OpenKmlFile", "bool", "KML export: Open KML/KMZ file after export", "Opens the KML file after the export with the standard programm for KML files", false )
+
+local handle = io.popen("xdg-user-dir DESKTOP")
+local result = handle:read()
+handle:close()
+dt.preferences.register("kml_export", "ExportDirectory", "directory", "KML export: Export directory", "A directory that will be used to export the KML/KMZ files", result )
+
+dt.preferences.register("kml_export", "CreatePath", "bool", "KML export: Connect images with path", "connect all images with a path", false )
+dt.preferences.register("kml_export", "CreateKMZ", "bool", "KML export: Create KMZ file", "Compress all imeges to one KMZ file", true )
+
+-- Register
+dt.register_storage("kml_export", "KML/KMZ Export", nil, create_kml_file)
+