当为主文档指定作业名称时,Tikz externalize 不起作用

当为主文档指定作业名称时,Tikz externalize 不起作用

我不确定这是否是众所周知的事实,但是如果使用与该文档的文件名不同的作业名来编译 LaTeX 文档,则使用 tikz 外部化库效果不佳。

例如,如果使用pdflatex(请注意参数)编译以下 MWE,则除非文件已命名(为方便起见,我们假设它名为),-jobname output否则它将无法工作:output.texmain.tex

%& -jobname=output
\documentclass{book}

\usepackage{tikz,pgfplots}
\usetikzlibrary{external}
\tikzset{external/only named=true}
\pgfplotsset{compat=newest}

\tikzexternalize

\begin{document}

\begin{figure}[h]
  \tikzsetnextfilename{sample_tikz}
  \begin{tikzpicture}[scale=1.50]
    \begin{axis}\addplot {x^3};\end{axis}
  \end{tikzpicture}
  \caption{Sample tikz picture.}
\end{figure}

\end{document}

如果编译时没有-jobname参数,它可以正常工作,而如果有参数,我就会收到如下错误:

===== 'mode=convert with system call': Invoking 'pdflatex -shell-escape -halt-o
n-error -interaction=batchmode -jobname "sample_tikz" "\def\tikzexternalrealjob
{output}\input{output}"' ========

! Package tikz Error: Sorry, the system call 'pdflatex -shell-escape -halt-on-e
rror -interaction=batchmode -jobname "sample_tikz" "\def\tikzexternalrealjob{ou
tput}\input{output}"' did NOT result in a usable output file 'sample_tikz' (exp
ected one of .pdf:.jpg:.jpeg:.png:).

从错误信息中,也可以很明显地看出哪里出了问题。默认的外部化系统调用如下所示:

pdflatex \tikzexternalcheckshellescape -halt-on-error -interaction=batchmode -jobname "\image" "\texsource"

其中宏\texsource\edef

\string\def\string\tikzexternalrealjob{\tikzexternal@realjob}\string\input{\tikzexternal@realjob}

并根据编译时使用\tikzexternal@realjob的值进行设置。当使用 进行编译时,会扩展为\jobnamemain.texmain.tex-jobname output\texsource

\def\tikzexternalrealjob{output}\input{output}

这是有问题的,因为main.tex没有被调用output.tex

可能的解决方案

我尝试查看 tikz 外部源代码,并尝试如何解决这个问题。我的理由是,我希望以\texsource某种方式扩展到

\def\tikzexternalrealjob{output}\input{main}

而是(请注意,\tikzexternalrealjob仍然必须\def将其添加到实际的\jobname,因为它在 tikz 外部化代码中用于决定当前作业是针对主文档还是针对 tikz 图像的外部化)。

我受到启发这个帖子使用该currfile包(感谢@martin-scharrer)自动检索名称main

到目前为止我想到的是(似乎有效)如下:

将 MWE 更改为:

%& -jobname=output -recorder
\documentclass{book}

\usepackage{tikz,pgfplots}
\usetikzlibrary{external}
\tikzset{external/only named=true}
\pgfplotsset{compat=newest}

\input{externalize-hack.tex} % <---- THIS WAS ADDED

\tikzexternalize

\begin{document}

\begin{figure}[h]
  \tikzsetnextfilename{sample_tikz}
  \begin{tikzpicture}[scale=1.50]
    \begin{axis}\addplot {x^3};\end{axis}
  \end{tikzpicture}
  \caption{Sample tikz picture.}
\end{figure}

\end{document}

并让文件externalize-hack.tex定义如下:

\usepackage{currfile-abspath}
\getmainfile

\usepackage{xpatch}

\makeatletter

\AtEndDocument{%
  \newwrite\maindeffile%
  \immediate\openout\maindeffile=\jobname.maindef%
  \immediate\write\maindeffile{%
    \noexpand\ifcsname mymainfile\noexpand\endcsname\noexpand\else%
      \noexpand\gdef\noexpand\mymainfile{\mymainfile}%
    \noexpand\fi%
  }%
  \immediate\closeout\maindeffile%
}

\@input{\jobname.maindef}

\ifcsname mymainfile\endcsname%
  \ifx\mymainfile\@empty%
    % Make a second attempt at extracting the real file name
    % (necessary because currfile needs two runs on MiKTeX..)
    \filename@parse{\themainfile}%
    \let\mymainfile\filename@base%
    \ifx\mymainfile\@empty%
      % If still empty, fallback to default behavior
      \def\mymainfile{\tikzexternal@realjob}%
    \fi%
  \fi%
\else%
  % First attempt at extracting real file name
  \filename@parse{\themainfile}%
  \let\mymainfile\filename@base%
\fi%

\xpatchcmd{\tikzexternal@assemble@systemcall}%
  {%
    \edef\texsource{%
      \string\def\string\tikzexternalrealjob{\tikzexternal@realjob}%
      \string\input{\tikzexternal@realjob}%
    }%
  }%
  {%
    \edef\texsource{%
      \string\def\string\tikzexternalrealjob{\tikzexternal@realjob}%
      \string\def\string\mymainfile{\mymainfile}%
      \string\input{\mymainfile}%
    }%
  }%
  {}
  {}

\let\old@tikzexternalize@opt@withname\tikzexternalize@opt@withname%
\def\tikzexternalize@opt@withname[#1]#2{%
  % Suppress externalization as long as \mymainfile is empty
  % (This will only be the case the one or two first compilation runs!)
  \ifx\mymainfile\@empty\else%
    \old@tikzexternalize@opt@withname[#1]{#2}%
  \fi%
}

\makeatother

还请注意-recorder,根据currfile包的要求,添加了选项。

但是,我觉得这个 hack 有点笨拙。因此,我非常感谢你们的任何意见!

答案1

您知道 tikz 用来\jobname编写生成外部图片的命令行。因此重新定义\jobname并同时使用 tikz 外部化太麻烦了。

可能的解决方法:

  • 用于\tikzsetfigurename{something}设置外部 tikz 图片的基本名称;
  • 称呼pdflatex 没有 -jobname output每次你改变 tikzpicture 时它都会正确生成图形;
  • 使用生成的外部图形,您可以随意更改文本中的所有内容并调用,pdflatex -jobname output因为只计算校验和而不需要真实的作业名称。

它与我的 MWE 一起工作:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{external}
\tikzexternalize
\tikzsetfigurename{something}

\begin{document}

\tikz \draw (0,0) -- (1,0.5);

\tikz \draw[red] (0,0) -- (1,0.5);

\end{document}

调用顺序:

  • pdflatex -shell-escape main(此处somethingN生成数字)
  • pdflatex -shell-escape -jobname output main

相关内容