tikzmark 过多导致“尺寸太大”错误

tikzmark 过多导致“尺寸太大”错误

这是讨论的后续内容这里。Andrew 针对页码过大导致的问题提供了一个补丁(请参阅链接问题中他和 Ulrike 的回答)。

然而,即使有了他的补丁(包含在下面的 MWE 中),我现在又遇到了“尺寸太大”的问题,这次肯定不是由页面数量引起的,而是由 tikzmarks 的数量引起的(或者我推测是这样的)。它只在第二次运行时失败,所以它可能与值更改有关。

我还观察到,当我以较少的迭代次数运行一次,然后继续缓慢增加次数时,它根本不会失败(除非我删除辅助文件),我甚至可以一直运行到超出 TeX 容量为止。所以这似乎与重新运行它有关,但我没有任何线索。

% !TEX TS-program = xelatexmk
\documentclass{article}

\usepackage{tikz}
\usetikzlibrary{tikzmark}

% Fix for error when pagenumber too large, 
% from: https://tex.stackexchange.com/questions/484980/dimension-too-large-error-with-tikz-graphic-using-tikzmark-when-document-gets
\makeatletter
\tikzdeclarecoordinatesystem{pic}{%
  \pgfutil@in@,{#1}%
  \ifpgfutil@in@%
    \tmk@labeldef#1\@nil
  \else
    \tmk@labeldef#1,(0pt,0pt)\@nil
  \fi
  \@ifundefined{save@pt@\tmk@label}{%
    \tikz@scan@one@point\pgfutil@firstofone\tmk@def
  }{%
    \pgfsys@getposition{\csname save@pt@\tmk@label\endcsname}%
    \save@orig@pic%
    \pgfsys@getposition{\pgfpictureid}\save@this@pic%
    \pgf@process{\pgfpointorigin\save@this@pic}%
    \pgf@xa=\pgf@x
    \pgf@ya=\pgf@y
    \pgf@process{\pgfpointorigin\save@orig@pic}%
    \advance\pgf@x by -\pgf@xa
    \advance\pgf@y by -\pgf@ya
    \pgf@xa=\pgf@x
    \pgf@ya=\pgf@y
    \pgf@process%
    {\pgfpointorigin\csname save@pt@\tmk@label @offset\endcsname}%
    \advance\pgf@xa by \pgf@x
    \advance\pgf@ya by \pgf@y
      \@ifundefined{save@pg@\csname save@pt@\tmk@label\endcsname}{}{%
        \@ifundefined{save@pg@\pgfpictureid}{}{%
          \pgfkeysvalueof{/tikz/next page vector}%
        \edef\tmk@pg{\the\numexpr \csname save@pg@\csname save@pt@\tmk@label\endcsname\endcsname - \csname save@pg@\pgfpictureid\endcsname\relax}%
        \advance \pgf@xa by %
        \tmk@pg\pgf@x\relax
        \advance \pgf@ya by %
        \tmk@pg\pgf@y\relax
        }%
      }%
      \pgf@x=\pgf@xa
      \pgf@y=\pgf@ya
    \pgftransforminvert
    \pgf@pos@transform{\pgf@x}{\pgf@y}%
    }%
  }
\makeatother

\tikzset{
  next page=below,
  brace/.style n args={2}{insert path={%
  ([xshift=0.15em,yshift=0.1pt+.5ex]#1) -- 
  ([xshift=-0.3pt,yshift=0.1pt+.5ex]#1) -- 
  ([xshift=-0.3pt,yshift=-0.1pt+.5ex]#2) -- 
  ([xshift=0.15em,yshift=-0.1pt+.5ex]#2) -- 
  ([xshift=0.15em,yshift=0.1pt+.5ex]#2) --
  ([xshift=0.3pt,yshift=0.1pt+.5ex]#2) --
  ([xshift=0.3pt,yshift=-0.1pt+.5ex]#1) --
  ([xshift=0.15em,yshift=-0.1pt+.5ex]#1) --
  cycle}}}

% Setup for regular brackets: 
\newcounter{tikzmkcnt}\setcounter{tikzmkcnt}{0} % counter to automatically set tikzmarks

\newif\iffirstmark

\newcommand{\bracketstart}{%
  \stepcounter{tikzmkcnt}%
  \tikzmark{a\thetikzmkcnt}%
  \global\firstmarktrue
  \iftikzmarkoncurrentpage{b\thetikzmkcnt}%
  \else
  \begin{tikzpicture}[remember picture,overlay,next page=below]%
%  \clip (current page text area.south west) rectangle (current page text area.north east);
  \fill[overlay,brace={pic cs:a\thetikzmkcnt}{pic cs:b\thetikzmkcnt}];
  \end{tikzpicture}%
  \fi
}

\newcommand{\bracketend}{%
  \iffirstmark
  \tikzmark{b\thetikzmkcnt}%
  \global\firstmarkfalse
  \fi
  \begin{tikzpicture}[remember picture,overlay]%
%  \clip (current page text area.south west) rectangle (current page text area.north east);
  \fill[overlay,brace={pic cs:a\thetikzmkcnt}{0,0}];
  \end{tikzpicture}%
  }

%% First I thought it had to do with some weird interaction with zref as it was part of this code:
%\RequirePackage[user,savepos]{zref}
%\newcommand{\offset}[1]{ % setting offset 
%\dimexpr\zposx{#1}sp-(\oddsidemargin+1in)\relax}
%\newcommand{\offsetmk}[1]{\leavevmode\zsaveposx{#1}} % defining offset point
%\newcounter{offsetmkcnt}\setcounter{offsetmkcnt}{0} % counter for automatic marks
%\newcommand{\onsetmark}{\bracketstart\stepcounter{offsetmkcnt}\offsetmk{\theoffsetmkcnt}\hspace{.15em}} 
%\newcommand{\offsetline}{\hspace{\dimexpr\offset{\theoffsetmkcnt}\relax}\bracketend\hspace{.15em}}
% 
%\newcommand{\Zftest}{test \onsetmark{}test\par \offsetline{}test \onsetmark{}test\par \offsetline{}test \par}
%\newcommand{\Tentests}{\Zftest\Zftest\Zftest\Zftest\Zftest\Zftest\Zftest\Zftest\Zftest\Zftest}

%% But then I realized that even this one produces the error:
\newcommand{\Tktest}{test \bracketstart{}test\par test  \bracketend{}test \bracketstart{}test \par test test  \bracketend{}test \par}
\newcommand{\Tentests}{\Tktest\Tktest\Tktest\Tktest\Tktest\Tktest\Tktest\Tktest\Tktest\Tktest}

\newcommand{\Hundredtests}{\Tentests\Tentests\Tentests\Tentests\Tentests\Tentests\Tentests\Tentests\Tentests\Tentests}

\parindent0pt
\begin{document}
%\Zftest
%\Tktest

\Hundredtests\Hundredtests\Hundredtests\Hundredtests\Hundredtests
\Hundredtests\Hundredtests\Hundredtests\Hundredtests\Hundredtests
\Hundredtests\Hundredtests\Hundredtests\Hundredtests\Hundredtests

\end{document}

答案1

(我对这份文件非常好奇……)

这是一个更紧凑的 MWE:

% !TEX TS-program = xelatexmk
\documentclass{article}

\usepackage{tikz}
\usetikzlibrary{tikzmark}

\tikzset{
  next page=below,
}

% Setup for regular brackets: 
\newcounter{tikzmkcnt}\setcounter{tikzmkcnt}{0} % counter to automatically set tikzmarks

\newif\iffirstmark

\newcommand{\dotikzmark}{%
  \stepcounter{tikzmkcnt}%
  \tikzmark{a\thetikzmkcnt}%
  TikZMark \thetikzmkcnt%
  \newpage
  \tikzmark{b\thetikzmkcnt}%
  \tikz[remember picture, overlay] {\draw (pic cs:b\thetikzmkcnt) -- (pic cs:a\thetikzmkcnt);}
}
%% But then I realized that even this one produces the error:
\newcommand{\Tktest}{\dotikzmark}
\newcommand{\Tentests}{\Tktest\Tktest\Tktest\Tktest\Tktest\Tktest\Tktest\Tktest\Tktest\Tktest}

\newcommand{\Hundredtests}{\Tentests\Tentests\Tentests\Tentests\Tentests\Tentests\Tentests\Tentests\Tentests\Tentests}

\parindent0pt
\begin{document}


\Hundredtests\Hundredtests\Hundredtests\Hundredtests\Hundredtests
\Hundredtests\Hundredtests\Hundredtests\Hundredtests\Hundredtests
\Hundredtests\Hundredtests\Hundredtests\Hundredtests\Hundredtests

\end{document}

问题是,当 tikzmark 位于不同的页面上时,软件包会尝试通过想象按照规范布局的页面next page并计算正确的位移来将其放置在“正确”的位置。您面临的问题是,由于我稍后会解释的原因,当前页面和 tikzmark 页面相距很远,位移超出了尺寸限制。

我提出的解决办法是不要再这么聪明了。如果 tikzmark 在前面一页,它现在会像在即时下一页。我认为不这样做真的没有什么好处。这就是完美是优秀的敌人。

这是在最新版本中实现的在 github 上

tikzmark 认为当前页面和 tikzmark 页面之间存在巨大差异的原因是,它通过将数据链接到图片 ID(用于计数文档中的图片)来跟踪信息。更改文档中的 tikz 图片数量意味着 tikzmarks 可能与错误的图片相关联(直到完成新运行并再次同步),因此页码将被错误计算(并且在您的情况下,变得非常大)。

一旦文档稳定下来,您的 tikzmarks 就会与正确的页面相关联,这就是为什么即使没有修复,错误也会在第二次运行时消失。

相关内容