How to make a smarter cropping with standalone or preview packages?

do not use the standalone documentclass. Create a default pdf output and then run pdfcrop on that file. The created <file>-crop.pdf has a correct bounding box. The example needs two pdflatex -shell-escape <file> runs:

\documentclass{minimal}
\usepackage{graphicx,tikz}
\pagestyle{empty}
\begin{document}

\IfFileExists{\jobname-crop.pdf}
  {\typeout{Delete \jobname-crop.pdf}%
   \immediate\write18{rm -f \jobname-crop.pdf}}
  {\IfFileExists{\jobname.pdf}
    {\immediate\write18{pdfcrop \jobname}}
    {\typeout{we need one more pdflatex run with option -shell-escape!}}
  }
\IfFileExists{\jobname-crop.pdf}
  {\frame{\includegraphics{\jobname-crop.pdf}}}
  {%
   \begin{tikzpicture}[scale=3,line width=3pt]
   \draw[red] (0,0) grid (1,1);
   \draw[blue,|->] (0,0) -- (1,1);
   \end{tikzpicture}%
}
\end{document}

enter image description here


As Martin Scharrer pointed out, preview or standalone classes see the Tikz picture as black boxes with some size reported by the TikZ bounding box. For this reason, it's only up to TikZ internals to compute the correct box.

However, arrows and line join artifacts don't contribute to bounding box calculations and I don't know a quick hack to fix this. Example:

\documentclass[tikz,border=0pt]{standalone}
\usepackage{tikz}

\begin{document}
\begin{tikzpicture}[scale=3,line width=3pt]
\draw[red] (0,0) grid (1,1);
\draw[blue,|->] (0,0) -- (1,1);
\draw[line join=miter] (1,1) -- (0,0.5) -- (1,0);
\end{tikzpicture}
\end{document}

enter image description here

You can manually change the bounding box to include the missing details for example with

\documentclass{standalone}
\usepackage{tikz}

\begin{document}
\begin{tikzpicture}[scale=3,line width=3pt]
\draw[red] (0,0) grid (1,1);
\draw[blue,|->] (0,0) -- (1,1);
\draw[line join=miter] (1,1) -- (0,0.5) -- (1,0);
\useasboundingbox ([shift={(-0.5\pgflinewidth,-0.5\pgflinewidth)}]current 
bounding box.south west) -- (current bounding box.north east);
\end{tikzpicture}
\end{document}

enter image description here

Note that the shift amount should be changed for each custom picture, I've just used a shortcut here.


Till Tantau explains that just including arrows.meta library solves the problem. Bounding box is adjusted to included arrow tips and tails.

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{arrows.meta}

\begin{document}
\begin{tikzpicture}[scale=3,line width=3pt]
\draw[red] (0,0) grid (1,1);
\draw[blue,|->] (0,0) -- (1,1);
\draw[line join=miter] (1,1) -- (0,0.5) -- (1,0);
\end{tikzpicture}
\end{document}

enter image description here