Цель:
Набор минималистичных обложек книг в 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