Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

I want to write a text in which each letter uses a different font. It is rather short. I guess I could make it letter by letter, selecting the font I want for each of them.

Are there easier ways?

share|improve this question
    
Do you care at all which fonts the package chooses? This is possible (make all letters active!) but weird and I guess more trouble to write the package than to do this by hand. –  Charles Stewart Oct 27 '10 at 8:59
    
An \everyletter hook would make this easy. Could such a thing be done in Luatex? –  Charles Stewart Oct 27 '10 at 9:00
1  
@Charles: It should not be hard to write a macro that gives a piece of text certain attribute (luatex attributes) and a function at pre_linebreak_filter this assigns nodes with that attribute a random font from a predefined set. But it might be too much work for a one use only feature. –  Khaled Hosny Oct 27 '10 at 9:19
1  
If the document itself is the text, I'd rather write a Python script that creates the TeX source file (then again, I'm more proficient in Python than in TeX, so YMMV). –  Martin Tapankov Oct 27 '10 at 9:58
    
why would you want to do this? –  Seamus Oct 31 '10 at 11:49
show 1 more comment

2 Answers

up vote 7 down vote accepted

Right, I'm sure that this could be vastly improved. In particular, it doesn't like spaces and it doesn't like being fed an argument (so using the lipsum package to demonstrate it didn't work). Of course, the kerning is completely messed up, but then I'd be amazed at a solution that got that right!

alt text

It uses the fontspec package, and for some reason unknown to me, to use the proper names of the fonts required me to use lualatex instead of xelatex.

Without further ado, here's the code:

\documentclass{article}

\usepackage{fontspec}
\pagestyle{empty}

\newfontfamily\fonta{TeX Gyre Bonum}
\newfontfamily\fontb{TeX Gyre Adventor}
\newfontfamily\fontc{TeX Gyre Chorus}
\newfontfamily\fontd{TeX Gyre Heros}
\newfontfamily\fonte{TeX Gyre Pagella}
\newfontfamily\fontf{TeX Gyre Schola}
\newfontfamily\fontg{TeX Gyre Termes}
\newfontfamily\fonth{GFS Artemisia}
\newfontfamily\fonti{GFS Bodoni}
\newfontfamily\fontj{Iwona}
\newfontfamily\fontk{GFS Didot}
\newfontfamily\fontl{GFS Neohellenic}
\newfontfamily\fontm{Kurier}
\newfontfamily\fontn{Free Mono}
\newfontfamily\fonto{Free Sans}
\newfontfamily\fontp{Free Serif}
\newfontfamily\fontq{Inconsolata}
\newfontfamily\fonts{Linux Libertine O}
\newfontfamily\fontt{Cyklop}
\newfontfamily\fontu{Old Standard}
\newfontfamily\fontv{Antykwa Poltawskiego}
\newfontfamily\fontw{STIX General}
\newfontfamily\fontx{Punknova}
\newfontfamily\fonty{Semafor}
\newfontfamily\fontz{UM Typewriter}

\makeatletter
\edef\my@relax{\relax}
\newcommand{\do@font}[1]{%
  \edef\my@arg{#1}%
  \ifx\my@arg\my@relax
  \else
  \@ifundefined{font#1}{}{%
    \csname font#1\endcsname}%
  \my@arg
  \expandafter\do@font
  \fi}

\newcommand{\dofont}[1]{%
  \edef\my@arg{#1}%
  \expandafter\do@font\my@arg\relax}
\makeatother

\begin{document}
\Large
\dofont{the quick brown fox jumped over the lazy dog}

\dofont{abcdefghijklmnopqrstuvwxyz}

\end{document}

All the fonts are ones that I found in my TeXLive2010 distribution.

share|improve this answer
    
XeLaTeX fonts can only be loaded by name if they are installed in the operating system (Mac) or with fontconfig (Windows/Linux). –  Will Robertson Oct 28 '10 at 0:20
    
@Will: Thanks! That's cleared that up for me. –  Andrew Stacey Oct 28 '10 at 10:41
add comment

Here is a different approach than what I proposed above, The following lua code is to be saved in a file randomfont.lua:

function randomfonts(fonts, text)
    local list = { }
    local last, new

    for s in string.gmatch(fonts,"([^, ]+)") do
        list[#list+1] = s
    end

    for c in string.utfcharacters(text) do
        if c:is_empty() then
            tex.sprint(c)
        else
            while last==new do
                new = math.random(#list)
            end
            tex.sprint(luatexbase.catcodetables.latex,
                string.format([[{\%s %s}]], list[new], c))
            last = new
        end
    end
end

And a test file:

\documentclass{article}
\usepackage{xcolor,fontspec}
\newfontfamily\one[Color=red]{TeX Gyre Termes}
\newfontfamily\two[Color=blue]{TeX Gyre Pagella}
\newfontfamily\three[Color=yellow]{TeX Gyre Heros}
\newfontfamily\four[Color=green]{TeX Gyre Bonum}

\directlua{dofile("randomfont.lua")} % load the lua file

\newcommand\randomfonts[2]{%
  \directlua{randomfonts("#1", "#2")}%
}

\begin{document}
% can take text strings
\randomfonts{one, two, three, four}{abcdef ghijk lmn o}

% or even macros
\def\sometext{the quick brown fox jumps over the lazy dog}
\randomfonts{one, two, three, four}{\sometext}
\end{document}

Update: updated to load the lua file just once instead of loading it with each macro invocation.

Update 2: now using string.utfcharacters(text) instead of unicode.utf8.gmatch(text,".") as the former looks better (it is a luatex extension to lua string library)

Update 3: make the lua code more compact, and make sure next character is always using a different font.

share|improve this answer
    
Also you seem to be generating (and parsing) the list of fonts t each time you produce a single letter. Could you do this only once in the code of randomfonts? –  Juan A. Navarro Oct 31 '10 at 8:09
    
@Juan: right, it was craft for previous, pre-post, iterations, now fixed. –  Khaled Hosny Oct 31 '10 at 9:20
    
Nice, but it won't work if the argument isn't purely expandable (say, \lipsum[1] for example). So, IMO, the pre_linebreak_filter approach would be superior. –  mpg Oct 31 '10 at 13:53
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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