To make your macro robust, you need to calculate both the width and the height of your \parbox
es. The following solution requires the calc
package.
Box widths
Each \fbox
has an inner padding of \fboxsep+\fboxrule
on each side. Therefore, your inner \parbox
es 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:
\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}