5

I am trying to create some nice-looking captions for some photos. I do not want to adjust the aspect ratio of these photos, so I am including the keepaspectratio option in \includegraphics.

Inspired by Martin Scharrer's answer to the question Automatic width of floats, I have used a savebox to capture the width of my photos, and then I use this width in the \captionsetup command. This approach works well, except that I am noticing a rather strange phenomenon:

  • If the width option in \includegraphics is set to width=1\textwidth, then everything compiles as it should.
  • If the width option in \includegraphics is set to width=a\textwidth, where a is less than 1, then the caption will be offset to the right by about 2pt, and will thus not be correctly centered under the image.
  • If the width option in \includegraphics is set to width=b\textwidth, where b is greater than 1, then there will be a thin amount of white space between the caption and the image (although the caption will not be offset in this case).

Below is a MWE:

\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage{graphicx}
\usepackage{xcolor}
\usepackage{tgbonum}
\usepackage{tikz}
\usepackage{caption}
\usepackage{float}
\usepackage{tcolorbox}
\usepackage{calc}

%include own graphics path \graphicspath{{/Users/...}}

%%captions formatting%% \definecolor{captionColor}{RGB}{103,143,150} \DeclareCaptionFormat{customCaption}{% \begin{tcolorbox}[ nobeforeafter, colback=captionColor, arc=0pt, outer arc=0pt, boxrule=0pt, colupper=white, %fontupper=\normal, boxsep=0pt ] #1#2#3 \end{tcolorbox}% }

\begin{document}

The beginning of the document stretches the full text width.

\begin{minipage}[t]{0.60\textwidth}\vspace{0pt} There will be some text on the left side of the page. The start of this text needs to be vertically aligned with the top of the other minipage. \end{minipage} \quad \quad \quad \begin{minipage}[t]{0.29\textwidth}\vspace{0pt} %FIRST PHOTO %use savebox to get the width of photo1 \newsavebox\placeHolderOne \sbox\placeHolderOne{\includegraphics[width=.9\linewidth,height=.9\linewidth,keepaspectratio]{examplePhoto1}} %set the width of the caption to the width of photo1 \captionsetup{type=figure,width=\wd\placeHolderOne,format=customCaption,labelformat=empty,justification=raggedright,position=bottom,skip=0pt,textfont={it}} %include photo1, with caption \includegraphics[width=.9\linewidth,height=.9\linewidth,keepaspectratio]{examplePhoto1} {\caption[]{Caption is offset to the side when width < linewidth}} \vspace{6mm} %SECOND PHOTO %use savebox to get the width of photo2 \newsavebox\placeHolderTwo \sbox\placeHolderTwo{\includegraphics[width=1.2\linewidth,height=.9\linewidth,keepaspectratio]{examplePhoto2}} %set the width of the caption to the width of photo2 \captionsetup{type=figure,width=\wd\placeHolderTwo,format=customCaption,labelformat=empty,justification=raggedright,position=bottom,skip=0pt,textfont={it}} %include photo2, with caption \includegraphics[width=1.2\linewidth,height=.9\linewidth,keepaspectratio]{examplePhoto2} {\caption[]{A white space appears between image and caption when width>linewidth}} \end{minipage} \end{document}

A screenshot of my output

Sam
  • 141
  • note for the landscape pictures there is no need to box and measure you know in advance the width is .9\linewidth as you are scaling it to that size, so you can simply set teh caption width to the same – David Carlisle Sep 09 '21 at 22:29
  • why are you scaling the height of the image to a fraction of the line width ? height=.9\linewidth didn't you intend \textheight there? – David Carlisle Sep 09 '21 at 22:30
  • @David (1) You make a valid point in your first comment: I do know the width of the landscape photos. But I still want to use the savebox and measure setup because I want a setup that does not require me to know whether the photo width will exceed its height (especially as I might be using this setup for multiple photos) – Sam Sep 09 '21 at 23:38
  • @David (2) (2) I did actually mean height=.9\linewidth, although I admit it might not have been the most logical choice. My thought behind this was that linewidth would be my unit, and all dimensions would be in terms of this unit (having a unit defined this way seems (at least to me) helpful since the definition of the unit will change if I change the size of the minipage in which this unit lives) – Sam Sep 09 '21 at 23:40
  • normally you only specify one of width or height, the use case of specifying both and using keepaspectratio was to scale to fit a given area making one dimension as large as possible, if you specify both in terms of linewidth, the image may not be scaled full width to avoid the height becoming more than linewidth even if it would actually scale laregr in the available space. – David Carlisle Sep 09 '21 at 23:44
  • @David: I'm a little confused here. If it was true that I was facing both horizontal and vertical constraints for the allocated space in which my images could be displayed (and this is indeed true), would my approach make any more sense to you? Or would it still be true that I am doing things in a strange/non-standard way? – Sam Sep 10 '21 at 17:20

2 Answers2

3

This answer only solves the first problem,

Caption is offset to the side when width < linewidth

The caption option width=<length> not only sets the width of captions, but also centers the caption. What you see is the effect of centering.

To control both the caption width and the left margin, use margin={0pt, \dimexpr\linewidth-<desired width>}.

An example demonstrating the centering alignment of width=<length>:

\documentclass{article}
\usepackage{caption}
\usepackage[pass, showframe]{geometry}
\usepackage{graphicx}
\usepackage[T1]{fontenc}

\begin{document} \captionsetup{type=figure, width=3cm} \includegraphics[width=3cm]{example-image} \caption{|text\hfill text|}

\captionsetup{type=figure, width=6cm} \includegraphics[width=6cm]{example-image} \caption{|text\hfill text|} \end{document}

enter image description here

Your example, using margin={0pt,\dimexpr\linewidth-\wd\placeHolder(One|Two)} instead of width=\wd\placeHolder(One|Two), document class article, and images example-image-[ab] instead of examplePhoto[12]:

\documentclass{article}

\usepackage[T1]{fontenc} \usepackage[utf8]{inputenc} \usepackage{graphicx} \usepackage{xcolor} \usepackage{tgbonum} \usepackage{tikz} \usepackage{caption} \usepackage{float} \usepackage{tcolorbox} \usepackage{calc}

%include own graphics path \graphicspath{{/Users/...}}

%%captions formatting%% \definecolor{captionColor}{RGB}{103,143,150} \DeclareCaptionFormat{customCaption}{% \begin{tcolorbox}[ nobeforeafter, colback=captionColor, arc=0pt, outer arc=0pt, boxrule=0pt, colupper=white, %fontupper=\normal, boxsep=0pt ] #1#2#3 \end{tcolorbox}% }

\begin{document}

The beginning of the document stretches the full text width.

\begin{minipage}[t]{0.60\textwidth}\vspace{0pt} There will be some text on the left side of the page. The start of this text needs to be vertically aligned with the top of the other minipage. \end{minipage} \quad \quad \quad \begin{minipage}[t]{0.29\textwidth}\vspace{0pt} %FIRST PHOTO %use savebox to get the width of photo1 \newsavebox\placeHolderOne \sbox\placeHolderOne{\includegraphics[width=.9\linewidth,height=.9\linewidth,keepaspectratio]{example-image-a}} %set the width of the caption to the width of photo1 \captionsetup{type=figure,margin={0pt,\dimexpr\linewidth-\wd\placeHolderOne},format=customCaption,labelformat=empty,justification=raggedright,position=bottom,skip=0pt,textfont={it}} %include photo1, with caption \includegraphics[width=.9\linewidth,height=.9\linewidth,keepaspectratio]{example-image-a} {\caption[]{Caption is offset to the side when width < linewidth}} \vspace{6mm} %SECOND PHOTO %use savebox to get the width of photo2 \newsavebox\placeHolderTwo \sbox\placeHolderTwo{\includegraphics[width=1.2\linewidth,height=.9\linewidth,keepaspectratio]{example-image-b}} %set the width of the caption to the width of photo2 \captionsetup{type=figure,margin={0pt,\dimexpr\linewidth-\wd\placeHolderTwo},format=customCaption,labelformat=empty,justification=raggedright,position=bottom,skip=0pt,textfont={it}} %include photo2, with caption \includegraphics[width=1.2\linewidth,height=.9\linewidth,keepaspectratio]{example-image-b} {\caption[]{A white space appears between image and caption when width>linewidth}} \end{minipage} \end{document}

enter image description here

muzimuzhi Z
  • 26,474
3

Another approach in which both the figure and its caption are typeset by a customed \tcbox. Note tcolorbox won't use caption settings done by caption package, so you have to do it yourself.

\documentclass{article}
\usepackage[T1]{fontenc}

\usepackage{tgbonum} \usepackage{tcolorbox} \tcbuselibrary{skins}

\definecolor{captionColor}{RGB}{103,143,150}

\newtcbox[use counter*=figure, list inside=lof]\tcbfigure[1]{ enhanced, nobeforeafter, colback=captionColor, colbacktitle=captionColor, arc=0pt, outer arc=0pt, boxrule=0pt, boxsep=0pt, leftupper=0pt, rightupper=0pt, top=0pt, bottom=0pt, toptitle=3mm, bottomtitle=3mm, flip title, fonttitle=\itshape, % before title=\RaggedRight, % need ragged2e package #1 }

\begin{document} The beginning of the document stretches the full text width.

\begin{minipage}[t]{0.60\textwidth}\vspace{0pt} There will be some text on the left side of the page. The start of this text needs to be vertically aligned with the top of the other minipage. \end{minipage} % \quad \quad \quad % \begin{minipage}[t]{0.29\textwidth}\vspace{0pt} \tcbfigure{title=Caption is offset to the side when width < linewidth} {\includegraphics[width=.9\linewidth]{example-image}}\par \vspace{6mm}

\tcbfigure{title=A white space appears between image and caption when width > linewidth} {\includegraphics[width=1.2\linewidth]{example-image}} \end{minipage} \end{document}

enter image description here

muzimuzhi Z
  • 26,474
  • This is a really nice approach - much, much cleaner than my idea with the save box!! I am accepting this answer, but I had one question: I did a search for the tcbfigure command in the tcolorbox manual, and could not find anything. I have never seen this command before...can you point me in the direction of the documentation for this command? – Sam Sep 10 '21 at 17:37
  • \tcbfigure is defined by \newtcbox, noted the line \newtcbox[use counter*=figure, list inside=lof]\tcbfigure[1]{<tcb options>}. – muzimuzhi Z Sep 10 '21 at 20:02