From 3019d930d6f828548ea2b5b99e4b62000014cbff Mon Sep 17 00:00:00 2001 From: TEC Date: Mon, 15 Jan 2024 23:39:59 +0800 Subject: [PATCH] ox-html: Allow inlining svg tex as elements * lisp/ox-html.el (org-html-latex-image--data, org-html-latex-image): Add support for inlining dvisvgm-exported svgs as elements, preserving the effect of the currentColor attribute. While making this change, we improve a few other aspects of the html LaTeX fragment export system, namely refactoring/code style improvements and the recognition of \[...\] and $$...$$ fragments as blocks not inline fragments. --- lisp/ox-html.el | 103 +++++++++++++++++++++++++++++++----------------- 1 file changed, 66 insertions(+), 37 deletions(-) diff --git a/lisp/ox-html.el b/lisp/ox-html.el index 34234a252..48c71ace4 100644 --- a/lisp/ox-html.el +++ b/lisp/ox-html.el @@ -1181,13 +1181,12 @@ This is a HTML-specific counterpart to This supports two extra properties, :image-dir an html-export counterpart of `org-latex-preview-cache', and -:inline images that should not be saved according to :image-dir, - but instead inlined in the generated HTML. This can be: - - t, to inline all images - - svg, to inline all images, using with SVGs - - nil, to never inline images - - an extension or list of extensions, for images that - should be inline (e.g. \"svg\")" +:inline a list of image formats (or single format symbol) that + should not be saved according to :image-dir, but instead + 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" :group 'org-export-html :package-version '(Org . "9.7") :type 'plist) @@ -3208,40 +3207,48 @@ that an image for ELEMENT already exists within it." (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)) - (rescale-factor (if (eq (plist-get (cdr path-info) :image-type) 'svg) - (plist-get image-options :scale) - 1)) + (block-p (memq (aref (org-element-property :value element) 1) '(?$ ?\[))) (image-source - (org-html-latex-image--data (car path-info) hash info))) + (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) - (string= (file-name-extension (car path-info)) "svg")) + (if (and (eq (plist-get image-options :inline) 'svg-embed) + (eq (plist-get (cdr path-info) :image-type) 'svg)) image-source - (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 (eq (org-element-type element) 'latex-environment) - (format "height: %.4fem" - (* rescale-factor (plist-get (cdr path-info) :height))) - (format "height: %.4fem; vertical-align: -%.4fem; display: inline-block" - (* rescale-factor (plist-get (cdr path-info) :height)) - (* rescale-factor (plist-get (cdr path-info) :depth)))) - :class (if (eq (org-element-type element) 'latex-environment) - "org-latex org-latex-environment" - "org-latex org-latex-fragment"))) - info)))) + (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))))) -(defun org-html-latex-image--data (source-file hash info) - "Obtaine the image source for SOURCE-FILE as a string, based on HASH and INFO. -This can take the form of a path, data URI, or element." +(defun org-html-latex-image--scaling (image-path-info info) + "Determine the appropriate ( . ) of IMAGE-PATH-INFO given INFO." + (let* ((image-options (plist-get info :html-latex-image-options)) + (rescale-factor (if (eq (plist-get (cdr image-path-info) :image-type) 'svg) + (plist-get image-options :scale) + 1))) + (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) + "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))) + (image-dir (plist-get image-options :image-dir)) + (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) @@ -3251,10 +3258,32 @@ This can take the form of a path, data URI, or element." (with-temp-buffer (insert-file-contents-literally source-file) (cond - ((and (eq inline-condition 'svg) - (string= (file-name-extension source-file) "svg")) + ((and (eq inline-condition 'svg-embed) + (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)) - ((string= (file-name-extension source-file) "svg") + ((eq image-format 'svg) ;; Modelled after . (concat "data:image/svg+xml," (url-hexify-string @@ -3269,7 +3298,7 @@ This can take the form of a path, data URI, or element." (t (base64-encode-region (point-min) (point-max)) (goto-char (point-min)) - (insert "data:image/" (file-name-extension source-file) ";base64,") + (insert "data:image/" (symbol-name image-format) ";base64,") (buffer-string)))))) ((stringp image-dir) (let* ((image-dir (expand-file-name image-dir))