如何检测 XeLaTeX 中的换行并相应地更改字母间距?

如何检测 XeLaTeX 中的换行并相应地更改字母间距?

我需要严格按照单行格式(即每行一个“短语”)排版大量短“短语”(由几个单词组成)。我还使用 XeLaTeX 下的 fontspec 来扩展默认排版样式中的字母间距。当“短语”对于可用的文本宽度来说有点太长(字母间距已扩展)时,就会出现问题。有没有办法检测 XeLaTeX 中的换行并自动减少字母间距以使“短语”适合?

例如:第一个 parbox - 不需要的换行;第二个 parbox - 所需的结果。

\documentclass{article}
\usepackage{fontspec}
\usepackage{polyglossia}

\setmainfont{Times New Roman}
\setlength\parindent{0pt}
\begin{document}%
\parbox{4.5cm}{\addfontfeature{LetterSpace=10.0}AAA BBB CCC DDD EEE FFF}\\
\parbox{4.5cm}{\addfontfeature{LetterSpace=0.0}AAA BBB CCC DDD EEE FFF}
\end{document}

XeLaTeX 结果

==================

编辑/更新:基于 egreg 的代码,我尝试构建一些半工作的东西,并且成功了 50%。简而言之,我尝试删除“拟合循环”(用零间距替换它)并将“拉伸” \makebox-es 转换为“左对齐”:

\documentclass{article}
\usepackage{fontspec}
\usepackage{polyglossia}

\setmainfont{Times New Roman}
\setlength\parindent{0pt}

\ExplSyntaxOn

\box_new:N \l__avilov_spaceout_try_box
\fp_new:N \l__avilov_spaceout_factor_fp

\NewDocumentCommand{\spaceouttowidth}{mm}
 {% #1 = width, #2 = text
  % initialize
  \fp_set:Nn \l__avilov_spaceout_factor_fp { 10 }
  \avilov_spaceout_main:nn { #1 } { #2 }
 }

\cs_new_protected:Nn \avilov_spaceout_main:nn
 {
  \hbox_set:Nn \l__avilov_spaceout_try_box
   {
    \addfontfeature{LetterSpace=\fp_use:N \l__avilov_spaceout_factor_fp}
    #2
   }
  \dim_compare:nTF { \box_wd:N \l__avilov_spaceout_try_box <= #1 }
   {% the box fits
    \makebox[#1][l]{\hbox_unpack_drop:N \l__avilov_spaceout_try_box}
   }
   {% reset the letter spacing to zero
    \fp_set:Nn \l__avilov_spaceout_factor_fp { 0 }
    \makebox[#1][l]{\hbox_unpack_drop:N \l__avilov_spaceout_try_box}
   }
   % uncomment the next line to print the factor (debugging tool)
   \makebox[0pt][l]{\tiny\fp_use:N \l__avilov_spaceout_factor_fp}
 }

\ExplSyntaxOff

\begin{document}
\rule{5cm}{0.4pt}

\spaceouttowidth{5cm}{AAA BBB CCC DDD EEE FFF}

\spaceouttowidth{5cm}{AAA BBB CCC DDD EEE FF}

\spaceouttowidth{5cm}{AAA BBB CC DD EE FF}

\spaceouttowidth{5cm}{AAA BBB CCC DDD EEE FFF GGG}

\end{document}

更新结果

可以看出,(在 \makebox-es 中将 [s] 更改为 [l] 后)不再对 LetterSpacing 做出反应 - 我不明白为什么。请帮忙!

另外,我希望有一个故障安全行为,即使“缩小”的文本不适合,它也会换行(即具有 parbox 行为),而不仅仅是向右突出。我也不明白如何编写代码。

答案1

您可以边试排版边减少字母间距。最后,通过稍微扩大单词间距,文本就可以排版到规定的宽度。

\documentclass{article}
\usepackage{fontspec}
\usepackage{polyglossia}

\setmainfont{Times New Roman}
\setlength\parindent{0pt}

\ExplSyntaxOn

\box_new:N \l__avilov_spaceout_try_box
\fp_new:N \l__avilov_spaceout_factor_fp

\NewDocumentCommand{\spaceouttowidth}{mm}
 {% #1 = width, #2 = text
  % initialize
  \fp_set:Nn \l__avilov_spaceout_factor_fp { 10 }
  \avilov_spaceout_main:nn { #1 } { #2 }
 }

\cs_new_protected:Nn \avilov_spaceout_main:nn
 {
  \hbox_set:Nn \l__avilov_spaceout_try_box
   {
    \addfontfeature{LetterSpace=\fp_use:N \l__avilov_spaceout_factor_fp}
    #2
   }
  \dim_compare:nTF { \box_wd:N \l__avilov_spaceout_try_box <= #1 }
   {% the box fits
    \makebox[#1][s]{\hbox_unpack_drop:N \l__avilov_spaceout_try_box}
    % uncomment the next line to print the factor (debugging tool)
    %\makebox[0pt][l]{\tiny\fp_use:N \l__avilov_spaceout_factor_fp}
   }
   {% reduce the letter spacing and retry
    \fp_add:Nn \l__avilov_spaceout_factor_fp { -0.1 }
    \fp_compare:nTF { \l__avilov_spaceout_factor_fp > 0 }
     {% still something to do
      \avilov_spaceout_main:nn { #1 } { #2 }
     }
     {% give up
      \mode_leave_vertical: \box_use:N \l__avilov_spaceout_try_box
      % uncomment the next line to print the message (debugging tool)
      %\makebox[0pt][l]{\tiny !!!!!~Doesn't~fit}
     }
   }
 }

\ExplSyntaxOff

\begin{document}

\rule{5cm}{0.4pt}

\spaceouttowidth{5cm}{AAA BBB CCC DDD EEE FFF}

\spaceouttowidth{5cm}{AAA BBB CCC DDD EEE FF}

\spaceouttowidth{5cm}{AAA BBB CCC DDD EEE FFF GGG}

\end{document}

对于图片,我删除了%字符以获取调试信息。

小心!这很慢。

在此处输入图片描述

当试验不成功时,不填充宽度并换行:

\documentclass{article}
\usepackage{fontspec}
\usepackage{polyglossia}

\setmainfont{Times New Roman}
\setlength\parindent{0pt}

\ExplSyntaxOn

\box_new:N \l__avilov_spaceout_try_box
\fp_new:N \l__avilov_spaceout_factor_fp

\NewDocumentCommand{\spaceouttowidth}{mm}
 {% #1 = width, #2 = text
  % initialize
  \fp_set:Nn \l__avilov_spaceout_factor_fp { 10 }
  \avilov_spaceout_main:nn { #1 } { #2 }
 }

\cs_new_protected:Nn \avilov_spaceout_main:nn
 {
  \hbox_set:Nn \l__avilov_spaceout_try_box
   {
    \addfontfeature{LetterSpace=\fp_use:N \l__avilov_spaceout_factor_fp}
    #2
   }
  \dim_compare:nTF { \box_wd:N \l__avilov_spaceout_try_box <= #1 }
   {% the box fits
    \mode_leave_vertical: \box_use:N \l__avilov_spaceout_try_box
    % uncomment the next line to print the factor (debugging tool)
    \makebox[0pt][l]{\tiny\fp_use:N \l__avilov_spaceout_factor_fp}
   }
   {% reduce the letter spacing and retry
    \fp_add:Nn \l__avilov_spaceout_factor_fp { -0.1 }
    \fp_compare:nTF { \l__avilov_spaceout_factor_fp > 0 }
     {% still something to do
      \avilov_spaceout_main:nn { #1 } { #2 }
     }
     {% give up
      \parbox[t]{#1}
       {
        \raggedright 
        \addfontfeature{LetterSpace=10}
        #2
        % uncomment the next line to print the factor (debugging tool)
        \makebox[0pt][l]{\tiny !!!!!~Doesn't~fit}
       }
     }
   }
 }

\ExplSyntaxOff

\begin{document}

\rule{5cm}{0.4pt}

\spaceouttowidth{5cm}{AAA BBB CCC DDD EEE FFF}

\spaceouttowidth{5cm}{AAA BBB CCC DDD EEE FF}

\spaceouttowidth{5cm}{AAA BBB CCC DDD EEE FFF GGG}

\end{document}

在此处输入图片描述

你可能希望设置字母间距的最小值,比如 5,

\fp_compare:nTF { \l__avilov_spaceout_factor_fp > 4.9 }

相关内容