Preserving Editability With Fidelity Underlays Deepdive
Preserve PDF Editability With a Fidelity Underlay
TLDR: A reliable PDF figure extractor does not have to choose between a screenshot and editable vectors. Keep one operator-native extraction engine, retain a raster crop as a locked fidelity underlay, mask only the text pixels you can replace confidently, and place editable paths and semantic text above it in one coordinate system.
The false choice
PDF extraction often begins with an uncomfortable choice. Rendering a region to pixels preserves appearance, including effects the extractor does not understand, but destroys editability. Reconstructing the region from paths and text keeps it editable, but every unsupported clip, gradient, transparency group, font program, or unusual blend mode becomes a visible hole.
The useful answer is a composite. Treat the raster as evidence of appearance and the vector scene as evidence of structure. Neither layer has to impersonate the other.
This is especially important for technical diagrams. A figure may contain native paths, embedded images, callout text, arrows, and font subsets in one bounding box. Calling the whole box an image throws away real structure. Calling it all vectors assumes the adapter understands every paint operation. Both claims are too strong.
Start from the operator list
A PDF renderer processes an ordered stream of graphics operations. Extraction should preserve that order before imposing document semantics. The neutral record needs at least the paint type, transform, graphics state, bounds, and source operator index.
displayList.push({
kind: "TEXT_PAINT",
opIndex,
ctm: [...graphicsState.ctm],
textMatrix: [...textState.matrix],
fontRef: textState.fontRef,
fontSize: textState.fontSize,
renderingMode: textState.renderingMode,
fill: graphicsState.fill,
stroke: graphicsState.stroke,
bounds
});
Paths and image paints use the same envelope. That makes z-order explicit and lets later stages ask what was painted inside a region without reinterpreting the whole page.
Semantic text usually comes from a separate text-content API. Link those runs to paint records monotonically, using order, normalized text, and geometry. The link is provenance, not merely a convenience. It says which source paint supports each editable string.
for (const run of semanticRuns) {
const match = findNextCompatiblePaint(run, paints, cursor);
if (!match) continue;
run.sourcePaint = match.opIndex;
match.semanticRun = run.id;
cursor = match.listIndex + 1;
}
Monotonic matching matters. Nearest-neighbor geometry alone can cross columns or associate repeated labels with the wrong paint. Preserving source order constrains the search without pretending that order alone defines reading order.
Build one shared coordinate stack
The extracted figure should be one positioning container with sibling layers:
<div class="figure-stack">
<img class="fidelity-underlay" alt="">
<svg class="editable-geometry"></svg>
<svg class="semantic-text"></svg>
</div>
All three layers must use the same crop bounds and scale. Nesting one independently sized overlay inside another is a common source of drift. Margins, intrinsic image dimensions, and SVG view boxes can each shift the text away from the pixels it is meant to replace.
The underlay is rendered at a higher scale, such as four device-independent pixels per source unit, then displayed at the crop's logical size. This gives base64 export enough detail without changing the coordinate system used by editable objects.
Remove only replaceable text pixels
If the PDF renderer cannot resolve an embedded font, the underlay may contain replacement squares. Simply drawing correct text over those pixels leaves both versions visible. Intercepting all text painting is risky because some glyphs are outlines, masks, or integral artwork.
Instead, white out only text items that have a confident semantic replacement. Reuse the exact box calculation used by the product's editable-text mode so visual editing and figure extraction agree.
for (const item of claimedText) {
const box = mapTextItemToCrop(item, crop, scale);
const pad = item.fontSize scale 0.28;
ctx.fillStyle = "#fff";
ctx.fillRect(
box.x - pad,
box.y - pad,
box.width + pad * 2,
box.height + pad * 2
);
}
Then render semantic text as real SVG text, carrying the source transform rather than rebuilding it from a few scalar guesses. Rotation, skew, and vertical writing all live in the matrix.
White is a policy, not a universal truth. It works for white callout panels, but non-white backgrounds require background sampling, clipping, or a paint-aware mask. Mark that limitation in the artifact rather than silently claiming perfect fidelity.
Keep the receiver contract explicit
An extractor can produce a technically impressive scene and still break the application consuming it. A schema editor may deliberately expect two outputs: a locked image for complete appearance and editable objects for known structure. Removing the image when vectors are present changes that contract and makes unsupported visual details disappear.
Model the output directly:
const figureArtifact = {
raster: fidelityDataUrl,
scene: {
paths: editablePaths,
text: semanticText
},
provenance: {
page,
crop,
sourceOperators
}
};
The receiver can lock raster, expose scene, and preserve provenance for later verification. If a consumer wants a pure vector export, it may choose one. The extractor should not erase evidence to force that choice.
Validate layers, not just screenshots
Visual inspection is necessary but insufficient. A browser test should assert the structural contract: one raster underlay, one geometry SVG, semantic text nodes, shared dimensions, and absence of known replacement glyphs. Unit tests should separately cover state capture, operator ordering, text-to-paint links, and region clipping.
A useful corpus includes rotated text, Type3 fonts, transparency groups, gradients, clipping paths, non-white labels, and multicolumn pages. Each fixture should identify which layer is expected to carry each visual fact.
The general principle
Document intelligence improves when appearance, structure, and meaning are separate claims joined by provenance. The raster says what the source looked like. The operator scene says what the file instructed a renderer to paint. Semantic text says what the content appears to mean. A hybrid figure keeps all three available, so fidelity does not require giving up editability and editability does not require inventing unsupported certainty.
This separation also makes future improvement incremental. Adding support for a new clipping rule can promote one detail from the underlay into the editable scene without changing the artifact shape. A better text verifier can update confidence and provenance without rerendering paths. Exporters can choose flattened, editable, or hybrid output according to their destination. The architecture grows by strengthening individual claims, not by repeatedly replacing the entire representation whenever a difficult page appears.