I recently developed the following workflow to attach images from my phone in emacs org mode.
First, I created the folder NEXTCLOUD_FOLDER on my nextcloud instance and used the nextcloud app on my phone to create photos in that folder.
Then I execute iko/org-attach-image-from-phone in an org mode document where I want the image to be attached using org-attach/org-download.
Emacs then first syncs NEXTCLOUD_FOLDER with ATTACHMENTS_CACHE_DIR. On success I am prompted with yad to choose the attachment among the files in ATTACHMENTS_CACHE_DIR. It is then sized down to 720p with imagemagick; otherwise the preview in emacs is too slow. Finally, the image is attached to the current node and a link to it is written into the file at point.
To use it, you need to install yad, nextcloudcmd and imagemagick on your machine, as well as org-download, s.el and f.el in your emacs. Finally, you need to configure ATTACHMENTS_CACHE_DIR, YOUR_USERNAME, YOUR_PASSWORD, YOUR_SERVER and NEXTCLOUD_FOLDER.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
| (cl-defun iko/run-process-async (name program &key stdin args on-exit)
"Run PROGRAM asynchronously with ARGS, outputting to BUFFER-NAME."
(with-current-buffer (get-buffer-create (concat "*" name "*"))
(let ((b (current-buffer))
(p (apply #'start-process name (current-buffer) program args)))
(set-process-sentinel
p
(lambda (proc event)
(when (eq (process-status proc) 'exit)
(when on-exit
(funcall on-exit
(process-exit-status proc)
(with-current-buffer b (buffer-string))
proc
event))
(kill-buffer b))))
(when stdin
(process-send-string p (if (string-suffix-p "\n" stdin)
stdin
(concat stdin "\n")))
(process-send-eof p))
p)))
(defun iko/scale-image-to-max-size (input-file output-file &optional max-width max-height)
"Downscale INPUT-FILE to fit within MAX-WIDTH x MAX-HEIGHT (default 1280x720) and save as OUTPUT-FILE."
(let ((max-width (or max-width 1280))
(max-height (or max-height 720)))
;; Call ImageMagick 'convert' to resize while keeping aspect ratio
(call-process
"convert" nil nil nil
input-file
"-resize" (format "%dx%d>" max-width max-height)
output-file)
(message "Saved scaled image to %s" output-file)))
(defun iko/yad-select-img-from-dir (dir)
"Use yad to select a file from DIR. Returns the selected file path."
(let* ((command (s-join " "
`("yad"
"--file"
"--filter=\"Images | *.png *.jpg *.jpeg *.gif *.webp *.bmp\""
"--title=\"Select Image\""
"--add-preview"
"--large-preview"
,(format "--workdir=%s" dir))))
(output (string-trim (shell-command-to-string command))))
(if (and (not (string-empty-p output))
(file-exists-p output))
output
(user-error "No file selected or yad failed"))))
(defun iko/org-attach-image-from-phone ()
(interactive)
(let* ((attachDir ATTACHMENTS_CACHE_DIR)
(user YOUR_USERNAME)
(password YOUR_PASSWORD)
(server YOUR_SERVER)
(args
`("-u" ,user
"--path" ,NEXTCLOUD_FOLDER
,attachDir
,server)))
(f-mkdir-full-path attachDir)
(iko/run-process-async
"nextcloudcmd-download"
"nextcloudcmd"
:args args
:stdin password
:on-exit
(lambda (status-code _output _proc _event)
(when (/= status-code 0)
(user-error "nextcloudcmd failed with code %s" status-code))
(let ((img-file (iko/yad-select-img-from-dir attachDir)))
(message "selected %s" img-file)
(when img-file
(let ((tmpfile (make-temp-file "scaled-img-" nil ".png")))
(message "buffer file: %s" tmpfile)
(iko/scale-image-to-max-size img-file tmpfile)
(org-download-image (concat "file://" tmpfile))
(message "attached %s" img-file))))))))
|