Skip to content

Commit f4c2a41

Browse files
committed
HDRMerge: add "groups" mode
For workflow together with e.g AutoGrouper, gives the ability to select multiple bracketed groups and runs HDRMerge on each of them, adding the result back to the group.
1 parent b49352e commit f4c2a41

File tree

1 file changed

+135
-54
lines changed

1 file changed

+135
-54
lines changed

contrib/HDRMerge.lua

Lines changed: 135 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,13 @@ Additional tags or style can be applied on auto import as well, if you desire.
3434
Base Options:
3535
Select your desired BPS (bits per sample and Embedded Preview Size.
3636
37-
Batch Options:
37+
Batch Mode Options:
3838
Select if you want to run in batch mode or not
3939
Select the gap, in seconds, between images for auto grouping in batch mode
4040
41+
Group Mode Options:
42+
The HDR image will be placed back in its group. Select if you want it to become the group leader.
43+
4144
See HDRMerge manual for further detail: http://jcelaya.github.io/hdrmerge/documentation/2014/07/11/user-manual.html
4245
4346
Auto-import Options:
@@ -208,61 +211,55 @@ end
208211
local function UpdateActivePreference() --sliders & entry boxes do not have a click/changed callback, so their values must be saved to the active preference
209212
temp = GUI.HDR.gap.value
210213
dt.preferences.write(mod, 'active_gap', 'integer', temp)
214+
temp = GUI.HDR.make_group_leader.value
215+
dt.preferences.write(mod, 'active_make_group_leader', 'bool', temp)
211216
temp = GUI.Target.add_tags.text
212217
dt.preferences.write(mod, 'active_add_tags', 'string', temp)
213218
end
214219

215-
local function main()
216-
PreCall({HDRM}) --check if furst run then check if install OK
217-
if HDRM.install_error then
218-
dt.print_error('HDRMerge install issue')
219-
dt.print(_('HDRMerge install issue, please ensure the binary path is correct'))
220-
return
221-
end
222-
images = dt.gui.action_images --get selected images
223-
if #images < 2 then --ensure enough images selected
224-
dt.print(_('not enough images selected, select at least 2 images to merge'))
225-
return
226-
end
227-
228-
UpdateActivePreference() --save current gui elements to active preference so those values will be pre-loaded at next startup
229-
230-
--create image string and output path
231-
HDRM.images_string = ''
220+
local function DoBatch(prog_table, images, output_arg)
221+
local prog = {}
222+
-- Copy program arguments
223+
for k, v in pairs(prog_table) do prog[k] = v end
232224
local out_path = ''
233225
local smallest_id = math.huge
234226
local smallest_name = ''
235227
local largest_id = 0
236228
local source_raw = {}
237-
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)
238-
local curr_image = image.path..os_path_seperator..image.filename
239-
HDRM.images_string = HDRM.images_string..df.sanitize_filename(curr_image)..' '
240-
out_path = image.path
241-
_unused, source_name, source_id = GetFileName(image.filename)
242-
source_id = tonumber(source_id) or 0
243-
if source_id < smallest_id then
244-
smallest_id = source_id
245-
smallest_name = source_name
246-
source_raw = image
229+
local image_files = {}
230+
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)
231+
if not image.is_hdr then
232+
num_images = num_images + 1
233+
local curr_image = image.path..os_path_seperator..image.filename
234+
table.insert(image_files, df.sanitize_filename(curr_image))
235+
_unused, source_name, source_id = GetFileName(image.filename)
236+
source_id = tonumber(source_id) or 0
237+
if source_id < smallest_id then
238+
out_path = image.path
239+
smallest_id = source_id
240+
smallest_name = source_name
241+
source_raw = image
242+
end
243+
if source_id > largest_id then largest_id = source_id end
247244
end
248-
if source_id > largest_id then largest_id = source_id end
249245
end
250-
out_path = out_path..os_path_seperator..smallest_name..'-'..largest_id..'.dng'
251-
out_path = df.create_unique_filename(out_path)
252-
253-
--create argument string
254-
HDRM.arg_string = HDRM.args.bps.text..GUI.HDR.bps.value..' '..HDRM.args.size.text..GUI.HDR.size.value..' '
255-
if GUI.HDR.batch.value then
256-
HDRM.arg_string = HDRM.arg_string..HDRM.args.batch.text..HDRM.args.gap.text..math.floor(GUI.HDR.gap.value)..' -a'
257-
else
258-
HDRM.arg_string = HDRM.arg_string..'-o '..df.sanitize_filename(out_path)
246+
if #image_files < 2 then
247+
dt.print(_("not enough images in group, skipping"))
248+
return
249+
end
250+
prog.images_string = table.concat(image_files, ' ')
251+
if output_arg then
252+
out_path = out_path..os_path_seperator..smallest_name..'-'..largest_id..'.dng'
253+
out_path = df.create_unique_filename(out_path)
254+
prog.arg_string = prog.arg_string..'-o '..df.sanitize_filename(out_path)
259255
end
260256

261257
-- create run command and execute
262-
local run_cmd = BuildExecuteCmd(HDRM)
258+
local run_cmd = BuildExecuteCmd(prog)
259+
dt.print_log('running HDRMerge: '..run_cmd)
263260
resp = dsys.external_command(run_cmd)
264261

265-
if resp == 0 and not GUI.HDR.batch.value then
262+
if resp == 0 and output_arg then
266263
local imported = dt.database.import(out_path) -- import the new file
267264
if GUI.Target.style.selected > 1 then -- apply selected style
268265
local set_style = styles[GUI.Target.style.selected - 1]
@@ -283,11 +280,66 @@ local function main()
283280
end
284281
end
285282
dt.print(_('HDRMerge completed successfully'))
286-
else
283+
return imported
284+
elseif resp == 0 then
285+
dt.print(_('HDRMerge completed successfully'))
286+
return nil -- TODO: can detect created files?
287+
elseif resp ~= 0 then
287288
dt.print_error('HDRMerge failed')
288289
dt.print(_('HDRMerge failed'))
289290
end
291+
end
292+
293+
local function main()
294+
PreCall({HDRM}) --check if furst run then check if install OK
295+
if HDRM.install_error then
296+
dt.print_error('HDRMerge install issue')
297+
dt.print(_('HDRMerge install issue, please ensure the binary path is correct'))
298+
return
299+
end
300+
images = dt.gui.action_images --get selected images
301+
if #images < 2 then --ensure enough images selected
302+
dt.print(_('not enough images selected, select at least 2 images to merge'))
303+
return
304+
end
305+
306+
UpdateActivePreference() --save current gui elements to active preference so those values will be pre-loaded at next startup
307+
308+
--create argument string
309+
HDRM.arg_string = HDRM.args.bps.text..GUI.HDR.bps.value..' '..HDRM.args.size.text..GUI.HDR.size.value..' '
310+
if GUI.HDR.mode.selected == 2 then
311+
end
290312

313+
-- do mode operation
314+
if GUI.HDR.mode.selected == 1 then
315+
doBatch(HDRM, images, true)
316+
elseif GUI.HDR.mode.selected == 2 then
317+
HDRM.arg_string = HDRM.arg_string..HDRM.args.batch.text..HDRM.args.gap.text..math.floor(GUI.HDR.gap.value)..' -a'
318+
dBatch(HDRM, images, false)
319+
elseif GUI.HDR.mode.selected == 3 then
320+
local by_group = {}
321+
for _, im in ipairs(images) do
322+
local leader = im.group_leader
323+
if not by_group[leader] then
324+
by_group[leader] = leader:get_group_members()
325+
end
326+
end
327+
for leader, group in pairs(by_group) do
328+
local imported = DoBatch(HDRM, group, true)
329+
if imported then
330+
imported:group_with(leader)
331+
332+
if GUI.HDR.make_group_leader.value then
333+
imported:make_group_leader()
334+
end
335+
end
336+
if dt.gui.libs.global_toolbox.grouping then
337+
-- Toggle off & on to update the view
338+
dt.gui.libs.global_toolbox.grouping = false
339+
dt.gui.libs.global_toolbox.grouping = true
340+
end
341+
end
342+
end
291343
end
292344

293345
local function install_module()
@@ -353,21 +405,12 @@ GUI.HDR.size = dt.new_widget('combobox'){
353405
dt.preferences.write(mod, 'active_size_ind', 'integer', self.selected)
354406
end
355407
}
356-
GUI.HDR.batch = dt.new_widget('check_button'){
357-
label = _('batch mode'),
358-
value = dt.preferences.read(mod, 'active_batch', 'bool'),
359-
tooltip = _('enable batch mode operation \nNOTE: resultant files will NOT be auto-imported'),
360-
clicked_callback = function(self)
361-
dt.preferences.write(mod, 'active_batch', 'bool', self.value)
362-
GUI.HDR.gap.sensitive = self.value
363-
end,
364-
reset_callback = function(self) self.value = false end
365-
}
408+
366409
temp = dt.preferences.read(mod, 'active_gap', 'integer')
367410
if not InRange(temp, 1, 3600) then temp = 3 end
368411
GUI.HDR.gap = dt.new_widget('slider'){
369412
label = _('batch gap [sec.]'),
370-
tooltip = _('gap, in seconds, between batch mode groups'),
413+
tooltip = _('gap, in seconds, between batch mode images within group'),
371414
soft_min = 1,
372415
soft_max = 30,
373416
hard_min = 1,
@@ -380,6 +423,44 @@ GUI.HDR.gap = dt.new_widget('slider'){
380423
self.value = 3
381424
end
382425
}
426+
427+
GUI.HDR.make_group_leader = dt.new_widget('check_button'){
428+
label = _('make group leader'),
429+
tooltip = _('make new image the group leader'),
430+
value = dt.preferences.read(mod, 'active_make_group_leader', 'bool')
431+
}
432+
temp = dt.preferences.read(mod, 'active_mode', 'integer')
433+
if not InRange(temp, 1, 3) then
434+
if dt.preferences.read(mod, 'active_batch', 'bool') then
435+
temp = 2
436+
else
437+
temp = 1
438+
end
439+
end
440+
GUI.HDR.opts = dt.new_widget('stack'){
441+
dt.new_widget('box'),
442+
GUI.HDR.gap,
443+
GUI.HDR.make_group_leader,
444+
active = temp
445+
}
446+
GUI.HDR.mode = dt.new_widget('combobox'){
447+
label = _('mode'),
448+
tooltip = _([[Operating mode:
449+
all: merge all images into a single image
450+
batch: group images into sets by comparing creation time. Images will NOT be auto-imported
451+
groups: merge images according to image grouping]]),
452+
value = temp,
453+
changed_callback = function(self)
454+
dt.preferences.write(mod, 'active_mode', 'integer', self.selected)
455+
GUI.HDR.opts.active = self.selected
456+
end,
457+
reset_callback = function(self) self.selected = 1 end,
458+
_('all'),
459+
_('batch'),
460+
_('groups')
461+
}
462+
463+
383464
local lbl_import = dt.new_widget('section_label'){
384465
label = _('import options')
385466
}
@@ -439,8 +520,8 @@ GUI.options = dt.new_widget('box'){
439520
lbl_hdr,
440521
GUI.HDR.bps,
441522
GUI.HDR.size,
442-
GUI.HDR.batch,
443-
GUI.HDR.gap,
523+
GUI.HDR.mode,
524+
GUI.HDR.opts,
444525
lbl_import,
445526
GUI.Target.style,
446527
GUI.Target.copy_tags,

0 commit comments

Comments
 (0)