Отрегулируйте размер шрифта, чтобы длинные слова помещались в 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 для простоты). Как мы узнаем, что строка слишком широкая? Виктор Эйкхаут представил метод для этого в своей книге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

Связанный контент