reamkit 1.29.0 → 1.31.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 +60 -24
- package/dist/esm/core/converter/project.js +3 -1
- package/dist/esm/core/crypto/offcrypto.js +1 -1
- package/dist/esm/core/document-model/index.d.ts +1 -1
- package/dist/esm/core/document-model/types.d.ts +65 -0
- package/dist/esm/core/drawingml/shape-render.js +13 -1
- package/dist/esm/core/font/index.d.ts +2 -0
- package/dist/esm/core/font/ttf-build.d.ts +113 -0
- package/dist/esm/core/font/ttf-build.js +1224 -0
- package/dist/esm/core/font/ttf-subset.d.ts +19 -0
- package/dist/esm/core/font/ttf-subset.js +14 -1
- package/dist/esm/core/fonts/index.d.ts +1 -1
- package/dist/esm/core/fonts/provider.d.ts +17 -0
- package/dist/esm/core/fonts/provider.js +27 -2
- package/dist/esm/core/fonts/remote-fonts.d.ts +8 -0
- package/dist/esm/core/fonts/remote-fonts.js +108 -18
- package/dist/esm/core/ir/flow.d.ts +88 -1
- package/dist/esm/core/numbering/index.d.ts +1 -1
- package/dist/esm/core/numbering/state.d.ts +11 -1
- package/dist/esm/core/numbering/state.js +10 -1
- package/dist/esm/core/style-cascade/resolver.js +35 -4
- package/dist/esm/core/style-cascade/types.d.ts +19 -1
- package/dist/esm/core/style-cascade/types.js +3 -0
- package/dist/esm/index.d.ts +2 -2
- package/dist/esm/layout/page-doc.d.ts +10 -3
- package/dist/esm/layout/styled-layout.d.ts +48 -7
- package/dist/esm/layout/styled-layout.js +881 -119
- package/dist/esm/layout/turned-section.d.ts +38 -0
- package/dist/esm/layout/turned-section.js +193 -0
- package/dist/esm/pdf/styled-page-emitter.js +78 -2
- package/dist/esm/pdf-reader/annot-draw.js +93 -1
- package/dist/esm/pdf-reader/annots.d.ts +18 -0
- package/dist/esm/pdf-reader/annots.js +86 -9
- package/dist/esm/pdf-reader/cff-outline.d.ts +27 -0
- package/dist/esm/pdf-reader/cff-outline.js +169 -21
- package/dist/esm/pdf-reader/cmap.js +5 -2
- package/dist/esm/pdf-reader/content.d.ts +70 -4
- package/dist/esm/pdf-reader/content.js +172 -12
- package/dist/esm/pdf-reader/display.d.ts +36 -0
- package/dist/esm/pdf-reader/display.js +82 -1
- package/dist/esm/pdf-reader/document.js +5 -1
- package/dist/esm/pdf-reader/embedded-fonts.d.ts +25 -0
- package/dist/esm/pdf-reader/embedded-fonts.js +78 -9
- package/dist/esm/pdf-reader/encodings.d.ts +8 -0
- package/dist/esm/pdf-reader/encodings.js +25 -3
- package/dist/esm/pdf-reader/face-outlines.d.ts +78 -0
- package/dist/esm/pdf-reader/face-outlines.js +362 -0
- package/dist/esm/pdf-reader/figures.d.ts +52 -0
- package/dist/esm/pdf-reader/figures.js +433 -0
- package/dist/esm/pdf-reader/flow-build.d.ts +224 -7
- package/dist/esm/pdf-reader/flow-build.js +545 -39
- package/dist/esm/pdf-reader/font.d.ts +27 -1
- package/dist/esm/pdf-reader/font.js +632 -63
- package/dist/esm/pdf-reader/glyf-outline.d.ts +33 -0
- package/dist/esm/pdf-reader/glyf-outline.js +148 -3
- package/dist/esm/pdf-reader/glyph-names.js +154 -1
- package/dist/esm/pdf-reader/glyph-shapes.d.ts +18 -0
- package/dist/esm/pdf-reader/glyph-shapes.js +57 -0
- package/dist/esm/pdf-reader/image-decode.js +70 -4
- package/dist/esm/pdf-reader/images.d.ts +5 -0
- package/dist/esm/pdf-reader/images.js +4 -2
- package/dist/esm/pdf-reader/jbig2.d.ts +40 -1
- package/dist/esm/pdf-reader/jbig2.js +78 -16
- package/dist/esm/pdf-reader/jpeg.d.ts +6 -3
- package/dist/esm/pdf-reader/jpeg.js +21 -1
- package/dist/esm/pdf-reader/layout.d.ts +119 -2
- package/dist/esm/pdf-reader/layout.js +2219 -184
- package/dist/esm/pdf-reader/lexer.d.ts +10 -0
- package/dist/esm/pdf-reader/lexer.js +17 -0
- package/dist/esm/pdf-reader/page-numbers.d.ts +53 -0
- package/dist/esm/pdf-reader/page-numbers.js +167 -0
- package/dist/esm/pdf-reader/pattern-tint.d.ts +11 -1
- package/dist/esm/pdf-reader/pattern-tint.js +21 -3
- package/dist/esm/pdf-reader/regions.d.ts +25 -0
- package/dist/esm/pdf-reader/regions.js +167 -0
- package/dist/esm/pdf-reader/shading.d.ts +58 -2
- package/dist/esm/pdf-reader/shading.js +181 -11
- package/dist/esm/pdf-reader/struct-tree.js +112 -8
- package/dist/esm/pdf-reader/tagged.js +207 -28
- package/dist/esm/pdf-reader/text-rules.js +1 -1
- package/dist/esm/pdf-reader/text.d.ts +6 -3
- package/dist/esm/pdf-reader/text.js +106 -22
- package/dist/esm/pdf-reader/type1-outline.d.ts +11 -0
- package/dist/esm/pdf-reader/type1-outline.js +63 -8
- package/dist/esm/pdf-reader/vector.d.ts +8 -2
- package/dist/esm/pdf-reader/vector.js +105 -6
- package/dist/esm/word/doc/doc-reader.js +6 -2
- package/dist/esm/word/doc/doc-text.d.ts +6 -0
- package/dist/esm/word/doc/doc-text.js +19 -1
- package/dist/esm/word/document-parser.d.ts +2 -2
- package/dist/esm/word/document-parser.js +11 -1
- package/dist/esm/word/docx-reader.js +5 -3
- package/dist/esm/word/docx-writer.js +341 -54
- package/dist/esm/word/drawing-parser.d.ts +5 -3
- package/dist/esm/word/drawing-parser.js +56 -10
- package/dist/esm/word/font-embed.d.ts +30 -0
- package/dist/esm/word/font-embed.js +173 -0
- package/dist/esm/word/font-table.d.ts +10 -0
- package/dist/esm/word/font-table.js +13 -1
- package/dist/esm/word/index.js +1 -1
- package/dist/esm/word/numbering-parser.d.ts +3 -1
- package/dist/esm/word/numbering-parser.js +2 -1
- package/dist/esm/word/paragraph-properties.d.ts +7 -6
- package/dist/esm/word/paragraph-properties.js +16 -2
- package/dist/esm/word/run-properties.js +26 -0
- package/package.json +12 -5
package/README.md
CHANGED
|
@@ -27,10 +27,12 @@ Runtime dependencies are minimal: `fflate` (ZIP/Deflate) and `fast-xml-parser`.
|
|
|
27
27
|
## Usage
|
|
28
28
|
|
|
29
29
|
Parse once into the format-neutral interlayer, convert to any target. The
|
|
30
|
-
format
|
|
30
|
+
format is sniffed from the bytes; no fonts to wire up — an open
|
|
31
31
|
metric-compatible substitute font (Arimo for sans, Tinos for serif, Cousine for
|
|
32
32
|
monospace, plus Carlito/Caladea for Calibri/Cambria — the same families LibreOffice
|
|
33
|
-
substitutes) is fetched automatically based on the document's referenced fonts
|
|
33
|
+
substitutes) is fetched automatically based on the document's referenced fonts,
|
|
34
|
+
with a Noto face for the Japanese, Korean, Chinese, Arabic, Hebrew or Thai text
|
|
35
|
+
the document holds:
|
|
34
36
|
|
|
35
37
|
```ts
|
|
36
38
|
import { Ream } from 'reamkit';
|
|
@@ -38,7 +40,7 @@ import { Ream } from 'reamkit';
|
|
|
38
40
|
// e.g. from an <input type="file"> or a fetch() — anything that yields bytes.
|
|
39
41
|
const bytes = new Uint8Array(await file.arrayBuffer());
|
|
40
42
|
|
|
41
|
-
const doc = Ream.parse(bytes); // docx, xlsx, pptx or
|
|
43
|
+
const doc = Ream.parse(bytes); // docx, xlsx, pptx, pdf, doc, xls or ppt — sniffed
|
|
42
44
|
const pdf = await doc.convert('pdf'); // async — fetches a font if needed
|
|
43
45
|
const svg = await doc.convert('svg'); // same parse, different target
|
|
44
46
|
const html = await doc.convert('html'); // flowed HTML — needs no fonts at all
|
|
@@ -57,6 +59,13 @@ and `doc.convertWithReport(...)` returns `{ bytes, losses }` (pass
|
|
|
57
59
|
are plain `Uint8Array`s, so wiring this to files, the network, or disk is up
|
|
58
60
|
to you.
|
|
59
61
|
|
|
62
|
+
An encrypted source opens with its password — a PDF's user password, or an
|
|
63
|
+
Office package's (MS-OFFCRYPTO, Agile and Standard):
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
const doc = Ream.parse(bytes, { password: 'secret' });
|
|
67
|
+
```
|
|
68
|
+
|
|
60
69
|
### Bring your own fonts (no network)
|
|
61
70
|
|
|
62
71
|
To embed specific fonts — or to avoid the network entirely — pass the font
|
|
@@ -139,7 +148,7 @@ rendering — inspect or analyze it without converting:
|
|
|
139
148
|
|
|
140
149
|
```ts
|
|
141
150
|
const doc = Ream.parse(bytes);
|
|
142
|
-
doc.format; // 'docx' | 'xlsx' | 'pptx' | 'pdf'
|
|
151
|
+
doc.format; // 'docx' | 'xlsx' | 'pptx' | 'pdf' | 'doc' | 'xls' | 'ppt'
|
|
143
152
|
doc.flow.body; // paragraphs / tables / images / charts …
|
|
144
153
|
doc.losses; // read-time losses
|
|
145
154
|
```
|
|
@@ -157,7 +166,9 @@ const pdf = await doc.convert('pdf', { fonts, hyphenator });
|
|
|
157
166
|
`convert` accepts (beyond the above): `info` (PDF `/Info` metadata — also read
|
|
158
167
|
automatically from the document's `docProps/core.xml`), `attachments`
|
|
159
168
|
(PDF/A-3 associated files), `tagged` (logical structure without full PDF/A),
|
|
160
|
-
`
|
|
169
|
+
`encrypt` (AES-256 with a user and an owner password and the permissions a
|
|
170
|
+
reader keeps: printing, copying, modifying, …), `pageWidth`/`pageHeight`/margins
|
|
171
|
+
overrides.
|
|
161
172
|
|
|
162
173
|
### Lower-level APIs
|
|
163
174
|
|
|
@@ -166,6 +177,9 @@ automatically from the document's `docProps/core.xml`), `attachments`
|
|
|
166
177
|
keeping unused formats out of your bundle); `layoutStyledDocument` produces the
|
|
167
178
|
frozen page model (`PageItem` pages in a top-left `Pt` frame) the page-based
|
|
168
179
|
writers consume (`docxWriter` works from the flow model, before layout).
|
|
180
|
+
- `createConverter({ readers })` — a converter over a reader registry of your
|
|
181
|
+
own: `detect` names the reader that recognises the bytes, and `convert` reads
|
|
182
|
+
and converts them in one call, returning `{ bytes, losses }`.
|
|
169
183
|
- `renderStyledPdf` drives the layout engine directly; the typed document
|
|
170
184
|
model is on the `reamkit/document-model` subpath.
|
|
171
185
|
|
|
@@ -187,27 +201,49 @@ encryption, digital signatures (PKCS#7/ECDSA/PAdES/RFC 3161), SVG page
|
|
|
187
201
|
preview, flowed HTML export, and **docx + xlsx output** (write WordprocessingML
|
|
188
202
|
/ SpreadsheetML back out, incl. round-trips). Reads OOXML Transitional and Strict.
|
|
189
203
|
|
|
204
|
+
A Word document is laid out by Word's own rules, each measured in Word: a line
|
|
205
|
+
as tall as Word sets its faces, two paragraphs standing the larger of their
|
|
206
|
+
spacings apart rather than the sum, widow and orphan control, a heading kept with
|
|
207
|
+
what it heads, table borders that take the room they are wide, a Word 2010
|
|
208
|
+
table placed by its first cell's text, and sections whose lines run down the
|
|
209
|
+
sheet.
|
|
210
|
+
|
|
190
211
|
**Reads PDF, too.** `Ream.parse` accepts a PDF and reconstructs a `FlowDoc` — a
|
|
191
212
|
tagged PDF from its structure tree (headings, tables, lists, reading order), an
|
|
192
|
-
untagged one
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
213
|
+
untagged one from where its glyphs stand: lines and paragraphs at the page's own
|
|
214
|
+
pitch, with their indents and alignment; headings and list items; columns of
|
|
215
|
+
any number, breaking and balancing where the page does; tables ruled or set out
|
|
216
|
+
on stops, within a column or across them; code listings; figures, a drawing and
|
|
217
|
+
the labels set on it kept as one group; the hanging entries of an index; and a
|
|
218
|
+
heading's bar as its shading. Running heads and feet become headers and footers,
|
|
219
|
+
their numbers PAGE fields counted in the page's own numerals — a book's roman
|
|
220
|
+
front matter, and a foot of its own for each side of its spreads.
|
|
221
|
+
|
|
222
|
+
It lifts back the text (via each font's `/ToUnicode`, or the embedded program's
|
|
223
|
+
own `cmap` where there is none, or the glyph names its `/Encoding` states — which
|
|
224
|
+
is all a PDF from TeX gives, its Greek and mathematics included) and the font
|
|
225
|
+
programs themselves: written to `.docx`, each face the page drew with travels
|
|
226
|
+
with the document, rebuilt as TrueType with the page's own advances, kerning and
|
|
227
|
+
ligatures, and embedded where its licence (OS/2 `fsType`) allows — so a line
|
|
228
|
+
breaks where the page broke it, on a machine that has none of its fonts. Raster
|
|
229
|
+
images come back (JPEG verbatim, a CMYK one re-coloured; PNG/Flate/LZW/CCITT-fax
|
|
230
|
+
and **JBIG2** decoded and re-encoded), with `/Link` hyperlinks, form-XObject
|
|
231
|
+
content, annotation and form appearances (drawing one itself where the file
|
|
232
|
+
supplies none), colour set through a named space — device, CIE (`CalGray`,
|
|
233
|
+
`CalRGB`, `Lab`), ICC-based, or a `Separation`/`DeviceN` run through its own
|
|
234
|
+
tint transform — and the page's artwork: filled / stroked / gradient shapes,
|
|
235
|
+
dashes and caps, clipping paths, tiling patterns, stencil image masks, opacity,
|
|
236
|
+
and the Type 3 glyphs that are drawings rather than letters.
|
|
237
|
+
|
|
238
|
+
It honours the layers a file turns off (§8.11 optional content), the box it says
|
|
239
|
+
to show (`/CropBox`) and the way it turns a page (`/Rotate` — a page whose words
|
|
240
|
+
run down its sheet comes back as a section set that way), and it decides for
|
|
241
|
+
itself whether a file is a document to re-flow or a page to keep — a paper is
|
|
242
|
+
mostly lines, a form is mostly marks — and there is nothing to configure: a
|
|
243
|
+
caller cannot know which of the two it was handed. It reads modern compressed
|
|
244
|
+
files (cross-reference + object streams) and encrypted ones (RC4 / AES — the
|
|
245
|
+
user password is passed to `Ream.parse(bytes, { password })`, defaulting to the
|
|
246
|
+
permissions-only case); a filter it does not carry can be handed to it through
|
|
211
247
|
`Ream.parse(bytes, { filters })`.
|
|
212
248
|
|
|
213
249
|
A form or a drawing is not a reflowable document, so the reader keeps it as a
|
|
@@ -28,7 +28,9 @@ function flowRenderOptions(flow) {
|
|
|
28
28
|
...flow.doNotExpandShiftReturn ? { doNotExpandShiftReturn: true } : {},
|
|
29
29
|
...flow.pageBackgroundColorHex ? { pageBackgroundColorHex: flow.pageBackgroundColorHex } : {},
|
|
30
30
|
...flow.pageBackgroundFill ? { pageBackgroundFill: flow.pageBackgroundFill } : {},
|
|
31
|
-
...flow.gutterAtTop ? { gutterAtTop: true } : {}
|
|
31
|
+
...flow.gutterAtTop ? { gutterAtTop: true } : {},
|
|
32
|
+
...flow.typesetBy ? { typesetBy: flow.typesetBy } : {},
|
|
33
|
+
...flow.compatibilityMode !== void 0 ? { compatibilityMode: flow.compatibilityMode } : {}
|
|
32
34
|
};
|
|
33
35
|
}
|
|
34
36
|
//#endregion
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { openCfb } from "../ole/cfb.js";
|
|
2
1
|
import { aesCbcDecrypt, aesEcbDecrypt, sha1, sha256, sha384, sha512 } from "./primitives.js";
|
|
2
|
+
import { openCfb } from "../ole/cfb.js";
|
|
3
3
|
//#region src/core/crypto/offcrypto.ts
|
|
4
4
|
/** Thrown when the bytes are encrypted and the password does not open them. */
|
|
5
5
|
var WrongPasswordError = class extends Error {
|
|
@@ -5,4 +5,4 @@
|
|
|
5
5
|
*
|
|
6
6
|
* @packageDocumentation
|
|
7
7
|
*/
|
|
8
|
-
export type { AbstractNumbering, Alignment, Border, BorderStyle, BodyElement, Comment, CellBorders, CellMerge, DocumentInfo, CellMargins, CellProperties, CellShading, CellDataBar, CellIcon, CellIconShape, CellSparkline, Chart, ChartBlock, ChartDataPoint, ChartLineStyle, ChartMarker, ChartMarkerSymbol, ChartSeries, ChartType, CustomGeometry, CustomPathCmd, DocumentModel, FontFamilyMap, HeaderFooterReference, HeaderFooterType, ImageBlock, ImageCrop, InlineImage, MathAccent, MathBar, MathDelimiter, MathEqArray, MathFraction, MathFunc, MathGroupChr, MathLimit, MathMatrix, MathNary, MathNode, MathRadical, MathRow, MathRun, MathScript, Numbering, NumberingFormat, NumberingInstance, NumberingLevel, PictureBullet, PictureOutline, NumberingReference, PageMargins, PageSize, Paragraph, ParagraphProperties, FrameProperties, RelativeSize, TabStop, Run, RunProperties, TextOutline, RowConditionalFormat, RowProperties, Section, FloatAnchor, SectionColumns, SectionProperties, ShapeBlock, ShapeShadow, ShapeDash, ShapeFill, ShapeFillKind, ShapeGeometry, ShapeGroupChild, ShapeLine, LineEnd, ShapeTextBody, ShapeTransform, Style, StyleSheet, StyleType, Table, TableCell, TableLook, TableProperties, TableStyleCondition, TableStyleConditionType, TableStyleLayer, TableRow, UnderlineStyle, VerticalAlign, } from './types.js';
|
|
8
|
+
export type { AbstractNumbering, Alignment, Border, BorderStyle, BodyElement, Comment, CellBorders, CellMerge, DocumentInfo, CellMargins, CellProperties, CellShading, CellDataBar, CellIcon, CellIconShape, CellSparkline, Chart, ChartBlock, ChartDataPoint, ChartLineStyle, ChartMarker, ChartMarkerSymbol, ChartSeries, ChartType, CustomGeometry, CustomPathCmd, DocumentModel, FontFamilyMap, HeaderFooterReference, HeaderFooterType, ImageBlock, ImageCrop, InlineImage, MathAccent, MathBar, MathDelimiter, MathEqArray, MathFraction, MathFunc, MathGroupChr, MathLimit, MathMatrix, MathNary, MathNode, MathRadical, MathRow, MathRun, MathScript, Numbering, NumberingFormat, NumberingInstance, NumberingLevel, PictureBullet, PictureOutline, NumberingReference, PageMargins, PageSize, Paragraph, ParagraphProperties, FrameProperties, RelativeSize, TabStop, Run, RunProperties, TextOutline, Ligatures, RowConditionalFormat, RowProperties, Section, FloatAnchor, SectionColumns, SectionProperties, ShapeBlock, ShapeShadow, ShapeDash, ShapeFill, ShapeFillKind, ShapeGeometry, ShapeGroupChild, ShapeLine, LineEnd, ShapeTextBody, ShapeTransform, Style, StyleSheet, StyleType, Table, TableCell, TableLook, TableProperties, TableStyleCondition, TableStyleConditionType, TableStyleLayer, TableRow, UnderlineStyle, VerticalAlign, } from './types.js';
|
|
@@ -6,6 +6,12 @@ export type Alignment = 'left' | 'right' | 'center' | 'both' | 'distribute';
|
|
|
6
6
|
export type UnderlineStyle = 'none' | 'single' | 'double' | 'thick' | 'dotted' | 'dottedHeavy' | 'dash' | 'dashHeavy' | 'wave';
|
|
7
7
|
/** Run vertical alignment (`w:vertAlign`): baseline or super/subscript. */
|
|
8
8
|
export type VerticalAlign = 'baseline' | 'superscript' | 'subscript';
|
|
9
|
+
/**
|
|
10
|
+
* [MS-DOCX] ST_Ligatures — which of a face's OpenType ligatures a run is set
|
|
11
|
+
* with (`w14:ligatures`): the standard ones (`liga`), the contextual (`clig`),
|
|
12
|
+
* the historical (`hlig`) and the discretionary (`dlig`), alone or together.
|
|
13
|
+
*/
|
|
14
|
+
export type Ligatures = 'none' | 'standard' | 'contextual' | 'historical' | 'discretional' | 'standardContextual' | 'standardHistorical' | 'contextualHistorical' | 'standardDiscretional' | 'contextualDiscretional' | 'historicalDiscretional' | 'standardContextualHistorical' | 'standardContextualDiscretional' | 'standardHistoricalDiscretional' | 'contextualHistoricalDiscretional' | 'all';
|
|
9
15
|
/**
|
|
10
16
|
* The four script slots of `w:rFonts` (§17.3.2.26). A character picks its font
|
|
11
17
|
* from the slot its Unicode range maps to (ASCII, high-ANSI, complex-script,
|
|
@@ -63,6 +69,21 @@ export interface RunProperties {
|
|
|
63
69
|
* (negative tightens). Word states it in twentieths of a point.
|
|
64
70
|
*/
|
|
65
71
|
readonly letterSpacingPt?: Pt;
|
|
72
|
+
/**
|
|
73
|
+
* §17.3.2.43 `w:w` — each character set at this share of its own width
|
|
74
|
+
* (1 is as the face sets it), the glyph itself narrowed or widened.
|
|
75
|
+
*/
|
|
76
|
+
readonly widthScale?: number;
|
|
77
|
+
/**
|
|
78
|
+
* §17.3.2.19 `w:kern` — the run's glyph pairs are KERNED, at this size and
|
|
79
|
+
* above (0 turns kerning off). Word kerns nothing a run does not ask for.
|
|
80
|
+
*/
|
|
81
|
+
readonly kerningMinPt?: Pt;
|
|
82
|
+
/**
|
|
83
|
+
* [MS-DOCX] `w14:ligatures` — the face's ligatures the run is set with.
|
|
84
|
+
* Word forms none at all in a document it opens in compatibility mode.
|
|
85
|
+
*/
|
|
86
|
+
readonly ligatures?: Ligatures;
|
|
66
87
|
/**
|
|
67
88
|
* §21.1.2.3.9 `a:rPr/a:ln` — a line drawn round the glyphs themselves, which
|
|
68
89
|
* DrawingML puts on a run and ISO 32000-1 §9.3.6 calls a text rendering mode
|
|
@@ -220,6 +241,24 @@ export interface ParagraphProperties {
|
|
|
220
241
|
* starts on a fresh page even if there is room on the current one.
|
|
221
242
|
*/
|
|
222
243
|
readonly pageBreakBefore?: boolean;
|
|
244
|
+
/**
|
|
245
|
+
* ECMA-376 Part 1 §17.3.1.14 — `w:keepNext`. The paragraph stands on the
|
|
246
|
+
* same page as the start of the one after it: a heading is not left at the
|
|
247
|
+
* foot of a page with its text on the next.
|
|
248
|
+
*/
|
|
249
|
+
readonly keepNext?: boolean;
|
|
250
|
+
/**
|
|
251
|
+
* ECMA-376 Part 1 §17.3.1.15 — `w:keepLines`. The paragraph's lines stand on
|
|
252
|
+
* one page, wherever one page holds them all.
|
|
253
|
+
*/
|
|
254
|
+
readonly keepLines?: boolean;
|
|
255
|
+
/**
|
|
256
|
+
* ECMA-376 Part 1 §17.3.1.44 — `w:widowControl`. When on, a page or column
|
|
257
|
+
* break that would leave the paragraph's first line alone at the foot of one
|
|
258
|
+
* page, or its last line alone at the head of the next, is moved so that
|
|
259
|
+
* neither stands alone. Word applies it wherever nothing says otherwise.
|
|
260
|
+
*/
|
|
261
|
+
readonly widowControl?: boolean;
|
|
223
262
|
/**
|
|
224
263
|
* ECMA-376 §17.3.1.6 — `w:bidi`. Sets the paragraph's base direction to RTL,
|
|
225
264
|
* so the BiDi paragraph embedding level is 1 and default alignment is right.
|
|
@@ -1127,6 +1166,8 @@ export interface ShapeLine {
|
|
|
1127
1166
|
readonly customDash?: ReadonlyArray<number>;
|
|
1128
1167
|
readonly cap?: 'flat' | 'round' | 'square';
|
|
1129
1168
|
readonly fill?: 'solid' | 'none';
|
|
1169
|
+
/** §20.1.2.3.1 `a:alpha` on the line's colour — how opaque the stroke is, `0..1`. */
|
|
1170
|
+
readonly alpha?: number;
|
|
1130
1171
|
/** §20.1.8.24 `a:headEnd` — the decoration at the line's first point. */
|
|
1131
1172
|
readonly headEnd?: LineEnd;
|
|
1132
1173
|
/** §20.1.8.42 `a:tailEnd` — the decoration at the line's last point. */
|
|
@@ -1174,6 +1215,13 @@ export interface ShapeTextBody {
|
|
|
1174
1215
|
readonly insetRight?: Pt;
|
|
1175
1216
|
readonly insetBottom?: Pt;
|
|
1176
1217
|
readonly anchor?: 't' | 'ctr' | 'b';
|
|
1218
|
+
/**
|
|
1219
|
+
* §20.1.2.1.1 `a:bodyPr @wrap="none"` — the lines run as far as their words
|
|
1220
|
+
* do, whatever the box's width. A label placed where a page set it is sized
|
|
1221
|
+
* to the words it was measured from, and set in a face a little wider it
|
|
1222
|
+
* broke inside its one word.
|
|
1223
|
+
*/
|
|
1224
|
+
readonly noWrap?: boolean;
|
|
1177
1225
|
/**
|
|
1178
1226
|
* §20.1.10.83 ST_TextVerticalType (`a:bodyPr @vert`) — text set along the
|
|
1179
1227
|
* box's long axis rather than across it. `vert` reads top-to-bottom (turned a
|
|
@@ -1541,6 +1589,12 @@ export interface SectionProperties {
|
|
|
1541
1589
|
* printed with. Absent ⇒ the count carries on from the section before.
|
|
1542
1590
|
*/
|
|
1543
1591
|
readonly pageNumberStart?: number;
|
|
1592
|
+
/**
|
|
1593
|
+
* §17.6.12 `w:pgNumType w:fmt` — how a PAGE field prints the section's page
|
|
1594
|
+
* numbers (§17.18.59): `lowerRoman` numbers a book's front matter i, ii,
|
|
1595
|
+
* iii before its body starts again at 1. Absent ⇒ decimal.
|
|
1596
|
+
*/
|
|
1597
|
+
readonly pageNumberFormat?: NumberingFormat;
|
|
1544
1598
|
/** §17.6.8 `w:lnNumType` — line numbers printed in the margin beside the text. */
|
|
1545
1599
|
readonly lineNumbering?: {
|
|
1546
1600
|
/** Print every `countBy`-th line (default 1). */
|
|
@@ -1577,6 +1631,17 @@ export interface SectionProperties {
|
|
|
1577
1631
|
* distinguished from `nextPage`.)
|
|
1578
1632
|
*/
|
|
1579
1633
|
readonly sectionStart?: 'continuous' | 'nextPage' | 'oddPage' | 'evenPage';
|
|
1634
|
+
/**
|
|
1635
|
+
* §17.6.20 `w:textDirection` — which way the section's lines run. `tbRl`
|
|
1636
|
+
* sets each line top to bottom and the next one to the left of it: the
|
|
1637
|
+
* text turned a quarter clockwise on the sheet, which is how a viewer shows
|
|
1638
|
+
* a page turned by `/Rotate 90` whose words stood upright in its box. Word
|
|
1639
|
+
* lays a section out that way for `btLr` as well, so the layout reads both
|
|
1640
|
+
* alike. Only the body's text turns: the headers, the footers and every
|
|
1641
|
+
* drawing anchored to the page keep the sheet's own axes. Absent ⇒ left to
|
|
1642
|
+
* right, top to bottom.
|
|
1643
|
+
*/
|
|
1644
|
+
readonly textDirection?: 'tbRl' | 'btLr';
|
|
1580
1645
|
/**
|
|
1581
1646
|
* §17.6.5 `w:docGrid` — the line grid a `lines`/`linesAndChars` section rules
|
|
1582
1647
|
* its text onto, as the pitch in points. Every line of the section's text is
|
|
@@ -192,13 +192,25 @@ function buildStroke(line) {
|
|
|
192
192
|
const widthPt = line.width ?? DEFAULT_LINE_WIDTH_EMU / 12700;
|
|
193
193
|
const dash = line.customDash?.map((n) => Math.max(.01, n * widthPt)) ?? (line.dash && line.dash !== "solid" ? dashPattern(line.dash, widthPt) : void 0);
|
|
194
194
|
const cap = line.cap === "flat" ? "butt" : line.cap;
|
|
195
|
+
const colorHex = line.colorHex ?? "000000";
|
|
195
196
|
return {
|
|
196
|
-
colorHex: line.colorHex
|
|
197
|
+
colorHex: line.alpha !== void 0 && line.alpha < 1 ? overWhite(colorHex, line.alpha) : colorHex,
|
|
197
198
|
widthPt,
|
|
198
199
|
...dash ? { dash } : {},
|
|
199
200
|
...cap ? { cap } : {}
|
|
200
201
|
};
|
|
201
202
|
}
|
|
203
|
+
/** A 6-hex colour drawn at `alpha` over white, as the opaque colour it comes to. */
|
|
204
|
+
function overWhite(hex, alpha) {
|
|
205
|
+
const n = parseInt(hex, 16);
|
|
206
|
+
if (Number.isNaN(n)) return hex;
|
|
207
|
+
const a = Math.max(0, Math.min(1, alpha));
|
|
208
|
+
return [
|
|
209
|
+
16,
|
|
210
|
+
8,
|
|
211
|
+
0
|
|
212
|
+
].map((shift) => Math.round(255 - (255 - (n >> shift & 255)) * a).toString(16).padStart(2, "0")).join("").toUpperCase();
|
|
213
|
+
}
|
|
202
214
|
function dashPattern(dash, w) {
|
|
203
215
|
const u = Math.max(w, .1);
|
|
204
216
|
switch (dash) {
|
|
@@ -9,3 +9,5 @@ export type { KerningMap, LigatureMap, ShapedRun } from './opentype-layout.js';
|
|
|
9
9
|
export { hasSubstitutable, lettersForLigature, substituteLetters } from './ligatures.js';
|
|
10
10
|
export { createFontMeasure } from './measure.js';
|
|
11
11
|
export type { FontMeasure } from './measure.js';
|
|
12
|
+
export { buildTrueType, editableEmbedding, MAX_BUILT_GLYPHS } from './ttf-build.js';
|
|
13
|
+
export type { BuiltFace, BuiltGlyph, BuiltKernPair, BuiltLigature, GlyphSeg, } from './ttf-build.js';
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/** One piece of a glyph's outline, in a one-unit em with y up. */
|
|
2
|
+
export type GlyphSeg = {
|
|
3
|
+
readonly op: 'move';
|
|
4
|
+
readonly x: number;
|
|
5
|
+
readonly y: number;
|
|
6
|
+
} | {
|
|
7
|
+
readonly op: 'line';
|
|
8
|
+
readonly x: number;
|
|
9
|
+
readonly y: number;
|
|
10
|
+
} | {
|
|
11
|
+
readonly op: 'cubic';
|
|
12
|
+
readonly x1: number;
|
|
13
|
+
readonly y1: number;
|
|
14
|
+
readonly x2: number;
|
|
15
|
+
readonly y2: number;
|
|
16
|
+
readonly x: number;
|
|
17
|
+
readonly y: number;
|
|
18
|
+
} | {
|
|
19
|
+
readonly op: 'close';
|
|
20
|
+
};
|
|
21
|
+
/** One glyph of a {@link BuiltFace}. */
|
|
22
|
+
export interface BuiltGlyph {
|
|
23
|
+
/** The characters that select it, as code points. */
|
|
24
|
+
readonly codePoints: ReadonlyArray<number>;
|
|
25
|
+
/** Its contours, filled by the nonzero rule; empty for a blank glyph. */
|
|
26
|
+
readonly outline: ReadonlyArray<GlyphSeg>;
|
|
27
|
+
/** How far the pen moves after it, in thousandths of an em. */
|
|
28
|
+
readonly advance: number;
|
|
29
|
+
}
|
|
30
|
+
/** Everything {@link buildTrueType} needs to know about the face it builds. */
|
|
31
|
+
export interface BuiltFace {
|
|
32
|
+
/** The family the font is installed under (`name` ID 1). */
|
|
33
|
+
readonly family: string;
|
|
34
|
+
/** The style within the family: its bold and italic slot (`name` ID 2). */
|
|
35
|
+
readonly bold: boolean;
|
|
36
|
+
readonly italic: boolean;
|
|
37
|
+
/** The PostScript name (`name` ID 6); only its printable ASCII is kept. */
|
|
38
|
+
readonly postScriptName: string;
|
|
39
|
+
readonly glyphs: ReadonlyArray<BuiltGlyph>;
|
|
40
|
+
/** Above and below the baseline, in thousandths of an em — `descent` negative. */
|
|
41
|
+
readonly ascent: number;
|
|
42
|
+
readonly descent: number;
|
|
43
|
+
readonly capHeight?: number;
|
|
44
|
+
readonly xHeight?: number;
|
|
45
|
+
/** Degrees counterclockwise from the vertical; a face slanted right is negative. */
|
|
46
|
+
readonly italicAngle?: number;
|
|
47
|
+
readonly fixedPitch?: boolean;
|
|
48
|
+
/**
|
|
49
|
+
* OS/2 `fsType` — the embedding the face's licence allows, carried over from
|
|
50
|
+
* the program the outlines came from.
|
|
51
|
+
*/
|
|
52
|
+
readonly fsType: number;
|
|
53
|
+
/** The pairs the face is kerned by: how far the second glyph moves in towards the first. */
|
|
54
|
+
readonly kerning?: ReadonlyArray<BuiltKernPair>;
|
|
55
|
+
/** The glyphs the face draws for a run of characters at once: its ligatures. */
|
|
56
|
+
readonly ligatures?: ReadonlyArray<BuiltLigature>;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* One ligature of a {@link BuiltFace}: a glyph no character reaches alone,
|
|
60
|
+
* substituted for the characters it joins wherever they meet (GSUB `liga`).
|
|
61
|
+
*/
|
|
62
|
+
export interface BuiltLigature {
|
|
63
|
+
/** The characters it stands for, in order — two or more. */
|
|
64
|
+
readonly codePoints: ReadonlyArray<number>;
|
|
65
|
+
readonly outline: ReadonlyArray<GlyphSeg>;
|
|
66
|
+
/** How far the pen moves after it, in thousandths of an em. */
|
|
67
|
+
readonly advance: number;
|
|
68
|
+
}
|
|
69
|
+
/** One kerning pair of a {@link BuiltFace}, by the characters it joins. */
|
|
70
|
+
export interface BuiltKernPair {
|
|
71
|
+
/** The code point of the glyph on the left, and of the one after it. */
|
|
72
|
+
readonly left: number;
|
|
73
|
+
readonly right: number;
|
|
74
|
+
/** The adjustment to the left glyph's advance, in thousandths of an em — negative tightens. */
|
|
75
|
+
readonly value: number;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Whether a face's licence lets it be embedded, as outlines and subset, in a
|
|
79
|
+
* document that stays EDITABLE: OS/2 `fsType` states installable embedding (no
|
|
80
|
+
* usage bit) or grants editable embedding, and neither forbids subsetting nor
|
|
81
|
+
* allows bitmaps only. Restricted-licence and preview-and-print faces are
|
|
82
|
+
* refused — the second may travel only in a document opened read-only.
|
|
83
|
+
*
|
|
84
|
+
* Several usage bits at once is an old font's way of stating permissions, and
|
|
85
|
+
* the least restrictive of them applies (OS/2 versions 0–2).
|
|
86
|
+
*
|
|
87
|
+
* @param fsType The field, or `undefined` where the program states none —
|
|
88
|
+
* which restricts nothing.
|
|
89
|
+
* @returns Whether an editable document may carry the face.
|
|
90
|
+
*/
|
|
91
|
+
export declare function editableEmbedding(fsType: number | undefined): boolean;
|
|
92
|
+
/**
|
|
93
|
+
* The most glyphs a built face holds. A `cmap` format 4 subtable is limited to
|
|
94
|
+
* 64 KB, and past this many characters it may not fit; a face that large is a
|
|
95
|
+
* whole CJK font, which is no subset.
|
|
96
|
+
*/
|
|
97
|
+
export declare const MAX_BUILT_GLYPHS = 8000;
|
|
98
|
+
/**
|
|
99
|
+
* Build a TrueType font from outlines (ISO/IEC 14496-22): `.notdef` first, then
|
|
100
|
+
* one glyph per {@link BuiltGlyph} in the order given, reachable through a
|
|
101
|
+
* Unicode `cmap`.
|
|
102
|
+
*
|
|
103
|
+
* Cubic curves become quadratic ones. A cubic that is a raised quadratic — what
|
|
104
|
+
* a TrueType source's outline arrives as — comes back as exactly that
|
|
105
|
+
* quadratic; any other is cut into as many quadratics as keep within half a
|
|
106
|
+
* unit of it. Each glyph's contours are turned to run clockwise round their
|
|
107
|
+
* ink, as TrueType's are.
|
|
108
|
+
*
|
|
109
|
+
* @param face The face: its names, metrics, licence and glyphs.
|
|
110
|
+
* @returns The font program's bytes.
|
|
111
|
+
* @throws When the face holds more than {@link MAX_BUILT_GLYPHS} glyphs.
|
|
112
|
+
*/
|
|
113
|
+
export declare function buildTrueType(face: BuiltFace): Uint8Array;
|