9

As in this question on stackoverflow, I want to replicate the so-called 'big text' formatting:

enter image description here

Functioning:

  1. You give as input:
    • the line (column) width for each line,
    • and the content of each line.
  2. The font size is dynamically adapted for each line so that they all have the same width.

(Note that, in previous example, each line is only one word long. However, I would like to be able to have longer lines (in terms of words number) as in this example.)

Question: how to achieve this formatting with LaTeX?


Partial/not satisfactory solutions (so far):

  • Of course, justified text is not satisfactory, since it adapt the line length by modulating the character and/or interword spacing... and not the font size.
  • Fit text into given box by adjusting the fontsize develops a solution, but is rather a "maximum" constraint (it won't makes the text bigger to fill all the space).

Edit:

What makes this formatting visually strong is that the very first/last pixel of each line are aligned (or in other words: there is no kerning nor protrusion)*. In suggested answers however, their is a protrusion that is especially noticeable at the beginning of the last two lines.

enter image description here

So, is it be possible to 'pixel-align' the beginning and the end of each line? (if yes, how?!)

*to be honest, I observed that there is a small protrusion in the given example. But it is less noticeable than in suggested answer, and I'd like to be able to have no protrusion at all.

  • I've selected egreg's answer, since it handles side-bearing adjustment, and get more used to LaTeX3-syntax. However, it needs to be compiled with XeLaTeX. Thus, I suggest you to also have a look to the also satisfactory solution written by Runar Trollet that is a bit easier to implement (imho) and requires LaTeX only. – ebosi Jul 1 '16 at 8:53
10

An implementation with expl3 for a cleaner syntax:

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\bigtext}{mm}
 { % #1 = width, #2 = text, with \\ to separate lines
  \ebo_bigtext:nn { #1 } { #2 }
 }

\seq_new:N \l_ebo_bigtext_text_seq
\box_new:N \l_ebo_bigtext_line_box

\cs_new_protected:Nn \ebo_bigtext:nn
 {
  \begin{minipage}{#1}
  \baselineskip=-\maxdimen \lineskip=4pt
  \seq_set_split:Nnn \l_ebo_bigtext_text_seq { \\ } { #2 }
  \seq_map_inline:Nn \l_ebo_bigtext_text_seq
   {
    \hbox_set:Nn \l_ebo_bigtext_line_box { ##1 }
    \box_resize_to_wd:Nn \l_ebo_bigtext_line_box { \textwidth }
    \box_use:N \l_ebo_bigtext_line_box
   }
  \end{minipage}
 }
\ExplSyntaxOff

\begin{document}

\noindent
\bigtext{15em}{SOME \\ TOTALLY \\ HIPSTER \\ QUOTE \\ ABOUT \\ LIFE}
\quad
\sffamily
\bigtext{15em}{SOME \\ TOTALLY \\ HIPSTER \\ QUOTE \\ ABOUT \\ LIFE}

\end{document}

Spaces around \\ are ignored.

enter image description here

One might add an optional argument to set the vertical space between lines, in the macros above set to 3pt.


With XeLaTeX, but it needs a further refinement for the case when the line has a single letter:

\documentclass{article}
\usepackage{xparse,l3regex}
\usepackage{fontspec}

\ExplSyntaxOn
\NewDocumentCommand{\bigtext}{mm}
 { % #1 = width, #2 = text, with \\ to separate lines
  \ebo_bigtext:nn { #1 } { #2 }
 }

\seq_new:N \l_ebo_bigtext_text_seq
\box_new:N \l_ebo_bigtext_line_box
\tl_new:N \l_ebo_bigtext_line_tl

\cs_new_protected:Nn \ebo_bigtext:nn
 {
  \begin{minipage}{#1}
  \baselineskip=-\maxdimen \lineskip=4pt
  \seq_set_split:Nnn \l_ebo_bigtext_text_seq { \\ } { #2 }
  \seq_map_inline:Nn \l_ebo_bigtext_text_seq
   {
    \hbox_set:Nn \l_ebo_bigtext_line_box { \ebo_bigtext_remsb:n { ##1 } }
    \box_resize_to_wd:Nn \l_ebo_bigtext_line_box { \textwidth }
    \box_use:N \l_ebo_bigtext_line_box
   }
  \end{minipage}
 }
\cs_new_protected:Nn \ebo_bigtext_remsb:n
 {
  \tl_set:Nn \l_ebo_bigtext_line_tl { #1 }
  \regex_replace_once:nnN { \A(.) } { \c{ebo_kleft:n}\cB\{\1\cE\} } \l_ebo_bigtext_line_tl
  \regex_replace_once:nnN { (.)\Z } { \c{ebo_kright:n}\cB\{\1\cE\} } \l_ebo_bigtext_line_tl
  \tl_use:N \l_ebo_bigtext_line_tl
 }
\cs_new_protected:Nn \ebo_kleft:n
 {
  \kern-\XeTeXglyphbounds1~\the\XeTeXcharglyph`#1 #1
 }
\cs_new_protected:Nn \ebo_kright:n
 {
  #1\kern-\XeTeXglyphbounds3~\the\XeTeXcharglyph`#1
 }
\ExplSyntaxOff

\begin{document}

\noindent
\bigtext{15em}{SOME \\ TOTALLY \\ HIPSTER \\ QUOTE \\ ABOUT \\ LIFE}
\quad
\sffamily
\bigtext{15em}{SOME \\ TOTALLY \\ HIPSTER \\ QUOTE \\ ABOUT \\ LIFE}

\end{document}

enter image description here

  • 1
    @ebo What you call “protrusion” is just how characters are designed; some have side-bearings, some haven't. You clearly see that the sans-serif L in my example has a side-bearing. You can remove them with XeTeX (only using OpenType/TrueType fonts). – egreg Jun 29 '16 at 8:27
  • Indeed, side-bearing is the term: I'll have a look at Precision copyfitting in xcoffin that you helped to solve! – ebosi Jun 29 '16 at 8:47
  • @ebo That's what I seemed to remember. – egreg Jun 29 '16 at 8:48
  • 1
    @ebo Done; don't try the code with a single letter in a line – egreg Jun 29 '16 at 9:27
  • 1
    This might be overkill, but is it possible to get some middleway between these two settings? I think it gives the illusion of not being straight anymore. – Runar Jun 29 '16 at 11:13
11

Here is a solution using adjustbox The vertical spacing between lines could be altered a bit, and the syntax could probably need some approvements.

Output

enter image description here

Code

\documentclass[11pt, margin=5pt]{standalone}
\usepackage{adjustbox}
\usepackage{xcolor}
\usepackage{pgffor}
\usepackage{helvet}

\definecolor{Pink}{HTML}{E22E3B}
\definecolor{Blue}{HTML}{0C2153}
\definecolor{DarkBlue}{HTML}{0C1C3B}
\definecolor{Red}{HTML}{C51E1F}

\setlength{\fboxrule}{4pt}
\setlength{\fboxsep}{10pt}

\newcommand{\BigWords}[1]{%
        \adjustboxset{min width=\linewidth, margin*=0.2em 1ex 0ex 0ex}%
        \foreach \i [count=\ni] in {#1}{%
                \ifnum\ni=1    
                        \adjustbox{}{\i}%
                \else
                        \\\adjustbox{}{\i}%
                \fi
        }\vspace{-1ex}%
}
\begin{document}
\fbox{%
    \begin{minipage}{15cm}
    \bfseries\sffamily
    \BigWords{SOME,TOTALLY,HIPSTER,QUOTE,ABOUT,LIFE}%
    \end{minipage}%
}%
\hspace{2em}%
\setlength{\fboxrule}{0.5pt}%
\fbox{%
    \begin{minipage}{20cm}
    \bfseries\sffamily
    \BigWords{
    \textcolor{Pink}{RUN},
    \textcolor{Blue}{LIKE},
    \textcolor{DarkBlue}{RYAN},
    \textcolor{Red}{GOSLING},
    \textcolor{Pink}{IS WAITING},
    \textcolor{Blue}{FOR YOU},
    \textcolor{DarkBlue}{AT THE},
    \textcolor{Red}{FINISH LINE},
    \textcolor{Pink}{(WITH A PUPPY)}%
    }%
    \end{minipage}%
}
\end{document}
  • You have several useless % characters, but miss some in important places. – egreg Jun 28 '16 at 13:21
  • @egreg I believe it is better now, thank you for pointing it out :) – Runar Jun 28 '16 at 15:31
  • Yes, I removed some (not really important) and added a couple (important). ;-) – egreg Jun 28 '16 at 15:46
  • Thank you for your answers! I've edited my question based on your results with a refinement about kerning. I'm trying to figure out how to disable protrusion, but if you feel like it, do not hesitate to update your answer (-; – ebosi Jun 29 '16 at 8:17
5

Here's one option, just using resizebox

\documentclass{article}
\usepackage{graphicx}
\begin{document}
\newlength\foo
\setlength\foo{15em}
\noindent
\resizebox{\foo}{!}{SOME}\\
\resizebox{\foo}{!}{TOTALLY}\\
\resizebox{\foo}{!}{HIPSTER}\\
\resizebox{\foo}{!}{QUOTE}\\
\resizebox{\foo}{!}{ABOUT}\\
\resizebox{\foo}{!}{LIFE}\\
\end{document}

It's inelegant and cumbersome. But it's a proof of concept. This could be combined with the answers to this question for a more automatic solution.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.