Alexander Gromnitsky's Blog

Making high-resolution screenshots of Emacs frames

Latest update:

Emacs 27.1 can utilise the Cairo drawing backend to take screenshots of itself via x-export-frames function. Unfortunately, the bare bone function is all we have here--there's no UI to it. Moreover, it doesn't support bitmap fonts, which means if you still use, say, Terminus, you get garbage in the output.

I wanted to share a screenshot of a Emacs frame on twitter. Twitter doesn't accept SVGs, for net income of $1.47bn isn't enough to support such a complex thing. The best way to obtain an arbitrary high-resolution png is to get it from a vector image. I found that postscript->png gives the best results & requires only ghostscript installed.

(defun my--screenshot-png(out)
  "Save a screenshot of the current frame as a png file. Requires ghostscript."
  (let ((ps (concat out ".tmp")))
    (my--screenshot ps 'postscript)
    (call-process "gs" nil (get-buffer-create "*Shell Command Output*") nil
                  "-sDEVICE=png16m" "-dBATCH" "-dNOPAUSE"
                  "-r300" "-dTextAlphaBits=4" "-dGraphicsAlphaBits=4"
                  (concat "-sOutputFile=" out) ps)
    (delete-file ps)
    ))

We use 300 dpi here to render a png. my--screenshot function below temporally changes a frame font to Inconsolata:

(defun my--screenshot(out format)
  (let ((fontdef (face-attribute 'default :font)))
    (set-frame-font "Inconsolata 10")
    (unwind-protect
        (with-temp-file out
          (insert (x-export-frames nil format)))
      (set-frame-font fontdef))
    ))

The last bit left is to provide a prompt for a user where to save the screenshot:

(defun my-ss()
  "Save a screenshot of the current frame in a file"
  (interactive)
  (let* ((out (expand-file-name (read-file-name "Output file name: ")))
         (ext (file-name-extension out)))
    (cond
     ((equal "png" ext)
      (my--screenshot-png out))
     ((equal "ps" ext)
      (my--screenshot out 'postscript))
     (t
      (my--screenshot out (intern ext)))
     )))

E.g.:

M-x my-ss<RET>
Output file name: ~/Downloads/1.png<RET>
a screenshot of a Emacs frame

The physical image size here is 3133x3642.


Tags: ойті
Authors: ag