3

I am learning about making LaTeX commands. I thought that they were just macro, and the command is replaced literally by its definition. But the following example does not work and I wanted to ask if it could be made to work and, more important, why it does not work.

Given this

\documentclass[]{article}%
\usepackage[demo]{graphicx}
\begin{document}
  \includegraphics[width=0.8\textwidth]{whatever}  %standard
\end{document}

I wanted to build the width=0.8\textwidth using my own command. This works:

\documentclass[]{article}%
\usepackage[demo]{graphicx}
  \newcommand{\X}[1]{#1\textwidth}  %works
\begin{document}
  \includegraphics[width=\X{0.8}]{whatever} %newcommand
\end{document}

But when changing the whole thing to be command, like this:

\documentclass[]{article}%
\usepackage[demo]{graphicx}
  \newcommand{\Y}[1]{width=#1\textwidth} %does not work
\begin{document}
  \includegraphics[\Y{0.8}]{whatever}
\end{document}

Latex gave the following error:

 Missing \endcsname inserted. \includegraphics[\Y{0.8}]{whatever}

So my whole thinking that commands are just blind macro replacements (like #define in C) was wrong, or maybe Latex is trying to evaluate things inside the \newcommand and that is why it complained?

Is there a way to make the last example above work as shown?

TL 2015

  • It is to do with... er... does the term 'expansion' mean much to you? If your heart isn't sinking, you have a whole world of woe yet to discover.... – cfr Jul 24 '15 at 2:53
  • @cfr I do not know what "expansion" exactly mean in Latex world. Is it like Latex is trying to evaluate the command before it is applied to the \includegraphics part? something like this may be. I do not know, that is why I am asking. – Nasser Jul 24 '15 at 2:55
  • 1
    It sees width=stuff as a single unit. So it complains that it doesn't know that key because the key it knows is width and not width=stuff. Expanding a macro within an argument to another command is, in general, tricky. In this case, the way that it gets parsed is that it tries to make the whole spec into a key which \includegraphics knows.... But I am not a good person to be commenting on this at all. It is well beyond my ken. – cfr Jul 24 '15 at 3:03
  • 2
    to extend @cfr's comment, you may do \expandafter\includegraphics\expandafter[\Y{0.8}]{whatever} to get it to work – Thomas Weise Jul 24 '15 at 3:03
  • As @ThomasWeise's comment shows, you're probably better off doing something like \newcommand{\Y}[2][1]{\includegraphics[width=#1\textwidth]{#2}} (then \Y[0.5]{whatever and \Y{whatever}) if you're really keen on saving some typing and will have many images that must be set at different widths. – jon Jul 24 '15 at 3:27
4

You will have to expand the optional argument in order for \Y{<x>} to appropriately be seen as width=<x>\textwidth. Here are a number of ways to achieve this:

First approach:

An indirect way of expanding the optional argument (and possibly the mandatory one, depending on the usage).

\documentclass{article}
\usepackage{graphicx}
\newcommand{\Y}[1]{width=#1\textwidth}
\let\oldincludegraphics\includegraphics
\renewcommand{\includegraphics}{\expandafter\oldincludegraphics\expandafter}
\begin{document}
\includegraphics[\Y{0.1},height=50pt]{example-image}
\end{document}

Second approach

A more direct approach by expanding only the optional argument.

\documentclass{article}
\usepackage{graphicx,letltxmacro}
\newcommand{\Y}[1]{width=#1\textwidth}
\LetLtxMacro\oldincludegraphics\includegraphics
\renewcommand{\includegraphics}[2][]{%
  \expandafter\oldincludegraphics\expandafter[#1]{#2}}
\begin{document}
\includegraphics[\Y{0.1},height=50pt]{example-image}
\end{document}

Third approach

A complete expansion of the macros argument(s).

\documentclass{article}
\usepackage{graphicx,letltxmacro}
\newcommand{\Y}[1]{width=#1\textwidth}
\LetLtxMacro\oldincludegraphics\includegraphics
\renewcommand{\includegraphics}[2][]{%
  \begingroup\edef\x{\endgroup%
    \noexpand\oldincludegraphics[#1]{#2}}\x}
\begin{document}
\includegraphics[\Y{0.1},height=50pt]{example-image}
\end{document}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.