\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{小结}

所谓插图，不过是个头较大的文字罢了。
