diff --git a/lisp/ox-html.el b/lisp/ox-html.el index 8773e9984..62fda837c 100644 --- a/lisp/ox-html.el +++ b/lisp/ox-html.el @@ -1186,7 +1186,9 @@ This supports two extra properties, inlined in the generated HTML. Valid format symbols are: - png, to inline png images using with a data URI - svg, to inline svg images using with a data URI - - svg-embed, to inline svg images using an element" + - svg-embed, to inline svg images using an element. + This is only applied when used along with svg, as in + (svg svg-embed)." :group 'org-export-html :package-version '(Org . "9.7") :type 'plist) @@ -1738,6 +1740,7 @@ INFO is the current state of the export process, as a plist." "Return close-tag for string TAG. ATTR specifies additional attributes. INFO is a property list containing current export state." + (declare (indent 1)) (concat "<" tag (org-string-nw-p (concat " " attr)) (if (org-html-xhtml-p info) " />" ">"))) @@ -3051,64 +3054,34 @@ CONTENTS is nil. INFO is a plist holding contextual information." (defun org-html-prepare-latex-images (parse-tree _backend info) "Make sure that appropriate preview images exist for all LaTeX. -TODO." - (when (assq (plist-get info :with-latex) org-latex-preview-process-alist) - (let* ((latex-preamble - (or org-latex-preview--preamble-content - (setq org-latex-preview--preamble-content - (org-latex-preview--get-preamble)))) - (elements - (org-element-map parse-tree - '(latex-fragment latex-environment) - #'identity - info)) - (entries-and-numbering - (org-latex-preview--construct-entries - elements t parse-tree)) - (processing-type (plist-get info :with-latex)) - (processing-info - (cdr (assq processing-type org-latex-preview-process-alist))) - (imagetype (or (plist-get processing-info :image-output-type) "png")) - (numbering-offsets (cons nil (cadr entries-and-numbering))) - (html-options (plist-get info :html-latex-image-options)) - (element-hash-table (make-hash-table :test #'eq :size (length elements))) - fragment-info prev-fg prev-bg) - (cl-loop - for entry in (car entries-and-numbering) - for element in elements - do - (pcase-let* ((`(,beg ,end ,provided-value) entry) - (value (or provided-value - (buffer-substring-no-properties beg end))) - (fg (plist-get html-options :foreground)) - (bg (plist-get html-options :background)) - (number (car (setq numbering-offsets (cdr numbering-offsets)))) - (hash (org-latex-preview--hash - processing-type latex-preamble value imagetype fg bg number)) - (options (org-combine-plists - org-latex-preview-appearance-options - html-options - (list :number number - :continue-color - (and (equal prev-bg bg) - (equal prev-fg fg)))))) - (puthash element hash element-hash-table) - (unless (org-latex-preview--get-cached hash) - (push (list :string (org-latex-preview--tex-styled - processing-type value options) - :overlay (org-latex-preview--ensure-overlay beg end) - :key hash) - fragment-info)) - (setq prev-fg fg prev-bg bg))) - (when fragment-info - (apply #'org-async-wait-for - (org-latex-preview--create-image-async - processing-type - (nreverse fragment-info) - :latex-preamble latex-preamble - :appearance-options html-options))) - (plist-put info :html-latex-preview-hash-table element-hash-table) - nil))) + +Create a hash table containing preview images for all LaTeX +fragments in PARSE-TREE, and add it to INFO. Filter out +fragments to be ignored according to INFO (see the INFO argument +of `org-element-map'). + +The keys of the hash table are elements and the values are lists +containing image paths and metadata used for display." + (prog1 nil + (let ((processing-type (plist-get info :with-latex))) + (when (assq processing-type org-latex-preview-process-alist) + (let* ((image-options (plist-get info :html-latex-image-options)) + (inline-condition (org-ensure-list + (plist-get image-options :inline))) + (image-type + (thread-first processing-type + (alist-get org-latex-preview-process-alist) + (plist-get :image-output-type) + (intern))) + (element-preview-hash-table + (apply #'org-latex-preview-cache-images parse-tree info + ;; Do not copy preview images to :image-dir if + ;; inlining of images in html is requested + (org-combine-plists + image-options + (and (memq image-type inline-condition) + (list :image-dir nil)))))) + (plist-put info :html-latex-preview-hash-table element-preview-hash-table)))))) (defun org-html--as-latex (element info &optional content) (let ((content (or content (org-element-property :value element)))) @@ -3202,33 +3175,43 @@ CONTENTS is nil. INFO is a plist holding contextual information." "Transcode the LaTeX fragment or environment ELEMENT from Org to HTML. INFO is a plist holding contextual information, and it is assumed that an image for ELEMENT already exists within it." - (let* ((hash (or (gethash element (plist-get info :html-latex-preview-hash-table)) - (error "Expected LaTeX preview hash to exist for element, but none found"))) - (path-info (or (org-latex-preview--get-cached hash) - (error "Expected LaTeX preview %S to exist in the cache" hash))) - (image-options (plist-get info :html-latex-image-options)) + (let* ((path-info + (or (gethash element (plist-get info :html-latex-preview-hash-table)) + (prog1 nil + (org-display-warning + (format "Expected LaTeX preview image to exist for element, but none found: %s" + (string-replace "\n" " " (org-element-property :value element))))))) + (image-options (org-ensure-list (plist-get info :html-latex-image-options))) (block-p (memq (aref (org-element-property :value element) 1) '(?$ ?\[))) - (image-source - (org-html-latex-image--data path-info hash info block-p))) - (unless (and (plist-get (cdr path-info) :height) - (plist-get (cdr path-info) :depth)) - (error "Something went wrong during image generation")) - (if (and (eq (plist-get image-options :inline) 'svg-embed) - (eq (plist-get (cdr path-info) :image-type) 'svg)) + (image-source (if path-info (org-html-latex-image--data path-info info block-p) ""))) + (if (and (eq (plist-get (cdr path-info) :image-type) 'svg) + (memq 'svg-embed (plist-get image-options :inline))) image-source - (let ((scaling (org-html-latex-image--scaling path-info info))) - (org-html-close-tag - "img" - (org-html--make-attribute-string - (list :src image-source - :alt (org-html-encode-plain-text - (org-element-property :value element)) - :style (if block-p - (format "height: %.4fem; display: block" (plist-get scaling :height)) - (format "height: %.4fem; vertical-align: -%.4fem; display: inline-block" - (plist-get scaling :height) (plist-get scaling :depth))) - :class (format "org-latex org-latex-%s" (if block-p "block" "inline")))) - info))))) + (let ((scaling + (if (and (plist-get (cdr path-info) :height) + (plist-get (cdr path-info) :depth)) + (org-html-latex-image--scaling path-info info) + (prog1 nil + (org-display-warning + (format "Missing geometry information for LaTeX preview image for element: %s" + (string-replace "\n" " " (org-element-property :value element)))))))) + (org-html-close-tag "img" + (org-html--make-attribute-string + (nconc + (list :src image-source + :alt (org-html-encode-plain-text (org-element-property :value element)) + :style + (if path-info + (if scaling + (if block-p + (format "height: %.4fem; display: block" (plist-get scaling :height)) + (format "height: %.4fem; vertical-align: -%.4fem; display: inline-block" + (plist-get scaling :height) (plist-get scaling :depth))) + (if block-p "display: block" "display: inline-block")) + "color: red") + :class (format "org-latex org-latex-%s" (if block-p "block" "inline"))) + (unless path-info (list :title "LaTeX preview image not generated.")))) + info))))) (defun org-html-latex-image--scaling (image-path-info info) "Determine the appropriate ( . ) of IMAGE-PATH-INFO given INFO." @@ -3239,78 +3222,64 @@ that an image for ELEMENT already exists within it." (list :height (* rescale-factor (plist-get (cdr image-path-info) :height)) :depth (* rescale-factor (plist-get (cdr image-path-info) :depth))))) -(defun org-html-latex-image--data (image-path-info hash info &optional block-p) +(defun org-html-latex-image--data (image-path-info info &optional block-p) "Obtaine the image source for IMAGE-PATH-INFO as a string. This can take the form of a path, data URI, or element depending on HASH and INFO. BLOCK-P signals that the image should be a block element." (let* ((image-options (plist-get info :html-latex-image-options)) - (inline-condition (plist-get image-options :inline)) - (image-dir (plist-get image-options :image-dir)) + (inline-condition (org-ensure-list (plist-get image-options :inline))) (image-format (plist-get (cdr image-path-info) :image-type)) (source-file (car image-path-info))) - (cond - ((or inline-condition - (member (file-name-extension source-file) - (org-ensure-list inline-condition))) - (let ((coding-system-for-read 'utf-8) - (file-name-handler-alist nil)) - (with-temp-buffer - (insert-file-contents-literally source-file) - (cond - ((and (eq inline-condition 'svg-embed) - (eq image-format 'svg)) - (goto-char (point-min)) - (let ((svg-closing-tag (and (search-forward "" nil t)))) + (if (memq image-format inline-condition) + (let ((coding-system-for-read 'utf-8) + (file-name-handler-alist nil)) + (with-temp-buffer + (insert-file-contents-literally source-file) + (cond + ((and (memq 'svg-embed inline-condition) + (eq image-format 'svg)) + (goto-char (point-min)) + (let ((svg-closing-tag (and (search-forward "" nil t)))) - (dolist (search '("" - " height=['\"][^\"']+[\"']" - " width=['\"][^\"']+[\"']")) - (goto-char (point-min)) - (when (re-search-forward search svg-closing-tag t) - (replace-match ""))) - (goto-char (point-min)) - (when (re-search-forward "viewBox=['\"][^\"']+[\"']" svg-closing-tag t) - (insert - " style=\"" - (let ((scaling (org-html-latex-image--scaling image-path-info info))) - (if block-p - (format "height: %.4fem; display: block" (plist-get scaling :height)) - (format "height: %.4fem; vertical-align: -%.4fem; display: inline-block" - (plist-get scaling :height) (plist-get scaling :depth)))) - "\" class=\"org-latex org-latex-" - (if block-p "block" "inline") - "\""))) - (buffer-string)) - ((eq image-format 'svg) - ;; Modelled after . - (concat "data:image/svg+xml," - (url-hexify-string - (subst-char-in-string ?\" ?\' (buffer-string)) - '(?a ?b ?c ?d ?e ?f ?g ?h ?i ?j ?k ?l ?m ?n - ?o ?p ?q ?r ?s ?t ?u ?v ?w ?x ?y ?z ?A ?B - ?C ?D ?E ?F ?G ?H ?I ?J ?K ?L ?M ?N ?O ?P - ?Q ?R ?S ?T ?U ?V ?W ?X ?Y ?Z ?0 ?1 ?2 ?3 - ?4 ?5 ?6 ?7 ?8 ?9 ?- ?_ ?. ?~ - ;;Special additions - ?\s ?= ?: ?/)))) - (t - (base64-encode-region (point-min) (point-max)) - (goto-char (point-min)) - (insert "data:image/" (symbol-name image-format) ";base64,") - (buffer-string)))))) - ((stringp image-dir) - (let* ((image-dir (expand-file-name image-dir)) - (image-path (file-name-with-extension - (file-name-concat image-dir (substring hash 0 11)) - (file-name-extension source-file)))) - (unless (file-directory-p image-dir) - (mkdir image-dir t)) - (unless (file-exists-p image-path) - (copy-file source-file image-path)) - image-path)) - (t source-file)))) + (dolist (search '("" + " height=['\"][^\"']+[\"']" + " width=['\"][^\"']+[\"']")) + (goto-char (point-min)) + (when (re-search-forward search svg-closing-tag t) + (replace-match ""))) + (goto-char (point-min)) + (when (re-search-forward "viewBox=['\"][^\"']+[\"']" svg-closing-tag t) + (insert + " style=\"" + (let ((scaling (org-html-latex-image--scaling image-path-info info))) + (if block-p + (format "height: %.4fem; display: block" (plist-get scaling :height)) + (format "height: %.4fem; vertical-align: -%.4fem; display: inline-block" + (plist-get scaling :height) (plist-get scaling :depth)))) + "\" class=\"org-latex org-latex-" + (if block-p "block" "inline") + "\""))) + (buffer-string)) + ((eq image-format 'svg) + ;; Modelled after . + (concat "data:image/svg+xml," + (url-hexify-string + (subst-char-in-string ?\" ?\' (buffer-string)) + '(?a ?b ?c ?d ?e ?f ?g ?h ?i ?j ?k ?l ?m ?n + ?o ?p ?q ?r ?s ?t ?u ?v ?w ?x ?y ?z ?A ?B + ?C ?D ?E ?F ?G ?H ?I ?J ?K ?L ?M ?N ?O ?P + ?Q ?R ?S ?T ?U ?V ?W ?X ?Y ?Z ?0 ?1 ?2 ?3 + ?4 ?5 ?6 ?7 ?8 ?9 ?- ?_ ?. ?~ + ;;Special additions + ?\s ?= ?: ?/)))) + (t + (base64-encode-region (point-min) (point-max)) + (goto-char (point-min)) + (insert "data:image/" (symbol-name image-format) ";base64,") + (buffer-string))))) + source-file))) ;;;; Line Break