Skip to content

feat(edit-pdf): add editing for existing PDF text - #111

Open
stidven-wq wants to merge 1 commit into
PDFCraftTool:mainfrom
stidven-wq:feature/edit-existing-pdf-text
Open

feat(edit-pdf): add editing for existing PDF text#111
stidven-wq wants to merge 1 commit into
PDFCraftTool:mainfrom
stidven-wq:feature/edit-existing-pdf-text

Conversation

@stidven-wq

Copy link
Copy Markdown

Summary

Adds in-place editing of existing PDF text to the current PDF.js annotation
interface.

Users can activate Edit text, select an existing text span, preview a
replacement, choose how overflow should be handled, and apply the change
without uploading the document to a server.

Motivation

The existing editor supports annotations and new content, but it does not
modify text already present in the PDF. This change makes common corrections
possible without requiring the original source document or a separate desktop
PDF editor.

What changed

  • Adds an Edit text item to the existing annotation toolbar.
  • Makes PDF.js text-layer spans selectable while edit mode is active.
  • Shows a contextual editor with a live preview.
  • Supports three overflow strategies:
    • preserve the original font size;
    • shrink the replacement to fit;
    • expand the insertion area.
  • Supports multiline replacement through a text box.
  • Preserves the source span's font, size, color, and baseline when possible.
  • Extracts and reuses embedded PDF fonts when PyMuPDF exposes them.
  • Falls back to an appropriate built-in or Unicode font when necessary.
  • Keeps a separate undo/redo history for destructive text replacements.
  • Warns when:
    • the replacement overflows its original area;
    • a fallback font was required;
    • the PDF contains digital signatures that become invalid after editing.
  • Updates English and Spanish tool metadata and help content.

Implementation

Text replacement is performed locally through the existing PyMuPDF WASM
runtime:

  1. Resolve the selected source span using its PDF coordinates and text.
  2. Read its font metadata, point size, color, bounding box, and baseline.
  3. Extract the embedded font where available.
  4. Redact only the selected text span while preserving overlapping images and
    vector graphics.
  5. Insert the replacement using the selected overflow strategy.
  6. Return the edited PDF together with font, overflow, and signature
    diagnostics.

No document content is sent to an external service.

Validation

  • tsc --noEmit
  • vitest run src/__tests__/lib/pdf/replace-existing-text.test.ts src/__tests__/components/tools/EditPDFTool.test.tsx
    • 16 tests passed
  • Production Docker build completed successfully.
  • Manual browser validation:
    • loaded a PDF in the production PDF.js viewer;
    • verified the new toolbar item;
    • verified the independent text history controls;
    • replaced existing text and inspected the rendered result.

The full repository suite currently reports 451/452 passing tests. The remaining
failure is the pre-existing ToolSidebar pointer-drop test and is reproducible
without these changes.

The repository's lint script currently cannot run because ESLint 9 does not
find an eslint.config.js configuration file.

Limitations

  • Exact typography depends on whether the original font is embedded and whether
    its subset contains the new glyphs.
  • PDFs may split visually continuous text into multiple independent spans; the
    current interaction edits the selected span.
  • Scanned/image-only PDFs require OCR before their text can be edited.
  • Editing document content invalidates existing digital signatures.
  • Preserving the original font size can intentionally allow longer text to
    extend beyond the original area; users can choose shrink or expand instead.

Files of interest

  • src/components/tools/edit-pdf/EditPDFTool.tsx
  • src/lib/pdf/processors/replace-existing-text.ts
  • src/lib/pdf/pymupdf-loader.ts
  • src/__tests__/lib/pdf/replace-existing-text.test.ts

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant