Build PDF Expert

YESreplaces $6.67/mosaves $80.04/yrback to the verdict

0%0 of 20 items done

Saved on this device only. Tick prerequisites first, then work the phases in order · do not start one until the checks above it pass.

A desktop application over mature PDF libraries: annotate and highlight, fill and flatten forms, merge, split and reorder pages, redact so the underlying text is genuinely gone, run optical character recognition over scans, and keep every original untouched with an operation log describing what produced each output.

estimated effort multi-daythe files for this build are in the project pack

ShellTauri with a TypeScript front endRenderingpdf.js for displayManipulationqpdf for structural operations and mupdf for contentOptical character recognitionTesseract, run locallyStorageOriginals untouched, outputs written alongside with a JSON operation log

Before step 1

Everything below is assumed from the first step. Tick each one when you actually have it, not when you plan to.

  1. installfree

    Why Builds the front end and the tooling.

    Get it nodejs.org, or nvm install 22. open ↗

    Verify node --version prints v22 or higher

  2. installfree

    Why Tauri compiles the native shell and runs the library calls.

    Get it Install with rustup from rustup.rs, plus the platform packages Tauri lists for your operating system. open ↗

    Verify A Tauri hello world builds and runs

  3. installfree

    Why Structural operations and content extraction. Writing either yourself means implementing parts of the PDF specification.

    Get it brew install qpdf mupdf, or your package manager. Decide early whether you bundle them or require them, because it affects distribution. open ↗

    Verify qpdf --version and mutool both run

  4. installfree

    Why Phase 5 only. Without it, scans stay unsearchable and everything else still works.

    Get it brew install tesseract, or your package manager, plus the language data for the languages you need. open ↗

    Verify tesseract --list-langs includes your language

  5. have readyfree

    Why Every phase is tested against them: a text document, a scan, an encrypted file, a form and a corrupted file. Testing against one clean PDF proves nothing.

    Get it Collect them from documents you already have. Corrupt one deliberately by truncating it. Keep them in a fixtures directory.

    Verify All five are present and each opens or fails with a specific message

Data model

Create these before the first phase that stores anything. Changing a table later is the expensive kind of change.

- documents(id, path, pages, encrypted, has_text_layer, imported_at, content_hash)
- operations(id, document_id, kind, params_json, output_path, at) · kind is annotate, fill, merge, split, redact, ocr or reorder
- annotations(id, document_id, page, kind, rect_json, content, color, created_at)
- form_fields(document_id, page, name, kind, value, flattened) · read from the file's own form definition
- The operation log is what makes an output auditable: every produced file names the input hash and the operations applied.

Environment variables

These go in a .env file the app reads at startup. The pack's .env.example is this table as a file · copy it, never commit the filled-in version.

VariableNeededExampleWhere the value comes from
OUTPUT_DIRrequired~/Documents/PDF OutputsWhere produced files are written. Deliberately never the source directory.
QPDF_PATHoptional/opt/homebrew/bin/qpdfOnly needed if qpdf is not bundled and not on PATH.
TESSERACT_PATHoptional/opt/homebrew/bin/tesseractOnly needed if Tesseract is not bundled. Recognition is disabled when it cannot be found.
OCR_MIN_DPIrequired300Below this, recognition accuracy falls sharply and a warning is shown.
OPERATION_LOG_PATHrequired~/Documents/PDF Outputs/operations.jsonThe audit trail linking every output to its input hash and operations.

The build, in order

  1. Open anything, and know what you opened

    Real PDFs render, including the broken ones, and you can describe what each file actually is.

    1. Render on demand rather than eagerly. A large document must open immediately and fill in as you scroll.

      Files src/render.ts

      terminal
      npm create tauri-app@latest
      npm install pdfjs-dist
    2. Text layer, encryption, forms, page count and structural damage. Each one changes which operations are possible.

      Files src/inspect.ts

    3. A scan, an encrypted file, a form, a very large document and something corrupt. These are your fixtures for every later phase.

      Files fixtures/

    done when · tick each as it passes
    watch out
    • A scanned PDF and a text PDF look identical on screen and behave completely differently: search finds nothing, selection selects nothing, and redaction cannot remove text that is not there. Detect the absence of a text layer at import and say so, rather than letting the user discover it when a redaction quietly does nothing.
  2. Annotation that other readers can see

    Highlights and notes are real PDF annotations, not a private overlay.

    1. Use the specification's annotation types rather than drawing into the page content. This is what makes them portable and editable elsewhere.

      Files src/annotate.ts

    2. Read the original, write a new file, record the operation. Checksum the input before and after as a test.

      Files src/pipeline.ts

    3. Open the output somewhere else. If your annotations are invisible there, they are not annotations.

    done when · tick each as it passes
    watch out
    • Storing annotations in your own sidecar database and drawing them at render time produces a document that is blank for everyone else. Write them into the PDF as annotation objects, then verify by opening the output in a different reader, which is the only test that matters.
  3. Forms

    You can fill a form and produce a version nobody can un-fill.

    1. Field names, types and current values come from the document. Never infer a form from visual layout.

      Files src/forms.ts

    2. Two outputs: filled and editable, or flattened and final. Make the difference explicit in the interface.

      Files src/forms.ts

    3. Inspect the output for remaining field objects with qpdf rather than trusting that it looks right.

      terminal
      qpdf --json out.pdf | grep -c AcroForm
    done when · tick each as it passes
    watch out
    • A filled but unflattened form still carries editable field values, so a recipient can change what you entered and the change is invisible in most viewers. If the document is going to anyone else, flatten it, and make that the prominent option rather than an advanced one.
  4. Pages, merging and redaction that is real

    You can restructure documents, and a redaction actually removes the text.

    1. Merge, split, rotate and reorder. It handles the page tree correctly, which hand-written manipulation does not.

      Files src/pages.ts

      terminal
      qpdf --empty --pages a.pdf b.pdf -- merged.pdf
    2. Delete the text objects in the region from the content stream, then draw the black box. Order matters and only one order is correct.

      Files src/redact.ts

    3. Extract text from the output and assert the redacted string is absent. Make this an automated test, because it is the one that protects people.

      Files test/redact.test.ts

      terminal
      pdftotext redacted.pdf - | grep -c "secret"
    done when · tick each as it passes
    watch out
    • A black rectangle drawn over text leaves the text in the file, selectable and extractable, and this has caused real disclosures in published legal and government documents. Redaction must remove the underlying content and then rasterise or rewrite the region. The test is text extraction on the output, not a visual check.
  5. Optical character recognition for scans

    A scanned document becomes searchable without its appearance changing.

    1. Check effective resolution and correct skew first. This does more for accuracy than any Tesseract setting.

      Files src/ocr.ts

    2. Text positioned over the image in invisible render mode, so appearance is unchanged and selection works.

      terminal
      tesseract page.png out pdf
    3. Per page. A low score is information the user needs before relying on a search result.

      Files src/ocr.ts

    done when · tick each as it passes
    watch out
    • Recognition quality depends heavily on resolution and skew. Below roughly 300 dots per inch, accuracy falls off sharply, and a skewed scan compounds it. Deskew and check the effective resolution before recognising, and report low confidence rather than presenting a bad result as a good one.
what this build does not replace
after v1, if you want it

Need the files? The project pack on the verdict page hands your agent the whole brief · more documents & pdfs.