調整字體大小以適合 vbox 中的長單字

調整字體大小以適合 vbox 中的長單字

目標:
在 ConTeXt 中排版簡約的書籍封面,標題採用盡可能最大的字體大小,同時保留在框框中。

問題:
長單字或行不符合框的右側並繼續離開頁面。

最小範例:
我發現這段程式碼來自沃夫岡在郵件列表中,感謝這個答案來自@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

相關內容