Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 88 additions & 35 deletions org-inline-pdf.el
Original file line number Diff line number Diff line change
Expand Up @@ -61,16 +61,23 @@

(defvar org-babel-temporary-directory)

(defvar org-inline-pdf-make-preview-program "pdf2svg")
(defvar org-inline-pdf-make-preview-program
;; "magick"
"pdf2svg"
)
(defvar org-inline-pdf-preview-format
;; "png"
"svg"
)

(defvar org-inline-pdf-cache-directory nil)

(defun org-inline-pdf-cache-directory ()
"Return temp directory for caching preview images."
(or org-inline-pdf-cache-directory
(if (eval-when-compile (fboundp 'org-babel-temp-directory))
(org-babel-temp-directory)
org-babel-temporary-directory)))
(org-babel-temp-directory)
org-babel-temporary-directory)))

(defconst org-inline-pdf--org-html-image-extensions-for-file
;; This list is taken from the definition of the variable
Expand All @@ -83,61 +90,107 @@

You can use `#+attr_org: :page NUM' to specify the page number."
(let* ((case-fold-search t)
(datum (org-element-context))
(par (org-element-lineage datum '(paragraph)))
(attr-re "^[ \t]*#\\+attr_.*?: +.*?:page +\\(\\S-+\\)")
(par-end (org-element-property :post-affiliated par))
(attr-page-num
(if (and par
(org-with-point-at
(org-element-property :begin par)
(re-search-forward attr-re par-end t)))
(match-string-no-properties 1)
"1")))
(datum (org-element-context))
(par (org-element-lineage datum '(paragraph)))
(attr-re "^[ \t]*#\\+attr_.*?: +.*?:page +\\(\\S-+\\)")
(par-end (org-element-property :post-affiliated par))
(attr-page-num
(if (and par
(org-with-point-at
(org-element-property :begin par)
(re-search-forward attr-re par-end t)))
(match-string-no-properties 1)
nil)))
attr-page-num))

(defun org-inline-pdf--make-preview-for-pdf (original-org--create-inline-image &rest arguments)
"Make a SVG preview when the inline image is a PDF.
"Make a preview file when the inline image is a PDF.
This function is to be used as an `around' advice to
`org--create-inline-image'. The original function is passed in
ORIGINAL-ORG--CREATE-INLINE-IMAGE and arguments in ARGUMENTS."
(let ((file (car arguments))
(page-num (org-inline-pdf--get-page-number)))
(page-num (org-inline-pdf--get-page-number)))
(apply original-org--create-inline-image
(cons
(if (member (file-name-extension file) '("pdf" "PDF"))
(let ((svg (expand-file-name
(concat "org-inline-pdf-"
(md5 (format "%s:%s" file page-num)))
(org-inline-pdf-cache-directory))))
(when (or (not (file-exists-p svg))
(time-less-p (nth 5 (file-attributes svg))
(nth 5 (file-attributes file))))
(call-process org-inline-pdf-make-preview-program
nil nil nil file svg page-num))
svg)
file)
(cdr arguments)))))

(cons
(if (member (downcase (file-name-extension file)) '("pdf"))
(let (cmd
(output_file (expand-file-name
(concat "org-inline-pdf-"
(md5 (format "%s:%s" file page-num))
(concat "." org-inline-pdf-preview-format))
(org-inline-pdf-cache-directory))))
(when (or (not (file-exists-p output_file))
(time-less-p (nth 5 (file-attributes output_file))
(nth 5 (file-attributes file))))
;;;
(setq cmd
(cond
((s-ends-with-p "pdf2svg" org-inline-pdf-make-preview-program)
(list org-inline-pdf-make-preview-program file output_file
(or page-num "1")))
((s-ends-with-p "magick" org-inline-pdf-make-preview-program)
(append
(list
org-inline-pdf-make-preview-program
"convert"
"-density"
"150"
"-trim")
(cond
((not (null page-num))
(list (concat file "[" page-num "]")))
(t (list file)))
(list
;; "-resize"
;; "200%"
"-quality"
"100"
;; "-flatten"
;; "-sharpen"
;; "0x1.0"
output_file)))
(t
(error "Unsupported `org-inline-pdf-make-preview-program': %s" org-inline-pdf-make-preview-program))))

(message "Executing command: %s" cmd)
(run-command-and-check-error cmd))
output_file)
file)
(cdr arguments)))))

(defun run-command-and-check-error (cmd)
(let* ((command (if (file-name-absolute-p (car cmd))
(car cmd)
(executable-find (car cmd))))
(output-buffer (generate-new-buffer "*cmd-output*"))
(exit-status (apply 'call-process command nil output-buffer nil (cdr cmd))))

(if (/= exit-status 0)
(progn
(with-current-buffer output-buffer
(message "Command failed with exit status %d:\n%s"
exit-status
(buffer-string)))
(kill-buffer output-buffer)))))
;;;###autoload
(define-minor-mode org-inline-pdf-mode
"Toggle inline previewing of PDF images in Org buffer."
:init-value nil :lighter "" :keymap nil
(cond
(org-inline-pdf-mode
(if (called-interactively-p 'interactive)
(message "org-inline-pdf-mode enabled"))
(message "org-inline-pdf-mode enabled"))
(add-to-list 'image-file-name-extensions "pdf")
(advice-add 'org--create-inline-image :around #'org-inline-pdf--make-preview-for-pdf)
(setf (alist-get "file" org-html-inline-image-rules nil t 'string=)
(regexp-opt (cons "pdf" org-inline-pdf--org-html-image-extensions-for-file))))
(regexp-opt (cons "pdf" org-inline-pdf--org-html-image-extensions-for-file))))
(t
(if (called-interactively-p 'interactive)
(message "org-inline-pdf-mode disabled"))
(message "org-inline-pdf-mode disabled"))
(setq image-file-name-extensions (delete "pdf" image-file-name-extensions))
(advice-remove 'org--create-inline-image #'org-inline-pdf--make-preview-for-pdf)
(setf (alist-get "file" org-html-inline-image-rules nil t 'string=)
(regexp-opt org-inline-pdf--org-html-image-extensions-for-file))
(regexp-opt org-inline-pdf--org-html-image-extensions-for-file))
(org-remove-inline-images))))

(provide 'org-inline-pdf)
Expand Down