Ajuste o tamanho da fonte para caber em palavras longas no vbox

Ajuste o tamanho da fonte para caber em palavras longas no vbox

Meta:
Composição de capas de livros minimalistas em ConTeXt, com o título no maior tamanho de fonte possível, permanecendo na caixa.

Problema:
Palavras ou linhas longas não respeitam o lado direito da caixa e continuam fora da página.

Exemplo mínimo:
eu encontreieste código de Wolfgangna lista de discussão, graças aesta respostade @aditya. (Desculpe pelo título bobo, mas queria uma palavra que soubesse que continuaria fora da página!)

\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

Compila para:
insira a descrição da imagem aqui Notas:
No contexto(sem trocadilhos!)de capas de livros, estou mais preocupado em obter o tamanho máximo do texto horizontalmente do que em preencher o espaço vertical. O ideal seria definir uma altura máxima que o texto poderia ter e largura absoluta, e encaixar o texto dentro, alinhado ao topo. Se o texto não ocupar o espaço vertical máximo, tudo bem.

Responder1

A configuração é um pouco mais complicada neste caso porque temos que criar um algoritmo completamente novo aqui. Aquele que você postou compõe o material em uma caixa e percorre o tamanho da fonte (aumentando) até atingir uma certa altura. Aqui queremos compor coisas em uma caixa, examinar se ela é muito larga ediminuiro tamanho da fonte. Isso significa que começamos com um tamanho de fonte ridiculamente grande (escolhi 100pt).

Agora o problema é que definimos coisas em um vbox com largura fixa ( \textwidthpara simplificar). Como sabemos se uma linha é muito larga? Victor Eijkhout apresentou um método para isso em seu livroTeX por tópicoque ele chamou \eatlines. Adaptei isso para medir a largura da linha e definir um valor booleano dependendo se a largura foi atendida ou não. A única coisa que resta a fazer é percorrer o tamanho da fonte (aqui em passos de 1 ponto, diminuindo). Eu também trato do caso de o tamanho da fonte diminuir abaixo de 0pt, caso em que o conteúdo nunca caberá na caixa (o que não deveria acontecer), mas deixar de fora esse caso resultaria em um loop infinito.

\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

Saída (com \showboxes):

insira a descrição da imagem aqui

O ConTeXt torna muito fácil adicionar uma interface abrangente de valores-chave para que você possa usar coisas como

\startcover[width=2in]
  Mary Poppins Sings Supercalifragilisticexpialidocious
\stopcover

\definecover[whatever][maxsize=200pt]
\setupcover[whatever][stepsize=5pt]
\startwhatever[width=4in]
  Mary Poppins Sings Supercalifragilisticexpialidocious
\stopwhatever

Isso pode parecer um pouco exagerado, mas pode-se ir além e colocar o material em um módulo, então você só precisa fazer isso \usemodule[cover]e está pronto. Salve o seguinte como t-cover.mkivem seu diretório de trabalho.

\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

Então seu arquivo principal seria lido

\usemodule[cover]

\starttext

\startcover
  Mary Poppins Sings Supercalifragilisticexpialidocious
\stopcover

\stoptext

Responder2

Se você não se importa em quebrar linhas manualmente (não deve ser um grande problema para páginas de rosto) e se você não se importa com o uso do tamanho óptico errado (muito poucas fontes alteram os glifos de acordo com o tamanho da fonte), você pode simplesmente compor a caixa e dimensioná-la adequadamente. Por exemplo:

\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

informação relacionada