2

In the MWE below, which currently results with this output (click for full-res):

test.png

... I want to:

  • Arrange four images in 2 rows, 2 columns, for which I've used a \matrix of \tikz nodes,
  • Have them all rotated on the page, including the caption,
  • Scale these images, such that they fill out remaining page space (or, fit their respective container nodes) - while keeping aspect ratio, and respecting the row sep and column sep of the \matrix
  • Annotate them with, say, tikz \draw commands (in principle, I'd add red rectangle borders around the circles on the images, but here they're just centered for the sake of simplicity).

Here are the problems in the current example:

  • The \nodes in the \matrix do scale according to page height (as they are rotated, with their width) - but the rotated nodes' height spills over the page width
  • The easiest way for me to obtain the coordinates of the annotating rectangles, is to use tikzedt, setting the image width to 10cm; and ultimately using the numbers produced (e.g. \draw[rd] (1.1,1.1) node (f1) {} rectangle (-1.1,-1.1);) as scaling factors in respect to the final image width (e.g. \draw[rd] (1.1\imw,1.1\imw) node (f1) {} rectangle (-1.1\imw,-1.1\imw);). The problem is, here I do not know what the final image width is, since the images are supposed to be scaled

Also, in the MWE, also the caption leaks outside the page margin - but that might actually be OK in this case, given how wide the page margins are. So I'd like to know how to achieve this in both cases: both with the caption fitting inside the page boundaries; and with the caption sitting outside page boundaries, and only the matrix of node/images fitting inside.

So, what would be the easiest way, to achieve scaling of images, keeping aspect ratio, into a matrix of nodes that scales to (fits) the page size inside the margins - both with the caption sitting inside, and outside, the page margin boundaries; and obtaining their final sizes, so as to use them for annotation drawings' coordinates?


EDIT: Just figured out that I mixed up the widths and heights for the images in the MWE below; so if in the MWE below all instances of max size={0.5\textwidth}{0.5\textheight} with max size={0.5\textheight}{0.5\textwidth} are replaced, I get the much more expected output:

test2.png

The scale size of the images now seems OK (though note that img1, since it is smaller than the node bounds, doesn't scale up - that is however no problem in this case) - but the positioning, as a whole, is still off in respect to page margin boundaries (and it seems kinda related to the caption); so the rest of the question(s) still stand(s)...


The MWE code:

\documentclass[10pt,twoside,openright]{book}

% to generate images, run the first time with:
% pdflatex -shell-escape test.tex
% (ImageMagick `convert` commands tested in `bash` shell)
\immediate\write18{
  convert -size 200x100 gradient:\#4b4-\#bfb -fill gradient:green-yellow -draw 'circle 50,30 50,50' img1.png ;
  convert -size 100x200 gradient:\#44b-\#bbf -fill gradient:green-yellow -draw 'circle 70,130 70,150' img2.png ;
  convert -size 300x200 gradient:\#b44-\#fbb -fill gradient:blue-yellow -draw 'circle 250,30 250,50' img3.png ;
  convert -size 200x300 gradient:\#4bb-\#ffb -fill gradient:blue-yellow -draw 'circle 70,230 70,250' img4.png ;
}

\usepackage{tikz}
\usepackage[export]{adjustbox}

\pagecolor{yellow!10} % \usepackage{xcolor}

\usepackage{lua-visual-debug} % compile with lualatex test.tex, for visual indication of margins

% both of these use adjustbox:
% http://tex.stackexchange.com/questions/32886/how-to-fit-a-large-figure-to-page
% http://tex.stackexchange.com/questions/44427/rotate-picture-with-caption
% note: \draw tikz dimensions: in unit centimeter

\begin{document}

\begin{figure}[p]
  \begin{adjustbox}{addcode={\begin{minipage}{\width}}{\caption{%
      Here is a caption of the figure which is so long that
      it has to be wrapped over multiple lines, but should
      not exceed the width (height after the rotation) of the image.
      }\end{minipage}},rotate=90,center}
      %
      %\includegraphics[scale=.6]{test/picture.png}%
      %
      \begin{tikzpicture}[
        ns/.style={inner sep=0pt,outer sep=0pt},
        mw/.style={minimum width=0.5\textheight, minimum height=0.5\textwidth},
        rd/.style={draw=red,line width=2pt},
      ]
      \matrix[ns,row sep=1mm,column sep=1mm] {
        % row 1, col 1:
        \node[ns,mw,draw] {%
          \includegraphics[max size={0.5\textwidth}{0.5\textheight},keepaspectratio]{img1.png}%
        };%
        \draw[rd] (1.1,1.1) node (f1) {} rectangle (-1.1,-1.1);%
        &% %end column%
        % row 1, col 2:
        \node[ns,mw,draw] {
          \includegraphics[max size={0.5\textwidth}{0.5\textheight},keepaspectratio]{img2.png}%
        };%
        \draw[rd] (1.1,1.1) node (f2) {} rectangle (-1.1,-1.1);%
        \\% %end row%
        % row 2, col 1:
        \node[ns,mw,draw] {
          \includegraphics[max size={0.5\textwidth}{0.5\textheight},keepaspectratio]{img3.png}%
        };%
        \draw[rd] (1.1,1.1) node (f3) {} rectangle (-1.1,-1.1);%
        &% %end column%
        % row 2, col 2:
        \node[ns,mw,draw] {
          \includegraphics[max size={0.5\textwidth}{0.5\textheight},keepaspectratio]{img4.png}%
        };%
        \draw[rd] (1.1,1.1) node (f4) {} rectangle (-1.1,-1.1);%
        \\% %end row%
      };
      \end{tikzpicture}
      %
  \end{adjustbox}
\end{figure}


\end{document}
2

1 Answer 1

2

Ok, I think I got it; the MWE below results with this (click for high-res):

test.png

... and the boxes and images fit to the space of the page with the caption inside (ATM, I couldn't even imagine what it would take to have the caption outside, on the page margin :) ).

Briefly, the trick is this:

  • First, as per Measuring/getting size of caption before it is typeset?, to get the size of the caption before the images are typeset, we should typeset the caption in a \savebox, inside the {figure}, but before the main {adjustbox} starts
    • At that point, once we have the typeset caption box size, we can also do relevant calculations for the individual node widths/heights

Essentially, this is all that is needed for the images / caption to be typeset like on the answer; but it is not enough for relative image size referencing for the annotation.

First I thought the fitting node style (e.g. as in Montage multiple PDF images, scaled to each other's dimensions, on a single PDF page?; see also code below) can be used, but that always crashed with ! Dimension too large., which makes sense once I realized that everywhere in those nodes, \pgf@pathmaxx and such are always +/- 16000pt. Then I noted in the tikz manual there is a \pgf@picmaxx and related, and those do indeed provide a more reasonable estimate - but only after the node is placed (so those can't really be used to set a node size with fitting node either). And still, those more reasonable estimates don't seem to depend on the final size of the image either. But:

  • Thankfully, it turns out the \adjustbox can save the final dimensions it included the image with, with keys like gstore width=\adjw

So basically, instead of \node{ \includegraphics[max size={..., one would have to use \node{ \begin{adjustbox}{max size={...,gstore width={... \includegraphics... (not even sure if the outer wrapping \node is needed - yes it is, because of outer \matrix); then add annotated draws and such in respect to the length that gstore width saved (and not in respect to the size of the outer wrapping node).

As a test, those red/violet squares are all supposed to inscribe a rectangle half the dimensions of the final size of the scaled images, using a relative reference like 0.25\adjw - and seemingly, it works. I wish there was an easier way to do this, however...

Anyways, here's the MWE code (sorry for the mess):

\documentclass[10pt,twoside,openright]{book}

% to generate images, run the first time with:
% pdflatex -shell-escape test.tex
% (ImageMagick `convert` commands tested in `bash` shell)
\immediate\write18{
  convert -size 200x100 gradient:\#4b4-\#bfb -fill gradient:green-yellow -draw 'circle 50,30 50,50' img1.png ;
  convert -size 100x200 gradient:\#44b-\#bbf -fill gradient:green-yellow -draw 'circle 70,130 70,150' img2.png ;
  convert -size 300x200 gradient:\#b44-\#fbb -fill gradient:blue-yellow -draw 'circle 250,30 250,50' img3.png ;
  convert -size 200x300 gradient:\#4bb-\#ffb -fill gradient:blue-yellow -draw 'circle 70,230 70,250' img4.png ;
}

\usepackage{tikz}
\usetikzlibrary{calc}
\usetikzlibrary{fit}
\usepackage[export]{adjustbox}

\pagecolor{yellow!10} % \usepackage{xcolor}

\usepackage{lua-visual-debug} % compile with lualatex test.tex, for visual indication of margins
\usepackage{trace}

% both of these use adjustbox:
% https://tex.stackexchange.com/questions/32886/how-to-fit-a-large-figure-to-page
% https://tex.stackexchange.com/questions/44427/rotate-picture-with-caption
% note: \draw tikz dimensions: in unit centimeter

\makeatletter
\tikzset{ %https://tex.stackexchange.com/questions/47704
  fitting node/.style={
    inner sep=0pt,
    fill=none,
    draw=none,
    %reset transform,
    fit={(\pgf@pathminx,\pgf@pathminy) (\pgf@pathmaxx,\pgf@pathmaxy)},
  },
  picfitting node/.style={ % also this: ! Dimension too large.
    inner sep=0pt,
    fill=none,
    draw=none,
    %reset transform,
    fit={(\pgf@picminx,\pgf@picminy)(\pgf@picmaxx,\pgf@picmaxy)},
  },
  reset transform/.code={\pgftransformreset},
  tt/.code={\pgf@relevantforpicturesizetrue \typeout{tt \the\pgf@pathminx,\the\pgf@pathminy,\the\pgf@pathmaxx,\the\pgf@pathmaxy; \the\pgf@picminx,\the\pgf@picminy,\the\pgf@picmaxx,\the\pgf@picmaxy; }},
}
\makeatother

\begin{document}

\begin{figure}[p]
  % https://tex.stackexchange.com/questions/227145/measuring-getting-size-of-caption-before-it-is-typeset
  \newsavebox{\boxcapt}% is allocated (though not set) globally now, https://tex.stackexchange.com/questions/7134/making-register-declarations-local-undef
  \savebox{\boxcapt}{%
  \parbox{\textheight}{% \width here is undefined (\adjustbox is below)
    \caption{%
      Here is a caption of the figure which is so long that
      it has to be wrapped over multiple lines, but should
      not exceed the width (height after the rotation) of the image.
    }%
  }% %end \parbox%
  }% %end \savebox%
  % prep calcs
  \newlength{\grsep}\setlength{\grsep}{1mm}%
  \newlength{\gcsep}\setlength{\gcsep}{1mm}%
  \newlength{\gnw}\newlength{\gnh}% node w, h (when rotated)
  \setlength{\skip0}{\dimexpr\ht\boxcapt+\dp\boxcapt}%
  % -1pt here just to avoid complaints: LaTeX Warning: Float too large for page by 0.79996pt on input line 153.
  \pgfmathsetlength{\gnw}{0.5*(\textheight-\gcsep-8*\pgflinewidth)-1pt}%
  \pgfmathsetlength{\gnh}{0.5*(\textwidth-\grsep-\the\skip0-8*\pgflinewidth)-1pt}%
  \global\grsep=\grsep\global\gcsep=\gcsep%
  \global\gnw=\gnw\global\gnh=\gnh%
  \newlength{\adjw}\newlength{\adjh}
  %
  \begin{adjustbox}{%
    precode={\begin{minipage}{\width}},
    appcode={% addcode= code after:
      %\typeout{boxcapt out:  wd is: \the\wd\boxcapt, ht is: \the\ht\boxcapt, dp is: \the\dp\boxcapt ; skip1: \the\skip1; skip3: \the\skip3; glw,h: \the\globimw, \the\globimh; tw \the\textwidth}% all are here
      \break% same w/ \linebreak, \\ or \newline
      \usebox{\boxcapt}% place the caption, finally
      \end{minipage}%
    },
    rotate=90,center%
  }% %closing of \begin{adjustbox}%
      %
      \begin{tikzpicture}[
        remember picture,
        ns/.style={inner sep=0pt,outer sep=0pt},
        mw/.style={minimum width=\gnw, minimum height=\gnh},
        rd/.style={draw=red,line width=1pt},
        rdb/.style={draw=red!60!blue,line width=2pt},
        %tt/.code={\makeatletter\typeout{tt \the\pgf@pathminx,\the\pgf@pathminy,\the\pgf@pathmaxx,\the\pgf@pathmaxy}\makeatother}, % have to wrap w makeatletter outside
      ]
      \matrix[ns,row sep=\grsep,column sep=\gcsep] {
        % row 1, col 1:
        \node[ns,mw,draw,tt] (n1) {%
          \tikz\node[ns,remember picture, overlay, tt] (n1a) {% fitting node: ! Dimension too large.
          \begin{adjustbox}{max size={\gnw}{\gnh},gstore width=\adjw,gstore totalheight=\adjh}%
          \includegraphics{img1.png}%
          \end{adjustbox}%
          };%
          %\typeout{\meaning\width,\meaning\height}% undefined by now
          % tt otputs always +- 16000; but this:
          \makeatletter\typeout{\the\adjw, \the\adjh -- \the\pgf@pathminx,\the\pgf@pathminy,\the\pgf@pathmaxx,\the\pgf@pathmaxy; \the\pgf@picminx,\the\pgf@picminy,\the\pgf@picmaxx,\the\pgf@picmaxy;}\makeatother%
          % outputs: 16000.0pt,16000.0pt,-16000.0pt,-16000.0pt; -136.48868pt,-77.37756pt,136.48868pt,77.37756pt
        };%
        % also here: -136.48868pt,-77.37756pt,136.48868pt, 77.37756pt;
        \makeatletter\typeout{\the\adjw, \the\adjh -- \the\pgf@pathminx,\the\pgf@pathminy,\the\pgf@pathmaxx,\the\pgf@pathmaxy; \the\pgf@picminx,\the\pgf@picminy,\the\pgf@picmaxx,\the\pgf@picmaxy;}\makeatother%
        \path let \p1=(n1a.north east), \p2=(n1a.south west), \p3=($(\p1)-(\p2)$) in node{\typeout{\x3, \y3}};%
        \draw[rd] (1.1,1.1) node (f1) {} rectangle (-1.1,-1.1);%
        \draw[rdb] (0.25\adjw,0.25\adjh) node (f1a) {} rectangle (-0.25\adjw,-0.25\adjh);%
        &% %end column%
        % row 1, col 2:
        \node[ns,mw,draw,tt] (n2) {
          \begin{adjustbox}{max size={\gnw}{\gnh},gstore width=\adjw,gstore totalheight=\adjh}%
          \includegraphics{img2.png}%
          \end{adjustbox}%
        };%
        \makeatletter\typeout{\the\pgf@pathminx,\the\pgf@pathminy,\the\pgf@pathmaxx,\the\pgf@pathmaxy; \the\pgf@picminx,\the\pgf@picminy,\the\pgf@picmaxx,\the\pgf@picmaxy;}\makeatother%
        \path let \p1=(n2.north east), \p2=(n2.south west), \p3=($(\p1)-(\p2)$) in node{\typeout{\x3, \y3}};%
        \draw[rd] (1.1,1.1) node (f2) {} rectangle (-1.1,-1.1);%
        \draw[rdb] (0.25\adjw,0.25\adjh) node (f1a) {} rectangle (-0.25\adjw,-0.25\adjh);%
        \\% %end row%
        % row 2, col 1:
        \node[ns,mw,draw] (n3) {
          \begin{adjustbox}{max size={\gnw}{\gnh},gstore width=\adjw,gstore totalheight=\adjh}%
          \includegraphics{img3.png}%
          \end{adjustbox}%
        };%
        \path let \p1=(n3.north east), \p2=(n3.south west), \p3=($(\p1)-(\p2)$) in node{\typeout{\x3, \y3}};%
        \draw[rd] (1.1,1.1) node (f3) {} rectangle (-1.1,-1.1);%
        \draw[rdb] (0.25\adjw,0.25\adjh) node (f1a) {} rectangle (-0.25\adjw,-0.25\adjh);%
        &% %end column%
        % row 2, col 2:
        \node[ns,mw,draw] (n4) {
          \begin{adjustbox}{max size={\gnw}{\gnh},gstore width=\adjw,gstore totalheight=\adjh}%
          \includegraphics[max size={\gnw}{\gnh},keepaspectratio]{img4.png}%
          \end{adjustbox}%
          %\typeout{\the\wd\collectedbox,\the\ht\collectedbox,\the\dp\collectedbox}% 0 by now
        };%
        \path let \p1=(n4.north east), \p2=(n4.south west), \p3=($(\p1)-(\p2)$) in node{\typeout{\x3, \y3}};%
        \draw[rd] (1.1,1.1) node (f4) {} rectangle (-1.1,-1.1);%
        \draw[rdb] (0.25\adjw,0.25\adjh) node (f1a) {} rectangle (-0.25\adjw,-0.25\adjh);%
        \\% %end row%
      };
      \end{tikzpicture}
      %
  \end{adjustbox}
\end{figure}


\end{document}

You must log in to answer this question.

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