我想要制作一份pdf
页面长度各异、宽度固定的文档。
更简单的情况
最简单的情况是:第一页的长度为 ,10cm
所有后续页面的长度为15cm
。但是,我正在寻找更复杂的情况。我想知道这是否可能。
真实情况
以下是我想要实现的目标:
- 第一页的长度是可变的,取决于内容(参见这个问题),最多
10cm
- 下一页的长度等于
15cm
- 最后一页的长度可变,取决于内容,最多为
15cm
赏金
对于那些感兴趣的人,回答问题将会获得赏金。
Heiko 解决方案中的“Bug”
顺便说一句,Heiko 提出的解决方案非常棒,但似乎在处理列表时存在问题。下面是一个显示此问题的 MWE。问题是,当有列表(环境itemize
)时,页面更改完成得太早,结果,第一页(8cm
在下面的示例中,其高度应该是)太短了。
\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}
wipet 解决方案中的“Bug”
我尝试使用 wipet 的解决方案来处理该软件包mdframed
,但发生了冲突。这是 MWE。它生成只有一页的文档。
\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}
答案1
以下示例使用包geometry
为所有页面设置页面高度为 15cm 的页面布局。在第一页的开头和最后一页的结尾5cm plus 1fill
添加了一个空格。它填充了剩余的空间并确保内容足够小,最大页面高度为 10cm。
包的位置标记zref-savepos
设置在页眉的第一页上以及填充空间之后的内容开头。包atbegshi
用于挂接到输出例程中。使用位置测量可用空间,并将整个页面移动到顶部,移动量为可用空间量,页面高度相应缩短。
对于最后一页,位置标记被添加到页眉和内容末尾。页面高度再次缩短,缩短量是通过位置标记和文本块高度计算得出的可用空间量 ( \textheight
)。
对于上一个操作,我们必须知道最后几页的页码。这是由通过参考系统zref-totpages
存储页数的包提供的\ztotpages
。假设文档的页码是绝对的。
由于页数参考和位置标记都需要额外运行 LaTeX,因此需要运行三次 LaTeX。
pdfTeX 和 LuaTeX 都支持位置标记(\pdfsavepos
并由\pdflastposy
包使用zref-savepos
)和媒体大小的设置(\pdfpageheight
)。
\flushbottom
将文本区域填充到底部。\setlength{\maxdepth}{0pt}
避免最后一行的下行部分超出文本区域。如果垂直边距为零,则这一点很重要。那么下行部分将超出页面。
\setlength{\topskip}{0pt}
然后\nointerlineskip
删除\zsavepos{PosFirst}
文本区域顶部的空白。
\documentclass{article}
\usepackage[
paperwidth=15cm,
paperheight=15cm,
hmargin=1cm,
vmargin=0cm,
]{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
\begin{document}
\vspace*{\dimexpr5cm-\topskip plus 1fill}% first page should not be larger than 15cm
\zsaveposy{PosFirst}
\nointerlineskip
\lipsum[1-9]
\end{document}
旧版本限制最后一页不超过 10 厘米:
\documentclass{article}
\usepackage[
paperwidth=15cm,
paperheight=15cm,
hmargin=1cm,
vmargin=.9cm,
]{geometry}
\pagestyle{empty}
% \flushbottom % optional
\setlength{\maxdepth}{0pt}% to address the "third bug"
% 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}%
\vspace*{5cm plus 1fill}% last page should not be largern than 15cm
}
\makeatother
\usepackage{lipsum}% provides dummy text
\begin{document}
\vspace*{\dimexpr5cm-\topskip plus 1fill}% first page should not be larger than 15cm
\zsaveposy{PosFirst}
\lipsum[1-11]
\end{document}
mdframed
版本的解决方法
环境mdframed
添加了额外的断点(例如 via \needspace
),这些断点比行之间的常规断点更受欢迎。
解决方法\interlinepenalty
可以将其设置为负值(-100):
\documentclass{article}
\usepackage[
paperwidth=15cm,
paperheight=15cm,
hmargin=1cm,
vmargin=0cm,
]{geometry}
\usepackage[framemethod=tikz, needspace=1.5cm]{mdframed}
\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}
\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*{\dimexpr5cm-\topskip plus 1fill}% first page should not be larger than 15cm
\zsaveposy{PosFirst}
\nointerlineskip
\begin{mybox}
\lipsum[1]
\end{mybox}
\lipsum[1-9]
\end{document}
负面也\interlinepenalty
有其缺点(鼓励过早分页)。
另一种方法是将框架环境放在不可破坏的小页面内,以删除额外的断点:
\noindent
\begin{minipage}[b]{\linewidth}
\begin{mybox}
\lipsum[1]
\end{mybox}%
\end{minipage}
但较长的内容mybox
不能跨页拆分。
更可靠的解决方案可能可以通过重写/修补输出例程来提供。但是,这可能会与longtable
使用其自己修改的输出例程的软件包(如)发生冲突。
答案2
页面高度由原始寄存器控制\pdfpageheight
。这意味着以下代码可以完成您想要的操作:
\def\lorem{Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad
minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
commodo consequat. Duis aute irure dolor in reprehenderit in voluptate
velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat
cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id
est laborum}
\setbox0=\vbox{\lorem.\par\lorem.}
\pdfpageheight=\ht0
\advance\pdfpageheight by2\voffset \advance\pdfpageheight by2in
\vsize=\ht0
\vbox to 0pt{\box0\vss}\vfil\break
\pdfpageheight=15cm
\vsize=\pdfpageheight \advance\vsize by-2in \advance\vsize by-2\voffset
\lorem.\par \lorem. \lorem.\par
\lorem.\par \lorem. \lorem.\par
\lorem.\par \lorem.\par
\lorem.\par \lorem.\par
\pdfpageheight=\pagetotal \vsize=\pagetotal
\advance\pdfpageheight by2\voffset \advance\pdfpageheight by2in
\end
通过 进行编译pdftex document
。
编辑:我添加了最后一页的计算。
为什么有非 LaTeX 解决方案?因为 1) 问题中没有指定 LaTeX,2) 我从不使用 LaTeX,3) 我想展示核解决方案:设置\pdfpageheight
原始寄存器。此核心未在此处第二个答案中准确显示,但必须使用它。
EDIT2(5 月 28 日):Colas:您能将它做成 LaTeX 解决方案吗……
因为我没有使用 LaTeX,所以我的 LaTeX 解决方案在 C++ 语言中看起来像汇编代码。但它确实有效。
\documentclass{article}
\topmargin=0pt % vertical shift of the text in the page
\pdfvorigin=1in % 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
}
\def\lorem{Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad
minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex
ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate
velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat
cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id
est laborum}
\begin{document}
\firstpage{\lorem.\par \lorem.}
\lorem.\par \lorem. \lorem.\par
\lorem.\par \lorem. \lorem.\par
\lorem.\par \lorem.\par
\lorem.\par \lorem.\par
\end{document}
注意这个肮脏的伎俩\let\textheight=\vsize
和\let\@colht=\vsize
。LaTeX 使用\vsize
原始的作为\textheight
用户并\@colht
在其\output
例程中使用。我需要让所有这些都作为一个对象,因为我的宏只使用进行操作\vsize
。