[Tex/LaTex] Automatically fit the graphics in the remaining space of a Beamer slide

beamergraphicsscaling

I want to put a figure in some part of the presentation (beginning, middle or end of the slide). I want the figure to be adjusted to the height of the available space while keeping the aspect ratio intact. How can I do that?

Suppose I have THIS image to be put in the slides. I have the following minimal example:

\documentclass{beamer}

\usepackage{graphicx}
\usepackage[pangram]{blindtext}

\usetheme{Pittsburgh}

\begin{document}

\begin{frame}
\frametitle{Something}
\blindenumerate[2]
\centering 
\includegraphics[width=\textwidth,height=\textheight,keepaspectratio]{2000px-If-then-else-control-flow-graph.svg.png}
\end{frame}

\begin{frame}
\frametitle{Something}
\blindenumerate[2]
\centering
\includegraphics[width=\textwidth,height=.5\textheight,keepaspectratio]{2000px-If-then-else-control-flow-graph.svg.png}
\blinddescription[2]
\end{frame}

\begin{frame}
\frametitle{Something}
\blindenumerate[6]
\centering
\includegraphics[width=\textwidth,height=.5\textheight,keepaspectratio]{2000px-If-then-else-control-flow-graph.svg.png}
\blinddescription[2]
\end{frame}

\end{document}

enter image description here
enter image description here
enter image description here

I want this figure to be adjusted within the available space automatically without changing the height manually (i.e. .5\textheight). Is it possible?

Best Answer

One way is to define a new command which takes as arguments the frame content before the image, the file name of the image and, optionally, any frame content following the image. So that these can be specified in their natural order, I use xparse's \NewDocumentCommand to define

\fitimage{<content before>}{<image file name>}[<content after>]

This command calculates the total height of a paragraph box containing the first and third arguments (\fitotherht). It then calculates an appropriate maximum height for the image (\fitimageht) by subtracting this from \textheight and making a few adjustments to allow room for the vertical spacing at the head and foot of the frame, and for some space between the different clusters of content within the frame.

Code:

\documentclass{beamer}
\usepackage[pangram]{blindtext}
\usetheme{Pittsburgh}
\usepackage{xparse,calc}
\newlength\fitimageht
\newlength\fitotherht
\newsavebox\fitimagebox
\NewDocumentCommand \fitimage { m m O {} }{%
  \sbox\fitimagebox{%
    \parbox{\textwidth}{%
      #1\par
      #3
    }%
  }%
  \settototalheight{\fitotherht}{%
    \usebox\fitimagebox
  }%
  \setlength\fitimageht{\textheight}%
  \addtolength\fitimageht{-\fitotherht-\topskip-\footskip-3\baselineskip}%
  #1\par
  \centering
  \includegraphics[width=\textwidth,height=\fitimageht,keepaspectratio]{#2}\par
  #3}
\begin{document}

\begin{frame}
  \fitimage{%
    \frametitle{Something}
    \blindenumerate[2]
  }{2000px-If-then-else-control-flow-graph}
\end{frame}

\begin{frame}
  \fitimage{%
    \frametitle{Something}
    \blindenumerate[2]%
  }{2000px-If-then-else-control-flow-graph}[%
    \blinddescription[2]
  ]
\end{frame}

\begin{frame}
  \fitimage{%
    \frametitle{Something}
    \blindenumerate[6]%
  }{2000px-If-then-else-control-flow-graph}[%
    \blinddescription[2]
  ]
\end{frame}

\end{document}

fit-my-image

It is important that all frame content be included within the arguments to the command. So this won't work with overly fragile content. (I imagine verbatim code would not work, for example.) But for ordinary text, frame title etc., it seems to do a reasonable job. If the spacing I've chosen is not to your taste, you can easily adjust the value of \fitimageht by subtracting more or less as applicable.

This does not result in any bad boxes, according to the log file.