3

I want to make a macro to insert image in page. There are following restrictions:

  1. Insert image with caption.
  2. Keep aspect ratio of image.
  3. Maximize image size.
  4. Center image vertically or horizontaly (depending on the size of image, the macro should be universal).
  5. Size of resulting object with image and caption must be equal to 1/3 of page height and consume all width.
  6. If I put this macro 3 times with absolutely any images and captions, this images must be on the single page, consuming all its size.

Now I'm ended up with the following macro:

\newcommand{\oneimage}[2]{
\begin{figure}
\fbox{%
\parbox[b][0.3\textheight][t]{\textwidth}{%
\fbox{\parbox[b][0.26\textheight][c]{\textwidth}{%
\centering%
\includegraphics[width=\textwidth,height=0.26\textheight,keepaspectratio]{img/#1}%
}}%
\par%
\fbox{\parbox[b][0.04\textheight][t]{\textwidth}{%
\caption{#2}%
\label{fig:#1}%
}}%
}%
}
\end{figure}
}

As you can see, the solution is not perfect, I left about 4 rows for caption, because it is not clear how to force it to consume only necessary amount of rows, and give 1/3 page height - height of caption to the image. Now the rule "maximize image size" is not implemented honestly.

1 Answer 1

1

To make your macro robust, you need to calculate both the width and the height of your \parboxes. The following solution requires the calc package.

Box widths

Each \fbox has an inner padding of \fboxsep+\fboxrule on each side. Therefore, your inner \parboxes should have a width of \textwidth-2\fboxsep-2\fboxrule. Furthermore, the actual image loaded with \includegraphics should have a width of \textwidth-4\fboxsep-4\fboxrule

Box heights

Here it gets a bit more complicated. For the caption box, you need to account for multi-line captions. You can measure the height of the caption using \heightof{\parbox[b][][t]{\textwidth-2\fboxsep-2\fboxrule}{\@makecaption\fnum@figure{#2}}} and then add the padding 2\fboxsep+2\fboxrule. Note that, as done in this answer, I increment and decrement the figure counter to make sure that the right number is used in the "dummy" caption that I measure. This leads to:

\stepcounter{figure}
\setlength{\capboxheight}{2\fboxsep+2\fboxrule+\heightof{\parbox[b][][t]{\textwidth-2\fboxsep-2\fboxrule}{\@makecaption\fnum@figure{#2}}}}
\addtocounter{figure}{-1}

For the figure box, you subtract the caption box height, the padding and the separation between boxes from the total 0.33\textheight-1.4\baselineskip (this is approximately the maximum height that still allows three figures to be placed on the same page, and I obtained it through some trial and error):

\setlength{\figboxheight}{0.33\textheight-1.4\baselineskip-2\fboxsep-2\fboxrule-\lineskip-\capboxheight}

This produces the following result. The full code and the three test images square.png, flat.png and tall.png (which, as per your code, need to be placed in a directory named ./img/) are at the end of the post:

threefig

\documentclass{article}
\usepackage[margin=1in]{geometry}
\usepackage{graphicx}
\usepackage{calc}

\newlength{\capboxheight}
\newlength{\figboxheight}

\makeatletter
\newcommand{\oneimage}[2]{

\stepcounter{figure}
\setlength{\capboxheight}{2\fboxsep+2\fboxrule+\heightof{\parbox[b][][t]{\textwidth-2\fboxsep-2\fboxrule}{\@makecaption\fnum@figure{#2}}}}
\addtocounter{figure}{-1}

\setlength{\figboxheight}{0.33\textheight-1.4\baselineskip-2\fboxsep-2\fboxrule-\lineskip-\capboxheight}

\begin{figure}
\fbox{%
\parbox[b][][t]{\textwidth}{\centering%
\fbox{\parbox[b][\figboxheight][c]{\textwidth-2\fboxsep-2\fboxrule}{%
\centering%
\includegraphics[width=\textwidth-4\fboxsep-4\fboxrule,height=\figboxheight-2\fboxsep-2\fboxrule,keepaspectratio]{img/#1}%
}}%
\par
\fbox{\parbox[b][\capboxheight][t]{\textwidth-2\fboxsep-2\fboxrule}{%
    \caption{#2}%
    \label{fig:#1}%
}}%
}%
}
\end{figure}
}

\makeatother

\begin{document}

\oneimage{square.png}{A square.}
\oneimage{flat.png}{A flat rectangle.}
\oneimage{tall.png}{A tall rectangle with a very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very long caption that spans 3 lines.}

\end{document}

square.png flat.png tall.png

8
  • Thank you, it is exactly what I am looking for! I have a small issue with this approach: I am using caption package, so it seems like instead using \setlength{\capboxheight}...{#2}, I should use \setlength{\capboxheight}...{\caption{#2}}, but it creates an error Package caption Error: \caption outside float. I use it, because it gives correct navigation in pdf (jump to image, but not to caption), so I can disable it, but maybe there exist some simple solution?
    – user150818
    Commented Dec 17, 2017 at 12:48
  • Also, I am interesting why it's important to use 0.3\textheight, because when I am using 0.33\textheight, the third image goes on the second page.
    – user150818
    Commented Dec 17, 2017 at 12:50
  • @BhavinChirag There does not seem to be an easy way to use \caption inside \heightof, because the \caption command needs to be inside a float (such as a figure). That is why I had to add those \...captionskip lengths. The reason why 0.33\textheight does not work is that Latex also adds some spacing between these \parboxes, which I unfortunately could not find documentation for. It is probably faster to tweak the 0.33 by trial and error: I got something like 0.33\textheight-1.4\baselineskip to be very close to the maximum value.
    – wimi
    Commented Dec 17, 2017 at 13:13
  • Maybe there is some problem with parbox fboxsep and fboxrule? When I do: \setlength{\fboxsep}{0pt},\setlength{\fboxrule}{0.001pt}, I see some offset from the top of caption, which eliminates, when I also include caption package.
    – user150818
    Commented Dec 17, 2017 at 13:36
  • 1
    \heightof is not considering prefix Figure 2: , so there maybe case when height equals only single line, but caption actually consumes two
    – user150818
    Commented Dec 17, 2017 at 14:05

You must log in to answer this question.