org.el: Relocate LaTeX preview code to new file

* lisp/org.el (org-format-latex-options, org-format-latex-signal-error,
org-latex-to-mathml-jar-file, org-latex-to-mathml-convert-command,
org-latex-to-html-convert-command, org-preview-latex-default-process,
org-preview-latex-process-alist, org-preview-latex-image-directory,
org-format-latex-header, org-format-latex-mathml-available-p,
org--make-preview-overlay, org-clear-latex-preview,
org--latex-preview-region, org-latex-preview, org-format-latex,
org-place-formula-image, org-create-math-formula,
org-format-latex-as-mathml, org-format-latex-as-html,
org--get-display-dpi, org-create-formula-image, org-dvipng-color,
org-dvipng-color-format, org-latex-color, org-latex-color-format,
org-normalize-color): Move to org-latex-preview.el.

* lisp/org-latex-preview.el: A new home for code related to the
generated of in-buffer previews of LaTeX fragments.
This commit is contained in:
TEC 2022-12-25 23:52:25 +08:00
parent 72ba4116eb
commit c591dda62a
Signed by: tec
SSH Key Fingerprint: SHA256:eobz41Mnm0/iYWBvWThftS0ElEs1ftBr6jamutnXc/A
2 changed files with 749 additions and 722 deletions

747
lisp/org-latex-preview.el Normal file
View File

@ -0,0 +1,747 @@
;;; org-latex-preview.el --- LaTeX previews for Org -*- lexical-binding: t; -*-
;; Copyright (C) 2022 Free Software Foundation, Inc.
;; Keywords: tex, extensions, tools
;; This file is part of GNU Emacs.
;; GNU Emacs is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
;;
;; LaTeX previews for Org
;;; Code:
(defgroup org-latex nil
"Options for embedding LaTeX code into Org mode."
:tag "Org LaTeX"
:group 'org)
(defcustom org-format-latex-options
'(:foreground default :background default :scale 1.0
:html-foreground "Black" :html-background "Transparent"
:html-scale 1.0 :matchers ("begin" "$1" "$" "$$" "\\(" "\\["))
"Options for creating images from LaTeX fragments.
This is a property list with the following properties:
:foreground the foreground color for images embedded in Emacs, e.g. \"Black\".
`default' means use the foreground of the default face.
`auto' means use the foreground from the text face.
:background the background color, or \"Transparent\".
`default' means use the background of the default face.
`auto' means use the background from the text face.
:scale a scaling factor for the size of the images, to get more pixels
:html-foreground, :html-background, :html-scale
the same numbers for HTML export.
:matchers a list indicating which matchers should be used to
find LaTeX fragments. Valid members of this list are:
\"begin\" find environments
\"$1\" find single characters surrounded by $.$
\"$\" find math expressions surrounded by $...$
\"$$\" find math expressions surrounded by $$....$$
\"\\(\" find math expressions surrounded by \\(...\\)
\"\\=\\[\" find math expressions surrounded by \\=\\[...\\]"
:group 'org-latex
:type 'plist)
(defcustom org-format-latex-signal-error t
"Non-nil means signal an error when image creation of LaTeX snippets fails.
When nil, just push out a message."
:group 'org-latex
:version "24.1"
:type 'boolean)
(defcustom org-latex-to-mathml-jar-file nil
"Value of\"%j\" in `org-latex-to-mathml-convert-command'.
Use this to specify additional executable file say a jar file.
When using MathToWeb as the converter, specify the full-path to
your mathtoweb.jar file."
:group 'org-latex
:version "24.1"
:type '(choice
(const :tag "None" nil)
(file :tag "JAR file" :must-match t)))
(defcustom org-latex-to-mathml-convert-command nil
"Command to convert LaTeX fragments to MathML.
Replace format-specifiers in the command as noted below and use
`shell-command' to convert LaTeX to MathML.
%j: Executable file in fully expanded form as specified by
`org-latex-to-mathml-jar-file'.
%I: Input LaTeX file in fully expanded form.
%i: Shell-escaped LaTeX fragment to be converted.
It must not be used inside a quoted argument, the result of %i
expansion inside a quoted argument is undefined.
%o: Output MathML file.
This command is used by `org-create-math-formula'.
When using MathToWeb as the converter, set this option to
\"java -jar %j -unicode -force -df %o %I\".
When using LaTeXML set this option to
\"latexmlmath %i --presentationmathml=%o\"."
:group 'org-latex
:version "24.1"
:type '(choice
(const :tag "None" nil)
(string :tag "\nShell command")))
(defcustom org-latex-to-html-convert-command nil
"Shell command to convert LaTeX fragments to HTML.
This command is very open-ended: the output of the command will
directly replace the LaTeX fragment in the resulting HTML.
Replace format-specifiers in the command as noted below and use
`shell-command' to convert LaTeX to HTML.
%i: The LaTeX fragment to be converted (shell-escaped).
It must not be used inside a quoted argument, the result of %i
expansion inside a quoted argument is undefined.
For example, this could be used with LaTeXML as
\"latexmlc literal:%i --profile=math --preload=siunitx.sty 2>/dev/null\"."
:group 'org-latex
:package-version '(Org . "9.4")
:type '(choice
(const :tag "None" nil)
(string :tag "Shell command")))
(defcustom org-preview-latex-default-process 'dvipng
"The default process to convert LaTeX fragments to image files.
All available processes and theirs documents can be found in
`org-preview-latex-process-alist', which see."
:group 'org-latex
:version "26.1"
:package-version '(Org . "9.0")
:type 'symbol)
(defcustom org-preview-latex-process-alist
'((dvipng
:programs ("latex" "dvipng")
:description "dvi > png"
:message "you need to install the programs: latex and dvipng."
:image-input-type "dvi"
:image-output-type "png"
:image-size-adjust (1.0 . 1.0)
:latex-compiler ("latex -interaction nonstopmode -output-directory %o %f")
:image-converter ("dvipng -D %D -T tight -o %O %f")
:transparent-image-converter
("dvipng -D %D -T tight -bg Transparent -o %O %f"))
(dvisvgm
:programs ("latex" "dvisvgm")
:description "dvi > svg"
:message "you need to install the programs: latex and dvisvgm."
:image-input-type "dvi"
:image-output-type "svg"
:image-size-adjust (1.7 . 1.5)
:latex-compiler ("latex -interaction nonstopmode -output-directory %o %f")
:image-converter ("dvisvgm %f --no-fonts --exact-bbox --scale=%S --output=%O"))
(imagemagick
:programs ("latex" "convert")
:description "pdf > png"
:message "you need to install the programs: latex and imagemagick."
:image-input-type "pdf"
:image-output-type "png"
:image-size-adjust (1.0 . 1.0)
:latex-compiler ("pdflatex -interaction nonstopmode -output-directory %o %f")
:image-converter
("convert -density %D -trim -antialias %f -quality 100 %O")))
"Definitions of external processes for LaTeX previewing.
Org mode can use some external commands to generate TeX snippet's images for
previewing or inserting into HTML files, e.g., \"dvipng\". This variable tells
`org-create-formula-image' how to call them.
The value is an alist with the pattern (NAME . PROPERTIES). NAME is a symbol.
PROPERTIES accepts the following attributes:
:programs list of strings, required programs.
:description string, describe the process.
:message string, message it when required programs cannot be found.
:image-input-type string, input file type of image converter (e.g., \"dvi\").
:image-output-type string, output file type of image converter (e.g., \"png\").
:image-size-adjust cons of numbers, the car element is used to adjust LaTeX
image size showed in buffer and the cdr element is for
HTML file. This option is only useful for process
developers, users should use variable
`org-format-latex-options' instead.
:post-clean list of strings, files matched are to be cleaned up once
the image is generated. When nil, the files with \".dvi\",
\".xdv\", \".pdf\", \".tex\", \".aux\", \".log\", \".svg\",
\".png\", \".jpg\", \".jpeg\" or \".out\" extension will
be cleaned up.
:latex-header list of strings, the LaTeX header of the snippet file.
When nil, the fallback value is used instead, which is
controlled by `org-format-latex-header',
`org-latex-default-packages-alist' and
`org-latex-packages-alist', which see.
:latex-compiler list of LaTeX commands, as strings. Each of them is given
to the shell. Place-holders \"%t\", \"%b\" and \"%o\" are
replaced with values defined below.
:image-converter list of image converter commands strings. Each of them is
given to the shell and supports any of the following
place-holders defined below.
If set, :transparent-image-converter is used instead of :image-converter to
convert an image when the background color is nil or \"Transparent\".
Place-holders used by `:image-converter' and `:latex-compiler':
%f input file name
%b base name of input file
%o base directory of input file
%O absolute output file name
Place-holders only used by `:image-converter':
%D dpi, which is used to adjust image size by some processing commands.
%S the image size scale ratio, which is used to adjust image size by some
processing commands."
:group 'org-latex
:package-version '(Org . "9.6")
:type '(alist :tag "LaTeX to image backends"
:value-type (plist)))
(defcustom org-preview-latex-image-directory "ltximg/"
"Path to store latex preview images.
A relative path here creates many directories relative to the
processed Org files paths. An absolute path puts all preview
images at the same place."
:group 'org-latex
:version "26.1"
:package-version '(Org . "9.0")
:type 'string)
(defun org-format-latex-mathml-available-p ()
"Return t if `org-latex-to-mathml-convert-command' is usable."
(save-match-data
(when (and (boundp 'org-latex-to-mathml-convert-command)
org-latex-to-mathml-convert-command)
(let ((executable (car (split-string
org-latex-to-mathml-convert-command))))
(when (executable-find executable)
(if (string-match
"%j" org-latex-to-mathml-convert-command)
(file-readable-p org-latex-to-mathml-jar-file)
t))))))
(defcustom org-format-latex-header "\\documentclass{article}
\\usepackage[usenames]{color}
\[DEFAULT-PACKAGES]
\[PACKAGES]
\\pagestyle{empty} % do not remove
% The settings below are copied from fullpage.sty
\\setlength{\\textwidth}{\\paperwidth}
\\addtolength{\\textwidth}{-3cm}
\\setlength{\\oddsidemargin}{1.5cm}
\\addtolength{\\oddsidemargin}{-2.54cm}
\\setlength{\\evensidemargin}{\\oddsidemargin}
\\setlength{\\textheight}{\\paperheight}
\\addtolength{\\textheight}{-\\headheight}
\\addtolength{\\textheight}{-\\headsep}
\\addtolength{\\textheight}{-\\footskip}
\\addtolength{\\textheight}{-3cm}
\\setlength{\\topmargin}{1.5cm}
\\addtolength{\\topmargin}{-2.54cm}"
"The document header used for processing LaTeX fragments.
It is imperative that this header make sure that no page number
appears on the page. The package defined in the variables
`org-latex-default-packages-alist' and `org-latex-packages-alist'
will either replace the placeholder \"[PACKAGES]\" in this
header, or they will be appended."
:group 'org-latex
:type 'string)
(defun org--make-preview-overlay (beg end image &optional imagetype)
"Build an overlay between BEG and END using IMAGE file.
Argument IMAGETYPE is the extension of the displayed image,
as a string. It defaults to \"png\"."
(let ((ov (make-overlay beg end))
(imagetype (or (intern imagetype) 'png)))
(overlay-put ov 'org-overlay-type 'org-latex-overlay)
(overlay-put ov 'evaporate t)
(overlay-put ov
'modification-hooks
(list (lambda (o _flag _beg _end &optional _l)
(delete-overlay o))))
(overlay-put ov
'display
(list 'image :type imagetype :file image :ascent 'center))))
(defun org-clear-latex-preview (&optional beg end)
"Remove all overlays with LaTeX fragment images in current buffer.
When optional arguments BEG and END are non-nil, remove all
overlays between them instead. Return a non-nil value when some
overlays were removed, nil otherwise."
(let ((overlays
(cl-remove-if-not
(lambda (o) (eq (overlay-get o 'org-overlay-type) 'org-latex-overlay))
(overlays-in (or beg (point-min)) (or end (point-max))))))
(mapc #'delete-overlay overlays)
overlays))
(defun org--latex-preview-region (beg end)
"Preview LaTeX fragments between BEG and END.
BEG and END are buffer positions."
(let ((file (buffer-file-name (buffer-base-buffer))))
(save-excursion
(org-format-latex
(concat org-preview-latex-image-directory "org-ltximg")
beg end
;; Emacs cannot overlay images from remote hosts. Create it in
;; `temporary-file-directory' instead.
(if (or (not file) (file-remote-p file))
temporary-file-directory
default-directory)
'overlays nil 'forbuffer org-preview-latex-default-process))))
(defun org-latex-preview (&optional arg)
"Toggle preview of the LaTeX fragment at point.
If the cursor is on a LaTeX fragment, create the image and
overlay it over the source code, if there is none. Remove it
otherwise. If there is no fragment at point, display images for
all fragments in the current section. With an active region,
display images for all fragments in the region.
With a `\\[universal-argument]' prefix argument ARG, clear images \
for all fragments
in the current section.
With a `\\[universal-argument] \\[universal-argument]' prefix \
argument ARG, display image for all
fragments in the buffer.
With a `\\[universal-argument] \\[universal-argument] \
\\[universal-argument]' prefix argument ARG, clear image for all
fragments in the buffer."
(interactive "P")
(cond
((not (display-graphic-p)) nil)
;; Clear whole buffer.
((equal arg '(64))
(org-clear-latex-preview (point-min) (point-max))
(message "LaTeX previews removed from buffer"))
;; Preview whole buffer.
((equal arg '(16))
(message "Creating LaTeX previews in buffer...")
(org--latex-preview-region (point-min) (point-max))
(message "Creating LaTeX previews in buffer... done."))
;; Clear current section.
((equal arg '(4))
(org-clear-latex-preview
(if (use-region-p)
(region-beginning)
(if (org-before-first-heading-p) (point-min)
(save-excursion
(org-with-limited-levels (org-back-to-heading t) (point)))))
(if (use-region-p)
(region-end)
(org-with-limited-levels (org-entry-end-position)))))
((use-region-p)
(message "Creating LaTeX previews in region...")
(org--latex-preview-region (region-beginning) (region-end))
(message "Creating LaTeX previews in region... done."))
;; Toggle preview on LaTeX code at point.
((let ((datum (org-element-context)))
(and (memq (org-element-type datum) '(latex-environment latex-fragment))
(let ((beg (org-element-property :begin datum))
(end (org-element-property :end datum)))
(if (org-clear-latex-preview beg end)
(message "LaTeX preview removed")
(message "Creating LaTeX preview...")
(org--latex-preview-region beg end)
(message "Creating LaTeX preview... done."))
t))))
;; Preview current section.
(t
(let ((beg (if (org-before-first-heading-p) (point-min)
(save-excursion
(org-with-limited-levels (org-back-to-heading t) (point)))))
(end (org-with-limited-levels (org-entry-end-position))))
(message "Creating LaTeX previews in section...")
(org--latex-preview-region beg end)
(message "Creating LaTeX previews in section... done.")))))
(defun org-format-latex
(prefix &optional beg end dir overlays msg forbuffer processing-type)
"Replace LaTeX fragments with links to an image.
The function takes care of creating the replacement image.
Only consider fragments between BEG and END when those are
provided.
When optional argument OVERLAYS is non-nil, display the image on
top of the fragment instead of replacing it.
PROCESSING-TYPE is the conversion method to use, as a symbol.
Some of the options can be changed using the variable
`org-format-latex-options', which see."
(when (and overlays (fboundp 'clear-image-cache)) (clear-image-cache))
(unless (eq processing-type 'verbatim)
(let* ((math-regexp "\\$\\|\\\\[([]\\|^[ \t]*\\\\begin{[A-Za-z0-9*]+}")
(cnt 0)
checkdir-flag)
(goto-char (or beg (point-min)))
;; Optimize overlay creation: (info "(elisp) Managing Overlays").
(when (and overlays (memq processing-type '(dvipng imagemagick)))
(overlay-recenter (or end (point-max))))
(while (re-search-forward math-regexp end t)
(unless (and overlays
(eq (get-char-property (point) 'org-overlay-type)
'org-latex-overlay))
(let* ((context (org-element-context))
(type (org-element-type context)))
(when (memq type '(latex-environment latex-fragment))
(let ((block-type (eq type 'latex-environment))
(value (org-element-property :value context))
(beg (org-element-property :begin context))
(end (save-excursion
(goto-char (org-element-property :end context))
(skip-chars-backward " \r\t\n")
(point))))
(cond
((eq processing-type 'mathjax)
;; Prepare for MathJax processing.
(if (not (string-match "\\`\\$\\$?" value))
(goto-char end)
(delete-region beg end)
(if (string= (match-string 0 value) "$$")
(insert "\\[" (substring value 2 -2) "\\]")
(insert "\\(" (substring value 1 -1) "\\)"))))
((eq processing-type 'html)
(goto-char beg)
(delete-region beg end)
(insert (org-format-latex-as-html value)))
((assq processing-type org-preview-latex-process-alist)
;; Process to an image.
(cl-incf cnt)
(goto-char beg)
(let* ((processing-info
(cdr (assq processing-type org-preview-latex-process-alist)))
(face (face-at-point))
;; Get the colors from the face at point.
(fg
(let ((color (plist-get org-format-latex-options
:foreground)))
(if forbuffer
(cond
((eq color 'auto)
(face-attribute face :foreground nil 'default))
((eq color 'default)
(face-attribute 'default :foreground nil))
(t color))
color)))
(bg
(let ((color (plist-get org-format-latex-options
:background)))
(if forbuffer
(cond
((eq color 'auto)
(face-attribute face :background nil 'default))
((eq color 'default)
(face-attribute 'default :background nil))
(t color))
color)))
(hash (sha1 (prin1-to-string
(list org-format-latex-header
org-latex-default-packages-alist
org-latex-packages-alist
org-format-latex-options
forbuffer value fg bg))))
(imagetype (or (plist-get processing-info :image-output-type) "png"))
(absprefix (expand-file-name prefix dir))
(linkfile (format "%s_%s.%s" prefix hash imagetype))
(movefile (format "%s_%s.%s" absprefix hash imagetype))
(sep (and block-type "\n\n"))
(link (concat sep "[[file:" linkfile "]]" sep))
(options
(org-combine-plists
org-format-latex-options
`(:foreground ,fg :background ,bg))))
(when msg (message msg cnt))
(unless checkdir-flag ; Ensure the directory exists.
(setq checkdir-flag t)
(let ((todir (file-name-directory absprefix)))
(unless (file-directory-p todir)
(make-directory todir t))))
(unless (file-exists-p movefile)
(org-create-formula-image
value movefile options forbuffer processing-type))
(org-place-formula-image link block-type beg end value overlays movefile imagetype)))
((eq processing-type 'mathml)
;; Process to MathML.
(unless (org-format-latex-mathml-available-p)
(user-error "LaTeX to MathML converter not configured"))
(cl-incf cnt)
(when msg (message msg cnt))
(goto-char beg)
(delete-region beg end)
(insert (org-format-latex-as-mathml
value block-type prefix dir)))
(t
(error "Unknown conversion process %s for LaTeX fragments"
processing-type)))))))))))
(defun org-place-formula-image (link block-type beg end value overlays movefile imagetype)
"Place an overlay from BEG to END showing MOVEFILE.
The overlay will be above BEG if OVERLAYS is non-nil."
(if overlays
(progn
(dolist (o (overlays-in beg end))
(when (eq (overlay-get o 'org-overlay-type)
'org-latex-overlay)
(delete-overlay o)))
(org--make-preview-overlay beg end movefile imagetype)
(goto-char end))
(delete-region beg end)
(insert
(org-add-props link
(list 'org-latex-src
(replace-regexp-in-string "\"" "" value)
'org-latex-src-embed-type
(if block-type 'paragraph 'character))))))
(defun org-create-math-formula (latex-frag &optional mathml-file)
"Convert LATEX-FRAG to MathML and store it in MATHML-FILE.
Use `org-latex-to-mathml-convert-command'. If the conversion is
successful, return the portion between \"<math...> </math>\"
elements otherwise return nil. When MATHML-FILE is specified,
write the results in to that file. When invoked as an
interactive command, prompt for LATEX-FRAG, with initial value
set to the current active region and echo the results for user
inspection."
(interactive (list (let ((frag (when (org-region-active-p)
(buffer-substring-no-properties
(region-beginning) (region-end)))))
(read-string "LaTeX Fragment: " frag nil frag))))
(unless latex-frag (user-error "Invalid LaTeX fragment"))
(let* ((tmp-in-file
(let ((file (file-relative-name
(make-temp-name (expand-file-name "ltxmathml-in")))))
(write-region latex-frag nil file)
file))
(tmp-out-file (file-relative-name
(make-temp-name (expand-file-name "ltxmathml-out"))))
(cmd (format-spec
org-latex-to-mathml-convert-command
`((?j . ,(and org-latex-to-mathml-jar-file
(shell-quote-argument
(expand-file-name
org-latex-to-mathml-jar-file))))
(?I . ,(shell-quote-argument tmp-in-file))
(?i . ,latex-frag)
(?o . ,(shell-quote-argument tmp-out-file)))))
mathml shell-command-output)
(when (called-interactively-p 'any)
(unless (org-format-latex-mathml-available-p)
(user-error "LaTeX to MathML converter not configured")))
(message "Running %s" cmd)
(setq shell-command-output (shell-command-to-string cmd))
(setq mathml
(when (file-readable-p tmp-out-file)
(with-current-buffer (find-file-noselect tmp-out-file t)
(goto-char (point-min))
(when (re-search-forward
(format "<math[^>]*?%s[^>]*?>\\(.\\|\n\\)*</math>"
(regexp-quote
"xmlns=\"http://www.w3.org/1998/Math/MathML\""))
nil t)
(prog1 (match-string 0) (kill-buffer))))))
(cond
(mathml
(setq mathml
(concat "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" mathml))
(when mathml-file
(write-region mathml nil mathml-file))
(when (called-interactively-p 'any)
(message mathml)))
((warn "LaTeX to MathML conversion failed")
(message shell-command-output)))
(delete-file tmp-in-file)
(when (file-exists-p tmp-out-file)
(delete-file tmp-out-file))
mathml))
(defun org-format-latex-as-mathml (latex-frag latex-frag-type
prefix &optional dir)
"Use `org-create-math-formula' but check local cache first."
(let* ((absprefix (expand-file-name prefix dir))
(print-length nil) (print-level nil)
(formula-id (concat
"formula-"
(sha1
(prin1-to-string
(list latex-frag
org-latex-to-mathml-convert-command)))))
(formula-cache (format "%s-%s.mathml" absprefix formula-id))
(formula-cache-dir (file-name-directory formula-cache)))
(unless (file-directory-p formula-cache-dir)
(make-directory formula-cache-dir t))
(unless (file-exists-p formula-cache)
(org-create-math-formula latex-frag formula-cache))
(if (file-exists-p formula-cache)
;; Successful conversion. Return the link to MathML file.
(org-add-props
(format "[[file:%s]]" (file-relative-name formula-cache dir))
(list 'org-latex-src (replace-regexp-in-string "\"" "" latex-frag)
'org-latex-src-embed-type (if latex-frag-type
'paragraph 'character)))
;; Failed conversion. Return the LaTeX fragment verbatim
latex-frag)))
(defun org-format-latex-as-html (latex-fragment)
"Convert LATEX-FRAGMENT to HTML.
This uses `org-latex-to-html-convert-command', which see."
(let ((cmd (format-spec org-latex-to-html-convert-command
`((?i . ,latex-fragment)))))
(message "Running %s" cmd)
(shell-command-to-string cmd)))
(defun org--get-display-dpi ()
"Get the DPI of the display.
The function assumes that the display has the same pixel width in
the horizontal and vertical directions."
(if (display-graphic-p)
(round (/ (display-pixel-height)
(/ (display-mm-height) 25.4)))
(error "Attempt to calculate the dpi of a non-graphic display")))
(defun org-create-formula-image
(string tofile options buffer &optional processing-type)
"Create an image from LaTeX source using external processes.
The LaTeX STRING is saved to a temporary LaTeX file, then
converted to an image file by process PROCESSING-TYPE defined in
`org-preview-latex-process-alist'. A nil value defaults to
`org-preview-latex-default-process'.
The generated image file is eventually moved to TOFILE.
The OPTIONS argument controls the size, foreground color and
background color of the generated image.
When BUFFER non-nil, this function is used for LaTeX previewing.
Otherwise, it is used to deal with LaTeX snippets showed in
a HTML file."
(let* ((processing-type (or processing-type
org-preview-latex-default-process))
(processing-info
(cdr (assq processing-type org-preview-latex-process-alist)))
(programs (plist-get processing-info :programs))
(error-message (or (plist-get processing-info :message) ""))
(image-input-type (plist-get processing-info :image-input-type))
(image-output-type (plist-get processing-info :image-output-type))
(post-clean (or (plist-get processing-info :post-clean)
'(".dvi" ".xdv" ".pdf" ".tex" ".aux" ".log"
".svg" ".png" ".jpg" ".jpeg" ".out")))
(latex-header
(or (plist-get processing-info :latex-header)
(org-latex-make-preamble
(org-export-get-environment (org-export-get-backend 'latex))
org-format-latex-header
'snippet)))
(latex-compiler (plist-get processing-info :latex-compiler))
(tmpdir temporary-file-directory)
(texfilebase (make-temp-name
(expand-file-name "orgtex" tmpdir)))
(texfile (concat texfilebase ".tex"))
(image-size-adjust (or (plist-get processing-info :image-size-adjust)
'(1.0 . 1.0)))
(scale (* (if buffer (car image-size-adjust) (cdr image-size-adjust))
(or (plist-get options (if buffer :scale :html-scale)) 1.0)))
(dpi (* scale (if (and buffer (display-graphic-p)) (org--get-display-dpi) 140.0)))
(fg (or (plist-get options (if buffer :foreground :html-foreground))
"Black"))
(bg (or (plist-get options (if buffer :background :html-background))
"Transparent"))
(image-converter
(or (and (string= bg "Transparent")
(plist-get processing-info :transparent-image-converter))
(plist-get processing-info :image-converter)))
(log-buf (get-buffer-create "*Org Preview LaTeX Output*"))
(resize-mini-windows nil)) ;Fix Emacs flicker when creating image.
(dolist (program programs)
(org-check-external-command program error-message))
(if (eq fg 'default)
(setq fg (org-latex-color :foreground))
(setq fg (org-latex-color-format fg)))
(setq bg (cond
((eq bg 'default) (org-latex-color :background))
((string= bg "Transparent") nil)
(t (org-latex-color-format bg))))
;; Remove TeX \par at end of snippet to avoid trailing space.
(if (string-suffix-p string "\n")
(aset string (1- (length string)) ?%)
(setq string (concat string "%")))
(with-temp-file texfile
(insert latex-header)
(insert "\n\\begin{document}\n"
"\\definecolor{fg}{rgb}{" fg "}%\n"
(if bg
(concat "\\definecolor{bg}{rgb}{" bg "}%\n"
"\n\\pagecolor{bg}%\n")
"")
"\n{\\color{fg}\n"
string
"\n}\n"
"\n\\end{document}\n"))
(let* ((err-msg (format "Please adjust `%s' part of \
`org-preview-latex-process-alist'."
processing-type))
(image-input-file
(org-compile-file
texfile latex-compiler image-input-type err-msg log-buf))
(image-output-file
(org-compile-file
image-input-file image-converter image-output-type err-msg log-buf
`((?D . ,(shell-quote-argument (format "%s" dpi)))
(?S . ,(shell-quote-argument (format "%s" (/ dpi 140.0))))))))
(copy-file image-output-file tofile 'replace)
(dolist (e post-clean)
(when (file-exists-p (concat texfilebase e))
(delete-file (concat texfilebase e))))
image-output-file)))
(defun org-dvipng-color (attr)
"Return a RGB color specification for dvipng."
(org-dvipng-color-format (face-attribute 'default attr nil)))
(defun org-dvipng-color-format (color-name)
"Convert COLOR-NAME to a RGB color value for dvipng."
(apply #'format "rgb %s %s %s"
(mapcar 'org-normalize-color
(color-values color-name))))
(defun org-latex-color (attr)
"Return a RGB color for the LaTeX color package."
(org-latex-color-format (face-attribute 'default attr nil)))
(defun org-latex-color-format (color-name)
"Convert COLOR-NAME to a RGB color value."
(apply #'format "%s,%s,%s"
(mapcar 'org-normalize-color
(color-values color-name))))
(defun org-normalize-color (value)
"Return string to be used as color value for an RGB component."
(format "%g" (/ value 65535.0)))
(provide 'org-latex-preview)
;;; org-latex-preview.el ends here

View File

@ -3209,244 +3209,6 @@ A nil value means to remove them, after a query, from the list."
:group 'org-agenda
:type 'boolean)
(defgroup org-latex nil
"Options for embedding LaTeX code into Org mode."
:tag "Org LaTeX"
:group 'org)
(defcustom org-format-latex-options
'(:foreground default :background default :scale 1.0
:html-foreground "Black" :html-background "Transparent"
:html-scale 1.0 :matchers ("begin" "$1" "$" "$$" "\\(" "\\["))
"Options for creating images from LaTeX fragments.
This is a property list with the following properties:
:foreground the foreground color for images embedded in Emacs, e.g. \"Black\".
`default' means use the foreground of the default face.
`auto' means use the foreground from the text face.
:background the background color, or \"Transparent\".
`default' means use the background of the default face.
`auto' means use the background from the text face.
:scale a scaling factor for the size of the images, to get more pixels
:html-foreground, :html-background, :html-scale
the same numbers for HTML export.
:matchers a list indicating which matchers should be used to
find LaTeX fragments. Valid members of this list are:
\"begin\" find environments
\"$1\" find single characters surrounded by $.$
\"$\" find math expressions surrounded by $...$
\"$$\" find math expressions surrounded by $$....$$
\"\\(\" find math expressions surrounded by \\(...\\)
\"\\=\\[\" find math expressions surrounded by \\=\\[...\\]"
:group 'org-latex
:type 'plist)
(defcustom org-format-latex-signal-error t
"Non-nil means signal an error when image creation of LaTeX snippets fails.
When nil, just push out a message."
:group 'org-latex
:version "24.1"
:type 'boolean)
(defcustom org-latex-to-mathml-jar-file nil
"Value of\"%j\" in `org-latex-to-mathml-convert-command'.
Use this to specify additional executable file say a jar file.
When using MathToWeb as the converter, specify the full-path to
your mathtoweb.jar file."
:group 'org-latex
:version "24.1"
:type '(choice
(const :tag "None" nil)
(file :tag "JAR file" :must-match t)))
(defcustom org-latex-to-mathml-convert-command nil
"Command to convert LaTeX fragments to MathML.
Replace format-specifiers in the command as noted below and use
`shell-command' to convert LaTeX to MathML.
%j: Executable file in fully expanded form as specified by
`org-latex-to-mathml-jar-file'.
%I: Input LaTeX file in fully expanded form.
%i: Shell-escaped LaTeX fragment to be converted.
It must not be used inside a quoted argument, the result of %i
expansion inside a quoted argument is undefined.
%o: Output MathML file.
This command is used by `org-create-math-formula'.
When using MathToWeb as the converter, set this option to
\"java -jar %j -unicode -force -df %o %I\".
When using LaTeXML set this option to
\"latexmlmath %i --presentationmathml=%o\"."
:group 'org-latex
:version "24.1"
:type '(choice
(const :tag "None" nil)
(string :tag "\nShell command")))
(defcustom org-latex-to-html-convert-command nil
"Shell command to convert LaTeX fragments to HTML.
This command is very open-ended: the output of the command will
directly replace the LaTeX fragment in the resulting HTML.
Replace format-specifiers in the command as noted below and use
`shell-command' to convert LaTeX to HTML.
%i: The LaTeX fragment to be converted (shell-escaped).
It must not be used inside a quoted argument, the result of %i
expansion inside a quoted argument is undefined.
For example, this could be used with LaTeXML as
\"latexmlc literal:%i --profile=math --preload=siunitx.sty 2>/dev/null\"."
:group 'org-latex
:package-version '(Org . "9.4")
:type '(choice
(const :tag "None" nil)
(string :tag "Shell command")))
(defcustom org-preview-latex-default-process 'dvipng
"The default process to convert LaTeX fragments to image files.
All available processes and theirs documents can be found in
`org-preview-latex-process-alist', which see."
:group 'org-latex
:version "26.1"
:package-version '(Org . "9.0")
:type 'symbol)
(defcustom org-preview-latex-process-alist
'((dvipng
:programs ("latex" "dvipng")
:description "dvi > png"
:message "you need to install the programs: latex and dvipng."
:image-input-type "dvi"
:image-output-type "png"
:image-size-adjust (1.0 . 1.0)
:latex-compiler ("latex -interaction nonstopmode -output-directory %o %f")
:image-converter ("dvipng -D %D -T tight -o %O %f")
:transparent-image-converter
("dvipng -D %D -T tight -bg Transparent -o %O %f"))
(dvisvgm
:programs ("latex" "dvisvgm")
:description "dvi > svg"
:message "you need to install the programs: latex and dvisvgm."
:image-input-type "dvi"
:image-output-type "svg"
:image-size-adjust (1.7 . 1.5)
:latex-compiler ("latex -interaction nonstopmode -output-directory %o %f")
:image-converter ("dvisvgm %f --no-fonts --exact-bbox --scale=%S --output=%O"))
(imagemagick
:programs ("latex" "convert")
:description "pdf > png"
:message "you need to install the programs: latex and imagemagick."
:image-input-type "pdf"
:image-output-type "png"
:image-size-adjust (1.0 . 1.0)
:latex-compiler ("pdflatex -interaction nonstopmode -output-directory %o %f")
:image-converter
("convert -density %D -trim -antialias %f -quality 100 %O")))
"Definitions of external processes for LaTeX previewing.
Org mode can use some external commands to generate TeX snippet's images for
previewing or inserting into HTML files, e.g., \"dvipng\". This variable tells
`org-create-formula-image' how to call them.
The value is an alist with the pattern (NAME . PROPERTIES). NAME is a symbol.
PROPERTIES accepts the following attributes:
:programs list of strings, required programs.
:description string, describe the process.
:message string, message it when required programs cannot be found.
:image-input-type string, input file type of image converter (e.g., \"dvi\").
:image-output-type string, output file type of image converter (e.g., \"png\").
:image-size-adjust cons of numbers, the car element is used to adjust LaTeX
image size showed in buffer and the cdr element is for
HTML file. This option is only useful for process
developers, users should use variable
`org-format-latex-options' instead.
:post-clean list of strings, files matched are to be cleaned up once
the image is generated. When nil, the files with \".dvi\",
\".xdv\", \".pdf\", \".tex\", \".aux\", \".log\", \".svg\",
\".png\", \".jpg\", \".jpeg\" or \".out\" extension will
be cleaned up.
:latex-header list of strings, the LaTeX header of the snippet file.
When nil, the fallback value is used instead, which is
controlled by `org-format-latex-header',
`org-latex-default-packages-alist' and
`org-latex-packages-alist', which see.
:latex-compiler list of LaTeX commands, as strings. Each of them is given
to the shell. Place-holders \"%t\", \"%b\" and \"%o\" are
replaced with values defined below.
:image-converter list of image converter commands strings. Each of them is
given to the shell and supports any of the following
place-holders defined below.
If set, :transparent-image-converter is used instead of :image-converter to
convert an image when the background color is nil or \"Transparent\".
Place-holders used by `:image-converter' and `:latex-compiler':
%f input file name
%b base name of input file
%o base directory of input file
%O absolute output file name
Place-holders only used by `:image-converter':
%D dpi, which is used to adjust image size by some processing commands.
%S the image size scale ratio, which is used to adjust image size by some
processing commands."
:group 'org-latex
:package-version '(Org . "9.6")
:type '(alist :tag "LaTeX to image backends"
:value-type (plist)))
(defcustom org-preview-latex-image-directory "ltximg/"
"Path to store latex preview images.
A relative path here creates many directories relative to the
processed Org files paths. An absolute path puts all preview
images at the same place."
:group 'org-latex
:version "26.1"
:package-version '(Org . "9.0")
:type 'string)
(defun org-format-latex-mathml-available-p ()
"Return t if `org-latex-to-mathml-convert-command' is usable."
(save-match-data
(when (and (boundp 'org-latex-to-mathml-convert-command)
org-latex-to-mathml-convert-command)
(let ((executable (car (split-string
org-latex-to-mathml-convert-command))))
(when (executable-find executable)
(if (string-match
"%j" org-latex-to-mathml-convert-command)
(file-readable-p org-latex-to-mathml-jar-file)
t))))))
(defcustom org-format-latex-header "\\documentclass{article}
\\usepackage[usenames]{color}
\[DEFAULT-PACKAGES]
\[PACKAGES]
\\pagestyle{empty} % do not remove
% The settings below are copied from fullpage.sty
\\setlength{\\textwidth}{\\paperwidth}
\\addtolength{\\textwidth}{-3cm}
\\setlength{\\oddsidemargin}{1.5cm}
\\addtolength{\\oddsidemargin}{-2.54cm}
\\setlength{\\evensidemargin}{\\oddsidemargin}
\\setlength{\\textheight}{\\paperheight}
\\addtolength{\\textheight}{-\\headheight}
\\addtolength{\\textheight}{-\\headsep}
\\addtolength{\\textheight}{-\\footskip}
\\addtolength{\\textheight}{-3cm}
\\setlength{\\topmargin}{1.5cm}
\\addtolength{\\topmargin}{-2.54cm}"
"The document header used for processing LaTeX fragments.
It is imperative that this header make sure that no page number
appears on the page. The package defined in the variables
`org-latex-default-packages-alist' and `org-latex-packages-alist'
will either replace the placeholder \"[PACKAGES]\" in this
header, or they will be appended."
:group 'org-latex
:type 'string)
(defun org-set-packages-alist (var val)
"Set the packages alist and make sure it has 3 elements per entry."
(set-default-toplevel-value var (mapcar (lambda (x)
@ -16046,6 +15808,8 @@ environment remains unintended."
;;;; LaTeX fragments
(require 'org-latex-preview)
(defun org-inside-LaTeX-fragment-p (&optional element)
"Test if point is inside a LaTeX fragment or environment.
@ -16061,466 +15825,6 @@ at point."
(org-in-regexp
"\\\\[a-zA-Z]+\\*?\\(\\(\\[[^][\n{}]*\\]\\)\\|\\({[^{}\n]*}\\)\\)*")))
(defun org--make-preview-overlay (beg end image &optional imagetype)
"Build an overlay between BEG and END using IMAGE file.
Argument IMAGETYPE is the extension of the displayed image,
as a string. It defaults to \"png\"."
(let ((ov (make-overlay beg end))
(imagetype (or (intern imagetype) 'png)))
(overlay-put ov 'org-overlay-type 'org-latex-overlay)
(overlay-put ov 'evaporate t)
(overlay-put ov
'modification-hooks
(list (lambda (o _flag _beg _end &optional _l)
(delete-overlay o))))
(overlay-put ov
'display
(list 'image :type imagetype :file image :ascent 'center))))
(defun org-clear-latex-preview (&optional beg end)
"Remove all overlays with LaTeX fragment images in current buffer.
When optional arguments BEG and END are non-nil, remove all
overlays between them instead. Return a non-nil value when some
overlays were removed, nil otherwise."
(let ((overlays
(cl-remove-if-not
(lambda (o) (eq (overlay-get o 'org-overlay-type) 'org-latex-overlay))
(overlays-in (or beg (point-min)) (or end (point-max))))))
(mapc #'delete-overlay overlays)
overlays))
(defun org--latex-preview-region (beg end)
"Preview LaTeX fragments between BEG and END.
BEG and END are buffer positions."
(let ((file (buffer-file-name (buffer-base-buffer))))
(save-excursion
(org-format-latex
(concat org-preview-latex-image-directory "org-ltximg")
beg end
;; Emacs cannot overlay images from remote hosts. Create it in
;; `temporary-file-directory' instead.
(if (or (not file) (file-remote-p file))
temporary-file-directory
default-directory)
'overlays nil 'forbuffer org-preview-latex-default-process))))
(defun org-latex-preview (&optional arg)
"Toggle preview of the LaTeX fragment at point.
If the cursor is on a LaTeX fragment, create the image and
overlay it over the source code, if there is none. Remove it
otherwise. If there is no fragment at point, display images for
all fragments in the current section. With an active region,
display images for all fragments in the region.
With a `\\[universal-argument]' prefix argument ARG, clear images \
for all fragments
in the current section.
With a `\\[universal-argument] \\[universal-argument]' prefix \
argument ARG, display image for all
fragments in the buffer.
With a `\\[universal-argument] \\[universal-argument] \
\\[universal-argument]' prefix argument ARG, clear image for all
fragments in the buffer."
(interactive "P")
(cond
((not (display-graphic-p)) nil)
((and untrusted-content (not org--latex-preview-when-risky)) nil)
;; Clear whole buffer.
((equal arg '(64))
(org-clear-latex-preview (point-min) (point-max))
(message "LaTeX previews removed from buffer"))
;; Preview whole buffer.
((equal arg '(16))
(message "Creating LaTeX previews in buffer...")
(org--latex-preview-region (point-min) (point-max))
(message "Creating LaTeX previews in buffer... done."))
;; Clear current section.
((equal arg '(4))
(org-clear-latex-preview
(if (use-region-p)
(region-beginning)
(if (org-before-first-heading-p) (point-min)
(save-excursion
(org-with-limited-levels (org-back-to-heading t) (point)))))
(if (use-region-p)
(region-end)
(org-with-limited-levels (org-entry-end-position)))))
((use-region-p)
(message "Creating LaTeX previews in region...")
(org--latex-preview-region (region-beginning) (region-end))
(message "Creating LaTeX previews in region... done."))
;; Toggle preview on LaTeX code at point.
((let ((datum (org-element-context)))
(and (org-element-type-p datum '(latex-environment latex-fragment))
(let ((beg (org-element-begin datum))
(end (org-element-end datum)))
(if (org-clear-latex-preview beg end)
(message "LaTeX preview removed")
(message "Creating LaTeX preview...")
(org--latex-preview-region beg end)
(message "Creating LaTeX preview... done."))
t))))
;; Preview current section.
(t
(let ((beg (if (org-before-first-heading-p) (point-min)
(save-excursion
(org-with-limited-levels (org-back-to-heading t) (point)))))
(end (org-with-limited-levels (org-entry-end-position))))
(message "Creating LaTeX previews in section...")
(org--latex-preview-region beg end)
(message "Creating LaTeX previews in section... done.")))))
(defun org-format-latex
(prefix &optional beg end dir overlays msg forbuffer processing-type)
"Replace LaTeX fragments with links to an image.
The function takes care of creating the replacement image.
Only consider fragments between BEG and END when those are
provided.
When optional argument OVERLAYS is non-nil, display the image on
top of the fragment instead of replacing it.
PROCESSING-TYPE is the conversion method to use, as a symbol.
Some of the options can be changed using the variable
`org-format-latex-options', which see."
(when (and overlays (fboundp 'clear-image-cache)) (clear-image-cache))
(unless (eq processing-type 'verbatim)
(let* ((math-regexp "\\$\\|\\\\[([]\\|^[ \t]*\\\\begin{[A-Za-z0-9*]+}")
(cnt 0)
checkdir-flag)
(goto-char (or beg (point-min)))
;; FIXME: `overlay-recenter' is not needed (and has no effect)
;; since Emacs 29.
;; Optimize overlay creation: (info "(elisp) Managing Overlays").
(when (and overlays (memq processing-type '(dvipng imagemagick)))
(overlay-recenter (or end (point-max))))
(while (re-search-forward math-regexp end t)
(unless (and overlays
(eq (get-char-property (point) 'org-overlay-type)
'org-latex-overlay))
(let* ((context (org-element-context))
(type (org-element-type context)))
(when (memq type '(latex-environment latex-fragment))
(let ((block-type (eq type 'latex-environment))
(value (org-element-property :value context))
(beg (org-element-begin context))
(end (save-excursion
(goto-char (org-element-end context))
(skip-chars-backward " \r\t\n")
(point))))
(cond
((eq processing-type 'mathjax)
;; Prepare for MathJax processing.
(if (not (string-match "\\`\\$\\$?" value))
(goto-char end)
(delete-region beg end)
(if (string= (match-string 0 value) "$$")
(insert "\\[" (substring value 2 -2) "\\]")
(insert "\\(" (substring value 1 -1) "\\)"))))
((eq processing-type 'html)
(goto-char beg)
(delete-region beg end)
(insert (org-format-latex-as-html value)))
((assq processing-type org-preview-latex-process-alist)
;; Process to an image.
(cl-incf cnt)
(goto-char beg)
(let* ((processing-info
(cdr (assq processing-type org-preview-latex-process-alist)))
(face (face-at-point))
;; Get the colors from the face at point.
(fg
(let ((color (plist-get org-format-latex-options
:foreground)))
(if forbuffer
(cond
((eq color 'auto)
(face-attribute face :foreground nil 'default))
((eq color 'default)
(face-attribute 'default :foreground nil))
(t color))
color)))
(bg
(let ((color (plist-get org-format-latex-options
:background)))
(if forbuffer
(cond
((eq color 'auto)
(face-attribute face :background nil 'default))
((eq color 'default)
(face-attribute 'default :background nil))
(t color))
color)))
(hash (sha1 (prin1-to-string
(list org-format-latex-header
org-latex-default-packages-alist
org-latex-packages-alist
org-format-latex-options
forbuffer value fg bg))))
(imagetype (or (plist-get processing-info :image-output-type) "png"))
(absprefix (expand-file-name prefix dir))
(linkfile (format "%s_%s.%s" prefix hash imagetype))
(movefile (format "%s_%s.%s" absprefix hash imagetype))
(sep (and block-type "\n\n"))
(link (concat sep "[[file:" linkfile "]]" sep))
(options
(org-combine-plists
org-format-latex-options
`(:foreground ,fg :background ,bg))))
(when msg (message msg cnt))
(unless checkdir-flag ; Ensure the directory exists.
(setq checkdir-flag t)
(let ((todir (file-name-directory absprefix)))
(unless (file-directory-p todir)
(make-directory todir t))))
(unless (file-exists-p movefile)
(org-create-formula-image
value movefile options forbuffer processing-type))
(org-place-formula-image link block-type beg end value overlays movefile imagetype)))
((eq processing-type 'mathml)
;; Process to MathML.
(unless (org-format-latex-mathml-available-p)
(user-error "LaTeX to MathML converter not configured"))
(cl-incf cnt)
(when msg (message msg cnt))
(goto-char beg)
(delete-region beg end)
(insert (org-format-latex-as-mathml
value block-type prefix dir)))
(t
(error "Unknown conversion process %s for LaTeX fragments"
processing-type)))))))))))
(defun org-place-formula-image (link block-type beg end value overlays movefile imagetype)
"Place an overlay from BEG to END showing MOVEFILE.
The overlay will be above BEG if OVERLAYS is non-nil."
(if overlays
(progn
(dolist (o (overlays-in beg end))
(when (eq (overlay-get o 'org-overlay-type)
'org-latex-overlay)
(delete-overlay o)))
(org--make-preview-overlay beg end movefile imagetype)
(goto-char end))
(delete-region beg end)
(insert
(org-add-props link
(list 'org-latex-src
(replace-regexp-in-string "\"" "" value)
'org-latex-src-embed-type
(if block-type 'paragraph 'character))))))
(defun org-create-math-formula (latex-frag &optional mathml-file)
"Convert LATEX-FRAG to MathML and store it in MATHML-FILE.
Use `org-latex-to-mathml-convert-command'. If the conversion is
successful, return the portion between \"<math...> </math>\"
elements otherwise return nil. When MATHML-FILE is specified,
write the results in to that file. When invoked as an
interactive command, prompt for LATEX-FRAG, with initial value
set to the current active region and echo the results for user
inspection."
(interactive (list (let ((frag (when (org-region-active-p)
(buffer-substring-no-properties
(region-beginning) (region-end)))))
(read-string "LaTeX Fragment: " frag nil frag))))
(unless latex-frag (user-error "Invalid LaTeX fragment"))
(let* ((tmp-in-file
(let ((file (file-relative-name
(make-temp-name (expand-file-name "ltxmathml-in")))))
(write-region latex-frag nil file)
file))
(tmp-out-file (file-relative-name
(make-temp-name (expand-file-name "ltxmathml-out"))))
(cmd (format-spec
org-latex-to-mathml-convert-command
`((?j . ,(and org-latex-to-mathml-jar-file
(shell-quote-argument
(expand-file-name
org-latex-to-mathml-jar-file))))
(?I . ,(shell-quote-argument tmp-in-file))
(?i . ,(shell-quote-argument latex-frag))
(?o . ,(shell-quote-argument tmp-out-file)))))
mathml shell-command-output)
(when (called-interactively-p 'any)
(unless (org-format-latex-mathml-available-p)
(user-error "LaTeX to MathML converter not configured")))
(message "Running %s" cmd)
(setq shell-command-output (shell-command-to-string cmd))
(setq mathml
(when (file-readable-p tmp-out-file)
(with-temp-buffer
(insert-file-contents tmp-out-file)
(goto-char (point-min))
(when (re-search-forward
(format "<math[^>]*?%s[^>]*?>\\(.\\|\n\\)*</math>"
(regexp-quote
"xmlns=\"http://www.w3.org/1998/Math/MathML\""))
nil t)
(match-string 0)))))
(cond
(mathml
(setq mathml
(concat "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" mathml))
(when mathml-file
(write-region mathml nil mathml-file))
(when (called-interactively-p 'any)
(message mathml)))
((warn "LaTeX to MathML conversion failed")
(message shell-command-output)))
(delete-file tmp-in-file)
(when (file-exists-p tmp-out-file)
(delete-file tmp-out-file))
mathml))
(defun org-format-latex-as-mathml (latex-frag latex-frag-type
prefix &optional dir)
"Use `org-create-math-formula' but check local cache first."
(let* ((absprefix (expand-file-name prefix dir))
(print-length nil) (print-level nil)
(formula-id (concat
"formula-"
(sha1
(prin1-to-string
(list latex-frag
org-latex-to-mathml-convert-command)))))
(formula-cache (format "%s-%s.mathml" absprefix formula-id))
(formula-cache-dir (file-name-directory formula-cache)))
(unless (file-directory-p formula-cache-dir)
(make-directory formula-cache-dir t))
(unless (file-exists-p formula-cache)
(org-create-math-formula latex-frag formula-cache))
(if (file-exists-p formula-cache)
;; Successful conversion. Return the link to MathML file.
(org-add-props
(format "[[file:%s]]" (file-relative-name formula-cache dir))
(list 'org-latex-src (replace-regexp-in-string "\"" "" latex-frag)
'org-latex-src-embed-type (if latex-frag-type
'paragraph 'character)))
;; Failed conversion. Return the LaTeX fragment verbatim
latex-frag)))
(defun org-format-latex-as-html (latex-fragment)
"Convert LATEX-FRAGMENT to HTML.
This uses `org-latex-to-html-convert-command', which see."
(let ((cmd (format-spec org-latex-to-html-convert-command
`((?i . ,(shell-quote-argument latex-fragment))))))
(message "Running %s" cmd)
(shell-command-to-string cmd)))
(defun org--get-display-dpi ()
"Get the DPI of the display.
The function assumes that the display has the same pixel width in
the horizontal and vertical directions."
(if (display-graphic-p)
(round (/ (display-pixel-height)
(/ (display-mm-height) 25.4)))
(error "Attempt to calculate the dpi of a non-graphic display")))
(defun org-create-formula-image
(string tofile options buffer &optional processing-type)
"Create an image from LaTeX source using external processes.
The LaTeX STRING is saved to a temporary LaTeX file, then
converted to an image file by process PROCESSING-TYPE defined in
`org-preview-latex-process-alist'. A nil value defaults to
`org-preview-latex-default-process'.
The generated image file is eventually moved to TOFILE.
The OPTIONS argument controls the size, foreground color and
background color of the generated image.
When BUFFER non-nil, this function is used for LaTeX previewing.
Otherwise, it is used to deal with LaTeX snippets showed in
a HTML file."
(let* ((processing-type (or processing-type
org-preview-latex-default-process))
(processing-info
(cdr (assq processing-type org-preview-latex-process-alist)))
(programs (plist-get processing-info :programs))
(error-message (or (plist-get processing-info :message) ""))
(image-input-type (plist-get processing-info :image-input-type))
(image-output-type (plist-get processing-info :image-output-type))
(post-clean (or (plist-get processing-info :post-clean)
'(".dvi" ".xdv" ".pdf" ".tex" ".aux" ".log"
".svg" ".png" ".jpg" ".jpeg" ".out")))
(latex-header
(or (plist-get processing-info :latex-header)
(org-latex-make-preamble
(org-export-get-environment (org-export-get-backend 'latex))
org-format-latex-header
'snippet)))
(latex-compiler (plist-get processing-info :latex-compiler))
(tmpdir temporary-file-directory)
(texfilebase (make-temp-name
(expand-file-name "orgtex" tmpdir)))
(texfile (concat texfilebase ".tex"))
(image-size-adjust (or (plist-get processing-info :image-size-adjust)
'(1.0 . 1.0)))
(scale (* (if buffer (car image-size-adjust) (cdr image-size-adjust))
(or (plist-get options (if buffer :scale :html-scale)) 1.0)))
(dpi (* scale (if (and buffer (display-graphic-p)) (org--get-display-dpi) 140.0)))
(fg (or (plist-get options (if buffer :foreground :html-foreground))
"Black"))
(bg (or (plist-get options (if buffer :background :html-background))
"Transparent"))
(image-converter
(or (and (string= bg "Transparent")
(plist-get processing-info :transparent-image-converter))
(plist-get processing-info :image-converter)))
(log-buf (get-buffer-create "*Org Preview LaTeX Output*"))
(resize-mini-windows nil)) ;Fix Emacs flicker when creating image.
(dolist (program programs)
(org-check-external-command program error-message))
(if (eq fg 'default)
(setq fg (org-latex-color :foreground))
(setq fg (org-latex-color-format fg)))
(setq bg (cond
((eq bg 'default) (org-latex-color :background))
((string= bg "Transparent") nil)
(t (org-latex-color-format bg))))
;; Remove TeX \par at end of snippet to avoid trailing space.
(if (string-suffix-p string "\n")
(aset string (1- (length string)) ?%)
(setq string (concat string "%")))
(with-temp-file texfile
(insert latex-header)
(insert "\n\\begin{document}\n"
"\\definecolor{fg}{rgb}{" fg "}%\n"
(if bg
(concat "\\definecolor{bg}{rgb}{" bg "}%\n"
"\n\\pagecolor{bg}%\n")
"")
"\n{\\color{fg}\n"
string
"\n}\n"
"\n\\end{document}\n"))
(let* ((err-msg (format "Please adjust `%s' part of \
`org-preview-latex-process-alist'."
processing-type))
(image-input-file
(org-compile-file
texfile latex-compiler image-input-type err-msg log-buf))
(image-output-file
(org-compile-file
image-input-file image-converter image-output-type err-msg log-buf
`((?D . ,(shell-quote-argument (format "%s" dpi)))
(?S . ,(shell-quote-argument (format "%s" (/ dpi 140.0))))))))
(copy-file image-output-file tofile 'replace)
(dolist (e post-clean)
(when (file-exists-p (concat texfilebase e))
(delete-file (concat texfilebase e))))
image-output-file)))
(defun org-splice-latex-header (tpl def-pkg pkg snippets-p &optional extra)
"Fill a LaTeX header template TPL.
In the template, the following place holders will be recognized:
@ -16580,30 +15884,6 @@ SNIPPETS-P indicates if this is run to create snippet images for HTML."
"\n"))
(if newline (concat pkg "\n") pkg))
(defun org-dvipng-color (attr)
"Return a RGB color specification for dvipng."
(org-dvipng-color-format (face-attribute 'default attr nil)))
(defun org-dvipng-color-format (color-name)
"Convert COLOR-NAME to a RGB color value for dvipng."
(apply #'format "rgb %s %s %s"
(mapcar 'org-normalize-color
(color-values color-name))))
(defun org-latex-color (attr)
"Return a RGB color for the LaTeX color package."
(org-latex-color-format (face-attribute 'default attr nil)))
(defun org-latex-color-format (color-name)
"Convert COLOR-NAME to a RGB color value."
(apply #'format "%s,%s,%s"
(mapcar 'org-normalize-color
(color-values color-name))))
(defun org-normalize-color (value)
"Return string to be used as color value for an RGB component."
(format "%g" (/ value 65535.0)))
;; Image display