js.documents 1.65.0 → 1.66.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 +9 -6
- package/dist/color-C98dn-pT.d.ts +2 -0
- package/dist/edit/docx/content.cjs +5 -0
- package/dist/edit/docx/content.js +5 -0
- package/dist/edit/docx/image.cjs +1 -0
- package/dist/edit/docx/image.d.cts +2 -2
- package/dist/edit/docx/image.d.ts +2 -2
- package/dist/edit/docx/image.js +1 -1
- package/dist/edit/docx/paragraph.cjs +10 -1
- package/dist/edit/docx/paragraph.d.cts +4 -3
- package/dist/edit/docx/paragraph.d.ts +4 -3
- package/dist/edit/docx/paragraph.js +13 -4
- package/dist/edit/docx/props.d.ts +1 -1
- package/dist/edit/docx/run.cjs +8 -1
- package/dist/edit/docx/run.d.cts +2 -2
- package/dist/edit/docx/run.d.ts +2 -2
- package/dist/edit/docx/run.js +8 -2
- package/dist/edit/docx/vector.cjs +69 -0
- package/dist/edit/docx/vector.d.cts +6 -0
- package/dist/edit/docx/vector.d.ts +6 -0
- package/dist/edit/docx/vector.js +68 -0
- package/dist/edit/drawingml/vector.cjs +113 -0
- package/dist/edit/drawingml/vector.d.cts +9 -0
- package/dist/edit/drawingml/vector.d.ts +9 -0
- package/dist/edit/drawingml/vector.js +109 -0
- package/dist/edit/odg/content.cjs +1 -26
- package/dist/edit/odg/content.js +1 -26
- package/dist/edit/odg/page.cjs +14 -1
- package/dist/edit/odg/page.d.cts +5 -3
- package/dist/edit/odg/page.d.ts +5 -3
- package/dist/edit/odg/page.js +14 -1
- package/dist/edit/odg/style.cjs +17 -3
- package/dist/edit/odg/style.d.cts +1 -0
- package/dist/edit/odg/style.d.ts +1 -0
- package/dist/edit/odg/style.js +17 -3
- package/dist/edit/odg/vector.cjs +65 -3
- package/dist/edit/odg/vector.d.cts +2 -2
- package/dist/edit/odg/vector.d.ts +2 -2
- package/dist/edit/odg/vector.js +63 -4
- package/dist/edit/odp/content.cjs +4 -1
- package/dist/edit/odp/content.js +5 -2
- package/dist/edit/odp/shape.cjs +1 -1
- package/dist/edit/odp/shape.d.cts +1 -1
- package/dist/edit/odp/shape.d.ts +1 -1
- package/dist/edit/odp/shape.js +1 -1
- package/dist/edit/odp/slide.cjs +4 -0
- package/dist/edit/odp/slide.d.cts +8 -5
- package/dist/edit/odp/slide.d.ts +9 -6
- package/dist/edit/odp/slide.js +4 -0
- package/dist/edit/odt/content.cjs +5 -0
- package/dist/edit/odt/content.d.ts +2 -2
- package/dist/edit/odt/content.js +5 -0
- package/dist/edit/odt/editor.cjs +7 -0
- package/dist/edit/odt/editor.d.cts +3 -2
- package/dist/edit/odt/editor.d.ts +5 -4
- package/dist/edit/odt/editor.js +7 -0
- package/dist/edit/odt/list.cjs +13 -0
- package/dist/edit/odt/list.d.cts +1 -1
- package/dist/edit/odt/list.d.ts +1 -1
- package/dist/edit/odt/list.js +13 -0
- package/dist/edit/odt/paragraph.d.ts +1 -1
- package/dist/edit/odt/run.d.ts +1 -1
- package/dist/edit/odt/table.d.ts +1 -1
- package/dist/edit/pptx/content.cjs +5 -2
- package/dist/edit/pptx/content.js +5 -2
- package/dist/edit/pptx/shape.cjs +2 -5
- package/dist/edit/pptx/shape.d.ts +1 -1
- package/dist/edit/pptx/shape.js +2 -5
- package/dist/edit/pptx/slide.cjs +7 -0
- package/dist/edit/pptx/slide.d.cts +6 -4
- package/dist/edit/pptx/slide.d.ts +8 -6
- package/dist/edit/pptx/slide.js +7 -0
- package/dist/edit/pptx/table.d.ts +1 -1
- package/dist/edit/pptx/vector.cjs +17 -0
- package/dist/edit/pptx/vector.d.cts +6 -0
- package/dist/edit/pptx/vector.d.ts +6 -0
- package/dist/edit/pptx/vector.js +16 -0
- package/dist/{image-BfRLAD9B.d.cts → image-DRqXQmEg.d.cts} +2 -1
- package/dist/{image-BfRLAD9B.d.ts → image-DRqXQmEg.d.ts} +2 -1
- package/dist/index.cjs +2 -2
- package/dist/index.d.cts +5 -5
- package/dist/index.d.ts +11 -11
- package/dist/index.js +2 -2
- package/dist/layout/shared.cjs +1 -0
- package/dist/layout/shared.js +1 -0
- package/dist/{list-BuBM9rwQ.d.cts → list-BzcN-LTJ.d.cts} +3 -0
- package/dist/{list-CvKxhy3y.d.ts → list-nlhN5bat.d.ts} +4 -1
- package/dist/markdown/write.cjs +1 -1
- package/dist/markdown/write.js +1 -1
- package/dist/model/color.d.ts +1 -1
- package/dist/model/embedded-drawing.cjs +47 -0
- package/dist/model/embedded-drawing.d.cts +4 -2
- package/dist/model/embedded-drawing.d.ts +4 -2
- package/dist/model/embedded-drawing.js +46 -1
- package/dist/{paragraph-CoUi_88j.d.ts → paragraph-DndYbWuT.d.ts} +1 -1
- package/dist/{run-D2rTWHbt.d.ts → run-BhYv2wJf.d.ts} +3 -2
- package/dist/{run-CJfh8rv3.d.ts → run-DtrwZwN6.d.ts} +1 -1
- package/dist/{run-B3GNScJH.d.cts → run-P0b2pDdX.d.cts} +2 -1
- package/dist/{shape-BkVcwPcf.d.ts → shape-B-TjU_Ej.d.ts} +1 -1
- package/dist/{shape-CXZ6fejV.d.cts → shape-C8qDhn0l.d.cts} +1 -1
- package/dist/{shape-CVXedeL7.d.ts → shape-XGp__l-J.d.ts} +2 -2
- package/dist/{table-DqfqMkVq.d.ts → table-BHeUmLzZ.d.ts} +1 -1
- package/dist/{table-DvS_7UQS.d.ts → table-DQpKafyl.d.ts} +1 -1
- package/dist/{vector-Puuqu_IT.d.cts → vector-D03KX8Ux.d.cts} +15 -2
- package/dist/{vector-Puuqu_IT.d.ts → vector-D03KX8Ux.d.ts} +15 -2
- package/package.json +2 -2
- package/dist/color-Bo228AY2.d.ts +0 -2
package/README.md
CHANGED
|
@@ -190,7 +190,7 @@ console.log(Object.values(numbering)[0]?.levels['0']?.format); // numbering is k
|
|
|
190
190
|
|
|
191
191
|
`openPptx`/`createPptx` and `PptxSlide`/`PptxShape` are the pptx equivalent (`slide.addTextBox`, `slide.addImage`, `shape.setParagraphs` for multi-paragraph styled text).
|
|
192
192
|
|
|
193
|
-
`openOdt`/`createOdt` and `OdtParagraph`/`OdtRun`/`OdtTable`/`OdtList` are the odt equivalent, built on ODF's own style-name-referencing model (`run.bold = true` interns or reuses a named `style:style` in `office:automatic-styles`, rather than writing an inline attribute — see [Conventions](#conventions) below). `editor.body.appendFormula(formula, frame)` writes a real embedded formula: a whole nested ODF formula sub-document inside the same package, referenced from a `draw:frame`/`draw:object`, which is how ODF embeds a formula at all (see [Architecture](#architecture)'s `src/odf-package/` entry) — the odt counterpart to `DocxParagraph.appendOfficeMath`. `openOdp`/`createOdp` and `OdpSlide`/`OdpShape` are the odp equivalent of `PptxSlide`/`PptxShape` (`slide.addTextBox`, `slide.addImage`, `slide.notes`), and reuse `OdtParagraph`/`OdtRun`/`OdtList` directly for a shape's own text content — a `draw:frame`'s `draw:text-box` holds the identical `text:p`/`text:span` model `office:text` does, interned into the same `content.xml` style registry:
|
|
193
|
+
`openOdt`/`createOdt` and `OdtParagraph`/`OdtRun`/`OdtTable`/`OdtList` are the odt equivalent, built on ODF's own style-name-referencing model (`run.bold = true` interns or reuses a named `style:style` in `office:automatic-styles`, rather than writing an inline attribute — see [Conventions](#conventions) below). A list item reads back as well as appends: `OdtListItem.paragraphs()` and `.nestedLists()` return live views on its own `text:p` children and any `text:list` nested inside it (the read counterparts to `appendParagraph`/`addNestedList`), and `.text` is those paragraphs newline-joined, matching `OdtTableCell.text`/`OdpShape.text`'s own convention — a nested list's text belongs to that list's own items, not to the item containing it, since ODF nests lists structurally rather than flagging membership per paragraph. `editor.body.appendFormula(formula, frame)` writes a real embedded formula: a whole nested ODF formula sub-document inside the same package, referenced from a `draw:frame`/`draw:object`, which is how ODF embeds a formula at all (see [Architecture](#architecture)'s `src/odf-package/` entry) — the odt counterpart to `DocxParagraph.appendOfficeMath`. `openOdp`/`createOdp` and `OdpSlide`/`OdpShape` are the odp equivalent of `PptxSlide`/`PptxShape` (`slide.addTextBox`, `slide.addImage`, `slide.notes`), and reuse `OdtParagraph`/`OdtRun`/`OdtList` directly for a shape's own text content — a `draw:frame`'s `draw:text-box` holds the identical `text:p`/`text:span` model `office:text` does, interned into the same `content.xml` style registry:
|
|
194
194
|
|
|
195
195
|
```ts
|
|
196
196
|
import { createOdp } from 'documents.js';
|
|
@@ -220,7 +220,7 @@ sheet.cell(500, 50).value = { kind: 'boolean', value: true }; // does not materi
|
|
|
220
220
|
const bytes = editor.toBytes();
|
|
221
221
|
```
|
|
222
222
|
|
|
223
|
-
`createOdg`/`openOdg` and `OdgEditor`/`OdgPage` are the drawing equivalent — a page-level container (`draw:page`), extended with the vector-primitive setters a drawing carries that a presentation typically doesn't. `OdgPage.addTextBox`/`.addImage` return real `OdpShape` instances (draw:frame's content model is byte-for-byte identical between odp and odg — see [Architecture](#architecture)); `addRect`/`addEllipse`/`addLine`/`addPath` return `OdgBoxVector`/`OdgLineVector`/`OdgPathVector`, writing real `draw:rect`/`draw:ellipse`/`draw:line`/`draw:path` elements. A vector's own paint order is purely document order — the same convention real LibreOffice output already uses, so an earlier `add*` call paints behind a later one, with no `draw:z-index` attribute ever written.
|
|
223
|
+
`createOdg`/`openOdg` and `OdgEditor`/`OdgPage` are the drawing equivalent — a page-level container (`draw:page`), extended with the vector-primitive setters a drawing carries that a presentation typically doesn't. `OdgPage.addTextBox`/`.addImage` return real `OdpShape` instances (draw:frame's content model is byte-for-byte identical between odp and odg — see [Architecture](#architecture)); `addRect`/`addEllipse`/`addLine`/`addPath` return `OdgBoxVector`/`OdgLineVector`/`OdgPathVector`, writing real `draw:rect`/`draw:ellipse`/`draw:line`/`draw:path` elements — `addPath` takes whatever `ContentSubpath[]` the caller passes, lines and cubics both, with no fixed or preset shape vocabulary of its own. `OdgPage.vectors()` is the read counterpart to those four (`shapes()` is the counterpart to `addTextBox`/`addImage`): it returns a live handle on every vector already on the page, in paint order, as an `OdgVector` union discriminated on `kind` (`'rect'`/`'ellipse'`/`'line'`/`'path'`, the same vocabulary `ContentVector` uses) — so a vector's fill, stroke, frame, and rotation stay editable long after the `add*` call that created it, exactly like every other live view in this package. A vector's own paint order is purely document order — the same convention real LibreOffice output already uses, so an earlier `add*` call paints behind a later one, with no `draw:z-index` attribute ever written.
|
|
224
224
|
|
|
225
225
|
```ts
|
|
226
226
|
import { createOdg } from 'documents.js';
|
|
@@ -488,12 +488,12 @@ Two honest limits, both structural rather than provisional. An embedded face is
|
|
|
488
488
|
|
|
489
489
|
The package is layered from generic primitives outward to the two conversion directions:
|
|
490
490
|
|
|
491
|
-
- **`src/model/`** — thin, documents.js-specific additions on top of the sibling [`document-schema.js`](https://github.com/ExaDev/document-schema.js) package, which now owns the two pivot models themselves: `LayoutDocument` (the PDF-side pivot: pages of positioned text/image/rect/line/ellipse/path/link items, PDF-native coordinates and units — `LayoutPath` is a general vector path, one or more subpaths of line/cubic segments sharing one fill/fillRule/stroke, the item kind `writePath`, pdf-codec's own content-write.ts, turns into PDF `m`/`l`/`c`/`h` content-stream operators) and `ContentDocument` (the semantic pivot: a discriminated union of `wordprocessing`, `presentation`, `spreadsheet`, `drawing`, and `formula` variants — the first four sharing paragraph/run/table/image building blocks, `drawing`'s own `ContentVector` vocabulary — rect/ellipse/line/path — being the vector-primitive counterpart to the shared `ContentShape`, and `formula` carrying a real MathML tree rather than any of them) are both imported, not defined here — `document-schema.js` exists specifically so `ooxml.js`, `odf.js`, `pdf-codec`, and `documents.js` share one schema instead of each maintaining an independent, drift-prone copy. What remains local: `bytes.ts` (magic-byte-validated `Uint8Array` schemas for docx/pptx/PDF, plus `Odt`/`Ods`/`Odp`/`OdgBytesSchema`, which check the package's actual declared media type against `odf.js`'s `ODF_MEDIA_TYPES` table rather than only the generic ZIP signature the OOXML schemas are limited to), `units.ts` (OOXML EMU/twip/point/half-point conversions), and `geometry.ts`/`color.ts`/`style.ts`, each now mostly a thin re-export of `document-schema.js`'s `Box`/`Margins`/`PageSize`/`Color`/`Alignment`/`LayoutFont` — the one genuinely PDF-specific piece each still adds locally is `geometry.ts`'s `flipY` (the top-left/y-down ↔ bottom-left/y-up space conversion between OOXML/ODF and PDF coordinates); `LayoutFont`/`DEFAULT_LAYOUT_FONT` moved to `document-schema.js` too (since `LayoutText`, part of the pivot, needs the field), leaving only the standard-14 font *resolution* logic that consumes it (pdf-codec's own `fonts.ts`/`font-read.ts`) as PDF-specific, now external to this package entirely. `ContentDocument`/`ContentDocumentSchema`/`CONTENT_FORMAT_VERSION` themselves have no local file at all any more — every consumer imports them directly from `document-schema.js`, which owns the envelope as well as everything it wraps. `paint-order.ts`'s `mergeByPaintOrder` merges a drawing page's two arrays (`shapes`, `vectors`) back into one true-paint-order walk through the shared `paintOrder` field both carry; it lives here rather than beside either caller because `src/layout/drawing.ts` and `src/edit/odg/content.ts` both need the identical merge and `src/layout/*` deliberately imports no `odf.js`/`edit` code. `formula.ts` holds the small helpers around document-schema.js's own `ContentFormula`: the `'formula'`-kind `ContentDocument` envelope, the `ContentEmbeddedObjectBlock` an odt/odp reader produces for an inline formula, the narrowing back out of such a block, and the plain-text stand-in (`formulaPlaceholderText`) every consumer that cannot typeset MathML writes instead. It declares no formula type of its own — the side-channel `EmbeddedFormula` it used to define is gone, replaced by the real schema type. `PositionedFormula` (the equivalent side-channel shape for a `LayoutDocument`) now lives in `pdf-codec` itself, which redeclares its own structurally-identical copy of it and of `MathBox` — see [Architecture](#architecture) below and pdf-codec's own README for why a real `MathBox` this package's `layoutFormula` produces crosses that package boundary with zero cast or wrapper.
|
|
491
|
+
- **`src/model/`** — thin, documents.js-specific additions on top of the sibling [`document-schema.js`](https://github.com/ExaDev/document-schema.js) package, which now owns the two pivot models themselves: `LayoutDocument` (the PDF-side pivot: pages of positioned text/image/rect/line/ellipse/path/link items, PDF-native coordinates and units — `LayoutPath` is a general vector path, one or more subpaths of line/cubic segments sharing one fill/fillRule/stroke, the item kind `writePath`, pdf-codec's own content-write.ts, turns into PDF `m`/`l`/`c`/`h` content-stream operators) and `ContentDocument` (the semantic pivot: a discriminated union of `wordprocessing`, `presentation`, `spreadsheet`, `drawing`, and `formula` variants — the first four sharing paragraph/run/table/image building blocks, `drawing`'s own `ContentVector` vocabulary — rect/ellipse/line/path — being the vector-primitive counterpart to the shared `ContentShape`, and `formula` carrying a real MathML tree rather than any of them) are both imported, not defined here — `document-schema.js` exists specifically so `ooxml.js`, `odf.js`, `pdf-codec`, and `documents.js` share one schema instead of each maintaining an independent, drift-prone copy. What remains local: `bytes.ts` (magic-byte-validated `Uint8Array` schemas for docx/pptx/PDF, plus `Odt`/`Ods`/`Odp`/`OdgBytesSchema`, which check the package's actual declared media type against `odf.js`'s `ODF_MEDIA_TYPES` table rather than only the generic ZIP signature the OOXML schemas are limited to), `units.ts` (OOXML EMU/twip/point/half-point conversions), and `geometry.ts`/`color.ts`/`style.ts`, each now mostly a thin re-export of `document-schema.js`'s `Box`/`Margins`/`PageSize`/`Color`/`Alignment`/`LayoutFont` — the one genuinely PDF-specific piece each still adds locally is `geometry.ts`'s `flipY` (the top-left/y-down ↔ bottom-left/y-up space conversion between OOXML/ODF and PDF coordinates); `LayoutFont`/`DEFAULT_LAYOUT_FONT` moved to `document-schema.js` too (since `LayoutText`, part of the pivot, needs the field), leaving only the standard-14 font *resolution* logic that consumes it (pdf-codec's own `fonts.ts`/`font-read.ts`) as PDF-specific, now external to this package entirely. `ContentDocument`/`ContentDocumentSchema`/`CONTENT_FORMAT_VERSION` themselves have no local file at all any more — every consumer imports them directly from `document-schema.js`, which owns the envelope as well as everything it wraps. `paint-order.ts`'s `mergeByPaintOrder` merges a drawing page's two arrays (`shapes`, `vectors`) back into one true-paint-order walk through the shared `paintOrder` field both carry; it lives here rather than beside either caller because `src/layout/drawing.ts` and `src/edit/odg/content.ts` both need the identical merge and `src/layout/*` deliberately imports no `odf.js`/`edit` code. `formula.ts` holds the small helpers around document-schema.js's own `ContentFormula`: the `'formula'`-kind `ContentDocument` envelope, the `ContentEmbeddedObjectBlock` an odt/odp reader produces for an inline formula, the narrowing back out of such a block, and the plain-text stand-in (`formulaPlaceholderText`) every consumer that cannot typeset MathML writes instead. It declares no formula type of its own — the side-channel `EmbeddedFormula` it used to define is gone, replaced by the real schema type. `PositionedFormula` (the equivalent side-channel shape for a `LayoutDocument`) now lives in `pdf-codec` itself, which redeclares its own structurally-identical copy of it and of `MathBox` — see [Architecture](#architecture) below and pdf-codec's own README for why a real `MathBox` this package's `layoutFormula` produces crosses that package boundary with zero cast or wrapper. `embedded-drawing.ts` is `formula.ts`'s exact counterpart for the `'drawing'` `objectKind`: `buildDrawingBlock` packages a page's recovered `ContentVector`s as a `ContentEmbeddedObjectBlock` carrying a one-page drawing `ContentDocument` (the only container in the shared schema with a `vectors` array at all, which is why a recovered rect lives there rather than directly in `ContentSection.blocks`/`ContentSlide.shapes`), `drawingOfBlock` narrows back out of one, and `embeddedDrawingVectors` flattens a block's vectors into whatever coordinate space the container about to write them uses — translating by the block's own frame plus the container's, never scaling.
|
|
492
492
|
- **The hand-written PDF codec, and the generic byte/image primitives it depends on, are now the external [`pdf-codec`](https://github.com/ExaDev/pdf-codec) dependency** rather than local `src/pdf/`/`src/bytes/`/`src/image/` directories — see that package's own README for its internal architecture (the object model, cross-reference handling, content-stream interpreter, standard-14 font resolution, the embedded math-font writer, and the generic byte/PNG/JPEG primitives it exports for a layout engine like this package's own `src/layout/` to build on).
|
|
493
493
|
- **`src/ports/`** — the injectable ports this package's own "identity, clock, and observability are first-class ports" convention calls for: `abort.ts`'s `throwIfAborted` (a signal-check helper called at row loop boundaries in `src/layout/sheets.ts`/`reconstruct.ts` — the codebase has no `await` point for cancellation to hook into implicitly, since the local pipeline is synchronous end to end, so every long-running loop checks explicitly instead; `pdf-codec` needed the identical helper for its own page loops and now carries its own independently-duplicated copy rather than depending on this package for it) and `clock.ts`'s `ClockPort`/`systemClock`/`fixedClock` (an injectable "now", for deterministic PDF output in tests). `ClockPort` is exported and tested in isolation but not yet consumed by any conversion path — `writePdf`'s own `/CreationDate`/`/ModDate` come directly from `LayoutDocument.metadata.createdIso`/`modifiedIso` when present, with nothing in pdf-codec's own write path calling `new Date()` to fill in a missing one, so there is currently no real call site for `ClockPort` to inject into. A real, tracked gap in wiring, not a documentation gap: a future default-timestamp write path should consume it rather than reaching for `new Date()` directly.
|
|
494
494
|
- **`src/xml/`** and **`src/opc/`** — parent-aware XML query/mutation and OPC package mechanics (relationship IDs, content-type entries, atomic media-part insertion) built over `ooxml.js`'s `Package`/`XmlNode`, needed because `ooxml.js`'s own XML nodes have no parent pointers and `ooxml.js` never writes new parts into an existing package. `src/xml/odf-text.ts` is the one ODF-specific module in this directory: `encodeOdfText`/`decodeOdfText` convert between a plain string and ODF's own whitespace-run element sequence (`text:s` for a run of two or more literal spaces, `text:tab`, `text:line-break` — all three occupy real character positions in an ODF paragraph but are ELEMENTS, not text-node characters, unlike docx's flat `w:t` run text) — see the Gotchas entry below on why every ODF text getter in this codebase must call `decodeOdfText`, never `ooxml.js`'s own plain-text-node `textContent()`.
|
|
495
495
|
- **`src/odf-package/`** — the ODF-side counterpart to `src/opc/`: `manifest.ts` re-exports `odf.js`'s own manifest read/build/write/sync/validate functions (`odf.js` already owns `META-INF/manifest.xml` end to end — reading, deriving, writing, syncing, and validating it — unlike `ooxml.js`'s read-only OPC relationship handling) and adds exactly one thing of its own, `syncOdfManifest`: `odf.js`'s `buildManifest` synthesises a `manifest:file-entry` for every embedded sub-document directory it finds (any `"<dir>/content.xml"` prefix) but resolves that entry's media type by file EXTENSION, which a directory has none of, so it comes out empty unless a caller supplies an override. `syncOdfManifest` derives each one from what the sub-document actually is — the single element inside its own `office:body`, the same discriminant every `odf.js` reader keys on — and every part-mutating helper here syncs through it, so adding an image to a document that already embeds a formula cannot blank the formula object's own entry on the way past. `media.ts`'s `addImageMedia` inserts a binary image part under `Pictures/` (the real-world LibreOffice/OASIS convention, confirmed against `odf.js`'s own round-trip/manifest fixtures) — one step simpler than OOXML's own `addImageMedia` (`src/opc/media.ts`) since ODF references a media part directly by its package path (`xlink:href`) rather than through a relationship-ID indirection. `formula.ts`'s `addFormulaObject` is the newer sibling and a genuinely different shape of insertion: an embedded ODF formula is not a markup vocabulary inside the host `content.xml` the way OOXML's own OMML is, it is a WHOLE NESTED DOCUMENT stored under its own directory prefix in the same zip (`Object 1/content.xml`, an `office:document-content` > `office:body` > `office:math` > `math:math` tree), referenced from the host by a `draw:frame`/`draw:object` naming that directory — precisely what `odf.js`'s own `readOdfFormula` reads back, and what `readOdfEmbeddedFormula` (`src/odf/formula/read.ts`) resolves out of the outer package's flat parts record. The formula's own MathML nodes are written straight through with no translation and no re-serialisation, since `document-schema.js`'s `MathMlNode` and `odf.js`'s `XmlNode` are structurally identical; the `math:math` element declares the MathML namespace both as the `math:` prefix and as the default, so a prefixed tree (real LibreOffice output) and a bare one (what `src/omml/read.ts` recovers from an OOXML equation) are each genuinely namespaced. `OdpSlide.addImage`/`OdpShape` (`src/edit/odp/image.ts`) is `addImageMedia`'s real caller — and, through `src/edit/odg/*`'s wholesale reuse of `OdpShape` (see the `src/edit/` entry below), `OdgPage.addImage` too; `OdtBody.appendFormula` (via `src/edit/odt/formula.ts`) is `addFormulaObject`'s; `src/odb/read.ts` also reuses `manifest.ts`'s `readManifest` directly, to check `database/script`'s own manifest-declared media type before treating it as an HSQLDB script part.
|
|
496
|
-
- **`src/edit/`** — the read-and-write editable model: live-view classes (`DocxEditor`/`DocxParagraph`/`DocxRun`/`DocxTable`, `PptxEditor`/`PptxSlide`/`PptxShape`, `OdtEditor`/`OdtParagraph`/`OdtRun`/`OdtTable`/`OdtList`, `OdpEditor`/`OdpSlide`/`OdpShape`, `OdsEditor`/`OdsSheet`/`OdsCell`, `OdgEditor`/`OdgPage`/`OdgBoxVector`/`OdgLineVector`/`OdgPathVector`) wrapping the actual `XmlElement` objects inside a decoded `Package`, plus `buildDocxPackage`/`buildPptxPackage`/`buildOdtPackage`/`buildOdpPackage`/`buildOdsPackage`/`buildOdgPackage` bridging a `ContentDocument` to a fresh package built entirely through those same primitives — `pdfToOdt`/`pdfToOdp`/`pdfToOds`/`pdfToOdg` each call the matching one. `DocxParagraph.appendOfficeMath` and `OdtBody.appendFormula` are the formula-writing primitives, and they are deliberately shaped differently because the two formats embed a formula in genuinely different ways: `appendOfficeMath` appends a real OMML display equation (`m:oMathPara` > `m:oMath`) built by `src/omml/write.ts` INLINE in the paragraph, while `appendFormula` writes a whole nested formula sub-document into the package (`src/odf-package/formula.ts`) and appends a `draw:frame`/`draw:object` referencing it. `buildDocxPackage`/`buildOdtPackage` use them to write an embedded formula as genuine, editable math in each format instead of a plain-text stand-in. `src/edit/odp/*` reuses `src/edit/odt/*`'s own paragraph/run/list/style-interning classes WHOLESALE rather than reimplementing them for presentations: a `draw:frame`'s `draw:text-box` holds the identical `text:p`/`text:span` content model `office:text` does, interned into the identical `content.xml` `office:automatic-styles` registry (`src/edit/odt/props.ts`'s `applyStyleChange`) — `OdpShape.appendParagraph`/`.paragraphs()`/`.addList()` return real `OdtParagraph`/`OdtList` instances, not odp-specific lookalikes. The genuinely new odp-specific work is `draw:page`/`draw:frame` mechanics (a slide is a `draw:page`, a shape's geometry is explicit `svg:x`/`svg:y`/`svg:width`/`svg:height` rather than pptx's placeholder-inheritance-heavy model) and rotation: `OdpShape.rotationDeg` is a genuine `draw:transform` setter built on `odf.js`'s own `applyOdfTransform`/`resolveOdfShapeGeometry` (`typed/shared/transform.ts`) — the write-side inverse of the exact function odf.js's own reader uses. `PptxShape.rotationDeg` (`src/edit/pptx/shape.ts`) is the DrawingML analogue, a plain `a:xfrm/@rot` attribute setter (60,000ths of a degree, clockwise, ECMA-376 20.1.7.6) needing no group-composition logic of its own, since `ooxml.js`'s own `composeShapeRotationDeg` already collapses to a bare passthrough of `xfrm.rotationDeg` for a top-level, ungrouped shape. That write side now lives in `src/edit/geometry.ts` (`buildTransformAttr`/`applyOdfGeometry`), a peer of the per-format edit directories rather than inside `odp/`, because `OdgBoxVector.rotationDeg`/`OdgPathVector.rotationDeg` need the identical machinery for `draw:rect`/`draw:ellipse`/`draw:path` — odf.js resolves all four element kinds through one `resolveOdfShapeGeometry`, so there is exactly one correct inverse of it. A table INSIDE a slide shape (not a document-level table) is now writable too: `OdpSlide.addTable` builds a `draw:frame` whose only child is a `table:table` directly (no `draw:text-box` wrapper) and reuses `OdtTable`/`buildTable` WHOLESALE for it, the same content-model-is-identical-wherever-it-lives argument `OdpShape`'s own paragraph/list reuse already rests on; `PptxSlide.addTable` (`src/edit/pptx/table.ts`) is the genuinely new DrawingML-side work, since a table shape lives in its own `p:graphicFrame` — a shape kind distinct from `p:sp`/`p:pic`, with its own frame on a direct `p:xfrm` child rather than nested in a `p:spPr` — and a DrawingML table's own merge model is a THIRD distinct convention from both docx's gridSpan-collapses-the-row scheme and ODF's covered-table-cell elements: every row always carries exactly as many `a:tc` as there are grid columns, and a covered cell is marked by a plain `hMerge`/`vMerge="1"` attribute on that same element, never an omitted or a differently-tagged one. `src/edit/ods/*` has no docx/pptx/odt/odp analogue to reuse for its core concern (cell addressing) but still reuses `src/edit/odt/*`'s style interning and `src/edit/odt/content.ts`'s `populateParagraph` for cell text content — `src/edit/ods/address.ts` is the write-side counterpart to `odf.js`'s own read-side `table:number-*-repeated`-aware cursor: setting a distant cell's value splits the covering repeated run in place at that one position rather than materialising every cell in between, exactly mirroring the read-side hazard `odf.js`'s own `typed/shared/a1.ts` already solved. `src/edit/ods/print-settings.ts` is the newest addition: `OdsSheet.printSettings`'s own getter/setter, mining `styles.xml`'s `office:automatic-styles`/`office:master-styles` directly (a part no other `src/edit/ods/*` module needed to touch before) rather than `content.xml` alone, reusing `odf.js`'s own exported `findStyleElement`/`resolvePageLayoutProperties`/`parsePageSize`/`parseMargins` for the read half and `src/edit/odt/automatic-styles.ts`'s `nextStyleName` (already generic over which `office:automatic-styles` element it scans) for the write half's own fresh-name minting. `src/edit/odg/*` reuses `OdpShape`/`buildTextBoxFrame`/`insertImageFrameMedia` WHOLESALE for `draw:frame` text/image content (a drawing page's `draw:frame` content model and geometry resolution — rotation included — are byte-for-byte identical to a presentation's, both resolved through `odf.js`'s own shared `readDrawFrame`), so there is no separate `OdgShape` class at all; the genuinely new work is the vector-primitive classes (a per-kind attribute vocabulary: `svg:x`/`y`/`width`/`height` for rect/ellipse/path, `svg:x1`/`y1`/`x2`/`y2` for a line) and their own fill/stroke, which needed a small, self-contained graphic-family style writer (`src/edit/odg/style.ts`) since `odf.js`'s own `StyleRegistry` recognises `'graphic'` as a style family but its `StylePropertiesSchema` only ever models text/paragraph formatting — it has no fill/stroke fields and never emits a `style:graphic-properties` element. A path vector's own `svg:d` is generated by `src/edit/odg/svg-path.ts`, the write-side inverse of `odf.js`'s own `typed/shared/path.ts` parser — always absolute, always space-separated commands, anchoring `svg:viewBox` at `"0 0 {widthPt} {heightPt}"` so the written numbers are the exact source `ContentPathPoint` values with no rescaling arithmetic either way (see Gotchas below for the cross-check against that exact parser).
|
|
496
|
+
- **`src/edit/`** — the read-and-write editable model: live-view classes (`DocxEditor`/`DocxParagraph`/`DocxRun`/`DocxTable`, `PptxEditor`/`PptxSlide`/`PptxShape`, `OdtEditor`/`OdtParagraph`/`OdtRun`/`OdtTable`/`OdtList`, `OdpEditor`/`OdpSlide`/`OdpShape`, `OdsEditor`/`OdsSheet`/`OdsCell`, `OdgEditor`/`OdgPage`/`OdgBoxVector`/`OdgLineVector`/`OdgPathVector`) wrapping the actual `XmlElement` objects inside a decoded `Package`, plus `buildDocxPackage`/`buildPptxPackage`/`buildOdtPackage`/`buildOdpPackage`/`buildOdsPackage`/`buildOdgPackage` bridging a `ContentDocument` to a fresh package built entirely through those same primitives — `pdfToOdt`/`pdfToOdp`/`pdfToOds`/`pdfToOdg` each call the matching one. `DocxParagraph.appendOfficeMath` and `OdtBody.appendFormula` are the formula-writing primitives, and they are deliberately shaped differently because the two formats embed a formula in genuinely different ways: `appendOfficeMath` appends a real OMML display equation (`m:oMathPara` > `m:oMath`) built by `src/omml/write.ts` INLINE in the paragraph, while `appendFormula` writes a whole nested formula sub-document into the package (`src/odf-package/formula.ts`) and appends a `draw:frame`/`draw:object` referencing it. `buildDocxPackage`/`buildOdtPackage` use them to write an embedded formula as genuine, editable math in each format instead of a plain-text stand-in. `src/edit/odp/*` reuses `src/edit/odt/*`'s own paragraph/run/list/style-interning classes WHOLESALE rather than reimplementing them for presentations: a `draw:frame`'s `draw:text-box` holds the identical `text:p`/`text:span` content model `office:text` does, interned into the identical `content.xml` `office:automatic-styles` registry (`src/edit/odt/props.ts`'s `applyStyleChange`) — `OdpShape.appendParagraph`/`.paragraphs()`/`.addList()` return real `OdtParagraph`/`OdtList` instances, not odp-specific lookalikes. The genuinely new odp-specific work is `draw:page`/`draw:frame` mechanics (a slide is a `draw:page`, a shape's geometry is explicit `svg:x`/`svg:y`/`svg:width`/`svg:height` rather than pptx's placeholder-inheritance-heavy model) and rotation: `OdpShape.rotationDeg` is a genuine `draw:transform` setter built on `odf.js`'s own `applyOdfTransform`/`resolveOdfShapeGeometry` (`typed/shared/transform.ts`) — the write-side inverse of the exact function odf.js's own reader uses. `PptxShape.rotationDeg` (`src/edit/pptx/shape.ts`) is the DrawingML analogue, a plain `a:xfrm/@rot` attribute setter (60,000ths of a degree, clockwise, ECMA-376 20.1.7.6) needing no group-composition logic of its own, since `ooxml.js`'s own `composeShapeRotationDeg` already collapses to a bare passthrough of `xfrm.rotationDeg` for a top-level, ungrouped shape. That write side now lives in `src/edit/geometry.ts` (`buildTransformAttr`/`applyOdfGeometry`), a peer of the per-format edit directories rather than inside `odp/`, because `OdgBoxVector.rotationDeg`/`OdgPathVector.rotationDeg` need the identical machinery for `draw:rect`/`draw:ellipse`/`draw:path` — odf.js resolves all four element kinds through one `resolveOdfShapeGeometry`, so there is exactly one correct inverse of it. A table INSIDE a slide shape (not a document-level table) is now writable too: `OdpSlide.addTable` builds a `draw:frame` whose only child is a `table:table` directly (no `draw:text-box` wrapper) and reuses `OdtTable`/`buildTable` WHOLESALE for it, the same content-model-is-identical-wherever-it-lives argument `OdpShape`'s own paragraph/list reuse already rests on; `PptxSlide.addTable` (`src/edit/pptx/table.ts`) is the genuinely new DrawingML-side work, since a table shape lives in its own `p:graphicFrame` — a shape kind distinct from `p:sp`/`p:pic`, with its own frame on a direct `p:xfrm` child rather than nested in a `p:spPr` — and a DrawingML table's own merge model is a THIRD distinct convention from both docx's gridSpan-collapses-the-row scheme and ODF's covered-table-cell elements: every row always carries exactly as many `a:tc` as there are grid columns, and a covered cell is marked by a plain `hMerge`/`vMerge="1"` attribute on that same element, never an omitted or a differently-tagged one. `src/edit/ods/*` has no docx/pptx/odt/odp analogue to reuse for its core concern (cell addressing) but still reuses `src/edit/odt/*`'s style interning and `src/edit/odt/content.ts`'s `populateParagraph` for cell text content — `src/edit/ods/address.ts` is the write-side counterpart to `odf.js`'s own read-side `table:number-*-repeated`-aware cursor: setting a distant cell's value splits the covering repeated run in place at that one position rather than materialising every cell in between, exactly mirroring the read-side hazard `odf.js`'s own `typed/shared/a1.ts` already solved. `src/edit/ods/print-settings.ts` is the newest addition: `OdsSheet.printSettings`'s own getter/setter, mining `styles.xml`'s `office:automatic-styles`/`office:master-styles` directly (a part no other `src/edit/ods/*` module needed to touch before) rather than `content.xml` alone, reusing `odf.js`'s own exported `findStyleElement`/`resolvePageLayoutProperties`/`parsePageSize`/`parseMargins` for the read half and `src/edit/odt/automatic-styles.ts`'s `nextStyleName` (already generic over which `office:automatic-styles` element it scans) for the write half's own fresh-name minting. `src/edit/odg/*` reuses `OdpShape`/`buildTextBoxFrame`/`insertImageFrameMedia` WHOLESALE for `draw:frame` text/image content (a drawing page's `draw:frame` content model and geometry resolution — rotation included — are byte-for-byte identical to a presentation's, both resolved through `odf.js`'s own shared `readDrawFrame`), so there is no separate `OdgShape` class at all; the genuinely new work is the vector-primitive classes (a per-kind attribute vocabulary: `svg:x`/`y`/`width`/`height` for rect/ellipse/path, `svg:x1`/`y1`/`x2`/`y2` for a line) and their own fill/stroke, which needed a small, self-contained graphic-family style writer (`src/edit/odg/style.ts`) since `odf.js`'s own `StyleRegistry` recognises `'graphic'` as a style family but its `StylePropertiesSchema` only ever models text/paragraph formatting — it has no fill/stroke fields and never emits a `style:graphic-properties` element. A path vector's own `svg:d` is generated by `src/edit/odg/svg-path.ts`, the write-side inverse of `odf.js`'s own `typed/shared/path.ts` parser — always absolute, always space-separated commands, anchoring `svg:viewBox` at `"0 0 {widthPt} {heightPt}"` so the written numbers are the exact source `ContentPathPoint` values with no rescaling arithmetic either way (see Gotchas below for the cross-check against that exact parser). That vector writer is no longer odg-only: `buildVectorElement`/`appendVectorTo` (`src/edit/odg/vector.ts`) are the single dispatch point `OdgPage.addVector`, `OdpSlide.addVector`, and `OdtBody.appendVectors` all go through, so a `draw:rect`/`draw:ellipse`/`draw:line`/`draw:path` is built exactly one way whichever ODF document kind it lands in — the same wholesale-reuse argument `OdpShape`'s own paragraph/list reuse rests on. `src/edit/drawingml/vector.ts` is the OOXML half of the same idea and a peer of the per-format directories for the same reason `src/edit/geometry.ts` is: it holds everything inside a DrawingML shape-properties element, which docx and pptx express identically (`CT_ShapeProperties` is one type in both), leaving only the per-format wrapper to `src/edit/docx/vector.ts` (a page-anchored `w:drawing`/`wp:anchor` carrying a `wps:wsp`) and `src/edit/pptx/vector.ts` (a plain `p:sp`). See the vector write-side gotchas below for the geometry mapping and the anchoring choices each makes.
|
|
497
497
|
- **`src/fonts/`** — source-embedded font extraction, and the registry composition every X → PDF conversion builds from it (see [Fonts](#fonts) above for the resolution order this produces). `obfuscation.ts` implements ECMA-376 Part 4, 2.8.1: `deriveFontKey` turns a `w:fontKey` GUID into the 16-byte XOR key — reading its 32 hex digits as byte pairs in REVERSE order, so `key[0]` is the GUID's LAST pair, verified against the specification's own worked example — and `deobfuscateEmbeddedFont` applies it twice across the part's first 32 bytes. One function covers docx and pptx both, by sniffing the leading sfnt signature FIRST and only deobfuscating bytes that are not already a recognisable font, rather than branching on source format: pptx's own `.fntdata` parts are stored clear and carry no font key at all, and a docx producer that stored a clear part stays readable too. `ooxml.ts` resolves `word/fontTable.xml` (or `ppt/presentation.xml`) through the package's own relationship graph rather than assuming a conventional path, reads each `w:embedRegular`/`w:embedBold`/`w:embedItalic`/`w:embedBoldItalic` (or `p:regular`/`p:bold`/`p:italic`/`p:boldItalic`) reference, and produces pdf-codec's `ProvidedFont` shape. `odf.ts` does the same for `style:font-face`'s `svg:font-face-src`/`svg:font-face-uri` — no relationship indirection, no obfuscation, and a face's weight/style taken from `loext:font-weight`/`loext:font-style` where a producer wrote them and from the font's OWN `OS/2` `fsSelection` bits where it did not (the better signal of the two: a `loext` attribute is a producer's claim about a file, `fsSelection` is that file's own declaration about itself). `registry.ts`'s `createDocumentFontRegistry` composes a source package plus any caller-supplied faces into a real `FontRegistry`, expressing the whole precedence chain as data (`sourceFonts` ahead of `fonts` ahead of the vendored substitutes) rather than as a branch. A face is deliberately never filtered by what the document actually uses: an embedded face is normally subsetted, so a character this package synthesises rather than reads can legitimately be absent from a face that is otherwise exactly right, and that is resolved per character by pdf-codec's own `onMissingGlyph`, not by dropping the whole face.
|
|
498
498
|
- **`src/mathml/`** — a MathML presentation-layer typesetting engine, comparable in scope to pdf-codec's own standard-14 text-layout half — genuinely self-contained: no import from `model`, `pdf-codec`, or `odf.js` at all (not even `document-schema.js`), matching `src/layout/`'s own "pure conversion algorithm" isolation one tier further down. `nodes.ts` defines `MathMlNode`/`MathMlElement` as a local, structurally-compatible mirror of `odf.js`'s own `XmlNode` (the same "mirror the shape, don't import the package" trick `src/interop.test.ts` already proves holds between `ooxml.js` and `odf.js`), so `odf.js`'s `readOdfFormula`'s real return value type-checks against it with zero cast. `variant.ts` maps `mathvariant` to the Unicode Mathematical Alphanumeric Symbols block (Latin/Greek/digits, including the block's own well-known Letterlike-Symbols hole-fillers — italic small h, eleven Script/Fraktur/Double-struck capitals — generated directly from Unicode's own `UnicodeData.txt`, not transcribed by hand). `operators.ts` is a deliberately bounded operator dictionary (lspace/rspace/stretchy/largeop/movablelimits per operator), not the MathML3 spec's own multi-thousand-entry table. `layout.ts` is the recursive box-model engine itself (`mrow`/`mi`/`mn`/`mo`/`mtext`/`mspace`/`msub`/`msup`/`msubsup`/`munder`/`mover`/`munderover`/`mfrac`/`msqrt`/`mroot`/`mtable`/`mtr`/`mtd`/`mstyle`/`semantics`, plus a text-content fallback with a diagnostic for anything else), driven entirely by the injected `MathFontMetrics` port (`metrics.ts`) rather than any font-parsing code of its own — pdf-codec's own `math-font.ts` is the real implementation, consumed only through this structural port, never imported directly. `compose.ts`/`radical.ts`/`length.ts` are its own small geometry helpers (baseline-offset box placement, a hand-drawn hooked radical sign built from line segments rather than a bare glyph substitute, MathML length-unit parsing). `layout.ts` additionally stretches a row's own vertical fences through the same `MathFontMetrics` port (its `stretch` method resolves the font's OpenType MATH `MathVariants` data into positioned glyph IDs), emitting them as `MathAssembledGlyphs` items — the one item kind addressed by glyph ID rather than by Unicode text, because most of the glyphs such a construction names have no code point at all. Output is a flat `MathBox` (positioned glyph runs, rules, strokes, and assembled glyph placements, box-local top-left/y-down coordinates), passed with zero cast into pdf-codec's `writePdf({ formulas })` — see pdf-codec's own README for the structural-typing mechanism that makes this work across a package boundary with no shared class or branded type.
|
|
499
499
|
- **`src/omml/`** — the MathML ⇄ OMML (Office Math Markup Language, ECMA-376 Part 1 §22.1's own `m:` vocabulary) structural translator, both directions. `write.ts`'s `buildOfficeMath`/`buildOfficeMathParagraph` are the write side, the counterpart to `src/mathml/`'s own typesetting engine, covering the identical construct set deliberately, so a formula rendered to PDF and the same formula written into a docx degrade in exactly the same places rather than one being silently better than the other: each MathML construct maps onto its real OMML element (`mfrac` → `m:f`, `msqrt`/`mroot` → `m:rad` with `m:radPr/m:degHide` and the degree/radicand order reversed, `msub`/`msup`/`msubsup` → `m:sSub`/`m:sSup`/`m:sSubSup`, `munder`/`mover` → `m:limLow`/`m:limUpp` and `munderover` → the two nested, `mtable`/`mtr`/`mtd` → `m:m`/`m:mr`/`m:e` with per-column `m:mcs`/`m:mc` justification, and every token element → an `m:r`/`m:t` run whose `mathvariant` becomes OMML's own `m:scr` script + `m:sty` style pair). `read.ts`'s `readOfficeMath`/`collectOfficeMathElements` are the read side, the structural inverse of every one of those mappings, and read STRICTLY MORE than the writer writes — deliberately, since the writer only ever has to express what MathML can say while the reader has to cope with whatever Word itself authored: `m:d` (Word's representation of every parenthesised sub-expression), `m:nary` (a sum/product/integral with limits AND its own operand), `m:acc`, `m:bar`, `m:func`, and `m:sPre` each have one exact MathML inverse and no writer counterpart at all. Both directions emit no geometry, measure nothing, and load no font — this is a vocabulary translation, not a rendering. The directory lives outside `src/mathml/` for that directory's own isolation rule: `write.ts`'s whole output type (and `read.ts`'s whole input type) is `ooxml.js`'s `XmlElement`, and `src/mathml/` imports no package at all. `shared.ts` holds what neither direction owns: the `OmmlDiagnostic` shape both report through, the one `mathvariant` ⇄ `m:scr`/`m:sty` table each reads in its own direction, and `mi`'s own intrinsic-variant default. `buildDocxPackage` and `readDocxContent` are their real callers; a construct with no counterpart in the target vocabulary degrades on its own, with a diagnostic, exactly as `src/mathml/layout.ts`'s own `unsupported` fallback does for the PDF path.
|
|
@@ -551,7 +551,10 @@ To run a single test file: `pnpm vitest run src/path/to/file.test.ts`.
|
|
|
551
551
|
- **`OdpShape.rotationDeg` writes a real `draw:transform`, built on `odf.js`'s own transform machinery.** It is the write-side inverse of `odf.js`'s `resolveOdfShapeGeometry` (`typed/shared/transform.ts`), built on that module's own exported `applyOdfTransform` rather than a hand-rolled rotation matrix, so it inherits that module's own empirically-verified rotate/translate composition order and sign convention by construction. `buildOdpPackage` writes a rotated shape's rotation back correctly — verified both by this package's own tests and by opening a fresh, editor-built `.odp` in actual LibreOffice. `PptxShape.rotationDeg` (see the `src/edit/` Architecture entry above) is the DrawingML-side counterpart, and a rotated shape now round-trips through `odpToPptx`/`pptxToOdp` both ways too (`src/convert/bridges.test.ts`'s own dedicated rotation test).
|
|
552
552
|
- **`readPdf` recovers a rect, an ellipse, and a line as their own `LayoutRect`/`LayoutEllipse`/`LayoutLine` kinds, not merely as generic paths — pdf-codec's own shape-pattern detection, and the reason every vector kind now survives a `odgToPdf` → `pdfToOdg` round trip.** PDF has exactly one shape operator (`re`, itself defined as a four-point rectangle subpath) and no ellipse or line operator at all, so a writer has no way to record what a path *was*; pdf-codec recovers it from the geometry instead — an axis-aligned closed four-corner subpath is a `LayoutRect` (any combination of fill and stroke, and a 90°-rotated CTM as well as an unrotated one), a closed subpath of four cubic segments meeting its bounding box at the four cardinal points with kappa-ratio control points is a `LayoutEllipse`, and an open single-straight-segment stroke-only subpath is a `LayoutLine`. See pdf-codec's own README for the tolerances and the honest caveat that these are bounded heuristics: a false positive can change an item's *kind*, never its geometry. What still narrows to a generic `LayoutPath`: an off-axis rotation, a freeform curve, a multi-subpath figure. A practical consequence for `pdfToOds`: a gridline written by `sheets.ts`'s own `renderGridlines` now comes back as a real `LayoutLine`, but `reconstructSpreadsheet`'s lattice detection still accepts the stroked-single-segment `LayoutPath` shape too, so a hand-built `LayoutDocument` and one from a producer other than `readPdf` detect identically.
|
|
553
553
|
- **`pdfToOds` re-types a recovered cell heuristically, and this is explicitly PROBABILISTIC BEST-EFFORT RECOVERY, not a fidelity guarantee.** A rendered PDF genuinely never carries a spreadsheet cell's own typed value — a page holds only the string the authoring application chose to print — so every re-typed value below is an inference from that string alone, and a string that looks exactly like a number may genuinely have *been* a string in the source spreadsheet (a part number, a version, a phone extension). Nothing in this package can tell those apart with certainty, and no further heuristic would change that. What is guaranteed: `ContentSheetCell.displayText` is a required field carrying the rendered string verbatim regardless of what was inferred from it, so the printed form is never lost. `src/layout/cell-typing.ts` re-types only where the string has exactly **one** defensible reading, which resolves to four concrete requirements: the decimal must be exactly representable as a JS number (checked by round-tripping it, not by a digit-count limit — this is what keeps a 19-digit barcode a string); the separators must be unambiguous (`.` reads as the decimal separator and `,` as grouping, but a lone comma group like `"1,234"` is **declined**, since the competing European reading of the identical string is 1.234, a thousandfold error — `"1,234,567"` and `"1,234.50"` have no such competing reading and are accepted); a leading zero (`"007"`, `"01.5"`) is declined outright, since a spreadsheet never prints a numeric value with one; and a date's component roles must be stated by the text itself — ISO ordering (`"2024-01-15"`) or a named month (`"15 Jan 2024"`, `"Jan 15, 2024"`) is accepted, an all-numeric separated date (`"01/02/2024"`) is declined regardless of whether one component happens to exceed 12 in that particular cell, because resolving it per cell would type one column inconsistently. `TRUE`/`FALSE` are re-typed as booleans; `Yes`/`No`/`Y`/`N`/`On`/`Off` are **declined**, since no mainstream spreadsheet prints a boolean that way by default, so a `"Yes"` cell is far more likely genuine text. Percentages recover ODF's own fraction convention (`"15%"` → `0.15`); a currency symbol names an ISO code only where it identifies exactly one (`£`→GBP, `€`→EUR; `$` and `¥` re-type as `currency` with the code left `undefined`). `'time'`/`'dateTime'`/`'error'` are deliberately out of scope, and a formula is never claimed. Two ways to tell an inferred value from an untouched one: `value.kind !== 'string'` is itself the flag, and `ReconstructOptions.onCellTypeInference` reports every decision — both a re-typing (with the rule that fired) and a deliberate refusal (with the named ambiguity), the latter being information the output alone cannot carry, since a declined cell is indistinguishable from one that was never number-shaped at all. `inferCellValue` is exported standalone for a caller who wants to replay the same decision over their own text.
|
|
554
|
-
- **`reconstructWordprocessing`/`reconstructPresentation`
|
|
554
|
+
- **`reconstructWordprocessing`/`reconstructPresentation` recover a page's vector primitives too, in a nested drawing document, and all four OOXML/ODF builders now write them out as real shapes.** Both directions used to filter each page down to its text and image items and discard every stroke and fill; they now run the same `layoutItemToVector` classification `reconstructDrawing` does (one implementation, not two) and carry the result in a `ContentEmbeddedObjectBlock` whose `objectKind` is `'drawing'` and whose nested `document` is a real one-page drawing `ContentDocument` — the shared schema's own designed mechanism, since `ContentSection.blocks` and `ContentSlide.shapes` have no vector vocabulary of their own. One honest consequence of the recovery itself: a PDF does not distinguish a stroke drawn to decorate from one drawn as structure, so a rule under a heading, an underline (pdf-codec writes one as a filled rectangle), and a table cell's background fill are all recovered as vectors — that is intended, since discarding real content because it *might* be incidental is exactly the silent loss this package's conventions rule out, but it does mean a reconstructed document carries more than its text alone. A table's own gridlines are the one case deliberately not double-counted: when the table recovery above claims a lattice, the strokes that formed it are excluded from vector recovery. On the write side, `buildDocxPackage` and `buildPptxPackage` emit real DrawingML (`a:prstGeom prst="rect"/"ellipse"/"line"`, and a genuine `a:custGeom` with `a:moveTo`/`a:lnTo`/`a:cubicBezTo`/`a:close` for a path), and `buildOdtPackage`/`buildOdpPackage` emit real `draw:rect`/`draw:ellipse`/`draw:line`/`draw:path` — see the dedicated write-side gotcha below for how each format wraps them. `pdfToMarkdown` still drops the block entirely rather than emitting a marker for it: a rect carries no text to stand in for, unlike a formula, and CommonMark has no vector construct regardless.
|
|
555
|
+
- **A recovered vector reaches the output FILE for all four formats, but not back through this package's own readers.** `buildDocxPackage`/`buildPptxPackage`/`buildOdtPackage`/`buildOdpPackage` all write real vector shapes now, so a `pdfToDocx`/`pdfToPptx`/`pdfToOdt`/`pdfToOdp` output opens in Word, PowerPoint, or LibreOffice with the recovered geometry in place. Re-reading that same file through `readDocxContent`/`readPptxContent`/`readOdtContent`/`readOdpContent` does **not** give the embedded-drawing block back: those four are thin adapters over `ooxml.js`'s `readDocx`/`readPptx` and `odf.js`'s `readOdt`/`readOdp`, none of which reads vector geometry into a `ContentDocument` at all — and for the ODF pair, `ContentSection.blocks`/`ContentSlide.shapes` have no vector vocabulary to read one into regardless. The practical consequence: the six PDF-bypassing bridges (`odtToDocx` and friends) carry no vectors across, since a bridge is `readXContent` → `buildYPackage` and the read half drops them. Closing this is reader-side work — the OOXML/ODF mirror of the second pass `src/odf/formula/detect.ts` already runs for embedded formulas — a tracked, bounded gap, not a silent one.
|
|
556
|
+
- **Each format wraps a vector shape in the construct that format actually has for one, and the two families each share one writer.** `src/edit/drawingml/vector.ts` holds everything inside a DrawingML shape-properties element (`a:xfrm`, the preset or custom geometry, `a:solidFill`/`a:noFill`, `a:ln`) — identical for docx and pptx, since `CT_ShapeProperties` is one type in both. Only the wrapper differs: pptx gets a plain `p:sp` on the slide's `p:spTree` (no `p:txBody` at all — a geometric primitive carries no text, and inventing an empty paragraph would make `readPptx` report a text shape where the source had pure geometry), while docx gets a `w:drawing`/`wp:anchor` positioned `relativeFrom="page"` on both axes, with `behindDoc="1"` and `wp:wrapNone`, carrying a `wps:wsp` inside `a:graphicData` — the wordprocessingShape extension part, the only DrawingML vocabulary WordprocessingML has for a non-picture shape (the pre-2010 alternative is VML, deprecated by ECMA-376 itself and deliberately not written). Anchoring rather than `wp:inline` is what preserves the recovered page-absolute coordinates; the honest limit is that the anchor still belongs to a paragraph, so which page the geometry lands on follows that paragraph if the document reflows differently in Word than it laid out in the source PDF. On the ODF side, `buildOdtPackage`/`buildOdpPackage` import `src/edit/odg/vector.ts`'s writer wholesale rather than reimplementing it — `draw:rect`/`draw:ellipse`/`draw:line`/`draw:path` carry byte-for-byte the same attribute vocabulary in a text document, a presentation, and a drawing, and `odf.js`'s own `readDrawPageContent` reads all three through one function. odp appends them directly to the slide's `draw:page` (a slide positions geometry against the page, exactly as a drawing page does); odt anchors them in a `text:p` of their own with `text:anchor-type="paragraph"` **plus** `style:horizontal-rel`/`style:vertical-rel="page"` in the graphic style, since a recovered vector's coordinates are page-absolute and a paragraph-relative reference would offset every shape by wherever its anchor paragraph flowed to. `style:wrap="run-through"`/`style:run-through="background"` are the ODF counterpart of docx's `wp:wrapNone`/`behindDoc="1"` pair.
|
|
557
|
+
- **`ContentStroke.style` (`solid`/`dashed`/`dotted`/`double`) is not written by any vector writer, ODF or DrawingML.** Nothing in this package produces one — `LayoutLine` and `LayoutPath` both carry a stroke of colour and width only (`document-schema.js`'s `layout.ts`), so no reconstruction path can populate it — and `a:prstDash` has no `double` member to map the fourth value onto regardless. A hand-built `ContentVector` setting it consequently paints solid. A real, bounded gap rather than an oversight.
|
|
555
558
|
- **`pdfToOds` recovers what was printed, not what was entered.** `reconstructSpreadsheet` (`src/layout/reconstruct.ts`) tries a real gridline lattice first: it scans the page's `LayoutLine`/stroked-single-segment-`LayoutPath` items (see the `interpret.ts` gotcha above) for enough parallel horizontal and vertical lines at consistent positions to call it a printed grid (`MIN_GRIDLINE_COUNT_PER_AXIS = 3` per axis, i.e. at least a 2×2 grid, and a span-consistency check that rejects a scatter of unrelated short strokes — a page border or a couple of decorative rules — as not a genuine lattice), and uses those line positions DIRECTLY as cell boundaries when found. Absent a lattice, it clusters text into a grid from geometry alone instead: rows reuse `clusterIntoLines` verbatim (a spreadsheet cell's own text is never wrapped across lines, so a text line already IS a row), and columns generalise `clusterIntoParagraphs`'s own single `dominantLeftX` to several recurring x-position anchors, first merging directly-adjacent same-line fragments (`splitLineByLargeGaps`, the same >2em-gap signal `reconstructPresentation`'s own block clustering uses) so a cell whose text arrived as several run-level-split `LayoutText` items isn't scattered across spurious columns. Column widths and row heights are genuinely measured from whichever geometry was used (drawn gridline gaps, or measured text/anchor extents), never invented. Every recovered cell always carries its own extracted `displayText` verbatim, and additionally carries a **heuristically re-typed** `value` wherever `src/layout/cell-typing.ts` finds exactly one defensible reading of that string; a formula is still never claimed. See the dedicated heuristic-re-typing gotcha below and [Fidelity](#fidelity) for the full framing. `buildOdsPackage` (`src/edit/ods/content.ts`) is `pdfToOds`'s own package-building half, mirroring `buildOdtPackage`/`buildOdpPackage`/`buildOdgPackage`'s role for `pdfToOdt`/`pdfToOdp`/`pdfToOdg`.
|
|
556
559
|
- **`OdsSheet.printSettings` (`src/edit/ods/print-settings.ts`) now round-trips every field `ContentSheetPrintSettingsSchema` carries, not just the five it started with.** `pageSize`/`margins`/`gridlines`/`headers`/`pageOrder` resolve through the `table:style-name` → `style:style[family="table"]` → `style:master-page-name` → `style:master-page` → `style:page-layout` → `style:page-layout-properties` chain (`odf.js`'s own exported `findStyleElement`/`resolvePageLayoutProperties`/`parsePageSize`/`parseMargins`); the setter mints a fresh `style:page-layout` + `style:master-page` + `style:style[family="table"]` triple and repoints the sheet's own `table:style-name` to it on every call, the same append-only style-editing convention `src/edit/odg/style.ts` already documents. The remaining, previously-unimplemented fields are now implemented too: `printRange` reads/writes `table:print-ranges` directly on `table:table`; `scalePercent`/`fitToPages` read/write `style:scale-to` and `style:scale-to-X`/`style:scale-to-Y` on the page-layout-properties element; `repeatColumns`/`repeatRows` are read via `scanTableStructure`, a scoped-down mirror of `odf.js`'s own private `readTable`'s table-wide column/row cursor tracking (the same walk that function performs before ever calling its own `readPrintSettings`), and written by moving the real `table:table-column`/`table:table-row` elements covering the given range into a fresh `table:table-header-columns`/`table:table-header-rows` wrapper; `manualBreaks` read/write `fo:break-before="page"` on the named row/column's own style. Writing `repeatRows`/`repeatColumns` required teaching `address.ts`'s row/column addressing that a row/column may now live nested one level inside a header wrapper rather than as a direct `table:table` child, so a subsequent cell/column/row write against a wrapped index finds the real element instead of creating a spurious duplicate outside it; the width/height and manual-break writers all target the same `style:table-column-properties`/`style:table-row-properties` element, so each reads the column/row's current style first and mints a fresh style carrying the merged result, rather than a naive single-property mint clobbering whatever an earlier call had already set. No known gap remains in `ContentSheetPrintSettingsSchema` coverage.
|
|
557
560
|
- **`OdsSheet` now has a real column-width/row-height setter (`setColumnWidth`/`setRowHeight`, `src/edit/ods/column-row.ts`), closing a gap that escalated from cosmetic to a genuine correctness bug once `xlsxToPdf`/`pdfToXlsx` started composing through `buildOdsPackage` internally.** `OdsSheet.cell()`'s own column/row-materialisation (`address.ts`) creates a real, explicit `table:table-column`/`table:table-row` element for any position a caller ever addresses, but previously never gave it a width/height style. This is a genuinely different failure shape from a column/row with NO element at all: `sheets.ts`'s own `resolveAxis` only falls back to `DEFAULT_COLUMN_WIDTH_PT`/`DEFAULT_ROW_HEIGHT_PT` for an index with no `ContentSheetColumn`/`ContentSheetRow` entry whatsoever — an explicit-but-unstyled element reads back at `widthPt`/`heightPt` 0 (`odf.js`'s own `resolveColumnWidthPt`/`readRowLayout`), and that explicit zero wins over the fallback. While `buildOdsPackage`'s own output was only ever a terminal deliverable (`pdfToOds`, or a caller's own `readOdsContent` round trip), this was cosmetic: a real app reopening it would use its own defaults instead of the source's. `xlsxToPdf` (`xlsxToOds` then `odsToPdf`) made it a real bug instead — the intermediate ods bytes get laid out again by `convertSpreadsheetToLayout`, and a zero-size grid collapses every cell onto the same physical position rather than merely losing precision. `setColumnWidth`/`setRowHeight` mint a fresh `style:style[family="table-column"|"table-row"]` per column/row and repoint its own `table:style-name`, the same append-only style-minting convention `writeSheetPrintSettings`/`src/edit/odg/style.ts` already establish; `buildOdsPackage` now calls both for every `ContentSheetColumn`/`ContentSheetRow` a source sheet carries. Column/row HIDDEN state and `ContentSheetImage`/formula `embeddedObjects` are no longer gaps either, closed in the same phase: `OdsSheet.setColumnHidden`/`setRowHidden` set or clear `table:visibility="collapse"` directly on the `table:table-column`/`table:table-row` element — a plain attribute, not a style property, so it never interacts with the width/height setters above — and `buildOdsPackage` calls one of these for every column/row whose `hidden` field is `true`. `OdsSheet.addImage` (`src/edit/ods/floating.ts`) writes a real floating `draw:frame`/`draw:image` into `table:shapes` (the ODF 1.3 content-model container for spreadsheet floating shapes, always `table:table`'s own first child in a package this editor builds), resolving a `ContentSheetImage`'s `anchorRow`/`anchorColumn` plus `offsetXPt`/`offsetYPt` to an absolute `svg:x`/`svg:y` by summing the real, currently-declared width/height of every column/row strictly before the anchor (header-wrapper-aware, hidden columns/rows contributing zero, falling back to the same default column/row size the layout engine assumes once the walk runs past what the sheet has declared) — reusing `addImageMedia` for the binary part and manifest entry, the same mechanism `src/edit/odp/image.ts` already uses for a slide. `OdsSheet.addEmbeddedObject` writes a real embedded ODF formula sub-document for `objectKind === 'formula'` (reusing `addFormulaObject`, the same mechanism `OdtBody.appendFormula` already uses); every other `objectKind` (`wordprocessing`/`presentation`/`spreadsheet`/`drawing`) is left unwritten, a documented, bounded gap mirroring `buildOdtPackage`'s identical narrowing for a `'drawing'` embedded object, since embedding one would mean writing that document's own package as a nested OLE sub-object, which no writer in this codebase implements. `buildOdsPackage` calls both for every sheet's images/embedded objects, after every column/row width/height/hidden call, so an image's own anchor resolves against the sheet's final, real column/row sizing. This is write-only for now: `odf.js`'s own `readOds` does not read ods floating shapes or embedded objects back at all (`images` hardcoded to `[]`, `embeddedObjects` never set — see the embedded-formula-detection gotcha below), so there is no `ContentDocument` re-read to verify a round trip against; every test verifies the real written package/XML structure directly instead, via `odf.js`'s own query/manifest/formula-reading primitives and a genuine zip encode/decode round trip.
|
|
@@ -564,7 +567,7 @@ To run a single test file: `pnpm vitest run src/path/to/file.test.ts`.
|
|
|
564
567
|
- **A drawing page's `shapes` and `vectors` are two separate arrays, but their true relative paint order is carried by a shared `paintOrder` field on both.** `ContentDrawPageSchema` (`document-schema.js`) still keeps text/image/table content (`shapes`) and vector primitives (`vectors`) apart, but `ContentVector` and `ContentShape` each carry a `paintOrder` — one monotonically increasing per-page document index `odf.js`'s own reader stamps on every element it walks (`typed/draw/shapes.ts`'s `walkDrawPageContent`/`paintOrderKey`, honouring a real `draw:z-index` where a producer wrote one, falling back to document position otherwise). `convertDrawingToLayout` merges the two arrays back into one true-paint-order walk through that field (`src/model/paint-order.ts`'s `mergeByPaintOrder`), `reconstructDrawing` stamps the same field from its own single walk over a page's recovered items, and `buildOdgPackage` appends in the same merged order (document order *is* paint order in a written `.odg` — this package never emits a `draw:z-index`). A page that genuinely interleaves the two mid-stack — a text label between two rectangles, a rectangle over a picture — consequently paints in the order its author built it, and survives `convertDrawingToLayout` → `reconstructDrawing` with that interleaving intact. The historical "every vector paints before every shape" rule survives only as the documented fallback for a page missing `paintOrder` anywhere (a hand-built `ContentDocument`, or one produced before the field existed), since an item with no value has no defensible position to be sorted into and inventing one would silently reorder content.
|
|
565
568
|
- **A rotated vector primitive renders as a `LayoutPath`, not as a rotated `LayoutRect`/`LayoutEllipse` — because neither of those carries a rotation field at all.** `ContentVectorSchema`'s `rect`/`ellipse`/`path` variants each carry a real `rotationDeg` (the `line` variant does not, and needs none — two endpoints already encode any orientation a line can have), `odf.js`'s own reader resolves one through the same `resolveOdfShapeGeometry` a `draw:frame` uses, and `OdgBoxVector.rotationDeg`/`OdgPathVector.rotationDeg` write one back through the same shared `applyOdfGeometry` (`src/edit/geometry.ts`) `OdpShape.rotationDeg` uses. `convertDrawingToLayout` resolves a rotated vector into a `LayoutPath` whose own points are the shape's corners/curve controls after rotation — a rotated rect becomes a genuine four-point closed subpath, a rotated ellipse its own four cubics rotated — since `LayoutRectSchema`/`LayoutEllipseSchema` model no rotation and only `LayoutText`/`LayoutImage` do (pdf-codec rotates those two through a text/image transformation matrix, which a path-painting operator sequence has no equivalent of). Nothing is approximated by this: an affine rotation maps a straight edge to a straight edge and a cubic Bézier to a cubic Bézier exactly. What a PDF round trip cannot preserve is the `rotationDeg` *field* — a recovered path records where the corners ended up, never that a right-angled box was turned to get there — so `pdfToOdg` returns a rotated rect as an unrotated `path` vector whose geometry is genuinely rotated, the same kind-narrowing every other vector already documents below.
|
|
566
569
|
- **`ContentVector`'s `path` variant's `fillRule` is never populated by the reader — always `undefined`, which `writePath` treats as nonzero.** `odf.js`'s `readDrawPathVector` does not currently resolve an evenodd fill rule from real ODF output, so every path this pipeline reads paints with PDF's default nonzero winding rule. `LayoutPathSchema`/`writePath` fully support `fillRule: 'evenodd'` regardless — a caller constructing a `LayoutPath` (or a future `ContentVector` producer) directly can still set it; it just never arrives via `odgToPdf` today.
|
|
567
|
-
- **A cell's declared border renders solid whatever its `style` says
|
|
570
|
+
- **A cell's declared border still renders solid whatever its `style` says — but the reason moved from "the layout schema has nowhere to carry a dash pattern" to "pdf-codec doesn't read the field yet".** `ContentSheetCellSchema` and `ContentTableCellSchema` both carry real per-cell `background`/`borders` (and `ContentSheetCellSchema` also `alignment`/`verticalAlignment`), `odf.js`'s own reader populates every one of them from a cell's resolved style chain, and `sheets.ts`/`engine.ts` render all of them: a background becomes a real `LayoutRect`, each declared border edge a real `LayoutLine`, and a cell's own alignment/vertical alignment override the value-kind default and the bottom default respectively. `ContentBorder.style` (`solid`/`dashed`/`dotted`/`double`) now genuinely reaches the `LayoutDocument`: as of `document-schema.js` 2.1.0, `LayoutLineSchema`/`LayoutPathSchema` both carry that same optional `style` enum, and `pushCellBorderLines` (`src/layout/shared.ts`, shared by both `engine.ts`'s docx/odt table-cell borders and `sheets.ts`'s ods/xlsx sheet-cell borders) sets it from `ContentBorder.style` on every emitted `LayoutLine` — the model-to-model plumbing this task closed. What still renders solid regardless is the PDF byte output: the installed `pdf-codec` 1.8.0's own `content-write.ts` `writeLine`/`writePath` always emit a plain stroke (`S`) operator with no dash array, so a non-solid `style` has nowhere to render differently yet — a real, separate, pdf-codec-side gap now, not a documents.js schema one. Rendering `double` as two hand-offset parallel lines was still considered and rejected regardless of which package's gap this is: the offset distance is nowhere in the model, so it would be an invented constant standing in for information the source never carried.
|
|
568
571
|
- **Ordinary text in PDF output now resolves through a real font registry rather than the standard 14 alone, and the standard 14 are only the last resort in that chain.** In order: the source document's own embedded faces (docx's `word/fontTable.xml`, pptx's `p:embeddedFontLst`, ODF's `office:font-face-decls` — see [Fonts](#fonts)), then any face the caller supplied through `options.fonts`, then pdf-codec's vendored Carlito/Caladea faces (genuinely metric-compatible with Calibri/Cambria, and embedded as real subsetted TrueType programs), then the standard 14. Helvetica/Times-Roman remain metric-compatible substitutes for Arial/Times New Roman, so a document asking for either still resolves to a standard font and embeds nothing. What is still not covered: a family with no embedded face, no caller-supplied face, and no vendored substitute — Aptos, say, or any third-party typeface — still renders through the nearest standard-14 face with a width-correction factor, so line wrapping and pagination will drift slightly from what Word itself would produce. Expect a faithful visual approximation there, not a line-identical reproduction. MathML formula rendering (`odfToPdf`, and formulas embedded inside odt/odp) is separate from all of this and always was: it embeds the real STIX Two Math font, which is not a registry-resolvable face and cannot be overridden by `options.fonts` — see the CFF-embedding gotcha below, and pdf-codec's own README, for the exact scope of that embedding (the whole `CFF ` table, not glyph-subsetted).
|
|
569
572
|
- **Justified paragraphs now stretch real inter-word gaps in all three layout engines — the flow one (`engine.ts`), the direct-placement one (`slides.ts`), and the spreadsheet one (`sheets.ts`).** `justifyLineGapsPt` (`src/layout/shared.ts`) recovers each wrapped line's own word-gap positions from a line's per-fragment `xOffsetPt` (a genuine gap wider than floating-point noise means a space stood there; two touching fragments are one word split across a run boundary, and stay touching), divides the line's slack evenly across every detected gap, and returns an all-zero shift whenever there is nothing to stretch (fewer than two fragments, no detected gap, or a line already at or past its target width — this function only ever adds space, never compresses). `layoutParagraphFlow`/`layoutParagraphInCell` (`engine.ts`, covering docx/odt paragraphs, docx/odt tables, and odm-assembled chapters) and `layoutParagraph` (`slides.ts`, covering pptx/odp shape text and slide-table cells) call it for every wrapped, non-final line of a `'justify'`-aligned paragraph; the paragraph's own final line (or a paragraph that never wraps at all) stays left-aligned, matching Word/LibreOffice/Impress's own convention. `sheets.ts`'s `renderCellText` calls it too, but a spreadsheet cell only ever renders one line by this module's own documented scope, so the "non-final line" case only arises when a cell's source text carries an explicit line break — `wrapRunsToWidth` then produces more than one line, of which only the first is ever rendered, and that first line is the genuinely non-final one a justified cell stretches; justification is skipped outright when that line already overflowed its cell (the numeric-`###`/string-spill-or-truncate fragments no longer reflect the natural layout the stretch needs) or for an ordinary single-line cell, matching every real spreadsheet application's own "justify only wraps, never a single line" behaviour. `alignmentOffsetPt` itself still returns `0` for `'justify'` in all three files, unchanged — the whole-line offset it computes is the wrong shape for inter-word stretching, which is why the stretch lives in a second, sibling function each caller applies on top, not a new branch inside it. No known gap remains in inter-word justification across any layout engine this package has.
|
|
570
573
|
- **Reading arbitrary real-world PDFs, encrypted-PDF support, and unsupported image filters (`CCITTFaxDecode`/`JBIG2Decode`/`JPXDecode`) are all pdf-codec's own scope boundaries now, not this package's.** In short: the parser targets cleanly-generated output from mainstream producers rather than adversarial-input robustness; `/Encrypt` in the trailer throws rather than attempting decryption, even for the common empty-user-password case; scanned-fax and JPEG2000 images are skipped with a diagnostic while the rest of the page still reads (JPEG and PNG both pass through losslessly). See pdf-codec's own README for the full statement of each.
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { COLOR_BLACK as COLOR_BLACK$1, Color as LayoutColor, ColorSchema as LayoutColorSchema, colorToRgbHex as colorToRgbHex$1, rgbHexToColor } from "document-schema.js";
|
|
2
|
+
export { rgbHexToColor as a, colorToRgbHex$1 as i, LayoutColor as n, LayoutColorSchema as r, COLOR_BLACK$1 as t };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_model_units = require("../../model/units.cjs");
|
|
3
3
|
const require_edit_docx_editor = require("./editor.cjs");
|
|
4
|
+
const require_model_embedded_drawing = require("../../model/embedded-drawing.cjs");
|
|
4
5
|
const require_model_formula = require("../../model/formula.cjs");
|
|
5
6
|
let ooxml_js = require("ooxml.js");
|
|
6
7
|
//#region src/edit/docx/content.ts
|
|
@@ -122,6 +123,10 @@ function appendBlock(body, block, options) {
|
|
|
122
123
|
else if (block.kind === "embeddedObject") appendEmbeddedObject(body, block, options);
|
|
123
124
|
}
|
|
124
125
|
function appendEmbeddedObject(body, block, options) {
|
|
126
|
+
if (require_model_embedded_drawing.drawingOfBlock(block) !== void 0) {
|
|
127
|
+
body.appendParagraph().appendVectorAnchors(require_model_embedded_drawing.embeddedDrawingVectors(block, require_model_embedded_drawing.FLOW_CONTAINER_ORIGIN));
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
125
130
|
const formula = require_model_formula.formulaOfBlock(block);
|
|
126
131
|
if (formula === void 0) return;
|
|
127
132
|
const paragraph = body.appendParagraph();
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ptToTwips } from "../../model/units.js";
|
|
2
2
|
import { createDocx } from "./editor.js";
|
|
3
|
+
import { FLOW_CONTAINER_ORIGIN, drawingOfBlock, embeddedDrawingVectors } from "../../model/embedded-drawing.js";
|
|
3
4
|
import { formulaOfBlock, formulaPlaceholderText } from "../../model/formula.js";
|
|
4
5
|
import { base64ToBytes } from "ooxml.js";
|
|
5
6
|
//#region src/edit/docx/content.ts
|
|
@@ -121,6 +122,10 @@ function appendBlock(body, block, options) {
|
|
|
121
122
|
else if (block.kind === "embeddedObject") appendEmbeddedObject(body, block, options);
|
|
122
123
|
}
|
|
123
124
|
function appendEmbeddedObject(body, block, options) {
|
|
125
|
+
if (drawingOfBlock(block) !== void 0) {
|
|
126
|
+
body.appendParagraph().appendVectorAnchors(embeddedDrawingVectors(block, FLOW_CONTAINER_ORIGIN));
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
124
129
|
const formula = formulaOfBlock(block);
|
|
125
130
|
if (formula === void 0) return;
|
|
126
131
|
const paragraph = body.appendParagraph();
|
package/dist/edit/docx/image.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { i as insertImageMedia, n as MediaContext, r as buildInlineDrawing, t as ImageInit } from "../../image-
|
|
2
|
-
export { ImageInit, MediaContext, buildInlineDrawing, insertImageMedia };
|
|
1
|
+
import { a as nextDrawingId, i as insertImageMedia, n as MediaContext, r as buildInlineDrawing, t as ImageInit } from "../../image-DRqXQmEg.cjs";
|
|
2
|
+
export { ImageInit, MediaContext, buildInlineDrawing, insertImageMedia, nextDrawingId };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { i as insertImageMedia, n as MediaContext, r as buildInlineDrawing, t as ImageInit } from "../../image-
|
|
2
|
-
export { ImageInit, MediaContext, buildInlineDrawing, insertImageMedia };
|
|
1
|
+
import { a as nextDrawingId, i as insertImageMedia, n as MediaContext, r as buildInlineDrawing, t as ImageInit } from "../../image-DRqXQmEg.js";
|
|
2
|
+
export { ImageInit, MediaContext, buildInlineDrawing, insertImageMedia, nextDrawingId };
|
package/dist/edit/docx/image.js
CHANGED
|
@@ -69,4 +69,4 @@ function insertImageMedia(context, documentRoot, image) {
|
|
|
69
69
|
return buildInlineDrawing(relationshipId, image.widthPt, image.heightPt, id, image.altText);
|
|
70
70
|
}
|
|
71
71
|
//#endregion
|
|
72
|
-
export { buildInlineDrawing, insertImageMedia };
|
|
72
|
+
export { buildInlineDrawing, insertImageMedia, nextDrawingId };
|
|
@@ -5,6 +5,7 @@ const require_xml_edit = require("../../xml/edit.cjs");
|
|
|
5
5
|
const require_edit_docx_image = require("./image.cjs");
|
|
6
6
|
const require_edit_docx_props = require("./props.cjs");
|
|
7
7
|
const require_edit_docx_run = require("./run.cjs");
|
|
8
|
+
const require_edit_docx_vector = require("./vector.cjs");
|
|
8
9
|
let ooxml_js = require("ooxml.js");
|
|
9
10
|
//#region src/edit/docx/paragraph.ts
|
|
10
11
|
function directChild(parent, tag) {
|
|
@@ -29,7 +30,7 @@ var DocxParagraph = class {
|
|
|
29
30
|
return create ? require_edit_docx_props.ensureFirstChild(node, "w:pPr") : directChild(node, "w:pPr");
|
|
30
31
|
}
|
|
31
32
|
get text() {
|
|
32
|
-
return
|
|
33
|
+
return require_edit_docx_run.wordprocessingText(this.live());
|
|
33
34
|
}
|
|
34
35
|
runs() {
|
|
35
36
|
const node = this.live();
|
|
@@ -118,6 +119,14 @@ var DocxParagraph = class {
|
|
|
118
119
|
written: true
|
|
119
120
|
};
|
|
120
121
|
}
|
|
122
|
+
appendVectorAnchors(vectors) {
|
|
123
|
+
const node = this.live();
|
|
124
|
+
if (this.imageContext === void 0) throw new Error("appendVectorAnchors requires a paragraph opened through a DocxEditor");
|
|
125
|
+
const { documentRoot } = this.imageContext;
|
|
126
|
+
vectors.forEach((vector, index) => {
|
|
127
|
+
node.children.push(require_xml_fragment.el("w:r", {}, [require_edit_docx_vector.buildAnchoredVectorDrawing(vector, require_edit_docx_image.nextDrawingId(documentRoot), index)]));
|
|
128
|
+
});
|
|
129
|
+
}
|
|
121
130
|
insertImageAfter(image) {
|
|
122
131
|
const node = this.live();
|
|
123
132
|
if (this.imageContext === void 0) throw new Error("insertImageAfter requires a paragraph opened through a DocxEditor");
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { r as MathMlNode$1 } from "../../nodes-pArN9ilm.cjs";
|
|
2
2
|
import { t as OmmlWriteResult } from "../../write-BQ6SK8r8.cjs";
|
|
3
|
-
import { n as MediaContext, t as ImageInit } from "../../image-
|
|
4
|
-
import { n as RunInit, t as DocxRun } from "../../run-
|
|
5
|
-
import { ContentListMembership } from "document-schema.js";
|
|
3
|
+
import { n as MediaContext, t as ImageInit } from "../../image-DRqXQmEg.cjs";
|
|
4
|
+
import { n as RunInit, t as DocxRun } from "../../run-P0b2pDdX.cjs";
|
|
5
|
+
import { ContentListMembership, ContentVector } from "document-schema.js";
|
|
6
6
|
import { Package, XmlElement, XmlNode } from "ooxml.js";
|
|
7
7
|
//#region src/edit/docx/paragraph.d.ts
|
|
8
8
|
interface ParagraphInit {
|
|
@@ -37,6 +37,7 @@ declare class DocxParagraph {
|
|
|
37
37
|
appendOfficeMath(mathml: readonly MathMlNode$1[]): OmmlWriteResult & {
|
|
38
38
|
readonly written: boolean;
|
|
39
39
|
};
|
|
40
|
+
appendVectorAnchors(vectors: readonly ContentVector[]): void;
|
|
40
41
|
insertImageAfter(image: ImageInit): void;
|
|
41
42
|
remove(): void;
|
|
42
43
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { r as MathMlNode$1 } from "../../nodes-pArN9ilm.js";
|
|
2
2
|
import { t as OmmlWriteResult } from "../../write-THs7ipBq.js";
|
|
3
|
-
import { n as MediaContext, t as ImageInit } from "../../image-
|
|
4
|
-
import { n as RunInit, t as DocxRun } from "../../run-
|
|
3
|
+
import { n as MediaContext, t as ImageInit } from "../../image-DRqXQmEg.js";
|
|
4
|
+
import { n as RunInit, t as DocxRun } from "../../run-BhYv2wJf.js";
|
|
5
5
|
import { Package, XmlElement, XmlNode } from "ooxml.js";
|
|
6
|
-
import { ContentListMembership } from "document-schema.js";
|
|
6
|
+
import { ContentListMembership, ContentVector } from "document-schema.js";
|
|
7
7
|
//#region src/edit/docx/paragraph.d.ts
|
|
8
8
|
interface ParagraphInit {
|
|
9
9
|
readonly text?: string;
|
|
@@ -37,6 +37,7 @@ declare class DocxParagraph {
|
|
|
37
37
|
appendOfficeMath(mathml: readonly MathMlNode$1[]): OmmlWriteResult & {
|
|
38
38
|
readonly written: boolean;
|
|
39
39
|
};
|
|
40
|
+
appendVectorAnchors(vectors: readonly ContentVector[]): void;
|
|
40
41
|
insertImageAfter(image: ImageInit): void;
|
|
41
42
|
remove(): void;
|
|
42
43
|
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { el } from "../../xml/fragment.js";
|
|
2
2
|
import { buildOfficeMathParagraph } from "../../omml/write.js";
|
|
3
3
|
import { getOrCreateChildElement, removeChild } from "../../xml/edit.js";
|
|
4
|
-
import { insertImageMedia } from "./image.js";
|
|
4
|
+
import { insertImageMedia, nextDrawingId } from "./image.js";
|
|
5
5
|
import { PPR_ORDER, ensureFirstChild, getAlignment, getStyleId, setAlignment, setStyleId } from "./props.js";
|
|
6
|
-
import { DocxRun, buildRun } from "./run.js";
|
|
7
|
-
import {
|
|
6
|
+
import { DocxRun, buildRun, wordprocessingText } from "./run.js";
|
|
7
|
+
import { buildAnchoredVectorDrawing } from "./vector.js";
|
|
8
|
+
import { attr } from "ooxml.js";
|
|
8
9
|
//#region src/edit/docx/paragraph.ts
|
|
9
10
|
function directChild(parent, tag) {
|
|
10
11
|
for (const child of parent.children) if (child.type === "element" && child.tag === tag) return child;
|
|
@@ -28,7 +29,7 @@ var DocxParagraph = class {
|
|
|
28
29
|
return create ? ensureFirstChild(node, "w:pPr") : directChild(node, "w:pPr");
|
|
29
30
|
}
|
|
30
31
|
get text() {
|
|
31
|
-
return
|
|
32
|
+
return wordprocessingText(this.live());
|
|
32
33
|
}
|
|
33
34
|
runs() {
|
|
34
35
|
const node = this.live();
|
|
@@ -117,6 +118,14 @@ var DocxParagraph = class {
|
|
|
117
118
|
written: true
|
|
118
119
|
};
|
|
119
120
|
}
|
|
121
|
+
appendVectorAnchors(vectors) {
|
|
122
|
+
const node = this.live();
|
|
123
|
+
if (this.imageContext === void 0) throw new Error("appendVectorAnchors requires a paragraph opened through a DocxEditor");
|
|
124
|
+
const { documentRoot } = this.imageContext;
|
|
125
|
+
vectors.forEach((vector, index) => {
|
|
126
|
+
node.children.push(el("w:r", {}, [buildAnchoredVectorDrawing(vector, nextDrawingId(documentRoot), index)]));
|
|
127
|
+
});
|
|
128
|
+
}
|
|
120
129
|
insertImageAfter(image) {
|
|
121
130
|
const node = this.live();
|
|
122
131
|
if (this.imageContext === void 0) throw new Error("insertImageAfter requires a paragraph opened through a DocxEditor");
|
package/dist/edit/docx/run.cjs
CHANGED
|
@@ -3,9 +3,15 @@ const require_xml_fragment = require("../../xml/fragment.cjs");
|
|
|
3
3
|
const require_xml_entities = require("../../xml/entities.cjs");
|
|
4
4
|
const require_xml_edit = require("../../xml/edit.cjs");
|
|
5
5
|
const require_edit_docx_props = require("./props.cjs");
|
|
6
|
+
const require_xml_query = require("../../xml/query.cjs");
|
|
6
7
|
let ooxml_js = require("ooxml.js");
|
|
7
8
|
let document_schema_js = require("document-schema.js");
|
|
8
9
|
//#region src/edit/docx/run.ts
|
|
10
|
+
function wordprocessingText(element) {
|
|
11
|
+
let out = "";
|
|
12
|
+
for (const cursor of require_xml_query.walkElements([element])) if (cursor.node.tag === "w:t") out += (0, ooxml_js.textContent)(cursor.node);
|
|
13
|
+
return out;
|
|
14
|
+
}
|
|
9
15
|
function directChild(parent, tag) {
|
|
10
16
|
for (const child of parent.children) if (child.type === "element" && child.tag === tag) return child;
|
|
11
17
|
}
|
|
@@ -38,7 +44,7 @@ var DocxRun = class {
|
|
|
38
44
|
return create ? require_edit_docx_props.ensureFirstChild(node, "w:rPr") : directChild(node, "w:rPr");
|
|
39
45
|
}
|
|
40
46
|
get text() {
|
|
41
|
-
return (
|
|
47
|
+
return wordprocessingText(this.live());
|
|
42
48
|
}
|
|
43
49
|
set text(value) {
|
|
44
50
|
const tNode = findOrCreateT(this.live());
|
|
@@ -141,3 +147,4 @@ function buildRun(init = {}) {
|
|
|
141
147
|
//#endregion
|
|
142
148
|
exports.DocxRun = DocxRun;
|
|
143
149
|
exports.buildRun = buildRun;
|
|
150
|
+
exports.wordprocessingText = wordprocessingText;
|
package/dist/edit/docx/run.d.cts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as RunInit, r as buildRun, t as DocxRun } from "../../run-
|
|
2
|
-
export { DocxRun, RunInit, buildRun };
|
|
1
|
+
import { i as wordprocessingText, n as RunInit, r as buildRun, t as DocxRun } from "../../run-P0b2pDdX.cjs";
|
|
2
|
+
export { DocxRun, RunInit, buildRun, wordprocessingText };
|
package/dist/edit/docx/run.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as RunInit, r as buildRun, t as DocxRun } from "../../run-
|
|
2
|
-
export { DocxRun, RunInit, buildRun };
|
|
1
|
+
import { i as wordprocessingText, n as RunInit, r as buildRun, t as DocxRun } from "../../run-BhYv2wJf.js";
|
|
2
|
+
export { DocxRun, RunInit, buildRun, wordprocessingText };
|
package/dist/edit/docx/run.js
CHANGED
|
@@ -3,8 +3,14 @@ import { el, txt } from "../../xml/fragment.js";
|
|
|
3
3
|
import { encodeXmlText, needsSpacePreserve } from "../../xml/entities.js";
|
|
4
4
|
import { removeChild, setAttr } from "../../xml/edit.js";
|
|
5
5
|
import { RPR_ORDER, ensureFirstChild, getColor, getFontFamily, getSizePt, getToggle, setColor, setFontFamily, setSizePt, setToggle } from "./props.js";
|
|
6
|
+
import { walkElements } from "../../xml/query.js";
|
|
6
7
|
import { textContent } from "ooxml.js";
|
|
7
8
|
//#region src/edit/docx/run.ts
|
|
9
|
+
function wordprocessingText(element) {
|
|
10
|
+
let out = "";
|
|
11
|
+
for (const cursor of walkElements([element])) if (cursor.node.tag === "w:t") out += textContent(cursor.node);
|
|
12
|
+
return out;
|
|
13
|
+
}
|
|
8
14
|
function directChild(parent, tag) {
|
|
9
15
|
for (const child of parent.children) if (child.type === "element" && child.tag === tag) return child;
|
|
10
16
|
}
|
|
@@ -37,7 +43,7 @@ var DocxRun = class {
|
|
|
37
43
|
return create ? ensureFirstChild(node, "w:rPr") : directChild(node, "w:rPr");
|
|
38
44
|
}
|
|
39
45
|
get text() {
|
|
40
|
-
return
|
|
46
|
+
return wordprocessingText(this.live());
|
|
41
47
|
}
|
|
42
48
|
set text(value) {
|
|
43
49
|
const tNode = findOrCreateT(this.live());
|
|
@@ -138,4 +144,4 @@ function buildRun(init = {}) {
|
|
|
138
144
|
return run;
|
|
139
145
|
}
|
|
140
146
|
//#endregion
|
|
141
|
-
export { DocxRun, buildRun };
|
|
147
|
+
export { DocxRun, buildRun, wordprocessingText };
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_xml_fragment = require("../../xml/fragment.cjs");
|
|
3
|
+
const require_model_units = require("../../model/units.cjs");
|
|
4
|
+
const require_edit_drawingml_vector = require("../drawingml/vector.cjs");
|
|
5
|
+
//#region src/edit/docx/vector.ts
|
|
6
|
+
const DRAWING_NS = {
|
|
7
|
+
wp: "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing",
|
|
8
|
+
a: "http://schemas.openxmlformats.org/drawingml/2006/main",
|
|
9
|
+
wps: "http://schemas.microsoft.com/office/word/2010/wordprocessingShape"
|
|
10
|
+
};
|
|
11
|
+
const ANCHOR_ATTRS = {
|
|
12
|
+
distT: "0",
|
|
13
|
+
distB: "0",
|
|
14
|
+
distL: "0",
|
|
15
|
+
distR: "0",
|
|
16
|
+
simplePos: "0",
|
|
17
|
+
locked: "0",
|
|
18
|
+
layoutInCell: "1",
|
|
19
|
+
allowOverlap: "1",
|
|
20
|
+
behindDoc: "1"
|
|
21
|
+
};
|
|
22
|
+
function position(tag, offsetPt) {
|
|
23
|
+
return require_xml_fragment.el(tag, { relativeFrom: "page" }, [require_xml_fragment.el("wp:posOffset", {}, [require_xml_fragment.txt(String(require_model_units.ptToEmu(offsetPt)))])]);
|
|
24
|
+
}
|
|
25
|
+
function buildAnchoredVectorDrawing(vector, drawingId, relativeHeight) {
|
|
26
|
+
const frame = require_edit_drawingml_vector.vectorPlacementBox(vector);
|
|
27
|
+
const cx = String(require_model_units.ptToEmu(frame.widthPt));
|
|
28
|
+
const cy = String(require_model_units.ptToEmu(frame.heightPt));
|
|
29
|
+
const name = require_edit_drawingml_vector.vectorShapeName(vector, drawingId);
|
|
30
|
+
const wsp = require_xml_fragment.el("wps:wsp", {}, [
|
|
31
|
+
require_xml_fragment.el("wps:cNvSpPr"),
|
|
32
|
+
require_xml_fragment.el("wps:spPr", {}, require_edit_drawingml_vector.buildVectorShapeProperties(vector)),
|
|
33
|
+
require_xml_fragment.el("wps:bodyPr")
|
|
34
|
+
]);
|
|
35
|
+
const anchor = require_xml_fragment.el("wp:anchor", {
|
|
36
|
+
...ANCHOR_ATTRS,
|
|
37
|
+
relativeHeight: String(relativeHeight)
|
|
38
|
+
}, [
|
|
39
|
+
require_xml_fragment.el("wp:simplePos", {
|
|
40
|
+
x: "0",
|
|
41
|
+
y: "0"
|
|
42
|
+
}),
|
|
43
|
+
position("wp:positionH", frame.xPt),
|
|
44
|
+
position("wp:positionV", frame.yPt),
|
|
45
|
+
require_xml_fragment.el("wp:extent", {
|
|
46
|
+
cx,
|
|
47
|
+
cy
|
|
48
|
+
}),
|
|
49
|
+
require_xml_fragment.el("wp:effectExtent", {
|
|
50
|
+
l: "0",
|
|
51
|
+
t: "0",
|
|
52
|
+
r: "0",
|
|
53
|
+
b: "0"
|
|
54
|
+
}),
|
|
55
|
+
require_xml_fragment.el("wp:wrapNone"),
|
|
56
|
+
require_xml_fragment.el("wp:docPr", {
|
|
57
|
+
id: String(drawingId),
|
|
58
|
+
name
|
|
59
|
+
}),
|
|
60
|
+
require_xml_fragment.el("a:graphic", {}, [require_xml_fragment.el("a:graphicData", { uri: DRAWING_NS.wps }, [wsp])])
|
|
61
|
+
]);
|
|
62
|
+
return require_xml_fragment.el("w:drawing", {
|
|
63
|
+
"xmlns:wp": DRAWING_NS.wp,
|
|
64
|
+
"xmlns:a": DRAWING_NS.a,
|
|
65
|
+
"xmlns:wps": DRAWING_NS.wps
|
|
66
|
+
}, [anchor]);
|
|
67
|
+
}
|
|
68
|
+
//#endregion
|
|
69
|
+
exports.buildAnchoredVectorDrawing = buildAnchoredVectorDrawing;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { ContentVector } from "document-schema.js";
|
|
2
|
+
import { XmlElement } from "ooxml.js";
|
|
3
|
+
//#region src/edit/docx/vector.d.ts
|
|
4
|
+
declare function buildAnchoredVectorDrawing(vector: ContentVector, drawingId: number, relativeHeight: number): XmlElement;
|
|
5
|
+
//#endregion
|
|
6
|
+
export { buildAnchoredVectorDrawing };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { XmlElement } from "ooxml.js";
|
|
2
|
+
import { ContentVector } from "document-schema.js";
|
|
3
|
+
//#region src/edit/docx/vector.d.ts
|
|
4
|
+
declare function buildAnchoredVectorDrawing(vector: ContentVector, drawingId: number, relativeHeight: number): XmlElement;
|
|
5
|
+
//#endregion
|
|
6
|
+
export { buildAnchoredVectorDrawing };
|