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>
The physical image size here is 3133x3642.
Tags: ойті
Authors: ag