https://liam.page/

近日大概重拾了一点对 LaTeX 的兴趣,遇见这样一个问题:如何在 LaTeX 中实现缩印效果(即,将两页或更多页排版在一页纸上),并且实现水印效果的页码?

缩印

以朴素的办法实现缩印效果并不困难。例如,可以先以 LaTeX 正常输出文档,再以 pdfpages 宏包将生成的文档载入进来排版。不过,这样的做法扩展性太差,并且需要至少编译两份文档——一份是原始文档,一份是缩印框架文档。

更有技巧的办法,需要深入到 TeX 构建页面输出的过程中去。基本上来说,我们需要让 TeX 按往常一样去构建页面,但是在 TeX 准备将页面输出(shipout)时我们需要插入一个钩子。这个钩子做两件事情:

  • 打断输出过程;
  • 将整个页面内容保存在一个盒子中备用。

我们将保存在盒子里的页面称为逻辑页面(logic pages)。而后,当保存的页面足够多时,或没有更多页面需要保存时,将这些盒子的内容成比例缩小并列印在页面上。我们将最终输出的页面称之为物理页面。

pgfpages 就是这样做的。它是 PGF 宏集的一部分,因而使用 texdoc pgf 可以看到它的文档(Section 89)。

首先我们从一个简单的例子开始,其效果见这里

demo-2on1-landscape.tex
1
2
3
4
5
6
7
8
documentclass{article}
usepackage{pgfpages}
pgfpagesuselayout{2 on 1}[a4paper, landscape, border shrink = 5mm]
begin{document}
This text is shown on the left.
clearpage
This text is shown on the right.
end{document}

这里,pgfpagesuselayout 命令是实现缩印效果的核心命令。参数 2 on 1 的含义不言自明。其后的可选参数:a4paper 表示物理页的尺寸是标准 A4 纸;landscape 表示要将物理页横过来——毕竟是二合一缩印,这很合理;border shink = 5mm 表示被缩印的逻辑页会被继续缩小,并在每个逻辑页的上下左右四周保留宽度为 5mm 的边框。

类似地,你也可以缩印 beamer 幻灯片。不过,由于 beamer 幻灯片的逻辑页本就是横着的,所以此处不需要在加 landscape 参数了。

相应的,4 on 1 需要加,6 on 18 on 1 不需要加,以及 16 on 1 又需要加。——32 on 1 是不存在的……

demo-2on1.tex
1
2
3
4
5
6
7
8
9
10
11
documentclass{beamer}
usepackage{pgfpages}
pgfpagesuselayout{2 on 1}[a4paper, border shrink=5mm]
begin{document}
begin{frame}
This text is shown at the top.
end{frame}
begin{frame}
This text is shown at the bottom.
end{frame}
end{document}

页码

在当前问题中,TeX 默认的页码机制实际上是作用在各个逻辑页上的。但显然,我们可能会想要为物理页编上页码。这里有两个问题需要解决:

  • 物理页的页码如何确定?
  • 缩印排版,有效内容字体很小且密集,如何保证物理页页码可见且不影响有效内容的阅读?

对于第一个问题,有两种思路。

一是读取逻辑页页码 page 计数器,然后按 x on 1 的比例做除法,得出物理页的页码。不过,这种方式是有前提的。具体来说,它要求 TeX 的逻辑页页码功能不在缩印的情况下失效,并且它要求 TeX 能正确计算整数除法(向上取整)。总得来说,这是一种快而脏的解法,不推荐。

如果十年以后,你以快而脏的方式做什么事的时候,能想象我在你的肩后看着,然后对自己说:「Dijkstra 不会希望这样的。」那么对我来说,这就和永生一样了。
—— Edsger Wybe Dijkstra

另一种思路则更加直接。既然页码本质是由计数器实现的,这一计数器随页面输出而自增,而 pgfpages 影响的正是 TeX 页面输出的逻辑,那么 pgfpages 内必然有什么地方可以下钩子来自增该计数器。

1
2
3
4
5
6
7
8
9
newcommandpgfshipoutphysicalpage{%
ifnumpgf@logicalpages>0relax%
pgfpages@buildshipoutbox%
pgfpages@shipoutshipoutbox%
pgfpages@performcopying%
globalpgfphysicalpageemptytrue%
globalpgf@holdingphysicalpagefalse%
fi%
}

通过翻阅 pgfpages.sty 的源码,我们不难发现有以上代码和物理页输出有关。可以说,PGF 宏集的代码风格相当好,一眼就能看明白代码在做什么。显然,pgfpages@shipoutshipoutbox 是在输出物理页,而它之前的 pgfpages@buildshipoutbox 就是将逻辑页构建成物理页的过程了。因此,我们需要在 pgfpages@buildshipoutbox 当中下钩子;此时我们又要用到老朋友 etoolbox 当中的 patchcmd 了。

1
2
3
4
5
6
7
8
9
10
11

newcounter{physicalpage}
makeatletter
patchcmd{pgfpages@buildshipoutbox}{%
pgfsys@beginpicture
}{%
pgfsys@beginpicture
stepcounter{physicalpage}%
}{}{}
makeatother

第二个问题可能有多种解决思路。我偏好于在页面中央以水印的形式加一个大大的页码。四年多以前,我利用 TikZ 实现了水印功能。TikZ 也是 PGF 宏集的一部分,用在这里正好。于是,我们的代码变为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
大专栏  在 LaTeX 中实现缩印效果pan class="line">17
18
19
20
21
22
23
% require packages: pgfpages, etoolbox, xcolor, tikz
newcommand{boxedcontent}[5]{parbox[b][paperheight]{paperwidth}{%
vfill%
centering%
tikz[remember picture, overlay]%
node [rotate = #1, scale = #2] at (#3)%
{textcolor{#4}{#5}};
vfill}} newcounter{physicalpage}
makeatletter
patchcmd{pgfpages@buildshipoutbox}{%
pgfsys@beginpicture
}{%
pgfsys@beginpicture
stepcounter{physicalpage}%
setbox0vbox{makebox[0pt][c]{boxedcontent{0}{30}{current page.center}{gray!80!cyan!30}{arabic{physicalpage}}}}%
pgfsys@beginscope
pgflowlevel{pgftransformshift{pgfpoint{0pgfphysicalwidth}{0pgfphysicalheight}}}%
pgfsys@hbox0%
pgfsys@endscope
}{}{}
makeatother

实际效果

将以上代码综合起来,我做了一个简单的 demo。

demo-reduced-print.tex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
documentclass[12pt]{article}
usepackage{mwe} pagestyle{empty}
usepackage{multicol}
setlength{columnseprule}{0.4pt} usepackage{geometry}
geometry{a4paper, scale = 1, includeall,
margin = 0pt, marginparwidth = 0pt, marginparsep = 0pt,
headheight = 0pt, headsep = 0pt, footskip = 0pt} usepackage{pgfpages}
pgfpagesuselayout{4 on 1}[a4paper, border shrink = 1.5mm] usepackage{tikz}
usepackage{xcolor}
usepackage{eso-pic}
usepackage{etoolbox} newcommand{boxedcontent}[5]{parbox[b][paperheight]{paperwidth}{%
vfill%
centering%
tikz[remember picture, overlay]%
node [rotate = #1, scale = #2] at (#3)%
{textcolor{#4}{#5}};
vfill}}
newcommand{watermark}[3]{AddToShipoutPictureBG{%
boxedcontent{#1}{#2}{current page.center}{gray!80!cyan!30}{#3}}} newcounter{physicalpage}
makeatletter
patchcmd{pgfpages@buildshipoutbox}{%
pgfsys@beginpicture
}{%
pgfsys@beginpicture
stepcounter{physicalpage}%
setbox0vbox{makebox[0pt][c]{boxedcontent{0}{30}{current page.center}{gray!80!cyan!30}{arabic{physicalpage}}}}%
pgfsys@beginscope
pgflowlevel{pgftransformshift{pgfpoint{0pgfphysicalwidth}{0pgfphysicalheight}}}%
pgfsys@hbox0%
pgfsys@endscope
}{}{}
makeatother begin{document}
begin{multicols}{3}
lipsum[1-79]
end{multicols}
end{document}

在 LaTeX 中实现缩印效果的更多相关文章

  1. 如何在latex 中插入EPS格式图片

    如何在latex 中插入EPS格式图片 第一步:生成.eps格式的图片 1.利用visio画图,另存为pdf格式的图片 利用Adobe Acrobat裁边,使图片大小合适 另存为.eps格式,如下图所 ...

  2. Latex中画出函数文件的调用关系拓扑图

    流程图,思维导图,拓扑图通常能把我们遇到的一些复杂的关系结构用图形的方式展现出来.在Latex中要想画这样的拓扑图,有一个很好用的绘图工具包 pgf/tikz . 1.pgf/tikz的安装:pgf/ ...

  3. Latex中插入C语言代码

    Latex是一个文本排版的语言,能排版出各种我们想要的效果.而且用代码排版的优点是易于修改板式,因此在文本内容的排版时,Latex应用十分广泛. 当我们需要在Latex中插入代码时,就需要用到 \us ...

  4. Latex中cls和sty文件有何区别?

    Latex中cls和sty文件有何区别? 资源 本文对 LaTeX 中 .cls 和 .sty 文件进行介绍,主要参考了 What are .cls and .sty files?How are th ...

  5. 在LaTeX中配置西夏文字体与环境

    目录 1 配置字族 2 粗体.斜体设定 3 文本编辑器的字体设定(以Sublime Text为例) 4 附录:一些字体的下载源 警告:这篇文章的部分内容需要西夏文字体才能正常显示.若您需要安装,可参考 ...

  6. LaTeX 中插入图片使其紧跟插入的文字之后

    LaTeX 中插入图片使其不跑到每页的开头而紧跟插入的文字之后. 此次建模过程中,遇到的一个比较棘手的问题是: 当插入图片时,图片的位置总是会自动跑到当页(或下一页)的最上方,而不是紧跟在其对应的说明 ...

  7. 一个LaTeX 中文文档的简单而实用的模板

    网上找的一个latex中文模板,感觉很简单,在我机器上有点小问题,完善记录一下. %要运行该模板,LaTex需要安装CJK库以支持汉字. %字体大小为12像素,文档类型为article %如果你要写论 ...

  8. LaTex 中圆圈序号及一些特殊字符的输入

    众所周知,LATEX 提供了 \textcircled 命令用以给字符加圈,但效果却不怎么好: 实际上,加圈并不是一个平凡的变换,它会涉及到圈内字符形状的微调,而这是几乎无法在 TEX 宏层面解决的. ...

  9. m.jd.com首页中的js效果

    m.jd.com中的部分js效果 昨天把m.jd.com的首页布局写好了,今天写一下首页中部分js效果.头部背景色透明度的改变,焦点图轮播,京东快报的小轮播,以及秒杀倒计时.这里html,css样式就 ...

随机推荐

  1. windows Apache 配置支持HTTPS的SSL证书

    在设置Apache + SSL之前, 需要做: 安装Apache, 下载安装Apache时请下载带有ssl版本的Apache安装程序. 并且ssl需要的文件在如下的位置: [Apache安装目录]/m ...

  2. 吴裕雄--天生自然python TensorFlow图片数据处理:解决TensorFlow2.0 module ‘tensorflow’ has no attribute ‘python_io’

    tf.python_io出错 TensorFlow 2.0 中使用 Python_io 暂时使用如下指令: tf.compat.v1.python_io.TFRecordWriter(filename ...

  3. 发布订阅--DBMS "无法作为数据库主体执行,因为主体“dbo”不存在、无法模拟这种..........”

    解决方案: 新附加的数据库需要设置所有者才能建立数据库关系图.供参考的操作步骤如下: 选择“AdventureWorks2012LT”,右键,选择“属性”,选择“文件”页,点击“所有者”右侧按钮,点击 ...

  4. iso镜像文件的挂载和yum库的搭建

    挂载镜像文件 1.上传镜像文件到服务器(或电脑)的某一目录下   如:(/media/rpm_pack/rhel...iso) 2.root 用户下创建镜像文件挂载目录 mkdir  /mnt/vcd ...

  5. 线性反馈移位寄存器(LFSR)-非线性反馈移位寄存器的verilog实现(产生伪随机数)

    一.线性反馈移位寄存器(LFSR) 通过对事先选定的种子做运算使得人工生成的伪随机序列的过程,在实际中,随机种子的选择决定了输出的伪随机序列的不同,也就是说随机种子的选择至关重要. 产生伪随机数的方法 ...

  6. C段和旁注

    踩点常用手段有哪些 1.旁站注入:利用同一 主机上面不同网站的漏洞得到 webshell,从而利用主机上的程序或者是服务所暴露的 用户所在的物理路径进行入侵.网站共享主机漏洞是更为严谨的学术叫法 2. ...

  7. EXAM-2018-7-29

    EXAM-2018-7-29 未完成 [ ] H [ ] A D 莫名TLE 不在循环里写strlen()就行了 F 相减特判 水题 J 模拟一下就可以发现规律,o(n) K 每个数加一减一不变,用m ...

  8. excle导出、导入、下载_jeesite注解@ExcelField

    介绍:对Apache POI 3.9的简单封装,实现Excel的导出导入功能.使用Annotation定义导出导入字段. 优点:1.简单易用,支持大数量导出,配置简单,代码量少. 2.支持Excel ...

  9. C#函数的基础应用

    C#函数的基础应用 函数之前的知识回顾 数据类型--变量常量--运算符表达式--语句(顺序,分支,循环)--数组--函数 程序里的函数:能完成一个相对独立功能的代码模块. 数学里的函数:高度抽象. 函 ...

  10. Spring+Mybais整合

    简单的来说,Spring主要用于在业务层(当然spring也有数据库交互的模块,个人觉得spring在这方面有一点不如mybatis),而mybatis主要用于数据持久化,在一个完整的项目中无论是业务 ...