什么原因导致错误?

什么原因导致错误?

请考虑以下示例:

\documentclass{article}
\usepackage[utf8]{inputenc}
\usepackage[usenames,dvipsnames]{xcolor}
\usepackage{hyperref}
\usepackage{tikz}
\usepackage{xparse}

\usetikzlibrary{external}
\tikzexternalize[prefix=./]


\NewDocumentCommand{\mypic}{O{red}O{1}}{%
\IfFileExists{mypic_#1.pdf}{\includegraphics[scale=#2]{mypic_#1.pdf}}{%
\tikzsetnextfilename{mypic_#1}%
\begin{tikzpicture}
\draw[#1] (1,0)--(0,1);
\end{tikzpicture}%
}}

\begin{document}

\mypic[Cerulean] \mypic[Cyan] \mypic[red] \mypic[YellowGreen]

\end{document}

如果存在这样的文件,该命令\mypic应该包含一个文件名中包含颜色的图片,或者如果之前没有创建过 pdf 图片,则创建该图片。它在我的电脑上不起作用,我收到的错误消息是

 Package tikz Error: Sorry, the system call 'pdflatex -shell-escape -halt-on-error -interaction=batchmode -jobname "./mypic_Cerulean"  "\def\tikzexternalrealjob{EIFFEL}\input{EIFFEL}"' did NOT result in a usable output file

但是,删除hyperref包后,它就可以正常工作。我读过一些关于hyperrefTikZ 外部化交互的帖子,但我尝试过的所有解决方案都对我不起作用。我能做什么吗?

更奇怪的是:保留hyperref但移除\IfFileExists部分,它仍然有效(但不允许我更改图片的比例)。这是从哪里来的?

答案1

问题与没有直接关系hyperref;根本原因是你试图跳过图片在生成过程中。这会导致 pdf 大小为 0,并且会被立即删除pdftex

事情是这样的:

  • 主程序已排版,这就是“如果图像存在”逻辑应该适用的地方。但事实并非如此,因为图形不存在。
  • 外部化已启动。为此,它开始生成图片(我们假设它以 mypic_Cerulean 开头)。然后检查是否mypic_Cerulean.pdf存在 - 如果 pdf 的标头已写入,则为真。
  • 你的“if”剥离了图片代码,而外部化则导致了空的输出文件。
  • pdftex 删除了已启动的 pdf 文件,因为它不包含输出。
  • 主程序尝试包含该文件但未能找到它。

因此,该逻辑本质上是脚本中的一个编程错误:当脚本即将生成图像时,它不能应用“如果图像存在”语句。

之所以hyperref会产生差异,是因为hyperref(似乎)在输出 PDF 中生成了一些标头信息,也就是说,它会导致在第一次发货开始之前写入文件。请注意,这hyperref不是唯一生成此类标头信息的工具,但在这种情况下,它会产生差异。

您必须使用\tikzifexternalizing来修复此问题。它经过以下修改后才起作用:

\documentclass{article}
\usepackage[utf8]{inputenc}
\usepackage[usenames,dvipsnames]{xcolor}
\usepackage{hyperref}
\usepackage{tikz}
\usepackage{xparse}

\usetikzlibrary{external}
\tikzexternalize[prefix=./]


\NewDocumentCommand{\mypic}{O{red}O{1}}{%
    \tikzifexternalizing{%
        \def\DOIT{1}%
    }{%
        \IfFileExists{mypic_#1.pdf}{%
            \includegraphics[scale=#2]{mypic_#1.pdf}%
            \def\DOIT{0}%
        }{%
            \def\DOIT{1}%
        }%
    }%
    %
    \if1\DOIT
        \tikzsetnextfilename{mypic_#1}%
        \begin{tikzpicture}
        \draw[#1] (1,0)--(0,1);
        \end{tikzpicture}%
    \fi
}

\begin{document}

\mypic[Cerulean] \mypic[Cyan] \mypic[red] \mypic[YellowGreen]

\end{document}

关键思想是仅在生成主 .tex 文件期间应用您的特殊逻辑,但如果外部化正在运行,则省略它。

\def\DOIT{<value>}存储<value>到宏 中\DOIT\if1\DOIT是 1 字符比较,检查是否\DOIT扩展为“1”。此检查当且仅当\DOIT扩展为最多一个字符时才有效(此处满足:它可以容纳10)。

答案2

我无法解释这个错误。不要给我赏金。(见下节)

假设您的 MWE\scalebox有效。如果您打算实现更复杂的事情,请告诉我。顺便说一句,无论您的目标是什么,逻辑都是external优于\IfFileExists

\documentclass{article}
\usepackage[usenames,dvipsnames]{xcolor}
\usepackage{tikz,xparse,hyperref}
\usetikzlibrary{external}\tikzexternalize
\NewDocumentCommand{\mypic}{O{red}O{1}}{
    \tikzsetnextfilename{mypic_#1}
    \scalebox{#2}{
        \begin{tikzpicture}
        \draw[#1] (1,0)--(0,1);
        \end{tikzpicture}%
    }
}
\begin{document}
    \mypic[Cerulean]    \mypic[Cyan]    \mypic[red]    \mypic[YellowGreen]
    \mypic[Cerulean][1] \mypic[Cyan][2] \mypic[red][3] \mypic[YellowGreen][4]
\end{document}

什么原因导致错误?

在回答这个问题之前,我想先谈谈图书馆external

问:如何external工作?

错误的答案:

\begin{tikzpicture}它提取和之间的代码\end{tikzpicture}。然后运行该段代码。

你可以在外面添加一些全局设置来证明这是错误的:

    \tikzset{
        every picture/.style={ ... }
    }

正确答案:

pdftex再次调用运行原始文件,但这次:

  • 输出例程被抑制,除非它满足tikzpicture
  • -jobname "name_of_that_picture"作为一个选项传递,因此这次运行将以结束name_of_that_picture.pdf

该机制在手册中进行了解释,目前为第 IX 部分“基础层”第 107 节“外部化图形”。

那么...通常究竟会发生什么呢?

您调用的图像pdftex

  • pdftex运行your_article.tex
  • pdftex到达\mypic{Cerulean}
  • pdftex尝试\IfFileExists{mypic_Cerulean.pdf},但徒劳无功;
  • pdftex决定生成mypic_Cerulean.pdf
  • pdftex呼叫另一个pdftex -jobname "mypic_Cerulean"
    • pdftex2次跑垒your_article.tex
    • pdftex2到达\mypic{Cerulean}
    • pdftex2次尝试\IfFileExists{mypic_Cerulean.pdf},均无效果;
    • pdftex2决定排版tikzpicture
    • pdftex2.完成后,将叶子mypic_Cerulean.pdf放在盘上;
  • pdftex很高兴看到结果,mypic_Cerulean.pdf包括;
  • pdftex到达\mypic{Cyan}
  • pdftex尝试\IfFileExists{mypic_ Cyan.pdf},但徒劳无功;
  • pdftex决定生成mypic_ Cyan.pdf
  • pdftex呼叫另一个pdftex -jobname "mypic_ Cyan"
    • pdftex3次跑垒your_article.tex

等等...

那么...为什么hyperref会导致错误?

  • pdftex运行your_article.tex
  • pdftex包括hyperrefyour_article.pdf创建;
  • pdftex到达\mypic{Cerulean}
  • pdftex尝试\IfFileExists{mypic_Cerulean.pdf},但徒劳无功;
  • pdftex决定生成mypic_Cerulean.pdf
  • pdftex呼叫另一个pdftex -jobname "mypic_Cerulean"
    • pdftex2次跑垒your_article.tex
    • pdftex2包括hyperrefmypic_Cerulean.pdf创建;
    • pdftex2到达\mypic{Cerulean}
    • pdftex2次尝试\IfFileExists{mypic_Cerulean.pdf},成功;
    • pdftex2决定纳入mypic_Cerulean.pdf,但徒劳无功;
    • pdftex2以 终止Fatal error
  • pdftex不高兴见到没有mypic_Cerulean.pdf
  • pdftex暂停并抛出您看到的错误;

其他解决方法

尽量不要自己测试文件。如果您真的想这样做,请模仿 PGF 测试文件的方式。如果您只想控制\includegraphics,PGF 提供了/pgf/images/include external

相关内容