A small Rust workspace that parses Bromcom-produced PDF timetables and renders a printable A4 SVG-style weekly timetable, with a color-coded timetable grid and an embedded school map highlighting departments.
Important
I built this for my daughter who has some additional needs and finds it easier to associate colours with rooms; it is based upon parsing the information out of Bromcom circa 2025; PDF parsing is notably brittle and so this may not work without significant fixes for other timetables. I'm happy to accept Pull Requests if you find an issue, ideally with some anonymized examples.
This repository contains two crates:
crates/core— library with parsing, configuration, overrides, map processing and rendering codecrates/cli— command-line utility which wires config + PDF + map -> SVG output
- Parse Bromcom timetable PDFs and reconstruct lessons (Subject, Room, Teacher, Class code)
- Configurable room-to-department mapping with separate background and foreground colors
- Per-week/day/period overrides via
config.tomlto correct parsing errors or make manual adjustments - Render A4 sized SVGs containing a timetable grid and an embedded school map
- CLI flags to supply student name/form manually (fallback when PDF doesn't contain an extractable name)
- Installation
- Quick Start
- Configuration
- Step-by-Step Tutorial
- Troubleshooting
- Architecture
- Development
- Contributing
- License
Download pre-built binaries from the Releases page for your platform:
- Linux:
timetable_cli-linux-x86_64.tar.gz(or arm64, riscv64) - macOS:
timetable_cli-macos-x86_64.tar.gzortimetable_cli-macos-arm64.tar.gz(Apple Silicon) - Windows:
timetable_cli-windows-x86_64.zip(or arm64) - FreeBSD:
timetable_cli-freebsd-x86_64.tar.gz
Extract and run:
# Linux/macOS
tar -xzf timetable_cli-*.tar.gz
./timetable_cli --help
# Windows
# Extract the ZIP file, then run in PowerShell or CMD
timetable_cli.exe --helpRequires Rust 1.70+ (install Rust).
git clone https://github.com/RichardSlater/bromcom-timetable-formatter.git
cd bromcom-timetable-formatter
cargo build --release
# Binary will be at: target/release/timetable_cli
./target/release/timetable_cli --helpOnce published to crates.io (package metadata added, publication pending):
cargo install timetable_cli# Build from source
cargo build --release
# Run with example (after creating config.toml and obtaining a PDF)
./target/release/timetable_cli \
--input input/Sample_Student_Timetable.pdf \
--config config.toml \
--map resources/SchoolMap.svg \
--output output/ \
--student-name "Alex Testington" \
--form "11XX"Output SVG files will be in the output/ directory, one per week.
Create a config.toml file with room mappings and optional overrides.
Maps room code prefixes to colors and map element IDs:
[[mappings]]
prefix = "MA" # Matches MA1, MA2, MA3, etc.
bg_color = "#fcdcd8" # Background color for cell and map
fg_color = "#e8a490" # Foreground/text color for labels
map_id = "Maths_Rooms" # SVG element ID in map file
label = "Maths" # Human-readable label
[[mappings]]
prefix = "SC"
bg_color = "#fad7e6"
fg_color = "#e68cb8"
map_id = "Science_Rooms"
label = "Science"Fields:
prefix— Room code prefix to match (case-sensitive)bg_color— Hex color for cell background and map highlightfg_color— Hex color for label text (optional, defaults to#231f20)map_id— SVG elementidordata-nameattribute to highlight in maplabel— Display name for department (optional)
Correct parsing errors or make manual adjustments:
[[overrides]]
week = 2 # Week number (1-based)
day = "Wednesday" # Monday-Friday (or Mon-Fri)
period = "L3" # PD, L1-L5
subject = "Geography" # Optional: override subject
room = "HU3" # Optional: override room
teacher = "Mr Smith" # Optional: override teacher
class_code = "HU9" # Optional: override class codeOnly the fields you specify will be overridden—others remain from the PDF parse.
You need:
- Bromcom timetable PDF (export from Bromcom system)
- School map SVG with labeled room areas
- Sample config.toml (modify the included example)
Copy the example config.toml and customize:
# Map room prefixes to departments and colors
[[mappings]]
prefix = "MA"
bg_color = "#fcdcd8"
fg_color = "#e8a490"
map_id = "Maths_Rooms"
label = "Maths"
# Add more mappings for each department
# ...
# Add overrides if needed
[[overrides]]
week = 1
day = "Monday"
period = "L1"
room = "MA5" # Correct parsing errorYour map SVG should have identifiable elements:
<svg>
<g id="Maths_Rooms">
<rect x="10" y="10" width="50" height="30" />
</g>
<g id="Science_Rooms">
<rect x="70" y="10" width="50" height="30" />
</g>
</svg>The id (or data-name) attributes must match the map_id values in your config.
./target/release/timetable_cli \
--input input/my_timetable.pdf \
--config config.toml \
--map resources/SchoolMap.svg \
--output output/Optional flags:
--student-name "Name"— Override extracted student name--form "11XX"— Override extracted form code
Find generated SVG files in output/:
Week_1_1.svgWeek_2_2.svg
Open in a web browser or vector editor (Inkscape, Illustrator) to preview. Print directly or export to PDF.
See Troubleshooting below for common problems.
Possible causes:
- PDF file is not a valid Bromcom timetable
- PDF doesn't contain extractable text (scanned image PDF)
- Output directory doesn't exist
Solutions:
- Verify the PDF opens in a PDF reader and contains text (not just images)
- Create the output directory:
mkdir output - Check terminal output for error messages
Possible causes:
- PDF format variation (coordinate system differs)
- Text grouping tolerance too strict
Solutions:
- Use overrides to correct specific lessons
- Report the issue with an anonymized PDF sample
- Adjust tolerance values (requires code modification)
Possible causes:
- Room prefix doesn't match configuration
- Room code format differs from expected
Solutions:
- Check that room codes in PDF match your
prefixconfig - Use longer, more specific prefixes (e.g., "MA1" instead of "M")
- Print debug info: Check console output for room codes found
Possible causes:
map_iddoesn't match SVG element ID- Map SVG structure is nested or uses different attributes
Solutions:
- Inspect your map SVG in a text editor
- Find the correct
idordata-nameattributes - Ensure elements are direct children or descendants of labeled groups
Possible causes:
- PDF doesn't contain name/form in expected location
- Text format differs from expected pattern
Solutions:
- Use CLI flags to override:
--student-name "Name" --form "XX" - These flags will be used when extraction fails
Possible causes:
- Bromcom character encoding issue (uses +29 offset)
- PDF uses non-standard fonts
Solutions:
- The parser automatically handles standard Bromcom encoding
- Report the issue with PDF sample if characters are still wrong
Possible causes:
- Rust version too old
- Missing system dependencies
Solutions:
- Update Rust:
rustup update - Ensure Rust 1.70+ is installed:
rustc --version - On Linux, install build essentials:
sudo apt install build-essential
- Check GitHub Issues for similar problems
- Open a new issue with:
- Exact command you ran
- Full error output
- OS and Rust version
- Anonymized PDF sample if possible
- See SUPPORT.md for more help channels
For detailed architecture documentation, module dependencies, and data flow diagrams, see ARCHITECTURE.md.
Key architectural concepts:
- Coordinate-based parsing: Reconstructs grid from PDF text positions
- Workspace structure: Core library + CLI binary separation
- Override system: User can correct parsing errors without code changes
- Embedded maps: SVG maps are highlighted and embedded in output
See CONTRIBUTING.md for development workflow, testing, and PR guidelines.
For a deeper look at unit vs integration tests, fixtures, and coverage goals, see docs/testing.md.
Quick commands:
# Run tests
cargo test --workspace
# Format code
cargo fmt --all
# Lint code
cargo clippy --all-targets --all-features -- -D warnings
# Build release binary
cargo build --release
# Generate API documentation
cargo doc --open --no-depsThis repository includes a .pre-commit-config.yaml to run common checks before committing and pushing.
Install pre-commit (requires Python):
pip install pre-commit
pre-commit install
pre-commit install --hook-type pre-pushHooks configured:
- YAML/formatting checks, whitespace trimming
cargo fmt --all -- --checkon commitcargo clippy --all-targets --all-features -- -D warningson commitcargo test --workspaceon push
Note: Running clippy and tests on every commit/push can be slow; you can skip via git commit --no-verify if necessary.
- See docs/TODO.md for the current roadmap and planned features
- Review CONTRIBUTING.md for development, testing, and commit guidelines
- Please follow the Code of Conduct and Support policy
- Security concerns should be reported privately (see SECURITY.md)
- Open issues for bugs or feature requests using the provided templates
- Contributions welcome!
MIT (see LICENSE)