OpenType 'rand' (Randomize) feature not correct implemented in XeTeX?
I don't think +rand
is supported however you can access all the variants by name (a.1
to a.31
in the case of "a") and then randomise in TeX eg using the PGF random
function.
\documentclass{article}
\usepackage{fontspec}
\setmainfont[Letters=Random]{punknova-regular.otf}
\usepackage{pgf}
\begin{document}
\XeTeXglyph\XeTeXglyphindex "a"
\XeTeXglyph\XeTeXglyphindex "a.1"
\XeTeXglyph\XeTeXglyphindex "a.2"
\XeTeXglyph\XeTeXglyphindex "a.3"
\XeTeXglyph\XeTeXglyphindex "a.4"
\XeTeXglyph\XeTeXglyphindex "a.5"
\XeTeXglyph\XeTeXglyphindex "a.6"
\pgfmathparse{random(31)}\XeTeXglyph\XeTeXglyphindex "a.\pgfmathresult"
\pgfmathparse{random(31)}\XeTeXglyph\XeTeXglyphindex "a.\pgfmathresult"
\pgfmathparse{random(31)}\XeTeXglyph\XeTeXglyphindex "a.\pgfmathresult"
\pgfmathparse{random(31)}\XeTeXglyph\XeTeXglyphindex "a.\pgfmathresult"
\pgfmathparse{random(31)}\XeTeXglyph\XeTeXglyphindex "a.\pgfmathresult"
\pgfmathparse{random(31)}\XeTeXglyph\XeTeXglyphindex "a.\pgfmathresult"
\pgfmathparse{random(31)}\XeTeXglyph\XeTeXglyphindex "a.\pgfmathresult"
\pgfmathparse{random(31)}\XeTeXglyph\XeTeXglyphindex "a.\pgfmathresult"
\pgfmathparse{random(31)}\XeTeXglyph\XeTeXglyphindex "a.\pgfmathresult"
\pgfmathparse{random(31)}\XeTeXglyph\XeTeXglyphindex "a.\pgfmathresult"
\pgfmathparse{random(31)}\XeTeXglyph\XeTeXglyphindex "a.\pgfmathresult"
\end{document}
Putting it all together, you can make a table with the glyph names and number of variants and then:
\documentclass{article}
\def\pntable#1#2#3{%
\expandafter\def\csname pn\number"#1-name\endcsname{#2}%
\expandafter\def\csname pn\number"#1-max\endcsname{#3}%
}
\pntable{0021}{exclam}{7}
\pntable{0022}{quotedbl}{7}
\pntable{0023}{numbersign}{7}
\pntable{0024}{dollar}{7}
\pntable{0025}{percent}{7}
\pntable{0026}{ampersand}{7}
\pntable{0027}{quotesingle}{7}
\pntable{0028}{parenleft}{7}
\pntable{0029}{parenright}{7}
\pntable{002A}{asterisk}{7}
\pntable{002B}{plus}{7}
\pntable{002C}{comma}{7}
\pntable{002D}{hyphen}{7}
\pntable{002E}{period}{7}
\pntable{002F}{slash}{7}
\pntable{0030}{zero}{7}
\pntable{0031}{one}{7}
\pntable{0032}{two}{7}
\pntable{0033}{three}{7}
\pntable{0034}{four}{7}
\pntable{0035}{five}{7}
\pntable{0036}{six}{7}
\pntable{0037}{seven}{7}
\pntable{0038}{eight}{7}
\pntable{0039}{nine}{7}
\pntable{003A}{colon}{7}
\pntable{003B}{semicolon}{7}
\pntable{003C}{less}{7}
\pntable{003D}{equal}{7}
\pntable{003E}{greater}{7}
\pntable{003F}{question}{7}
\pntable{0040}{at}{7}
\pntable{0041}{A}{15}
\pntable{0042}{B}{15}
\pntable{0043}{C}{15}
\pntable{0044}{D}{15}
\pntable{0045}{E}{15}
\pntable{0046}{F}{15}
\pntable{0047}{G}{15}
\pntable{0048}{H}{15}
\pntable{0049}{I}{15}
\pntable{004A}{J}{15}
\pntable{004B}{K}{15}
\pntable{004C}{L}{15}
\pntable{004D}{M}{15}
\pntable{004E}{N}{15}
\pntable{004F}{O}{15}
\pntable{0050}{P}{15}
\pntable{0051}{Q}{15}
\pntable{0052}{R}{15}
\pntable{0053}{S}{15}
\pntable{0054}{T}{15}
\pntable{0055}{U}{15}
\pntable{0056}{V}{15}
\pntable{0057}{W}{15}
\pntable{0058}{X}{15}
\pntable{0059}{Y}{15}
\pntable{005A}{Z}{15}
\pntable{005B}{bracketleft}{7}
\pntable{005C}{backslash}{7}
\pntable{005D}{bracketright}{7}
\pntable{005E}{asciicircum}{7}
\pntable{005F}{underscore}{7}
\pntable{0060}{grave}{7}
\pntable{0061}{a}{31}
\pntable{0062}{b}{31}
\pntable{0063}{c}{31}
\pntable{0064}{d}{31}
\pntable{0065}{e}{31}
\pntable{0066}{f}{31}
\pntable{0067}{g}{31}
\pntable{0068}{h}{31}
\pntable{0069}{i}{31}
\pntable{006A}{j}{31}
\pntable{006B}{k}{31}
\pntable{006C}{l}{31}
\pntable{006D}{m}{31}
\pntable{006E}{n}{31}
\pntable{006F}{o}{31}
\pntable{0070}{p}{31}
\pntable{0071}{q}{31}
\pntable{0072}{r}{31}
\pntable{0073}{s}{31}
\pntable{0074}{t}{31}
\pntable{0075}{u}{31}
\pntable{0076}{v}{31}
\pntable{0077}{w}{31}
\pntable{0078}{x}{31}
\pntable{0079}{y}{31}
\pntable{007A}{z}{31}
\pntable{007B}{braceleft}{7}
\pntable{007D}{braceright}{7}
\pntable{00A1}{exclamdown}{7}
\pntable{00A8}{dieresis}{7}
\pntable{00AF}{macron}{7}
\pntable{00B4}{acute}{7}
\pntable{00B8}{cedilla}{7}
\pntable{00BF}{questiondown}{7}
\pntable{00C6}{AE}{15}
\pntable{00D8}{Oslash}{15}
\pntable{00DF}{germandbls}{31}
\pntable{00E6}{ae}{31}
\pntable{00F8}{oslash}{31}
\pntable{0131}{dotlessi}{31}
\pntable{0152}{OE}{15}
\pntable{0153}{oe}{31}
\pntable{0237}{uni0237}{31} %dotlessj
\pntable{02C6}{circumflex}{7}
\pntable{02C7}{caron}{7}
\pntable{02D8}{breve}{7}
\pntable{02D9}{dotaccent}{7}
\pntable{02DA}{ring}{7}
\pntable{02DC}{tilde}{7}
\pntable{02DD}{hungarumlaut}{7}
\pntable{0391}{Alpha}{15}
\pntable{0392}{Beta}{15}
\pntable{0393}{Gamma}{15}
\pntable{0394}{Delta}{15}
\pntable{0395}{Epsilon}{15}
\pntable{0396}{Zeta}{15}
\pntable{0397}{Eta}{15}
\pntable{0398}{Theta}{15}
\pntable{0399}{Iota}{15}
\pntable{039A}{Kappa}{15}
\pntable{039B}{Lambda}{15}
\pntable{039C}{Mu}{15}
\pntable{039D}{Nu}{15}
\pntable{039E}{Xi}{15}
\pntable{039F}{Omicron}{15}
\pntable{03A0}{Pi}{15}
\pntable{03A1}{Rho}{15}
\pntable{03A3}{Sigma}{15}
\pntable{03A4}{Tau}{15}
\pntable{03A5}{Upsilon}{15}
\pntable{03A6}{Phi}{15}
\pntable{03A7}{Chi}{15}
\pntable{03A8}{Psi}{15}
\pntable{03A9}{Omega}{15}
\pntable{2013}{endash}{7}
\pntable{2014}{emdash}{7}
\pntable{2018}{quoteleft}{7}
\pntable{2019}{quoteright}{7}
\pntable{201C}{quotedblleft}{7}
\pntable{201D}{quotedblright}{7}
\makeatletter
\def\rndpn#1{\xrndpn#1\relax}
\def\xrndpn#1{%
\ifx\relax#1%
\else
\expandafter\ifx\csname pn\number\expandafter`\noexpand#1-name\endcsname\relax
#1%
\else
\pgfmathrandominteger\pgfmathresult
{1}%
{\csname pn\number\expandafter`\string#1-max\endcsname}%
\XeTeXglyph\XeTeXglyphindex
"\csname pn\number\expandafter`\string#1-name\endcsname.\pgfmathresult"\relax
\fi
\expandafter\xrndpn
\fi}
\usepackage{fontspec}
\setmainfont[Letters=Random]{punknova-regular.otf}
\usepackage{pgf}
\begin{document}
\rndpn{bananes\ et\ ananas}
\end{document}
This is expanding on David Carlisle’s answer. Instead of using glyph names, we can treat rand
feature as a simple multiple alternate feature and try to access those alternates randomly:
\documentclass{article}
\usepackage{fontspec}
\setmainfont{punknova-regular.otf}
\usepackage{pgf}
\begin{document}
\makeatletter
\def\randomalt#1{%
\pgfmathparse{random(31)}%
{\addfontfeature{RawFeature={+rand=\pgfmathresult}}#1}%
}
\def\randomtext#1{\@tfor\next:=#1\do{\randomalt{\next}}}
\makeatother
% XXX: the spaces are eaten by the loop unless escaped!
\randomtext{bananes\ et\ ananas}
\end{document}
There are some caveats, though:
- Due to the way
\addfontfeature{}
is implemented, font features between the characters will not work (kerning, ligatures, etc.) since each alternate will be using a different font. This is not an issue for Punk Nova though as it does not have any such features IIRC. - There is currently no way to get the number of alternates supported by the feature (the
31
above), one will need to examine the font externally or just use an arbitrary number. - The spaces need to be escaped in the macro above, but that is probably because of my poor TeX skills (I just copied the macro from https://tex.stackexchange.com/a/253205/729).
A version that doesn't need to escape spaces
\documentclass{article}
\usepackage{fontspec}
\newfontfamily{\punk}{punknova-regular.otf}
\usepackage{pgf}
\ExplSyntaxOn
\NewDocumentCommand{\randomtext}{m}
{
\group_begin:
\punk
\seq_set_split:Nnn \l_khaled_randomtext_seq { ~ } { #1 }
\seq_map_inline:Nn \l_khaled_randomtext_seq
{
\khaled_random_word:n { ##1 }~
}
\unskip % remove the last space
\group_end:
}
\seq_new:N \l_khaled_randomtext_seq
\cs_new_protected:Nn \khaled_random_word:n
{
\tl_map_inline:nn { #1 }
{
\group_begin:
\pgfmathparse{random(31)}
\addfontfeature{RawFeature={+rand=\pgfmathresult}}##1
\group_end:
}
}
\ExplSyntaxOff
\begin{document}
Normal text
\randomtext{bananes et ananas}
Normal text
\end{document}