您当前的位置:首页 > 计算机 > 编程开发 > Other

org-mode 屏幕截图

时间:12-14来源:作者:点击数:

平时使用 org-mode 的时候有截图需求,之前在网上 copy 了一个函数。

#+BEGIN_SRC elisp  ;; 在org-mode中方便地截图并显示  (defun peng-org-screenshot ()    "Take a screenshot into a unique-named file in the current buffer file      directory and insert a link to this file."    (interactive)    (setq filename          (concat (make-temp-name "./") ".png"))    (setq fullfilename          (concat (file-name-directory (buffer-file-name)) "img/" filename))    (if (file-accessible-directory-p (concat (file-name-directory                                              (buffer-file-name)) "img/"))        nil      (make-directory "img/" t))    (call-process-shell-command "screencapture" nil nil nil nil "-i" (concat                                                                      "/"" fullfilename "/"" ))    (insert (concat "[[./img/" filename "]]"))    (org-display-inline-images)    )#+END_SRC

它可以实现 使用 screencapture 来抓图,以一个临时生成的名字来做为抓取图片的文件 名,最后把图片文件存到当前目录中的 img 目录中。然后通过 insert 函 数把链接插入到org文件中。但是这个函数有几个方面还达不到我的要求:

  1. 删除麻烦。每次想删先得手动到 img 目录中把对应文件删除,然后再到 org 中删链接。
  2. 如果一次抓图失误,重新抓图又要重新生成一个新的文件,之前的文件就成了垃圾放到了 img 目录中。删除又得重复一次1的动作。
  3. 图片名字全是临时文件的名字,完全没有自解释性。

为了解决上述几个问题,自己动手搞了一下。首先图片名字不能再上临时的了,每次抓图时需要手动输入。我结合ivy-read,把当前目录中的 img 目录中的图片做为候选,这样可以方便地更新某次错误抓图,而且新建图片也很方便。

于是把函数改成这样:

#+BEGIN_SRC elisp  (defcustom peng-org-screenshot-dir-name  "img"    "default image directory name for org screenshot"    :type 'string    )  (defun peng-org-screenshot ()    (interactive)    "Take a screenshot into a user specified file in the current       buffer file directory and insert a link to this file."    (let* ((img-dir peng-org-screenshot-dir-name))      (progn        (if (file-exists-p img-dir)            (print "yes")          (mkdir img-dir))        (let ((temp-name (ivy-read "please selete a image name"                                   (delete ".." (delete "." (directory-files img-dir))))))          (setq filename (concat img-dir "/" (file-name-base temp-name) ".png"))          (call-process-shell-command "screencapture" nil nil nil nil "-i" (concat                                                                            "/"" filename "/"" ))          (insert (concat "[[./" filename "]]"))))))#+END_SRC

这样搞定了创造截图。重点是删除了。删除需要考虑两方面,一个是删除存在于img 目录的图片文件,一个是存在于 org 文件中的图片链接。删除文件其实很简单。直接使用 ivy-read 读出 img 目录中的所有图片文件,然后调用delete-file 函数删除就好了。

删除 org 文件中的图片链接就有点麻烦了。我是这样想的:

  1. 首先我需要先找到 org 文件中的所有 link
  2. 过滤出我想删除的图片的链接。
  3. 干掉它。

关于第一点我找到这样一段 elisp 代码:

#+BEGIN_SRC elisp  (org-element-map (org-element-parse-buffer) 'link                     (lambda (link)                       (when (string= (org-element-property :type link) "file")                         (list (org-element-property :path link)                               (org-element-property :begin link)                               (org-element-property :end link)))))#+END_SRC

这段代码可以找到本文件按照刚才的方式插入的图片链接。返回的一个类似于这样的列表:

#+BEGIN_EXAMPLE  (("./img/test.png" 363 373))#+END_EXAMPLE

可以看到,这是一个大列表A,大列表中的每个元素B由三个元素组成,它们分别的含义是:图片文件的地址、链接在文件中的的起始位置、结束位置。有了这些数据,就可以直接通过 goto-char 到链接开始,然后使用 delete-char 把链接干掉。

全部的代码如下:

#+BEGIN_SRC elisp  (defcustom peng-org-screenshot-dir-name  "img"    "default image directory name for org screenshot"    :type 'string    )  (defun peng-org-screenshot ()    (interactive)    "Take a screenshot into a user specified file in the current       buffer file directory and insert a link to this file."    (let* ((img-dir peng-org-screenshot-dir-name))      (progn        (if (file-exists-p img-dir)            (print "yes")          (mkdir img-dir))        (let ((temp-name (ivy-read "please selete a image name"                                   (delete ".." (delete "." (directory-files img-dir))))))          (setq filename (concat img-dir "/" (file-name-base temp-name) ".png"))          (call-process-shell-command "screencapture" nil nil nil nil "-i" (concat                                                                            "/"" filename "/"" ))          (insert (concat "[[./" filename "]]"))))))  (defun peng-find-org-link-begin-and-end (plist string)    "find link from plist whose link is equal to string, return a  list just like `((name begin-position end-position))'"    (let ((return-list '()))      (progn        (while plist          (progn            (if (string-equal (car (car plist))                              string)                (add-to-list 'return-list (cdr (car plist))))            (setq plist (cdr plist))))        return-list)))  (defun peng-do-delete-link-function (be-list)    "goto the begining of link and delete it, be-list is a list  just like `((name begin-position end-position))'"    (while be-list      (progn        (goto-char (car (car be-list)))        (delete-char (- (car (cdr (car be-list)))                        (car (car be-list))))        (setq be-list (cdr be-list)))))  (defun peng-delete-org-screenshot-image-file-and-link ()    (interactive)    (let* ((link-list (org-element-map (org-element-parse-buffer) 'link                        (lambda (link)                          (when (string= (org-element-property :type link) "file")                            (list (org-element-property :path link)                                  (org-element-property :begin link)                                  (org-element-property :end link))))))           (img-dir peng-org-screenshot-dir-name)           (temp-name (concat "./" img-dir "/"                                   (ivy-read "please selete a image name you want to delete"                                             (delete ".." (delete "." (directory-files img-dir))))))           (begin-end-list (peng-find-org-link-begin-and-end link-list temp-name)))      (progn        (if (yes-or-no-p "Do you really want to delete the image file? This can't be revert!!")            (delete-file temp-name))        (if (yes-or-no-p "Do you also want to delete the image links?")            (peng-do-delete-link-function begin-end-list)))))#+END_SRC

使用 peng-org-screenshot 函数来截图,需要输入截图名字,如果需要更新原有图片,直接在 ivy-read 中过滤出原来的文件,选中即可。如果需要新建,输入其名字就是啦。

使用 peng-delete-org-screenshot-image-file-and-link 函数来删除文件或 link。选中想删除的文件,然后回答 yes 或者 no 就是了。

函数写得很 dirty,但是至少现在它是可以工作了。

方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
    无相关信息
栏目更新
栏目热门
本栏推荐