I would like to produce a pdf
document whose pages have various lengths and fixed widths.
An easier situation
The easiest case would be for instance: the first page has a length of 10cm
all the next pages have a length of 15cm
. But, what I am looking is more complicated. I wonder if it is possible.
The real situation
Here is what I would like to achieve:
- the first page has a variable length, depending of the content (cf. this question), which is at most
10cm
- the next pages have a length equal to
15cm
- the last page has a variable length, depending of the content, which is at most
15cm
Bounty-rewarded
For those interested, there will be bounties for answers.
"Bug" in Heiko's solution
The solution propped by Heiko, which is great by the way, seems to have problem handling the list. Here is a MWE that shows this problem. The problem is that when there is a list (an itemize
environment), the page change is done too early, and, as a result, the first page, whose height should be 8cm
in the following example, is too short.
\documentclass{article}
\usepackage%
[paperwidth=10.000000cm,
paperheight=8cm,
hmargin=1.000000mm,
top=1.000000mm,
bottom=1.000000mm]
{geometry}
\pagestyle{empty}
\flushbottom
\setlength{\maxdepth}{0pt}% to address the "third bug"
\setlength{\topskip}{0pt}% no space above the first line
% assuming the page number is the absolute page number
\usepackage{zref-totpages,zref-savepos}
\usepackage{atbegshi}
\makeatletter
\providecommand*{\zsaveposy}{\zsavepos}% for older zref-savepos
\def\@oddhead{\PosFirstHead\PosLastHead\hss}%
\def\@evenhead{\PosLastHead\hss}%
\newcommand*{\PosFirstHead}{%
\ifnum\value{page}=1 %
\zsaveposy{PosFirstHead}%
\global\let\PosFirstHead\@empty
\fi
}
\newcommand*{\PosLastHead}{%
\ifnum\value{page}=\ztotpages
\zsaveposy{PosLastHead}%
\global\let\PosLastHead\@empty
\fi
}
\AtBeginShipout{%
\ifnum\value{page}=1 %
\dimen@=\dimexpr
\zposy{PosFirstHead}sp-\headsep
-\zposy{PosFirst}sp%
\relax
\setbox\AtBeginShipoutBox=\vbox{%
\kern-\dimen@ %
\copy\AtBeginShipoutBox
}%
\advance\pdfpageheight by -\dimen@
\else
\ifnum\value{page}=\ztotpages
\advance\pdfpageheight by%
-\dimexpr
\textheight
-\zposy{PosLastHead}sp+\headsep
+\zposy{PosLast}sp%
\relax
\fi
\fi
}
\AtEndDocument{%
\par
\nobreak
\dimen@=\prevdepth
\ifdim\dimen@>\maxdepth
\kern-\maxdepth
\else
\ifdim\dimen@>0pt %
\kern-\dimen@
\fi
\fi
\zsaveposy{PosLast}%
}
\makeatother
\usepackage{lipsum}% provides dummy text
\interlinepenalty=-100
\begin{document}
\vspace*{\dimexpr0.000cm-\topskip plus 1fill}
\zsaveposy{PosFirst}
\nointerlineskip
This is a test. This is a longer sentence with some more words, isn't it? This is a test. This is a longer sentence with some more words, isn't it? This is a test. This is a longer sentence with some more words, isn't it? This is a test. This is a longer sentence with some more words, isn't it?
This is a test:
\begin{itemize}
\item Hello
\item This is a test. This is a longer sentence with some more words, isn't it? This is a test. This is a longer sentence with some more words, isn't it? This is a test.
\item Good Bye
\item Hello
\item This is a test. This is a longer sentence with some more words, isn't it? This is a test. This is a longer sentence with some more words, isn't it? This is a test.
\end{itemize}
This is a test. This is a longer sentence with some more words, isn't it? This is a test. This is a longer sentence with some more words, isn't it? This is a test. This is a longer sentence with some more words, isn't it? This is a test. This is a longer sentence with some more words, isn't it? This is a test. This is a longer sentence with some more words, isn't it? This is a test. This is a longer sentence with some more words, isn't it? This is a test. This is a longer sentence with some more words, isn't it? This is a test. This is a longer sentence with some more words, isn't it? This is a test. This is a longer sentence with some more words, isn't it? This is a test. This is a longer sentence with some more words, isn't it? This is a test. This is a longer sentence with some more words, isn't it? This is a test. This is a longer sentence with some more words, isn't it?
This is a test. This is a longer sentence with some more words, isn't it? This is a test. This is a longer sentence with some more words, isn't it? This is a test. This is a longer sentence with some more words, isn't it? This is a test. This is a longer sentence with some more words, isn't it?
This is a test. This is a longer sentence with some more words, isn't it? This is a test. This is a longer sentence with some more words, isn't it? This is a test. This is a longer sentence with some more words, isn't it? This is a test. This is a longer sentence with some more words, isn't it?
\end{document}
"Bug" in wipet's solution
I tried wipet's solution with the package mdframed
and it clashes. Here is a MWE. It produces a document with only one page.
\documentclass{article}
\usepackage[
paperwidth=15cm,
paperheight=15cm,
hmargin=1cm,
vmargin=0cm,
]{geometry}
\usepackage[framemethod=tikz, needspace=1.5cm]{mdframed}
\usepackage{lipsum}
\newmdenv[%
innerleftmargin = 2mm,
innerrightmargin = 2mm,
innertopmargin = 2mm,
innerbottommargin = 2mm,
leftmargin = 0mm,
rightmargin = 0mm,
splitbottomskip = 2mm,
splittopskip = 4mm,
middlelinewidth = 0mm,
linecolor = red,
backgroundcolor = red,
roundcorner = 0pt,
skipbelow = 0mm,
skipabove = 0mm,
]
{mybox}
\pagestyle{empty}
\topmargin=0pt % vertical shift of the text in the page
\pdfvorigin=0in % vertical margins above and below the text
\let\textheight=\vsize
\expandafter\let\csname @colht\endcsname=\vsize
\newdimen\topbotmargin
\topbotmargin=2\pdfvorigin \advance\topbotmargin by2\voffset
\headheight=0pt \headsep=0pt
\long\def\firstpage#1{\setbox0=\vbox{#1}\pdfpageheight=\ht0
\advance\pdfpageheight by\topbotmargin \vsize=\ht0 \box0 \vfil\break
\pdfpageheight=15cm \vsize=\pdfpageheight \advance\vsize by-\topbotmargin
}
\AtEndDocument{\pdfpageheight=\pagetotal \vsize=\pagetotal
\advance\pdfpageheight by\topbotmargin
}
\begin{document}
\begin{mybox}
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Ut purus elit, vestibulum ut, placerat ac, adipiscing vitae, felis. Curabitur dictum gravida mauris. Nam arcu libero, nonummy eget, consectetuer id, vulputate a, magna. Donec vehicula augue eu neque.
\end{mybox}
\lipsum[1-9]
\end{document}
Best Answer
The following example uses package
geometry
to set the page layout with page height 15cm for all pages. At the beginning of the first page and at the end of the last page a space of5cm plus 1fill
is added. It fills the remaining space and ensures that the contents is small enough for a maximum page height of 10cm.Position markers of package
zref-savepos
are set on the first page in the header and the start of the contents after the filler space. Packageatbegshi
is used to hook into the output routine. The free space is measured using the positions and the whole page is moved to the top by the amount of the free space and the page height is shortened accordingly.For the last page, the position markers are added in the header and the end of the contents. Again the page height is shortened by the amount of free space that is calculated via the position markers and the height of the text block (
\textheight
).For the previous action we must know the page number of the last pages. This is provided by package
zref-totpages
that stores the number of pages in\ztotpages
via the reference system. It is assumed that the page numbering of the document is absolute.Because both the reference for the number of pages and the position markers need an additional LaTeX run, three LaTeX runs are needed.
Both pdfTeX and LuaTeX support position markers (
\pdfsavepos
and\pdflastposy
are used by packagezref-savepos
) and the setting of the media size (\pdfpageheight
).\flushbottom
fills the text area to the bottom.\setlength{\maxdepth}{0pt}
avoids that the descenders of the last line are outside the text area. Important, if the vertical margins are zero. Then the descenders would be out of the page.\setlength{\topskip}{0pt}
and\nointerlineskip
after\zsavepos{PosFirst}
remove white space at the top of the text area.Older version with the constraint that the last page does not exceed 10 cm:
Workaround for
mdframed
versionThe environment of
mdframed
adds additional breakpoints (e.g. via\needspace
), which are preferred over the regular break points between lines.As workaround the
\interlinepenalty
can be set to a negative value (-100):A negative
\interlinepenalty
has its drawbacks (encouraging too early page breaks).An alternative would be to put the framed environment inside a non-breakable minipage that removes the additional breakpoints:
But then a longer
mybox
cannot be broken across pages.A more reliable solution can probably be provided by a rewrite/patch of the output routine. However, that might clash with packages like
longtable
, which uses their own modifications of the output routine.