Files
tepbc-ross-retyped/build.sh
T
bdeshiandClaude Sonnet 5.5 d48ce1f50c Re-encode plates to lossless JBIG2 / JPEG at build time (115 MB -> 12 MB)
The scan is a bilevel 300 dpi JBIG2 layer plus lower-resolution colour, so
storing every plate as 8-bit PNG only added size. tools/optimize_plates.py
writes copies under work/plates-opt (bilevel to generic-mode, lossless JBIG2;
genuine halftone to JPEG q88) and repoints work/pages at them; plates/ and
src/ are untouched. The Dockerfile builds jbig2enc and adds qpdf, ghostscript
and img2pdf.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-09-29 14:36:18 +06:00

40 lines
2.7 KiB
Bash
Executable File

#!/bin/sh
# Assemble: preamble, title (p0001), colophon, remaining pages in PDF-page order,
# endnotes; compile with XeLaTeX (3 passes: marks/backrefs).
set -e
cd "$(dirname "$0")"
OUT=ross-1988-retypeset.pdf
# Two builds must never share work/: they share main.aux, and the second reads
# the first's half-written copy and dies at \begin{document} with "Undefined
# control sequence" or "File ended while scanning use of \enotez@note" — which
# reads like an unbalanced brace in a page file and is nothing of the kind.
# mkdir is atomic, so it is the lock. The way a second build actually gets
# started is mundane: someone runs `make` again while an earlier build is still
# going. Check `docker ps` before starting one — a build takes several minutes
# and gives no output until it finishes, so a running one is easy to forget.
if ! mkdir work/.buildlock 2>/dev/null; then
echo "build.sh: another build holds work/.buildlock — refusing to start." >&2
echo " check: docker ps (if nothing is running: rmdir work/.buildlock)" >&2
exit 1
fi
trap 'rmdir work/.buildlock 2>/dev/null' EXIT INT TERM
# Three full passes run below regardless, so a stale aux buys nothing.
rm -f work/main.aux work/main.toc work/main.out
python3 tools/polish.py >/dev/null # typographic pass: src/pages -> work/pages
# Re-encode the plates to match what they actually hold: bilevel type goes to
# lossless JBIG2, genuine halftone stays 8-bit as JPEG. Writes copies under
# work/plates-opt and repoints work/pages at them -- plates/ and src/ are
# never touched, so deleting work/ reverts it. Must run AFTER polish.py, which
# is what creates work/pages.
python3 tools/optimize_plates.py
{ cat src/preamble.tex
printf '%s\n' '\begin{document}\immediate\openout\unsurefile=unsure.log\immediate\openout\erratafile=errata.log\immediate\openout\qslipfile=qslips.log'
printf '\\input{%s}\n' work/pages/p0001.tex src/colophon.tex
for f in work/pages/p*.tex; do [ "$f" = work/pages/p0001.tex ] || printf '\\input{%s}\n' "$f"; done
printf '%s\n' '\notesection' '\printerrata' '\immediate\closeout\unsurefile\immediate\closeout\erratafile\immediate\closeout\qslipfile\end{document}'
} > src/main.tex
for i in 1 2; do xelatex -interaction=nonstopmode -halt-on-error -output-directory=work src/main.tex >work/pass$i.log 2>&1 || { grep -E "^!" -A3 work/pass$i.log; exit 1; }; done
xelatex -interaction=nonstopmode -halt-on-error -output-directory=work src/main.tex | grep -E "Overfull|Warning: .*(undefined|multiply)" | sort | uniq -c || true
cp work/main.pdf "$OUT"; cp work/unsure.log . 2>/dev/null || true; cp work/errata.log . 2>/dev/null || true; cp work/qslips.log . 2>/dev/null || true
echo "built $OUT: $(pdfinfo "$OUT" | grep Pages)"