diff --git a/contrib/image_time.lua b/contrib/image_time.lua index dbd15ba..fef5931 100644 --- a/contrib/image_time.lua +++ b/contrib/image_time.lua @@ -138,8 +138,9 @@ script_data.show = nil -- only required for libs since the destroy_method only h -local PS = dt.configuration.runnin_os == "windows" and "\\" or "/" -local ERROR = -1 +local PS = dt.configuration.runnin_os == "windows" and "\\" or "/" +local ERROR = -1 +local HAS_INTERNAL_METADATA = dt.metadata.exists("Exif.Image.DataTime") -- function to convert from exif time to system time local function exiftime2systime(exiftime) @@ -241,21 +242,30 @@ end local function _get_windows_image_file_creation_time(image) local datetime = nil - local p = io.popen("dir " .. image.path .. PS .. image.filename) - if p then - for line in p:lines() do - if string.match(line, ds.sanitize_lua(image.filename)) then - local mo, day, yr, hr, min, apm = string.match(line, "(%d+)/(%d+)/(%d+) (%d-):(%d+) (%S+)") - if apm == "PM" then - hr = hr + 12 - end - datetime = vars2exiftime(yr, mo, day, hr, min, 0) - end - end - p:close() + local datestring = nil + + if HAS_INTERNAL_METADATA then + datestring = image.DateString else - dt.print(string.format(_("unable to get information for %s"), image.filename)) - datetime = ERROR + local p = io.popen("dir " .. image.path .. PS .. image.filename) + if p then + for line in p:lines() do + if string.match(line, ds.sanitize_lua(image.filename)) then + datestring = line + end + end + p:close() + else + dt.print(string.format(_("unable to get information for %s"), image.filename)) + datetime = ERROR + end + end + if datestring then + local mo, day, yr, hr, min, apm = string.match(datestring, "(%d+)/(%d+)/(%d+) (%d-):(%d+) (%S+)") + if apm == "PM" then + hr = hr + 12 + end + datetime = vars2exiftime(yr, mo, day, hr, min, 0) end return datetime end diff --git a/official/auto_straighten.lua b/official/auto_straighten.lua index 2849370..3f22703 100644 --- a/official/auto_straighten.lua +++ b/official/auto_straighten.lua @@ -211,9 +211,14 @@ local function straighten_image(image) for line in pipe:lines() do local pr, val = string.match(line, "(.).+: (.+)") if pr == "R" then + local sign = 1.0 dt.print_log("roll angle is " .. val) log.msg(log.debug, "roll angle is " .. val) - roll = determine_correction(tonumber(val)) + -- check for Nidon and change the sign + if string.match(string.upper(image.exif_maker), "NIKON") then + sign = -1.0 + end + roll = determine_correction(tonumber(val) * sign) dt.print_log("corrected roll angle is " .. roll) log.msg(log.debug, "corrected roll angle is " .. roll) elseif pr == "P" then diff --git a/official/extract_burst_roll_images.lua b/official/extract_burst_roll_images.lua index 90871b9..d487f45 100644 --- a/official/extract_burst_roll_images.lua +++ b/official/extract_burst_roll_images.lua @@ -127,6 +127,9 @@ local CS = dt.configuration.running_os == "windows" and "&" or ";" local EXIFTOOL = df.check_if_bin_exists("exiftool") local EXIV2 = df.check_if_bin_exists("exiv2") local DNGLAB = df.check_if_bin_exists("dnglab") +local EXIV2TAG = "Exif.Canon.RawBurstModeRoll" + +local HAS_INTERNAL_METADATA = dt.metadata.exists(EXIV2TAG) local DNGLAB_ARGS = " convert --image-index all --embed-raw false " local EXIV2_ARGS = " -K Exif.Canon.RawBurstModeRoll -pt " @@ -150,6 +153,7 @@ local extract_burst_roll_images = {} extract_burst_roll_images.preferred_tag_reader = nil extract_burst_roll_images.on_import = true +extract_burst_roll_images.select_button = true extract_burst_roll_images.imported_images = {} extract_burst_roll_images.log_level = DEFAULT_LOG_LEVEL @@ -172,9 +176,18 @@ dt.preferences.register(MODULE, -- script: This is a string used to avoid "bool", -- type _("extract burst roll images on import"), -- label _("extract burst roll images on import"), -- tooltip + false) -- default + +-- display selection button +dt.preferences.register(MODULE, -- 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. + "select_button", -- name + "bool", -- type + _("display select burst roll images button"), -- label + _("add a button to the select module to select burst roll images"), -- tooltip true) -- default + -- - - - - - - - - - - - - - - - - - - - - - - - -- A L I A S E S -- - - - - - - - - - - - - - - - - - - - - - - - @@ -256,27 +269,40 @@ end local function is_burst_roll_image(image) local old_log_level = set_log_level() local result = false - local cmd = EXIFTOOL .. EXIFTOOL_ARGS - if ebri.preferred_tag_reader == "exiv2" then - cmd = EXIV2 .. EXIV2_ARGS - end - - local p = io.popen(cmd .. ds.sanitize(image.path) .. PS .. ds.sanitize(image.filename)) - if p then - for line in p:lines() do - if ebri.preferred_tag_reader == "exiv2" then - line = get_last_value(line) - end - line = tonumber(line) - if type(line) == "number" then - if tonumber(line) > 0 then - log.msg(log.info, image.filename .. " is a burst roll container image") + if HAS_INTERNAL_METADATA then + if image.RawBurstModeRoll then + local val = get_last_value(image.RawBurstModeRoll) + val = tonumber(val) + if type(val) == "number" then + if val > 0 then result = true end end end - p:close() + else + local cmd = EXIFTOOL .. EXIFTOOL_ARGS + + if ebri.preferred_tag_reader == "exiv2" then + cmd = EXIV2 .. EXIV2_ARGS + end + + local p = io.popen(cmd .. ds.sanitize(image.path) .. PS .. ds.sanitize(image.filename)) + if p then + for line in p:lines() do + if ebri.preferred_tag_reader == "exiv2" then + line = get_last_value(line) + end + line = tonumber(line) + if type(line) == "number" then + if line > 0 then + log.msg(log.info, image.filename .. " is a burst roll container image") + result = true + end + end + end + p:close() + end end restore_log_level(old_log_level) @@ -321,6 +347,14 @@ local function extract_burst(image) restore_log_level(old_log_level) end +local function extract_burst_images(images) + for _, image in ipairs(images) do + if is_burst_roll_image(image) then + extract_burst(image) + end + end +end + local function process_image(image) local old_log_level = set_log_level() if is_burst_roll_image(image) then @@ -384,36 +418,86 @@ local function process_import(images) restore_log_level(old_log_level) end +local function select_burst_roll_images(event, images) + local old_log_level = set_log_level() + local selected = {} + + for _, image in ipairs(images) do + if is_burst_roll_image(image) then + table.insert(selected, image) + end + end + + restore_log_level(old_log_level) + return selected +end + +local function set_select_sensitive() + if #dt.collection > 0 then + dt.gui.libs.select.set_sensitive(MODULE, true) + else + dt.gui.libs.select.set_sensitive(MODULE, false) + end +end + +local function set_action_sensitive() + local sensitive = false + if #dt.gui.action_images > 0 then + if is_burst_roll_image(dt.gui.action_images[1]) then + sensitive = true + end + end + dt.gui.libs.image.set_sensitive(MODULE, sensitive) +end -- - - - - - - - - - - - - - - - - - - - - - - - -- M A I N P R O G R A M -- - - - - - - - - - - - - - - - - - - - - - - - -if not DNGLAB then - log.msg(log.error, MODULE .. _("dnglab executable not found")) - log.msg(log.screen, script_data.metadata.name .. _(": dnglab executable not found, exiting...")) - return + if not DNGLAB then + log.msg(log.error, MODULE .. _("dnglab executable not found")) + log.msg(log.screen, script_data.metadata.name .. _(": dnglab executable not found, exiting...")) + return + end + +if HAS_INTERNAL_METADATA then + log.msg(log.info, "Exif.Canon.RawBurstModeRoll detected, using internal metadata") +else + if not EXIFTOOL and not EXIV2 then + log.msg(log.error, MODULE .. _("no exif tag reader available")) + log.msg(log.screen, script_data.metadata.name .. _(" no exif tag reader available, exiting...")) + return + end + + ebri.preferred_tag_reader = pref_read("tag_reader", "enum") + + if not string.match(EXIFTOOL, ebri.preferred_tag_reader) and not string.match(EXIV2, ebri.preferred_tag_reader) then + log.msg(log.error, MODULE .. " selected tag " .. ebri.preferred_tag_reader .." not available") + log.msg(log.screen, script_data.metadata.name .. string.format(_(" selected tag reader %s not available"), ebri.preferred_tag_reader)) + return + end end -if not EXIFTOOL and not EXIV2 then - log.msg(log.error, MODULE .. _("no exif tag reader available")) - log.msg(log.screen, script_data.metadata.name .. _(" no exif tag reader available, exiting...")) - return -end - -ebri.preferred_tag_reader = pref_read("tag_reader", "enum") - -if not string.match(EXIFTOOL, ebri.preferred_tag_reader) and not string.match(EXIV2, ebri.preferred_tag_reader) then - log.msg(log.error, MODULE .. " selected tag " .. ebri.preferred_tag_reader .." not available") - log.msg(log.screen, script_data.metadata.name .. string.format(_(" selected tag reader %s not available"), ebri.preferred_tag_reader)) - return -end - -ebri.on_import = dt.preferences.read(MODULE, "on_import", "bool") +ebri.on_import = pref_read("on_import", "bool") +ebri.select_button = pref_read("select_button", "bool") -- - - - - - - - - - - - - - - - - - - - - - - - -- U S E R I N T E R F A C E -- - - - - - - - - - - - - - - - - - - - - - - - +if ebri.select_button then + dt.gui.libs.select.register_selection(MODULE, _("select burst roll images"), select_burst_roll_images, + _("select burst roll image containers")) +end + +dt.gui.libs.image.register_action( + MODULE, + _("extract burst roll images"), + function(event, images) + extract_burst_images(images) + end, + _("extract and group burst roll images with container") +) + -- - - - - - - - - - - - - - - - - - - - - - - - -- D A R K T A B L E I N T E G R A T I O N -- - - - - - - - - - - - - - - - - - - - - - - - @@ -421,6 +505,10 @@ ebri.on_import = dt.preferences.read(MODULE, "on_import", "bool") local function destroy() dt.destroy_event(MODULE, "post-import-film") dt.destroy_event(MODULE, "post-import-image") + if ebri.select_button then + dt.gui.libs.select.destroy_selection(MODULE) + end + dt.gui.libs.image.action.destroy_action(MODULE) end script_data.destroy = destroy @@ -444,6 +532,27 @@ dt.register_event(MODULE, "post-import-image", end ) +dt.register_event(MODULE, "selection-changed", + function(event) + set_action_sensitive() + end +) + +if dt.preferences.read("darktable", "plugins/lighttable/act_on", "bool") then + dt.print_log("adding mouse-over-image-changed event") + dt.register_event(MODULE, "mouse-over-image-changed", + function(event, image) + set_action_sensitive() + end + ) +end + +dt.register_event(MODULE, "collection-changed", + function(event) + set_select_sensitive() + end +) + if not dt.query_event(MODULE, "shortcut") then dt.register_event(MODULE, "shortcut", function(event, shortcut)