2

I would like to define a simpler alias for \includegraphics using this synthax :

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

...wich would be equivalent to :

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

This is what I did to try to implement it :

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

...However it doesn't work. When I pass no optional options (\Img{file.png}, I get a `! Package keyval Error: undefined.

When I pass a size (\Img[5cm x 20cm]{file.png}), I get : Package keyval Error: width=5cm ,height=20cm, undefined.

For the second case, my guess is that there is an expansion problem, and \ImgSize is expanded to a single token... But I've no idea for the first one... (Actually, I'm not even sure for the second...)

How could I make such a macro work ? `

2
  • well it is not a "simple" alias what you are trying to do. You should split the argument to extract width and height first and store them in some simple macro or length register and not try to do everything in one go in the includegraphics argument. Beside this: what will you do if you have only one optional argument, is that then always the width/height or the optional args? Commented Mar 28, 2021 at 17:22
  • By simple, I meant "simple to use". If only one argument, always width x height.
    – hl037_
    Commented Mar 28, 2021 at 17:24

1 Answer 1

5

Solution

The following does what you asked for. Since an o-type argument will not be affected by processors if it wasn't used, we can test whether there was an optional argument at all at top level, else we forward the split arguments to an internal. That one can test whether the first optional argument of \Img had an x at all by checking whether #2 is -NoValue-. In that case we assume the argument is the width (no further checks). If #2 was indeed used (so the first optional argument contained an x), we test whether #1 is blank (that would be an argument like x5cm if you only want a height) and branch accordingly.

Edit: you can also leave the first optional argument blank now, if you for some reason need neither width nor height but use \Img for some reason anyway.

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

enter image description here

Solution with less branching

The code below uses less branching by fully expanding the optional argument of \includegraphics (protecting everything that shouldn't expand before \includegraphics processes its argument).

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

Output like above.

Short explanation on why your method didn't work

keyval first splits the list of keys by commas. Your code doesn't have any commas, as nothing of the optional argument of \includegraphics is expanded before keyval starts parsing it. So the first (and only) key that is found (since it was split at commas, which aren't hidden inside braces) is \IfValueT{#1}{\ImgSize@#1,}\IfValueT{#2}{#2,}, it is then checked whether that's a defined key, which it obviously isn't, and the error is thrown. During the output of your error message (and while testing for the defined key macro) all of this will get expanded and you get the output you described in your question.

4
  • Thanks for the explanation ! I actually got a lot information by reading your code and thinking about the problem, and learned a lot about tokens and expansion. I think it is possible to construct the list without having to write all the branching (for two option, it is doable, but I'm ooking for a more generic approach). I'm looking at l3keys to see what is possible with it
    – hl037_
    Commented Mar 29, 2021 at 14:15
  • @hl037_ you don't want another key=value system, you want to interface keyval as employed by graphicx. I don't think there is much gain from l3keys here. One could use less branches (by using an \use:x{\exp_not:N\includegraphics[{\myifblankTF{#1}{}{width={\exp_not:n{#1}},}\IfValueT{#2}{height={\exp_not:n{#2}},}#3}]}{#4} in \Img@) but there is not too much gain from this, imho.
    – Skillmon
    Commented Mar 29, 2021 at 15:01
  • @hl037_ I've added the less-branching variant to the answer (and wrote it in expl3, I hope that's fine).
    – Skillmon
    Commented Mar 29, 2021 at 15:08
  • just wonderful !
    – hl037_
    Commented Mar 29, 2021 at 15:30

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .