我想定义一个更简单的别名来\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-
#2
x
#1
x5cm
编辑:您现在也可以将第一个可选参数留空,如果由于某种原因您既不需要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,}