Ajustar el tamaño de fuente para que quepa en palabras largas en vbox

Ajustar el tamaño de fuente para que quepa en palabras largas en vbox

Meta:
Composición tipográfica de portadas de libros minimalistas en ConTeXt, con el título en el tamaño de fuente más grande posible mientras permanece en el cuadro.

Problema:
Las palabras o líneas largas no respetan el lado derecho del cuadro y continúan fuera de la página.

Ejemplo mínimo:
encontréeste código de Wolfgangen la lista de correo, gracias aesta respuestade @aditya. (¡Perdón por el título tonto, pero quería una palabra que sabía que continuaría fuera de la 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

Se compila en:
ingrese la descripción de la imagen aquí Notas:
En el contexto(¡sin juego de palabras!)de portadas de libros, me preocupa más obtener el tamaño máximo de texto horizontalmente que llenar el espacio vertical. Lo ideal sería establecer una altura máxima que podría tener el texto y un ancho absoluto, y ajustar el texto dentro, alineado hacia arriba. Si el texto no ocupa el máximo espacio vertical, está bien.

Respuesta1

La configuración es un poco más complicada en este caso porque tenemos que crear un algoritmo completamente nuevo. El que publicaste escribe cosas en un cuadro y recorre el tamaño de fuente (aumentando) hasta alcanzar una cierta altura. Aquí queremos componer cosas en una caja, examinar si es demasiado ancha ydisminuirel tamaño de fuente. Eso significa que comenzamos con un tamaño de fuente ridículamente grande (elegí 100 puntos).

Ahora el problema es que configuramos cosas en un vbox con un ancho fijo ( \textwidthpor simplicidad). ¿Cómo sabemos si una línea es demasiado ancha? Victor Eijkhout presentó un método para ello en su libro.TeX por temaal que llamó \eatlines. Adapté esto para medir el ancho de la línea y establecí un valor booleano dependiendo de si se cumple el ancho o no. Lo único que queda por hacer es recorrer el tamaño de fuente (aquí en pasos de 1 punto, decreciente). También manejo el caso en el que el tamaño de fuente disminuye por debajo de 0pt, en cuyo caso el contenido nunca puede caber en el cuadro (lo que no debería suceder), pero omitir este caso resultaría en un bucle 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

Salida (con \showboxes):

ingrese la descripción de la imagen aquí

ConTeXt hace que sea bastante fácil agregar una interfaz clave-valor completa a esto para que puedas usar cosas 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

Esto puede parecer un poco exagerado, pero uno podría incluso ir más allá y poner todo el material en un módulo, así que sólo tendría que hacerlo \usemodule[cover]y listo. Guarde lo siguiente como t-cover.mkiven su directorio de trabajo.

\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

Entonces su archivo principal se leerá

\usemodule[cover]

\starttext

\startcover
  Mary Poppins Sings Supercalifragilisticexpialidocious
\stopcover

\stoptext

Respuesta2

Si no le importa dividir líneas manualmente (no debería ser un gran problema para las portadas), y si no le importa que se utilice el tamaño óptico incorrecto (muy pocas fuentes cambian los glifos según el tamaño de fuente), simplemente puede componer la caja y escale adecuadamente. Por ejemplo:

\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

información relacionada