5

I want to copy images from Emacs to macOS clipboard. I have tried selecting them and yanking, which hasn't worked. Google also didn't have a solution.

2

2 Answers 2

4

A very rudimentary function that will yank the displayed image at point to the X11 clipboard:

(defun x11-yank-image-at-point-as-image ()
  "Yank the image at point to the X11 clipboard as image/png."
  (interactive)
  (let ((image (get-text-property (point) 'display)))
    (if (eq (car image) 'image)
        (let ((data (plist-get (cdr image) ':data))
              (file (plist-get (cdr image) ':file)))
          (cond (data
                 (with-temp-buffer
                   (insert data)
                   (call-shell-region
                    (point-min) (point-max)
                    "xclip -i -selection clipboard -t image/png")))
                (file
                 (if (file-exists-p file)
                     (start-process
                      "xclip-proc" nil "xclip"
                      "-i" "-selection" "clipboard" "-t" "image/png"
                      "-quiet" (file-truename file))))
                (t
                 (message "The image seems to be malformed."))))
      (message "Point is not at an image."))))

Requirements

You need to have xclip installed.

Limitations

  1. Only works on a system with X11 (i.e. won't easily work on MacOS, Windows etc.). Unfortunately, it seems that pbpaste, which is usually a drop-in replacement for xclip cannot copy an image to the clipboard. For possible workarounds, see here. I don't have access to a MacOS system, so I can't apply these myself.

  2. xclip cannot currently copy to multiple targets/atoms (github issue), so programs that can't deal with the image/png target atom, will either ignore the paste from the clipboard or insert the image as binary "text".

  3. (Relatively easily circumventable.) Currently, the atom used is image/png irrespective of whether the image is actually a png or not. However, it seems that the programs that can deal with an "image" target atom (such as gimp or inkscape) seem to (somehow) correctly deal with the paste, even if the image was not a png. If needed, this could be circumvented by first inspecting the image type and selecting the target atom based on that.

Miscellaneous

Region

For a region, (get-text-property (text-property-not-all (point-min) (point-max) 'display nil) 'display) would get you the first image (or other "special" display property) in the region. The other property search functions might also be helpful.

Debugging :data

Try:

(let ((data (plist-get
             (cdr (get-text-property (point) 'display))
             ':data))
      (coding-system-for-write 'no-conversion))
  (with-temp-buffer
    (insert data)
    (save-buffer)))

(you will be prompted about the location where to save).

5
  • 1
    Thanks! I made it work in macOS. I will post it as another answer.
    – HappyFace
    Commented Apr 15, 2018 at 16:02
  • This only works when the point is exactly before the image. How can I make it work for regions? Or when the point is after the image?
    – HappyFace
    Commented Apr 15, 2018 at 16:06
  • When data is not nil, this doesn't work in macOS.
    – HappyFace
    Commented Apr 15, 2018 at 16:33
  • I have done some testing for the data case, using pbcopy instead of impbcopy. Running 'pbpaste > t.jpg' results in a corrupt file. Here is the data variable: gist.github.com/NightMachinary/2c67957b1aa8261679d9d973a5f6366a
    – HappyFace
    Commented Apr 15, 2018 at 16:48
  • I've edited the answer with some suggestions. I've also made it into a "community wiki" so you can change it, if you want. Looking at the data in the gist, it does indeed seem to be corrupt, but I'm not sure why.
    – aplaice
    Commented Apr 15, 2018 at 18:28
2

From @aplaice's answer, adapted to macOS:

(defun ns-yank-image-at-point-as-image ()
    "Yank the image at point to the X11 clipboard as image/png."
    (interactive)
    (let ((image (get-text-property (point) 'display)))
      (if (eq (car image) 'image)
          (let ((data (plist-get (cdr image) ':data))
                (file (plist-get (cdr image) ':file)))
            (cond (data
                   (with-temp-buffer
                     (insert data)
                     (call-shell-region
                      (point-min) (point-max)
                      "impbcopy")))     ;; http://www.alecjacobson.com/weblog/?p=3816 Linux x11: https://emacs.stackexchange.com/questions/41016/how-can-i-yank-images-from-emacs?noredirect=1#comment64407_41016
                  (file
                   (if (file-exists-p file)
                       (start-process
                        "_" nil "impbcopy"  (file-truename file))))
                  (t
                   (message "The image seems to be malformed."))))
        (message "Point is not at an image."))))

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.