1

In this answer, I've been conservative and used the following code:

\expandafter\scalebox\expandafter{\my@scale}{\usebox{\my@box}}

to make sure not to rely on undocumented (?) behavior of \scalebox from the graphicx package (in case you are wondering, \my@scale has been defined with \pgfmathsetmacro). However, as shown in the following example, it seems that \scalebox fully expands at least its first argument, therefore I am considering if I should simplify the above line by removing the two \expandafter calls.

\documentclass{article}
\usepackage{graphicx}
\usepackage{xfp}

\newcommand*{\scalea}{0.5}
\newcommand*{\scaleb}{\scalebaux}
\newcommand*{\scalebaux}{\fpeval{0.5^2}}

\newsavebox{\mybox}
\sbox{\mybox}{\includegraphics{example-image}} % any box would do

\begin{document}

\scalebox{1.0}{\usebox{\mybox}}\par
\scalebox{\scalea}{\usebox{\mybox}}\par
\scalebox{\scaleb}{\usebox{\mybox}}

\end{document}

Screenshot

Questions

  1. Is it considered to be part of the \scalebox API that it fully expands the two arguments giving scale factors, noted 〈h-scale〉 and 〈v-scale〉 in the below syntax reminder?

    \scalebox{〈h-scale〉}[〈v-scale〉]{〈text〉}
    
  2. If you answered “no”, is there any integer n > 0 such that at least n expansion steps are guaranteed to happen on the same two arguments?

  3. Do the previous answers also apply when using:

    \includegraphics{scale=...}{some-file}
    

    ?

Thanks!

Henri Menke
  • 109,596
frougon
  • 24,283
  • 1
  • 32
  • 55
  • 1
    It will expand its first mandatory and its optional argument, they are used inside of dimen assignments, \hbox to cases and inside a \special, in the first two they'll be expanded because that's the way TeX works, in the \special it'll be expanded \edef like (in the special your input will be wrapped inside a \def\Gscale@x and \def\Gscale@y and only those are used inside the \special). – Skillmon Jun 28 '19 at 08:49
  • For the \hbox to 〈dimen〉, it must be full expansion. What is the \special used for here? And does it perform full expansion too? Thanks. – frougon Jun 28 '19 at 08:53
  • 1
    From the TeXbook: "TeX's primitive commands \mark{..}, \message{...}, \errmessage{...}, \special{...}, and \write<number>{...} all expand the token lists in braces almost exactly as \edef and \xdef do." The difference is, that you don't need to double # inside those to put a single # in the argument. – Skillmon Jun 28 '19 at 08:55
  • 1
    classic tex has no notion of scaling, you need to use \special or an equivalent whatsit such as \pdfliteral to inject PostScript or PDF transformations around the tex-generated output – David Carlisle Jun 28 '19 at 09:00
  • 1
    @DavidCarlisle except for font scaling, that is available in classic TeX. – Skillmon Jun 28 '19 at 09:05
  • Thanks for all the comments (I was “away” for 20 minutes). @DavidCarlisle What does your comment reply to? Is it to tell me that the \special is used, and necessary, to implement the scaling operation? From what I've gathered in these comments, we have full expansion for both scale factors. If so, what remains for 1 and 2 in my question is, can we consider this fact to be part of the API? (I guess the answer is yes, to avoid breaking existing code) – frougon Jun 28 '19 at 09:19
  • 1
    I was answering your What is the \special used for here question. It is not so much a matter of not breaking existing code as I don't see how you could define this and avoid expansion. It is same as say \setlength the length argument has to be expanded in the end to get a length. So even though \scalebox doesn't do anything special here the arguments get expanded because tex is a macro expansion language and that is what happens unless you stop it happening. – David Carlisle Jun 28 '19 at 09:24
  • @Skillmon oh yes and \mag scaling of the whole document but they are different beasts, I meant scaling of arbitrary boxes – David Carlisle Jun 28 '19 at 09:26
  • @DavidCarlisle Well, it may sound like a weird idea, but theoretically, it would be possible to design a \scalebox-like macro that handles scale factors such as 0.5e0 without expanding any macro in the argument, only grabbing it token by token and analysing these. So, there is an API choice. I understand, though, that full expansion is part of the API from your POV. BTW, this explicit API aspect regarding expansion is one of the things I find tremendously better in LaTeX3 as compared to LaTeX2e. – frougon Jun 28 '19 at 09:29
  • @frougon in an equivalent expl3 construct such as \dim_set:Nn note the expression argument gets n not x even though (in the sense you mean here) it is fully expanded as the expansion is implied by its use as a length. So I wouldn't say it's any more explicit in this case. – David Carlisle Jun 28 '19 at 09:38
  • @DavidCarlisle Yes, this is one thing in LaTeX3 that surprised me at first (actually, it was for an 〈integer expression〉 such as the first argument of \int_step_inline:nn, but this is the same catch). I've learnt this fact from egreg and find it convenient to use when coding. It just means that the syntax for 〈dimension expression〉 (or 〈integer expression〉) is very flexible: even complex expressions are already conformant to 〈dimension expression〉, before any expansion has been performed on them. But this fact is really part of the LaTeX3 API, IMHO. :-) – frougon Jun 28 '19 at 09:47
  • @frougon no, not really, L3 just puts a \dimexpr...\relax there, same for <integer expression> is just a \numexpr, you could do the same in L2 (see the calc package). – Skillmon Jun 28 '19 at 11:17
  • @Skillmon I don't think what you just said contradicts what I said. The fact that 〈integer expression〉 relies on something like, or being exactly \numexpr ... \relax (and ditto for 〈dimension expression〉 with \dimexpr...\relax), is IMO an implementation detail. When one knows it, one can easily deduce the API, but normally, both are distinct. A given API can in general be implemented in different ways, and most of the time, what matters for users (programmers) is the API, not the implementation details. Back to my question, the factors used by \scalebox are... – frougon Jun 28 '19 at 11:55
  • @Skillmon ... neither a 〈number〉 nor a 〈dimen〉, therefore citing TeX's behavior when reading a 〈number〉 or a 〈dimen〉 is not enough to tell what is legal input for the scale factors. These factors could probably have been 〈floating point expression〉s, had graphicx been written after \fp_eval:n became available—or something similar in the TeX engine. If I understood right, they are used as the 〈factor〉 of a 〈normal dimen〉, which is what prescribes the rules for what is allowed and what isn't. I thought this could be clearly stated as being the intended API, but won't insist anymore... – frougon Jun 28 '19 at 11:56

1 Answers1

3

This is defined by graphics (not graphicx) the package does nothing to expand these arguments but expansion just happens as a natural course of TeX processing. So the \expandafter are not needed.

The subsidiary question asked in comments as to what is the syntax that the arguments may expand into is harder to answer.

The scale factor is used for two separate things:

  1. working out what size the box is (and taking care of negative scale factors etc).

    in this part of the code, TeX dimen arithmetic is used so it has to be a <factor> in TeXBook syntax notation. Specifically things like \ifdim#2\p@<\z@ have to work, where #2 is one of the supplied scale factors.

  2. The scale factor is passed to the back end code to actually scale the typeset output, here it uses \special or \pdfliteral or whatever suitable whatsit is available.

    The default definition for scaling is:

    \providecommand\Gscale@start{\@latex@error{Scaling not supported}\@ehc
                \global\let\Gscale@start\relax}
    

    That is, it gives an error on first use and does nothing otherwise.

    ie, the default definition has all input being invalid.

    So what happens in other cases depends on the driver (and in 1993-4 when this was written there was a lot more variation than there is now, with far more different dvi drivers being used.)

    Even now, dvips.def does

    \Gscale@x\GPT@space \Gscale@y\GPT@space scale
    

    which means that as well as being a legal <factor> the arguments must expand to a legal PostScript number.

    pdftex does something a bit more complicated but the end result is again that the arguments need to expand to a valid PDF number.

Examples of things that are a <factor> but do not expand to a PostScript or PDF number are \count@ or \value{section} or "FF

David Carlisle
  • 757,742
  • Thank you very much! As you pointed out, a 〈factor〉 (according to the TeXbook definition) is too general to define the supported syntax. Closer to the desired definition than 〈factor〉 should be 〈decimal constant〉, I suppose, but this probably isn't restrictive enough either (I see a 〈decimal constant〉 may contain commas, and there may be limits on magnitude, number of digits, etc.). The final specification depends, as I understand your answer, on the driver used. At least, I know that the arguments corresponding to scale factors will be fully expanded. :-) – frougon Jun 28 '19 at 14:15