Могу ли я сделать макрос LaTeX «вернуть» имя файла? - PullRequest
9 голосов
/ 18 мая 2010

Я пишу свою диссертацию / диссертацию, и, поскольку это постоянная работа, у меня не всегда есть фактические изображения, готовые для рисунков, которые я положил в свой документ, но по разным причинам хочу, чтобы он автоматически заменял фиктивную. фигура на месте, когда включенный графический файл не существует. Например. Я могу сделать что-то вроде \includegraphics[width=8cm]{\chapdir/figures/fluxcapacitor} (где \chapdir - это макрос для моего «текущего» каталога глав, например, \def\chapdir{./ch_timetravel}, и если нет ./ch_timetravel/figures/fluxcapacitor.jpg, вместо него будет вставлено ./commands/dummy.jpg.

Я структурировал свои макросы (возможно, наивно?) Так, чтобы у меня был макрос (\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 содержать только значение , а не полный макрос, но я получаю ошибку Undefined control sequence с жалобами на переменные, которые я пытаюсь \def в \figFileOrDummy макрос не определен.

Так что мой вопрос либо

  1. Как мне правильно развернуть этот макрос ?; или
  2. Если это неправильный способ структурирования моих макросов, как мне на самом деле структурировать такой макрос, чтобы иметь возможность автоматически вставлять фиктивные / реальные цифры ?; или
  3. Есть ли пакет, который уже хорошо обрабатывает такие вещи, которые я пропустил?

Я чувствую, что мне здесь не хватает чего-то довольно фундаментального ...

Ответы [ 3 ]

3 голосов
/ 18 мая 2010

Я думаю, дело в том, что \ expandafter интересует только свои аргументы в виде строки, представляющей имя файла, поэтому не оценивает его & mdash; макроязыки ленивы! Попробуйте \expandafter {\includegraphics[width=8cm]}{\chapdir/figures/fluxcapacitor}.

Две точки стиля:

  1. Вам не нужно ставить% в конце строки, чтобы остановить ложные пробелы, если строка заканчивается контрольной последовательностью: контрольная последовательность поглощает все последующие пробелы, включая конец строки. Это делает код намного более читабельным, на мой вкус. Обратите внимание, что, в частности, для «рта» Текса и \def\newcs{abc}, и \def \newcs {abc} идентичны: они представляют собой одну и ту же последовательность токенов.
  2. Я отбросил код вокруг \ figtest: вы получаете лучшие отчеты об ошибках - всегда с наценкой с Tex-, если вы используете либо \ newif примитив (создайте новый тест с \ newif \ figexists, установите / сбросьте с помощью \ figexiststrue, \ figexistsfalse и протестируйте с \ iffigexists ...) или пакетом латексного ифтеля (для соблюдения православия).

Код очистки

Сначала я подумал, что проблема кроется в другом месте, поэтому написал что-то красивее:

\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
2 голосов
/ 19 мая 2010

Хорошо, поэтому я нашел возможный ответ на вопрос № 2, изменив структуру работы макросов (и используя некоторые предложения из ответа Чарльза Стюарта - я признаю, что мне не нравится «внешний вид» то, что обычно считается хорошим кодом 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}

Опять же, я хотел бы думать, что есть способ заставить оригинальную идею работать, вместо того, чтобы создавать оболочку для существующих функций, но пока это подойдет ...

1 голос
/ 18 мая 2010

Ответ на вопрос № 3: Для этой цели я считаю очень полезным пакет todonotes. Он не обеспечивает тот уровень автоматизации, который должен предлагать ваш код, но у него есть очень приятная команда \missingfigure, которая позволяет вам поставить пустую рамку для, как вы думаете, пропущенной цифры.

...