# Absolute positioning of \caption with tikz

I'm using tikz to lay out an image on a page and control precisely its (absolute) position.

I now want to attach a caption to this image and align the (bottom) baseline of my caption to the bottom of the picture.

While this is perfectly working if I manually typeset the caption within a tikz node (see MWE page 1), I can't achieve the same result with the \caption macro. Indeed, it seems that the \caption is embedded in a sort of minipage and that I can only align the bottom of the minipage with the bottom of my image.

I would like to keep using the \captionof macro because my page layout is part of a larger document with other floating figures, a list of figures and continuous numbering of figures.

How can I get the proper alignement of the \captionof baseline ?

\documentclass[a4]{article}
\usepackage{graphicx,lipsum}
\usepackage{tikz}
\usepackage{tikzpagenodes}
\usetikzlibrary{backgrounds,positioning}
\usepackage{subcaption}

\renewcommand{\fboxsep}{0pt}
\setlength{\fboxrule}{0.1pt}

% absolute positioning of a picture on a page
\newcommand{\mypict}{
\begin{tikzpicture}[remember picture, inner sep=0pt]
\coordinate[] (P) at (current page.center);
\node[anchor=center] at (P){
\includegraphics[width=8cm]{example-image-a}
};
\coordinate (TL) at (current bounding box.north west); % top-left corner
\coordinate (BL) at (current bounding box.south west); % bottom-left corner
\coordinate (TR) at (current bounding box.north east); % top-left corner
\coordinate (BR) at (current bounding box.south east); % bottom-left corner
\coordinate[xshift=5cm] (B) at (current bounding box.south east); % bottom-left corner
\pgfresetboundingbox
\path[use as bounding box] (0,0);
\end{tikzpicture}
\begin{tikzpicture}[remember picture, inner sep=0pt]
\draw[line width=0.5pt,red] (BR)--(B);
\pgfresetboundingbox
\path[use as bounding box] (0,0);
\end{tikzpicture}
}

\begin{document}

% FIRST PAGE
% manual caption
\mypict
\begin{tikzpicture}[remember picture, inner sep=0pt]
\node[anchor=base west] at (BR){%
\fbox{\parbox[b]{5cm}{\textbf{Figure 2.3~:} This is my first custom caption and the baseline is correctly aligned with the picture gqp.}}
};
\pgfresetboundingbox
\path[use as bounding box] (0,0);
\end{tikzpicture}

% SECOND PAGE
% auto caption with \captionof
\clearpage
\mypict

\captionsetup{skip=0pt, textfont={sf,small}, labelfont={sf,small,bf}}

\begin{tikzpicture}[remember picture, inner sep=0pt]
\node[anchor=base west] at (BR){%
\fbox{\parbox[b]{5cm}{\captionof{figure}[list entry]{This is my first custom caption and the baseline is correctly aligned with the picture gqp.}}}
};
\pgfresetboundingbox
\path[use as bounding box] (0,0);
\end{tikzpicture}

\end{document}


• Welcome to TeX.SE! This is the most advanced first question I've seen in a while! (But personally I'd say that the caption of the second rather than the first question is correctly aligned.) – user121799 Feb 12 '18 at 23:00
• a4 won't do anything useful, by the way. – cfr Feb 12 '18 at 23:08
• @marmot I agree, though it might depend on the content of the actual image, I guess. Although it is hard to think of what might make the first alignment look correct. – cfr Feb 12 '18 at 23:10
• Well, maybe you are right about which option is better. But if you think about single line captions It might be preferable to get a baseline alignment. It looks weird otherwise. Any idea to achieve this with \captionof ? – Lionel du Peloux Feb 12 '18 at 23:31
• You would have to copy/modify \@makecaption from whatever package currently sets it. You might even be able to use tikz commands INSIDE \@makecaption. Also, you would be better off using a named local bounding box from a scope. – John Kormylo Feb 13 '18 at 17:57

There is an option in caption package that minimizes the problem. If I pass the strut=off option to the caption style the enclosing box is now tight to the caption text paragraph.

However I still cannot mesure the depth of the box/minipage generated by the captionof command and yshift the box consequently (see page 3 of the MWE).

The solution might be to trigger a "phantom captionof" to get correct label and list entry and to print the caption title separately in a common macro.

\documentclass[a4]{article}
\usepackage{graphicx,lipsum}
\usepackage{tikz}
\usepackage{tikzpagenodes}
\usetikzlibrary{backgrounds,positioning}
\usepackage{subcaption}

\renewcommand{\fboxsep}{0pt}
\setlength{\fboxrule}{0.1pt}

% absolute positioning of a picture on a page
\newcommand{\mypict}{
\begin{tikzpicture}[remember picture, inner sep=0pt]
\coordinate[] (P) at (current page.north);
\node[anchor=north] at (P){
\includegraphics[width=8cm]{example-image-a}
};
\coordinate (TL) at (current bounding box.north west); % top-left corner
\coordinate (BL) at (current bounding box.south west); % bottom-left corner
\coordinate (TR) at (current bounding box.north east); % top-left corner
\coordinate (BR) at (current bounding box.south east); % bottom-left corner
\coordinate[xshift=5cm] (B) at (current bounding box.south east); % bottom-left corner
\pgfresetboundingbox
\path[use as bounding box] (0,0);
\end{tikzpicture}
\begin{tikzpicture}[remember picture, inner sep=0pt]
\draw[line width=0.5pt,red] (BR)--(B);
\pgfresetboundingbox
\path[use as bounding box] (0,0);
\end{tikzpicture}
}

\makeatletter

\caption@AtBeginDocument{%
\def\rawcaptionof{\caption@teststar\caption@of{\caption*}\caption}%
}

\newcommand*\rawcaption@of[2]{\caption@settype*{#2}#1}

\long\def\caption@@caption#1[#2]#3{

\ifcaption@star \else
\caption@prepareanchor{#1}{#2}%
\memcaptioninfo{#1}{\csname the#1\endcsname}{#2}{#3}%
\@nameuse{nag@hascaptiontrue}%
\fi
\par
\caption@beginex{#1}{#2}{#3}%
% \caption@setfloatcapt{%
%   \caption@boxrestore
%   \if@minipage
%     \@setminipage
%   \fi
\caption@normalsize
\ifcaption@star
\let\caption@makeanchor\@firstofone
\fi

\@makecaption{\csname fnum@#1\endcsname}%
{\ignorespaces\caption@makeanchor{#3}}\par
%   \caption@if@minipage\@minipagetrue\@minipagefalse
%   }%
\caption@end}

\makeatother

\begin{document}

% FIRST PAGE
% manual caption
\mypict
\begin{tikzpicture}[remember picture, inner sep=0pt]
\node[anchor=base west] at (BR){%
\fbox{\parbox[b]{5cm}{\textbf{Figure 2.3~:} This is my first custom caption and the baseline is correctly aligned with the picture gqp.}}
};
\pgfresetboundingbox
\path[use as bounding box] (0,0);
\end{tikzpicture}

% SECOND PAGE
% auto caption with \captionof
\clearpage
\mypict

\captionsetup{skip=0pt, textfont={sf,small}, labelfont={sf,small,bf}}

\begin{tikzpicture}[remember picture, inner sep=0pt]
\node[anchor=base west] at (BR){%
\fbox{\parbox[b]{5cm}{\rawcaptionof{figure}[list entry]{This is my first custom caption and the baseline is correctly aligned with the picture gqp.}}}
};
\pgfresetboundingbox
\path[use as bounding box] (0,0);
\end{tikzpicture}

% THIRD PAGE
% auto caption with \captionof
\clearpage
\mypict

\captionsetup{skip=0pt, textfont={sf,small}, labelfont={sf,small,bf},strut=off}

\newsavebox{\mybox}
\savebox{\mybox}{\parbox[b]{5cm}{\rawcaptionof{figure}[list entry]{This is my first custom caption and the baseline is correctly aligned with the picture gqp.}}}

\begin{tikzpicture}[remember picture, inner sep=0pt]
\node[anchor=base west,yshift=-\ht\mybox] at (BR){%
\fbox{\usebox{\mybox}}
};
\pgfresetboundingbox
\path[use as bounding box] (0,0);
\end{tikzpicture}

\begin{tikzpicture}[remember picture, inner sep=0pt]
\node[anchor=base east,yshift=-\dp\mybox] at (BL){%
\fbox{\usebox{\mybox}}
};
\pgfresetboundingbox
\path[use as bounding box] (0,0);
\end{tikzpicture}

\end{document}