我可以制作一个 LaTeX 宏“返回”吗?文件名?

发布于 2024-09-01 13:58:30 字数 2509 浏览 4 评论 0原文

我正在写我的论文/论文,由于它是一项正在进行的工作,我并不总是为我放入文档中的图形准备好实际图像,但由于各种原因希望自动用它代替虚拟图形当包含的图形文件不存在时。例如,我可以执行类似 \includegraphics[width=8cm]{\chapdir/figures/fluxcapacitor} 的操作(其中 \chapdir 是我的“当前”章节目录的宏,例如 \def\chapdir{./ch_timetravel} 如果没有 ./ch_timetravel/figures/fluxcapacitor.jpg 它将插入 ./commands/dummy。 。

我已经构造了我的宏(也许很天真?),以便我有一个宏(\figFileOrDummy),它通过检查是否提供给它的参数来确定要包含的适当文件 存在,这样我就可以调用 \includegraphics[properties]{\figFileOrDummy{\chapdir/figures/fluxcapacitor}} ,但根据我尝试调用它的方式,我会收到各种错误。就“良好的 LaTeX 编程”而言,我正在以一种根本上有缺陷的方式解决这个问题。

这是检查文件是否存在的宏(并“返回”文件名或虚拟文件名):


\newcommand{\figFileOrDummy}[1]{%
    % Figure base name (no extension) to be used if the file exists
    \def\fodname{#1}%
    \def\dummyfig{commands/dummy}%
    % Check if output is PS (.EPS) or PDF (.JPG/.PDF/.PNG/...) figures
    \ifx\pdfoutput\undefined%
        % EPS figures only
        \IfFileExists{\fodname.eps}{}{\def\fodname{\dummyfig}}%
    \else%
        % Check existence of various extensions: PDF, TIF, TIFF, JPG, JPEG, PNG, MPS
        \def\figtest{0}% flag below compared to this value
        \IfFileExists{\fodname.pdf}{\def\figfilenamefound{1}}{\def\figfilenamefound{0}}%
        \IfFileExists{\fodname.jpg}{\def\figfilenamefound{1}}{}%
        \IfFileExists{\fodname.png}{\def\figfilenamefound{1}}{}%
        % and so on...
        % If no files found matching the filename (flag is 0) then use the dummy figure
        \ifx\figfilenamefound\figtest%
            \def\fodname{\dummyfig}%
        \fi%
    \fi%
    % 'return' the filename
    \fodname%
}%

或者,这是一个。更简单的版本似乎有类似的问题:

\newcommand{\figFileOrDummy}[1]{%
    \def\dummyfig{commands/dummy}%
    \dummyfig%
}

\def 命令似乎是在他们试图定义的宏扩展之后处理的,所以它最终被\def {commands/dummy}... (注意 \def 后面的空格)并且明显抱怨。

此外,它似乎将宏的文字内容视为 \includegraphics 的文件名,而不是首先解析/扩展它,因此抱怨文件 '\def {commands/dummy}. .. .png' 不存在..

我也尝试过做类似的事情 \edef\figfilename{\figFileOrDummy{\chapdir/figures/fluxcapacitor}} 尝试强制它使 \figfilename 仅保存而不是完整的宏,但我收到一个 未定义的控制序列 错误,抱怨我试图在 \figFileOrDummy 宏中 \def 的变量未定义。

所以我的问题是

  1. 如何使这个宏正确扩展?
  2. 如果这是构造我的宏的错误方式,我实际上应该如何构造这样的宏,以便能够自动插入虚拟/真实图形? 或者
  3. 是否有一个包已经可以很好地处理我忽略的此类事情?

我觉得我在这里错过了一些非常基本的东西......

I'm writing my thesis/dissertation and since its an on-going work I don't always have the actual images ready for the figures I put into my document, but for various reasons want to automatically have it substitute a dummy figure in place when the included graphics file doesn't exist. E.g. I can do something like \includegraphics[width=8cm]{\chapdir/figures/fluxcapacitor} (where \chapdir is a macro for my 'current' chapter directory, e.g. \def\chapdir{./ch_timetravel} and if there's no ./ch_timetravel/figures/fluxcapacitor.jpg it'll insert ./commands/dummy.jpg instead.

I've structured my macros (perhaps naïvely?) so that I have a macro (\figFileOrDummy) that determines the appropriate file to include by checking if the argument provided to it exists, so that I can call \includegraphics[properties]{\figFileOrDummy{\chapdir/figures/fluxcapacitor}}. Except I'm getting various errors depending on how I try to call this, which seem to suggest that I'm approaching the problem in a fundamentally flawed way as far as 'good LaTeX programming' goes.

Here's the macro to check if the file exists (and 'return' either filename or the dummy filename):


\newcommand{\figFileOrDummy}[1]{%
    % Figure base name (no extension) to be used if the file exists
    \def\fodname{#1}%
    \def\dummyfig{commands/dummy}%
    % Check if output is PS (.EPS) or PDF (.JPG/.PDF/.PNG/...) figures
    \ifx\pdfoutput\undefined%
        % EPS figures only
        \IfFileExists{\fodname.eps}{}{\def\fodname{\dummyfig}}%
    \else%
        % Check existence of various extensions: PDF, TIF, TIFF, JPG, JPEG, PNG, MPS
        \def\figtest{0}% flag below compared to this value
        \IfFileExists{\fodname.pdf}{\def\figfilenamefound{1}}{\def\figfilenamefound{0}}%
        \IfFileExists{\fodname.jpg}{\def\figfilenamefound{1}}{}%
        \IfFileExists{\fodname.png}{\def\figfilenamefound{1}}{}%
        % and so on...
        % If no files found matching the filename (flag is 0) then use the dummy figure
        \ifx\figfilenamefound\figtest%
            \def\fodname{\dummyfig}%
        \fi%
    \fi%
    % 'return' the filename
    \fodname%
}%

Alternatively, here's a much simpler version which seems to have similar problems:

\newcommand{\figFileOrDummy}[1]{%
    \def\dummyfig{commands/dummy}%
    \dummyfig%
}

The \def commands seems to be processed after the expansion of the macro they're trying to define, so it ends up being \def {commands/dummy}... (note the space after \def) and obviously complains.

Also it seems to treat the literal contents of the macro as the filename for \includegraphics, rather than resolving/expanding it first, so complains that the file '\def {commands/dummy}... .png' doesn't exist..

I've tried also doing something like
\edef\figfilename{\figFileOrDummy{\chapdir/figures/fluxcapacitor}} to try to force it to make \figfilename hold just the value rather than the full macro, but I get an Undefined control sequence error complaining the variables I'm trying to \def in the \figFileOrDummy macro are undefined.

So my question is either

  1. How do I make this macro expand properly?; or
  2. If this is the wrong way of structuring my macros, how should I actually structure such a macro, in order to be able to insert dummy/real figures automatically?; or
  3. Is there a package that already handles this type of thing nicely that I've overlooked?

I feel like I'm missing something pretty fundamental here...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

掌心的温暖 2024-09-08 13:58:31

我认为重点是 \expandafter 只对其参数作为表示文件名的字符串感兴趣,因此不会评估它 - 宏语言是懒惰的!尝试 \expandafter {\includegraphics[width=8cm]}{\chapdir/figures/fluxcapacitor}

两点风格:

  1. 如果行以控制序列结尾,则不需要在行尾放置 % 来阻止虚假空格:控制序列会吞噬所有后续空格,包括行尾。根据我的口味,这使得代码更具可读性。请特别注意,对于 Tex 的“嘴”来说, \def\newcs{abc}\def \newcs {abc} 是相同的:它们是完全相同的序列的代币。
  2. 我将代码放在 \figtest 周围:如果您使用 \newif 原语(使用 \newif\figexists 创建新测试,使用 \figexiststrue、\figexistsfalse 设置/重置,并测试),您将获得更好的错误报告 - 始终以 Tex 为溢价 -与 \iffigexists...) 或 Latex ifthenelse 包(以保持正统)。

清理代码

我首先认为问题出在其他地方,所以写了一些更漂亮的东西:

\def\dummypath{commands/dummy}%
\ifx\pdfoutput\undefined
\def\figFileOrDummy#1{\IfFileExists
    {#1.eps}{#1}\dummypath}
\else
\def\figFileOrDummy#1{\IfFileExists
    {#1.pdf}{#1}{\IfFileExists
      {#1.jpg}{#1}{\IfFileExists
        {#1.png}{#1}\dummypath}}} %or have more graphics types, if you like.
\fi

I think the point is that \expandafter is only interested in its arguments as a string representing a filename, so doesn't evaluate it — macro languages are lazy! Try \expandafter {\includegraphics[width=8cm]}{\chapdir/figures/fluxcapacitor}.

Two points of style:

  1. You don't need to put % at the end of a line to stop spurious whitespace if the line ends with a control sequence: the control sequence gobbles up all following whitespace, including the end of line. This makes the code much more readable, to my taste. Note that, in particular, to Tex's "mouth" both \def\newcs{abc} and \def \newcs {abc} are identical: they are exactly the same sequence of tokens.
  2. I dropped the code around \figtest: you get better error reporting -always at a premium with Tex- if you use either \newif primitive (create new test with \newif\figexists, set/reset with \figexiststrue, \figexistsfalse, and test with \iffigexists...) or the Latex ifthenelse package (to keep with orthodoxy).

Cleaned-up code

I first thought the problem lay elsewhere, so wrote something prettier:

\def\dummypath{commands/dummy}%
\ifx\pdfoutput\undefined
\def\figFileOrDummy#1{\IfFileExists
    {#1.eps}{#1}\dummypath}
\else
\def\figFileOrDummy#1{\IfFileExists
    {#1.pdf}{#1}{\IfFileExists
      {#1.jpg}{#1}{\IfFileExists
        {#1.png}{#1}\dummypath}}} %or have more graphics types, if you like.
\fi
无边思念无边月 2024-09-08 13:58:31

对 #3 的回答:为此目的,我发现 todonotes 包非常有用。它没有提供您的代码旨在提供的自动化级别,但它有一个非常好的 \missingfigure 命令,可以让您为(您猜对了)缺失的图形放置一个虚拟框。

Answer to #3: For this purpose, I find very useful the todonotes package. It does not provide the level of automation that your code is aiming to offer, but it has a very nice \missingfigure command that lets you put a dummy box for, you guess it, a missing figure.

若相惜即相离 2024-09-08 13:58:31

好吧,所以我已经找到了问题 2 的可能答案,通过重组宏的工作方式(并使用了 Charles Stewart 答案中的一些建议 - 我承认我不喜欢看起来的“外观”)虽然我被广泛认为是优秀的 LaTeX 代码,但我的 C/C++ 方式可能太根深蒂固,无法成为一名真正的 LaTeX 程序员)。

无论如何,我的答案...

不要尝试在宏中生成文件名以将传递给 \includegraphics 宏,而是创建一个包装 \includegraphics 的宏 并向其传递真实或虚拟文件名。这似乎避免了传递(作为参数)长脚本/宏,尽管我没有看到任何好的理由为什么必须这样编写。但它确实有效...

% Dummy figure file
\def\dummyfigure{commands/dummy}%

% Includegraphics wrapper macro to include either dummy or real figure
\ifx\pdfoutput\undefined
\newcommand{\incgfx}[2]{%
    \def\testfile{\chapdir/fig/#2}%
    \IfFileExists{\testfile.eps}%
        {\includegraphics[#1]{\testfile}}% test file found
        {\includegraphics[#1]{\dummyfigure}}% test file not found
}
\else
\newcommand{\incgfx}[2]{%
    \def\figfilename{\dummyfigure}
    \def\testfile{\chapdir/fig/#2}
    \IfFileExists{\testfile.jpg}{\def\figfilename{\testfile}}{}
    \IfFileExists{\testfile.png}{\def\figfilename{\testfile}}{}
    \IfFileExists{\testfile.pdf}{\def\figfilename{\testfile}}{}
    \IfFileExists{\testfile.jpeg}{\def\figfilename{\testfile}}{}
    \IfFileExists{\testfile.tif}{\def\figfilename{\testfile}}{}
    \IfFileExists{\testfile.tiff}{\def\figfilename{\testfile}}{}
    \includegraphics[#1]{\figfilename}
}
\fi

这允许人们按预期使用它:

\begin{figure}
    \begin{center}
        \incgfx{height=3cm}{\chapdir/fig/fluxcapacitor}
        \caption{...}\label{fig:...}
    \end{center}
\end{figure}

同样,我想认为有一种方法可以使最初的想法发挥作用,而不必为现有函数制作包装器,但现在就这样了......

Alright, so I've found a possible answer to #2, by restructuring the way the macros work (and sort of using some suggestions from Charles Stewart's answer — I'll admit I don't like the 'look' of what seems to be widely considered good LaTeX code, I'm perhaps too ingrained in my C/C++ ways to be a real LaTeX programmer).

Anyway, my answer...

Instead of trying to produce the file name in a macro to pass to the \includegraphics macro, make a macro that wraps \includegraphics and passes it the real or dummy file name. This seems to avoid passing (as an argument) a long script/macro, though I don't see any good reason why it should have to be written this way. But it does work...

% Dummy figure file
\def\dummyfigure{commands/dummy}%

% Includegraphics wrapper macro to include either dummy or real figure
\ifx\pdfoutput\undefined
\newcommand{\incgfx}[2]{%
    \def\testfile{\chapdir/fig/#2}%
    \IfFileExists{\testfile.eps}%
        {\includegraphics[#1]{\testfile}}% test file found
        {\includegraphics[#1]{\dummyfigure}}% test file not found
}
\else
\newcommand{\incgfx}[2]{%
    \def\figfilename{\dummyfigure}
    \def\testfile{\chapdir/fig/#2}
    \IfFileExists{\testfile.jpg}{\def\figfilename{\testfile}}{}
    \IfFileExists{\testfile.png}{\def\figfilename{\testfile}}{}
    \IfFileExists{\testfile.pdf}{\def\figfilename{\testfile}}{}
    \IfFileExists{\testfile.jpeg}{\def\figfilename{\testfile}}{}
    \IfFileExists{\testfile.tif}{\def\figfilename{\testfile}}{}
    \IfFileExists{\testfile.tiff}{\def\figfilename{\testfile}}{}
    \includegraphics[#1]{\figfilename}
}
\fi

This allows one to use it as intended:

\begin{figure}
    \begin{center}
        \incgfx{height=3cm}{\chapdir/fig/fluxcapacitor}
        \caption{...}\label{fig:...}
    \end{center}
\end{figure}

Again, I'd like to think there's a way to make the original idea work rather than having to make a wrapper for existing functions, but this will do for now...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文