Using image-dired to browse the latest screenshots from multiple directories

| emacs, image, org, link

Since A+ and I play lots of Minecraft together, I figured it's a good opportunity to slowly get her into the idea of documenting learning. Besides, I can always practise it myself. Screenshots are handy for that. In Minecraft Java, F1 hides the usual heads-up display, and F2 takes the screenshot. Usually, when I start taking screenshots. A+ starts taking screenshots too. I want to build on her enthusiasm by including her screenshots in notes. To make it easy to incorporate her pictures into our notes, I've shared her GDLauncher folder and her Videos folder with my computer using Syncthing so that I can grab any screenshots or videos that she's taken.

In Emacs, image-dired makes it easy to see thumbnails. The neat thing is that it doesn't just work with a single directory. Just like Dired, you can give it a cons cell with a directory in the first part and a list of files in the second part as the first argument to the function, and it will display those files. This means I can use directory-files-recursively to make a list of files, sort it to show most recent screenshots first, limit it to the most recent items, and then display a buffer with thumbnails. image-dired-show-all-from-dir reports a small error when you do this (I need to send a patch upstream), so we hush it with condition-case in my-show-combined-screenshots.

(defvar my-screenshot-dirs
  '("~/recordings"
    "~/.var/app/org.prismlauncher.PrismLauncher/data/PrismLauncher/instances/"
    "~/sync/gdlauncher-instances/"))
(defvar my-recent-screenshot-limit 50)

(defun my-combined-screenshots (&optional limit)
  (seq-take
   (sort
    (seq-mapcat (lambda (dir)
                  (directory-files-recursively dir "^[0-9][0-9][0-9][0-9]-.*\\.\\(png\\|webm\\)"))
                my-screenshot-dirs)
    :key #'file-name-base
    :lessp #'string<
    :reverse t)
   (or limit my-recent-screenshot-limit)))

(defun my-latest-screenshot ()
  (car (my-combined-screenshots)))

(defun my-show-combined-screenshots (&optional limit)
  "Show thumbnails for combined screenshots."
  (interactive (list (when current-prefix-arg (read-number "Limit: "))))
  (condition-case nil
      ;; ignore errors from image-dired trying to set default-directory
      (image-dired-show-all-from-dir
       (cons (car my-screenshot-dirs) (my-combined-screenshots limit)))
    (error nil)))
2025-01-02_08-19-32.png
Figure 1: The result of my-show-combined-screenshots

In the *image-dired* buffer created by my-show-combined-screenshots, I can use m (image-dired-mark-thumb-original-file) to mark images and C-u w (image-dired-copy-filename-as-kill) to copy their absolute paths.

To make it easier to create links to a file by using org-store-link (which I've bound to C-c l) and org-insert-link (C-c C-l in an Org buffer), I can define a link-storing function that takes the original filename:

(defun my-org-image-dired-store-link ()
  (when (and (derived-mode-p 'image-dired-thumbnail-mode)
             (get-text-property (point) 'original-file-name))
    (org-link-store-props
     :link (concat "file:" (get-text-property (point) 'original-file-name)))))

(with-eval-after-load 'org
  (org-link-set-parameters
   "image-dired"
   :store #'my-org-image-dired-store-link))

To make it easier to insert the marked links that have been copied as absolute paths:

(defun my-org-yank-file-links-from-kill-ring ()
  (interactive)
  (dolist (file (read (concat "(" (current-kill 0) ")")))
      (insert (org-link-make-string (concat "file:" file)) "\n")))

I usually want to copy those files to another directory anyway. I have a my-org-copy-linked-files function in Copy linked file and change link that copies the files and rewrites the Org links. This means that I can copy my notes to an index.org in a directory I share with A+, save the images to an images subdirectory, and export the index.html so that she can read the notes any time she likes.

This is part of my Emacs configuration.
View org source for this post
You can comment with Disqus or you can e-mail me at sacha@sachachua.com.