目标:
在 ConTeXt 中排版简约的书籍封面,标题采用尽可能最大的字体大小但仍保留在框中。
问题:
长单词或长行不尊重框的右侧并且会延伸到页面外。
最小示例:
我发现这是 Wolfgang 的代码在邮件列表中,感谢这个答案来自@aditya。(抱歉,标题有点傻,但我想找一个我知道会延续到页面之外的词!)
\newbox\cover
\newdimen\coverheight \coverheight= 4in
\newdimen\coverwidth \coverwidth = 7in
\newdimen\coverfont \coverfont = 12pt
\newdimen\fontstep \fontstep = 1pt
\def\startcover
{\dostartbuffer[cover][startcover][stopcover]}
\def\stopcover
{\setups[cover:place]}
\def\boxsize
{\setbox\cover\vbox
{\hsize\coverwidth
\definedfont[Serif at \the\coverfont]\setupinterlinespace
\setupalign[nothyphenated]
\emergencystretch\maxdimen
\getbuffer[cover]}}
\def\covertext
{\boxsize\doloop
{\boxsize
\ifdim\ht\cover>\coverheight
\global\advance\coverfont-\fontstep
\exitloop
\else
\global\advance\coverfont\fontstep
\fi}}
\startsetups[cover:place]
\covertext
\boxsize
\vbox to\coverheight{\box\cover}
\stopsetups
\starttext
\startcover
\strut Mary Poppins Sings Supercalifragilisticexpialidocious
\stopcover
\stoptext
编译为:
笔记:
在上下文中(无双关语!)书籍封面,我更关心的是水平方向上文本的最大尺寸,而不是填充垂直空间。理想的做法是设置文本的最大高度和绝对宽度,并将文本放入其中,与顶部对齐。如果文本不占用最大垂直空间,那就没问题。
答案1
在这种情况下,设置会稍微复杂一些,因为我们必须想出一个全新的算法。您发布的算法将内容排版在一个框中,并循环字体大小(增加),直到达到一定的高度。在这里,我们想将内容排版在一个框中,检查它是否太宽,然后减少字体大小。这意味着我们从一个非常大的字体大小开始(我选择了 100pt)。
现在的问题是,我们在一个固定宽度的 vbox 中设置内容(\textwidth
为了简单起见)。我们如何知道一行是否太宽?Victor Eijkhout 在他的书中介绍了一种方法。TeX 按主题分类他称之为\eatlines
。我对此进行了修改,以测量线的宽度,并根据宽度是否满足设置布尔值。剩下要做的就是循环遍历字体大小(这里以 1pt 为步长,逐渐减小)。我还处理了字体大小减小到 0pt 以下的情况,在这种情况下,内容永远无法放入框中(不应该发生这种情况),但如果忽略这种情况,则会导致无限循环。
\newdimen\coverwidth \coverwidth = \textwidth
\newdimen\coverfont \coverfont = 100pt
\newdimen\fontstep \fontstep = 1pt
\newconditional\widthmet
\def\startcover
{\dostartbuffer[cover][startcover][stopcover]}
\def\stopcover
{\setups[cover:place]}
\def\eatlines{%
\global\settrue\widthmet
\setbox\scratchboxone=\lastbox
\ifvoid\scratchboxone\else
\unskip\unpenalty
{\eatlines}%
\copy\scratchboxone
\setbox\scratchboxtwo=\hbox{\unhbox\scratchboxone}%
\ifdim\wd\scratchboxtwo>\coverwidth
\global\setfalse\widthmet
\fi
\fi
}
\startsetups cover:place
\start\dontcomplain
\doloop{%
\setbox\scratchbox=\vbox{\hsize=\coverwidth
\definedfont[Serif at \the\coverfont]\setupinterlinespace
\setupalign[nothyphenated]\emergencystretch\maxdimen
\getbuffer[cover]%
\par\eatlines
}%
\ifconditional\widthmet
\box\scratchbox
\exitloop
\else
\global\advance\coverfont by -\fontstep
\fi
\ifdim\coverfont<0pt
\exitloop
\fi
}
\stop
\stopsetups
\starttext
\startcover
Mary Poppins Sings Supercalifragilisticexpialidocious
\stopcover
\stoptext
输出(带有\showboxes
):
ConTeXt 可以很容易地为其添加一个全面的键值接口,因此您可以使用类似
\startcover[width=2in]
Mary Poppins Sings Supercalifragilisticexpialidocious
\stopcover
\definecover[whatever][maxsize=200pt]
\setupcover[whatever][stepsize=5pt]
\startwhatever[width=4in]
Mary Poppins Sings Supercalifragilisticexpialidocious
\stopwhatever
这可能看起来有点夸张,但人们甚至可以更进一步将这些东西放入模块中,所以你只需\usemodule[cover]
要这样做就可以了。将以下内容保存t-cover.mkiv
为工作目录中的内容。
\startmodule[cover]
\unprotect
\installcorenamespace{cover}
\installcommandhandler \??cover {cover} \??cover
\startinterface all
\setinterfaceconstant {maxsize} {maxsize}
\setinterfaceconstant {stepsize} {stepsize}
\stopinterface
\appendtoks
\setuevalue{\e!start\currentcover}{\cover_start[\currentcover]}%
\setuvalue {\e!stop\currentcover}{\cover_process}%
\to \everydefinecover
\setupcover[
\c!width=\textwidth,
\c!maxsize=100pt,
\c!stepsize=1pt,
]
\unexpanded\def\cover_start
{\bgroup\obeylines\dodoubleargument\cover_start_indeed}
\starttexdefinition cover_start_indeed [#1][#2]
\egroup
\edef\currentcover{#1}
\setupcover[#1][#2]
\grabbufferdata[coverbuffer][start#1][stop#1]
\stoptexdefinition
\unexpanded\def\cover_process{%
\start\dontcomplain
\scratchdimen=\coverparameter\c!maxsize
\doloop{%
\setbox\scratchbox=\vbox{\hsize=\coverparameter\c!width
\definedfont[Serif at \the\scratchdimen]\setupinterlinespace
\setupalign[nothyphenated]\emergencystretch\maxdimen
\getbuffer[coverbuffer]%
\par\eatlines
}%
\ifconditional\scratchcounter
\box\scratchbox
\exitloop
\else
\global\advance\scratchdimen by -\coverparameter\c!stepsize
\fi
\ifdim\scratchdimen<0pt
\exitloop
\fi
}%
\stop
}
\def\eatlines{%
\global\settrue\scratchcounter
\setbox\scratchboxone=\lastbox
\ifvoid\scratchboxone\else
\unskip\unpenalty
{\eatlines}%
\copy\scratchboxone
\setbox\scratchboxtwo=\hbox{\unhbox\scratchboxone}%
\ifdim\wd\scratchboxtwo>\coverparameter\c!width
\global\setfalse\scratchcounter
\fi
\fi
}
\definecover[cover]
\protect
\stopmodule
然后你的主文件将会读取
\usemodule[cover]
\starttext
\startcover
Mary Poppins Sings Supercalifragilisticexpialidocious
\stopcover
\stoptext
答案2
如果您不介意手动换行(对于封面来说应该不是什么大问题),并且不介意使用错误的光学尺寸(很少有字体会根据字体大小更改字形),您可以简单地排版框并适当缩放。例如:
\define[1]\FitBox
{\scale[width=10cm,height=5cm,factor=max]{\framed[align=normal]{#1}}}
\starttext
\FitBox{Mary \\ Poppins Sings \\ Supercalifragilisticexpialidocious}
\FitBox{A \\ B \\ C \\ D \\ E \\ F \\ G \\ H \\ I \\ J \\ K \\ L \\ M \\ N}
\stoptext