OpenType 的‘rand’(随机化)功能在 XeTeX 中未正确实现?

OpenType 的‘rand’(随机化)功能在 XeTeX 中未正确实现?

如果 XeLaTeX (v3.14159265-2.6-0.99996) 编译

\documentclass{article}
\usepackage{fontspec} 
\setmainfont[Letters=Random]{punknova-regular.otf}
\begin{document}
bananes et ananas
\end{document}

它将输出一个每个字形只有一个固定变体的文档(每个“a”都是相同的图片):

随机变体是固定变体

省略Letters=Random表明 XeLaTeX 确实能够使用变体,但不能随机选择它们:

无变体字形

相比之下,LuaLaTeX 可以正确编译相同的文档:

LuaLaTeX 可以处理随机化功能

问题是,这是 XeLaTeX 中的一个错误,或者是否有可能强制 XeLaTeX 循环使用随机变体(例如通过向 fontspec 添加一个选项)?

答案1

我不认为+rand支持,但是您可以通过名称访问所有变体(在“a”的情况a.1a.31),然后使用 PGFrandom函数在 TeX 中随机化。

在此处输入图片描述

\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}

综合起来,你可以制作一个包含字形名称和变体数量的表格,然后:

在此处输入图片描述

\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}

答案2

这是对 David Carlisle 答案的扩展。我们可以不使用字形名称,而是将rand特征视为一个简单的多个替代特征,并尝试随机访问这些替代特征:

\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}

XeTeX 输出

但也有一些注意事项:

  • 由于实现方式的原因\addfontfeature{},字符之间的字体功能将无法使用(字距调整、连字等),因为每个替代字体将使用不同的字体。但对于 Punk Nova 来说这不是问题,因为它没有任何此类功能(如果我没记错的话)。
  • 目前无法获取该功能(上述31)支持的替代数量,需要从外部检查字体或使用任意数字。
  • 上面的宏中的空格需要转义,但这可能是因为我的 TeX 技能不好(我只是从https://tex.stackexchange.com/a/253205/729)。

不需要转义空格的版本

\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}

在此处输入图片描述

相关内容