5

While experimenting with KOMA-Script's features I have found captionbeside. That's a really great option for me as I want my captions to be formatted this way. The only problem is that in a long document of mine I do not want to rewrite every figure.

So the question is how I could automatically change (by redefinition):

\begin{figure}
\includegraphics{}
\caption{Blub}
\end{figure}

to be treated as

\begin{figure}
\begin{captionbeside}{Blub}
\includegraphics{}
\end{captionbeside}
\end{figure}

If it helps, I use LuaLaTeX, so a Lua solution would be okay too (although I would prefer LaTeX).

Complete code example:

\documentclass{scrartcl}
\usepackage{graphicx}

\begin{document}
    \begin{figure}
        \centering
        \includegraphics[height=10\baselineskip]{example-image}
        \caption{Test a}\label{testa}
    \end{figure}
    \begin{figure}
        \begin{captionbeside}{Test b}
            \centering
            \includegraphics[height=10\baselineskip]{example-image}
            \label{testb}
        \end{captionbeside}
    \end{figure}
\end{document}

Update: I have redefined figure to gobble captions. In that sense captionbeside works, but it of course won't output the right caption. How could I realize this (using the parameter of a not-yet-issued macro)?

\documentclass{scrartcl}
\usepackage{graphicx}

\makeatletter
\let\oldfigure\figure
\let\oldendfigure\endfigure
\renewenvironment{figure}{
    \oldfigure\let\caption\@gobble
        \begin{captionbeside}{Figure}
}{\end{captionbeside}\oldendfigure}
\makeatother

\begin{document}
    \begin{figure}
        \centering
        \includegraphics[height=10\baselineskip]{example-image}
        \caption{Test a}\label{testa}
    \end{figure}
    \begin{figure}
        \centering
        \includegraphics[height=10\baselineskip]{example-image}
        \caption{Test b}\label{testb}
    \end{figure}
\end{document}
  • 1
    I don't have much time right now, but: You might redefine the figure-environment to include the captionbeside-environment. The issue with redefining the \caption command might be a little tricky. Maybe a two run solution does work. – Skillmon likes topanswers.xyz May 13 '17 at 17:34
  • @Skillmon Well I thought about redefining the figure environment, but have no clue how I would capture the argument of \caption to be given to captionbeside. A two-run-solution would be fine for me. – TeXnician May 13 '17 at 17:36
  • The problem is that KOMA replaces \caption with either \captionabove or \captionbelow. See tex.stackexchange.com/questions/353986/… – John Kormylo May 14 '17 at 0:11
  • @JohnKormylo Then one would have to replace both of them. Do you know a smart redefinition? – TeXnician May 14 '17 at 6:15
  • Both \captionabove and \captionbelow call the same macro (\scr@caption), they set a boolean switch for the formatting behavior (if I'm not mistaken). – Skillmon likes topanswers.xyz May 14 '17 at 10:41
6

You have to redefine \caption (and \captionabove and \captionbelow) to store the values and use them as arguments of the captionbeside environment. In the example below I also store the argument of \label to make it possible to have (exactly one) \label in the environment instead of in the \caption argument.

\documentclass{scrartcl}
\usepackage{graphicx}
\usepackage{varwidth}
\usepackage{xparse}
\newsavebox\figurebox
\makeatletter
\let\truefigure\figure
\let\endtruefigure\endfigure
\RenewDocumentEnvironment{figure}{ o }{%
  \begin{lrbox}{\figurebox}%
    \begin{varwidth}[b]{\linewidth}
      \global\let\mandatorycaptionarg\relax
      \RenewDocumentCommand{\caption}{om}{%
        \ifx\mandatorycaptionarg\relax
          \IfNoValueTF{##1}%
            {\gdef\optionalcaptionarg{##2}}%
            {\gdef\optionalcaptionarg{##1}}%
          \gdef\mandatorycaptionarg{##2}%
        \else
          \@latex@warning{caption lost.\MessageBreak
            This implementation of `figure' supports only\MessageBreak
            one \string\caption\space per environment.\MessageBreak
            `\string\caption' ignored%
          }%
        \fi
      }%
      \RenewDocumentCommand{\label}{m}{%
        \ifx\labelarg\relax
          \gdef\labelarg{##1}%
        \else
          \@latex@warning{label lost.\MessageBreak
            This implementation of `figure' supports only\MessageBreak
            one \string\label\space per environment.\MessageBreak
            `\string\label' ignored%
          }%
        \fi
      }%
      \global\let\labelarg\relax
      \let\captionabove\caption
      \let\captionbelow\caption
}{%
    \end{varwidth}%
  \end{lrbox}%
  \def\caption{%
    \if@figurecaptionabove\expandafter\captionabove
    \else\expandafter\captionbelow\fi
  }%
  \IfNoValueTF{#1}%
    {\truefigure}%
    {\truefigure[#1]}%
  \begin{captionbeside}[\optionalcaptionarg]{\mandatorycaptionarg}%
    \usebox\figurebox
  \end{captionbeside}%
  \ifx\labelarg\relax\else\label{\labelarg}\fi%
  \endtruefigure
}
\makeatother

\begin{document}
    \begin{figure}
        \centering
        \includegraphics[height=10\baselineskip]{example-image}
        \caption{Test a\label{testB}}\label{testA}% will work
%        \caption{Onther caption}% will be ignored (see warning in log)
    \end{figure}
    \begin{truefigure}
        \begin{captionbeside}{Test b\label{testa}}% \label will work
            \centering
            \includegraphics[height=10\baselineskip]{example-image}
            \label{testb}% will not work
        \end{captionbeside}
        \label{testc}% will work
    \end{truefigure}

    See figures~\ref{testA} and \ref{testB} or \ref{testa}, \ref{testb},
    \ref{testc}.
\end{document}

As you can see, I've only solved the problem with the \label in your example. But note that you cannot have more than one \caption or more than one \label (outside \caption) in such a figure. If you need multi-caption figures you have to use truefigure now.

The varwidth if useful if you have vertical material (\par) in the figure. If not you can remove it.

Active the commented second \caption, if you want so see what happens, if you're using more than one \caption in such a figure.

enter image description here

I've used \RenewDocumentEnvironment because it supports easy usage of the environment arguments in the end part of the declaration. And you could also add additional optional arguments to the new figure environment to use them for the optional arguments of the internal captionbeside environment. \RenewDocumentEnvironment is not limited to only one optional argument.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.