//
··
1#!/usr/bin/env bash
2# Render each paper/figures/fig-*.tex to a standalone PDF + PNG
3# so the web client can embed the figures inline beside the proof
4# on the claim page.
5#
6# Why this exists: each fig-*.tex defines a `\begin{figure}` wrapping
7# a `\begin{tikzpicture}`. When the main paper builds, those figures
8# float into the rendered PDF. To show a single figure inline on a
9# claim page, we need it as a standalone image — that's what this
10# script produces.
11#
12# Output: paper/figures/fig-<id>.{pdf,png}, one of each per source
13# .tex file. The .pdf is the tectonic-compiled vector; the .png is
14# a 300dpi rasterisation via ImageMagick (which delegates to
15# ghostscript for PDF parsing). The .png is what the web client
16# embeds — vector via SVG would be nicer but requires an extra
17# poppler/dvisvgm install; PNG-at-300dpi is indistinguishable from
18# vector at the sizes we render inline.
19#
20# Requires: tectonic, magick (ImageMagick 7), gs (Ghostscript).
21#
22# Usage:
23# ./scripts/render-figures.sh # render all
24# ./scripts/render-figures.sh fig-i-1 # render one
25
26set -euo pipefail
27
28SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
29ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
30FIG_DIR="$ROOT/paper/figures"
31WORK_DIR="$(mktemp -d)"
32trap 'rm -rf "$WORK_DIR"' EXIT
33
34for tool in tectonic magick gs; do
35 if ! command -v "$tool" >/dev/null 2>&1; then
36 echo "ERROR: $tool not found in PATH." >&2
37 echo "Install:" >&2
38 case "$tool" in
39 tectonic) echo " brew install tectonic" >&2 ;;
40 magick) echo " brew install imagemagick" >&2 ;;
41 gs) echo " brew install ghostscript" >&2 ;;
42 esac
43 exit 127
44 fi
45done
46
47# Filter to a specific figure if a stem was passed; otherwise render all.
48if [[ $# -gt 0 ]]; then
49 TARGETS=()
50 for stem in "$@"; do
51 [[ -f "$FIG_DIR/${stem}.tex" ]] || { echo "missing: $FIG_DIR/${stem}.tex" >&2; exit 2; }
52 TARGETS+=("$FIG_DIR/${stem}.tex")
53 done
54else
55 TARGETS=("$FIG_DIR"/fig-*.tex)
56fi
57
58PREAMBLE='\documentclass[tikz, border=2pt]{standalone}
59\usepackage{tikz}
60\usetikzlibrary{calc, angles, quotes, intersections, through}
61\begin{document}'
62POSTAMBLE='\end{document}'
63
64for tex in "${TARGETS[@]}"; do
65 stem="$(basename "$tex" .tex)"
66 out_pdf="$FIG_DIR/${stem}.pdf"
67 out_png="$FIG_DIR/${stem}.png"
68
69 # Each fig-*.tex is wrapped in a `\begin{figure}[H]` ... `\caption{}`
70 # block — strip those and keep only the `tikzpicture` for the
71 # standalone wrapper. We also drop the `\label` (which the
72 # standalone build doesn't need).
73 tikzpic=$(awk '
74 /\\begin{tikzpicture}/ { capture=1 }
75 capture { print }
76 /\\end{tikzpicture}/ { capture=0 }
77 ' "$tex")
78
79 if [[ -z "$tikzpic" ]]; then
80 echo "warn: no \\begin{tikzpicture}…\\end{tikzpicture} block found in $tex, skipping" >&2
81 continue
82 fi
83
84 wrapped_tex="$WORK_DIR/${stem}.tex"
85 printf '%s\n%s\n%s\n' "$PREAMBLE" "$tikzpic" "$POSTAMBLE" > "$wrapped_tex"
86
87 # Tectonic chatters about cache hits + xdvipdfmx; redirect noise.
88 tectonic --outdir "$WORK_DIR" "$wrapped_tex" >/dev/null 2>&1 || {
89 echo "ERROR: tectonic failed on $stem.tex" >&2
90 continue
91 }
92
93 cp "$WORK_DIR/${stem}.pdf" "$out_pdf"
94 # IM7 syntax: density before input, background+flatten after, so the
95 # alpha channel is composed against a solid white before encoding the
96 # PNG (avoids a transparent background that disappears against a dark
97 # site theme).
98 magick -density 300 -background white "$out_pdf" -flatten "$out_png"
99
100 size_pdf=$(wc -c < "$out_pdf" | tr -d ' ')
101 size_png=$(wc -c < "$out_png" | tr -d ' ')
102 echo "rendered $stem: pdf=${size_pdf}B png=${size_png}B"
103done
104
105echo "Done. Outputs in $FIG_DIR/*.{pdf,png}"
106
