vbox 内の長い単語に合わせてフォント サイズを調整する

vbox 内の長い単語に合わせてフォント サイズを調整する

ゴール:
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

この場合、セットアップは少し複雑になります。まったく新しいアルゴリズムを考え出さなければならないからです。あなたが投稿したアルゴリズムは、ボックス内に文字をタイプセットし、一定の高さに達するまでフォントサイズをループします(増加します)。ここでは、ボックス内に文字をタイプセットし、幅が広すぎるかどうかを調べ、減少フォント サイズ。つまり、途方もなく大きなフォント サイズ (私は 100 pt を選択しました) から開始することになります。

ここで問題となるのは、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

関連情報