Skip to content

Lighttable copy original file paths - #22862

Open
softwaregames1 wants to merge 2 commits into
darktable-org:masterfrom
softwaregames1:lighttable-copy-original-file-paths
Open

softwaregames1 wants to merge 2 commits into
darktable-org:masterfrom
softwaregames1:lighttable-copy-original-file-paths

Conversation

@softwaregames1

@softwaregames1 softwaregames1 commented Oct 30, 2026 •

Copy link
Copy Markdown

Summary

Add "copy original file paths" under actions on selection → images.

The action copies unique original-file locations in selection order, one per line, using the GTK clipboard. It leaves the clipboard unchanged when no paths are available.

It does not export images, launch external software, or modify originals. Intended uses include file manifests, locating files across folders, and reporting exact files. Paths are plain text; consumers must parse or quote them appropriately.

Lua already supports file lists and external-tool workflows, including stacking and panorama scripts. This proposes a built-in clipboard convenience without script setup. Whether that convenience warrants inclusion in core remains open for review.

This PR contains only the copy-paths action, its regression tests, and its release note. Collection navigation has been moved to a separate branch.

Validation

  • Linux build passed after separating the branches.
  • All six tests passed with a real GTK clipboard, covering selection order, deduplication, spaces, Unicode, and clipboard preservation.
  • CTest passed; its default invocation skips the clipboard case, which was run separately.
  • Windows and macOS GUI behavior was not tested locally.

Test instructions

Select images, use "copy original file paths," and paste into a text editor. Each original should appear once in selection order.

With no selection, the button should be disabled. A shortcut can be configured; no default shortcut is assigned.

Add an action that copies distinct original paths in selection order. Preserve the clipboard when no paths are available and cover path handling and GTK clipboard behavior with tests.
@wpferguson

Copy link
Copy Markdown
Member

What problem does this solve? How/why would anyone use this?

@softwaregames1

Copy link
Copy Markdown
Author

It gets the file paths of a whole selection out of darktable in one step. Today you can only copy one path at a time from the image information panel.

The main use is handing culled or tagged images to tools darktable doesn't cover: focus stacking or panorama software, exiftool, backup/rsync or upload scripts. You select the images, copy, and paste the list into a terminal or file list. It's also handy for locating originals spread across several folders, or for listing exact files in a bug report.

Paths are one per line so shells and tools can take them directly. Duplicates collapse to one entry because they're the same file on disk.

@wpferguson

wpferguson commented Oct 30, 2026 •

Copy link
Copy Markdown
Member

The main use is handing culled or tagged images to tools darktable doesn't cover: focus stacking or panorama software

That's what the Lua scripts do. In fact, you could create your list with a Lua script and format it however you want, then pass it to whatever you want and optionally return the results, all from within darktable.

EDIT:

The Lua scripts distributed with darktable already have focus stacking (enfuseAdvanced) and panorama stitching (hugin), along with many other interfaces to external software.

EDIT 2:

Reading this again I noticed that your use case would be sending RAW images to software that doesn't necessarily handle RAWs. If those external programs modify the RAWs then that would go against darktable's rule of never modifying RAW files.

The Lua scripts pointed out above export the RAW files into an image format the external applications can handle (usually TIFF, sometimes JPG).

Here's a Lua script that copies the list to the clipboard or writes it to a file in the temp directory.

local dt = require "darktable"

local MODULE <const> = "copy_file_list"

local PS <const> = dt.configuration.running_os == "windows" and "\\" or "/"
local LS <const> = dt.configuration.running_os == "windows" and "\r\n" or "\n"

local gettext = dt.gettext.gettext

local function _(msgid)
    return gettext(msgid)
end

dt.preferences.register(MODULE, "file_list_output", "enum", _("file list destination"), _("where to put the list of files"),
  _("clipboard"), _("clipboard"), _("file"))

local function write_to_clipboard(text)
    
  if dt.configuration.running_os == "windows" then
    -- Windows: Pipe to clip.exe
    local pipe = io.popen("clip", "w")
    if pipe then
      pipe:write(text)
      pipe:close()
    end
  else
    -- Mac/Linux: Check the uname to differentiate
    if dt.configuration.running_os == "macos" then
      -- macOS: Pipe to pbcopy
      local pipe = io.popen("pbcopy", "w")
      if pipe then
        pipe:write(text)
        pipe:close()
      end
    else
      -- Linux: Try xclip (most common) or xsel
    local pipe = io.popen("xclip -selection clipboard", "w")
      if pipe then
        pipe:write(text)
        pipe:close()
      else
        -- Fallback to xsel if xclip isn't installed
        pipe = io.popen("xsel --clipboard --input", "w")
        if pipe then
          pipe:write(text)
          pipe:close()
        end
      end
    end
  end
end

local function create_file_list(images)

  if #images < 1 then
    dt.print("No images selected")
    return
  end

  local dest_file = dt.preferences.read(MODULE, "file_list_output", "enum") == _("file") and true or false

  local file_list = {}

  for _, img in ipairs(images) do
    table.insert(file_list, img.path .. PS .. img.filename)
  end

  if dest_file then
    local f = io.open(dt.configuration.tmp_dir .. PS .. "file_list.txt", "w")
    if f then
      f:write(table.concat(file_list, LS))
      f:close()
    else
      dt.print_error("ERROR: could not create file\n")
    end
  else
    write_to_clipboard(table.concat(file_list, LS))
  end
end

dt.gui.libs.image.register_action(
  MODULE, 
  _("copy file list"),
  function(event, images)
    create_file_list(images)
  end,
  _("copy list of file names and paths to " .. dt.configuration.tmp_dir .. PS .. "file_list.txt for clipboard")
)

if not dt.query_event(MODULE, "shortcut") then  -- skip if shortcut already registered
  dt.register_event(MODULE, "shortcut",
    function(event, shortcut)
      create_file_list(dt.gui.action_images)
    end, _("copy list of file names and paths to " .. dt.configuration.tmp_dir .. PS .. "file_list.txt or clipboard")
  )
end

@wpferguson

Copy link
Copy Markdown
Member

This PR, for me, is not needed because:

  • It's purpose is to interface to external software, which is why we have Lua
  • It can be solved with a Lua script that uses less code than the solution
  • This PR would add to the software maintenance burden
  • I'm not sure this PR solves a problem, or solves it correctly. Some of the use cases stated above are already covered by existing Lua scripts
  • The Lua solution is probably better since it could be extended to launch whatever software the list is for, providing an end to end solution. Actually using Lua let's you pass the information directly to the receiving software, so the clipboard is not needed at all.

@softwaregames1
softwaregames1 force-pushed the lighttable-copy-original-file-paths branch from 643490b to 6e683bc Compare October 31, 2026 18:23
@softwaregames1

Copy link
Copy Markdown
Author

Thanks for the explanation and example script. You're right that stacking and panorama workflows are already covered by Lua; those were poor examples for this proposal.

The narrower use case is copying selected originals' locations for file manifests, locating files across folders, or reporting exact files. The action only reads paths and writes text to the GTK clipboard. It does not export images, launch external software, or modify originals.

Lua can provide this functionality too. The proposed benefit is having a built-in clipboard action without script setup.

I've also removed collection navigation from this PR and preserved it on a separate branch, so this PR now covers only copying original file paths.

@wpferguson

Copy link
Copy Markdown
Member

If the script is added to the repository, then it's included with the darktable release and only needs to be turned on for those who want it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants