Problem with setting correct custom page size with 'geometry' in xelatex

Well, finally I think I got somewhere with switching between custom page sizes and page layouts with geometry in mid-document (the MWE is below (see also previous post on geometry's pass); click on image for full size):

First of all, a couple of words about geometry:

  • You can call \geometry only in preamble, and there multiple commands have simply the effect of replacing previously set values of parameters
  • geometry first calculates a layout (margins etc) after \begin{document}, which the manual calls layout L1
  • The command \restoregeometry can only restore L1!
  • The command \newgeometry can only be called after \begin{document} (and thus, after L1 is created)
  • Layouts created with \newgeometry can be \save/\loadgeometry-ied
  • \newgeometry does NOT care about \paperwidth/height! In fact, if you thought you could cheat with:
    \setlength{\paperwidth}{100mm}
    \setlength{\paperheight}{100mm}
    \newgeometry{twoside,...}
    , geometry will care not a bit, and will in fact reset paperwidth/height back to the documentclass setting (or I guess, the last named page size setting in geometry, if any).
  • However, geometry does take into account parameters called layoutwidth and layoutheight, which serve the purpose of page size limits.

Thus, how geometry calculates margins, is independent of the actual page setting in \paperwidth/\pdfpagewidth. Having all this in mind, the following checklist can be submitted for managing custom page sizes and layouts:

  • Prepare in preamble custom page sizes as new lengths
  • Prepare in preamble commands \generatePageLayouts, \switchToLayoutPageA and \switchToLayoutPageB
  • After \begin{document}, call first \generatePageLayouts, not doing any actual page size switching with \paperwidth/\pdfpagewidth
    • it will call \newgeometry with layoutwidth/height set to respective custom pagesize newlengths, and then \savegeometry
  • Then \switchToLayoutPageA and typeset content
    • it will do actual page switching with \paperwidth/\pdfpagewidth, and call respective loadgeometry
  • Then \switchToLayoutPageB and typeset content
    • it will -- || --

Note that even \loadgeometry resets \paperwidth/height - which can be seen on the image, in the table produced by layouts: there it is reported, on both pages, that: \paperwidth = 614.295pt - even if neither of the pages is of that size:

$ pdfinfo -box -f 1 -l 2 test.pdf | grep Page
Pages:          2
Page    1 size: 300 x 400 pts
Page    2 size: 400 x 500 pts

In any case, here is the MWE, compiled with xelatex test.tex:

\documentclass{article}
% reminder: US letter: 596pt x 795pt

\newlength{\pagewidthA}
\newlength{\pageheightA}
\setlength{\pagewidthA}{300bp}
\setlength{\pageheightA}{400bp}

\newlength{\pagewidthB}
\newlength{\pageheightB}
\setlength{\pagewidthB}{400bp}
\setlength{\pageheightB}{500bp}

\newlength{\stockwidth}
\newlength{\stockheight}


\usepackage{geometry}

% these seem to have NO effect in preamble!
% geometry first has effect after begin{document}!
\pdfpagewidth=\pagewidthA \pdfpageheight=\pageheightA % to enforce?
\paperwidth=\pagewidthA \paperheight=\pageheightA     % for TikZ
\stockwidth=\pagewidthA \stockheight=\pageheightA % hyperref (memoir)?!

% this command will take effect into L1 layout just after \begin{document}
\geometry{twoside,inner=50bp,outer=30bp,top=50bp,bottom=50bp}


\usepackage{tikz,enumitem}
\usepackage{fix-cm}

\usepackage{fontspec}
\defaultfontfeatures{Ligatures=TeX}
\setmainfont{Junicode}

\usepackage{layouts}

\usepackage{etoolbox}
\patchcmd{\drawpage}{\ifdrawparameters}{\iftrue}%
  {\typeout{^^J*******\string\drawpage fixed*******^^J}}%
  {\typeout{^^J*******\string\drawpage not fixed*******^^J}}

\usepackage{lipsum}



\makeatletter
\newcommand{\printpagevalues}{%
  % from geometry.sty:
  * paper: \ifx\Gm@paper\@undefined<default>\else\Gm@paper\fi \\%
  * layout: \ifGm@layout<custom>\else<same size as paper>\fi \\%
  \@ifundefined{ifGm@layout}{}{%
  \ifGm@layout
  * layout(width,height): (\the\Gm@layoutwidth,\the\Gm@layoutheight) \\%
  \fi
  * layoutoffset:(h,v)=(\the\Gm@layouthoffset,\the\Gm@layoutvoffset) \\%
  }%
  \pagevalues % from package layouts
}
\makeatother

\newcommand{\generatePageLayouts}{%
  % this command must be called after \begin{document}!

  % geometry needs layoutwidth - cause it ignores the above paper sizes!
  % layoutwidth=148mm ok, layoutwidth=\paperwidth NOT ok
  % paperwidth gets reset again internally in newgeometry: in log: *geometry* verbose mode: * layout(width,height): (614.295pt,794.96999pt)
  % but by using \stockwidth, which here is just a custom length: * layout(width,height): (421.10078pt,597.50787pt)

  \newgeometry{layoutwidth=\pagewidthA,layoutheight=\pageheightA,left=1mm,right=5mm,bottom=1mm,top=1mm}
  \savegeometry{LayoutPageA}

  \newgeometry{layoutwidth=\pagewidthB,layoutheight=\pageheightB,twoside,inner=2.5cm,outer=0.5cm,top=1.5cm,bottom=1.5cm}
  \savegeometry{LayoutPageB}
}

\newcommand{\switchToLayoutPageA}{%
  % doesn't include page sizes; so page size too:
  \pdfpagewidth=\pagewidthA \pdfpageheight=\pageheightA % for PDF output
  \paperwidth=\pagewidthA \paperheight=\pageheightA     % for TikZ
  \stockwidth=\pagewidthA \stockheight=\pageheightA % hyperref (memoir)?!
  \loadgeometry{LayoutPageA} % note; \loadgeometry may reset paperwidth/h!
}

\newcommand{\switchToLayoutPageB}{%
  % doesn't include page sizes; so page size too:
  \pdfpagewidth=\pagewidthB \pdfpageheight=\pageheightB % for PDF output
  \paperwidth=\pagewidthB \paperheight=\pageheightB     % for TikZ
  \stockwidth=\pagewidthB \stockheight=\pageheightB % hyperref (memoir)?!
  \loadgeometry{LayoutPageB} % note; \loadgeometry may reset paperwidth/h!
}

\fontspec[Scale=1.0]{Junicode}



\begin{document}
  % here geometry layout L1 is instantiated;
  % without anything else, paper size defaults to US letter!
  % \restoregeometry command restores L1!!

  \fontsize{8}{9}\selectfont % this nowork in preamble!


  % generate page layouts first based on layoutwidth as page size;
  % don't switch actual page sizes yet:
  \generatePageLayouts{}


  %%% start with content

  % start with LayoutPageA (includes switching page size)
  \switchToLayoutPageA{}


    \pagestyle{empty} % no page numbers here
    \\
     \the\paperwidth
    \lipsum[1]
    \printpagevalues{}
    \clearpage

  % switch to LayoutPageB (includes switching page size)
  \switchToLayoutPageB{}


    % start page numbering here ("this will reset the page number"):
    \pagenumbering{arabic}
    % make page numbers visible
    \pagestyle{plain}


    \the\paperwidth
    \lipsum[1]

    Trying

    some

    text

    \printpagevalues{}

\end{document}

And finally - here is how the above image was generated:

convert -density 150 -bordercolor LimeGreen -border 2 test.pdf[0] test1.png
convert -density 150 -bordercolor LimeGreen -border 2 test.pdf[1] test2.png
montage test1.png test2.png -geometry +2+2 -tile 2x1 test.png

Well, hope this helps someone,
Cheers!