Screenshots into emacs org files in Windows

Related to my previous post, I needed to resolve the need to quickly take screenshots from Windows and put them in an org file in emacs. This proved a bit more difficult than I’d hoped; triggering a screenshot in Windows from emacs is non-obvious, and my attempts to use yank-media suggested that screenshots didn’t end up on the clipboard in a way emacs could see them. Other options I could find in melpa knew how to screenshot from XWindows, but not Windows.

It turns out when you just use PrintScr to snag a screenshot in Windows, the result ends up in the Pictures/Screenshots directory. So instead of solving the screenshotting problem, I just solved the problem of copying the most recent screenshot file into an images/ directory next to the org file, then inserting a reference to the file at point.

I set this up using org-babel’s literate emacs initialization feature, so rather than break this down in the blog post, I’ll let the config file itself do the talking. You can save this file to win-screenshots.org and then load it with (org-babel-load-file "win-screenshots.org").

To use the resulting tool:

  • configure win-screenshot-source-dir with the full path to your Pictures/Screenshots directory
  • take a screenshot
  • in your org file, M-x win-screenshot-here to grab the most recently-taken screenshot, put it in the images/ directory, and insert a link to it at the cursor.
* Variables
#+BEGIN_SRC emacs-lisp
(defvar win-screenshot-source-dir "C:/Users/mtomc/Pictures/Screenshots"
 "Directory screenshots live in.")
#+END_SRC

* Helpers
** Get screenshot file
#+BEGIN_SRC emacs-lisp
  (defun win-screenshot-most-recent-file ()
    "Get full path of most recent file in win-screenshot-source-dir"
    (caar (sort
  	(directory-files-and-attributes win-screenshot-source-dir t "\\(.*\\).png$" t)
  	:key #'file-attribute-modification-time
  	:lessp #'time-less-p
  	:reverse t)))
#+END_SRC

** Copy most recent screenshot file to CWD/images/<timestamp>.png and return relative path
#+BEGIN_SRC emacs-lisp
  (defun win-screenshot-capture-file-as-screenshot (screenshot-file)
    "Copy SCREENSHOT-FILE to <pwd>/images/<timestamp>.png and return relative path (images/<timestamp>.png)."
    (let*
        ((relative-path (concat "images/" (string-replace ":" "-" (format-time-string "%Y-%m-%dT%T" (current-time))) ".png"))
         (full-path (concat default-directory relative-path)))
      (copy-file screenshot-file full-path nil t t t)
      relative-path))
#+END_SRC

* Public interface
** Put screenshot in file at point
#+BEGIN_SRC emacs-lisp
  (defun win-screenshot-here ()
    "Copy most recent screenshot to images/ directory and insert org image embed at point."
    (interactive)
    (insert (concat
  	   "[[./"
  	   (win-screenshot-capture-file-as-screenshot (win-screenshot-most-recent-file))
  	   "]]\n"))
    ;; need to do this to force the newly-added image to show up.
    (org-redisplay-inline-images))
#+END_SRC

Comments