Hello,
I'm having some trouble exporting captions for images generated by
source code blocks within an Org document (Emacs 30.2, Org mode
version 9.7.11). The following small example uses the "by-backend"
macro from the Org documentation to support HTML and PDF exports.
(A complete example is appended at the end of this message.)
#+name: tikz-basic-picture
#+header: :headers '("\\usepackage{tikz}" "\\usetikzlibrary{shapes}")
#+header: :file-ext (by-backend ('latex 'nil) (_ "svg"))
#+header: :results (by-backend ('latex "latex") (_ "raw file"))
#+begin_src latex
\begin{tikzpicture}
\node[fill=green, minimum size=2em] {};
\end{tikzpicture}
#+end_src
#+name: results--tikz-basic-picture
#+caption: Image created by the LaTeX source code block.
#+results: tikz-basic-picture
The HTML export works as is, but the LaTeX backend fails to include
the figure caption. I have to add a :wrap to the source code block
header,
#+header: :wrap (by-backend ('latex "figure") (_ nil))
to get the LaTeX backend to create the caption in the LaTeX export.
But, unfortunately, this causes the HTML backend to drop the image
caption in HTML exports.
Is there an idiomatic approach to solving this conflict? I've tried
adding "#+attr_latex: :float t" to the results block header in lieu of
the :wrap source code block argument, but that looks like it only
applies to images.
Currently, I am applying :before advice to org-babel-insert-result to
remove a nil wrap setting, but I would rather not be advising
Org-babel behavior if there is a less invasive alternative.
#+name: fix-missing-captions-in-html-exports
#+begin_src emacs-lisp :exports none :results none
(defun remove-nil-wrap (result &optional result-params info hash
lang exec-time)
(if-let* ((header-args (nth 2 info))
(wrap (assq :wrap header-args))
(wrap-is-nil (not (cdr wrap))))
(setf header-args (delq wrap header-args))))
(advice-add 'org-babel-insert-result :before #'remove-nil-wrap)
#+end_src
The HTML backend defines an org-html-standalone-image-predicate that I
may be able to use to get the caption back for wrapped images. But I
didn't get very far before getting lost in the org element tree.
Thanks in advance for any advice and help.
The full example follows.
# (Requires LaTeX and Inkscape.)
#+latex_header: \usepackage{tikz}
This is a reference to Figure\nbsp{}[[results--tikz-basic-picture]].
#+name: tikz-basic-picture
#+header: :headers '("\\usepackage{tikz}" "\\usetikzlibrary{shapes}")
#+header: :file-ext (by-backend ('latex 'nil) (_ "svg"))
#+header: :results (by-backend ('latex "latex") (_ "raw file"))
#+begin_src latex
\begin{tikzpicture}
\node[fill=green, minimum size=2em] {};
\end{tikzpicture}
#+end_src
#+name: results--tikz-basic-picture
#+caption: Image created by the LaTeX source code block.
#+results: tikz-basic-picture
# ###
# The prereqs source code block may need to be manually evaluated
# prior to exporting this example.
#+name: prereqs
#+begin_src emacs-lisp :exports none :results none
(if (not (macrop 'by-backend))
(defmacro by-backend (&rest body)
`(pcase (cond ((boundp 'backend) (org-export-backend-name backend))
((and (boundp 'org-export-current-backend)
org-export-current-backend)
org-export-current-backend))
,@body)))
(let ((langs org-babel-load-languages))
(setf (alist-get 'latex langs) t)
(customize-set-variable
'org-babel-load-languages
langs))
(customize-set-variable
'org-babel-latex-preamble
(lambda (_)
(concat "\\documentclass[tikz,preview]{standalone}\n"
"\\def\\pgfsysdriver{pgfsys-tex4ht.def}\n")))
#+end_src