Org: make LaTeX conditional preamble a bit fancier

Introduced to org-latex-feature-implementations in this commit:
+ :when keyword
+ :prevents keyword
+ special treatment of features starting with !

No more universal preamble.

Moved all latex template content other than font into preamble features.

Added xkcd feature implications.

Refactored org-latex-generate-features-preamble.

Update org-latex-clever-preamble graphic to better illustrate the
functionality.
This commit is contained in:
TEC 2021-03-26 01:59:48 +08:00
parent e2c55369b6
commit 55212eae28
Signed by: tec
GPG Key ID: 779591AFDB81F06C
2 changed files with 265 additions and 126 deletions

View File

@ -7122,9 +7122,11 @@ The =hyperref= setup needs to be handled separately however.
**** A cleverer preamble
***** Use case
We always want some particular elements in the preamble, let's call this
the "universal preamble"
#+name: org-latex-universal-preamble
We often want particular snippets of LaTeX in our documents preambles.
It's a pain to have to work out / remember them every time.
For example, I almost always want to include the snippet below.
#+name: org-latex-embed-files-preamble
#+begin_src LaTeX
\\usepackage[main,include]{embedall}
\\IfFileExists{./\\jobname.org}{\\embedfile[desc=The original file]{\\jobname.org}}{}
@ -7134,13 +7136,21 @@ We could have every package we could possibly need in every one of
~org-latex-classes~, but that's /horribly/ inefficient and I don't want to think
about maintaining that.
Instead, we can have a "universal preamble" which contains a snippet which we
want to /always/ appear, and then conditional preamble snippets, which are only
included when a certain regex is successfully found in the Org buffer.
Instead we can provide some granularity by splitting up the features we want,
and then take the experience to a whole new level by implementing a system to
automatically detect which features are desired and generating a preamble that
provides these features.
***** Conditional Content
Let's consider some other content we only want in certain situations.
Let's consider content we want in particular situations.
Captions could do with a bit of tweaking such that
+ You can easily have multiple captions
+ Links to figures take you to the /top/ of the figure (not the bottom)
+ Caption labels could do with being emphasised slightly more
+ Multiline captions should run ragged-right, but only when then span more than
one line
#+name: org-latex-caption-preamble
#+begin_src LaTeX
@ -7149,10 +7159,11 @@ Let's consider some other content we only want in certain situations.
\\setkomafont{caption}{\\sffamily\\small}
\\setkomafont{captionlabel}{\\upshape\\bfseries}
\\captionsetup{justification=raggedright,singlelinecheck=true}
\\setcapindent{0pt}
\\usepackage{capt-of} % required by Org
#+end_src
The default checkboxes look rather ugly, so let's provide some prettier alternatives.
#+name: org-latex-checkbox-preamble
#+begin_src LaTeX
\\newcommand{\\checkboxUnchecked}{$\\square$}
@ -7160,6 +7171,9 @@ Let's consider some other content we only want in certain situations.
\\newcommand{\\checkboxChecked}{\\rlap{\\raisebox{0.2ex}{\\hspace{0.35ex}\\scriptsize \\ding{52}}}$\\square$}
#+end_src
It's nice to have "message blocks", things like info/warning/error/success.
A LaTeX macro should make them trivial to create.
#+name: org-latex-box-preamble
#+begin_src LaTeX
% args = #1 Name, #2 Colour, #3 Ding, #4 Label
@ -7182,25 +7196,25 @@ Lastly, we will pass this content into some global variables we for ease of
access.
#+begin_src emacs-lisp :noweb no-export
(defvar org-latex-universal-preamble "
<<org-latex-universal-preamble>>
(defvar org-latex-embed-files-preamble "
<<org-latex-embed-files-preamble>>
"
"Preamble to be included in every export.")
"Preamble that embeds files within the pdf.")
(defvar org-latex-caption-preamble "
<<org-latex-caption-preamble>>
"
"Preamble to be included to improve captions.")
"Preamble that improves captions.")
(defvar org-latex-checkbox-preamble "
<<org-latex-checkbox-preamble>>
"
"Preamble to be included to improve checkboxes.")
"Preamble that improves checkboxes.")
(defvar org-latex-box-preamble "
<<org-latex-box-preamble>>
"
"Preamble to be included to improve boxes.")
"Preamble that provides a macro for custom boxes.")
#+end_src
In the "universal preamble", we already embed the source =.org= file, but it would
@ -7277,34 +7291,52 @@ implementation of feature dependency.
digraph {
graph [bgcolor="transparent"];
node [shape="underline" penwidth="2" width="1.3" style="rounded,filled" fillcolor="#efefef" color="#c9c9c9" fontcolor="#000000" fontname="overpass"];
edge [arrowhead=none color="#aaaaaa" penwidth="1.2"]
edge [color="#aaaaaa" penwidth="1.2"]
rankdir=LR
"Checkboxes" [color="#2ec27e"]
"Fancy blocks" [color="#2ec27e"]
"Images" [color="#2ec27e"]
"Dingbats" [color="#f5c211"]
"Graphics" [color="#f5c211"]
"pifont" [color="#813d9c"]
"graphicx" [color="#813d9c"]
node[group=a,color="#2ec27e"]
"file:*.jpeg"
"file:*.png"
"file:*.svg"
"#+caption"
"xkcd:*"
node[group=b,color="#f5c211"]
"image"
"svg"
"caption"
node[group=c,color="#813d9c"]
"(TeX) graphicx"
"(TeX) svg"
"(TeX) caption"
"Checkboxes" -> "Dingbats" -> "pifont"
"Fancy blocks" -> "Dingbats"
"Images" -> "Graphics" -> "graphicx"
"file:*.jpeg" -> "image" -> "(TeX) graphicx"
"file:*.png" -> "image"
"file:*.svg" -> "svg" -> "(TeX) svg"
"(TeX) svg":e -> "(TeX) graphicx":s [constraint=false]
"#+caption" -> "caption" -> "(TeX) caption"
"xkcd:*" -> "image"
"xkcd:*" -> "caption"
}
#+end_src
#+caption: Association between Org features, feature flags, and LaTeX snippets required.
#+attr_html: :class invertible :alt Graph of possible Emacs task integrations :style max-width:min(24em,100%)
#+attr_html: :class invertible :alt DAG showing how Org features flow through to LaTeX :style max-width:min(24em,100%)
#+attr_latex: :width 0.6\linewidth
[[file:misc/org-latex-clever-preamble.svg]]
#+begin_src emacs-lisp
(defvar org-latex-embed-files t
"Embed the source .org, .tex, and any tangled files.")
(defvar org-latex-use-microtype t
"Use the microtype pakage.")
(defvar org-latex-italic-quotes t
"Make \"quote\" environments italic.")
(defvar org-latex-par-sep t
"Vertically seperate paragraphs, and remove indentation.")
(defvar org-latex-conditional-features
'((t . universal)
("^[ \t]*#\\+begin_src\\|^[ \t]*#\\+BEGIN_SRC" . embed-tangled)
'(("\\[\\[file:\\(?:[^]]\\|\\\\\\]\\)+?\\.\\(?:eps\\|pdf\\|png\\|jpeg\\|jpg\\|jbig2\\)\\]\\]" . image)
("\\[\\[file:\\(?:[^]]+?\\|\\\\\\]\\)\\.svg\\]\\]" . svg)
("\\[\\[file:\\(?:[^]]\\|\\\\\\]\\)+?\\.\\(?:eps\\|pdf\\|png\\|jpeg\\|jpg\\|jbig2\\)\\]\\]" . image)
("\\\\(\\|\\\\\\[\\|\\\\begin{\\(?:math\\|displaymath\\|equation\\|align\\|flalign\\|multiline\\|gather\\)[a-z]*\\*?}" . maths)
("^[ \t]*|" . table)
("cref:\\|\\cref{" . cleveref)
@ -7313,12 +7345,18 @@ digraph {
(":float wrap" . float-wrap)
(":float sideways" . rotate)
("^[ \t]*#\\+caption:\\|\\\\caption" . caption)
("\\[\\[xkcd:" . (image caption))
(org-latex-use-microtype . microtype)
((and org-latex-italic-quotes "^[ \t]*#\\+begin_quote\\|\\\\begin{quote}") . italic-quotes)
(org-latex-par-sep . par-sep)
(org-latex-embed-tangled-files . embed-files)
((and org-latex-embed-files "^[ \t]*#\\+begin_src\\|^[ \t]*#\\+BEGIN_SRC") . embed-tangled)
("^[ \t]*\\(?:[-+*]\\|[0-9]+[.)]\\|[A-Za-z]+[.)]\\) \\[[ -X]\\]" . checkbox)
("^[ \t]*#\\+begin_warning\\|\\\\begin{warning}" . box-warning)
("^[ \t]*#\\+begin_info\\|\\\\begin{info}" . box-info)
("^[ \t]*#\\+begin_success\\|\\\\begin{success}" . box-success)
("^[ \t]*#\\+begin_error\\|\\\\begin{error}" . box-error))
"Org feature tests and associated LaTeX feature flags.
"Org feature tests and associated LaTeX feature flags.
Alist where the car is a test for the presense of the feature,
and the cdr is either a single feature symbol or list of feature symbols.
@ -7326,7 +7364,7 @@ and the cdr is either a single feature symbol or list of feature symbols.
When a string, it is used as a regex search in the buffer.
The feature is registered as present when there is a match.
The care can also be a
The car can also be a
- symbol, the value of which is fetched
- function, which is called
- list, which is `eval'uated
@ -7338,18 +7376,21 @@ existance of the feature.")
#+begin_src emacs-lisp
(defvar org-latex-feature-implementations
'((universal :snippet org-latex-universal-preamble :order -2)
(embed-tangled :snippet (concat (org-latex-embed-tangled-files) "\n") :order -1)
(image :snippet "\\usepackage{graphicx}")
'((image :snippet "\\usepackage{graphicx}")
(svg :snippet "\\usepackage{svg}")
(maths :snippet "\\usepackage{bmc-maths}")
(maths :snippet "\\usepackage[nofont]{bmc-maths}")
(table :snippet "\\usepackage{longtable}\n\\usepackage{booktabs}")
(cleveref :snippet "\\usepackage{cleveref}" :order 1) ; after bmc-maths
(underline :snippet "\\usepackage[normalem]{ulem}")
(float-wrap :snippet "\\usepackage{wrapfig}")
(rotate :snippet "\\usepackage{rotating}")
(caption :snippet org-latex-caption-preamble)
(microtype :snippet "\\usepackage[activate={true,nocompatibility},final,tracking=true,kerning=true,spacing=true,factor=2000]{microtype}\n")
(embed-files :snippet org-latex-embed-files-preamble :order -2)
(embed-tangled :requires embed-files :snippet (concat (org-latex-embed-tangled-files) "\n") :order -1)
(acronym :snippet "\\newcommand{\\acr}[1]{\\protect\\textls*[110]{\\scshape #1}}\n\\newcommand{\\acrs}{\\protect\\scalebox{.91}[.84]{\\hspace{0.15ex}s}}" :order 2)
(italic-quotes :snippet "\\renewcommand{\\quote}{\\list{}{\\rightmargin\\leftmargin}\\item\\relax\\em}\n")
(par-sep :snippet "\\setlength{\\parskip}{\\baselineskip}\n\\setlength{\\parindent}{0pt}\n")
(pifont :snippet "\\usepackage{pifont}")
(checkbox :requires pifont :snippet (concat (unless (memq 'maths features)
"\\usepackage{amssymb} % provides \\square")
@ -7371,8 +7412,13 @@ following keys:
- a list, which is passed to `eval', with a list of feature flags available
as \"features\".
- :requires, a feature or list of features that must be available
- :when, a feature or list of features that when all available should cause this
to be automatically enabled.
- :prevents, a feature or list of features that should be masked
- :order, for when ordering is important. Lower values appear first.
The default is 0.")
The default is 0.
Features that start with ! will be eagerly loaded, i.e. without being detected.")
#+end_src
***** Feature determination
@ -7409,37 +7455,67 @@ Once a list of required features has been determined, we want to use
~org-latex-feature-implementations~ to generate the LaTeX which should be inserted
into the preamble to provide those features.
This is done in stages.
+ The dependencies for each listed feature are added to feature list (=:requires=).
First we want to process our fancy keywords in ~org-latex-feature-implementations~
to produce an /expanded/ list of features. We'll do that by performing the
following steps.
+ The dependencies for each listed feature are added to feature list
(=:requires=).
+ The =:when= conditions of each feature, and available features starting with =!=
are evaluated, and they are added/removed accordingly
+ Any features present in a =:prevents= value are removed
+ The feature list is scrubbed of duplicates
+ The feature list is sorted by =:order= (ascending)
+ The value of each feature's =:snippet= parameter is concatenated
#+begin_src emacs-lisp
(defun org-latex-generate-features-preamble (features)
"Generate the LaTeX preamble content required to provide FEATURES.
This is done according to `org-latex-feature-implementations'"
(defun org-latex-expand-features (features)
"For each feature in FEATURES process :requires, :when, and :prevents keywords and sort according to :order."
(dolist (feature features)
(unless (assoc feature org-latex-feature-implementations)
(error "Feature %s not provided in org-latex-feature-implementations" feature))
(when-let ((requirements (plist-get (cdr (assoc feature org-latex-feature-implementations)) :requires)))
(setf features (append (if (listp requirements) requirements (list requirements)) features))))
(mapconcat (lambda (feature)
(when-let ((snippet (plist-get (cdr (assoc feature org-latex-feature-implementations)) :snippet)))
(concat
(pcase snippet
((pred stringp) snippet)
((pred functionp) (funcall snippet features))
((pred listp) (eval `(let ((features ',features)) (,@snippet))))
((pred symbolp) (symbol-value snippet))
(_ (user-error "org-latex-feature-implementations :snippet value %s unable to be used" snippet)))
"\n")))
(sort (delete-dups features)
(lambda (feat1 feat2)
(if (< (or (plist-get (cdr (assoc feat1 org-latex-feature-implementations)) :order) 0)
(or (plist-get (cdr (assoc feat2 org-latex-feature-implementations)) :order) 0))
t nil)))
""))
(dolist (potential-feature
(append features (delq nil (mapcar (lambda (feat)
(when (= ?! (aref (symbol-name (car feat)) 0))
(car feat)))
org-latex-feature-implementations))))
(when-let ((prerequisites (plist-get (cdr (assoc potential-feature org-latex-feature-implementations)) :when)))
(setf features (if (cl-every (lambda (preq) (memq preq features)) prerequisites)
(append (list potential-feature) features)
(delq potential-feature features)))))
(dolist (feature features)
(when-let ((prevents (plist-get (cdr (assoc feature org-latex-feature-implementations)) :prevents)))
(setf features (cl-set-difference features (if (listp prevents) prevents (list prevents))))))
(sort (delete-dups features)
(lambda (feat1 feat2)
(if (< (or (plist-get (cdr (assoc feat1 org-latex-feature-implementations)) :order) 0)
(or (plist-get (cdr (assoc feat2 org-latex-feature-implementations)) :order) 0))
t nil))))
#+end_src
Now that we have a nice list of the final features to use, we can just pull out
their snippets and join the result together.
#+begin_src emacs-lisp
(defun org-latex-generate-features-preamble (features)
"Generate the LaTeX preamble content required to provide FEATURES.
This is done according to `org-latex-feature-implementations'"
(let ((expanded-features (org-latex-expand-features features)))
(concat
(format "\n%% features: %s\n" expanded-features)
(mapconcat (lambda (feature)
(when-let ((snippet (plist-get (cdr (assoc feature org-latex-feature-implementations)) :snippet)))
(concat
(pcase snippet
((pred stringp) snippet)
((pred functionp) (funcall snippet features))
((pred listp) (eval `(let ((features ',features)) (,@snippet))))
((pred symbolp) (symbol-value snippet))
(_ (user-error "org-latex-feature-implementations :snippet value %s unable to be used" snippet)))
"\n")))
expanded-features
"")
"% end features\n")))
#+end_src
Then Org needs to be advised to actually use this generated preamble content.

View File

@ -4,83 +4,146 @@
<!-- Generated by graphviz version 2.42.3 (0)
-->
<!-- Title: %3 Pages: 1 -->
<svg width="365pt" height="152pt"
viewBox="0.00 0.00 365.00 152.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 148)">
<svg width="407pt" height="260pt"
viewBox="0.00 0.00 407.10 260.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 256)">
<title>%3</title>
<!-- Checkboxes -->
<!-- file:*.jpeg -->
<g id="node1" class="node">
<title>Checkboxes</title>
<polygon fill="#efefef" stroke="transparent" stroke-width="2" points="95.5,-90 1.5,-90 1.5,-54 95.5,-54 95.5,-90"/>
<polyline fill="none" stroke="#2ec27e" stroke-width="2" points="1.5,-54 95.5,-54 "/>
<text text-anchor="middle" x="48.5" y="-68.3" font-family="overpass" font-size="14.00" fill="#000000">Checkboxes</text>
<title>file:*.jpeg</title>
<polygon fill="#efefef" stroke="transparent" stroke-width="2" points="94,-252 0,-252 0,-216 94,-216 94,-252"/>
<polyline fill="none" stroke="#2ec27e" stroke-width="2" points="0,-216 94,-216 "/>
<text text-anchor="middle" x="47" y="-230.3" font-family="overpass" font-size="14.00" fill="#000000">file:*.jpeg</text>
</g>
<!-- Dingbats -->
<g id="node4" class="node">
<title>Dingbats</title>
<polygon fill="#efefef" stroke="transparent" stroke-width="2" points="227,-63 133,-63 133,-27 227,-27 227,-63"/>
<polyline fill="none" stroke="#f5c211" stroke-width="2" points="133,-27 227,-27 "/>
<text text-anchor="middle" x="180" y="-41.3" font-family="overpass" font-size="14.00" fill="#000000">Dingbats</text>
</g>
<!-- Checkboxes&#45;&gt;Dingbats -->
<g id="edge1" class="edge">
<title>Checkboxes&#45;&gt;Dingbats</title>
<path fill="none" stroke="#aaaaaa" stroke-width="1.2" d="M95.52,-62.4C107.59,-59.89 120.61,-57.17 132.69,-54.66"/>
</g>
<!-- Fancy blocks -->
<g id="node2" class="node">
<title>Fancy blocks</title>
<polygon fill="#efefef" stroke="transparent" stroke-width="2" points="97,-36 0,-36 0,0 97,0 97,-36"/>
<polyline fill="none" stroke="#2ec27e" stroke-width="2" points="0,0 97,0 "/>
<text text-anchor="middle" x="48.5" y="-14.3" font-family="overpass" font-size="14.00" fill="#000000">Fancy blocks</text>
</g>
<!-- Fancy blocks&#45;&gt;Dingbats -->
<g id="edge3" class="edge">
<title>Fancy blocks&#45;&gt;Dingbats</title>
<path fill="none" stroke="#aaaaaa" stroke-width="1.2" d="M97.35,-27.98C108.88,-30.38 121.18,-32.94 132.64,-35.33"/>
</g>
<!-- Images -->
<g id="node3" class="node">
<title>Images</title>
<polygon fill="#efefef" stroke="transparent" stroke-width="2" points="95.5,-144 1.5,-144 1.5,-108 95.5,-108 95.5,-144"/>
<polyline fill="none" stroke="#2ec27e" stroke-width="2" points="1.5,-108 95.5,-108 "/>
<text text-anchor="middle" x="48.5" y="-122.3" font-family="overpass" font-size="14.00" fill="#000000">Images</text>
</g>
<!-- Graphics -->
<g id="node5" class="node">
<title>Graphics</title>
<polygon fill="#efefef" stroke="transparent" stroke-width="2" points="227,-144 133,-144 133,-108 227,-108 227,-144"/>
<polyline fill="none" stroke="#f5c211" stroke-width="2" points="133,-108 227,-108 "/>
<text text-anchor="middle" x="180" y="-122.3" font-family="overpass" font-size="14.00" fill="#000000">Graphics</text>
</g>
<!-- Images&#45;&gt;Graphics -->
<g id="edge4" class="edge">
<title>Images&#45;&gt;Graphics</title>
<path fill="none" stroke="#aaaaaa" stroke-width="1.2" d="M95.52,-126C107.59,-126 120.61,-126 132.69,-126"/>
</g>
<!-- pifont -->
<!-- image -->
<g id="node6" class="node">
<title>pifont</title>
<polygon fill="#efefef" stroke="transparent" stroke-width="2" points="357,-63 263,-63 263,-27 357,-27 357,-63"/>
<polyline fill="none" stroke="#813d9c" stroke-width="2" points="263,-27 357,-27 "/>
<text text-anchor="middle" x="310" y="-41.3" font-family="overpass" font-size="14.00" fill="#000000">pifont</text>
<title>image</title>
<polygon fill="#efefef" stroke="transparent" stroke-width="2" points="224,-198 130,-198 130,-162 224,-162 224,-198"/>
<polyline fill="none" stroke="#f5c211" stroke-width="2" points="130,-162 224,-162 "/>
<text text-anchor="middle" x="177" y="-176.3" font-family="overpass" font-size="14.00" fill="#000000">image</text>
</g>
<!-- Dingbats&#45;&gt;pifont -->
<g id="edge2" class="edge">
<title>Dingbats&#45;&gt;pifont</title>
<path fill="none" stroke="#aaaaaa" stroke-width="1.2" d="M227.21,-45C238.81,-45 251.26,-45 262.86,-45"/>
<!-- file:*.jpeg&#45;&gt;image -->
<g id="edge1" class="edge">
<title>file:*.jpeg&#45;&gt;image</title>
<path fill="none" stroke="#aaaaaa" stroke-width="1.2" d="M90.98,-215.87C101.43,-211.46 112.72,-206.7 123.55,-202.13"/>
<polygon fill="#aaaaaa" stroke="#aaaaaa" stroke-width="1.2" points="125.06,-205.29 132.92,-198.18 122.34,-198.84 125.06,-205.29"/>
</g>
<!-- graphicx -->
<!-- file:*.png -->
<g id="node2" class="node">
<title>file:*.png</title>
<polygon fill="#efefef" stroke="transparent" stroke-width="2" points="94,-198 0,-198 0,-162 94,-162 94,-198"/>
<polyline fill="none" stroke="#2ec27e" stroke-width="2" points="0,-162 94,-162 "/>
<text text-anchor="middle" x="47" y="-176.3" font-family="overpass" font-size="14.00" fill="#000000">file:*.png</text>
</g>
<!-- file:*.png&#45;&gt;image -->
<g id="edge3" class="edge">
<title>file:*.png&#45;&gt;image</title>
<path fill="none" stroke="#aaaaaa" stroke-width="1.2" d="M94.21,-180C102.46,-180 111.13,-180 119.63,-180"/>
<polygon fill="#aaaaaa" stroke="#aaaaaa" stroke-width="1.2" points="119.86,-183.5 129.86,-180 119.86,-176.5 119.86,-183.5"/>
</g>
<!-- file:*.svg -->
<g id="node3" class="node">
<title>file:*.svg</title>
<polygon fill="#efefef" stroke="transparent" stroke-width="2" points="94,-36 0,-36 0,0 94,0 94,-36"/>
<polyline fill="none" stroke="#2ec27e" stroke-width="2" points="0,0 94,0 "/>
<text text-anchor="middle" x="47" y="-14.3" font-family="overpass" font-size="14.00" fill="#000000">file:*.svg</text>
</g>
<!-- svg -->
<g id="node7" class="node">
<title>graphicx</title>
<polygon fill="#efefef" stroke="transparent" stroke-width="2" points="357,-144 263,-144 263,-108 357,-108 357,-144"/>
<polyline fill="none" stroke="#813d9c" stroke-width="2" points="263,-108 357,-108 "/>
<text text-anchor="middle" x="310" y="-122.3" font-family="overpass" font-size="14.00" fill="#000000">graphicx</text>
<title>svg</title>
<polygon fill="#efefef" stroke="transparent" stroke-width="2" points="224,-36 130,-36 130,0 224,0 224,-36"/>
<polyline fill="none" stroke="#f5c211" stroke-width="2" points="130,0 224,0 "/>
<text text-anchor="middle" x="177" y="-14.3" font-family="overpass" font-size="14.00" fill="#000000">svg</text>
</g>
<!-- Graphics&#45;&gt;graphicx -->
<!-- file:*.svg&#45;&gt;svg -->
<g id="edge4" class="edge">
<title>file:*.svg&#45;&gt;svg</title>
<path fill="none" stroke="#aaaaaa" stroke-width="1.2" d="M94.21,-18C102.46,-18 111.13,-18 119.63,-18"/>
<polygon fill="#aaaaaa" stroke="#aaaaaa" stroke-width="1.2" points="119.86,-21.5 129.86,-18 119.86,-14.5 119.86,-21.5"/>
</g>
<!-- #+caption -->
<g id="node4" class="node">
<title>#+caption</title>
<polygon fill="#efefef" stroke="transparent" stroke-width="2" points="94,-90 0,-90 0,-54 94,-54 94,-90"/>
<polyline fill="none" stroke="#2ec27e" stroke-width="2" points="0,-54 94,-54 "/>
<text text-anchor="middle" x="47" y="-68.3" font-family="overpass" font-size="14.00" fill="#000000">#+caption</text>
</g>
<!-- caption -->
<g id="node8" class="node">
<title>caption</title>
<polygon fill="#efefef" stroke="transparent" stroke-width="2" points="224,-117 130,-117 130,-81 224,-81 224,-117"/>
<polyline fill="none" stroke="#f5c211" stroke-width="2" points="130,-81 224,-81 "/>
<text text-anchor="middle" x="177" y="-95.3" font-family="overpass" font-size="14.00" fill="#000000">caption</text>
</g>
<!-- #+caption&#45;&gt;caption -->
<g id="edge7" class="edge">
<title>#+caption&#45;&gt;caption</title>
<path fill="none" stroke="#aaaaaa" stroke-width="1.2" d="M94.21,-81.75C102.55,-83.51 111.32,-85.36 119.91,-87.17"/>
<polygon fill="#aaaaaa" stroke="#aaaaaa" stroke-width="1.2" points="119.35,-90.63 129.86,-89.27 120.79,-83.78 119.35,-90.63"/>
</g>
<!-- xkcd:* -->
<g id="node5" class="node">
<title>xkcd:*</title>
<polygon fill="#efefef" stroke="transparent" stroke-width="2" points="94,-144 0,-144 0,-108 94,-108 94,-144"/>
<polyline fill="none" stroke="#2ec27e" stroke-width="2" points="0,-108 94,-108 "/>
<text text-anchor="middle" x="47" y="-122.3" font-family="overpass" font-size="14.00" fill="#000000">xkcd:*</text>
</g>
<!-- xkcd:*&#45;&gt;image -->
<g id="edge9" class="edge">
<title>xkcd:*&#45;&gt;image</title>
<path fill="none" stroke="#aaaaaa" stroke-width="1.2" d="M90.98,-144.13C101.43,-148.54 112.72,-153.3 123.55,-157.87"/>
<polygon fill="#aaaaaa" stroke="#aaaaaa" stroke-width="1.2" points="122.34,-161.16 132.92,-161.82 125.06,-154.71 122.34,-161.16"/>
</g>
<!-- xkcd:*&#45;&gt;caption -->
<g id="edge10" class="edge">
<title>xkcd:*&#45;&gt;caption</title>
<path fill="none" stroke="#aaaaaa" stroke-width="1.2" d="M94.21,-116.25C102.55,-114.49 111.32,-112.64 119.91,-110.83"/>
<polygon fill="#aaaaaa" stroke="#aaaaaa" stroke-width="1.2" points="120.79,-114.22 129.86,-108.73 119.35,-107.37 120.79,-114.22"/>
</g>
<!-- (TeX) graphicx -->
<g id="node9" class="node">
<title>(TeX) graphicx</title>
<polygon fill="#efefef" stroke="transparent" stroke-width="2" points="366,-198 260,-198 260,-162 366,-162 366,-198"/>
<polyline fill="none" stroke="#813d9c" stroke-width="2" points="260,-162 366,-162 "/>
<text text-anchor="middle" x="313" y="-176.3" font-family="overpass" font-size="14.00" fill="#000000">(TeX) graphicx</text>
</g>
<!-- image&#45;&gt;(TeX) graphicx -->
<g id="edge2" class="edge">
<title>image&#45;&gt;(TeX) graphicx</title>
<path fill="none" stroke="#aaaaaa" stroke-width="1.2" d="M224.12,-180C232.39,-180 241.13,-180 249.77,-180"/>
<polygon fill="#aaaaaa" stroke="#aaaaaa" stroke-width="1.2" points="249.82,-183.5 259.82,-180 249.82,-176.5 249.82,-183.5"/>
</g>
<!-- (TeX) svg -->
<g id="node10" class="node">
<title>(TeX) svg</title>
<polygon fill="#efefef" stroke="transparent" stroke-width="2" points="360,-36 266,-36 266,0 360,0 360,-36"/>
<polyline fill="none" stroke="#813d9c" stroke-width="2" points="266,0 360,0 "/>
<text text-anchor="middle" x="313" y="-14.3" font-family="overpass" font-size="14.00" fill="#000000">(TeX) svg</text>
</g>
<!-- svg&#45;&gt;(TeX) svg -->
<g id="edge5" class="edge">
<title>Graphics&#45;&gt;graphicx</title>
<path fill="none" stroke="#aaaaaa" stroke-width="1.2" d="M227.21,-126C238.81,-126 251.26,-126 262.86,-126"/>
<title>svg&#45;&gt;(TeX) svg</title>
<path fill="none" stroke="#aaaaaa" stroke-width="1.2" d="M224.12,-18C234.22,-18 245.03,-18 255.49,-18"/>
<polygon fill="#aaaaaa" stroke="#aaaaaa" stroke-width="1.2" points="255.8,-21.5 265.8,-18 255.8,-14.5 255.8,-21.5"/>
</g>
<!-- (TeX) caption -->
<g id="node11" class="node">
<title>(TeX) caption</title>
<polygon fill="#efefef" stroke="transparent" stroke-width="2" points="362,-117 264,-117 264,-81 362,-81 362,-117"/>
<polyline fill="none" stroke="#813d9c" stroke-width="2" points="264,-81 362,-81 "/>
<text text-anchor="middle" x="313" y="-95.3" font-family="overpass" font-size="14.00" fill="#000000">(TeX) caption</text>
</g>
<!-- caption&#45;&gt;(TeX) caption -->
<g id="edge8" class="edge">
<title>caption&#45;&gt;(TeX) caption</title>
<path fill="none" stroke="#aaaaaa" stroke-width="1.2" d="M224.12,-99C233.67,-99 243.85,-99 253.77,-99"/>
<polygon fill="#aaaaaa" stroke="#aaaaaa" stroke-width="1.2" points="253.97,-102.5 263.97,-99 253.97,-95.5 253.97,-102.5"/>
</g>
<!-- (TeX) svg&#45;&gt;(TeX) graphicx -->
<g id="edge6" class="edge">
<title>(TeX) svg:e&#45;&gt;(TeX) graphicx:s</title>
<path fill="none" stroke="#aaaaaa" stroke-width="1.2" d="M361,-18C406.17,-18 405.97,-77.53 384,-117 367.92,-145.89 324.16,-128.77 314.79,-150.91"/>
<polygon fill="#aaaaaa" stroke="#aaaaaa" stroke-width="1.2" points="311.3,-150.54 313,-161 318.19,-151.76 311.3,-150.54"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 8.1 KiB