;;; org-attach-embedded-images.el --- Transmute images to attachments ;; ;; Copyright 2018-2021 Free Software Foundation, Inc. ;; ;; Author: Marco Wahl ;; Version: 0.1 ;; Keywords: org, media ;; ;; This file is not part of GNU Emacs. ;; ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 3, or (at your option) ;; any later version. ;; ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs. If not, see . ;;; Commentary: ;; ;; There are occasions when images are displayed in a subtree which ;; are not org attachments. For example if you copy and paste a part ;; of a web page (containing images) from eww to an org subtree. ;; This module provides command `org-attach-embedded-images-in-subtree' ;; to save such images as attachments and insert org links to them. ;; Install: ;; To use this module insert it to `org-modules'. The insert can be ;; performed via {M-x customize-variable RET org-modules RET} followed ;; by insertion of `org-attach-embedded-images' to the external ;; modules section. ;; Alternatively you can add the line ;; (require 'org-attach-embedded-images) ;; to your emacs configuration. ;; Use ;; M-x org-attach-embedded-images-in-subtree ;; in a subtree with embedded images. The images get attached and can ;; later be reviewed. ;; Note: Possibly ;; M-x org-toggle-inline-images ;; is needed to see the images in the Org mode window. ;; Code: (require 'org) (require 'org-attach) ;; Auxiliary functions (defun org-attach-embedded-images--next-property-display-data (position limit) "Return position of the next property-display location with image data. Return nil if there is no next display property. POSITION and LIMIT as in `next-single-property-change'." (let ((pos (next-single-property-change position 'display nil limit))) (while (and (< pos limit) (let ((display-prop (plist-get (text-properties-at pos) 'display))) (or (not display-prop) (not (plist-get (cdr display-prop) :data))))) (setq pos (next-single-property-change pos 'display nil limit))) pos)) (defun org-attach-embedded-images--attach-with-sha1-name (data) "Save the image given as DATA as org attachment with its sha1 as name. Return the filename." (let* ((extension (symbol-name (image-type-from-data data))) (basename (concat (sha1 data) "." extension)) (dir (org-attach-dir t)) (filename (concat dir "/" basename))) (unless (file-exists-p filename) (with-temp-file filename (setq buffer-file-coding-system 'binary) (set-buffer-multibyte nil) (insert data))) (org-attach-sync) basename)) ;; Command ;;;###autoload (defun org-attach-embedded-images-in-subtree () "Save the displayed images as attachments and insert links to them." (interactive) (when (org-before-first-heading-p) (user-error "Before first heading. Nothing has been attached.")) (save-excursion (org-attach-dir t) (let ((beg (progn (org-back-to-heading) (point))) (end (progn (org-end-of-subtree) (point))) names) ;; pass 1 (goto-char beg) (while (< (goto-char (org-attach-embedded-images--next-property-display-data (point) end)) end) (let ((data (plist-get (cdr (plist-get (text-properties-at (point)) 'display)) :data))) (assert data) (push (org-attach-embedded-images--attach-with-sha1-name data) names))) ;; pass 2 (setq names (nreverse names)) (goto-char beg) (while names (goto-char (org-attach-embedded-images--next-property-display-data (point) end)) (while (get-text-property (point) 'display) (goto-char (next-property-change (point) nil end))) (skip-chars-forward "]") (insert (concat "\n[[attachment:" (pop names) "]]")))))) (provide 'org-attach-embedded-images) ;;; org-attach-embedded-images.el ends here