0

I have a LaTeX document that is generated from a collection of other documents that include source for generating images. These images end up with varying sizes, some of which are too wide for the page. Rather than have them scaled down to fit the page width, I want those images (and their captions) to be automatically rotated when their aspect ratio is more landscape than 5×2.

I am unable to customize how the figure environment is emitted into the generated LaTeX document, but I have full control of the document prolog (i.e. everything before the generated content). Is there some way I can rig up figure environments to automatically rotate based on aspect ratio? I'm currently using graphicx package for graphics, set up like so:

\usepackage{graphicx,grffile}
\makeatletter
\def\maxwidth{\ifdim\Gin@nat@width>\linewidth\linewidth\else\Gin@nat@width\fi}
\def\maxheight{\ifdim\Gin@nat@height>\textheight\textheight\else\Gin@nat@height\fi}
\makeatother
\setkeys{Gin}{width=\maxwidth,height=\maxheight,keepaspectratio}

Images are emitted into the generated LaTeX doc as so:

\begin{figure}
\hypertarget{generated-target-name}{%
\centering
\includegraphics{images/image-filename.png}
\caption{Caption for image}\label{generated-target-name}
}
\end{figure}
2
  • Do you want to rotate the caption? Commented Oct 29, 2018 at 18:53
  • Yeah, I want to rotate the entire contents of the figure environment. Commented Oct 29, 2018 at 19:23

1 Answer 1

3

I assume you only want to rotate if the image is too wide.

Note, this version only allows one caption and label per figure.

\documentclass{scrbook}
\usepackage{graphicx}
\usepackage{varwidth}
\usepackage{caption}
\usepackage{hyperref}

\let\oldfigure=\figure
\let\endoldfigure=\endfigure
\newsavebox{\figurebox}
\newif\ifcentering
\newif\ifcaption
\newif\ifcaptionlabel
\newcommand{\saveshortcaption}{}% reserve global names
\newcommand{\savecaption}{}
\newcommand{\savecaptionlabel}{}

\renewenvironment{figure}[1][tbp]{\oldfigure[#1]%
  \centeringfalse
  \captionfalse
  \captionlabelfalse
  \begin{lrbox}{\figurebox}%
    \def\centering{\global\centeringtrue}%
    \renewcommand{\caption}[2][\empty]{\global\captiontrue
      \gdef\saveshortcaption{##1}%
      \gdef\savecaption{##2}}%
    \renewcommand{\label}[1]{\global\captionlabeltrue
      \xdef\savecaptionlabel{##1}}%
    \varwidth[b]{2\textheight}}% need some upper limit
{\endvarwidth
  \end{lrbox}%
  \ifcaption
    \savebox{\figurebox}{\begin{minipage}[b]{\wd\figurebox}
      \usebox{\figurebox}%
      \ifx\empty\saveshortcaption\relax
        \caption{\savecaption}%
      \else
        \caption[\saveshortcaption]{\savecaption}%
      \fi
      \ifcaptionlabel \label{\savecaptionlabel}\fi
     \end{minipage}}%
  \fi
  \ifdim\wd\figurebox>\columnwidth
    \ifdim 2\wd\figurebox > 5\ht\figurebox \savebox\figurebox{\rotatebox{90}{\box\figurebox}}\fi
  \fi
  \ifdim\wd\figurebox>\columnwidth
    \dimen0=\columnwidth
  \else
    \dimen0=\wd\figurebox
  \fi
  \ifdim\ht\figurebox>\textheight
    \dimen1=\textheight
  \else
    \dimen1=\ht\figurebox
  \fi
  \sbox0{\resizebox{\dimen0}{\dimen1}{\box\figurebox}}%
  \ifcentering
    \makebox[\columnwidth][c]{\box0}%
  \else
    \box0
  \fi
\endoldfigure}

\begin{document}

\begin{figure}[htp]
\centering
\hypertarget{generated-target-name}{%
\rule{20cm}{6cm}}
\caption{Caption for image}\label{generated-target-name}
\end{figure}

\hyperlink{generated-target-name}{Using hyperlink}

Using \verb|\ref| \ref{generated-target-name}

\end{document}

A simpler and less restrictive solution is to use the environ package.

\documentclass{scrbook}
\usepackage{environ}
\usepackage{graphicx}
\usepackage{varwidth}
\usepackage{caption}
\usepackage{hyperref}

\let\oldfigure=\figure
\let\endoldfigure=\endfigure
\newif\ifcentering

\RenewEnviron{figure}[1][tbp]{\oldfigure[#1]%
  \centeringfalse
  \sbox0{% get width without caption
    \def\centering{\global\centeringtrue}%
    \renewcommand{\caption}[2][\empty]{}%
    \renewcommand{\label}[1]{}%
    \begin{varwidth}[b]{2\textheight}% need some upper limit
      \BODY
    \end{varwidth}}
  \sbox1{% repeat with caption
    \begin{minipage}[b]{\wd0}
      \BODY
    \end{minipage}}%
  \ifdim\wd1>\columnwidth
    \ifdim 2\wd1 > 5\ht1 \sbox1{\rotatebox{90}{\box1}}\fi
  \fi
  \ifdim\wd1>\columnwidth
    \dimen0=\columnwidth
  \else
    \dimen0=\wd1
  \fi
  \ifdim\ht1>\textheight
    \dimen1=\textheight
  \else
    \dimen1=\ht1
  \fi
  \sbox0{\resizebox{\dimen0}{\dimen1}{\box1}}%
  \ifcentering
    \makebox[\columnwidth][c]{\box0}%
  \else
    \box0
  \fi
\endoldfigure}

\begin{document}

\begin{figure}[htp]
\centering
\hypertarget{generated-target-name}{%
\rule{20cm}{6cm}}
\caption{Caption for image}\label{generated-target-name}
\end{figure}

\hyperlink{generated-target-name}{Using hyperlink}

Using \verb|\ref| \ref{generated-target-name}

\end{document}
6
  • As I mentioned in the question itself, I can't change the template used for emitting the images (i.e. the figure environment). Any autorotation has to be able to apply without changes between \begin{figure} and \end{figure}, inclusive to those lines. Commented Oct 29, 2018 at 19:28
  • One can redefine figure, but adding the caption is tricky. Commented Oct 29, 2018 at 19:45
  • This does rotate the images appropriately but centering no longer happens and the caption text has shrunk to the point where it is no longer readable. I assume this has to do with the fact that documentclass is scrbook for my document rather than article. Commented Oct 29, 2018 at 21:04
  • Okay, this version redefines \caption and \label as well as \centering to delay implementation. Commented Oct 29, 2018 at 22:11
  • Thanks. I'll give this a shot when I'm back in the office tomorrow morning. Commented Oct 30, 2018 at 0:05

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .