2

How to automatically scale a centred image to be (at the same time to being centred) left aligned with a hanging caption?

enter image description here

MWE with guessed image widths:

\documentclass{book}

\usepackage{graphicx}   
\usepackage{caption}                

\captionsetup{%
    singlelinecheck=false,
    format=hang
}

\begin{document}

\chapter{test}

\begin{figure}[htbp]
    \centering
    \includegraphics[width=.7\textwidth]{example-image}
    \caption{Text}
\end{figure}

\setcounter{figure}{1000}

\begin{figure}[htbp]
    \centering
    \includegraphics[width=.62\textwidth]{example-image}
    \caption{Text}
\end{figure}


\end{document}

3 Answers 3

2
+100

Due to a missunderstanding in my first answer I adapted the caption to the image. Here the image width is adapted to the caption. It works with different label formats.

For this a new caption format was written, which is a copy of the original hang plus a macro to calculate the \imagewidth. The caption must be known before the image, so the command \captionafter sets it into a box. The latter is then printed with \printcaption after the image.

Using these macros will result in this:

enter image description here

The code:

\documentclass{book}
\usepackage[showframe]{geometry} % just for checking centering
\usepackage{etoolbox}
\usepackage{graphicx}   
\usepackage{caption}                

\makeatletter
\newlength{\imagewidth}

\newcommand*{\set@imagewidth}{%
    \global\imagewidth\dimexpr\textwidth-2\caption@hangindent
}

% copoied from caption3.sty, renamed and added \set@imagewidth
\DeclareCaptionFormat{myhang}[#1#2#3\par]{%
  \caption@ifin@list\caption@lsepcrlist\caption@lsepname
    {\caption@Error{%
       The option `labelsep=\caption@lsepname' does not work\MessageBreak
       with `format=hang'}}%
    {\@hangfrom{#1#2}%
     \advance\caption@parindent\hangindent
     \advance\caption@hangindent\hangindent
     % added
     \set@imagewidth
     \caption@@par#3\par}}

% caption must be known to set \imagewidth, so store it in a box
\newbox\captionafterbox
\newcommand{\captionafter}[2][]{%
    \setbox\captionafterbox\vbox{\caption[#1]{#2}}%
}
% and print it later
\newcommand{\printcaption}{\box\captionafterbox}

\makeatother

\captionsetup{%
    singlelinecheck=false,
    format=myhang
}

% just for testing
\setcounter{totalnumber}{4}

\begin{document}

\chapter{test}

\begin{figure}[htbp]
    \centering
    \captionafter{Text}
    \includegraphics[width=\imagewidth,height=1cm]{example-image}
    \printcaption
\end{figure}

\begin{figure}[htbp]
    \centering
    \captionsetup{labelfont=bf}
    \captionafter{Text}
    \includegraphics[width=\imagewidth,height=1cm]{example-image}
    \printcaption
\end{figure}

\setcounter{figure}{1000}

\begin{figure}[htbp]
    \centering
    \captionafter{A very long caption text, which needs more than one line. Just some more text to fill it.}
    \includegraphics[width=\imagewidth,height=1cm]{example-image}
    \printcaption
\end{figure}

\setcounter{figure}{1000000}

\begin{figure}[htbp]
    \centering
    \captionafter{A very long caption text, which needs more than one line. Just some more text to fill it. Amd make it even longer.}
    \includegraphics[width=\imagewidth,height=1cm]{example-image}
    \printcaption
\end{figure}

\end{document}
3
  • Fantastic! Thank you very much for this nice and clean solution! Commented Nov 18, 2017 at 18:25
  • @samcarter Thank you very much for the nice blue box below the green hook :-)
    – Mike
    Commented Nov 21, 2017 at 22:02
  • Figured your answer would look better with more colour :) Your answer help me a lot! Commented Nov 21, 2017 at 22:08
1

As long as you set the width of the image manually (or know it), you can use this:

Edit: added a command to set up caption so it ocupies the rest of the line.

Edit 2: added onside to \captionsetup in \captionimagewidth;
added a new command \capimagewidth, which corrects width and indent, so for wide images the label ("Figure 1.1") doesn't move into the left margin.

\documentclass{book}
\usepackage[showframe]{geometry} % just for checking centering
\usepackage{etoolbox}
\usepackage{graphicx}   
\usepackage{caption}                

\captionsetup{%
    singlelinecheck=false,
}

\DeclareCaptionLabelFormat{myfigure}{\llap{#1 #2:\ }}
\captionsetup{labelformat=myfigure}

% Edit
\newlength{\capindent}
\newlength{\capwidth}
\newcommand{\captionimagewidth}[1]{%
    \capindent\dimexpr0.5\textwidth-#1/2\relax
    \capwidth\dimexpr\textwidth-\capindent
    \captionsetup{width=\capwidth,margin={\capindent,0pt},oneside}%
}

% Edit 2: added `oneside` to \captionsetup
%         correction for wide images
\newcommand{\capimagewidth}[1]{%
    \capindent\dimexpr0.5\textwidth-#1/2\relax
    % from your answer
    \addtocounter{figure}{1}%
    \settowidth{\capwidth}{%
        \figurename~\thefigure:\space% 
    }%
    \addtocounter{figure}{-1}%
    %
    \ifdim\capindent<\capwidth
        \capindent\capwidth
    \fi
    \capwidth\dimexpr\textwidth-\capindent
    \captionsetup{width=\capwidth,margin={\capindent,0pt},oneside}%
}

\begin{document}

\chapter{test}

\begin{figure}[htbp]
    \centering
    \includegraphics[width=0.3\textwidth]{example-image}
    \captionsetup{width=0.3\textwidth}
    \caption{Text}
\end{figure}

\setcounter{figure}{1000}

\begin{figure}[htbp]
    \centering
    \includegraphics[width=0.5\textwidth]{example-image}
    % old
    %\captionsetup{width=0.5\textwidth}
    % Edit
    \captionimagewidth{0.5\textwidth}
    \caption{A very long caption text, which needs more than one line. Just some more text to fill it.}
\end{figure}

\begin{figure}[htbp]
    \centering
    \includegraphics[width=0.9\textwidth]{example-image}
    \capimagewidth{0.9\textwidth}
    \caption{A very long caption text, which needs more than one line. Just some more text to fill it. Amd make it even longer.}
\end{figure}

\end{document}

Result after edit:

enter image description here

But for wide images, the label moves into the margin:

enter image description here

With new command from second edit:

enter image description here

Old result:

enter image description here

7
  • Thanks a lot for your answer! This is an interesting solution if the caption should not occupy the whole line. Commented Nov 18, 2017 at 0:19
  • @samcarter I added a solution, wich uses the rest of the line.
    – Mike
    Commented Nov 18, 2017 at 2:00
  • Thank you very much for your effort! Do you happen to see a way to move the "Figure xxxx" part to the begin of the line? Commented Nov 18, 2017 at 2:05
  • @samcarter does \DeclareCaptionLabelFormat{myfigure}{\llap{\hbox to \capindent{#1~#2:\hfill}}} do what you want? (This doesn't work with the first version.)
    – Mike
    Commented Nov 18, 2017 at 3:09
  • @samcarter And it doesn't work for wide images with the second version (\captionimagewidth). Where should the second line hang from, left of the image or right of the "Figure xxxx" part?
    – Mike
    Commented Nov 18, 2017 at 3:28
1

The following solution is a bit clumsy as it calculates the hanging indent of the caption by emulating the caption label ... this has the big drawback that it does not automatically adjust to the format of the caption, the font size and style.

\documentclass{book}

\usepackage{etoolbox}
\usepackage{graphicx}   
\usepackage{caption}                

\captionsetup{%
    singlelinecheck=false,
    format=hang
}

% calculate idention of caption
\newlength{\captionindent}
\AtBeginEnvironment{figure}{%
    \addtocounter{figure}{1}%
    \settowidth{\captionindent}{%
        Figure\space\thefigure:\space% 
    }%
    \addtocounter{figure}{-1}%
}

\begin{document}

\chapter{test}

\begin{figure}[htbp]
    \centering
    \includegraphics[width=\dimexpr\textwidth-2\captionindent\relax]{example-image}
    \caption{Text}
\end{figure}

\end{document}

You must log in to answer this question.

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