编辑:外部库很棒,但我想补充一下,我弄清楚了如何打印样式的内容(虽然没有完全展开,所以如果它包含其他样式,则不会完全展开)。样式存储在子键中.@cmd
,与键的代码位于同一位置。因此,\pgfkeys{/key/.code=<code>}
指令<code>
直接放入/key/.@cmd
,而/.style
指令将其包装在中/pgfkeysalso{<style>}
。(因此/.code
和/.style
可以相互附加或覆盖。):
\documentclass{article}
\usepackage{tikz}
\def\mean#1{\texttt{\string#1: \meaning#1}\par}
\begin{document}
\makeatletter
\tikzset{my style/.style={draw=red}}
\pgfkeysgetvalue{/tikz/my style/.@cmd}{\mystyle}
\mean\mystyle
% strip \pgfkeysalso prefix, only works if style hasn't been prepended or appended to
\def\getstyle\pgfkeysalso #1\@nil{\def\mystyle{#1}}
\expandafter\getstyle\mystyle\pgfeov\@nil
\mean\mystyle
\end{document}
我有一个宏,它根据其参数进行一些处理(它设置了一些长度寄存器和 TikZ 样式),然后使用这些长度和样式绘制一个简单的 TikZ 图片。我需要一种将图片的扩展内容写入文件的方法,这样就可以\input
在后续编译期间绕过所有处理开销。我知道如何扩展长度寄存器以及如何在\write
不扩展的情况下执行 TikZ 命令,但我不知道如何打印样式的内容:因此,如果在执行的处理过程中\tikzset{my style/.style={draw=red}}
,我希望能够draw=red
在写入过程中用 或其内容替换所有出现的样式。我不知道这是否可能,或者它是否涉及设置样式(无论如何它都会是)并使用 手动获取所有相关键的值\pgfkeysvalueof
。我知道我可以\tikzset
逐字编写命令,因此样式是在新创建的文件中设置和使用的,但我想知道是否有更好的方法。这是一个非常我的包的功能的简化版本:
\documentclass{article}
\usepackage{tikz}
\usepackage{etoolbox}
\def\gtikzset#1{
\begingroup%
\globaldefs=1\relax%
\tikzset{#1}%
\endgroup%
}
% do some preprocessing here to compute styles; as far as MWE is concerned,
% let's just set styles 0--100 to be red
\foreach \n in {0,...,100}{\gtikzset{anyon\n/.style={red}}}
\newcount\childn
% the child operation seems to start a new group, so not using \global to
% advance the childn counter results it being equal to the current
% depth, #1
\def\DrawChildren#1#2{%
% #1: current depth, #2: total depth
\ifnumless{#1}{#2}{%
% right
child[anyon\the\childn] {%
node {}%
\pgfextra{\global\advance\childn by 1\relax}%
\DrawChildren{#1+1}{#2} }%
% left
child[anyon\the\childn] {%
node {}%
\pgfextra{\global\advance\childn by 1\relax}%
\DrawChildren{#1+1}{#2} }%
}{}%
}
\def\DrawTree#1{%
% #1: tree depth
\childn=1\relax%
% do more processing here, compute lengths, use them to clip the image
% \clip...
\node [anyon0] {} child { node {} \DrawChildren{0}{#1} };%
}
\begin{document}
\tikz\DrawTree{3};
\end{document}
答案1
@Henri Menke 的建议正是我所需要的:TikZ 有一个外部库,可以自动将任何 tikzpicture 导出为 pdf 文件,并且高度可定制(pgf 手册第 50 章)。
要开始使用它,只需要:
\usetikzlibrary{external}
\tikzexternalize
要启用/禁用图片外部化,直到当前组结束(或直到下一个禁用/启用命令):\tikzexternalenable
或\tikzexternaldisable
。要跳过下一个图:\tikzset{external/export next=false}
默认情况下,它按从0 开始的\jobname-figure<n>
位置命名文件,可以使用或<n>
进行更改。这将为所有图形设置基本名称(尽管它对于一个组来说是本地的),并且每个图形在末尾都会有一个数字。要设置下一张图片的完整基本名称,请使用。可以使用或设置将应用于每个图像的全局前缀(例如目录路径)。即使对于文件名经过特别设置的图像,此前缀也适用。也可以使用 设置后缀。\tikzsetfigurename{<name>}
\tikzset{external/figure name=<name>}
\tikzsetnextfilename{<file name>}
\tikzsetexternalprefix{<prefix>}
\tikzset{external/prefix={<prefix>}}
\tikzappendtofigurename{<suffix>}
默认情况下,它使用 tikzpicture 环境内容的哈希值来确定图片是否已更改。如果图片使用外部定义的宏并且它们发生变化,则此方法将不起作用,但始终可以使用\tikzset{external/remake next=true}
或 对所有图形全局强制重建下一个图形\tikzset{external/force remake=true}
。还有其他最新检查模式可供选择:\tikzset{external/up to date check={<mode>}}
,其中<mode>
可以是md5
(默认)、diff
(类似于 md5)或simple
(仅检查是否存在此名称的文件)。当使用简单时,如果图形的顺序发生变化,则这不会反映在主文档中,直到重建外部图形(手动或通过强制 TikZ)。此外,可以使用 为特定图形设置依赖项\tikzpicturedependsonfile{<file name>}
,以便如果<file name>
发生变化,将重建图片。
有几种模式可确定如何(以及是否)编译导出的图像:\tikzset{external/mode={<mode>}}
。这些模式包括:
convert with system call
:调用系统命令(使用 \write18)连续制作各幅图像。only graphics
:假设所有导出的图像都已编译并仅包含它们(如果文件不存在则会出错)graphics if exists
:与上面相同,但会跳过那些无法找到二进制文件的任务no graphics
:根本不检查外部图形,总是排版图片list only
:生成\jobname.figlist
(要导出的所有图像的行分隔文件);在主文档中为每张图片插入替换文本list and make
:除了生成 之外\jobname.figlist
,还要写入\jobname.makefile
,它可以与 make 一起使用来做并行编译(当用 make 或手动构建时,\ref
图片里面的 也会被解析,但在模式下并非如此convert with system call
);此外,还包括任何已经编译好的图像。
可以设置使用该模式时调用的命令convert with system call
。默认情况下,它确定用于主文件的 pdf 驱动程序并添加一些选项。因此对于 (pdf|lua|xe)latex,系统调用将是:
(pdf|lua|xe)latex \tikzexternalcheckshellescape -halt-on-error -interaction=batchmode -jobname "\image" "\texsource"
其中\image
保存了完整的图像文件名(由图形名称和任何全局前缀/后缀生成),并且仅当已允许用于主文档\tikzexternalcheckshellescape
时才为非空。它所保存的实际参数(默认情况下)可以使用以下方式设置-shell-escape
-shell-escape
\tikzset{external/shell escape={<cmdline arg>}}
在主文档内部,可以根据此编译运行中是否仅生成导出的图像,或者是否排版完整文档有条件地执行代码:\tikzifexternalizing{<true code>}{<false code>}
。
还有多种方法可以通过忽略其中的某些宏调用来优化导出的图形,更多信息请参阅手册。
话虽如此,我可以在宏中包含支持,以便根据其内容自动命名每个图形,以便在文档中移动它们或多次使用它不会导致重建它。我也喜欢列表和 make 模式,因为我已经在为这个项目使用 Makefile,并且它完美地集成,允许我并行编译图片。MWE 将是:
main.tex
:
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{external}
\tikzexternalize[
prefix=img/, % needs to exist
figure name=tikz_external_test_,
mode=list and make,
figure list=true,
]
\begin{document}
\begin{tikzpicture}
\draw (-1,-1) rectangle (1,1);
\draw (0,0) circle[radius=1];
\end{tikzpicture}
\end{document}
Makefile
:
.PHONY: clean fullclean
.DEFAULT: main
# removed in 'clean' and 'fullclean'
tmp_files := $(wildcard $(addprefix main.,aux auxlock log \
out figlist makefile))
# removed in 'fullclean' only
out_files := $(wildcard main.pdf img/*)
define compile =
pdflatex $(1)
$(MAKE) -f $(1).makefile # can add -j<N> for parallel compilation
pdflatex $(1)
endef
main: main.pdf
%.pdf: %.tex
$(call compile,$*)
clean:
ifneq ($(tmp_files),)
rm $(tmp_files)
endif
fullclean:
ifneq ($(strip $(tmp_files) $(out_files)),)
rm $(tmp_files) $(out_files)
endif