Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
214 changes: 147 additions & 67 deletions contrib/HDRMerge.lua
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,13 @@ Additional tags or style can be applied on auto import as well, if you desire.
Base Options:
Select your desired BPS (bits per sample and Embedded Preview Size.

Batch Options:
Batch Mode Options:
Select if you want to run in batch mode or not
Select the gap, in seconds, between images for auto grouping in batch mode

Group Mode Options:
The HDR image will be placed back in its group. Select if you want it to become the group leader.

See HDRMerge manual for further detail: http://jcelaya.github.io/hdrmerge/documentation/2014/07/11/user-manual.html

Auto-import Options:
Expand Down Expand Up @@ -135,23 +138,20 @@ local function InRange(test, low, high) --tests if test value is within range of
end
end

local function GetFileName(full_path) --Parses a full path (path/filename_identifier.extension) into individual parts
--[[Input: Folder1/Folder2/Folder3/Img_0001.CR2
local function FileNameParts(filename_ext) --Parses a filename (filename_identifier.extension) into individual parts
--[[Input: Img_0001.CR2

Returns:
path: Folder1/Folder2/Folder3/
filename: Img_0001
identifier: 0001
extension: .CR2

EX:
path_1, file_1, id_1, ext_1 = GetFileName(full_path_1)
file_1, id_1 = FileNameParts(im_filename)
]]
local path = string.match(full_path, '.*[\\/]')
local filename = string.gsub(string.match(full_path, '[%w-_]*%.') , '%.' , '' )
local identifier = string.match(filename, '%d*$')
local extension = string.match(full_path, '%.%w*')
return path, filename, identifier, extension
local ext_idx = string.find(filename_ext, '%.[^%.]*$')
local filename = string.sub(filename_ext, 1, ext_idx and ext_idx - 1 or nil)
local identifier = string.match(filename, '%d*$') or ''
return filename, identifier
end

local function CleanSpaces(text) --removes spaces from the front and back of passed in text
Expand Down Expand Up @@ -208,61 +208,58 @@ end
local function UpdateActivePreference() --sliders & entry boxes do not have a click/changed callback, so their values must be saved to the active preference
temp = GUI.HDR.gap.value
dt.preferences.write(mod, 'active_gap', 'integer', temp)
temp = GUI.HDR.make_group_leader.value
dt.preferences.write(mod, 'active_make_group_leader', 'bool', temp)
temp = GUI.Target.add_tags.text
dt.preferences.write(mod, 'active_add_tags', 'string', temp)
end

local function main()
PreCall({HDRM}) --check if furst run then check if install OK
if HDRM.install_error then
dt.print_error('HDRMerge install issue')
dt.print(_('HDRMerge install issue, please ensure the binary path is correct'))
return
end
images = dt.gui.selection() --get selected images
if #images < 2 then --ensure enough images selected
dt.print(_('not enough images selected, select at least 2 images to merge'))
return
end

UpdateActivePreference() --save current gui elements to active preference so those values will be pre-loaded at next startup

--create image string and output path
HDRM.images_string = ''
local function DoBatch(prog_table, images, output_arg)
local prog = {}
-- Copy program arguments
for k, v in pairs(prog_table) do prog[k] = v end
local out_path = ''
local smallest_id = math.huge
local smallest_id_n = math.huge
local smallest_name = ''
local largest_id = 0
local largest_id_n = -1
local largest_id = ''
local source_raw = {}
for _,image in pairs(images) do --loop to concat the images string, also track the image indexes for use in creating the final image name (eg; IMG_1034-1037.dng)
local curr_image = image.path..os_path_seperator..image.filename
HDRM.images_string = HDRM.images_string..df.sanitize_filename(curr_image)..' '
out_path = image.path
_unused, source_name, source_id = GetFileName(image.filename)
source_id = tonumber(source_id) or 0
if source_id < smallest_id then
smallest_id = source_id
smallest_name = source_name
source_raw = image
local image_files = {}
for _,image in ipairs(images) do --loop to concat the images string, also track the image indexes for use in creating the final image name (eg; IMG_1034-1037.dng)
if not image.is_hdr then
local curr_image = image.path..os_path_seperator..image.filename
table.insert(image_files, df.sanitize_filename(curr_image))
source_name, source_id = FileNameParts(image.filename)
local source_id_n = tonumber(source_id) or 0
if source_id_n < smallest_id_n then
out_path = image.path
smallest_id_n = source_id_n
smallest_name = source_name
source_raw = image
end
if source_id_n > largest_id_n then
largest_id = source_id
largest_id_n = source_id_n
end
end
if source_id > largest_id then largest_id = source_id end
end
out_path = out_path..os_path_seperator..smallest_name..'-'..largest_id..'.dng'
out_path = df.create_unique_filename(out_path)

--create argument string
HDRM.arg_string = HDRM.args.bps.text..GUI.HDR.bps.value..' '..HDRM.args.size.text..GUI.HDR.size.value..' '
if GUI.HDR.batch.value then
HDRM.arg_string = HDRM.arg_string..HDRM.args.batch.text..HDRM.args.gap.text..math.floor(GUI.HDR.gap.value)..' -a'
else
HDRM.arg_string = HDRM.arg_string..'-o '..df.sanitize_filename(out_path)
if #image_files < 2 then
dt.print(_("not enough images in group, skipping"))
return
end
prog.images_string = table.concat(image_files, ' ')
if output_arg then
out_path = out_path..os_path_seperator..smallest_name..'-'..largest_id..'.dng'
out_path = df.create_unique_filename(out_path)
prog.arg_string = prog.arg_string..'-o '..df.sanitize_filename(out_path)
end

-- create run command and execute
local run_cmd = BuildExecuteCmd(HDRM)
local run_cmd = BuildExecuteCmd(prog)
dt.print_log('running HDRMerge: '..run_cmd)
resp = dsys.external_command(run_cmd)

if resp == 0 and not GUI.HDR.batch.value then
if resp == 0 and output_arg then
local imported = dt.database.import(out_path) -- import the new file
if GUI.Target.style.selected > 1 then -- apply selected style
local set_style = styles[GUI.Target.style.selected - 1]
Expand All @@ -283,11 +280,65 @@ local function main()
end
end
dt.print(_('HDRMerge completed successfully'))
else
return imported
elseif resp == 0 then
dt.print(_('HDRMerge completed successfully'))
return nil -- TODO: can detect created files?
elseif resp ~= 0 then
dt.print_error('HDRMerge failed')
dt.print(_('HDRMerge failed'))
end
end

local function main()
PreCall({HDRM}) --check if furst run then check if install OK
if HDRM.install_error then
dt.print_error('HDRMerge install issue')
dt.print(_('HDRMerge install issue, please ensure the binary path is correct'))
return
end
images = dt.gui.action_images --get selected images
if #images < 2 then --ensure enough images selected
dt.print(_('not enough images selected, select at least 2 images to merge'))
return
end

UpdateActivePreference() --save current gui elements to active preference so those values will be pre-loaded at next startup

--create argument string
HDRM.arg_string = HDRM.args.bps.text..GUI.HDR.bps.value..' '..HDRM.args.size.text..GUI.HDR.size.value..' '
if GUI.HDR.mode.selected == 2 then
end

-- do mode operation
if GUI.HDR.mode.selected == 1 then
doBatch(HDRM, images, true)
elseif GUI.HDR.mode.selected == 2 then
HDRM.arg_string = HDRM.arg_string..HDRM.args.batch.text..HDRM.args.gap.text..math.floor(GUI.HDR.gap.value)..' -a'
dBatch(HDRM, images, false)
elseif GUI.HDR.mode.selected == 3 then
local by_group = {}
for _, im in ipairs(images) do
local leader = im.group_leader
if not by_group[leader] then by_group[leader] = {} end
table.insert(by_group[leader], im)
end
for leader, group in pairs(by_group) do
local imported = DoBatch(HDRM, group, true)
if imported then
imported:group_with(leader)

if GUI.HDR.make_group_leader.value then
imported:make_group_leader()
end
end
if dt.gui.libs.global_toolbox.grouping then
-- Toggle off & on to update the view
dt.gui.libs.global_toolbox.grouping = false
dt.gui.libs.global_toolbox.grouping = true
end
end
end
end

local function install_module()
Expand Down Expand Up @@ -353,21 +404,12 @@ GUI.HDR.size = dt.new_widget('combobox'){
dt.preferences.write(mod, 'active_size_ind', 'integer', self.selected)
end
}
GUI.HDR.batch = dt.new_widget('check_button'){
label = _('batch mode'),
value = dt.preferences.read(mod, 'active_batch', 'bool'),
tooltip = _('enable batch mode operation \nNOTE: resultant files will NOT be auto-imported'),
clicked_callback = function(self)
dt.preferences.write(mod, 'active_batch', 'bool', self.value)
GUI.HDR.gap.sensitive = self.value
end,
reset_callback = function(self) self.value = false end
}

temp = dt.preferences.read(mod, 'active_gap', 'integer')
if not InRange(temp, 1, 3600) then temp = 3 end
GUI.HDR.gap = dt.new_widget('slider'){
label = _('batch gap [sec.]'),
tooltip = _('gap, in seconds, between batch mode groups'),
tooltip = _('gap, in seconds, between batch mode images within group'),
soft_min = 1,
soft_max = 30,
hard_min = 1,
Expand All @@ -380,6 +422,44 @@ GUI.HDR.gap = dt.new_widget('slider'){
self.value = 3
end
}

GUI.HDR.make_group_leader = dt.new_widget('check_button'){
label = _('make group leader'),
tooltip = _('make new image the group leader'),
value = dt.preferences.read(mod, 'active_make_group_leader', 'bool')
}
temp = dt.preferences.read(mod, 'active_mode', 'integer')
if not InRange(temp, 1, 3) then
if dt.preferences.read(mod, 'active_batch', 'bool') then
temp = 2
else
temp = 1
end
end
GUI.HDR.opts = dt.new_widget('stack'){
dt.new_widget('box'),
GUI.HDR.gap,
GUI.HDR.make_group_leader,
active = temp
}
GUI.HDR.mode = dt.new_widget('combobox'){
label = _('mode'),
tooltip = _([[Operating mode:
all: merge all images into a single image
batch: group images into sets by comparing creation time. Images will NOT be auto-imported
groups: merge images according to image grouping]]),
value = temp,
changed_callback = function(self)
dt.preferences.write(mod, 'active_mode', 'integer', self.selected)
GUI.HDR.opts.active = self.selected
end,
reset_callback = function(self) self.selected = 1 end,
_('all'),
_('batch'),
_('groups')
}


local lbl_import = dt.new_widget('section_label'){
label = _('import options')
}
Expand Down Expand Up @@ -439,8 +519,8 @@ GUI.options = dt.new_widget('box'){
lbl_hdr,
GUI.HDR.bps,
GUI.HDR.size,
GUI.HDR.batch,
GUI.HDR.gap,
GUI.HDR.mode,
GUI.HDR.opts,
lbl_import,
GUI.Target.style,
GUI.Target.copy_tags,
Expand Down Expand Up @@ -483,4 +563,4 @@ script_data.restart = restart
script_data.destroy_method = "hide"
script_data.show = restart

return script_data
return script_data