2段抜き・3段抜きの図版を入れる

段抜きをどうするか

本文を段組みにした際に、その2段分を使って図を入れるのが「2段抜き」。3段分を使うのが「3段抜き」です。

なお、2段組の2段抜きや、3段組の3段抜きなら、multicols環境を一時的に解除すればいいだけですし、twocolumnオプションで「figure*」環境を使う手もあります。問題は、3段組の2段抜きなどをどうするかです。

それも、1〜2段目を段抜きにした図と、2〜3段目を段抜きにした図の2つが同じページ内に入るという場合もありえます。4段組以上だと、2段抜きと3段抜きが同じページに入る場合もあるでしょう。これらについて考えてみようと思います。

\output ルーチン

ここで、TeXのページ整形の仕組みを簡単に説明します。TeXは、1段落分のテキストを読み込んだら、最適な改行位置を探して行の長さ (\hsize) ごとに分割しています。これをどんどん貯めていき、ページの高さ (\vsize) を越えるか \pagebreak が発生したら、今まで組んだテキストを \box255 という特別な変数に入れて \output ルーチンを呼び出します。

\output ルーチンでは、ヘッダやノンブルを付けてページを出力し、ページ番号を1増やすという処理が書かれています。この \output ルーチンはユーザーがマクロで書き換えることができます。

twocolumnオプションが指定されている場合は、\output ルーチンが呼ばれてもページを出力せずに別の変数に保存しておきます。そして、次回 \output ルーチンが呼ばれたときに、その2ページ分を並べて出力するという仕組みです。一方、multicols環境は、例えば3段組なら予め \vsize (ページの高さ) を3倍に設定しておいて、\output ルーチンが呼ばれたらその中で3分割して並べるという仕組みです。

要するに、twocolumnオプションは1段ごとに (1ページに2回) \output ルーチンが呼ばれるのに対して、multicols環境は何段あっても1ページに1回\outputルーチンが呼ばれる仕組みですね。\pagebreak の挙動が両者で違うのはこのためです。

というわけで、段抜きのマクロを書こうと思ったら、どう考えても\outputルーチンを書き換えなければならないでしょう。これは、plain TeXなら比較的簡単なのですが、LaTeXは少々やっかいです。LaTeXはデフォルトのマクロ自体が比較的複雑ですし、いろんなスタイルパッケージがあるので、それらと衝突しないように書き換えようと思うと大変なのです。

実際問題として、\outputルーチンを書き換えなきゃならないようなレイアウトをしようと思ったら、plain TeXの方がずっと楽だというのは言えるかと思います。まあ、単純に私がLaTeXの内部構造をわかっていないからという話もあるのかもしれませんが(笑)。

実際のマクロ

ここでは簡単のため、「段抜きは必ず版面の四隅のどれかに触れている」という制約を設けてマクロを考えることにします。要するに、段抜きがページの真ん中に来ることはないという制約ですね。1ページに入る段抜きの図は最大4枚になります。

また、LaTeXの他のパッケージとの衝突はあまり考えないことにします。従って、以下のマクロを使うと、LaTeXの他の機能が使えなくなる可能性は大いにあると思います(笑)。実際、twocolumnやmulticolsと衝突するので、多段組はこのマクロ自体で実現しています。plain TeXなら特に問題は起こらないかと思いますが。

\catcode`@=11
\ifx\textwidth\undefined\newdimen\textwidth\fi
\ifx\textheight\undefined\newdimen\textheight\fi
\ifx\columnwidth\undefined\newdimen\columnwidth\fi
\ifx\columnsep\undefined\newdimen\columnsep\fi
\newcount\linenum\newcount\columnnum\newdimen\colwid@sep
\newbox\@ULbox\newbox\@URbox\newbox\@LLbox\newbox\@LRbox
\newbox\U@box\newbox\L@box\newbox\@tmpbox\newbox\page@box
\newcount\@ULcnt\newcount\@URcnt\newcount\@LLcnt\newcount\@LRcnt
\newcount\tmp@n\newcount\tmp@m\newcount\cur@col\cur@col=\@ne
\newdimen\tmp@h\newdimen\tmp@v
\def\pagesetup#1#2#3{%
 \global\linenum=#2\global\columnnum=#3
 \global\columnwidth=1zw\global\multiply\columnwidth #1
 \global\parindent=1zw\global\columnsep=2zw
 \global\baselineskip=1.75zw
 \global\colwid@sep=\columnwidth
 \global\advance\colwid@sep\columnsep
 \global\textwidth=\columnnum\colwid@sep
 \global\advance\textwidth-\columnsep
 \global\textheight=\linenum\baselineskip
 \global\advance\textheight-\baselineskip
 \global\advance\textheight 1zh
 \ifx\linewidth\undefined\else\global\linewidth\columnwidth\fi
 \ifx\@colht\undefined\else\global\@colht\textheight\fi
 \ifx\@colroom\undefined\else\global\@colroom\textheight\fi
 \setbox\@tmpbox=\hbox{\char\jis"2121}%
 \global\topskip=\ht\@tmpbox\global\maxdepth=\dp\@tmpbox
 \global\parskip=\z@
 \global\hsize=\columnwidth\global\vsize=\textheight
}
\def\columnbreak{\par\vfil\penalty-10000\relax}%
\def\pagebreak{\par\vfil\penalty-10005\relax}%
\long\def\layout#1#2{%
 \edef\pos{#1}\setbox\@tmpbox\hbox{#2}%
 \tmp@h=\wd\@tmpbox\tmp@v=\ht\@tmpbox\advance\tmp@v\dp\@tmpbox
 \divide\tmp@h\colwid@sep\tmp@n=\number\tmp@h\advance\tmp@n\@ne
 \advance\tmp@v\baselineskip\advance\tmp@v-1zh\advance\tmp@v-1sp
 \divide\tmp@v\baselineskip\tmp@m=\number\tmp@v\advance\tmp@m\@ne
 \if\pos1
  \global\setbox\@ULbox=\vbox to\tmp@m\baselineskip{%
   \hbox to\columnwidth{\unhbox\@tmpbox\hss}\vss}%
  \global\@ULcnt=\tmp@n
 \else\if\pos2
  \global\setbox\@URbox=\vbox to\tmp@m\baselineskip{%
   \hbox to\columnwidth{\hss\unhbox\@tmpbox}\vss}%
  \global\@URcnt=\tmp@n
 \else\if\pos3
  \global\setbox\@LLbox=\vbox to\tmp@m\baselineskip{%
   \vss\hbox to\columnwidth{\unhbox\@tmpbox\hss}\vskip\z@}%
  \global\@LLcnt=\tmp@n
 \else\if\pos4
  \global\setbox\@LRbox=\vbox to\tmp@m\baselineskip{%
   \vss\hbox to\columnwidth{\hss\unhbox\@tmpbox}\vskip\z@}%
  \global\@LRcnt=\tmp@n
 \fi\fi\fi\fi
}
\output{%
 \splittopskip=\topskip\splitmaxdepth=\maxdepth\tmp@v=\textheight
 \setbox\U@box=\vbox to\z@{\vss}\setbox\L@box=\vbox to\z@{\vss}%
 \tmp@m=\@ULcnt\advance\tmp@m\@ne
 \ifnum\cur@col<\tmp@m
  \ifnum\cur@col=\@ne
   \setbox\@tmpbox\vbox to\ht\@ULbox{\vss}%
   \setbox\U@box\box\@ULbox\global\setbox\@ULbox\box\@tmpbox
  \else
   \setbox\U@box\vbox to\ht\@ULbox{\vss}%
  \fi
  \advance\tmp@v-\ht\U@box
 \fi
 \tmp@m=\columnnum\advance\tmp@m-\@URcnt
 \ifnum\cur@col>\tmp@m
  \ifnum\cur@col=\columnnum
   \setbox\U@box\box\@URbox
  \else
   \setbox\U@box\vbox to\ht\@URbox{\vss}%
  \fi
  \advance\tmp@v-\ht\U@box
 \fi
 \tmp@m=\@LLcnt\advance\tmp@m\@ne
 \ifnum\cur@col<\tmp@m
  \ifnum\cur@col=\@ne
   \setbox\@tmpbox\vbox to\ht\@LLbox{\vss}%
   \setbox\L@box\box\@LLbox\global\setbox\@LLbox\box\@tmpbox
  \else
   \setbox\L@box\vbox to\ht\@LLbox{\vss}%
  \fi
  \advance\tmp@v-\ht\L@box
 \fi
 \tmp@m=\columnnum\advance\tmp@m-\@LRcnt
 \ifnum\cur@col>\tmp@m
  \ifnum\cur@col=\columnnum
   \setbox\L@box\box\@LRbox
  \else
   \setbox\L@box\vbox to\ht\@LRbox{\vss}%
  \fi
  \advance\tmp@v-\ht\L@box
 \fi
 \setbox\@tmpbox=\hbox{\char\jis"2121}\advance\tmp@v-\dp\@tmpbox
 \setbox\@tmpbox\vsplit\@cclv to\tmp@v
 \ifnum\cur@col=\@ne
  \global\setbox\page@box\hbox{\hbox to\columnwidth{%
   \vbox to\textheight{%
   \offinterlineskip\box\U@box\box\@tmpbox\vss\box\L@box}\hss}}%
 \else
  \global\setbox\page@box\hbox{\unhbox\page@box\hskip\columnsep
   \hbox to\columnwidth{\vbox to\textheight{%
   \offinterlineskip\box\U@box\box\@tmpbox\vss\box\L@box}\hss}}%
 \fi
 \ifnum\outputpenalty<-\@M\cur@col=\columnnum\fi
 \ifnum\cur@col=\columnnum
  \global\setbox\@tmpbox\box\@cclv
  \global\setbox\@cclv\vbox{\hbox to\textwidth{%
   \unhbox\page@box\hss}\vss}%
  \global\tmp@h=\hsize\global\hsize=\textwidth
  \ifx\plainoutput\undefined % LaTeX
   \@makecol\@opcol\@startcolumn
  \else % plain TeX
   \iftdir\shipout\vbox{\yoko\hsize=\textheight
    \makeheadline\vbox{\tate\pagebody}\makefootline}%
   \else\shipout\vbox{\makeheadline\pagebody\makefootline}\fi
   \advancepageno\ifnum\outputpenalty>-\@MM\else\dosupereject\fi
  \fi
  \global\hsize=\tmp@h\global\cur@col=\@ne
  \global\@ULcnt=\z@\global\@URcnt=\z@
  \global\@LLcnt=\z@\global\@LRcnt=\z@
  \unvbox\@tmpbox
 \else
  \global\advance\cur@col\@ne
  \unvbox\@cclv
 \fi
}
\catcode`@=12

上記のマクロを使うときは、

\pagesetup{16}{32}{4}
\layout{1}{\includegraphics{hoge.eps}}

のようにします。\pagesetup はそのページの文字組を設定するマクロで、上記の例では1行16文字×32行×4段組に設定します。LaTeXなら \begin{document} の直後に書くといいかと思います。ページごとに設定を変えることができますが、何も指定しなかったら前のページと同じ設定になります。

\layout が段抜きの指定です。最初の引数は図を張る位置で、版面の四隅を1〜4の番号で指定します。1〜4は、横書きページならそれぞれ左上、右上、左下、右下を意味し、縦書きページならそれぞれ右上、右下、左上、左下を意味します。要するに、ページ内の字を読んでいく順番に番号を付けています。2番目の引数は図を指定しますが、前にやった \ovalframe 等を書けば囲み記事等を段抜きにできます。minipageとかも入れられると思います。

やっていることは、\layout で図の位置を予約して、次に \output ルーチンが呼ばれたときに予約していた位置に図を入れるという仕組みです。\layout では予約しているだけなので、基本的にどこに書いてもいいですが、1〜2段目を段抜きにするなら1段目の終わりまでの間に書き、3〜4段目を段抜きするなら3段目の終わりまでの間に書くようにします。

マクロ内では、図の大きさを見て、それが「1段幅 + 段間隔」より小さければ1段抜き。その2倍より小さければ2段抜きなど、自動判別します。字送り方向も図の大きさを見てそれがうまく入るように「n行取り」しますので、各段の行のラインは揃います。断ち切りにしたい場合は、「断ち切りの写真を入れる」の回で示したように、図の大きさを偽装してずらせばいいです。

というわけで、かなり手抜きのマクロになっていますが、私としてはマクロを作ることが目的ではなく、本を作ることが目的だったので、こんな状態です。


渡邉たけし <t-wata@dab.hi-ho.ne.jp>