Skip to content

Commit c1cea98

Browse files
committed
add dpi meta data
1 parent 21a93f0 commit c1cea98

27 files changed

+623
-71
lines changed

CHANGES_DPI_METADATA.md

Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
# DPI Metadata Enhancement for MicroTeX SVG Output
2+
3+
## Overview
4+
5+
This document describes the enhancement made to `microtex_rs` to embed DPI (dots per inch) metadata in generated SVG output. This metadata is essential for downstream processors (like PDF generators) to correctly size and position SVG content.
6+
7+
## Problem Statement
8+
9+
When MicroTeX renders LaTeX formulas to SVG, the generated SVG contains width and height attributes in pixels, but there was no indication of the DPI used during rendering. Downstream processors (like `genpdfi_extended`) had to make assumptions about the DPI, leading to incorrect sizing when the actual DPI differed from the assumed value.
10+
11+
For example:
12+
- MicroTeX renders at 720 DPI (default)
13+
- SVG generated with `width="120px"` (a 12pt formula)
14+
- A PDF generator assuming 300 DPI would incorrectly calculate the formula's physical size
15+
- Result: Formula appears ~2.4x larger than intended
16+
17+
## Solution
18+
19+
### New Public Function: `add_dpi_to_svg()`
20+
21+
A public function has been added to embed DPI metadata into SVG elements:
22+
23+
```rust
24+
/// Adds DPI metadata to an SVG string as a `data-dpi` attribute.
25+
pub fn add_dpi_to_svg(svg: &str, dpi: i32) -> String
26+
```
27+
28+
**Behavior:**
29+
- Locates the `<svg>` opening tag in the SVG content
30+
- Injects a `data-dpi="XXX"` attribute before the closing `>`
31+
- Returns the modified SVG with metadata embedded
32+
- Returns original SVG unchanged if no `<svg>` tag is found
33+
34+
**Example:**
35+
36+
Input:
37+
```xml
38+
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="50">
39+
```
40+
41+
Output (with dpi=720):
42+
```xml
43+
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="50" data-dpi="720">
44+
```
45+
46+
### Modified Methods
47+
48+
The following public methods now automatically embed DPI metadata in their output:
49+
50+
#### 1. `MicroTex::render()`
51+
- **Location:** `src/lib.rs:936-981`
52+
- **Change:** SVG output is processed through `add_dpi_to_svg()` before being returned
53+
- **Impact:** Every rendered SVG now contains the DPI value used during rendering
54+
55+
#### 2. `MicroTex::render_to_svg_with_metrics()`
56+
- **Location:** `src/lib.rs:1038-1122`
57+
- **Change:** SVG extracted from JSON response is processed through `add_dpi_to_svg()` before being included in `RenderResult`
58+
- **Impact:** Both SVG rendering methods now consistently embed DPI metadata
59+
60+
## Implementation Details
61+
62+
### Function: `add_dpi_to_svg()`
63+
- **File:** `src/lib.rs:813-852`
64+
- **Type:** Public function
65+
- **Algorithm:**
66+
1. Search for `<svg` opening tag in the SVG string
67+
2. If found, locate the closing `>` character
68+
3. Insert ` data-dpi="XXX"` before the `>`
69+
4. Return the modified string
70+
5. If no `<svg>` tag found or malformed, return original string unchanged
71+
72+
**Key Features:**
73+
- Safe: Returns original string on any parsing error (no exceptions)
74+
- Efficient: Single-pass string manipulation
75+
- Robust: Handles XML declarations, namespaces, and attributes
76+
- Preserves: All existing SVG content and structure
77+
78+
## Testing
79+
80+
### Unit Tests Added
81+
Six comprehensive tests verify the `add_dpi_to_svg()` function:
82+
83+
```rust
84+
test tests::test_add_dpi_to_svg_simple ... ok
85+
test tests::test_add_dpi_to_svg_with_namespace ... ok
86+
test tests::test_add_dpi_to_svg_different_dpi_values ... ok
87+
test tests::test_add_dpi_to_svg_no_svg_tag ... ok
88+
test tests::test_add_dpi_to_svg_malformed ... ok
89+
test tests::test_add_dpi_to_svg_preserves_content ... ok
90+
```
91+
92+
**Test Coverage:**
93+
1. **Simple SVG**: Verifies basic attribute injection with standard namespace
94+
2. **Namespace handling**: Tests with full SVG namespace declaration
95+
3. **Multiple DPI values**: Confirms correct values (300, 720) are embedded
96+
4. **No SVG tag**: Ensures graceful fallback when no `<svg>` tag exists
97+
5. **Malformed SVG**: Validates error handling for incomplete tags
98+
6. **Content preservation**: Confirms that SVG body content remains unchanged
99+
100+
### Test Results
101+
All tests pass:
102+
- **Unit tests:** 26 passed
103+
- **Binary tests:** 3 passed
104+
- **Integration tests:** 7 passed
105+
- **Multiple renderer tests:** 1 passed
106+
- **Example validation:** 7 passed
107+
- **Total:** 44 tests passed, 0 failed
108+
109+
### Example Verification
110+
The `simple_formula` example was updated to verify DPI embedding in real-world scenarios. Output confirms:
111+
```
112+
data-dpi attribute found! (for Einstein's E=mc²)
113+
data-dpi attribute found! (for Pythagorean theorem)
114+
data-dpi attribute found! (for Quadratic formula)
115+
data-dpi attribute found! (for Sum notation)
116+
data-dpi attribute found! (for Integration)
117+
```
118+
119+
## Impact on Downstream Processors
120+
121+
### For `genpdfi_extended`
122+
The PDF generator can now:
123+
1. Read the `data-dpi` attribute from SVG
124+
2. Use the actual rendering DPI (not assumed values) for sizing calculations
125+
3. Correctly position SVG content in PDF pages
126+
4. Fix the issue where large formulas were incorrectly placed and cut off
127+
128+
### Example Usage in `genpdfi_extended`
129+
130+
```rust
131+
// In src/elements/images.rs (ImageSource::intrinsic_size)
132+
ImageSource::Svg(svg) => {
133+
let mmpi: f32 = 25.4;
134+
135+
// Extract actual DPI from data-dpi attribute
136+
let actual_dpi = svg.dpi.unwrap_or_else(|| {
137+
// Fallback: try to extract from SVG string's data-dpi attribute
138+
extract_data_dpi_attribute(&svg_content)
139+
.unwrap_or(300.0)
140+
});
141+
142+
let width_px = svg.width.map(|px| px.0 as f32).unwrap_or(100.0);
143+
let height_px = svg.height.map(|px| px.0 as f32).unwrap_or(100.0);
144+
145+
Size::new(
146+
mmpi * (width_px / actual_dpi),
147+
mmpi * (height_px / actual_dpi),
148+
)
149+
}
150+
```
151+
152+
## Backward Compatibility
153+
154+
**Fully backward compatible**
155+
156+
- The change only adds metadata; existing SVG functionality is not affected
157+
- SVG files without the `data-dpi` attribute work as before
158+
- Downstream processors can ignore the attribute if they don't need it
159+
- No breaking changes to the public API
160+
- All existing tests pass without modification
161+
162+
## Benefits
163+
164+
1. **Correct Sizing**: Downstream processors can now accurately determine SVG dimensions
165+
2. **Self-Documenting**: SVG files contain metadata about their rendering context
166+
3. **Robustness**: Eliminates guessing about DPI values
167+
4. **Standardization**: Establishes a convention for encoding DPI in SVG
168+
5. **Debugging**: Easier to troubleshoot sizing issues with explicit DPI information
169+
170+
## Files Modified
171+
172+
- **`src/lib.rs`**
173+
- Added public function `add_dpi_to_svg()` (lines 813-852)
174+
- Modified `MicroTex::render()` to use `add_dpi_to_svg()` (line 945)
175+
- Modified `MicroTex::render_to_svg_with_metrics()` to use `add_dpi_to_svg()` (line 1078)
176+
- Added 6 unit tests for `add_dpi_to_svg()` (lines 1513-1563)
177+
178+
- **`examples/simple_formula.rs`**
179+
- Updated to verify `data-dpi` attribute in output (lines 39-42)
180+
181+
## Testing Commands
182+
183+
```bash
184+
# Run all tests in microtex_rs
185+
cargo test
186+
187+
# Run only DPI-related tests
188+
cargo test --lib add_dpi
189+
190+
# Run the simple formula example with verification
191+
cargo run --example simple_formula
192+
```
193+
194+
## Related Issues
195+
196+
This change addresses the core issue in `genpdfi_extended` where SVG formulas were incorrectly sized due to DPI assumptions. See: `genpdfi_extended/ANALYSIS_PDF_LAYOUT_DEFECT.md`
197+
198+
## Version
199+
200+
- **microtex_rs:** v0.1 (enhanced)
201+
- **Date:** January 11, 2026
202+
- **Status:** ✅ Complete and tested
Lines changed: 17 additions & 0 deletions
Loading

0 commit comments

Comments
 (0)