## What this changes
**File ▸ Open opens Word, Excel, PowerPoint, OpenDocument and RTF files** as new, unsaved PDFs (`Report.docx` → `Report.pdf`), the "LibreOffice sidecar" that `docs/gaps.md` (gap 8) and `docs/file-format-parity.md` planned for `create.from-office`.
- **Conversion** (`crates/create/src/office.rs`): an installed LibreOffice runs headless as a separate process, in a private temporary folder (the input is always `document.<ext>`, so the user's file name never reaches its command line). It gets a fresh profile with `DisableMacrosExecution`, `MacroSecurityLevel` 3 and `BlockUntrustedRefererLinks` set, and Writer's and Calc's `Content/Update/Link` set to *Never* (2 for Writer and 1 for Calc: the two number their values differently), no console window on Windows (`CREATE_NO_WINDOW`), and is killed after 120 s. The output is size-capped (512 MB), must start `%PDF-`, and must open as a PDF before it is used. LibreOffice is found through `PDFCRAFT_SOFFICE`, the `PATH`, then the usual install folders per OS. Without it, the user is told it's needed rather than "not a readable PDF".
- **Off the frame thread:** File ▸ Open converts on the existing open worker (`ResultKind::Converted`); the frame thread only opens the result.
- **Detection:** `SourceKind::Office` requires an Office extension *and* an OLE, ZIP or RTF signature, so `photos.zip`, or a PDF saved with a `.docx` name, are not misread.
- **Open dialog:** PDF (still the default), Images, Office documents, Text, All files. All files is left out on macOS, where rfd merges every filter into one allowed-types list, and on the web; Office documents are left out on the web. The extension lists are now shared constants in `pdfcraft-create` (`IMAGE_EXTENSIONS`, `TEXT_EXTENSIONS`, `OFFICE_EXTENSIONS`), used by both detection and the picker. The duplicate filter list in `open_dialog` is gone. The two new labels are in all 22 catalogues, with their `ATTRIBUTION.toml` hashes updated.
- **Automation:** `doc_create_multiple`, `doc_combine` and batch `convert` go through `convert_to_pdf`, so they take Office documents too; their descriptions say so.
**Deliberately not in this PR:** Insert pages, Combine files and Create ▸ Multiple files convert on the frame thread, so they now refuse Office documents with a pointer to File ▸ Open (`convert_to_pdf_inline` / `as_pdf_inline`) rather than freezing the window for seconds. Moving them onto a worker is the follow-up. `create.from-office` goes planned → **partial**, with that and the rest listed in its notes.
## How you verified it
On Windows 11 Pro with LibreOffice 26.8.1 installed, per crate:
- [x] `cargo fmt --check`
- [x] `cargo clippy -p pdfcraft-create -p pdfcraft-engine -p pdfcraft-ui-egui -p pdfcraft-automation -j 2 --all-targets -- -D warnings`
- [x] `cargo test -p pdfcraft-create -p pdfcraft-engine --lib` (42 and 276 pass); `-p pdfcraft-automation --test automation` (the combine/create tests); `-p pdfcraft-ui-egui --lib open_worker` and `--test editing --test create`
- [x] `cargo xtask layers`, `cargo xtask assets`, `cargo xtask parity --partial`
- [ ] wasm check: the `wasm32-unknown-unknown` target isn't installed here, so I'm leaving it to CI. The web paths are `cfg`'d and were reviewed by eye.
**Tests seen failing before the fix**, by reverting each part:
- Detection off → `office_documents_are_their_own_kind`, `source_kind_tells_pdfs_images_and_text_apart`, and both engine Office tests fail.
- Worker conversion off → `file_open_converts_an_office_document_on_the_worker` fails with the old user-facing message, *"the file is not a readable PDF: no readable page tree or cross-reference data was found"*.
New tests also cover a converter that hangs (it's stopped; the test binary stands in for LibreOffice), one that writes no PDF, a missing converter, temp-folder cleanup, `file://` URL escaping (spaces, drive letters, UTF-8), and the search order.
**Real conversions, end to end:** `crates/automation/tests/it/office.rs` builds a minimal DOCX, an XLSX (with a formula, `=6*7`), a PPTX and an RTF inside the test, so no binary fixtures are committed. It runs them through `doc_create_multiple` in `separate` mode (each output reopened and its text checked, including `42`) and in `combine` mode (page order and bookmarks), and through `doc_combine` beside a PDF, with a page range on one file. These tests, `libreoffice_converts_a_document_when_installed` and the process-tree cleanup test (5 out of 5 reruns) pass with LibreOffice 26.8.1. The Office tests skip where LibreOffice isn't installed, which includes CI.
Three existing tests used a 4-byte `report.docx` as their "file that can't be converted" example. That's no longer true, so they now use `archive.zip`, which keeps what they test.
## Never-crash
- [x] No new `unwrap`/`expect`/`panic!`/`unreachable!`/`todo!` outside tests
- [x] No input-derived indexing or slicing (`rsplit_once` for the extension); the PDF read back is size-capped
- [x] No `unsafe`. The Windows flag uses `std::os::windows::process::CommandExt`
- [x] A crashing, hanging or misbehaving LibreOffice is an error, never a panic or a stuck app: the worker's `catch_unwind`, a 120 s kill, and output checks
## Provenance
- [x] No Adobe assets; no fonts; no copied code
- [x] LibreOffice (MPL-2.0) is only *run* as an external process, as the docs planned; nothing of it is linked or copied. Its command-line options and the profile keys come from LibreOffice's public documentation.
- [x] The translations are contributor-original, written from the plain meaning of "Office documents" and "All files" ("Office" kept as a product name); hashes updated, `cargo xtask assets` passes
## Security
- [x] `--root` confinement unchanged: automation still resolves and reads paths before converting; only the private temp folder is written outside it
- [x] MCP and the control channel untouched
- [ ] **No new outbound network: please decide.** PdfCraft itself opens no connection. The profile blocks untrusted referer links and sets Writer and Calc never to update linked content on load. I converted eight synthetic files that link to a listener on 127.0.0.1: RTF `INCLUDETEXT` and `INCLUDEPICTURE`, a DOCX external picture, an ODT linked section and linked picture, an ODS table source and an external cell reference, and an ODP linked picture. None made a connection, with or without the link settings. Two things remain open: Impress has no link-update setting, and the process's network access isn't sandboxed (documented in `crates/create/README.md` and `docs/gaps.md`).
## Parity and reach
- [x] `create.from-office` planned → partial, with the evidence tests and what's still missing
- [x] Reachable headlessly (`doc_create_multiple`, `doc_combine`, batch `convert`)
- [x] Docs: `docs/file-format-parity.md` (Word/Excel/PowerPoint and RTF rows), `docs/gaps.md` gap 8, `docs/target-app-parity.md` row J (numbers not re-measured), `docs/roadmap.md` M10, the `ROADMAP.md` log, and the `crates/create` README
## Anything a reviewer should look at first
1. **The network question** above. It's the owner's call.
2. **The frame-thread restraint:** Insert, Combine and Create Multiple refuse Office documents rather than block. Is a worker for those wanted in this PR, or as a follow-up?
10 KiB
File format parity
Last reviewed: 2026-10-12 · Last updated: 2026-10-22 · Change: minor (Word, Excel, PowerPoint, OpenDocument and RTF open through an installed LibreOffice;
.p7b/.p7cbundles read for trust import) · Target: Adobe Acrobat Pro (Acrobat DC, continuous track 26.002.21931, macOS)
Every format Acrobat Pro reads or writes, and PdfCraft's support for it. Acrobat's list comes from
its bundle's Info.plist CFBundleDocumentTypes (what it opens) and its public documentation
(Create PDF and Export PDF). PdfCraft's support comes from the code and
parity/acrobat-features.toml. Summary in target-app-parity.md; gaps
in gaps.md.
Legend: R read/import, W write/export. Fidelity: high (tested against an external oracle or round-trips exactly), good (tested, known limits), basic (works, visibly lossy), none.
File formats and conversion ≈ 40% ready (estimated): PDF itself is strong except encrypted output interoperability; the conversion formats users reach for most (Word, Excel, PowerPoint, Office to PDF, OCR beyond English) are weak or missing. 120–220 h to parity (within the features total).
| Format | Acrobat | PdfCraft | Fidelity | Tests and evidence |
|---|---|---|---|---|
| PDF 1.0–1.7, ISO 32000-1 | R W | R W | high for reading and unencrypted writing | 958-file pdf.js corpus open/edit/save; qpdf --check on saved outputs; xtask check baselines |
| PDF 2.0 (ISO 32000-2) | R W | R W (2.0-only features ignored but preserved) | good | No UTF-8 strings, /AF, DPart, namespaces (pdf-spec-parity.md) |
| Encrypted PDF (standard security R2–R6) | R W | R W | reading high; writing opens in Acrobat DC since #836 (#774; AES-256 and RC4-128 checked by hand, no automated interop suite) | crates/crypt, crates/cos tests (the_catalog_of_an_encrypted_document_stays_outside_object_streams); all 7 corpus encrypted files open |
| Certificate-encrypted PDF (public-key handler) | R W | none (clear message) | none | core.unsupported-handlers |
| Linearized PDF (Fast Web View) | R W | R (as normal PDF); no W | none for W | core.linearization planned |
| Damaged PDF | R (repair) | R (repair, logged) | high | core.repair-broken-files, nightly fuzzing |
| PDF/A-1, 2, 3, 4 | R W, verify | R; verify/convert 2b and 3b (partial) | basic | optimize.pdfa-*; veraPDF not yet used as oracle |
| PDF/X, PDF/UA, PDF/E, PDF/VT | R W, verify | R only | none | pdf-spec-parity.md |
| PDF Portfolio (collection) | R W | R as a PDF with attachments; no portfolio view | none | organize.portfolio-* planned |
| XFA forms (in PDF) | R W (fill) | R, lay out dynamic forms, fill, save datasets (partial) | basic | form.xfa-* partial; crates/xfa tests |
Data and interchange formats
| Format | Acrobat | PdfCraft | Fidelity | Tests and evidence |
|---|---|---|---|---|
FDF (.fdf) comments and form data |
R W | R W | good | crates/xfdf; comment-exchange fixes for popups, polygon vertices and callouts (#807, #809, #819) |
XFDF (.xfdf, ISO 19444-1) |
R W | R W | good | as above |
| XML form data | R W | R W | good | form.data-xml-csv-txt |
XDP data (.xdp) for XFA forms |
R W | R W: Export Data writes the whole datasets as an XDP; Import Data takes an XDP, datasets or data XML | good | form.xfa-data (data_exports_as_datasets_xml_or_an_xdp_and_imports_from_any_of_them, xfa_data_files_export_and_import_through_tools) |
| XDP opened as a document | R | none | none | Acrobat opens .xdp as a document type |
| CSV / tab-delimited form data | W (merge to spreadsheet) | R W; merge to spreadsheet | good | form.merge-to-spreadsheet |
| Comment summary (PDF) | W | W (comments only layout) | basic | comment.summarize partial |
| Measurement CSV | W | W | good | comment.measure-export |
| Compare report (PDF) | W | W | good | misc.compare-report |
Action Wizard sequences (.sequ) |
R W | own JSON actions; no .sequ |
none for .sequ |
misc.action-wizard-* |
Security settings (.acrobatsecuritysettings), .apf profiles, .secstore |
R W | none | none | out of scope unless asked |
Search index (.pdx) |
R W | none | none | view.search-index planned |
| JDF / MJD job definitions | R | none | none | print.jdf planned (P3) |
Preflight profiles (.kfp) and reports |
R W | none | none | gap 9 |
PDF Optimizer settings (.optimize) |
R W | none (dialog settings not saved as presets) | none | optimize.optimizer-presets planned |
Certificates and keys
| Format | Acrobat | PdfCraft | Fidelity | Tests and evidence |
|---|---|---|---|---|
PKCS #12 digital IDs (.p12, .pfx) |
R W | R W (self-signed IDs) | high | OpenSSL-made fixtures (crates/sign/tests/data/README.md) |
Certificates (.cer, .der, .pem, .p7c, .p7b) |
R W | R (.cer/.pem/.der/.p7b/.p7c/.p12 trust import); W public certificate |
good; .p7c/.p7b bundles read (DER or PEM), not written |
sign.trust-import partial, sign.export-certificate |
| CMS / PKCS #7 signatures, RFC 3161 tokens, OCSP, CRL | R W | R W | high | pdfsig and OpenSSL oracles |
Create PDF from
| Source | Acrobat | PdfCraft | Fidelity | Tests and evidence |
|---|---|---|---|---|
| JPEG, PNG, TIFF (multipage, and BigTIFF), GIF, BMP, JPEG 2000 | yes | yes (ICC profiles kept; DPI choices) | good | create.from-images, create.from-multipage-tiff, bigtiff_images_become_pages |
| PCX | yes | no | none | in Acrobat's document types |
| Plain text | yes | yes | good | create.from-text |
| Clipboard (image or text) | yes | yes | good | create.from-clipboard |
| Screenshot | yes | no | none | create.from-screenshot planned |
| Word, Excel, PowerPoint (and Visio, Publisher on Windows) | yes | yes, desktop only, through an installed LibreOffice (File ▸ Open); not Visio or Publisher | good where LibreOffice is (its layout, not measured against Acrobat) | create.from-office partial |
| HTML file, web page URL | yes | no | none | create.from-html, create.from-web-page planned |
| RTF | yes | yes, through LibreOffice (as Office documents) | good where LibreOffice is | create.from-office partial |
| PostScript / EPS (Distiller) | yes | no | none | create.distiller planned (P3) |
| Markdown | no | no | none | create.from-markdown planned (P2; not an Acrobat feature) |
| Scanner | yes | no | none | ocr.scanner-acquire planned |
| Several files at once | yes | yes: combine PDFs, images and text into one document, or create a separate PDF for each non-PDF source (GUI and doc_create_multiple mode=separate); existing outputs get numbered names |
good for supported source types | create.create-multiple, separate_batch_creates_one_pdf_per_source_without_replacing_existing_files |
Export PDF to
| Target | Acrobat | PdfCraft | Fidelity | Tests and evidence |
|---|---|---|---|---|
Word (.docx) |
yes, layout-preserving | flowing paragraphs and inferred tables (bordered only along the grid lines the page draws); positioned text/artwork only for pages with rotated text or text overlapping an image/watermark, with per-page sizes | basic (#773 synthetic invoice regression covered; exact fonts, vector rules and general layout fidelity remain incomplete) | create.export-docx partial |
Word 97–2003 (.doc) |
yes | no | none | |
Excel (.xlsx), XML Spreadsheet 2003 |
yes | no | none | create.export-xlsx planned |
PowerPoint (.pptx) |
yes | slides per page: title from largest text, body text, images, tables (no slide overflow reflow / normAutofit; first page sets presentation dimensions) | basic | create.export-pptx partial |
| RTF | yes | yes | basic | create.export-rtf |
| HTML (single page, multiple pages) | yes | single file with headings, paragraphs, images, tables | basic | create.export-html partial |
| Plain text | yes | yes (reading order) | good (word-F1 0.98 vs pdftotext; reading order is scored separately, because F1 cannot see it) |
create.export-text, xtask text-oracle |
| Accessible text (from tags) | yes | no | none | create.export-accessible-text planned |
| PNG, JPEG, TIFF | yes | yes | good | create.export-png, create.export-jpeg-tiff |
| JPEG 2000 | yes | no | none | create.export-jpeg2000 planned |
| All embedded images | yes | yes | good | create.export-all-images |
| XML 1.0 | yes | no | none | create.export-xml planned |
| SVG | no (dropped by Adobe) | no | none | create.export-svg planned |
| PostScript, EPS | yes | no | none | create.export-ps, create.export-eps planned |
OCR (scans to searchable PDF)
| Capability | Acrobat | PdfCraft | Fidelity |
|---|---|---|---|
| Searchable image (invisible text layer) | yes | yes (Tr 3 text fitted to word boxes) | good for English |
| Editable text and images output | yes | no | none |
| Languages | dozens (Latin with accents, Cyrillic, Greek, CJK, Arabic, Hebrew, Indic) | Latin without accents only (ocrs models) | basic (#744) |
| Deskew, rotation, despeckle, background and halo removal, descreen | yes | no | none |
| Camera images (edges, perspective, whiteboard, card) | yes | no | none |
| MRC (adaptive) compression, PDF/A output of scans | yes | no | none |
Revision history
| Date | Change | Summary |
|---|---|---|
| 2026-10-22 | minor | Office documents (Word, Excel, PowerPoint, OpenDocument, RTF) open from File ▸ Open as new PDFs, converted by an installed LibreOffice; create.from-office partial. |
| 2026-10-19 | patch | Certificates row: .p7b/.p7c bundles (DER or PEM PKCS7/CMS) are read for trust import. |
| 2026-10-12 | minor | XDP split into data (read and write for XFA forms, already shipped under form.xfa-data) and opening .xdp as a document (none). Create PDF reads BigTIFF; malformed GIF headers are no longer detected as images. |
| 2026-10-11 | minor | #773: inferred tables have no invented borders; rotated or overlapping invoice pages use floating shapes and page sections. Full Office layout fidelity remains partial. |
| 2026-10-11 | minor | Encrypted PDF row: written files open in Acrobat DC (#774, fixed by #836). FDF row: #807, #809 and #819 fixed |
| 2026-10-10 | major | Created from Acrobat 26.002.21931's CFBundleDocumentTypes, Acrobat's public Create/Export documentation, and PdfCraft's code and checklist |