Work Open source

ExactDoc

Shipped

PDF to editable DOCX, checked by rendering the result back and diffing word positions

Aug 2026 tool

16/16

corpus documents converted, verified by render-back diff

  • 0.9588

    mean live-text retention across the frozen corpus

  • 1.045 pt

    median vertical drift against the source page

  • 11 → 0

    blocking findings over seven live Google Docs passes

  • 663

    tests, over a SHA-256-pinned document corpus

Stack

  • Python
  • PDFium / pypdfium2
  • OOXML
  • LibreOffice headless
  • PyMuPDF
  • pytest

What it is

Most PDF-to-Word converters give you one of two bad outcomes: a pile of text boxes pinned at absolute positions, which looks right and cannot be edited, or reflowed text that has lost the layout. ExactDoc infers the semantic structure — margins, paragraphs, headings, lists, tables, multi-column sections, headers and footers, hyperlinks — and writes real flowing Word constructs whose rendered geometry matches the source to within points.

The interesting part is not the converter. It is the loop that checks it: each DOCX is rendered back to PDF with LibreOffice headless, and word positions are diffed against the original for recall, drift percentiles, SSIM and ink IoU. Every quality claim in the repository is a committed JSON artifact recording the numbers, the environment fingerprint and the commit that produced them.

What I measured

On the frozen 16-document corpus with the shipping profile: 16/16 page match, 0.9588 mean live-text retention, 1.045 pt median vertical drift. The unrefined profile matches 15/16, which is what the refinement loop is worth. Seven live Google Docs qualification passes took blocking findings from 11 to 0. The suite is 663 tests over a SHA-256-pinned corpus, and compiled-in base-14 font widths give identical geometry on Linux and Windows.

Limitations

Long, dense, multi-column documents inflate their page count badly — an 80-page publication becomes 106, a 126-page one becomes 337. Interactive forms and image-only scans are rejected with typed exit codes rather than silently mangled. The page cap is 250. Those classes are documented as plainly as the ones that work.