documents.js 1.39.0 → 1.40.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![GitHub](https://img.shields.io/badge/GitHub-181717?logo=github&logoColor=white)](https://github.com/ExaDev/documents.js) [![npm](https://img.shields.io/badge/npm-CB3837?logo=npm&logoColor=white)](https://www.npmjs.com/package/documents.js) [![Release](https://img.shields.io/github/v/release/ExaDev/documents.js)](https://github.com/ExaDev/documents.js/releases/latest) [![CI](https://img.shields.io/github/actions/workflow/status/ExaDev/documents.js/ci.yml?branch=main)](https://github.com/ExaDev/documents.js/actions)
4
4
 
5
- > Bidirectional docx/pptx ⇄ PDF conversion, one-directional odt → PDF conversion, a read-and-write live-view editor for docx/pptx content, and a fully hand-written PDF codec, built on [ooxml.js](https://github.com/ExaDev/ooxml.js) and [odf.js](https://github.com/ExaDev/odf.js).
5
+ > Bidirectional docx/pptx ⇄ PDF conversion, one-directional odt/odp → PDF conversion, a read-and-write live-view editor for docx/pptx content, and a fully hand-written PDF codec, built on [ooxml.js](https://github.com/ExaDev/ooxml.js) and [odf.js](https://github.com/ExaDev/odf.js).
6
6
 
7
7
  `documents.js` depends on `ooxml.js` for lossless docx/pptx/xlsx ⇄ JSON handling and extends it in two directions `ooxml.js` deliberately does not cover: full PDF support (parsing arbitrary real-world PDFs and generating new ones), and a read-**and-write** manipulation API for docx/pptx content — `ooxml.js`'s own typed readers (`readDocx`/`readPptx`) are one-way and explicitly forbid write-back. PDF reading, writing, and the docx⇄PDF/pptx⇄PDF conversion pipeline are entirely hand-written: no external PDF library (`pdf-lib`, `pdfjs-dist`, `mupdf`, or any other) is a dependency. The one exception is [`fflate`](https://github.com/101arrowz/fflate) for raw DEFLATE/zlib compression underneath PDF's `FlateDecode` filter and PNG's `IDAT` chunks — the same dependency `ooxml.js` itself already relies on for ZIP handling.
8
8
 
@@ -30,10 +30,10 @@ npm install documents.js
30
30
 
31
31
  ## Usage
32
32
 
33
- The four round-trip ergonomic conversions, plus odt's one-directional addition:
33
+ The six round-trip ergonomic conversions (docx/pptx/odt ⇄ PDF), plus odp's one-directional addition:
34
34
 
35
35
  ```ts
36
- import { docxToPdf, odtToPdf, pdfToDocx, pptxToPdf, pdfToPptx } from 'documents.js';
36
+ import { docxToPdf, odpToPdf, odtToPdf, pdfToDocx, pdfToOdt, pptxToPdf, pdfToPptx } from 'documents.js';
37
37
 
38
38
  const pdfBytes = docxToPdf(docxBytes);
39
39
  const docxBytes2 = pdfToDocx(pdfBytes);
@@ -41,10 +41,13 @@ const docxBytes2 = pdfToDocx(pdfBytes);
41
41
  const pdfFromSlides = pptxToPdf(pptxBytes);
42
42
  const pptxBytes2 = pdfToPptx(pdfFromSlides);
43
43
 
44
- const pdfFromOdt = odtToPdf(odtBytes); // odt -> PDF only -- there is no pdfToOdt yet (no live-view odt editor exists to build one back)
44
+ const pdfFromOdt = odtToPdf(odtBytes);
45
+ const odtBytes2 = pdfToOdt(pdfFromOdt);
46
+
47
+ const pdfFromOdp = odpToPdf(odpBytes); // odp -> PDF only -- there is no pdfToOdp yet (no live-view odp editor exists to build one back)
45
48
  ```
46
49
 
47
- Each accepts an optional `signal` (`AbortSignal`) and either a `onSubstitution` callback (docx/pptx/odt → PDF, called once per character not representable in a standard-14 font) or a `sink` (PDF → docx/pptx, called once per recoverable parse diagnostic).
50
+ Each accepts an optional `signal` (`AbortSignal`) and either a `onSubstitution` callback (docx/pptx/odt/odp → PDF, called once per character not representable in a standard-14 font) or a `sink` (PDF → docx/pptx/odt, called once per recoverable parse diagnostic).
48
51
 
49
52
  The same conversions behind a swappable port, for a caller that wants to inject a different implementation later without changing call sites:
50
53
 
@@ -86,7 +89,7 @@ const layout = readPdf(pdfBytes); // -> LayoutDocument: pages of positioned text
86
89
  const bytes = writePdf(layout);
87
90
  ```
88
91
 
89
- The same three round trips (PDF ⇄ `LayoutDocument`, docx ⇄ PDF, pptx ⇄ PDF) are each also available as a schema-validated [`z.codec()`](https://zod.dev) pair, mirroring `ooxml.js`'s own `packageCodec` — `z.decode`/`z.encode` validate both the raw bytes (against the magic-byte schemas below) and the parsed value (against `LayoutDocumentSchema`) on every call, catching a malformed value that a bare function call wouldn't. This is the no-extra-options form: `readPdf`/`writePdf`/`docxToPdf`/etc. remain the entry points for cancellation (`signal`), diagnostics (`sink`), or substitution reporting (`onSubstitution`), none of which fit `z.codec()`'s fixed `decode(input)`/`encode(output)` signature.
92
+ The same four round trips (PDF ⇄ `LayoutDocument`, docx ⇄ PDF, pptx ⇄ PDF, odt ⇄ PDF) are each also available as a schema-validated [`z.codec()`](https://zod.dev) pair, mirroring `ooxml.js`'s own `packageCodec` — `z.decode`/`z.encode` validate both the raw bytes (against the magic-byte schemas below) and the parsed value (against `LayoutDocumentSchema`) on every call, catching a malformed value that a bare function call wouldn't. This is the no-extra-options form: `readPdf`/`writePdf`/`docxToPdf`/etc. remain the entry points for cancellation (`signal`), diagnostics (`sink`), or substitution reporting (`onSubstitution`), none of which fit `z.codec()`'s fixed `decode(input)`/`encode(output)` signature. There is no `odpPdfCodec`: a `z.codec()` pair needs a genuine decode+encode round trip, and odp has no `pdfToOdp` to encode with yet.
90
93
 
91
94
  ```ts
92
95
  import { z } from 'zod';
@@ -99,7 +102,7 @@ const pdfFromDocx = z.decode(docxPdfCodec, docxBytes);
99
102
  const docxBack = z.encode(docxPdfCodec, pdfFromDocx);
100
103
  ```
101
104
 
102
- `readDocxContent`/`readPptxContent`/`readOdtContent` (docx/pptx/odt → `ContentDocument`), `convertWordprocessingToLayout`/`convertPresentationToLayout` (`ContentDocument` → `LayoutDocument`), and `reconstructWordprocessing`/`reconstructPresentation` (`LayoutDocument` → `ContentDocument`) are each exported individually too, for a caller that wants one stage of the pipeline without the rest. `readDocxContent` and `readOdtContent` both produce the identical `wordprocessing`-variant `ContentDocument` shape from two completely unrelated package formats (OOXML and ODF), which is what lets `odtToPdf` feed `convertWordprocessingToLayout` without a single line of that engine changing.
105
+ `readDocxContent`/`readPptxContent`/`readOdtContent`/`readOdpContent` (docx/pptx/odt/odp → `ContentDocument`), `convertWordprocessingToLayout`/`convertPresentationToLayout` (`ContentDocument` → `LayoutDocument`), and `reconstructWordprocessing`/`reconstructPresentation` (`LayoutDocument` → `ContentDocument`) are each exported individually too, for a caller that wants one stage of the pipeline without the rest. `readDocxContent` and `readOdtContent` both produce the identical `wordprocessing`-variant `ContentDocument` shape from two completely unrelated package formats (OOXML and ODF), which is what lets `odtToPdf` feed `convertWordprocessingToLayout` without a single line of that engine changing; `readPptxContent` and `readOdpContent` do the same for the `presentation` variant and `convertPresentationToLayout`.
103
106
 
104
107
  ## Architecture
105
108
 
@@ -114,9 +117,9 @@ The package is layered from generic primitives outward to the two conversion dir
114
117
  - **Read**: `lexer.ts`/`parse.ts` (byte tokenizer and tokens → `PdfObject`), `filters.ts`/`predictors.ts` (Flate/LZW/ASCII85/ASCIIHex/RunLength, TIFF/PNG predictors), `xref.ts`/`document.ts` (classic and cross-reference-stream resolution, object streams, `/Prev` chains, linear-scan recovery, the page tree with attribute inheritance), `content-read.ts`/`interpret.ts` (the content-stream tokenizer and graphics/text state machine, including form-XObject recursion), `cmap.ts`/`font-style.ts`/`font-read.ts` (`/ToUnicode` CMaps, font-dictionary resolution), `images-read.ts` (Image XObjects → PNG/JPEG bytes), `read.ts` (`readPdf`, assembling all of the above into a `LayoutDocument`).
115
118
  - `codec.ts` — `pdfCodec`, a `z.codec()` pair over `readPdf`/`writePdf` (PDF bytes ⇄ `LayoutDocument`).
116
119
  - **`src/ooxml/`** — resolves a `Package` into a `ContentDocument`: `docx/read.ts` and `pptx/read.ts` are now thin adapters over `ooxml.js`'s own `readDocx`/`readPptx`, wrapping their `{ metadata, sections }`/`{ metadata, slides }` result into `ContentDocument`'s `wordprocessing`/`presentation` shape. The docx style cascade (`docDefaults` → named-style `basedOn` chains → paragraph-mark run properties → character styles → direct formatting), the pptx placeholder → layout → master → theme inheritance cascade, and DrawingML geometry/colour resolution all now live upstream in `ooxml.js` itself, not in this package.
117
- - **`src/odf/`** — the ODF-side counterpart to `src/ooxml/`, resolving an `odf.js` `Package` into a `ContentDocument`: `odt/read.ts`'s `readOdtContent` is a thin adapter over `odf.js`'s own `readOdt`, wrapping its `{ metadata, sections }` result into the identical `wordprocessing` shape `readDocxContent` produces — the concrete proof that odt and docx genuinely share one pivot and one layout engine. There is no `src/odf/odt/content.ts` (`buildOdtPackage`) yet: odt has no live-view editor, so the PDF → odt direction doesn't exist.
118
- - **`src/layout/`** — the pure conversion algorithms, importing only `model` (no I/O): `engine.ts` (`ContentDocument` wordprocessing → `LayoutDocument`: flow, line-breaking, pagination — fed identically by docx- and odt-sourced content), `slides.ts` (`ContentDocument` presentation → `LayoutDocument`: direct EMU-to-point placement, no pagination needed), `reconstruct.ts` (`LayoutDocument` → `ContentDocument`, both variants: baseline-proximity line clustering, then paragraph/text-block clustering from geometry — PDF has no semantic paragraph or shape structure to recover, only positioned glyphs).
119
- - **`src/convert/`** — `convert.ts` (the four round-trip ergonomic wrappers plus `odtToPdf`'s one-directional addition), `codec.ts` (`docxPdfCodec`/`pptxPdfCodec`, a `z.codec()` pair over each — there is no `odtPdfCodec`, since a `z.codec()` pair needs both directions), `port.ts`/`local.ts` (the swappable `DocumentConverter` contract and its synchronous local implementation, covering `docx`/`pptx`/`odt` → `pdf` and `pdf` → `docx`/`pptx`).
120
+ - **`src/odf/`** — the ODF-side counterpart to `src/ooxml/`, resolving an `odf.js` `Package` into a `ContentDocument`: `odt/read.ts`'s `readOdtContent` is a thin adapter over `odf.js`'s own `readOdt`, wrapping its `{ metadata, sections }` result into the identical `wordprocessing` shape `readDocxContent` produces — the concrete proof that odt and docx genuinely share one pivot and one layout engine. `odp/read.ts`'s `readOdpContent` is the same adapter over `odf.js`'s `readOdp`, wrapping `{ metadata, slides }` into the identical `presentation` shape `readPptxContent` produces. odt's live-view editor now builds the reverse direction too (`buildOdtPackage`, `src/edit/odt/content.ts`); there is no `src/odf/odp/content.ts` (`buildOdpPackage`) yet, since odp has no live-view editor, so the PDF → odp direction doesn't exist.
121
+ - **`src/layout/`** — the pure conversion algorithms, importing only `model` (no I/O): `engine.ts` (`ContentDocument` wordprocessing → `LayoutDocument`: flow, line-breaking, pagination — fed identically by docx- and odt-sourced content), `slides.ts` (`ContentDocument` presentation → `LayoutDocument`: direct EMU-to-point placement, no pagination needed — fed identically by pptx- and odp-sourced content), `reconstruct.ts` (`LayoutDocument` → `ContentDocument`, both variants: baseline-proximity line clustering, then paragraph/text-block clustering from geometry — PDF has no semantic paragraph or shape structure to recover, only positioned glyphs).
122
+ - **`src/convert/`** — `convert.ts` (the four round-trip ergonomic wrappers plus `odtToPdf`'s and `odpToPdf`'s one-directional additions), `codec.ts` (`docxPdfCodec`/`pptxPdfCodec`/`odtPdfCodec`, a `z.codec()` pair over each — there is no `odpPdfCodec`, since a `z.codec()` pair needs both directions and odp has no reverse), `port.ts`/`local.ts` (the swappable `DocumentConverter` contract and its synchronous local implementation, covering `docx`/`pptx`/`odt`/`odp` → `pdf` and `pdf` → `docx`/`pptx`/`odt`).
120
123
 
121
124
  Dependency direction is strictly downward and checkable: `model`/`bytes` import nothing local; `image` imports `bytes` only; `pdf` imports `model`+`bytes`+`image` only; `ooxml/*` imports `xml`/`model` only (no PDF knowledge); `odf/*` imports `model` only (no PDF knowledge, no `xml/*` — `odf.js` already owns its own XML query helpers); `layout` imports `model` only; `convert` composes everything else. No `PdfObject`/`PdfDict`/`PdfStream` type appears outside `src/pdf/`.
122
125
 
@@ -128,7 +131,7 @@ pnpm typecheck # tsc --noEmit
128
131
  pnpm lint # eslint . --max-warnings 0
129
132
  pnpm test # vitest run --project unit
130
133
  pnpm test:watch # vitest --project unit
131
- pnpm test:smoke # rebuilds dist/, then verifies ESM/CJS parity, a real docxToPdf/pdfToDocx round trip, and a real odtToPdf conversion, from the built CJS bundle
134
+ pnpm test:smoke # rebuilds dist/, then verifies ESM/CJS parity, a real docxToPdf/pdfToDocx round trip, and real odtToPdf/odpToPdf conversions, from the built CJS bundle
132
135
  pnpm test:corpus # optional real-world PDF conformance checks against a local, gitignored test/corpus/ (see Fidelity)
133
136
  ```
134
137
 
@@ -137,7 +140,7 @@ To run a single test file: `pnpm vitest run src/path/to/file.test.ts`.
137
140
  ## Conventions
138
141
 
139
142
  - **Zod-first schema/type/guard**, matching `ooxml.js`: every model type is inferred from its Zod schema, never hand-written. `ContentBlock` (recursive, mirroring `ooxml.js`'s own `XmlNode` treatment) uses a hand-written structural guard + `z.custom`, not `z.lazy`, which collapses to `unknown` for recursive element-children in the pinned Zod version.
140
- - **`z.codec()` for every schema-to-schema round trip**, matching `ooxml.js`'s `packageCodec`/`xmlCodec`: `pdfCodec` (PDF bytes ⇄ `LayoutDocument`) and `docxPdfCodec`/`pptxPdfCodec` (docx/pptx bytes ⇄ PDF bytes) each wrap an already-independently-tested function pair, adding automatic two-way schema validation. These are deliberately the no-options form — `readPdf`/`writePdf`/`docxToPdf`/`pdfToDocx`/`pptxToPdf`/`pdfToPptx` remain the primary entry points wherever a caller needs an `AbortSignal`, a `PdfDiagnosticSink`, or an `onSubstitution` callback, since `z.codec()`'s fixed `decode(input)`/`encode(output)` signature has no room for side-channel options.
143
+ - **`z.codec()` for every schema-to-schema round trip**, matching `ooxml.js`'s `packageCodec`/`xmlCodec`: `pdfCodec` (PDF bytes ⇄ `LayoutDocument`) and `docxPdfCodec`/`pptxPdfCodec`/`odtPdfCodec` (docx/pptx/odt bytes ⇄ PDF bytes) each wrap an already-independently-tested function pair, adding automatic two-way schema validation. These are deliberately the no-options form — `readPdf`/`writePdf`/`docxToPdf`/`pdfToDocx`/`pptxToPdf`/`pdfToPptx`/`odtToPdf`/`pdfToOdt` remain the primary entry points wherever a caller needs an `AbortSignal`, a `PdfDiagnosticSink`, or an `onSubstitution` callback, since `z.codec()`'s fixed `decode(input)`/`encode(output)` signature has no room for side-channel options. `odpToPdf` has no codec counterpart yet, for the same no-reverse-direction reason odt didn't until `pdfToOdt` existed.
141
144
  - **`PdfObject` has no Zod schema at all**, deliberately: it never crosses a public boundary or round-trips through JSON, and is constructed exclusively by this package's own parser — validating it would just be validating our own output. It narrows natively on its own `kind` discriminant instead, the same reasoning `ooxml.js` applies when it picks a hand-written `isXmlNode` guard over `z.lazy`.
142
145
  - **No type assertions anywhere.** Every third-party or loosely-typed value is narrowed through a type guard or a Zod parse at the boundary.
143
146
  - **Live views, not flatten-and-regenerate.** `src/edit/*`'s editor classes hold a reference directly into the real `Package`/`XmlElement` objects; saving is `encodePackage(pkg)`, nothing more. This is what makes "everything you didn't touch stays byte-faithful" a structural guarantee rather than a best effort.
@@ -148,7 +151,7 @@ To run a single test file: `pnpm vitest run src/path/to/file.test.ts`.
148
151
 
149
152
  - **`ooxml.js`'s typed readers (`readDocx`/`readPptx`) are now the actual basis for conversion** — `readDocxContent`/`readPptxContent` are thin wrappers around them, not an independent walk of `word/document.xml`/`ppt/slides/slideN.xml`. They are still deliberately not re-exported from this package's own public surface: `readDocx`/`readPptx` also carry `comments`/`footnotes`/`headers`/`footers` (docx) that `ContentDocument` doesn't model, so exposing both the wrapper and the thing it wraps would invite a caller to reach for the wrong one rather than genuinely offering two competing models.
150
153
  - **The docx⇄PDF and pptx⇄PDF conversions are explicitly not round-trip-lossless** — in deliberate contrast to `ooxml.js`'s own `packageCodec`, which is byte/part-faithful by design. See [Fidelity](#fidelity).
151
- - **`odtToPdf` is one-directional — there is no `pdfToOdt`.** The PDF → docx/pptx direction needs a live-view editor to build the output package (`buildDocxPackage`/`buildPptxPackage`); odt has no live-view editor in this package yet (no `openOdt`/`createOdt`), so there is nothing for a `pdfToOdt` to build a package through. `odtToPdf` itself needed zero new layout code: `readOdtContent` (`src/odf/odt/read.ts`) produces the identical `wordprocessing` `ContentDocument` shape `readDocxContent` does, so it feeds `convertWordprocessingToLayout` unmodified.
154
+ - **`odpToPdf` is one-directional — there is no `pdfToOdp`.** The PDF → docx/pptx/odt direction needs a live-view editor to build the output package (`buildDocxPackage`/`buildPptxPackage`/`buildOdtPackage`); odp has no live-view editor in this package yet (no `openOdp`/`createOdp`), so there is nothing for a `pdfToOdp` to build a package through, and no `odpPdfCodec` either (see `src/convert/` above). `odpToPdf` itself needed zero new layout code: `readOdpContent` (`src/odf/odp/read.ts`) produces the identical `presentation` `ContentDocument` shape `readPptxContent` does, so it feeds `convertPresentationToLayout` unmodified — including the existing hidden-annotation speaker-notes mechanism below, which carries odp's `presentation:notes` through to the PDF with no new notes-handling code at all.
152
155
  - **PDF output uses the standard 14 fonts only — no font embedding.** Helvetica/Times-Roman are genuinely metric-compatible substitutes for Arial/Times New Roman, but Word's actual current defaults (Calibri, Aptos) are not, so line wrapping and pagination will drift slightly from what Word itself would produce. Expect a faithful visual approximation, not a line-identical reproduction.
153
156
  - **Reading arbitrary real-world PDFs is the single largest risk surface in this package**, and the parser is honest about its design target: cleanly-generated output from mainstream producers (Word, PowerPoint, Chrome, LibreOffice, Acrobat), recovering from the malformations those producers and their downstream tooling actually create, and failing loudly and specifically on anything else — not matching a mature library's robustness against adversarial input.
154
157
  - **Encrypted PDFs are unsupported.** `/Encrypt` present in the trailer throws `PdfEncryptedError`, even for the common empty-user-password case.
@@ -161,11 +164,11 @@ To run a single test file: `pnpm vitest run src/path/to/file.test.ts`.
161
164
 
162
165
  ## Fidelity
163
166
 
164
- **docx/pptx/odt → PDF** is a genuine layout render: the docx/odt flow/pagination engine and the pptx direct-placement engine both produce real positioned text, images, tables, and (for docx/odt) numbered/bulleted lists, styled through the full cascade (theme fonts/colours, `basedOn` chains, placeholder inheritance for docx/pptx; `style:default-style`/`style:parent-style-name` chains for odt). It is a faithful **visual approximation**, not a pixel- or line-identical reproduction of what Word/PowerPoint/Writer would themselves render — see the standard-14 font substitution gotcha above.
167
+ **docx/pptx/odt/odp → PDF** is a genuine layout render: the docx/odt flow/pagination engine and the pptx/odp direct-placement engine both produce real positioned text, images, tables, and (for docx/odt) numbered/bulleted lists, styled through the full cascade (theme fonts/colours, `basedOn` chains, placeholder inheritance for docx/pptx; `style:default-style`/`style:parent-style-name` chains for odt/odp). It is a faithful **visual approximation**, not a pixel- or line-identical reproduction of what Word/PowerPoint/Writer/Impress would themselves render — see the standard-14 font substitution gotcha above.
165
168
 
166
- **PDF → docx/pptx** is necessarily a **best-effort reconstruction** from geometry: a PDF page is just positioned glyphs and images, with no semantic paragraph or shape structure to recover. Reading order, bold/italic/colour/font-size, and page/slide count are preserved; paragraph and text-block boundaries are inferred from baseline spacing and left-margin indentation, not recovered exactly.
169
+ **PDF → docx/pptx/odt** is necessarily a **best-effort reconstruction** from geometry: a PDF page is just positioned glyphs and images, with no semantic paragraph or shape structure to recover. Reading order, bold/italic/colour/font-size, and page/slide count are preserved; paragraph and text-block boundaries are inferred from baseline spacing and left-margin indentation, not recovered exactly. There is no PDF → odp direction yet (see the `odpToPdf` gotcha above).
167
170
 
168
- Neither direction is round-trip-lossless, and the two conversions are not inverses of each other — `pdfToDocx(docxToPdf(x))` will not reproduce `x` exactly, and is not intended to. This is a deliberate, permanent contrast with `ooxml.js`'s own `packageCodec`, which genuinely is a lossless round trip. `docxPdfCodec`/`pptxPdfCodec`/`pdfCodec` share `packageCodec`'s *mechanism* (`z.codec()`, schema-validated both ways) but not its *guarantee* — wrapping a lossy conversion in `z.codec()` validates the shape of what comes out, not its fidelity to what went in.
171
+ Neither direction is round-trip-lossless, and the two conversions are not inverses of each other — `pdfToDocx(docxToPdf(x))` will not reproduce `x` exactly, and is not intended to. This is a deliberate, permanent contrast with `ooxml.js`'s own `packageCodec`, which genuinely is a lossless round trip. `docxPdfCodec`/`pptxPdfCodec`/`odtPdfCodec`/`pdfCodec` share `packageCodec`'s *mechanism* (`z.codec()`, schema-validated both ways) but not its *guarantee* — wrapping a lossy conversion in `z.codec()` validates the shape of what comes out, not its fidelity to what went in.
169
172
 
170
173
  **Optional real-world corpus.** `test/corpus/` (gitignored, never committed) holds a `pnpm test:corpus` vitest project for manual conformance checking against real PDFs a hand-built fixture can't fully stand in for — a Word "Save as PDF", a PowerPoint "Save as PDF", a Chrome "Print to PDF", a LibreOffice export. It is not part of `pnpm test` and does not gate CI; drop files in locally before a significant parser change.
171
174
 
@@ -183,7 +186,7 @@ Commits follow Conventional Commits (`feat:`, `fix:`, `test:`, `chore:`, …), e
183
186
 
184
187
  - [ooxml.js](https://github.com/ExaDev/ooxml.js) — the sibling package this depends on for all docx/pptx/xlsx ⇄ JSON handling and cascade-resolved typed reading.
185
188
  - [document-content-model](https://github.com/ExaDev/document-content-model) — the sibling package that owns `ContentDocument`/`LayoutDocument` themselves; both `ooxml.js` and `documents.js` import from it rather than each maintaining an independent copy.
186
- - [odf.js](https://github.com/ExaDev/odf.js) — a sibling package doing the equivalent lossless-codec job for the OpenDocument Format (odt/ods/odp/odg/…), also built on `document-content-model`. A dependency of `documents.js` for: this package's `Odt`/`Ods`/`Odp`/`OdgBytesSchema` (`src/model/bytes.ts`), which validate against its `ODF_MEDIA_TYPES` table; `src/interop.test.ts`, a type-level guard that `ooxml.js`'s and `odf.js`'s raw `XmlElement`/`XmlNode`/`Attribute`/`Package` container types stay structurally compatible; and `src/odf/odt/read.ts`'s `readOdtContent`, a thin adapter over `odf.js`'s own `readOdt`, feeding `odtToPdf` (`src/convert/convert.ts`). odt → `ContentDocument` reading and PDF conversion are integrated; ods/odp/odg → `ContentDocument` reading (the equivalent for spreadsheets, presentations, and drawings) is not yet.
189
+ - [odf.js](https://github.com/ExaDev/odf.js) — a sibling package doing the equivalent lossless-codec job for the OpenDocument Format (odt/ods/odp/odg/…), also built on `document-content-model`. A dependency of `documents.js` for: this package's `Odt`/`Ods`/`Odp`/`OdgBytesSchema` (`src/model/bytes.ts`), which validate against its `ODF_MEDIA_TYPES` table; `src/interop.test.ts`, a type-level guard that `ooxml.js`'s and `odf.js`'s raw `XmlElement`/`XmlNode`/`Attribute`/`Package` container types stay structurally compatible; `src/odf/odt/read.ts`'s `readOdtContent`, a thin adapter over `odf.js`'s own `readOdt`, feeding `odtToPdf`/`pdfToOdt` (`src/convert/convert.ts`); and `src/odf/odp/read.ts`'s `readOdpContent`, the same adapter over `odf.js`'s `readOdp`, feeding `odpToPdf`. odt → `ContentDocument` reading and PDF conversion are integrated both ways; odp → `ContentDocument` reading and PDF conversion are integrated one way (odp → PDF only); ods/odg → `ContentDocument` reading (the equivalent for spreadsheets and drawings) is not yet.
187
190
 
188
191
  ## License
189
192
 
package/dist/index.cjs CHANGED
@@ -7437,6 +7437,17 @@ function readOdtContent(pkg) {
7437
7437
  };
7438
7438
  }
7439
7439
  //#endregion
7440
+ //#region src/odf/odp/read.ts
7441
+ function readOdpContent(pkg) {
7442
+ const odpDoc = (0, odf_js.readOdp)(pkg);
7443
+ return {
7444
+ kind: "presentation",
7445
+ formatVersion: 1,
7446
+ metadata: { ...odpDoc.metadata },
7447
+ slides: odpDoc.slides
7448
+ };
7449
+ }
7450
+ //#endregion
7440
7451
  //#region src/pdf/text-layout.ts
7441
7452
  const WORD_OR_WHITESPACE_PATTERN = /\n|\s+|\S+/g;
7442
7453
  function atomizeRuns(runs, measurer) {
@@ -8424,6 +8435,14 @@ function pptxToPdf(bytes, options) {
8424
8435
  onSubstitution: options?.onSubstitution
8425
8436
  });
8426
8437
  }
8438
+ function odpToPdf(bytes, options) {
8439
+ const content = readOdpContent((0, odf_js.decodePackage)(bytes));
8440
+ if (content.kind !== "presentation") throw new Error("readOdpContent returned a non-presentation ContentDocument");
8441
+ return writePdf(convertPresentationToLayout(content, { measurer: createStandardFontMeasurer() }), {
8442
+ signal: options?.signal,
8443
+ onSubstitution: options?.onSubstitution
8444
+ });
8445
+ }
8427
8446
  function pdfToDocx(bytes, options) {
8428
8447
  const content = reconstructWordprocessing(readPdf(bytes, {
8429
8448
  signal: options?.signal,
@@ -8455,7 +8474,7 @@ const pptxPdfCodec = zod.z.codec(PptxBytesSchema, PdfBytesSchema, {
8455
8474
  decode: (pptxBytes) => pptxToPdf(pptxBytes),
8456
8475
  encode: (pdfBytes) => pdfToPptx(pdfBytes)
8457
8476
  });
8458
- zod.z.codec(OdtBytesSchema, PdfBytesSchema, {
8477
+ const odtPdfCodec = zod.z.codec(OdtBytesSchema, PdfBytesSchema, {
8459
8478
  decode: (odtBytes) => odtToPdf(odtBytes),
8460
8479
  encode: (pdfBytes) => pdfToOdt(pdfBytes)
8461
8480
  });
@@ -8474,6 +8493,10 @@ const SUPPORTED_CONVERSIONS = [
8474
8493
  source: "odt",
8475
8494
  target: "pdf"
8476
8495
  },
8496
+ {
8497
+ source: "odp",
8498
+ target: "pdf"
8499
+ },
8477
8500
  {
8478
8501
  source: "pdf",
8479
8502
  target: "docx"
@@ -8549,6 +8572,19 @@ function createLocalDocumentConverter() {
8549
8572
  diagnostics
8550
8573
  });
8551
8574
  }
8575
+ if (source.format === "odp" && targetFormat === "pdf") {
8576
+ const bytes = odpToPdf(source.bytes, {
8577
+ signal: options.signal,
8578
+ onSubstitution: (s, c) => diagnostics.push(substitutionDiagnostic(s, c))
8579
+ });
8580
+ return Promise.resolve({
8581
+ document: {
8582
+ format: "pdf",
8583
+ bytes
8584
+ },
8585
+ diagnostics
8586
+ });
8587
+ }
8552
8588
  if (source.format === "pdf" && targetFormat === "docx") {
8553
8589
  const bytes = pdfToDocx(source.bytes, {
8554
8590
  signal: options.signal,
@@ -8953,6 +8989,8 @@ Object.defineProperty(exports, "isXmlNode", {
8953
8989
  return ooxml_js.isXmlNode;
8954
8990
  }
8955
8991
  });
8992
+ exports.odpToPdf = odpToPdf;
8993
+ exports.odtPdfCodec = odtPdfCodec;
8956
8994
  exports.odtToPdf = odtToPdf;
8957
8995
  exports.openDocx = openDocx;
8958
8996
  exports.openOdt = openOdt;
@@ -8977,10 +9015,12 @@ Object.defineProperty(exports, "parseXml", {
8977
9015
  });
8978
9016
  exports.pdfCodec = pdfCodec;
8979
9017
  exports.pdfToDocx = pdfToDocx;
9018
+ exports.pdfToOdt = pdfToOdt;
8980
9019
  exports.pdfToPptx = pdfToPptx;
8981
9020
  exports.pptxPdfCodec = pptxPdfCodec;
8982
9021
  exports.pptxToPdf = pptxToPdf;
8983
9022
  exports.readDocxContent = readDocxContent;
9023
+ exports.readOdpContent = readOdpContent;
8984
9024
  exports.readOdtContent = readOdtContent;
8985
9025
  exports.readPdf = readPdf;
8986
9026
  exports.readPptxContent = readPptxContent;
package/dist/index.d.cts CHANGED
@@ -610,6 +610,9 @@ declare function readPptxContent(pkg: Package$1): ContentDocument;
610
610
  //#region src/odf/odt/read.d.ts
611
611
  declare function readOdtContent(pkg: Package$2): ContentDocument;
612
612
  //#endregion
613
+ //#region src/odf/odp/read.d.ts
614
+ declare function readOdpContent(pkg: Package$2): ContentDocument;
615
+ //#endregion
613
616
  //#region src/pdf/measure.d.ts
614
617
  interface UnderlineMetrics {
615
618
  readonly offsetPt: number;
@@ -659,19 +662,22 @@ interface DocumentToPdfOptions {
659
662
  declare function docxToPdf(bytes: Uint8Array<ArrayBuffer>, options?: DocumentToPdfOptions): Uint8Array<ArrayBuffer>;
660
663
  declare function odtToPdf(bytes: Uint8Array<ArrayBuffer>, options?: DocumentToPdfOptions): Uint8Array<ArrayBuffer>;
661
664
  declare function pptxToPdf(bytes: Uint8Array<ArrayBuffer>, options?: DocumentToPdfOptions): Uint8Array<ArrayBuffer>;
665
+ declare function odpToPdf(bytes: Uint8Array<ArrayBuffer>, options?: DocumentToPdfOptions): Uint8Array<ArrayBuffer>;
662
666
  interface PdfToDocumentOptions {
663
667
  readonly signal?: AbortSignal;
664
668
  readonly sink?: PdfDiagnosticSink;
665
669
  }
666
670
  declare function pdfToDocx(bytes: Uint8Array<ArrayBuffer>, options?: PdfToDocumentOptions): Uint8Array<ArrayBuffer>;
667
671
  declare function pdfToPptx(bytes: Uint8Array<ArrayBuffer>, options?: PdfToDocumentOptions): Uint8Array<ArrayBuffer>;
672
+ declare function pdfToOdt(bytes: Uint8Array<ArrayBuffer>, options?: PdfToDocumentOptions): Uint8Array<ArrayBuffer>;
668
673
  //#endregion
669
674
  //#region src/convert/codec.d.ts
670
675
  declare const docxPdfCodec: z.ZodCodec<z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>, z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>>;
671
676
  declare const pptxPdfCodec: z.ZodCodec<z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>, z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>>;
677
+ declare const odtPdfCodec: z.ZodCodec<z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>, z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>>;
672
678
  //#endregion
673
679
  //#region src/convert/port.d.ts
674
- type DocumentFormat = 'docx' | 'pptx' | 'odt' | 'pdf';
680
+ type DocumentFormat = 'docx' | 'pptx' | 'odt' | 'odp' | 'pdf';
675
681
  interface DocumentPayload {
676
682
  readonly format: DocumentFormat;
677
683
  readonly bytes: Uint8Array<ArrayBuffer>;
@@ -714,4 +720,4 @@ declare function fixedClock(date: Date): ClockPort;
714
720
  //#region src/ports/abort.d.ts
715
721
  declare function throwIfAborted(signal: AbortSignal | undefined): void;
716
722
  //#endregion
717
- export { type Alignment, type Attribute, AttributeSchema, type BinaryPart, BinaryPartSchema, type Box, COLOR_BLACK, CONTENT_FORMAT_VERSION, type ClockPort, type Comment, CommentSchema, type CompactAttrPairs, type CompactPackage, CompactPackageSchema, type CompactPart, CompactPartSchema, type CompactXmlNode, CompactXmlNodeSchema, type ContentBlock, ContentBlockSchema, type ContentDocument, ContentDocumentSchema, type ContentImageBlock, ContentImageBlockSchema, type ContentListMembership, type ContentPageBreak, ContentPageBreakSchema, type ContentParagraph, ContentParagraphSchema, type ContentRun, ContentRunSchema, type ContentSection, ContentSectionSchema, type ContentShape, ContentShapeSchema, type ContentSlide, ContentSlideSchema, type ContentTable, type ContentTableCell, ContentTableCellSchema, type ContentTableRow, ContentTableRowSchema, ContentTableSchema, type ConversionRequest, type ConversionResult, DEFAULT_LAYOUT_FONT, type DefinedName, DefinedNameSchema, type Diagnostic, type DocumentConverter, type DocumentFormat, type DocumentPayload, type DocumentToPdfOptions, type DocxBody, DocxBytesSchema, DocxEditor, DocxParagraph, DocxRun, DocxTable, DocxTableCell, DocxTableRow, type DrawingParagraphInit, type DrawingRunInit, type EngineLayoutOptions, LAYOUT_FORMAT_VERSION, type LayoutColor, type LayoutDocument, type LayoutEllipse, type LayoutFont, type LayoutImage, type LayoutImageAsset, type LayoutItem, type LayoutLine, type LayoutLink, type LayoutMetadata, type LayoutPage, type LayoutRect, type LayoutText, type Margins, NOOP_DIAGNOSTIC_SINK, OdgBytesSchema, OdpBytesSchema, OdsBytesSchema, type OdtBody, OdtBytesSchema, OdtEditor, OdtList, OdtListItem, OdtParagraph, type ParagraphInit as OdtParagraphInit, OdtRun, type RunInit as OdtRunInit, OdtTable, OdtTableCell, type TableInit as OdtTableInit, OdtTableRow, PAGE_SIZE_A4, PAGE_SIZE_LETTER, type Package, PackageSchema, type PageSize, type Part, PartSchema, PdfBytesSchema, type PdfDiagnostic, type PdfDiagnosticSeverity, type PdfDiagnosticSink, PdfEncryptedError, PdfParseError, type PdfToDocumentOptions, PptxBytesSchema, PptxEditor, PptxShape, PptxSlide, type ReadPdfOptions, type ReconstructOptions, type Relationship, SLIDE_SIZE_STANDARD, SLIDE_SIZE_WIDESCREEN, type SlideImageInit, type SlidesLayoutOptions, type TextBoxInit, type WinAnsiSubstitution, type WritePdfOptions, type XmlCdata, XmlCdataSchema, type XmlComment, XmlCommentSchema, type XmlDeclaration, XmlDeclarationSchema, type XmlElement, XmlElementSchema, type XmlNode, XmlNodeSchema, type XmlPart, XmlPartSchema, type XmlPi, XmlPiSchema, type XmlText, XmlTextSchema, attr, base64ToBytes, buildDocxPackage, buildOdtPackage, buildPptxPackage, buildXml, bytesToBase64, childrenWithTag, compactCodec, compactPackageCodec, convertPresentationToLayout, convertWordprocessingToLayout, createDocx, createLocalDocumentConverter, createOdt, createPptx, decodeCompactPackage, decodeEntities, decodePackage, docxPdfCodec, docxToPdf, elementsWithTag, encodeCompactPackage, encodePackage, fixedClock, flipY, fromCompact, isCompactXmlNode, isContentBlock, isXmlNode, odtToPdf, openDocx, openOdt, openPptx, packageCodec, parsePackage, parseXml, pdfCodec, pdfToDocx, pdfToPptx, pptxPdfCodec, pptxToPdf, readDocxContent, readOdtContent, readPdf, readPptxContent, reconstructPresentation, reconstructWordprocessing, resolveRelationships, rgbHexToColor, rootElement, serializePackage, systemClock, textContent, throwIfAborted, toCompact, unzipPackage, walk, writePdf, xmlCodec, zipPackage };
723
+ export { type Alignment, type Attribute, AttributeSchema, type BinaryPart, BinaryPartSchema, type Box, COLOR_BLACK, CONTENT_FORMAT_VERSION, type ClockPort, type Comment, CommentSchema, type CompactAttrPairs, type CompactPackage, CompactPackageSchema, type CompactPart, CompactPartSchema, type CompactXmlNode, CompactXmlNodeSchema, type ContentBlock, ContentBlockSchema, type ContentDocument, ContentDocumentSchema, type ContentImageBlock, ContentImageBlockSchema, type ContentListMembership, type ContentPageBreak, ContentPageBreakSchema, type ContentParagraph, ContentParagraphSchema, type ContentRun, ContentRunSchema, type ContentSection, ContentSectionSchema, type ContentShape, ContentShapeSchema, type ContentSlide, ContentSlideSchema, type ContentTable, type ContentTableCell, ContentTableCellSchema, type ContentTableRow, ContentTableRowSchema, ContentTableSchema, type ConversionRequest, type ConversionResult, DEFAULT_LAYOUT_FONT, type DefinedName, DefinedNameSchema, type Diagnostic, type DocumentConverter, type DocumentFormat, type DocumentPayload, type DocumentToPdfOptions, type DocxBody, DocxBytesSchema, DocxEditor, DocxParagraph, DocxRun, DocxTable, DocxTableCell, DocxTableRow, type DrawingParagraphInit, type DrawingRunInit, type EngineLayoutOptions, LAYOUT_FORMAT_VERSION, type LayoutColor, type LayoutDocument, type LayoutEllipse, type LayoutFont, type LayoutImage, type LayoutImageAsset, type LayoutItem, type LayoutLine, type LayoutLink, type LayoutMetadata, type LayoutPage, type LayoutRect, type LayoutText, type Margins, NOOP_DIAGNOSTIC_SINK, OdgBytesSchema, OdpBytesSchema, OdsBytesSchema, type OdtBody, OdtBytesSchema, OdtEditor, OdtList, OdtListItem, OdtParagraph, type ParagraphInit as OdtParagraphInit, OdtRun, type RunInit as OdtRunInit, OdtTable, OdtTableCell, type TableInit as OdtTableInit, OdtTableRow, PAGE_SIZE_A4, PAGE_SIZE_LETTER, type Package, PackageSchema, type PageSize, type Part, PartSchema, PdfBytesSchema, type PdfDiagnostic, type PdfDiagnosticSeverity, type PdfDiagnosticSink, PdfEncryptedError, PdfParseError, type PdfToDocumentOptions, PptxBytesSchema, PptxEditor, PptxShape, PptxSlide, type ReadPdfOptions, type ReconstructOptions, type Relationship, SLIDE_SIZE_STANDARD, SLIDE_SIZE_WIDESCREEN, type SlideImageInit, type SlidesLayoutOptions, type TextBoxInit, type WinAnsiSubstitution, type WritePdfOptions, type XmlCdata, XmlCdataSchema, type XmlComment, XmlCommentSchema, type XmlDeclaration, XmlDeclarationSchema, type XmlElement, XmlElementSchema, type XmlNode, XmlNodeSchema, type XmlPart, XmlPartSchema, type XmlPi, XmlPiSchema, type XmlText, XmlTextSchema, attr, base64ToBytes, buildDocxPackage, buildOdtPackage, buildPptxPackage, buildXml, bytesToBase64, childrenWithTag, compactCodec, compactPackageCodec, convertPresentationToLayout, convertWordprocessingToLayout, createDocx, createLocalDocumentConverter, createOdt, createPptx, decodeCompactPackage, decodeEntities, decodePackage, docxPdfCodec, docxToPdf, elementsWithTag, encodeCompactPackage, encodePackage, fixedClock, flipY, fromCompact, isCompactXmlNode, isContentBlock, isXmlNode, odpToPdf, odtPdfCodec, odtToPdf, openDocx, openOdt, openPptx, packageCodec, parsePackage, parseXml, pdfCodec, pdfToDocx, pdfToOdt, pdfToPptx, pptxPdfCodec, pptxToPdf, readDocxContent, readOdpContent, readOdtContent, readPdf, readPptxContent, reconstructPresentation, reconstructWordprocessing, resolveRelationships, rgbHexToColor, rootElement, serializePackage, systemClock, textContent, throwIfAborted, toCompact, unzipPackage, walk, writePdf, xmlCodec, zipPackage };
package/dist/index.d.ts CHANGED
@@ -610,6 +610,9 @@ declare function readPptxContent(pkg: Package$1): ContentDocument;
610
610
  //#region src/odf/odt/read.d.ts
611
611
  declare function readOdtContent(pkg: Package$2): ContentDocument;
612
612
  //#endregion
613
+ //#region src/odf/odp/read.d.ts
614
+ declare function readOdpContent(pkg: Package$2): ContentDocument;
615
+ //#endregion
613
616
  //#region src/pdf/measure.d.ts
614
617
  interface UnderlineMetrics {
615
618
  readonly offsetPt: number;
@@ -659,19 +662,22 @@ interface DocumentToPdfOptions {
659
662
  declare function docxToPdf(bytes: Uint8Array<ArrayBuffer>, options?: DocumentToPdfOptions): Uint8Array<ArrayBuffer>;
660
663
  declare function odtToPdf(bytes: Uint8Array<ArrayBuffer>, options?: DocumentToPdfOptions): Uint8Array<ArrayBuffer>;
661
664
  declare function pptxToPdf(bytes: Uint8Array<ArrayBuffer>, options?: DocumentToPdfOptions): Uint8Array<ArrayBuffer>;
665
+ declare function odpToPdf(bytes: Uint8Array<ArrayBuffer>, options?: DocumentToPdfOptions): Uint8Array<ArrayBuffer>;
662
666
  interface PdfToDocumentOptions {
663
667
  readonly signal?: AbortSignal;
664
668
  readonly sink?: PdfDiagnosticSink;
665
669
  }
666
670
  declare function pdfToDocx(bytes: Uint8Array<ArrayBuffer>, options?: PdfToDocumentOptions): Uint8Array<ArrayBuffer>;
667
671
  declare function pdfToPptx(bytes: Uint8Array<ArrayBuffer>, options?: PdfToDocumentOptions): Uint8Array<ArrayBuffer>;
672
+ declare function pdfToOdt(bytes: Uint8Array<ArrayBuffer>, options?: PdfToDocumentOptions): Uint8Array<ArrayBuffer>;
668
673
  //#endregion
669
674
  //#region src/convert/codec.d.ts
670
675
  declare const docxPdfCodec: z.ZodCodec<z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>, z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>>;
671
676
  declare const pptxPdfCodec: z.ZodCodec<z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>, z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>>;
677
+ declare const odtPdfCodec: z.ZodCodec<z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>, z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>>;
672
678
  //#endregion
673
679
  //#region src/convert/port.d.ts
674
- type DocumentFormat = 'docx' | 'pptx' | 'odt' | 'pdf';
680
+ type DocumentFormat = 'docx' | 'pptx' | 'odt' | 'odp' | 'pdf';
675
681
  interface DocumentPayload {
676
682
  readonly format: DocumentFormat;
677
683
  readonly bytes: Uint8Array<ArrayBuffer>;
@@ -714,4 +720,4 @@ declare function fixedClock(date: Date): ClockPort;
714
720
  //#region src/ports/abort.d.ts
715
721
  declare function throwIfAborted(signal: AbortSignal | undefined): void;
716
722
  //#endregion
717
- export { type Alignment, type Attribute, AttributeSchema, type BinaryPart, BinaryPartSchema, type Box, COLOR_BLACK, CONTENT_FORMAT_VERSION, type ClockPort, type Comment, CommentSchema, type CompactAttrPairs, type CompactPackage, CompactPackageSchema, type CompactPart, CompactPartSchema, type CompactXmlNode, CompactXmlNodeSchema, type ContentBlock, ContentBlockSchema, type ContentDocument, ContentDocumentSchema, type ContentImageBlock, ContentImageBlockSchema, type ContentListMembership, type ContentPageBreak, ContentPageBreakSchema, type ContentParagraph, ContentParagraphSchema, type ContentRun, ContentRunSchema, type ContentSection, ContentSectionSchema, type ContentShape, ContentShapeSchema, type ContentSlide, ContentSlideSchema, type ContentTable, type ContentTableCell, ContentTableCellSchema, type ContentTableRow, ContentTableRowSchema, ContentTableSchema, type ConversionRequest, type ConversionResult, DEFAULT_LAYOUT_FONT, type DefinedName, DefinedNameSchema, type Diagnostic, type DocumentConverter, type DocumentFormat, type DocumentPayload, type DocumentToPdfOptions, type DocxBody, DocxBytesSchema, DocxEditor, DocxParagraph, DocxRun, DocxTable, DocxTableCell, DocxTableRow, type DrawingParagraphInit, type DrawingRunInit, type EngineLayoutOptions, LAYOUT_FORMAT_VERSION, type LayoutColor, type LayoutDocument, type LayoutEllipse, type LayoutFont, type LayoutImage, type LayoutImageAsset, type LayoutItem, type LayoutLine, type LayoutLink, type LayoutMetadata, type LayoutPage, type LayoutRect, type LayoutText, type Margins, NOOP_DIAGNOSTIC_SINK, OdgBytesSchema, OdpBytesSchema, OdsBytesSchema, type OdtBody, OdtBytesSchema, OdtEditor, OdtList, OdtListItem, OdtParagraph, type ParagraphInit as OdtParagraphInit, OdtRun, type RunInit as OdtRunInit, OdtTable, OdtTableCell, type TableInit as OdtTableInit, OdtTableRow, PAGE_SIZE_A4, PAGE_SIZE_LETTER, type Package, PackageSchema, type PageSize, type Part, PartSchema, PdfBytesSchema, type PdfDiagnostic, type PdfDiagnosticSeverity, type PdfDiagnosticSink, PdfEncryptedError, PdfParseError, type PdfToDocumentOptions, PptxBytesSchema, PptxEditor, PptxShape, PptxSlide, type ReadPdfOptions, type ReconstructOptions, type Relationship, SLIDE_SIZE_STANDARD, SLIDE_SIZE_WIDESCREEN, type SlideImageInit, type SlidesLayoutOptions, type TextBoxInit, type WinAnsiSubstitution, type WritePdfOptions, type XmlCdata, XmlCdataSchema, type XmlComment, XmlCommentSchema, type XmlDeclaration, XmlDeclarationSchema, type XmlElement, XmlElementSchema, type XmlNode, XmlNodeSchema, type XmlPart, XmlPartSchema, type XmlPi, XmlPiSchema, type XmlText, XmlTextSchema, attr, base64ToBytes, buildDocxPackage, buildOdtPackage, buildPptxPackage, buildXml, bytesToBase64, childrenWithTag, compactCodec, compactPackageCodec, convertPresentationToLayout, convertWordprocessingToLayout, createDocx, createLocalDocumentConverter, createOdt, createPptx, decodeCompactPackage, decodeEntities, decodePackage, docxPdfCodec, docxToPdf, elementsWithTag, encodeCompactPackage, encodePackage, fixedClock, flipY, fromCompact, isCompactXmlNode, isContentBlock, isXmlNode, odtToPdf, openDocx, openOdt, openPptx, packageCodec, parsePackage, parseXml, pdfCodec, pdfToDocx, pdfToPptx, pptxPdfCodec, pptxToPdf, readDocxContent, readOdtContent, readPdf, readPptxContent, reconstructPresentation, reconstructWordprocessing, resolveRelationships, rgbHexToColor, rootElement, serializePackage, systemClock, textContent, throwIfAborted, toCompact, unzipPackage, walk, writePdf, xmlCodec, zipPackage };
723
+ export { type Alignment, type Attribute, AttributeSchema, type BinaryPart, BinaryPartSchema, type Box, COLOR_BLACK, CONTENT_FORMAT_VERSION, type ClockPort, type Comment, CommentSchema, type CompactAttrPairs, type CompactPackage, CompactPackageSchema, type CompactPart, CompactPartSchema, type CompactXmlNode, CompactXmlNodeSchema, type ContentBlock, ContentBlockSchema, type ContentDocument, ContentDocumentSchema, type ContentImageBlock, ContentImageBlockSchema, type ContentListMembership, type ContentPageBreak, ContentPageBreakSchema, type ContentParagraph, ContentParagraphSchema, type ContentRun, ContentRunSchema, type ContentSection, ContentSectionSchema, type ContentShape, ContentShapeSchema, type ContentSlide, ContentSlideSchema, type ContentTable, type ContentTableCell, ContentTableCellSchema, type ContentTableRow, ContentTableRowSchema, ContentTableSchema, type ConversionRequest, type ConversionResult, DEFAULT_LAYOUT_FONT, type DefinedName, DefinedNameSchema, type Diagnostic, type DocumentConverter, type DocumentFormat, type DocumentPayload, type DocumentToPdfOptions, type DocxBody, DocxBytesSchema, DocxEditor, DocxParagraph, DocxRun, DocxTable, DocxTableCell, DocxTableRow, type DrawingParagraphInit, type DrawingRunInit, type EngineLayoutOptions, LAYOUT_FORMAT_VERSION, type LayoutColor, type LayoutDocument, type LayoutEllipse, type LayoutFont, type LayoutImage, type LayoutImageAsset, type LayoutItem, type LayoutLine, type LayoutLink, type LayoutMetadata, type LayoutPage, type LayoutRect, type LayoutText, type Margins, NOOP_DIAGNOSTIC_SINK, OdgBytesSchema, OdpBytesSchema, OdsBytesSchema, type OdtBody, OdtBytesSchema, OdtEditor, OdtList, OdtListItem, OdtParagraph, type ParagraphInit as OdtParagraphInit, OdtRun, type RunInit as OdtRunInit, OdtTable, OdtTableCell, type TableInit as OdtTableInit, OdtTableRow, PAGE_SIZE_A4, PAGE_SIZE_LETTER, type Package, PackageSchema, type PageSize, type Part, PartSchema, PdfBytesSchema, type PdfDiagnostic, type PdfDiagnosticSeverity, type PdfDiagnosticSink, PdfEncryptedError, PdfParseError, type PdfToDocumentOptions, PptxBytesSchema, PptxEditor, PptxShape, PptxSlide, type ReadPdfOptions, type ReconstructOptions, type Relationship, SLIDE_SIZE_STANDARD, SLIDE_SIZE_WIDESCREEN, type SlideImageInit, type SlidesLayoutOptions, type TextBoxInit, type WinAnsiSubstitution, type WritePdfOptions, type XmlCdata, XmlCdataSchema, type XmlComment, XmlCommentSchema, type XmlDeclaration, XmlDeclarationSchema, type XmlElement, XmlElementSchema, type XmlNode, XmlNodeSchema, type XmlPart, XmlPartSchema, type XmlPi, XmlPiSchema, type XmlText, XmlTextSchema, attr, base64ToBytes, buildDocxPackage, buildOdtPackage, buildPptxPackage, buildXml, bytesToBase64, childrenWithTag, compactCodec, compactPackageCodec, convertPresentationToLayout, convertWordprocessingToLayout, createDocx, createLocalDocumentConverter, createOdt, createPptx, decodeCompactPackage, decodeEntities, decodePackage, docxPdfCodec, docxToPdf, elementsWithTag, encodeCompactPackage, encodePackage, fixedClock, flipY, fromCompact, isCompactXmlNode, isContentBlock, isXmlNode, odpToPdf, odtPdfCodec, odtToPdf, openDocx, openOdt, openPptx, packageCodec, parsePackage, parseXml, pdfCodec, pdfToDocx, pdfToOdt, pdfToPptx, pptxPdfCodec, pptxToPdf, readDocxContent, readOdpContent, readOdtContent, readPdf, readPptxContent, reconstructPresentation, reconstructWordprocessing, resolveRelationships, rgbHexToColor, rootElement, serializePackage, systemClock, textContent, throwIfAborted, toCompact, unzipPackage, walk, writePdf, xmlCodec, zipPackage };
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { AttributeSchema, BinaryPartSchema, CommentSchema, CompactPackageSchema, CompactPartSchema, CompactXmlNodeSchema, DefinedNameSchema, PackageSchema, PartSchema, XmlCdataSchema, XmlCommentSchema, XmlDeclarationSchema, XmlElementSchema, XmlNodeSchema, XmlPartSchema, XmlPiSchema, XmlTextSchema, attr, attr as attr$1, base64ToBytes, base64ToBytes as base64ToBytes$1, buildXml, bytesToBase64, bytesToBase64 as bytesToBase64$1, childrenWithTag, compactCodec, compactPackageCodec, decodeCompactPackage, decodeEntities, decodePackage, decodePackage as decodePackage$1, elementsWithTag, encodeCompactPackage, encodePackage, encodePackage as encodePackage$1, fromCompact, isCompactXmlNode, isXmlNode, packageCodec, parsePackage, parseXml, readDocx, readPptx, resolveRelationships, resolveRelationships as resolveRelationships$1, rootElement, rootElement as rootElement$1, serializePackage, textContent, textContent as textContent$1, toCompact, unzipPackage, walk, xmlCodec, zipPackage } from "ooxml.js";
2
2
  import { COLOR_BLACK, ContentBlockSchema, ContentImageBlockSchema, ContentPageBreakSchema, ContentParagraphSchema, ContentRunSchema, ContentSectionSchema, ContentSectionSchema as ContentSectionSchema$1, ContentShapeSchema, ContentSlideSchema, ContentSlideSchema as ContentSlideSchema$1, ContentTableCellSchema, ContentTableRowSchema, ContentTableSchema, DEFAULT_LAYOUT_FONT, LAYOUT_FORMAT_VERSION, LAYOUT_FORMAT_VERSION as LAYOUT_FORMAT_VERSION$1, LayoutDocumentSchema, LayoutMetadataSchema, PAGE_SIZE_A4, PAGE_SIZE_LETTER, SLIDE_SIZE_STANDARD, SLIDE_SIZE_WIDESCREEN, colorToRgbHex, isContentBlock, rgbHexToColor } from "document-content-model";
3
3
  import { z } from "zod";
4
- import { ODF_MEDIA_TYPES, StyleRegistry, decodeOdfText, decodePackage as decodePackage$2, encodePackage as encodePackage$2, formatOdfLength, readOdt, resolveStyle, setDocumentMediaType, syncManifest, xmlnsAttributes } from "odf.js";
4
+ import { ODF_MEDIA_TYPES, StyleRegistry, decodeOdfText, decodePackage as decodePackage$2, encodePackage as encodePackage$2, formatOdfLength, readOdp, readOdt, resolveStyle, setDocumentMediaType, syncManifest, xmlnsAttributes } from "odf.js";
5
5
  import { Unzlib, inflateSync, unzlibSync, zlibSync } from "fflate";
6
6
  //#region src/model/content.ts
7
7
  const CONTENT_FORMAT_VERSION = 1;
@@ -7436,6 +7436,17 @@ function readOdtContent(pkg) {
7436
7436
  };
7437
7437
  }
7438
7438
  //#endregion
7439
+ //#region src/odf/odp/read.ts
7440
+ function readOdpContent(pkg) {
7441
+ const odpDoc = readOdp(pkg);
7442
+ return {
7443
+ kind: "presentation",
7444
+ formatVersion: 1,
7445
+ metadata: { ...odpDoc.metadata },
7446
+ slides: odpDoc.slides
7447
+ };
7448
+ }
7449
+ //#endregion
7439
7450
  //#region src/pdf/text-layout.ts
7440
7451
  const WORD_OR_WHITESPACE_PATTERN = /\n|\s+|\S+/g;
7441
7452
  function atomizeRuns(runs, measurer) {
@@ -8423,6 +8434,14 @@ function pptxToPdf(bytes, options) {
8423
8434
  onSubstitution: options?.onSubstitution
8424
8435
  });
8425
8436
  }
8437
+ function odpToPdf(bytes, options) {
8438
+ const content = readOdpContent(decodePackage$2(bytes));
8439
+ if (content.kind !== "presentation") throw new Error("readOdpContent returned a non-presentation ContentDocument");
8440
+ return writePdf(convertPresentationToLayout(content, { measurer: createStandardFontMeasurer() }), {
8441
+ signal: options?.signal,
8442
+ onSubstitution: options?.onSubstitution
8443
+ });
8444
+ }
8426
8445
  function pdfToDocx(bytes, options) {
8427
8446
  const content = reconstructWordprocessing(readPdf(bytes, {
8428
8447
  signal: options?.signal,
@@ -8454,7 +8473,7 @@ const pptxPdfCodec = z.codec(PptxBytesSchema, PdfBytesSchema, {
8454
8473
  decode: (pptxBytes) => pptxToPdf(pptxBytes),
8455
8474
  encode: (pdfBytes) => pdfToPptx(pdfBytes)
8456
8475
  });
8457
- z.codec(OdtBytesSchema, PdfBytesSchema, {
8476
+ const odtPdfCodec = z.codec(OdtBytesSchema, PdfBytesSchema, {
8458
8477
  decode: (odtBytes) => odtToPdf(odtBytes),
8459
8478
  encode: (pdfBytes) => pdfToOdt(pdfBytes)
8460
8479
  });
@@ -8473,6 +8492,10 @@ const SUPPORTED_CONVERSIONS = [
8473
8492
  source: "odt",
8474
8493
  target: "pdf"
8475
8494
  },
8495
+ {
8496
+ source: "odp",
8497
+ target: "pdf"
8498
+ },
8476
8499
  {
8477
8500
  source: "pdf",
8478
8501
  target: "docx"
@@ -8548,6 +8571,19 @@ function createLocalDocumentConverter() {
8548
8571
  diagnostics
8549
8572
  });
8550
8573
  }
8574
+ if (source.format === "odp" && targetFormat === "pdf") {
8575
+ const bytes = odpToPdf(source.bytes, {
8576
+ signal: options.signal,
8577
+ onSubstitution: (s, c) => diagnostics.push(substitutionDiagnostic(s, c))
8578
+ });
8579
+ return Promise.resolve({
8580
+ document: {
8581
+ format: "pdf",
8582
+ bytes
8583
+ },
8584
+ diagnostics
8585
+ });
8586
+ }
8551
8587
  if (source.format === "pdf" && targetFormat === "docx") {
8552
8588
  const bytes = pdfToDocx(source.bytes, {
8553
8589
  signal: options.signal,
@@ -8598,4 +8634,4 @@ function fixedClock(date) {
8598
8634
  return { now: () => date };
8599
8635
  }
8600
8636
  //#endregion
8601
- export { AttributeSchema, BinaryPartSchema, COLOR_BLACK, CONTENT_FORMAT_VERSION, CommentSchema, CompactPackageSchema, CompactPartSchema, CompactXmlNodeSchema, ContentBlockSchema, ContentDocumentSchema, ContentImageBlockSchema, ContentPageBreakSchema, ContentParagraphSchema, ContentRunSchema, ContentSectionSchema, ContentShapeSchema, ContentSlideSchema, ContentTableCellSchema, ContentTableRowSchema, ContentTableSchema, DEFAULT_LAYOUT_FONT, DefinedNameSchema, DocxBytesSchema, DocxEditor, DocxParagraph, DocxRun, DocxTable, DocxTableCell, DocxTableRow, LAYOUT_FORMAT_VERSION, NOOP_DIAGNOSTIC_SINK, OdgBytesSchema, OdpBytesSchema, OdsBytesSchema, OdtBytesSchema, OdtEditor, OdtList, OdtListItem, OdtParagraph, OdtRun, OdtTable, OdtTableCell, OdtTableRow, PAGE_SIZE_A4, PAGE_SIZE_LETTER, PackageSchema, PartSchema, PdfBytesSchema, PdfEncryptedError, PdfParseError, PptxBytesSchema, PptxEditor, PptxShape, PptxSlide, SLIDE_SIZE_STANDARD, SLIDE_SIZE_WIDESCREEN, XmlCdataSchema, XmlCommentSchema, XmlDeclarationSchema, XmlElementSchema, XmlNodeSchema, XmlPartSchema, XmlPiSchema, XmlTextSchema, attr, base64ToBytes, buildDocxPackage, buildOdtPackage, buildPptxPackage, buildXml, bytesToBase64, childrenWithTag, compactCodec, compactPackageCodec, convertPresentationToLayout, convertWordprocessingToLayout, createDocx, createLocalDocumentConverter, createOdt, createPptx, decodeCompactPackage, decodeEntities, decodePackage, docxPdfCodec, docxToPdf, elementsWithTag, encodeCompactPackage, encodePackage, fixedClock, flipY, fromCompact, isCompactXmlNode, isContentBlock, isXmlNode, odtToPdf, openDocx, openOdt, openPptx, packageCodec, parsePackage, parseXml, pdfCodec, pdfToDocx, pdfToPptx, pptxPdfCodec, pptxToPdf, readDocxContent, readOdtContent, readPdf, readPptxContent, reconstructPresentation, reconstructWordprocessing, resolveRelationships, rgbHexToColor, rootElement, serializePackage, systemClock, textContent, throwIfAborted, toCompact, unzipPackage, walk, writePdf, xmlCodec, zipPackage };
8637
+ export { AttributeSchema, BinaryPartSchema, COLOR_BLACK, CONTENT_FORMAT_VERSION, CommentSchema, CompactPackageSchema, CompactPartSchema, CompactXmlNodeSchema, ContentBlockSchema, ContentDocumentSchema, ContentImageBlockSchema, ContentPageBreakSchema, ContentParagraphSchema, ContentRunSchema, ContentSectionSchema, ContentShapeSchema, ContentSlideSchema, ContentTableCellSchema, ContentTableRowSchema, ContentTableSchema, DEFAULT_LAYOUT_FONT, DefinedNameSchema, DocxBytesSchema, DocxEditor, DocxParagraph, DocxRun, DocxTable, DocxTableCell, DocxTableRow, LAYOUT_FORMAT_VERSION, NOOP_DIAGNOSTIC_SINK, OdgBytesSchema, OdpBytesSchema, OdsBytesSchema, OdtBytesSchema, OdtEditor, OdtList, OdtListItem, OdtParagraph, OdtRun, OdtTable, OdtTableCell, OdtTableRow, PAGE_SIZE_A4, PAGE_SIZE_LETTER, PackageSchema, PartSchema, PdfBytesSchema, PdfEncryptedError, PdfParseError, PptxBytesSchema, PptxEditor, PptxShape, PptxSlide, SLIDE_SIZE_STANDARD, SLIDE_SIZE_WIDESCREEN, XmlCdataSchema, XmlCommentSchema, XmlDeclarationSchema, XmlElementSchema, XmlNodeSchema, XmlPartSchema, XmlPiSchema, XmlTextSchema, attr, base64ToBytes, buildDocxPackage, buildOdtPackage, buildPptxPackage, buildXml, bytesToBase64, childrenWithTag, compactCodec, compactPackageCodec, convertPresentationToLayout, convertWordprocessingToLayout, createDocx, createLocalDocumentConverter, createOdt, createPptx, decodeCompactPackage, decodeEntities, decodePackage, docxPdfCodec, docxToPdf, elementsWithTag, encodeCompactPackage, encodePackage, fixedClock, flipY, fromCompact, isCompactXmlNode, isContentBlock, isXmlNode, odpToPdf, odtPdfCodec, odtToPdf, openDocx, openOdt, openPptx, packageCodec, parsePackage, parseXml, pdfCodec, pdfToDocx, pdfToOdt, pdfToPptx, pptxPdfCodec, pptxToPdf, readDocxContent, readOdpContent, readOdtContent, readPdf, readPptxContent, reconstructPresentation, reconstructWordprocessing, resolveRelationships, rgbHexToColor, rootElement, serializePackage, systemClock, textContent, throwIfAborted, toCompact, unzipPackage, walk, writePdf, xmlCodec, zipPackage };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "documents.js",
3
- "version": "1.39.0",
3
+ "version": "1.40.0",
4
4
  "description": "Bidirectional docx/pptx <-> PDF conversion and a read+write editable OOXML document model, built on ooxml.js and Zod 4 codecs.",
5
5
  "type": "module",
6
6
  "repository": {