I was reading a book this week and I wanted to use one of the images in a presentation.

I’m, unsurprisingly, using Emacs to read the book. So I hit ? to see what options I had - but there was not one for saving images.

I used my DDG-foo1 to search for “emacs nov.el extract images from epub” and found a reddit link suggesting raising an issue. The current repo for nov.el doesn’t have a way to raise issues, so I went to the archived GitHub repo. Issue 20 addressed my question - and it included code!

So, I’ve added the following function (from that GitHub issue) to my Emacs configuration:

(defun other/extract-image-at-point ()
  (interactive)
  (let ((image-spec (plist-get (text-properties-at (point)) 'display)))
    (when (or (not image-spec) (not (eq (car-safe image-spec) 'image)))
      (user-error "No image at point"))
    (cond
     ((memq :file image-spec)
      (let* ((source (plist-get (cdr image-spec) :file))
             (default-file (file-name-nondirectory source))
             (prompt (format "Save %s at " default-file))
             (dest (expand-file-name (read-file-name prompt))))
        (when (file-directory-p dest)
          (setq dest (expand-file-name default-file dest)))
        (copy-file source dest t)
        (message "File saved at %s" dest)))
     ((memq :data image-spec)
      (let* ((data (plist-get (cdr image-spec) :data))
             (dest (expand-file-name (read-file-name "Save at "))))
        (with-temp-file dest
          (insert data))
        (message "File saved at %s" dest)))
     (t (error "Invalid image descriptor")))))

and then extended the configuration for nov.el mode that I first discussed in my post Reading books in Emacs like so:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
(use-package nov
  :init (defun my-nov-font-setup ()
          (face-remap-add-relative 'variable-pitch :family "Liberation Serif"
                                   :height 1.3)
          (setq fill-column (my-centre-width)
                nov-text-width (- fill-column 2)
                visual-fill-column-center-text t))
  :bind (:map nov-mode-map
              ("s" . other/extract-image-at-point))
  :hook ((nov-mode . my-nov-font-setup)
         (nov-mode . visual-line-mode)
         (nov-mode . visual-fill-column-mode)))

(add-to-list 'auto-mode-alist '("\\.epub\\'" . nov-mode))

The only difference is lines 8 and 9 where I bind (i.e. set) the key s to be the function defined above to extract and save the image.

Now when I hit ? I see that s is defined to save the image, as show in the following:

Screenshot: nov.el Help

Yet another example of the power that you get when using Emacs. Try configuring any of your other daily tools that easily.


  1. DuckDuckGo-fu (AKA DDG-fu) is like google-fu, but for DuckDuckGo obviously. I couldn’t find any links to DDG-fu when I searched, so either my fu isn’t so good, or this might be the first page to use that term. I am hopeful, so feel free to link to this note as your reference! ↩︎