Pdf Processor
Post-Mortem: Building a PDF Path Reconciler That Actually Works
TLDR
Stress-testing a PDF vector path reconciler specification against real-world documents (JasperReports, LibreOffice Writer exports) exposed three invalid design assumptions before production implementation:shapeId whitelist guards prevented valid table cell borders from merging, De Casteljau subdivision underestimated Bezier bounding boxes, and consecutive dash merging failed on non-adjacent operator streams.
| Proposed Architecture Design | Identified Failure Mode | Production Replacement |
|---|---|---|
shapeId Merge Whitelist | Prevents cell border merging across 70 path calls | Upstream subpath isolation + Lattice gap guards |
| De Casteljau Subdivision | Underestimates bounds on steep diagonal curves | Analytical quadratic derivative root solver |
| Consecutive Dash Merging | Misses non-adjacent dashes in operator stream | Global partition by color, width, & Y-band |
Technical lessons & retrospective findings
1. Global dash partitioning
Grouping dashed lines strictly by consecutive operator order fails when PDF generators interleave drawing operations:// REFACTORED: Global multi-key partition key includes stroke width precision
export function buildDashPartitionKey(subpathRecord, epsilonPx = 4) {
const colorHex = subpathRecord.strokeColor
.map(c => Math.round(c * 255).toString(16).padStart(2, '0'))
.join('');
const widthBucket = Math.round(subpathRecord.strokeWidth * 2); // 0.5px precision
const segment = subpathRecord.segsViewport[0];
const orientation = Math.abs(segment.ay - segment.by) < epsilonPx ? 'H' : 'V';
const yBand = Math.round(segment.ay / epsilonPx) * epsilonPx;
return ${colorHex}|${widthBucket}|${orientation}|${yBand}; }
Rule of thumb: Stress-test vector extraction assumptions against multi-generator PDF corpora before locking architectural designs.
Read this post in the full Engineering Journal →