org-mode 导出html到指定文件夹 方案分享

我们编写的 org 文件有时候并不是在一个特定的项目中的,org-publish 系列的函数常常不满足需求。

因此我在 org-dispatch 的基础上,以一种相对简单清晰的方式,编写了一个能指定特定导出目录的 memacs/org-dispatch

(defvar memacs--org-export-directory (expand-file-name "~/Desktop"))
(defun memacs/org-export-dispatch (&optional arg)
  "Change exported destination to the special path."
  (interactive "P")
  ;; 选择导出文件夹目录
  (let ((dest (read-directory-name "Export to Directory: "
                                   nil default-directory nil)))
    (setq memacs--org-export-directory dest)
    (org-export-dispatch))
  )

;; 一个在 org-add-export-dir 执行前的切面
(defadvice org-export-output-file-name (before org-add-export-dir activate)
  "Modifies org-export to place exported files in a different directory"
  (when (not pub-dir)
    (setq pub-dir memacs--org-export-directory)
    (when (not (file-directory-p pub-dir))
      (make-directory pub-dir))))

虽然以上代码能将 html 导出到指定目录,但是 org 文件中的图片链接不会被修改,因此导出的 html 文件都无法正确显示图片。

我的解决方式是:创建一个自己的 link type ,自定义它的导出函数。 以下是代码:

;; 链接点击事件
(defun memacs-img--custom-link-img-follow (path)
  "Click event of custom link img."
  (org-open-file-with-emacs path))

;; 根据链接里的路径求算出绝对路径,并将图片文件拷贝到导出目录的 statics 文件夹下面
;; 返回新的相对地址
(defun memacs-img//copy-to-destination-statics-dir (path desc format)
  "A aspect for copy src file to statics dir in destination."
  (let ((uri-slices (split-string path "/"))
        (abs-path (expand-file-name path))
        (statics-dir (concat memacs--org-export-directory "statics/")))
    (if (not (file-exists-p abs-path))
        ;; return nil if image does not exist
        nil
      ;; modify url and copy image file if image exists
      (unless (file-exists-p statics-dir)
        (make-directory statics-dir))
      (let ((dest (concat statics-dir (nth (- (length uri-slices) 1) uri-slices)))
            (relative-path (concat "./statics/" (nth (- (length uri-slices) 1) uri-slices))))
        (unless (file-exists-p dest)
          (copy-file abs-path dest))
        relative-path)))
  )

;; 修改链接为网络资源地址,该导出函数用于我的blog发布
(defun memacs-img//export-to-Internet (path desc format)
  "A aspect for change path to url in the internet."
  (let ((index (string-match "statics/" path)))
    (if (not index)
        ;; index is nil
        (concat custom-link-img-export-host "/statics/not_found.png")
      ;; index is the offset of "statics/"
      (concat custom-link-img-export-host "/" (substring path index))
      )
    )
  )

;; 设置默认导出函数
(setq memacs-img/before-export-aspect #'memacs-img//copy-to-destination-statics-dir)

(defun memacs-img--custom-link-img-export (path desc format)
  "export event of custom link img."
  ;; concat custom img host and final two section of the path
  (let ((url (funcall memacs-img/before-export-aspect path desc format)))
     (cond
      ((eq format 'html)
       (format "<img src=\"%s\" alt=\"%s\"/>" (url-encode-url url) desc))
      ((eq format 'md)
       (format "![%s](%s)" desc (url-encode-url url)))
      )
     )
  )

;;;; Init

;; 自定义link类型
(defun memacs-img--link-init ()
  "Add link type 'img'."
  (org-add-link-type "img" 'memacs-img--custom-link-img-follow 'memacs-img--custom-link-img-export)
  (message "Add Custom Link 'img'.")
  )

(memacs-img--link-init)

当然,这个方案兼容性不好,本身指定义 link 类型就与其他人的 org-mode 不兼容了,buffer中显示图片、 org-download 配置 都需要一定修改。后者比较简单,前者有点糟糕:

我的思路是在仿照 org-toggle-inline-images 提供一套自定义的 , 不是很优雅,不再赘述,有兴趣的可以看源码 memacs-org-ext

欢迎各位探讨学习。

1 个赞

我觉得用软链接挺好

如果导出内容需要分享给他人或部署到远程服务器上,软连接就不适合了

hardlink?

1 个赞

可以的,好想法