解决方案

解决方案

我想定义一个更简单的别名来\includegraphics使用这个合成器:

\Img[width x height][other_opts]{filename}

...这相当于:

\includegraphics[width=width, height=height, other_opts...]{filename}

这是我为尝试实现它而做的事情:

\usepackage{xparse}
\usepackage{graphicx}
\usepackage{trimspaces}


\def\trim@{\trim@spaces}

\def\ImgSize@#1x#2{width=\trim@{#1},height=\trim@{#2}}

\DeclareDocumentCommand \Img {o o m}{%
  \includegraphics[%
    \IfValueT{#1}{\ImgSize@#1,}%
    \IfValueT{#2}{#2,}
  ]{#3}
}

...但是它不起作用。当我不传递可选选项 ( 时\Img{file.png},我得到一个 `! Package keyval Error: undefined.

当我传递一个尺寸(\Img[5cm x 20cm]{file.png})时,我得到: Package keyval Error: width=5cm ,height=20cm, undefined.

对于第二种情况,我的猜测是存在扩展问题,并且\ImgSize扩展为单个标记...但是对于第一种情况我不知道......(实际上,我甚至不确定第二种情况......)

我怎样才能让这样的宏发挥作用?

答案1

解决方案

以下操作可满足您的要求。由于o-type 参数在未使用时不会受到处理器的影响,因此我们可以在顶层测试是否存在可选参数,否则我们将拆分参数转发到内部。可以通过检查是否为来测试的第一个可选参数是否有\Img。在这种情况下,我们假设参数是宽度(不再检查)。如果确实使用了(因此第一个可选参数包含),我们测试是否为空白(这将是一个参数,就像您只想要高度一样)并相应地分支。x#2-NoValue-#2x#1x5cm

编辑:您现在也可以将第一个可选参数留空,如果由于某种原因您既不需要width也不用,但无论如何出于某种原因height使用。\Img

\documentclass[]{article}

\usepackage{graphicx}

\makeatletter
\ExplSyntaxOn
\cs_new_eq:NN \myifblankTF \tl_if_blank:nTF
\ExplSyntaxOff
\NewDocumentCommand\Img{>{\SplitArgument{1}{x}}o O{} m}
  {%
    \IfNoValueTF{#1}
      {\includegraphics{#3}}
      {\Img@#1{#2}{#3}}%
  }
\newcommand*\Img@[4]
  {%
    \IfNoValueTF{#2}
      {%
        \myifblankTF{#1}
          {\includegraphics[{#3}]{#4}}%
          {\includegraphics[{width={#1},#3}]{#4}}%
      }%
      {%
        \myifblankTF{#1}
          {\includegraphics[{height={#2},#3}]{#4}}
          {\includegraphics[{width={#1},height={#2},#3}]{#4}}%
      }%
  }
\makeatother

\begin{document}
\Img{example-image-duck}
\Img[5cm]{example-image-duck}
\Img[x5cm]{example-image-duck}
\Img[3cmx5cm]{example-image-duck}
\Img[3cmx5cm][keepaspectratio]{example-image-duck}
\Img[][scale=0.8]{example-image-duck}
\end{document}

在此处输入图片描述

分支较少的解决方案

下面的代码通过完全扩展可选参数(保护在处理其参数\includegraphics之前不应扩展的所有内容)来使用更少的分支。\includegraphics

\documentclass[]{article}

\usepackage{graphicx}

\ExplSyntaxOn
\NewDocumentCommand\Img{>{\SplitArgument{1}{x}}o O{} m}
  {%
    \IfNoValueTF{#1}
      { \includegraphics {#3} }
      { \__hlOET_img:nnnn #1 {#2} {#3} }%
  }
\cs_new_protected:Npn \__hlOET_img:nnnn #1#2#3#4
  {%
    \use:x
      {
        \exp_not:N \includegraphics
          [{
            \tl_if_blank:nF {#1} { width = { \exp_not:n {#1} } , }
            \IfNoValueF {#2} { height = { \exp_not:n {#2} } , }
            \exp_not:n {#3}
          }]
      }
      {#4}
  }
\ExplSyntaxOff

\begin{document}
\Img{example-image-duck}
\Img[5cm]{example-image-duck}
\Img[x5cm]{example-image-duck}
\Img[3cmx5cm]{example-image-duck}
\Img[3cmx5cm][keepaspectratio]{example-image-duck}
\Img[][scale=0.8]{example-image-duck}
\end{document}

输出如上。

简要解释一下你的方法为什么不起作用

keyval首先用逗号分割键列表。您的代码中没有逗号,因为在开始解析\includegraphics之前,可选参数 的任何内容都没有展开。因此,找到的第一个(也是唯一的)键(因为它在逗号处被分割,逗号没有隐藏在括号内)是,然后检查它是否是已定义的键,显然不是,然后抛出错误。在输出错误消息期间(以及在测试已定义的键宏时),所有这些都将展开,您将获得问题中描述的输出。keyval\IfValueT{#1}{\ImgSize@#1,}\IfValueT{#2}{#2,}

相关内容