请考虑以下示例:
\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
包后,它就可以正常工作。我读过一些关于hyperref
TikZ 外部化交互的帖子,但我尝试过的所有解决方案都对我不起作用。我能做什么吗?
更奇怪的是:保留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
扩展为最多一个字符时才有效(此处满足:它可以容纳1
或0
)。
答案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"
;pdftex
2次跑垒your_article.tex
;pdftex
2到达\mypic{Cerulean}
;pdftex
2次尝试\IfFileExists{mypic_Cerulean.pdf}
,均无效果;pdftex
2决定排版tikzpicture
;pdftex
2.完成后,将叶子mypic_Cerulean.pdf
放在盘上;
pdftex
很高兴看到结果,mypic_Cerulean.pdf
包括;pdftex
到达\mypic{Cyan}
;pdftex
尝试\IfFileExists{mypic_ Cyan.pdf}
,但徒劳无功;pdftex
决定生成mypic_ Cyan.pdf
;pdftex
呼叫另一个pdftex -jobname "mypic_ Cyan"
;pdftex
3次跑垒your_article.tex
;
等等...
那么...为什么hyperref
会导致错误?
pdftex
运行your_article.tex
;pdftex
包括hyperref
、your_article.pdf
创建;pdftex
到达\mypic{Cerulean}
;pdftex
尝试\IfFileExists{mypic_Cerulean.pdf}
,但徒劳无功;pdftex
决定生成mypic_Cerulean.pdf
;pdftex
呼叫另一个pdftex -jobname "mypic_Cerulean"
;pdftex
2次跑垒your_article.tex
;pdftex
2包括hyperref
、mypic_Cerulean.pdf
创建;pdftex
2到达\mypic{Cerulean}
;pdftex
2次尝试\IfFileExists{mypic_Cerulean.pdf}
,成功;pdftex
2决定纳入mypic_Cerulean.pdf
,但徒劳无功;pdftex
2以 终止Fatal error
;
pdftex
不高兴见到没有mypic_Cerulean.pdf
;pdftex
暂停并抛出您看到的错误;
其他解决方法
尽量不要自己测试文件。如果您真的想这样做,请模仿 PGF 测试文件的方式。如果您只想控制\includegraphics
,PGF 提供了/pgf/images/include external
。