\chapter{插图}
在某些情境下,一图可胜千言。\ConTeXt\ 在插图方面,不仅支持常见的 JPEG,GIF 和 PNG 等位图格式,也支持 PDF,SVG 以及 \METAPOST\ 等矢量图格式。
\section[figure]{位图}
所谓位图,直观上的认识是,对其进行放大或缩小,图像会失真。照片和屏幕截图,都是位图。常见的几种位图格式文件的扩展名是「\type{.jpg}」(或「\type{.jpeg}」),「\type{.gif}」和「\type{.png}」。\ConTeXt\ 在处理插图时,若发现插图文件的扩展名是这些扩展名之一,便会以位图的形式将图片插入版面相应位置。
假设在 \ConTeXt\ 源文件同一目录里有一幅位图 ctxnotes.png,以下代码,
\starttyping[option=TEX]
\externalfigure[ctxnotes.png]
\stoptyping
\noindent 便可将 ctxnotes.png 作为插图,即 \externalfigure[08/ctxnotes.png]。显然,这是插图,但很可能并非是我们想要的插图形式。我们想要的是,独占一行且居中放置的插图,这个要求这并不难实现:
\starttyping[option=TEX]
\midaligned{\externalfigure[ctxnotes.png]}
\stoptyping
\midaligned{\externalfigure[08/ctxnotes.png]}
如果需要让插图更大一些,例如宽度为 8 cm,高度按图片原有比例自动放大,只需
\starttyping[option=TEX]
\midaligned{\externalfigure[ctxnotes.png][width=8cm]}
\stoptyping
\noindent 通常更建议使用相对尺寸,例如 0.3 倍的版心宽度(满行文字的最大宽度):
\starttyping[option=TEX]
\midaligned{\externalfigure[ctxnotes.png][width=.375\textwidth]}
\stoptyping
\midaligned{\externalfigure[08/ctxnotes.png][width=.375\textwidth]}
如法炮制,给图片加上标题也很容易:
\starttyping[option=TEX]
\midaligned{\externalfigure[ctxnotes.png][width=.375\textwidth]}
\midaligned{\tfx \ConTeXt\ 学习笔记封面截图}
\stoptyping
\midaligned{\externalfigure[08/ctxnotes.png][width=.375\textwidth]}
\midaligned{\tfx\ConTeXt\ 学习笔记封面截图}
\indentation 如果你还希望插图能有编号,对于篇幅较小的文章,手工输入即可,建议在编号后,使用 \type{\quad} 插入一个字宽的空白作为间隔,因为普通的空格只有半个字宽。例如
\starttyping[option=TEX]
\midaligned{\externalfigure[ctxnotes.png][width=.375\textwidth]}
\midaligned{\tfx 图 1\quad\ConTeXt\ 学习笔记封面截图}
\stoptyping
\midaligned{\externalfigure[08/ctxnotes.png][width=.375\textwidth]}
\midaligned{\tfx 图 1\quad\ConTeXt\ 学习笔记封面截图}
如果你担心,插图太多,手工输入图片编号难免会出错,可以使用 \ConTeXt\ 的计数器功能,让 \ConTeXt\ 为你自动递增图片序号。首先,定义一个计数器:
\starttyping[option=TEX]
\definenumber[myfig]
\stoptyping
\noindent 然后,每次在给插图添加加标题时,将该计数器增 1,并获取它的当前的值:
\starttyping[option=TEX]
\midaligned{\externalfigure[ctxnotes.png][width=.375\textwidth]}
\incrementnumber[myfig]
\midaligned{\tfx 图 \getnumber[myfig]\quad\ConTeXt\ 学习笔记封面截图}
\blank[line]
\midaligned{\externalfigure[ctxnotes-2.png][width=.375\textwidth]}
\incrementnumber[myfig]
\midaligned{\tfx 图 \getnumber[myfig]\quad 涂鸦版 Hilbert 曲线}
\stoptyping
\definenumber[myfig][prefix=no]
\midaligned{\externalfigure[08/ctxnotes.png][width=.375\textwidth]}
\incrementnumber[myfig]
\midaligned{\tfx 图 \getnumber[myfig]\quad\ConTeXt\ 学习笔记封面截图}
\midaligned{\externalfigure[08/ctxnotes-2.png][width=.375\textwidth]}
\incrementnumber[myfig]
\midaligned{\tfx 图 \getnumber[myfig]\quad 涂鸦版 Hilbert 曲线}
\section{矢量图}
所谓矢量图,对其进行放大或缩小,图像不会失真。PDF 和 SVG 格式,皆为矢量图格式,文件扩展名分别为 \type{.pdf} 和 \type{.svg},将它们作为文档插图,方法与位图相同,例如
\starttyping[option=TEX]
\externalfigure[ctxnotes.pdf][width=.7\textwidth]
\stoptyping
\section{宏}
超弦理论认为,宇宙是十维的,其中有六个维度蜷缩在卡拉比-丘空间,人类目前观测不到。我不知道这个理论是否正确,但是在 \TeX\ 系统中,的确能将让一些维度蜷缩在一个空间里,这个空间叫作「宏」。
在 \in[breaking-lines] 节,我们曾经定义过一个宏:
\starttyping[option=TEX]
\def\foo{\hskip 0pt plus 2pt minus 0pt}
\stoptyping
\noindent 当我们使用 \type{\foo} 时,\TeX\ 引擎会将其展开为「\type{\hskip 0pt plus 2pt minus 0pt}」。用类似的方法,可以让 \in[figure] 节中的制作插图的代码蜷缩在一个带参数的宏里,例如
\starttyping[option=TEX]
\definenumber[myfig] % 定义插图编号计数器
\def\placemyfigure#1#2{%
\midaligned{#2}
\incrementnumber[myfig]
\midaligned{\tfx 图 \getnumber[myfig]\quad #1}
\blank[line]
}
\stoptyping
\noindent 之后,在文章里放入插图会更为容易,例如
\starttyping[option=TEX]
\placemyfigure
{涂鸦版 Hilbert 曲线}
{\externalfigure[ctxnotes-2.png][width=.375\textwidth]}
\stoptyping
你可能并不能完全理解 \type{\palcemyfigure} 的定义,但是基于上一节的一些示例,应该能猜出其要义。这已经足够了,日后倘若你觉得有些经常重复使用的排版代码,它们只存在少许差异,便可尝试为它们定义一个宏,用宏的参数代替差异。现在也许你已经隐隐感觉到了,\ConTeXt\ 的排版命令也是 \TeX\ 宏。
\section{\type{\placefigure}}
事实上,\ConTeXt\ 提供了比我们定义的 \type{\palcemyfigure} 更为强大的命令 \type{\palcefigure},其用法为
\starttyping[option=TEX]
\placefigure[插图摆放位置][引用]{插图标题}{\exteranlfigure[...][...]}
\stoptyping
例如,将 ctxnotes-2.png 作为插图,居中放置,引用为「Hilbert 曲线」,标题为「涂鸦版 Hilbert 曲线」,只需
\starttyping[option=TEX]
\placefigure
[][Hilbert 曲线]
{涂鸦版 Hilbert 曲线}
{\externalfigure[ctxnotes-2.png][width=.3\textwidth]}
\stoptyping
\midaligned{\externalfigure[08/hibert.pdf]}
\subsection{插图标题样式}
对于 \type{\placefigure} 的结果,可能你已经觉得有些不满意了。在中文排版中,图片的编号前缀不应该是 Figure,而应该是「图」,此外,编号也没必要粗体,而且标题字号应当比正文字体小一级。没有办法,\ConTeXt\ 一切默认的样式,皆针对西文排版。不过,我们可以通过以下命令,将插图标题样式设置成我们所期望的样式:
\starttyping[option=TEX,space=on]
\setupcaption[figure][style=\tfx,headstyle=\rm]
\setuplabeltext[en][figure={图 }]
\stoptyping
\midaligned{\externalfigure[08/hibert-1.pdf]}
上述设定的样式,已基本符合我们的要求。根据排版结果,很容易能猜出来,\type{\setupcaption} 的 \type{style} 参数用于设定插图字体样式,\type{headstyle} 则用于设定插图编号样式。至于 \type{\setuplabeltext},与 \ConTeXt\ 的语言界面有关,但现在不必涉及太多细节,仅需知道,它可将插图标题的前缀「\type{Figure}」替换为「\type[space=on]{图 }」。不过,依然存在一个细微的问题,标题里的汉字之间的粘连的伸长特性又被 \ConTeXt\ 触发了,导致汉字分布有些疏松。该问题的解决方法与第 \in[post] 章的示例 \in[zaoshu-5] 相似,用将对齐参数设为 \type{center},即
\starttyping[option=TEX]
\setupcaption[figure][style=\tfx,headstyle=\normal,align=center]
\stoptyping
\midaligned{\externalfigure[08/hibert-2.pdf]}
\subsection{插图位置}
\type{\placefigure} 的第一个参数用于设定插图摆放位置。当该参数为空时,\ConTeXt\ 默认插图居中放置。有时为了节省排版空间,需要将插图居左或居右放置,该需求可通过参数 \type{left} 或 \type{right} 实现。例如,
\starttyping[option=TEX]
% 居左
\placefigure[left][...]{...}{...}
% 居右
\placefigure[right][...]{...}{...}
\stoptyping
与 Mircro Word 这种字处理软件相比,\ConTeXt\ 的居中插图缺乏文字环绕功能,若想实现该功能,需对在 \TeX\ 层面掌握如何控制段落形状。
在 \ConTeXt\ 世界里,插图实际上是浮动对象(Float Object)的特例。所谓浮动对象,即你以为插图应该在文档的某个位置出现,但实际上 \TeX\ 引擎会根据版面的拥挤程度,修改插图的位置。例如,在文档的某一页的底部,若剩余空间已经不够放置一幅插图,则 \TeX\ 引擎会努力在下一页为插图寻找一个更合适的位置,但是原本应该位于插图之后的正文内容会出现在插图之前。若是禁止插图浮动,只需
\starttyping[option=TEX]
\placefigure[force][...]{...}{...}
\stoptyping
\noindent 还有一个参数 \type{here},强迫性比 \type{force} 要弱一些,只是建议 \TeX\ 引擎尽量让插图保持在原位置。
除上述参数之外,\type{\placefigure} 还有许多控制插图摆放位置的参数,但并不常用,欲知其详,请参考 \ConTeXt\ Wiki 页面「Floating Objects」\cite[floating-objects]。
\subsection{引用}
\type{\placefigure} 的第二个参数用于设定图片的引用标记。在正文中,使用 \type{\in[...]} 便可得到插图编号。例如
\starttyping[option=TEX]
如图 \in[Hilbert 曲线] 所示……
\placefigure
[][Hilbert 曲线]
{涂鸦版 Hilbert 曲线}{\externalfigure[ctxnotes-2.png][width=.3\textwidth]}
\stoptyping
\midaligned{\blueframed{\externalfigure[08/hibert-3.pdf]}}
\section[figure-matrix]{阵列}
有时为了节省排版空间,需要将两幅或更多幅插图并排放置,如图 \in[win-r] 和 \in[cmd-window] 所示。该效果可使用 floatcombination 环境构造插图阵列来实现。例如,首先构建一行两列的插图阵列:
\starttyping[option=TEX]
\startfloatcombination[nx=2,ny=1]
\placefigure{}{}
\placefigure{}{}
\stopfloatcombination
\stoptyping
\leftaligned{\externalfigure[08/floatcomb.pdf]}
\noindent 然后将所得阵列作为插图,便可得到居中放置的插图阵列:
\starttyping[option=TEX]
\placefigure[none][]{}{
\startfloatcombination[nx=2,ny=1]
\placefigure{}{}
\placefigure{}{}
\stopfloatcombination
}
\stoptyping
\midaligned{\externalfigure[08/floatcomb-2.pdf]}
上述示例用了 \type{\placefigure} 一个小技巧:当 \type{\placefigure} 的第一个参数含有 \type{none} 时,可以消除插图编号和标题。此外,你应该发现了,\type{\placefigure} 的参数为空时,\ConTeXt\ 会以一个矩形框表示插图,还应当注意到,方括号形式的参数,通常是可以省略的。
若 \type{\placefigure} 的第一个参数含有 \type{nonumber} 时,可以消除插图编号,仅保留标题。因此,上述实现图片阵列的方法稍加变换,便可实现由多幅插图组合为一幅插图的效果:
\starttyping[option=TEX]
\placefigure{}{
\startfloatcombination[nx=2,ny=1]
\placefigure[nonumber]{a}{}
\placefigure[nonumber]{b}{}
\stopfloatcombination
}
\stoptyping
\midaligned{\externalfigure[08/floatcomb-3.pdf]}
基于 \type{combination} 环境可实现与上例等效的插图阵列,只是所用代码略多一些,但形式上更为结构化且应用范围更广。例如
\starttyping[option=TEX]
\placefigure{}{
\startcombination[nx=2,ny=1]
\startcontent \externalfigure[ctxnotes.png][height=3cm] \stopcontent
\startcaption a \stopcaption
\startcontent \externalfigure[ctxnotes-2.png][height=3cm] \stopcontent
\startcaption b \stopcaption
\stopcombination
}
\stoptyping
\midaligned{\externalfigure[08/floatcomb-4.pdf]}
\section{图片目录}
前文所有示例,插图所用图形文件皆需与 \ConTeXt\ 源文件位于同一目录。为了让文件目录更为整洁,我们在 \ConTeXt\ 源文件所在目录下,构建了一子目录,例如 figures,专门用于存放图形文件。为了让 \ConTeXt\ 能够找到图形文件,在构造插图时,需要向 \type{\externalfigure} 提供图形文件的相对路径:
\starttyping[option=TEX]
\externalfigure[figures/图形文件]
\stoptyping
若不想每次插图时如此麻烦,可以通过以下命令将图形文件所在目录告知 \ConTeXt:
\starttyping[option=TEX]
\setupexternalfigures[directory={./figures}]
\stoptyping
\section{\MetaFun}
在 \ConTeXt\ 中,还有一种插图形式,\METAPOST\ 绘图代码,这些绘图代码被嵌入在 \ConTeXt\ 的 \MetaFun\ 环境里。例如,使用 \MetaFun\ 环境 \type{useMPgraphic},以 \METAPOST\ 语言绘制一个边线被轻微随机扰动的矩形:
\starttyping[option=TEX]
\startuseMPgraphic{metapost 图形}
path p; p := fullsquare xyscaled (7cm, 3cm) randomized 0.07u;
drawpath p; drawpoints p;
\stopuseMPgraphic
\placefigure{\MetaFun\ example}{\useMPgraphic{metapost 图形}}
\stoptyping
\midaligned{\externalfigure[08/metapost.pdf]}
上述示例在排版插图标题时,涉及 \TeX\ 宏在使用时即宏调用时的一个细节。例如,\type{\TeX} 之后跟随一个或多个空格,即 \type[space=on]{\TeX },这些空格会被 \TeX\ 引擎吞掉,不会显示在排版结果中,原因是默认情况下,空格是 \TeX\ 引擎需要知道宏的名字的结束符。如果需要在一个宏调用之后插入空格,需要对空格进行转义,即 \type[space=on]{\ },亦即反斜线后跟随一个空格。
\section{小结}
所谓插图,不过是个头较大的文字罢了。