emacs 可以在 org-mode 中显示 zip 存档文件中的图像吗
Can emacs show an image in a zip archieve file in org-mode
在启用了 iimage-mode 的 emacs org-mode 中,它可以显示来自相对文件路径的内联图像,例如:
[[文件:images/foo.jpg]]
我想要的是:它如何显示位于 zip 存档中的图像,如下所示:
[[file:images.zip/foo.jpg]]
有办法吗?
感谢kaushalmodi,
下面是我按照这个问题 how to display pdf images in org mode 中的答案所做的。由于是第一次做lisp编程,代码可能设计的不太好
(add-hook 'org-mode-hook #'modi/org-include-img-from-zip)
(defun modi/org-include-img-from-zip (&rest ignore)
"extract images from zip an archive.
This function does nothing if not in org-mode."
(interactive)
(when (derived-mode-p 'org-mode)
(save-excursion
(goto-char (point-min))
(while (search-forward-regexp
"^\s-*#\+STARTUP:.*\s-convertfromzip"
nil 'noerror)
(let* (filenoext imgext imgfile imgfilename zipfile imgpath cmd)
(setq zipfile "arc.zip")
;; Keep on going on to the next line till it finds a line with
;; `[[FILE]]'
(while (progn
(forward-line 1)
(not (looking-at "\[\[\(.*\)\.\(.*\)\]\]"))))
(when (looking-at "\[\[file:\(.*\)\.\(.*\)\]\]")
(setq filenoext (match-string-no-properties 1))
(setq imgext (match-string-no-properties 2))
(setq imgpath (concat filenoext "." imgext))
(setq imgfile (expand-file-name (concat filenoext "." imgext)))
(setq imgfilename (file-name-nondirectory imgfile))
(when (string= (substring imgpath 0 1) "~")
(setq imgpath (concat "%HOME%" (substring imgpath 1 nil)))
(setq imgpath (file-name-directory imgpath))
(setq cmd (concat "7z e " zipfile " -y -o"imgpath " " imgfilename " " imgfilename ))
(with-temp-buffer (shell-command cmd t))
)
))))))
工作规则:
- 如果您有包含图像
myimage.png
的 zip 文件 zippedimg.zip
,您应该在组织模式文件中将其引用为 [[./zippedimg_zip/myimage.png]]
。请注意,我已将 zippedimg.zip
中的 .
替换为 _
。
- 这样做的原因是我正在创建与
[[
和 ]]
中提到的目录相同的目录。但是由于 zippedimg.zip
文件存在,emacs 不允许创建同名目录。因此,对于 zippedimg.zip
文件,我只提取其中的图像 ,同时将 zip 中的路径保留到 zippedimg_zip
目录中。
这是一个用于测试的最小工作组织文件:
#+TITLE: Image from archive
#+STARTUP: inlineimages
#+NAME: fig:myimage
#+HEADER: :extractfromarchive t
# The below caption line is optional
#+CAPTION: My image myimage.png inside ./zippedimg.zip
[[./zippedimg_zip/myimage.png]]
这是您需要放在 emacs init 某处的代码:
;; Execute the `modi/org-include-img-from-archive' function just before saving the file
(add-hook 'before-save-hook #'modi/org-include-img-from-archive)
;; Execute the `modi/org-include-img-from-archive' function before processing the
;; file for export
(add-hook 'org-export-before-processing-hook #'modi/org-include-img-from-archive)
(defun modi/org-include-img-from-archive (&rest ignore)
"Extract image files from the archive files. Only .zip files are supported
as of now.
Only looks at #HEADER: lines that have \":extractfromarchive t\".
This function does nothing if not in org-mode, so you can safely
add it to `before-save-hook'."
(interactive)
(when (derived-mode-p 'org-mode)
(save-excursion
(goto-char (point-min)) ; go to the beginning of the buffer
(while (search-forward-regexp
"^\s-*#\+HEADER:.*\s-:extractfromarchive\s-+t"
nil :noerror)
(let (;; only .zip supported as of now
(search-expr "\[\[\(.*?\)_zip/\(.*?\)\([^/]+\..*\)\]\]")
arc-file
path-in-arc-file
img-file img-file-full-path
dest-dir dest-dir-full-path
cmd)
;; Keep on going on to the next line till it finds a line with
;; `[[./path/to/zip-file/path/inside/zip/to/the/image]]'
(while (progn
(forward-line 1)
(or (not (looking-at search-expr))
(eobp))))
(when (looking-at search-expr)
(setq arc-file (expand-file-name
(concat (match-string-no-properties 1) ".zip")))
(setq path-in-arc-file (match-string-no-properties 2))
(setq img-file (match-string-no-properties 3))
(setq dest-dir (concat "./" (file-name-base arc-file)
"_zip/" path-in-arc-file))
(setq dest-dir-full-path (concat (file-name-sans-extension arc-file)
"_zip/" path-in-arc-file))
(setq img-file-full-path (expand-file-name img-file dest-dir))
;; (message (concat "arc-file: %s\npath-in-arc-file: %s\n"
;; "img-file: %s\nimg-file-full-path: %s\n"
;; "dest-dir: %s\ndest-dir-full-path: %s")
;; arc-file path-in-arc-file
;; img-file img-file-full-path
;; dest-dir dest-dir-full-path)
(when (file-newer-than-file-p arc-file img-file-full-path)
;; This block is executed only if arc-file is newer than
;; img-file-full-path
;; or if img-file does not exist
;; https://www.gnu.org/software/emacs/manual/html_node/elisp/Testing-Accessibility.html
(when (file-exists-p dest-dir-full-path)
(delete-directory dest-dir-full-path t t))
(make-directory dest-dir-full-path t)
(setq cmd (format "unzip -j %s %s%s -d ./%s."
arc-file path-in-arc-file img-file
(concat (file-name-base arc-file) "_zip/"
path-in-arc-file)))
(message "%s" cmd)
(shell-command cmd)
(shell-command (concat "touch " img-file-full-path)))))))))
在启用了 iimage-mode 的 emacs org-mode 中,它可以显示来自相对文件路径的内联图像,例如: [[文件:images/foo.jpg]]
我想要的是:它如何显示位于 zip 存档中的图像,如下所示: [[file:images.zip/foo.jpg]] 有办法吗?
感谢kaushalmodi, 下面是我按照这个问题 how to display pdf images in org mode 中的答案所做的。由于是第一次做lisp编程,代码可能设计的不太好
(add-hook 'org-mode-hook #'modi/org-include-img-from-zip)
(defun modi/org-include-img-from-zip (&rest ignore)
"extract images from zip an archive.
This function does nothing if not in org-mode."
(interactive)
(when (derived-mode-p 'org-mode)
(save-excursion
(goto-char (point-min))
(while (search-forward-regexp
"^\s-*#\+STARTUP:.*\s-convertfromzip"
nil 'noerror)
(let* (filenoext imgext imgfile imgfilename zipfile imgpath cmd)
(setq zipfile "arc.zip")
;; Keep on going on to the next line till it finds a line with
;; `[[FILE]]'
(while (progn
(forward-line 1)
(not (looking-at "\[\[\(.*\)\.\(.*\)\]\]"))))
(when (looking-at "\[\[file:\(.*\)\.\(.*\)\]\]")
(setq filenoext (match-string-no-properties 1))
(setq imgext (match-string-no-properties 2))
(setq imgpath (concat filenoext "." imgext))
(setq imgfile (expand-file-name (concat filenoext "." imgext)))
(setq imgfilename (file-name-nondirectory imgfile))
(when (string= (substring imgpath 0 1) "~")
(setq imgpath (concat "%HOME%" (substring imgpath 1 nil)))
(setq imgpath (file-name-directory imgpath))
(setq cmd (concat "7z e " zipfile " -y -o"imgpath " " imgfilename " " imgfilename ))
(with-temp-buffer (shell-command cmd t))
)
))))))
工作规则:
- 如果您有包含图像
myimage.png
的 zip 文件zippedimg.zip
,您应该在组织模式文件中将其引用为[[./zippedimg_zip/myimage.png]]
。请注意,我已将zippedimg.zip
中的.
替换为_
。 - 这样做的原因是我正在创建与
[[
和]]
中提到的目录相同的目录。但是由于zippedimg.zip
文件存在,emacs 不允许创建同名目录。因此,对于zippedimg.zip
文件,我只提取其中的图像 ,同时将 zip 中的路径保留到zippedimg_zip
目录中。
这是一个用于测试的最小工作组织文件:
#+TITLE: Image from archive
#+STARTUP: inlineimages
#+NAME: fig:myimage
#+HEADER: :extractfromarchive t
# The below caption line is optional
#+CAPTION: My image myimage.png inside ./zippedimg.zip
[[./zippedimg_zip/myimage.png]]
这是您需要放在 emacs init 某处的代码:
;; Execute the `modi/org-include-img-from-archive' function just before saving the file
(add-hook 'before-save-hook #'modi/org-include-img-from-archive)
;; Execute the `modi/org-include-img-from-archive' function before processing the
;; file for export
(add-hook 'org-export-before-processing-hook #'modi/org-include-img-from-archive)
(defun modi/org-include-img-from-archive (&rest ignore)
"Extract image files from the archive files. Only .zip files are supported
as of now.
Only looks at #HEADER: lines that have \":extractfromarchive t\".
This function does nothing if not in org-mode, so you can safely
add it to `before-save-hook'."
(interactive)
(when (derived-mode-p 'org-mode)
(save-excursion
(goto-char (point-min)) ; go to the beginning of the buffer
(while (search-forward-regexp
"^\s-*#\+HEADER:.*\s-:extractfromarchive\s-+t"
nil :noerror)
(let (;; only .zip supported as of now
(search-expr "\[\[\(.*?\)_zip/\(.*?\)\([^/]+\..*\)\]\]")
arc-file
path-in-arc-file
img-file img-file-full-path
dest-dir dest-dir-full-path
cmd)
;; Keep on going on to the next line till it finds a line with
;; `[[./path/to/zip-file/path/inside/zip/to/the/image]]'
(while (progn
(forward-line 1)
(or (not (looking-at search-expr))
(eobp))))
(when (looking-at search-expr)
(setq arc-file (expand-file-name
(concat (match-string-no-properties 1) ".zip")))
(setq path-in-arc-file (match-string-no-properties 2))
(setq img-file (match-string-no-properties 3))
(setq dest-dir (concat "./" (file-name-base arc-file)
"_zip/" path-in-arc-file))
(setq dest-dir-full-path (concat (file-name-sans-extension arc-file)
"_zip/" path-in-arc-file))
(setq img-file-full-path (expand-file-name img-file dest-dir))
;; (message (concat "arc-file: %s\npath-in-arc-file: %s\n"
;; "img-file: %s\nimg-file-full-path: %s\n"
;; "dest-dir: %s\ndest-dir-full-path: %s")
;; arc-file path-in-arc-file
;; img-file img-file-full-path
;; dest-dir dest-dir-full-path)
(when (file-newer-than-file-p arc-file img-file-full-path)
;; This block is executed only if arc-file is newer than
;; img-file-full-path
;; or if img-file does not exist
;; https://www.gnu.org/software/emacs/manual/html_node/elisp/Testing-Accessibility.html
(when (file-exists-p dest-dir-full-path)
(delete-directory dest-dir-full-path t t))
(make-directory dest-dir-full-path t)
(setq cmd (format "unzip -j %s %s%s -d ./%s."
arc-file path-in-arc-file img-file
(concat (file-name-base arc-file) "_zip/"
path-in-arc-file)))
(message "%s" cmd)
(shell-command cmd)
(shell-command (concat "touch " img-file-full-path)))))))))