iPadで作図しMacでいい感じにメモる

コード書いたり読んだりするのはMacでやったほうが楽だし、図を書いたりするのはiPadが楽。ということでこの間をいい感じに繋いだ話。

今までの連携方法

今までは以下の手順で連携していた。それなりに面倒なので、気軽に図を書いて差し込むという気になれなかった。

  1. iPadのPaperというアプリで図を書く
  2. ShareからAirDropを使ってファイルを転送
  3. (ほとんどの場合キャンバスサイズいっぱいに図を書かないので)Previewで画像の切り出し
  4. メモ先(Emacs)にドラッグ&ドロップ

Catalinaの機能を利用した連携

macOS CatalinaからMacとiPadを連携させるSidecarと共に、MacとiOS1を連携するいくつかの便利機能が入った。 いずれもMac側から実行するとiPadのアプリが自動で起動する。そしてiPad側で編集が完了すると、Mac側にその結果が反映されるという動き。

NotesへiPadから写真/ドキュメント/図/を挿入
公式メモアプリのNotes2で 右クリック > insert from iPhone or iPad > Take Photo/Scan Document/Add sketch
画像/PDFにiPadで書き込み
Finderから画像/PDFを 右クリック > Quick Action > Markup

Notes以外でも連携したい

Figure 1: Integration Flow

Figure 1: Integration Flow

公式の機能も便利なんだけど、Notesだけだとコードのシンタックスハイライトとか機能が無さすぎるので常用できない。(つまりEmacs org-mode3つかいたい) また、iPadでの作図もPaper4というアプリが使いやすいのでこれを使いたい。何か良い方法がないかと考えていると、Appleデバイス間のクリップボード同期機能 を思い出した。

クリップボードを利用すれば、アプリケーションに縛られることなくiPad<->Mac間で連携できる。非常に便利5

  1. iPadのPaperで図を書く
  2. ShareからCopyを選択
  3. MacのEmacsでペースト(ペースト時にhookして画像のみ書き込み部分をCrop)

実際の設定

Clipboardから画像を生成するところはpngpaste6、そして画像の余白自動切り抜きはImageMagicのmogrifyを利用している。 メイン処理自体はShellScriptなのでどのエディタからも同じように利用できるはずだ。

(defun org-insert-clipboard-image ()
       "Generate png file from a clipboard image and insert a link with caption and org-download tag to current buffer."
       (interactive)
       (let* ((filename
               (concat (file-name-nondirectory (buffer-file-name))
                       "_imgs/"
                       (format-time-string "%Y%m%d_%H%M%S")
                       ".png")))
         (unless (file-exists-p (file-name-directory filename))
           (make-directory (file-name-directory filename)))
         (let* ((output-buffer (generate-new-buffer "*Async Image Generator*"))
                (proc (progn
                        (async-shell-command (concat "pngpastet " filename) output-buffer)
                        (get-buffer-process output-buffer))))
           (if (process-live-p proc)
               (set-process-sentinel proc #'org-display-inline-images)))
         (insert (concat
             ;; DOWNLOADED tag allows you to delete an image by org-download-delete command.
             "#+DOWNLOADED: clipboard @ "
             (format-time-string "%Y-%m-%d %H:%M:%S\n#+CAPTION: \n")
             "[[file:" filename "]]"))))

;; Do not pop-up async-image-generator buffer because it's annoying.
(add-to-list 'display-buffer-alist '("^*Async Image Generator*" . (display-buffer-no-window)))

(define-key org-mode-map (kbd "C-M-y") 'org-insert-clipboard-image)
Code 1: org-download形式でclipboardの画像を非同期に挿入する
#!/bin/bash -eu

img=${1%.*}
ext=${1##*.}

function cleanup () {
    [ -f $img.tif ] && rm $img.tif
}
trap cleanup EXIT

pngpaste $img.tif && \
    convert $img.tif $img.$ext && \
    mogrify -fuzz 5% -trim +repage $img.$ext

echo "Success to generate $(basename $img.$ext)"
Code 2: clipboardからpng画像を生成して、余白をcropするコマンド

Paperからコピーした画像は、clipboardinfoを読んでも画像情報がのっていない。 そのせいか、pngpasteで直接pngを生成すると変色してしまう。よって、gifのように劣化せず、jpegのように透過無効化されないtifを経由するというworkaroundをとっている。 (tifそのままだと画像サイズがでかいのでNG)

既存の図にチョイ足しする

ドキュメントとかスライドを読んでいると、出てくる図に対して理解した内容を書き込みたいことがある。そんな場合は、標準のQuickAction > Markup を使って書き込んでいく。この時、画像のパスを手動で探してFinder開くのは面倒なのでこれも関数を定義しておく。

(defun org-image-open-in-finder()
  (interactive)
  (let* ((linkp (bounds-of-thing-at-point 'sentence))
         (link (buffer-substring-no-properties (car linkp) (cdr linkp)))
         (filename (replace-regexp-in-string "\\[\\[\\([^:]*:\\)?\\([^]]+\\)\\].*" "\\2" link)))
    (shell-command (concat "open " (file-name-directory filename)))))

(define-key org-mode-map (kbd "C-M-l") 'org-image-open-in-finder)
Code 3: カーソル上のイメージディレクトリをFinderで開く
直接QuickActionをEmacsから呼びたかったが、AutomaterあたりのLibraryにその手の関数がなかったので諦めた。なにか方法があれば教えてほしい。

  1. つまり、iPadだけではなくiPhoneでも使える ↩︎

  2. Keynoteでも同様の機能が右クリックで呼び出せた(おそらく他の公式アプリでも同様の機能が使える) ↩︎

  3. このブログもorg-modeで書かれている(HugoはOrg記法もサポート) ↩︎

  4. シンプルで手軽に使えて、直線/矢印/図形補正が掛かるので図もSketchも書きやすく、背景も透過できて、コピペなどのジェスチャーが賢いアプリ ↩︎

  5. 余白カットが特に… :thinking_face: ↩︎

  6. クリップボードの画像を出力するpngpasteコマンドとEmacsの連携 (macOS) - Qiita ↩︎

.