Initial commit: Ross 1988 re-typeset edition

A searchable, re-typeset edition of Fiona Ross, "The Evolution of the
Printed Bengali Character from 1778 to 1978" (Ph.D., SOAS, 1988),
transcribed from the 431-leaf ProQuest scan. All 431 pages done; 178
plates and 410 inline type specimens cut from the scan; 51 errata.

Tracked: the transcription (src/pages), the preamble and its typographic
decisions, the cut images (plates/ — not reliably regenerable, the crop
specs for the inline cuts were never scripted), tools, and the four
working documents.

Not tracked: the built PDF, which `make` remakes from src/ and plates/;
the ProQuest scan under source/, which is third-party and needed only by
`make prep` and `make plate`; scans/ and work/, both regenerable.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-14 19:03:25 +06:00
co-authored by Claude Opus 5
commit 82849eb94d
1053 changed files with 6089 additions and 0 deletions
+183
View File
@@ -0,0 +1,183 @@
# CONTINUATION — Ross 1988 re-typeset
## State (end of session 4, 2026-09-14)
- **All 431 PDF pages transcribed.** No `\unsure` readings outstanding.
- Chapter 5 `Vincent Figgins and Richard Watts` closed at orig. p.211 (PDF 213, notes 1–93, plates 89–96).
- Chapter 6 `European Typefoundries` orig. pp.214–240 (PDF 216–242, notes 1–81, plates 97–105).
- Section C `Indigenous Ventures` title at orig. p.241 (PDF 243).
- Chapter 7 `The Girīśa Vidyāratna Press and later foundry types.` orig. pp.242–263 (PDF 244–265,
notes 1–54, plates 106–117).
- **Part II** `Mechanical Typefounding and Composition of Bengali` title at orig. p.266 (PDF 268).
- Chapter 8 `Linotype Composition` orig. pp.267–308 (PDF 269–310, notes 1–124, plates 118–133).
- Chapter 9 `Monotype Composition` orig. pp.309–337 (PDF 311–339, notes 1–54, plates 134–148).
- **Part III** `Photocomposition of the Bengali Script` title at orig. p.338 (PDF 340).
- Chapter 10 `Filmsetting` orig. pp.339–363 (PDF 341–365, notes 1–74, plates 149–160).
- Chapter 11 `Digital Photocomposition` orig. pp.364–404 (PDF 366–406, notes 1–80, plates 161–174).
- `Conclusion` orig. pp.405–410 (PDF 407–412, notes 1–19).
- `Epilogue` orig. pp.411–418 (PDF 413–420, notes 1–14, plates 175–178).
- `Bibliography` orig. pp.419–429 (PDF 421–431), set with the new `biblist`/`bibgroup`/`bibhead`
macros: a bold group heading, then one entry per paragraph with a 1.6em hanging indent, set solid.
### Earlier state (end of session 3, 2026-09-13)
- Building clean: **195 edition pages, 199/431 PDF pages done**. No `\unsure` readings outstanding.
- Done (PDF pages): 1 title, 2 colophon, 3 dropped, 4–16 front matter, 17–30 Introduction (orig. pp. 15–28,
notes 1–26, plates 1–6), 31 Part I title, 32 Section A title, 33–74 chapter 1 `Charles Wilkins`
(orig. pp. 31–72, notes 1–131, plates 7–25).
- **Errata section** at the end; seven entries. `\erratum` + `src/errata.tex` + `make check` keep text and list in step.
PLAN.md's Editorial row records the policy; its Type row records the specimen rule.
- **Inline type specimens**: 214 cut so far into `plates/inline/`, set with `\ig` at native size. Workflow per page:
**NB `work/lines.py`'s line N is usually the line *after* the one counted visually — if a sheet comes
back with the wrong line, try the band one earlier.**
`work/lines.py N` lists the text lines → `work/glyphs.py N y0,y1 …` makes a numbered contact sheet of the ink
runs on chosen lines → `tools/crop_inline.py N name=INDEX[:left|right|first|last|mid|trimright|trimleft] …`
cuts them. When the space between a word and the glyph is too noisy to register as a gap, measure the run's
column profile and use the `INDEX+PX` form (e.g. `48+63`).
- **Watch for scanner bars in plate crops.** The `--rule` guard that stops engraved rules splitting a plate also
let thin bars survive; `crop_plate.py` now sweeps any very dark thin run at an edge *after* autocropping
(`strip_edge_bars`). Nine plates were re-cropped for this. If a plate looks like it has a black line down one
side, that is the cause — re-run `make plate` with its recorded recipe.
- **Bengali policy (Sammay, 2026-09-13)**: modern script → Tiro Bangla text; a historical typeface →
cut from the scan and set with `\ig`. Slips inside quoted matter are never corrected — mark them
`\qslip{}` (logged to `qslips.log`) and list them in QUESTIONS.md for checking against the source.
## Typography and plates — reworked 2026-09-13/14 at Sammay's request
- **Type**: 11pt TeX Gyre ScholaX (Century Schoolbook, from `texlive-fonts-extra`, added to the Dockerfile
for it) on a 5.2in measure ≈70 characters a line; leading 1.22; ragged right; hanging punctuation;
`\frenchspacing`; widows/orphans forbidden; heads a step larger; endnotes smaller and tighter
(`\notesection`); running head names the current chapter.
- **`tools/polish.py`** runs first in `build.sh`: `src/pages` (faithful transcription, never hand-edit the
output) → `work/pages` (what is actually typeset). It applies ties, en-dashes for ranges, small caps for
institutional acronyms, `\mbox` round specimens, and cross-reference links. See CLAUDE.md for the full
contract, especially the internal-vs-external rule for `p. N` references and the instruction to re-audit
the links after changing it.
- **Contents** and **List of Plates** entries are whole-line links to `page.N`.
- **Plates**: `crop_plate.py` deskews an out-of-square page (rule-centre measurement, profile-variance
fallback) and sweeps the grey gutter shadow. Deskew is the only step that resamples. All 89 plates were
re-cropped; a sample was checked and none lost content. If a plate looks tilted or has a dark band down
one side, re-run `make plate N=… ARGS="<recipe from the manifest>"`.
## Known cosmetic issue
Three plate files (p0130, p0131, p0218) report an identical `Overfull \hbox (57.8pt)`; the rendered pages show
no visible damage and the plates sit inside the measure. Cause not yet identified — not the image width (the
images differ) and not the margin note (moving it outside the minipage changed nothing). The three share one
trait: their images are **wide** enough that `width=\textwidth` (not `height=0.74\textheight`) is the binding
constraint, so the minipage content is exactly the measure and anything else on the line tips it over.
## Open with Sammay — see QUESTIONS.md
Nothing outstanding. The quotation-slip table in QUESTIONS.md lists the 15 suspected slips inside quoted
matter, left as printed for checking against the quoted sources; it is a courtesy list, not a blocker.
## Next
1. **Transcription is complete.** What remains is finishing work, not conversion:
read the built PDF end to end for damage the per-batch spot-checks could miss;
settle the two open QUESTIONS items (p.295 *compliments*, p.348 a dropped *to*);
move the QUESTIONS "adopted corrections" list into the colophon.
2. Expect more inline specimens — budget for the `lines.py` → `glyphs.py` → `crop_inline.py` loop per page.
3. Later polish: move the QUESTIONS "adopted corrections" list into the colophon; a plate-only page's running
head shows the previous text page too ("orig. pp. 16–38") — acceptable, refine if wanted.
### Never kill a build mid-run without clearing `work/main.aux`
A full build is ~20 min at 420 pages, so the temptation is to stop one that is carrying a change you
are about to supersede. Don't, unless you then `rm -f work/main.aux work/main.toc work/main.out`.
`build.sh` does not clear them, so the next run reads back a `.aux` truncated mid-`\enotez@note` and
dies at `\begin{document}` with `File ended while scanning use of \enotez@note` / `Runaway argument?`
— an error that looks like an unbalanced brace in a page file and is not. Check
`tail -c 200 work/main.aux` first: a clean block-boundary size (e.g. exactly 172032 bytes) ending
mid-entry is the tell.
### Hyphenation — settled, do not re-open
The original never breaks a word at a line end. Checked over all 431 leaves: 59 line-ending hyphens,
every one a compound the author typed or OCR noise off a plate image (`work/lineend-hyphens.json`
holds the list). Output hyphenation is therefore off (`\lefthyphenmin=62`, `\hyphenpenalty=10000`),
with `\exhyphenpenalty` left low so a typed hyphen may still end a line as it does in the original.
### Unnumbered in-text figures — `\fig`
Chapters 7 and 8 set illustrations in the run of the text with **no plate number and no caption** (the
sentence before them carries the reference): orig. p.245's two cut/penned `ব` forms, orig. p.259's tier
diagram. `\fig{plates/fig-pNNNN.png}` (added 2026-09-14) centres one at native size, shrinking it only if
it is wider than the measure. Cut these by explicit pixel box with PIL — `crop_plate.py` is for whole-page
plates — and record the box in the manifest `notes` column.
### A printed page number inside the plate's own column range
Plate 119 (PDF 272) has the thesis's printed page number sitting in the same columns as the plate's lower
figure, so no `--box` can exclude it. Crop such a plate with PIL instead: paint the page number's rectangle
white, then take the ink bounding box. Record both steps in the manifest `notes` column.
### Framed plates need `--raw`
Chapter 6's plates are reproductions of whole framed pages (`plates 97–103`). The frame's own border rules sit
at the very edge of the crop, where `strip_edge_bars` reads them as scanner bars and sweeps them off — taking
content with them on p0222, where two lines were lost. `crop_plate.py --raw` (added 2026-09-14) takes an
explicit `--box` exactly: no shadow sweep, no deskew, no bar sweep, no autocrop. Measure the box first by
finding the frame's rules (columns/rows whose ink mean exceeds 0.5), then pass `--raw --box L,T,R,B` as
**fractions** of the raw page — `--box` is fractional, not pixels, and pixel values raise a PIL
DecompressionBombError. Every plate recipe is in the manifest `notes` column.
### Measuring the original's leading — autocorrelate, don't count bands
Counting gaps between ink bands gives nonsense: a line's ascender band and its x-height band are often
detected separately, halving the apparent pitch, and a page with a plate or a displayed extract poisons the
median. Pages came back at 40, 53, 70, 94 px for the same document. Autocorrelating the row-ink profile over
the text block and taking the peak in 35-140 px is robust: every ordinary page then returns 94-95 px at
300 dpi, and so does every specimen page. **The original is leaded 22.9 pt uniformly** — the thing to
reproduce. Its specimens reach 16.9 pt at the 90th percentile, 74% of the line, and only 0.7% crowd it.
Our build now measures 23.1 pt on a plain page and 23.1 pt on a specimen page (r=0.85 / 0.41; the low r is
a seven-line block, not unevenness).
### First-line indent and the ragged2e trap
The original never indents: it separates paragraphs by a blank line, and being justified, that blank line
sits under a flush line and reads clearly. Reflowed and ragged right the cue is much weaker, so this edition
indents 1.6em and keeps `\parskip` small (Sammay, 2026-09-14). Setting `\parindent` alone is not enough —
ragged2e's `\RaggedRight` assigns `\parindent` from `\RaggedRightParindent` (0pt by default) every time it
is invoked, so set both, and remember that any `\RaggedRight` inside a macro re-zeroes the indent locally.
### Swallowed digits: a TeX integer assignment eats the text after it
Reported 2026-09-14: the Halhed shelfmarks on orig. p.420 came out as `- 5593`, `and 5596`, `A and 5660B`,
`E`, `F`, `A`, `B`. The transcription in `src/pages/p0422.tex` was correct and so was `work/pages/p0422.tex`;
the loss was in the typesetting. `biblist` set `\everypar{\hangindent=1.6em\hangafter=1}`, and `\hangafter`
is an integer parameter: TeX goes on scanning digits after the `1`, so a paragraph beginning `5590 - 5593`
assigned `\hangafter=15590` and the number was gone. Fixed by terminating the assignment with `\relax`.
**Any numeric assignment in an `\everypar`, a hook, or a macro that can be followed by body text needs
`\relax`.**
### One build at a time in `work/`
`build.sh` runs every pass in `work/`, so two concurrent `make build`s share `main.aux`. Starting a second
build (or clearing the aux files by hand) while one is running kills the first at `\end{document}` with
"I can't find file `main.aux'", and the next pass dies at `\begin{document}` in `\openout\@mainaux` — which
looks like a permissions or disk fault and is neither. Wait for the running build before starting another.
### A group that ends before its own `\par` loses its leading
Twice now: the plate captions, and the last paragraph of `src/colophon.tex`. `\setstretch` (like `\small`)
is a paragraph-shape parameter read at the `\par` that ends the paragraph, so `{\setstretch{1.2} text}` or
`\begingroup\setstretch{1.2} ... \endgroup` sets the final paragraph at the *outer* leading. End the
paragraph explicitly — `\par` before the closing brace or `\endgroup`.
### `tools/reprocheck.py` — the reproduction check that found it
Bag comparison, not sequence: every token in `src/pages/*.tex` must reach the built PDF at least as often as
it appears in the source. Order-insensitive, because endnotes and the Contents move text about. Run it after
any build that changes the preamble:
python3 tools/reprocheck.py [pdf]
It de-TeXes the page files (macro table in the script says which argument of each macro carries copy) and
compares against `pdftotext -layout`. Two extraction artifacts are reported separately as "merged into a
neighbour", not as losses: poppler glues an endnote superscript onto the word before it (`em.`+`55`), and it
drops the thin space between the two Bengali forms in a Scheme-of-Transliteration cell. `-layout` is required
— without it poppler rejoins a compound broken at its own hyphen (`Staats-Druckerei`), which this text does
constantly, and ~80 false positives appear. A clean run prints `0 tokens short`.
## Environment
Runs from this directory with Claude Code; tools via `make` (Docker). `CLAUDE.md` has the rules and macro table.
The Makefile exports `UID`/`GID` (zsh does not). `make check` and `make build` must both pass at the end of
every batch.
## Layout
```
ross-thesis/
PLAN.md CONTINUATION.md QUESTIONS.md manifest.tsv build.sh
src/preamble.tex src/colophon.tex src/errata.tex src/main.tex (generated) src/pages/pNNNN.tex
tools/prep.sh tools/ocr2tex.py tools/crop_plate.py tools/crop_inline.py tools/check.py tools/setrow.py tools/reprocheck.py
work/lines.py work/glyphs.py (scratch helpers for the specimen workflow)
fonts/TiroBangla-*.ttf plates/pNNNN.png plates/inline/pNNNN-*.png plates/logo-proquest.png
scans/ work/ (scratch; excluded from tarball) older-versions/ ross-1988-retypeset.pdf
```