diff --git a/lisp/org-latex-preview.el b/lisp/org-latex-preview.el
new file mode 100644
index 000000000..98746d289
--- /dev/null
+++ b/lisp/org-latex-preview.el
@@ -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 .
+
+;;; 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 \" \"
+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 ""
+ (regexp-quote
+ "xmlns=\"http://www.w3.org/1998/Math/MathML\""))
+ nil t)
+ (prog1 (match-string 0) (kill-buffer))))))
+ (cond
+ (mathml
+ (setq mathml
+ (concat "\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
diff --git a/lisp/org.el b/lisp/org.el
index 98034f0ed..3404cd48a 100644
--- a/lisp/org.el
+++ b/lisp/org.el
@@ -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 \" \"
-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 ""
- (regexp-quote
- "xmlns=\"http://www.w3.org/1998/Math/MathML\""))
- nil t)
- (match-string 0)))))
- (cond
- (mathml
- (setq mathml
- (concat "\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