自动导出 TikZ 图像(以前扩展(打印)TikZ 样式的内容)

自动导出 TikZ 图像(以前扩展(打印)TikZ 样式的内容)

编辑:外部库很棒,但我想补充一下,我弄清楚了如何打印样式的内容(虽然没有完全展开,所以如果它包含其他样式,则不会完全展开)。样式存储在子键中.@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

相关内容