standalone

standalone은 그림이나 TikZ 그림 하나만을 내용 크기에 맞게 잘라 낸 한 페이지 LaTeX 문서로 조판하기 위한 클래스입니다. 진짜 값어치는 잘라 내기보다 한 파일이 두 얼굴을 가진다는 데 있습니다. figure.tex를 단독으로 컴파일하면 그림만 담긴 PDF가 되고, 논문에서 \input하면 같은 파일이 한 글자도 바뀌지 않고 본문으로 흘러 들어갑니다. 잘라 내는 장치에도 내력이 있습니다. 지금 기본값인 crop이 들어오기 전, standalone이 쓰던 것은 Emacs의 AUCTeX에서 자라난 preview 패키지, 곧 편집기 위에 수식 미리보기를 띄우는 바로 그 코드였습니다. 이 페이지는 클래스와 패키지 자체를 다룹니다. border=가 작동하는 방식, multisubpreambles, 그리고 실제로 마주치는 오류입니다. 완성한 그림을 PNG나 SVG로 만드는 공정은 다른 페이지의 몫입니다.

같은 그림 파일을 단독으로도 본문에서도 쓰기

문서가 커지면 그림을 별도 파일로 빼고 싶어집니다. 그런데 그런 그림 파일만 시험 삼아 컴파일하려면 매번 \documentclass, \begin{document}라는 틀을 덧붙여야 하고, 출력도 큰 흰 본문 페이지 한쪽에 그림이 놓인 모양이 됩니다. standalone 클래스는 이 둘을 한 번에 해결합니다. 그림 파일 맨 앞에 \documentclass{standalone}을 써 두면 단독으로 컴파일할 수 있고, 출력은 내용 크기에 맞게 잘린 한 페이지(PDF·DVI·PS)가 되며 페이지 번호도 머리말도 꼬리말도 나오지 않습니다.

latex
% figure.tex — a figure that is its own document
\documentclass[tikz,border=2pt]{standalone}
\begin{document}
\begin{tikzpicture}
  \draw[thick,->] (0,0) -- (3,0) node[right] {$x$};
  \draw[blue,thick] (0,0) .. controls (1,2) .. (3,1);
\end{tikzpicture}
\end{document}

standalone은 두 얼굴로 이루어져 있습니다. 그림 파일 쪽에서 쓰는 클래스(\documentclass{standalone})와 본문 문서 쪽에서 불러오는 패키지(\usepackage{standalone})입니다. 클래스는 “한 조각을 단독으로 조판”하는 역할을, 패키지는 “그 조각을 본문에 가져오는” 역할을 맡습니다. 만든 사람은 Martin Scharrer이고, TeX Live 2024에 들어 있는 것은 2022년 10월판 v1.3b입니다. 의존 관계는 클래스 쪽이 xkeyval, 패키지 쪽은 거기에 더해 currfile, gincltex, filemod, adjustbox이며 모두 TeX Live와 MiKTeX에 기본 포함되어 있습니다.

crop과 preview의 차이, 그리고 기본값은 어디서 정해지는가

기본값은 crop, 여백은 0pt입니다. 다만 그 기본값은 클래스 파일이 아니라 설정 파일 standalone.cfg 에 적혀 있습니다. standalone.cls 자체는 preview와 0.50001bp를 기본으로 두는데, 이는 v0.x의 동작입니다. 그리고 옵션 처리가 시작되기 직전에 standalone.cfg가 읽혀 \standaloneconfig{crop}\standaloneconfig{border=0pt}로 둘 다 덮어씁니다. 이 이중 구조에는 쓸모가 있습니다. 자기 몫의 standalone.cfg를 프로젝트 디렉터리나 로컬 TEXMF 트리에 두면 그 환경의 모든 standalone 파일의 기본값을 바꿀 수 있습니다. 배포판 cfg는 갱신 때마다 덮어써지므로, 자기 설정은 반드시 별도 파일에 두세요.

croppreview는 서로 배타적이라 둘 다 지정하면 나중에 쓴 쪽이 이기고, 어느 쪽이든 float=false를 함께 끌고 옵니다. 실제 차이는 재 보면 드러납니다. 2 cm × 1 cm 사각형만 담은 그림을 TeX Live 2024에서 조판하면 기본값 crop에서는 57.09 × 28.75 bp 입니다. 여기서 \end{document} 앞에 빈 줄을 하나 넣으면 crop에서는 아무것도 달라지지 않지만, preview를 지정한 경우 폭이 343.71 bp 로 뛰어오릅니다. 빈 줄이 문단의 끊김으로 읽혀 내용이 \linewidth 가득한 문단이 되기 때문입니다. “그림 오른쪽에 넓은 여백이 생긴다”는 단골 증상이 바로 이것이고, crop이 기본값이 된 것도 이를 피하기 위해서였습니다. 그럼에도 preview가 남아 있는 이유는 XeLaTeX에서 TikZ 셰이딩이 제대로 나오지 않을 때의 도피처가 필요하기 때문입니다.

border=로 여백 더하기 — 값이 읽히는 방식

가장 자주 쓰는 옵션은 border=(별칭 margin=)입니다. 값을 하나 쓰면 네 변 모두, 둘이면 좌우와 상하, 넷이면 왼쪽·아래·오른쪽·위 순으로 적용됩니다. 공백으로 나눈 여러 값을 넘길 때는 전체를 중괄호로 감싸 border={10pt 5pt}처럼 씁니다. 단위를 뺀 맨 숫자는 bp(PostScript 포인트)로 읽힙니다. 앞의 57.09 × 28.75 bp 그림에서 재 보면 border=5pt67.05 × 38.71 bp(각 변에 5pt, 약 4.98bp), border={10pt 5pt}77.02 × 38.71 bp 가 됩니다. bordervarwidth는 문서 전체에 걸리는 설정이 아니므로, 프리앰블에서 또는 multi가 켜져 있으면 문서 중간에서도 \standaloneconfig{...} 로 나중에 바꿀 수 있습니다.

옵션효과기본값
crop내용을 상자에 넣고 페이지를 내용 크기와 여백에 맞게 자름true, standalone.cfg가 설정
previewpreview 패키지(active·tightpage 지정)로 자르는 예전 방식. crop과 배타적off
border / margin자르기에 더하는 여백. 값 1개=네 변, 2개=좌우/상하, 4개=왼쪽/아래/오른쪽/위0pt
varwidth내용을 varwidth 환경으로 감싸 문단이 자연스러운 폭을 갖게 함. varwidth=6cm으로 상한 지정off
tikz / pstricks그림 패키지를 불러오고 그 환경을 한 장씩 잘라 냄(multi=tikzpicture, varwidth=false 설정)off
multi / ignorerest내용을 여러 페이지로 나누고 각 페이지를 따로 자름. ignorerest는 선언한 환경 바깥을 버림off
class아래에서 불러올 클래스를 고름. class=jsarticle처럼 일본어 클래스도 지정 가능article
beamer자르기를 끄고 내용을 빈 beamer 프레임에 얹어 조판off

한 파일에서 여러 그림 잘라 내기(multi)

기본적으로 document 환경 안의 내용은 통째로 한 페이지가 됩니다. multi 를 켜면 지정한 환경이 나타날 때마다 한 장씩 잘려 나오고, 각각 따로 잘립니다. \documentclass[tikz]{standalone}이 편리한 이유가 여기 있습니다. tikz 옵션은 내부에서 multi=tikzpicturevarwidth=false를 설정하므로, tikzpicture를 둘 나란히 쓰면 PDF가 2페이지가 됩니다(PSTricks에는 pstricks 옵션이 같은 일을 합니다). 임의의 환경을 대상으로 하려면 \standaloneenv{myfig}를 선언하고 환경 바깥에는 아무것도 두지 않습니다. 굳이 바깥에 써야 할 것이 있을 때만 ignorerest를 더하세요. 수식을 하나씩 잘라 내는 math 옵션도 있는데, 이쪽은 multiignoreempty에 더해 0.50001bp 여백을 함께 설정합니다.

standalone에서 자주 만나는 오류와 증상

standalone의 오류는 어느 것이나 원인이 분명해서 증상에서 곧바로 되짚어 갈 수 있습니다. 가장 흔한 것은 figure 환경을 standalone 파일 안에 넣는 경우로, crop이나 preview가 작동 중이면 ! LaTeX Error: Not in outer par mode. 또는 “Float(s) lost”가 나옵니다. 자르기는 내용을 상자에 담아 이루어지는데, 상자 안에서는 플로트가 떠다닐 수 없기 때문입니다. croppreview는 둘 다 스스로 float=false를 설정하므로, 이 오류는 나중에 손으로 float=true를 쓴 경우에만 나타납니다. 플로트는 본문 문서에 두고, standalone 파일에는 그림 자체만 넣으세요.

  • 그림 오른쪽에 넓은 여백이 생긴다. 내용이 문단이 된 것입니다. \end{document} 앞의 빈 줄이나 불필요한 \par를 지우거나, varwidth를 붙이거나, multi\standaloneenv로 환경을 선언하세요.
  • 오른쪽 끝이 잘려 내용이 빠진다. varwidth의 상한(기본값 \linewidth)이 너무 좁습니다. varwidth=15cm처럼 넓히거나 varwidth=false로 끄세요.
  • 옵션 값이 통과하지 않는다. 불리언 키에 true/false 이외를 쓰면 ! Class standalone Error: Invalid value 'maybe' for boolean key 'crop'. 처럼 멈춥니다.
  • 여러 페이지 파일에 쓸데없는 페이지가 섞인다. multi를 쓰는 중이고 선언한 환경 바깥에 조판되는 내용이 있습니다. 그것을 지우거나 ignorerest를 켜세요.
  • DVI 경로에서 잘림이 이상하다. crop은 DVI 모드에서 PostScript 명령을 써 내는 구현이고, 매뉴얼 자체가 그 코드를 실험적이라고 밝힙니다. latex 경로에서는 preview가 더 안정적일 때가 있습니다.

패키지 쪽 — 본문에서 \input하기

본문 문서 프리앰블의 가능한 한 이른 시점에 \usepackage{standalone}을 불러오면, 패키지는 \documentclass를 재정의해 \input한 그림 파일의 \documentclass부터 \begin{document}까지를 건너뛰게 합니다. 그림 파일의 document 환경은 그저 TeX 그룹으로 취급되고, \end{document} 뒤에 쓴 것도 무시됩니다. 즉 본문 쪽에는 그림 파일의 내용만 흘러 들어옵니다. 전제는 하나, 그림 파일이 필요로 하는 패키지를 본문 쪽에서도 불러 둘 것입니다. 그림 파일의 프리앰블은 건너뛰므로 tikz 같은 것은 본문이 읽을 수밖에 없습니다.

latex
\documentclass{article}
% load the standalone package early
\usepackage{standalone}
% and everything the sub-files need
\usepackage{tikz}

\begin{document}
\begin{figure}
  \input{figure}%  the standalone file from above
  \caption{A sub-file}
\end{figure}
\end{document}

프리앰블을 손으로 옮기는 것이 번거롭다면 \usepackage[subpreambles=true]{standalone} 이 대신 모아 줍니다. 각 그림 파일의 프리앰블이 보조 파일에 모이고, 다음 처리 때 본문 문서로 들어옵니다. sort를 더하면 그림들이 불러오는 패키지와 옵션이 중복 없이 정리되고 \PassOptionsToPackage를 통해 로드되어 옵션 충돌을 피할 수 있습니다. 직접 본문 프리앰블에 옮겨 적고 싶다면 print가 목록을 출력해 주지만, 이는 수집 전용 모드여서 Package standalone Warning: Running 'standalone' package in sub-preamble print mode. All body content of file 'figure.tex' is ignored! 라는 경고 그대로 본문은 조판되지 않습니다.

\includestandalone과 mode= — 소스인가 이미지인가

\input 대신 \includestandalone{figure} 를 쓰면 패키지 옵션 mode=로 가져오는 방식을 고를 수 있습니다. 값은 tex(소스를 포함. 기본값), image(이미 있는 PDF·EPS를 \includegraphics로 포함), image|tex(이미지가 있으면 이미지, 없으면 소스), build(매번 빌드해 사용), buildmissing(이미지가 없을 때만 빌드), buildnew(소스가 더 새로울 때만 빌드. XeLaTeX에서는 동작하지 않음)입니다. 목적은 속도입니다. 복잡한 그림을 본문 문서를 돌릴 때마다 다시 조판하지 않아도 됩니다. 외부 명령을 호출하는 것은 build 계열 셋뿐이며, 그때는 -shell-escape가 필요합니다. 빌드에 실패하면 경고를 내고 소스 포함으로 되돌아간다고 공식 매뉴얼에 명시되어 있습니다.

여기서부터 뒤의 공정 — 잘라 낸 PDF를 PNG나 SVG로 내보내기, pdfcrop으로 기존 PDF의 여백 떼어내기, dvisvgm 사용법, convert=에 넘기는 설정 — 은 “이미지로 내보내기” 페이지가 맡습니다. standalone 클래스 쪽에서 기억해 둘 것은 하나뿐입니다. 여백을 만들지 않는 편이 나중에 잘라 내는 것보다 빠르고 정확하다는 것입니다.

프로젝트에 넣는 방식

실제 논문에서는 standalone 파일 하나하나를 그림의 소스로 다루고, 본문과 따로 점검할 수 있는 형태로 두면 강해집니다. 본문은 paper.tex, 그림은 figures/ 아래에 두고, 본문에는 \input{figures/energy-flow}만 씁니다. 그러면 그림을 고치는 사람은 figures/energy-flow.tex만 단독으로 컴파일해 확인할 수 있고, 본문 쪽은 캡션·번호·참조만 관리합니다. 검토할 때는 이 한 페이지 PDF를 첨부해 “그림만 보는” 차례를 만들면, 전체 원고의 재빌드를 기다리지 않고 그림의 질을 높일 수 있습니다.

terminal
paper.tex
standalone.cfg          # optional: your own defaults for every figure
figures/
  energy-flow.tex
  apparatus-layout.tex
  timing-diagram.tex

그림의 내용이 본문과 같은 조판 규칙을 따라야 할 때는 class= 로 하위 클래스를 맞춥니다. 일본어 라벨이 들어간 그림이라면 upLaTeX에서 \documentclass[class=jsarticle,border=5pt]{standalone}, LuaLaTeX에서 class=ltjsarticle을 쓰면 일본어 자간과 서체가 본문과 나란해집니다. 클래스와 패키지가 함께 제공하는 \ifstandalone, \IfStandalone{단독일 때}{포함될 때}, \onlyifstandalone{...} 도 편리합니다. 축척 막대나 디버그용 테두리를 그림 파일에서만 보이게 하는 일을 한 줄로 쓸 수 있습니다.

subfiles·TikZ external과의 차이

목적이 비슷한 방식이 둘 있는데, 둘 다 방향이 반대입니다. subfiles 에서는 하위 파일이 본문 문서의 프리앰블을 가져옵니다. standalone은 그 반대로, 하위 파일의 프리앰블을 본문 쪽으로 모을 수 있습니다. 그래서 한 장의 그림을 논문·발표·학위논문처럼 여러 문서에서 재사용한다면 standalone이, 본문과 하위 파일이 일대일로 대응하는 장 단위 분할이라면 subfiles가 맞습니다. TikZ의 external 라이브러리 는 본문 파일에서 임시 이미지를 써 내는 방식이라 역시 반대 방향입니다. 다만 \includestandalone[mode=buildnew]를 쓰면 무거운 그림을 캐시하는 효과를 사실상 그대로 얻으면서도 그림을 독립된 파일로 유지할 수 있습니다.