diff --git a/official/enfuse.lua b/official/enfuse.lua new file mode 100644 index 0000000..32a835b --- /dev/null +++ b/official/enfuse.lua @@ -0,0 +1,174 @@ +--[[ + This file is part of darktable, + copyright (c) 2016 Tobias Ellinghaus + + darktable is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + darktable is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with darktable. If not, see . +]] +--[[ +RUN ENFUSE ON THE SELECTED IMAGES +This script uses enfuse to merge the selected images into one HDR and imports the result. +It only works on ldr images (like, JPEG). + +USAGE +* require this script from your main lua file +* it creates a new lighttable module + +TODO +* remember the exposure_mu value in config when the slider is moved +* make the output filename unique so you can use it more than once per filmroll +* find a less stupid way to make sure the float value of exposure_mu gets turned into a string + with a decimal point instead of a comma in some languages +* export images that are not ldr and remove them afterwards +]] + +local dt = require "darktable" + +dt.configuration.check_version(...,{3,0,0}) + +-- thanks Tobias Jakobs for this function (taken from contrib/hugin.lua) +local function checkIfBinExists(bin) + local handle = io.popen("which "..bin) + local result = handle:read() + local ret + handle:close() + if (result) then + dt.print_error("true checkIfBinExists: "..bin) + ret = true + else + dt.print_error(bin.." not found") + ret = false + end + return ret +end + +-- add a new lib +-- is enfuse installed? +local enfuse_installed = checkIfBinExists("enfuse") + +-- initialize exposure_mu value and depth setting in config to sane defaults (would be 0 otherwise) +if dt.preferences.read("enfuse", "depth", "integer") == 0 then + dt.preferences.write("enfuse", "depth", "integer", 2) + dt.preferences.write("enfuse", "exposure_mu", "float", 0.5) +end + +-- set up some widgets, initialized from config +local exposure_mu = dt.new_widget("slider") +{ + label = "exposure mu", + tooltip = "center also known as MEAN of Gaussian weighting function (0 <= MEAN <= 1); default: 0.5", + hard_min = 0, + hard_max = 1, + value = dt.preferences.read("enfuse", "exposure_mu", "float") +} + +local depth = dt.new_widget("combobox") +{ + label = "depth", + tooltip = "the number of bits per channel of the output image", + value = dt.preferences.read("enfuse", "depth", "integer"), + changed_callback = function(w) dt.preferences.write("enfuse", "depth", "integer", w.selected) end, + "8", "16", "32" +} + +-- ... and tell dt about it all +dt.register_lib( + "enfuse", -- plugin name + "enfuse", -- name + true, -- expandable + false, -- resetable + {[dt.gui.views.lighttable] = {"DT_UI_CONTAINER_PANEL_RIGHT_CENTER", 100}}, -- containers + dt.new_widget("box") -- widget + { + orientation = "vertical", + sensitive = enfuse_installed, + exposure_mu, + depth, + dt.new_widget("button") + { + label = enfuse_installed and "run enfuse" or "enfuse not installed", + clicked_callback = function (_) + -- remember exposure_mu + -- TODO: find a way to save it whenever the value changes + local mu = exposure_mu.value + dt.preferences.write("enfuse", "exposure_mu", "float", mu) + + -- create a temp response file + local response_file = os.tmpname() + local f = io.open(response_file, "w") + if not f then + dt.print("error writing to `"..response_file.."'") + os.remove(response_file) + return + end + + -- add all filenames to the response file + local cnt = 0 + local n_skipped = 0 + local target_dir + for _, i in ipairs(dt.gui.action_images) do + -- only use ldr files as enfuse can't open raws. alternatively we could export raws that we encounter + if i.is_ldr then + cnt = cnt + 1 + f:write(i.path.."/"..i.filename.."\n") + target_dir = i.path + else + dt.print("skipping "..i.filename) + n_skipped = n_skipped + 1 + end + end + f:close() + -- bail out if there is nothing to do + if cnt == 0 then + dt.print("no suitable images selected, nothing to do for enfuse") + os.remove(response_file) + return + end + if n_skipped == 1 then + dt.print(n_skipped.." image skipped") + elseif n_skipped > 1 then + dt.print(n_skipped.." images skipped") + end + + -- call enfuse on the response file + -- TODO: find something nicer + local ugly_decimal_point_hack = string.gsub(string.format("%.04f", mu), ",", ".") + -- TODO: make filename unique + local output_image = target_dir.."/enfuse.tiff" + local command = "enfuse --depth "..depth.value.." --exposure-mu "..ugly_decimal_point_hack + .." -o \""..output_image.."\" \"@"..response_file.."\"" + if coroutine.yield("RUN_COMMAND", command) > 0 then + dt.print("enfuse failed, see terminal output for details") + os.remove(response_file) + return + end + + -- remove the response file + os.remove(response_file) + + -- import resulting tiff + local image = dt.database.import(output_image) + + -- tell the user that everything worked + dt.print("enfuse was successful, resulting image was imported") + -- normally printing to stdout is bad, but we allow enfuse to show its output, so adding one extra line is ok + print("enfuse: done, resulting image '"..output_image.."' was imported with id "..image.id) + end + } + }, + nil,-- view_enter + nil -- view_leave +) + +-- vim: shiftwidth=2 expandtab tabstop=2 cindent syntax=lua +-- kate: hl Lua;