- Add startup banner with NO AUTH warning - Add --max-decompress-gb CLI flag (default 1 GB) - Add hard cap for --max-upload-mb at 4096 MB (4 GiB) - Add max_decompress_gb form field parsing - Update CLI help text with security model documentation - Add comprehensive security model docs to serve.rs rustdoc This implements the security constraints required by the bead: - No built-in authentication (deploy behind reverse proxy) - No file-path parameters (multipart upload only) - Hard caps to prevent integer overflow - Visible security warnings at startup Closes: pdftract-4li3d
3.7 KiB
3.7 KiB
pdftract-1jlpy: Page /Rotate normalization applied to glyph bboxes
Summary
Implemented page /Rotate normalization for glyph bboxes in content_stream.rs. The normalization is applied after content stream execution to ensure downstream layout phases operate in an un-rotated coordinate system.
Changes Made
Function Added: normalize_glyph_bboxes_by_rotation()
Location: crates/pdftract-core/src/content_stream.rs
Signature:
pub fn normalize_glyph_bboxes_by_rotation(
glyphs: &mut [Glyph],
rotate: i32,
media_box: [f64; 4],
diagnostics: &mut Vec<Diagnostic>,
) -> (f64, f64)
Behavior:
- Normalizes rotate value to 0, 90, 180, or 270 degrees
- Emits
PageInvalidRotatediagnostic for non-multiple-of-90 values (treats as 0) - Applies inverse rotation transformation to all glyph bboxes
- Returns rotated page dimensions (width/height swapped for 90°/270°)
Rotation Matrices Implemented
| Rotate | Transformation | Example (100x200 page) |
|---|---|---|
| 0° | Identity (no change) | (x, y) → (x, y) |
| 90° | Counter-clockwise | (x, y) → (y, page_width - x) |
| 180° | Invert both axes | (x, y) → (page_width - x, page_height - y) |
| 270° | Counter-clockwise | (x, y) → (page_height - y, x) |
Tests Added
8 comprehensive tests covering all acceptance criteria:
test_normalize_rotation_0_no_change- /Rotate 0 leaves bboxes unchangedtest_normalize_rotation_90_with_specific_bbox- /Rotate 90 swaps axes correctlytest_normalize_rotation_90_swaps_axes- Dimensions swap for 90°test_normalize_rotation_180_inverts_both_axes- /Rotate 180 inverts both axestest_normalize_rotation_270_swaps_axes_inverted- /Rotate 270 swaps axes invertedtest_normalize_rotation_invalid_emits_diagnostic- /Rotate 45 emits diagnostictest_normalize_rotation_negative_normalized- Negative rotations normalizedtest_normalize_rotation_450_wraps_to_90- Rotations > 360° wrap correctly
Test Results
All 8 tests pass:
PASS [ 0.005s] pdftract-core content_stream::tests::test_normalize_rotation_0_no_change
PASS [ 0.005s] pdftract-core content_stream::tests::test_normalize_rotation_90_swaps_axes
PASS [ 0.005s] pdftract-core content_stream::tests::test_normalize_rotation_90_with_specific_bbox
PASS [ 0.005s] pdftract-core content_stream::tests::test_normalize_rotation_180_inverts_both_axes
PASS [ 0.005s] pdftract-core content_stream::tests::test_normalize_rotation_270_swaps_axes_inverted
PASS [ 0.005s] pdftract-core content_stream::tests::test_normalize_rotation_invalid_emits_diagnostic
PASS [ 0.004s] pdftract-core content_stream::tests::test_normalize_rotation_negative_normalized
PASS [ 0.005s] pdftract-core content_stream::tests::test_normalize_rotation_450_wraps_to_90
Acceptance Criteria Status
| Criterion | Status |
|---|---|
| /Rotate 0: all bboxes unchanged | ✅ PASS |
| /Rotate 90: bbox transformation verified | ✅ PASS |
| /Rotate 180: bbox transformation verified | ✅ PASS |
| /Rotate 270: bbox transformation verified | ✅ PASS |
| Output page.width/height match rotated dimensions | ✅ PASS |
| /Rotate 45 (illegal) emits diagnostic | ✅ PASS |
Commits
606e162- feat(pdftract-1jlpy): implement page /Rotate normalization for glyph bboxes
Notes
- The function is designed to be called AFTER content stream execution (via
execute_with_do) but BEFORE passing glyphs to Phase 4 layout phases - The normalization happens in-place on the glyph slice
- Page dimensions returned by the function should be used for the output schema's
page.widthandpage.heightfields - The implementation handles negative rotations and rotations > 360° correctly by normalizing to the 0-360 range