pdf-codec 1.7.0 → 1.8.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 +13 -8
- package/dist/formula.d.cts +1 -1
- package/dist/formula.d.ts +1 -1
- package/dist/index.d.cts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/math-content-write.cjs +37 -1
- package/dist/math-content-write.d.cts +1 -1
- package/dist/math-content-write.d.ts +1 -1
- package/dist/math-content-write.js +38 -2
- package/dist/math-font-write.cjs +6 -1
- package/dist/math-font-write.d.cts +1 -1
- package/dist/math-font-write.d.ts +1 -1
- package/dist/math-font-write.js +6 -1
- package/dist/math-font.cjs +48 -0
- package/dist/math-font.d.cts +1 -1
- package/dist/math-font.d.ts +1 -1
- package/dist/math-font.js +48 -0
- package/dist/{math-types-YSQUTviw.d.ts → math-types-BZkWO5Ow.d.cts} +28 -2
- package/dist/{math-types-YSQUTviw.d.cts → math-types-Bq7tyV4g.d.ts} +28 -2
- package/dist/math-types.d.cts +3 -2
- package/dist/math-types.d.ts +3 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -98,7 +98,7 @@ const { box } = layoutFormula(mathml, { metrics: metricsAt(12), sizePt: 12, colo
|
|
|
98
98
|
const pdfBytes = writePdf(doc, { formulas: [{ pageIndex: 0, xPt: 50, yPt: 700, box }] });
|
|
99
99
|
```
|
|
100
100
|
|
|
101
|
-
Because `MathBox` and its own constituent types (`MathGlyphRun`/`MathRule`/`MathStroke`/`MathColor`) are plain, structurally-typed data — not a class, not branded — any producer whose output happens to match the shape works here with no cast, no wrapper, and no transformation, whether or not it imports this package at all.
|
|
101
|
+
Because `MathBox` and its own constituent types (`MathGlyphRun`/`MathRule`/`MathStroke`/`MathAssembledGlyphs`/`MathColor`) are plain, structurally-typed data — not a class, not branded — any producer whose output happens to match the shape works here with no cast, no wrapper, and no transformation, whether or not it imports this package at all.
|
|
102
102
|
|
|
103
103
|
Sizing a stretchy glyph — a parenthesis or brace tall enough to wrap a big fraction, a radical sign sized to its own radicand, an over-brace as wide as the content under it — is the OpenType `MATH` table's `MathVariants` job, and `loadMathFont()` exposes it directly. `stretchGlyph` takes a target extent in points and returns the glyph(s) to draw with each one's own offset along the stretch axis, already in points at the requested font size:
|
|
104
104
|
|
|
@@ -114,7 +114,11 @@ const paren = stretchGlyph(0x28, 'vertical', 40, 12); // a '(' stretched to 40pt
|
|
|
114
114
|
|
|
115
115
|
Three outcomes are possible and `kind` records which happened: `'base'` when the unstretched glyph was already big enough, `'variant'` when one of the font's own pre-drawn larger glyphs was selected (always preferred — a hand-drawn glyph beats a glued-together one), and `'assembly'` when the construction was genuinely built by repeating the font's own extender piece between its end pieces, overlapping each seam by as much as both sides' declared connector lengths allow so the joined outlines meet cleanly. `offset` is measured along the stretch axis from the construction's own start — the bottom for a vertical construction, the left for a horizontal one. For a caller working in design units rather than points, `MathFont.stretchyConstruction(codePoint, axis)` returns the raw parsed `MathVariants` data and `assembleStretchyGlyph` performs the same computation over it.
|
|
116
116
|
|
|
117
|
-
|
|
117
|
+
A stretched construction is genuinely drawable, through `MathBox`'s own `MathAssembledGlyphs` item kind: a list of `{ glyphId, xPt, yPt }` placements addressed by **glyph ID**, not by Unicode text. That distinction is the whole point rather than a convenience — most of the glyphs a `MathVariants` construction names have no Unicode code point at all, so they could never travel through `MathGlyphRun.text`, which the writer resolves through the font's `cmap`. Every pre-built larger variant is unencoded, and so are the radical's and the over-brace's assembly pieces; the bracket family is the one exception, since Unicode gives its pieces dedicated code points (the U+239B–U+23AD block — which is also an independent confirmation that assembly parts really are listed bottom-first, given `LEFT PARENTHESIS LOWER HOOK` comes first and `UPPER HOOK` last). Drawing by glyph ID works regardless, because the composite font this package embeds is Identity-H with CID == GID (see [Gotchas](#gotchas-and-quirks)), so a bare glyph ID is directly showable with no `cmap` involvement.
|
|
118
|
+
|
|
119
|
+
The one thing a glyph ID cannot carry is meaning: an unencoded glyph gets no ToUnicode entry, so `MathAssembledGlyphs` also carries the operator's own original `text` (`"("`, `"["`), which `math-content-write.ts` emits as an `/ActualText` marked-content span around the whole construction. A tall assembled bracket therefore still extracts, searches, and copies as `(`.
|
|
120
|
+
|
|
121
|
+
`MathFontMetrics.stretch` is the layout-facing form of all this, and the one a layout engine actually calls: it resolves a construction at a target size and additionally **measures** it — `inkAscentPt`/`inkDescentPt` are the whole construction's real ink extent about its drawing origin, taken from actual glyph outlines. Without that a caller cannot place the result, since a construction's ink neither starts at its drawing origin (a large parenthesis variant straddles the baseline) nor is bounded by its advance-derived `size`.
|
|
118
122
|
|
|
119
123
|
Building a layout engine on top of this codec (this is what `documents.js`'s own `src/layout/` does for docx/pptx/odt/odp/ods/odg): `TextMeasurer`/`createStandardFontMeasurer` and `wrapRunsToWidth` answer "how wide does this text render, and where does this line break" against the standard-14 metrics; `resolveStandardFont`/`STANDARD_METRICS` map an arbitrary requested family/weight/style onto one of the 14 standard PDF faces and that face's own AFM-derived metrics; `rotatePointAboutCenter` handles shape-rotation placement math. None of these do any PDF I/O themselves — they're the same primitives `writePdf`/`readPdf` use internally, exported so a caller assembling its own `LayoutDocument` (from any source format) can measure and wrap text identically to how this package will actually render it.
|
|
120
124
|
|
|
@@ -174,9 +178,9 @@ The package is layered from generic primitives outward to the codec itself:
|
|
|
174
178
|
- **Write**: `objects.ts` (the `PdfObject` discriminated union), `afm-widths.ts`/`encoding.ts`/`winansi.ts`/`fonts.ts` (standard-14 metrics, WinAnsi encoding, family resolution), `font-registry.ts` (the source-document → caller-supplied → vendored-substitute → standard-14 resolution port sitting in front of `resolveStandardFont`, plus `resolveFaceWithRegistry`, the one step both the measurer and the writer resolve through so they can never disagree about which face a `LayoutFont` means), `measure.ts`/`text-layout.ts` (greedy line-wrapping, measured against either a standard-14 face's AFM widths plus a per-family correction or a resolved face's own real `hmtx` advances — never both, see [Fidelity](#fidelity)), `matrix.ts`, `content-write.ts` (`LayoutItem[]` → content-stream operators, with text branching on whether its font resolved to a standard-14 face shown as a WinAnsi byte string or an embedded one shown as Identity-H 2-byte CIDs), `write.ts` (the full object graph, classic cross-reference table, trailer, and — when `WritePdfOptions.formulas` is non-empty — one embedded math composite font group, plus one embedded text font group per face `WritePdfOptions.fonts` resolved, each allocated once in a fixed sorted order and shared across pages).
|
|
175
179
|
- **sfnt font tables**: `sfnt.ts` (a bounds-checked sfnt table-directory reader, big-endian primitive readers, and the `hasBytes` range check every table parser below pre-checks with), `cmap-table.ts` (Unicode → glyph ID, formats 4/12/6), `hmtx-table.ts` (per-glyph advance widths), `font-tables.ts` (`head`/`maxp`/`OS/2`/`post`/`name` — design grid, glyph count, vertical metrics and style bits, italic angle and underline geometry, PostScript and family names), `glyf.ts` (the `loca` offset index, per-glyph headers, a composite glyph's own component records — a composite refers to its base letter and combining marks by glyph ID, and those references nest, so subsetting one safely means taking the transitive closure over this walk — and `glyphInkBounds`, a glyph's own tight ink box, read straight out of a simple glyph's header where the format already states it and unioned from a composite's own transformed, placed components where it does not), and `math-table.ts` (the OpenType `MATH` table's constants, glyph-info, and variants subtables). Every one of these parsers degrades to `undefined` on a missing or truncated table rather than throwing: the vendored fonts are trusted, but a font extracted from an arbitrary source document is not.
|
|
176
180
|
- **sfnt subsetting**: `sfnt-subset.ts` (a TrueType-outline glyph subsetter: Unicode code points → glyph IDs through `cmap-table.ts`, the transitive closure over `glyf.ts`'s composite-component walk, then a rebuilt sfnt container carrying only those glyphs' outlines). **Glyph IDs are preserved, never renumbered** — an unused ID below the highest used one survives as an empty `loca` entry rather than being squeezed out — which keeps every composite's own component references correct inside bytes copied verbatim, keeps a caller's already-resolved glyph IDs valid against the subset, and makes CID == GID trivially true for the embedded program (a `/CIDFontType2` then needs only `/CIDToGIDMap /Identity`). The output rebuilds `head`/`hhea`/`maxp`/`loca`/`glyf`/`hmtx` (with `indexToLocFormat` forced long, one always-legal code path), copies the hinting programs (`cvt `/`fpgm`/`prep`) verbatim, stubs `post` as a version 3.0 "no glyph names" header, and omits `cmap`/`name`/`OS/2`/`GSUB`/`GPOS`/`kern` — none of which an embedded `CIDFontType2` program is read through (ISO 32000-1 9.9). The honest cost of preserving IDs: `loca` and `hmtx` stay proportional to the highest used glyph ID rather than to the number of glyphs kept, so for a document touching one glyph near the end of a large font's glyph order, most of the (already much smaller) output is those two index tables rather than outline data. Applies to `glyf`-flavoured fonts only; a CFF-flavoured one returns `undefined`, the same scope boundary [Fidelity](#fidelity) states for the embedded math font.
|
|
177
|
-
- **Embedded math font**: `math-font.ts` (parses and caches the vendored STIX Two Math font once per process, exposing a size-specific `MathFontMetrics` implementation and a points-in/points-out stretchy-glyph entry point), `math-stretch.ts` (the OpenType MATH two-stage stretching model over that parsed `MathVariants` data: pick the smallest pre-built variant that reaches the target, else assemble from repeated parts with every seam overlapped inside both sides' own declared connector lengths -- unit-agnostic, so it works in design units or points alike), `math-font-write.ts` (builds the `/Type0`/`/CIDFontType0`/`/FontDescriptor`/`/FontFile3`/ToUnicode object group), `math-content-write.ts` (a `PositionedFormula[]` → PDF content-stream bytes, Identity-H 2-byte CIDs for text-showing, `re`/`m`/`l` operators for rules and the radical hook). See [Fidelity](#fidelity) for the CFF-full-embed (not glyph-subsetted) simplification this makes.
|
|
181
|
+
- **Embedded math font**: `math-font.ts` (parses and caches the vendored STIX Two Math font once per process, exposing a size-specific `MathFontMetrics` implementation and a points-in/points-out stretchy-glyph entry point), `math-stretch.ts` (the OpenType MATH two-stage stretching model over that parsed `MathVariants` data: pick the smallest pre-built variant that reaches the target, else assemble from repeated parts with every seam overlapped inside both sides' own declared connector lengths -- unit-agnostic, so it works in design units or points alike), `math-font-write.ts` (builds the `/Type0`/`/CIDFontType0`/`/FontDescriptor`/`/FontFile3`/ToUnicode object group), `math-content-write.ts` (a `PositionedFormula[]` → PDF content-stream bytes, Identity-H 2-byte CIDs for text-showing, `re`/`m`/`l` operators for rules and the radical hook, and one glyph-ID-addressed text object per placement of a stretched construction, wrapped in an `/ActualText` marked-content span). See [Fidelity](#fidelity) for the CFF-full-embed (not glyph-subsetted) simplification this makes.
|
|
178
182
|
- **Embedded text faces**: `embedded-font.ts` (parses and caches one TrueType-outline face's `cmap`/`hmtx`/`hhea`/`head`/`OS/2`/`post`/`name` metrics, and `encodeForShowEmbedded`, the single code path both measurement and text-showing go through — the same reason `winansi.ts`'s `encodeForShow` exists, since encoding and measuring separately lets the two disagree about which characters resolved to which glyph and silently desyncs a computed wrap point from the drawn line). Every geometry field it exposes is converted into PDF's 1000-units-per-em glyph space (ISO 32000-1 9.8.1), which a font's own design grid frequently is not: STIX Two Math is drawn on a 1000-unit em so that factor is an identity for the math font, but Carlito is drawn on a 2048-unit em, where getting the conversion wrong is silent rather than loud — the font simply renders with roughly twice its intended metrics and nothing anywhere reports an error. The serif flag a `/FontDescriptor` needs is read off the face's own PANOSE classification rather than guessed from its family name. `embedded-font-write.ts` builds the `/Type0`/`/CIDFontType2`/`/FontDescriptor`/`/FontFile2`/ToUnicode object group, with `/CIDToGIDMap /Identity` written explicitly (stating outright the CID == GID invariant `sfnt-subset.ts`'s GID-preserving design guarantees) and `/Length1` set to the **uncompressed** subset length — the single most commonly mis-set key in TrueType embedding, since the obvious-looking value, the stream's own `/Length`, is silently accepted by lenient readers and rejected by strict ones. Its subset tag (`ABCDEF+Carlito-Regular`, six uppercase letters per 9.6.4) is a CRC32 over the face's PostScript name and its exact ascending glyph-ID list, so identical input yields byte-identical output and two subsets of one face carrying different glyphs can never be mistaken for one another.
|
|
179
|
-
- **ToUnicode CMaps**: `tounicode.ts`, shared by both embedded-font writers above rather than duplicated in each — a character code → Unicode code point mapping written as a bfchar CMap (9.10.3), with supplementary-plane code points encoded as genuine UTF-16BE surrogate pairs and entries emitted in blocks of at most 100, the limit the CMap syntax sets and one a subsetted text face routinely exceeds.
|
|
183
|
+
- **ToUnicode CMaps**: `tounicode.ts`, shared by both embedded-font writers above rather than duplicated in each — a character code → Unicode code point mapping written as a bfchar CMap (9.10.3), with supplementary-plane code points encoded as genuine UTF-16BE surrogate pairs and entries emitted in blocks of at most 100, the limit the CMap syntax sets and one a subsetted text face routinely exceeds. A glyph with no code point to map back to (a stretchy construction's own unencoded pieces) is dropped from the CMap rather than mapped to a stand-in that would extract as the wrong character; the `/ActualText` span around such a construction carries its real text instead.
|
|
180
184
|
- **CFF reading**: `cff.ts` holds the two container structures every CFF program is built out of — the `INDEX` and the `DICT` — shared by the two readers built on it rather than hand-rolled twice. `cff-bounds.ts` is a Type 2 charstring interpreter that computes each glyph's own tight ink bounding box: a CFF glyph, unlike a TrueType one, stores no bounding box anywhere, so the only way to know what area it covers is to run its outline program. It is a path *walker*, not a rasteriser — it tracks the current point through every path-construction operator and solves each cubic's real extrema from the roots of its own derivative, so a bound it reports is genuinely tight rather than a control-point hull. Hint operators are decoded only far enough to know how many bytes a following `hintmask` consumes. Verified against the vendored STIX Two Math font's whole 5,543-glyph repertoire: every glyph matches fontTools' own `BoundsPen` to within 0.01 design units, and the union of all 5,543 computed boxes lands exactly on the font's own `head` table `FontBBox`. Out of scope, each reported as `undefined` rather than guessed at: a CID-keyed program (its local subroutines live per-FD behind `FDArray`/`FDSelect`), `endchar` in its four-argument seac-like form (which needs the charset and Standard Encoding to resolve into two other glyphs), and the arithmetic/storage/conditional escaped operators. `cff-probe.ts` reads a bare CFF program's header, Name INDEX, and just enough of its Top DICT to detect the `ROS` operator (the escaped `12 30` whose presence *is* the definition of a CID-keyed font, CFF 1.0 Appendix H). It exists to make the embedding path **refuse** such a font rather than mis-embed it: a CID-keyed CFF carries its own charset mapping CIDs onto glyph indices, so CID == GID does not hold, and showing text through Identity-H against one anyway produces no error anywhere — the file is structurally valid, every reader accepts it, and the page simply renders the wrong glyphs. Not wired into any write path yet; it is the guard a later source-embedded-font phase needs. It correctly reports the vendored STIX Two Math font's own `CFF ` table as *not* CID-keyed, which is what makes `math-font-write.ts`'s existing embedding sound.
|
|
181
185
|
- **Read**: `lexer.ts`/`parse.ts` (byte tokenizer and tokens → `PdfObject`), `filters.ts`/`predictors.ts` (Flate/LZW/ASCII85/ASCIIHex/RunLength/CCITTFax, TIFF/PNG predictors), `xref.ts`/`document.ts` (classic and cross-reference-stream resolution, object streams, `/Prev` chains, linear-scan recovery, the page tree with attribute inheritance), `encrypt.ts` (the standard security handler: `/Encrypt` parsing, empty-user-password key derivation and `/U` verification, per-object keys, and the string/stream decryption `document.ts` applies transparently as each indirect object is fetched — see [Gotchas](#gotchas-and-quirks)), `content-read.ts`/`interpret.ts` (the content-stream tokenizer and graphics/text state machine, including form-XObject recursion and general vector-path tracking — see [Gotchas](#gotchas-and-quirks)), `cmap.ts`/`font-style.ts`/`font-read.ts` (`/ToUnicode` CMaps, font-dictionary resolution), `images-read.ts` (Image XObjects → PNG/JPEG bytes), `read.ts` (`readPdf`, assembling all of the above into a `LayoutDocument`).
|
|
182
186
|
- `codec.ts` — `pdfCodec`, a `z.codec()` pair over `readPdf`/`writePdf`, plus a standalone, ~20-line local copy of just the `%PDF-` header check `PdfBytesSchema` needs (`documents.js`'s own equivalent schema lives in a file that also carries unrelated docx/pptx/odt schemas that have no place here).
|
|
@@ -205,9 +209,10 @@ Dependency direction is strictly downward and checkable: `math-types`/`formula`/
|
|
|
205
209
|
- **`interpret.ts` tracks general vector paths, not just axis-aligned `re` rectangles.** `m`/`l`/`c`/`v`/`y`/`h` (and `re` itself, per its own ISO 32000-1 definition as a 4-point rectangle subpath) accumulate real subpaths — CTM-transformed line/cubic segments, open or closed — and any paint operator (`f`/`F`/`f*`/`S`/`s`/`B`/`B*`/`b`/`b*`) emits an item built from them. Verified both by dedicated tests and by a genuine `writePath` → `writePdf` → `readPdf` round trip recovering the original `LayoutPath` value exactly. This is the shared infrastructure a caller reconstructing structure from a `LayoutDocument` (a spreadsheet grid, a vector drawing) builds on.
|
|
206
210
|
- **A recovered path that matches one of three characteristic shape patterns comes back as that shape's own kind, not as a generic `LayoutPath`.** PDF has exactly one shape operator, `re`, and no ellipse or line operator at all, so a writer has no way to record what a path *was* — `interpret.ts` recovers it from the geometry instead. A single closed four-corner subpath whose every edge runs along one axis is a `LayoutRect` (so `re` under a non-rotated *or* 90°-rotated CTM, a hand-built `m`/`l`/`l`/`l`/`h` rectangle, and any combination of fill and stroke all reach it — not just the fill-only single-`re` case an earlier fast path covered); a closed subpath of exactly four cubic segments meeting at its bounding box's four cardinal points, with all eight control points at the standard kappa offset (`BEZIER_KAPPA`, 4/3·(√2−1)) those extremes imply, is a `LayoutEllipse` — precisely what `writeEllipse` emits; an open single-straight-segment stroke-only subpath is a `LayoutLine`. Tolerance is `max(1e-3pt, 1e-4 × the shape's own extent)`: the absolute floor is twenty times the 5e-5pt quantisation `formatNumber`'s 4-decimal-place rounding imposes, and the relative term is what lets a large ellipse from a producer that rounded its kappa constant more coarsely (`0.5523`) still match. **These are deliberate, bounded heuristics, not certainties** — a hand-authored freeform path that happens to consist of four kappa-ratio cubics between its bounding box's cardinal points is indistinguishable from a "real" ellipse in the PDF bytes, because at that point it geometrically *is* one, whatever the author called it. What a false positive can never do is misreport geometry: every detected shape reproduces its source path's own points exactly, so it changes an item's kind, never where or how big it is. Anything the patterns don't cover — a non-90° rotation, a curve that isn't the four-quadrant construction, a polygon that isn't a rectangle, multiple subpaths — stays a `LayoutPath`, and a rotated ellipse deliberately does too, since `LayoutEllipse` carries no rotation to report one with.
|
|
207
211
|
- **`writePdf`/`readPdf` round-trip a page's own `notes` field via a hidden annotation, not any real PDF feature.** PDF has no native concept of hidden presenter notes, so a page's `LayoutPage.notes` (when present) is written as a `/Subtype /Text` annotation (the same construct Acrobat's own sticky-note tool uses) with the `Hidden` annotation flag set so it never renders or prints, and `readPdf` reads it back via an internal author marker that distinguishes this package's own notes annotation from a genuine third-party sticky note. This is a round-trip mechanism specific to this package's own writer/reader pair — a PDF produced by anything else will never carry it, and a PDF consumer other than this package's own `readPdf` will never see it as anything but an invisible, empty sticky note. `documents.js` uses this to carry pptx/odp speaker notes through `pptxToPdf`/`pdfToPptx` and `odpToPdf`/`pdfToOdp`.
|
|
208
|
-
- **STIX Two Math (the embedded formula font) is a CFF-flavoured OpenType font (an `OTTO` sfnt wrapping a `CFF ` table), not TrueType/glyf** — confirmed by inspecting the vendored font's own sfnt table directory while `math-font.ts` was built. Genuine Type2-charstring glyph subsetting (re-encoding charstrings, rebuilding the CFF `INDEX` structures with a renumbered, minimal glyph set) is a substantially larger undertaking than TrueType glyf/loca subsetting, and is out of scope: the **entire** `CFF ` table is embedded verbatim, unmodified, as a single `/FontFile3` `/Subtype /CIDFontType0C` stream — a real, correct, working embedded font, just not glyph-subsetted. Everything else genuinely IS built from a targeted parse of only what's used: `cmap` resolves exactly the Unicode code points a document's formulas actually reference to glyph IDs, and the emitted `/W` widths array
|
|
209
|
-
- **The OpenType `MATH` table's `MathVariants` subtable is
|
|
210
|
-
- **
|
|
212
|
+
- **STIX Two Math (the embedded formula font) is a CFF-flavoured OpenType font (an `OTTO` sfnt wrapping a `CFF ` table), not TrueType/glyf** — confirmed by inspecting the vendored font's own sfnt table directory while `math-font.ts` was built. Genuine Type2-charstring glyph subsetting (re-encoding charstrings, rebuilding the CFF `INDEX` structures with a renumbered, minimal glyph set) is a substantially larger undertaking than TrueType glyf/loca subsetting, and is out of scope: the **entire** `CFF ` table is embedded verbatim, unmodified, as a single `/FontFile3` `/Subtype /CIDFontType0C` stream — a real, correct, working embedded font, just not glyph-subsetted. Everything else genuinely IS built from a targeted parse of only what's used: `cmap` resolves exactly the Unicode code points a document's formulas actually reference to glyph IDs, and the emitted `/W` widths array covers only the glyph IDs actually drawn (those, plus any unencoded pieces a stretchy construction contributed), not the font's full ~5,500-glyph repertoire; the ToUnicode CMap covers the subset of those that have a code point at all. A CID-keyed composite font built this way needs no `/CIDToGIDMap` at all (that key exists only for `/CIDFontType2`): per ISO 32000-1 9.7.4.2, a `/CIDFontType0` whose `/FontFile3` is a "bare" (non-CID-keyed) CFF program is read with CID treated as directly indexing the CFF's own `CharStrings` INDEX by glyph order — i.e. CID == GID, exactly the numbering `cmap`-derived glyph IDs already use, so Identity-H text-showing needs no further remapping anywhere in the write path.
|
|
213
|
+
- **The OpenType `MATH` table's `MathVariants` subtable is parsed, its stretchy-glyph assembly implemented (`math-table.ts`/`math-stretch.ts`), and the result genuinely drawable (`math-types.ts`'s `MathAssembledGlyphs`, `math-content-write.ts`).** Variant selection and part assembly are real, tested computation — `loadMathFont().stretchGlyph(...)` gives back the glyph IDs and offsets for a parenthesis, brace, radical sign, or over-brace at any target size, with every seam overlapped inside the parts' own declared connector lengths — and `MathFontMetrics.stretch` wraps that with the real ink measurement a layout engine needs to place it. Drawing goes by **glyph ID**, because most of the glyphs a construction names have no Unicode code point at all: every pre-built larger variant is unencoded, as are the radical's and the over-brace's assembly pieces, with the bracket family the one exception (Unicode's own U+239B–U+23AD piece block covers it). That works because CID == GID here, so a glyph ID is shown directly with no `cmap` involvement. Two real consequences follow, both handled rather than left silent: `collectUsedGlyphs` now maps a glyph ID to `number | undefined`, so an unencoded glyph still gets its `/W` width but contributes no ToUnicode entry, and the construction is wrapped in an `/ActualText` marked-content span carrying the operator's own text so it still extracts as `(` rather than as nothing. `MathConstants` (every fraction/radical/script-positioning constant `MathFontMetrics` exposes) and `MathGlyphInfo` (italics correction, top-accent attachment) are genuinely parsed in full too.
|
|
214
|
+
- **What this package draws for a stretchy glyph is decided entirely by its caller.** This package resolves and draws whatever construction it is asked for, on either axis; which operators a document actually stretches, and to what, is a layout-engine decision — `documents.js`'s own `src/mathml/layout.ts` currently stretches vertical fences in an `mrow` and nothing else. See that package's own README for which constructions genuinely stretch today and which still render at a fixed size.
|
|
215
|
+
- **Real per-glyph ink bounds are now measured from the outline, but `ascentPerEm`/`descentPerEm` still exist alongside them and a caller has to choose.** `MathGlyphMetrics.inkAscentPt`/`inkDescentPt` (and `MathFont.glyphInkBounds`, the same thing in design units) carry each glyph's own tight ink extent, computed by walking its Type 2 charstring — a full stop measures 0.12 em tall against the 1.0 em the font's nominal `hhea` metrics claim for every glyph alike. `ascentPerEm`/`descentPerEm` remain what they always were: one uniform figure for the whole face, still the right measure for anything sized against the font rather than against particular characters, and still the fallback for a glyph with no outline to measure (a space) or one `cff-bounds.ts` declines to walk, where both ink fields come back `undefined` together. The consumer that motivated this — `documents.js`'s own MathML `layoutToken` — now uses them: it takes the max ink ascent and max ink descent across a run's glyphs, falling back to the nominal metrics per glyph that carries no bounds.
|
|
211
216
|
- **An ink box is genuinely tight, which for a math font means it is often *larger* than the nominal metrics, not smaller.** The "ink is a fraction of the nominal extent" intuition holds for text-like glyphs (a full stop, a parenthesis, an `x`) and fails for the extension pieces, display-size operators, and pre-built large variants a math font is full of: over a tenth of STIX Two Math's repertoire draws above its own nominal ascent, and another tenth below its nominal descent, reaching 2.6 em up and 1.6 em down at the extremes. Sizing those from `ascentPerEm` under-reports them exactly as badly as it over-reports a full stop, which is the whole reason the per-glyph measurement exists.
|
|
212
217
|
- **A glyph's ink descent is negative where its lowest ink sits above the baseline.** `inkDescentPt` follows `descentPerEm`'s own sign convention (ink below the baseline is a positive descent), so a superscript-height glyph honestly reports a negative descent rather than a clamped zero. A consumer that needs a box which never crosses the baseline clamps at its own layer, where it can see what the box is for.
|
|
213
218
|
- **An embedded `CIDFontType2` program needs no `cmap` table of its own, and `sfnt-subset.ts`'s output doesn't carry one — this is a property of the spec, not an oversight this package works around.** `cmap` maps a character code to a glyph ID for a *simple* font; a `Type0` composite font never asks the embedded font program to do that lookup at all. Character code → CID goes through the `Type0` font's own `/Encoding` (Identity-H here, so CID == character code by construction for the 2-byte codes this package writes), and CID → GID goes through `/CIDToGIDMap` (`/Identity` here, matching `sfnt-subset.ts`'s own GID-preserving design). Both steps happen inside the PDF's own object graph, entirely before the embedded font program is ever consulted — ISO 32000-1 9.7.4.2. This is exactly why the subset output can safely omit `cmap` alongside `name`/`OS/2`/`GSUB`/`GPOS`/`kern` (see Architecture above): none of the five is on the code-path a `CIDFontType2` reader actually walks.
|
|
@@ -249,7 +254,7 @@ Dependency direction is strictly downward and checkable: `math-types`/`formula`/
|
|
|
249
254
|
|
|
250
255
|
**The acceptance bar for embedded-font fidelity is deliberately "no page-count drift on a real corpus", not "line-identical".** Every glyph in an embedded run is placed at its own bare `hmtx` advance width and nothing else — there is no pair-kerning adjustment anywhere in this package's measurement or content-stream writing path (see [Gotchas](#gotchas-and-quirks)). Reaching genuine line-identical parity with the original authoring application would additionally need a GPOS pair-kerning reader on top of the outline subsetter this package already has, a materially larger, separate undertaking this phase deliberately did not attempt. What the current bar does guarantee: a real document measured and drawn through the same resolved face's own advances will not silently reflow onto a different number of pages the way a width-corrected standard-14 substitute occasionally can.
|
|
251
256
|
|
|
252
|
-
**The one exception is math-formula rendering (`WritePdfOptions.formulas`): this genuinely embeds a real, hand-parsed font.** Real box-model glyph runs are shown through the embedded STIX Two Math font with genuine per-glyph metrics (advance width, italic correction, top-accent attachment) and font-wide layout constants (axis height, fraction/radical rule thickness and gaps, script shift amounts) parsed directly from that font's own `MATH` table — not approximated or hand-tuned. See [Gotchas](#gotchas-and-quirks) for the exact boundary of what this package's own font parsing does and doesn't cover (the CFF-full-embed simplification,
|
|
257
|
+
**The one exception is math-formula rendering (`WritePdfOptions.formulas`): this genuinely embeds a real, hand-parsed font.** Real box-model glyph runs are shown through the embedded STIX Two Math font with genuine per-glyph metrics (advance width, italic correction, top-accent attachment) and font-wide layout constants (axis height, fraction/radical rule thickness and gaps, script shift amounts) parsed directly from that font's own `MATH` table — not approximated or hand-tuned. Stretchy constructions are real too: a `MathVariants` variant or part assembly is resolved, measured against actual glyph outlines, and drawn by glyph ID. See [Gotchas](#gotchas-and-quirks) for the exact boundary of what this package's own font parsing does and doesn't cover (the CFF-full-embed simplification, and what a stretched construction costs in ToUnicode terms).
|
|
253
258
|
|
|
254
259
|
**`readPdf(writePdf(doc))` is not guaranteed to reproduce `doc` exactly, and `writePdf(readPdf(bytes))` is not guaranteed to reproduce `bytes` exactly — this package makes no round-trip-losslessness claim in either direction.** A PDF page is fundamentally a stream of positioned drawing operators, not a structured document: a rectangle, an ellipse, and a line are recovered as their own kinds only because each is *always* written as one characteristic operator pattern this package recognises (see the shape-detection gotcha above) — a shape drawn any other way, or rotated off-axis, still collapses to a generic `LayoutPath`, and text is recovered as positioned glyph runs with no guarantee the original run boundaries (which characters were grouped into one `Tj` versus several) survive identically. This is a deliberate, permanent contrast with format-preserving codecs like `ooxml.js`'s own `packageCodec`. `pdfCodec` shares `z.codec()`'s *mechanism* (schema-validated both ways) but not that *guarantee* — wrapping this round trip in `z.codec()` validates the shape of what comes out, not its fidelity to what went in.
|
|
255
260
|
|
package/dist/formula.d.cts
CHANGED
package/dist/formula.d.ts
CHANGED
package/dist/index.d.cts
CHANGED
|
@@ -12,7 +12,9 @@ import { DEFAULT_VERTICAL_METRIC_POLICY, FontMeasurerOptions, StandardFontMeasur
|
|
|
12
12
|
import { WinAnsiSubstitution } from "./winansi.cjs";
|
|
13
13
|
import { i as Point, u as rotatePointAboutCenter } from "./matrix-BHzJESll.cjs";
|
|
14
14
|
import { ResolvedFont, resolveStandardFont } from "./fonts.cjs";
|
|
15
|
-
import { a as
|
|
15
|
+
import { a as MathGlyphPart, c as MathVariants, n as MathGlyphAssembly, o as MathGlyphVariant, r as MathGlyphConstruction } from "./math-table-gFNB8DmQ.cjs";
|
|
16
|
+
import { a as assembleStretchyGlyph, i as MathStretchPlacement, n as MathStretchConstruction, o as scaleMathStretchConstruction, r as MathStretchOptions, t as MathStretchAxis } from "./math-stretch-DXWjs8gL.cjs";
|
|
17
|
+
import { a as MathGlyphMetrics, c as MathLayoutItem, d as MathStretchResult, f as MathStroke, i as MathFontMetrics, l as MathRule, n as MathBox, o as MathGlyphPlacement, r as MathColor, s as MathGlyphRun, t as MathAssembledGlyphs, u as MathStretchGlyph } from "./math-types-BZkWO5Ow.cjs";
|
|
16
18
|
import { PositionedFormula } from "./formula.cjs";
|
|
17
19
|
import { CcittFaxImage, CcittFaxOptions, decodeCcittFax } from "./image/ccitt.cjs";
|
|
18
20
|
import { n as Jbig2UnsupportedError, t as Jbig2ParseError } from "./jbig2-errors-Bj6MPxrx.cjs";
|
|
@@ -27,8 +29,6 @@ import { PngEncodeOptions, encodePng } from "./image/png-encode.cjs";
|
|
|
27
29
|
import { PngFilterType, filterScanlines, unfilterScanlines } from "./image/png-filter.cjs";
|
|
28
30
|
import { ReadPdfOptions, readPdf } from "./read.cjs";
|
|
29
31
|
import { WritePdfOptions, writePdf } from "./write.cjs";
|
|
30
|
-
import { a as MathGlyphPart, c as MathVariants, n as MathGlyphAssembly, o as MathGlyphVariant, r as MathGlyphConstruction } from "./math-table-gFNB8DmQ.cjs";
|
|
31
|
-
import { a as assembleStretchyGlyph, i as MathStretchPlacement, n as MathStretchConstruction, o as scaleMathStretchConstruction, r as MathStretchOptions, t as MathStretchAxis } from "./math-stretch-DXWjs8gL.cjs";
|
|
32
32
|
import { LoadedMathFont, MathFont, MathFontDescriptorMetrics, loadMathFont } from "./math-font.cjs";
|
|
33
33
|
import { StyledFragment, StyledRun, WrapOptions, WrappedLine, wrapRunsToWidth } from "./text-layout.cjs";
|
|
34
|
-
export { ByteReader, ByteWriter, type CcittFaxImage, type CcittFaxOptions, DEFAULT_VERTICAL_METRIC_POLICY, type DeflateLevel, type EmbeddedFace, type EmbeddedFaceMetrics, type EmbeddedFaceSubstitution, type FontMeasurerOptions, type FontMetrics, type FontRegistry, type FontRegistryOptions, type FontSubstitution, type GlyphInkBounds, type InflateResult, type Jbig2DecodeOptions, type Jbig2Image, Jbig2ParseError, Jbig2UnsupportedError, type Jp2ChannelDefinition, type Jp2ColourSpace, type Jp2Container, type Jp2ImageHeader, type Jpeg2000ComponentMetadata, type Jpeg2000DecodeOptions, type Jpeg2000Image, type Jpeg2000Metadata, Jpeg2000ParseError, type Jpeg2000ProgressionOrder, type Jpeg2000QuantizationStyle, type Jpeg2000Transform, Jpeg2000UnsupportedError, type JpegInfo, type LoadedMathFont, MAX_INFLATE_OUTPUT_BYTES, type MathBox, type MathColor, type MathFont, type MathFontDescriptorMetrics, type MathFontMetrics, type MathGlyphAssembly, type MathGlyphConstruction, type MathGlyphMetrics, type MathGlyphPart, type MathGlyphRun, type MathGlyphVariant, type MathLayoutItem, type MathRule, type MathStretchAxis, type MathStretchConstruction, type MathStretchOptions, type MathStretchPlacement, type MathStroke, type MathVariants, NOOP_DIAGNOSTIC_SINK, PdfBytesSchema, type PdfDiagnostic, type PdfDiagnosticSeverity, type PdfDiagnosticSink, PdfEncryptedError, PdfParseError, PdfPasswordRequiredError, type PngDecodeOptions, type PngEncodeOptions, type PngFilterType, type Point, type PositionedFormula, type ProvidedFont, type RawImage, type ReadPdfOptions, type ResolvedFace, type ResolvedFont, STANDARD_METRICS, type StandardFontMeasurerOptions, type StandardFontName, type StyledFragment, type StyledRun, type TextMeasurer, type UnderlineMetrics, type VerticalMetricPolicy, type WinAnsiSubstitution, type WrapOptions, type WrappedLine, type WritePdfOptions, assembleStretchyGlyph, concatBytes, crc32, createFontMeasurer, createFontRegistry, createStandardFontMeasurer, decodeCcittFax, decodeJbig2Embedded, decodeJpeg2000, decodePng, deflate, encodePng, filterScanlines, inflate, inflateTolerant, isAsciiWhitespace, loadMathFont, looksLikeBareCodestream, parseJp2Container, pdfCodec, readJpeg2000Metadata, readJpegInfo, readPdf, resolveFaceWithRegistry, resolveStandardFont, rotatePointAboutCenter, scaleMathStretchConstruction, unfilterScanlines, wrapRunsToWidth, writePdf };
|
|
34
|
+
export { ByteReader, ByteWriter, type CcittFaxImage, type CcittFaxOptions, DEFAULT_VERTICAL_METRIC_POLICY, type DeflateLevel, type EmbeddedFace, type EmbeddedFaceMetrics, type EmbeddedFaceSubstitution, type FontMeasurerOptions, type FontMetrics, type FontRegistry, type FontRegistryOptions, type FontSubstitution, type GlyphInkBounds, type InflateResult, type Jbig2DecodeOptions, type Jbig2Image, Jbig2ParseError, Jbig2UnsupportedError, type Jp2ChannelDefinition, type Jp2ColourSpace, type Jp2Container, type Jp2ImageHeader, type Jpeg2000ComponentMetadata, type Jpeg2000DecodeOptions, type Jpeg2000Image, type Jpeg2000Metadata, Jpeg2000ParseError, type Jpeg2000ProgressionOrder, type Jpeg2000QuantizationStyle, type Jpeg2000Transform, Jpeg2000UnsupportedError, type JpegInfo, type LoadedMathFont, MAX_INFLATE_OUTPUT_BYTES, type MathAssembledGlyphs, type MathBox, type MathColor, type MathFont, type MathFontDescriptorMetrics, type MathFontMetrics, type MathGlyphAssembly, type MathGlyphConstruction, type MathGlyphMetrics, type MathGlyphPart, type MathGlyphPlacement, type MathGlyphRun, type MathGlyphVariant, type MathLayoutItem, type MathRule, type MathStretchAxis, type MathStretchConstruction, type MathStretchGlyph, type MathStretchOptions, type MathStretchPlacement, type MathStretchResult, type MathStroke, type MathVariants, NOOP_DIAGNOSTIC_SINK, PdfBytesSchema, type PdfDiagnostic, type PdfDiagnosticSeverity, type PdfDiagnosticSink, PdfEncryptedError, PdfParseError, PdfPasswordRequiredError, type PngDecodeOptions, type PngEncodeOptions, type PngFilterType, type Point, type PositionedFormula, type ProvidedFont, type RawImage, type ReadPdfOptions, type ResolvedFace, type ResolvedFont, STANDARD_METRICS, type StandardFontMeasurerOptions, type StandardFontName, type StyledFragment, type StyledRun, type TextMeasurer, type UnderlineMetrics, type VerticalMetricPolicy, type WinAnsiSubstitution, type WrapOptions, type WrappedLine, type WritePdfOptions, assembleStretchyGlyph, concatBytes, crc32, createFontMeasurer, createFontRegistry, createStandardFontMeasurer, decodeCcittFax, decodeJbig2Embedded, decodeJpeg2000, decodePng, deflate, encodePng, filterScanlines, inflate, inflateTolerant, isAsciiWhitespace, loadMathFont, looksLikeBareCodestream, parseJp2Container, pdfCodec, readJpeg2000Metadata, readJpegInfo, readPdf, resolveFaceWithRegistry, resolveStandardFont, rotatePointAboutCenter, scaleMathStretchConstruction, unfilterScanlines, wrapRunsToWidth, writePdf };
|
package/dist/index.d.ts
CHANGED
|
@@ -12,7 +12,9 @@ import { DEFAULT_VERTICAL_METRIC_POLICY, FontMeasurerOptions, StandardFontMeasur
|
|
|
12
12
|
import { WinAnsiSubstitution } from "./winansi.js";
|
|
13
13
|
import { i as Point, u as rotatePointAboutCenter } from "./matrix-BHzJESll.js";
|
|
14
14
|
import { ResolvedFont, resolveStandardFont } from "./fonts.js";
|
|
15
|
-
import { a as
|
|
15
|
+
import { a as MathGlyphPart, c as MathVariants, n as MathGlyphAssembly, o as MathGlyphVariant, r as MathGlyphConstruction } from "./math-table-DhPrNoPa.js";
|
|
16
|
+
import { a as assembleStretchyGlyph, i as MathStretchPlacement, n as MathStretchConstruction, o as scaleMathStretchConstruction, r as MathStretchOptions, t as MathStretchAxis } from "./math-stretch-Bwk_bxh1.js";
|
|
17
|
+
import { a as MathGlyphMetrics, c as MathLayoutItem, d as MathStretchResult, f as MathStroke, i as MathFontMetrics, l as MathRule, n as MathBox, o as MathGlyphPlacement, r as MathColor, s as MathGlyphRun, t as MathAssembledGlyphs, u as MathStretchGlyph } from "./math-types-Bq7tyV4g.js";
|
|
16
18
|
import { PositionedFormula } from "./formula.js";
|
|
17
19
|
import { CcittFaxImage, CcittFaxOptions, decodeCcittFax } from "./image/ccitt.js";
|
|
18
20
|
import { n as Jbig2UnsupportedError, t as Jbig2ParseError } from "./jbig2-errors-Bj6MPxrx.js";
|
|
@@ -27,8 +29,6 @@ import { PngEncodeOptions, encodePng } from "./image/png-encode.js";
|
|
|
27
29
|
import { PngFilterType, filterScanlines, unfilterScanlines } from "./image/png-filter.js";
|
|
28
30
|
import { ReadPdfOptions, readPdf } from "./read.js";
|
|
29
31
|
import { WritePdfOptions, writePdf } from "./write.js";
|
|
30
|
-
import { a as MathGlyphPart, c as MathVariants, n as MathGlyphAssembly, o as MathGlyphVariant, r as MathGlyphConstruction } from "./math-table-DhPrNoPa.js";
|
|
31
|
-
import { a as assembleStretchyGlyph, i as MathStretchPlacement, n as MathStretchConstruction, o as scaleMathStretchConstruction, r as MathStretchOptions, t as MathStretchAxis } from "./math-stretch-Bwk_bxh1.js";
|
|
32
32
|
import { LoadedMathFont, MathFont, MathFontDescriptorMetrics, loadMathFont } from "./math-font.js";
|
|
33
33
|
import { StyledFragment, StyledRun, WrapOptions, WrappedLine, wrapRunsToWidth } from "./text-layout.js";
|
|
34
|
-
export { ByteReader, ByteWriter, type CcittFaxImage, type CcittFaxOptions, DEFAULT_VERTICAL_METRIC_POLICY, type DeflateLevel, type EmbeddedFace, type EmbeddedFaceMetrics, type EmbeddedFaceSubstitution, type FontMeasurerOptions, type FontMetrics, type FontRegistry, type FontRegistryOptions, type FontSubstitution, type GlyphInkBounds, type InflateResult, type Jbig2DecodeOptions, type Jbig2Image, Jbig2ParseError, Jbig2UnsupportedError, type Jp2ChannelDefinition, type Jp2ColourSpace, type Jp2Container, type Jp2ImageHeader, type Jpeg2000ComponentMetadata, type Jpeg2000DecodeOptions, type Jpeg2000Image, type Jpeg2000Metadata, Jpeg2000ParseError, type Jpeg2000ProgressionOrder, type Jpeg2000QuantizationStyle, type Jpeg2000Transform, Jpeg2000UnsupportedError, type JpegInfo, type LoadedMathFont, MAX_INFLATE_OUTPUT_BYTES, type MathBox, type MathColor, type MathFont, type MathFontDescriptorMetrics, type MathFontMetrics, type MathGlyphAssembly, type MathGlyphConstruction, type MathGlyphMetrics, type MathGlyphPart, type MathGlyphRun, type MathGlyphVariant, type MathLayoutItem, type MathRule, type MathStretchAxis, type MathStretchConstruction, type MathStretchOptions, type MathStretchPlacement, type MathStroke, type MathVariants, NOOP_DIAGNOSTIC_SINK, PdfBytesSchema, type PdfDiagnostic, type PdfDiagnosticSeverity, type PdfDiagnosticSink, PdfEncryptedError, PdfParseError, PdfPasswordRequiredError, type PngDecodeOptions, type PngEncodeOptions, type PngFilterType, type Point, type PositionedFormula, type ProvidedFont, type RawImage, type ReadPdfOptions, type ResolvedFace, type ResolvedFont, STANDARD_METRICS, type StandardFontMeasurerOptions, type StandardFontName, type StyledFragment, type StyledRun, type TextMeasurer, type UnderlineMetrics, type VerticalMetricPolicy, type WinAnsiSubstitution, type WrapOptions, type WrappedLine, type WritePdfOptions, assembleStretchyGlyph, concatBytes, crc32, createFontMeasurer, createFontRegistry, createStandardFontMeasurer, decodeCcittFax, decodeJbig2Embedded, decodeJpeg2000, decodePng, deflate, encodePng, filterScanlines, inflate, inflateTolerant, isAsciiWhitespace, loadMathFont, looksLikeBareCodestream, parseJp2Container, pdfCodec, readJpeg2000Metadata, readJpegInfo, readPdf, resolveFaceWithRegistry, resolveStandardFont, rotatePointAboutCenter, scaleMathStretchConstruction, unfilterScanlines, wrapRunsToWidth, writePdf };
|
|
34
|
+
export { ByteReader, ByteWriter, type CcittFaxImage, type CcittFaxOptions, DEFAULT_VERTICAL_METRIC_POLICY, type DeflateLevel, type EmbeddedFace, type EmbeddedFaceMetrics, type EmbeddedFaceSubstitution, type FontMeasurerOptions, type FontMetrics, type FontRegistry, type FontRegistryOptions, type FontSubstitution, type GlyphInkBounds, type InflateResult, type Jbig2DecodeOptions, type Jbig2Image, Jbig2ParseError, Jbig2UnsupportedError, type Jp2ChannelDefinition, type Jp2ColourSpace, type Jp2Container, type Jp2ImageHeader, type Jpeg2000ComponentMetadata, type Jpeg2000DecodeOptions, type Jpeg2000Image, type Jpeg2000Metadata, Jpeg2000ParseError, type Jpeg2000ProgressionOrder, type Jpeg2000QuantizationStyle, type Jpeg2000Transform, Jpeg2000UnsupportedError, type JpegInfo, type LoadedMathFont, MAX_INFLATE_OUTPUT_BYTES, type MathAssembledGlyphs, type MathBox, type MathColor, type MathFont, type MathFontDescriptorMetrics, type MathFontMetrics, type MathGlyphAssembly, type MathGlyphConstruction, type MathGlyphMetrics, type MathGlyphPart, type MathGlyphPlacement, type MathGlyphRun, type MathGlyphVariant, type MathLayoutItem, type MathRule, type MathStretchAxis, type MathStretchConstruction, type MathStretchGlyph, type MathStretchOptions, type MathStretchPlacement, type MathStretchResult, type MathStroke, type MathVariants, NOOP_DIAGNOSTIC_SINK, PdfBytesSchema, type PdfDiagnostic, type PdfDiagnosticSeverity, type PdfDiagnosticSink, PdfEncryptedError, PdfParseError, PdfPasswordRequiredError, type PngDecodeOptions, type PngEncodeOptions, type PngFilterType, type Point, type PositionedFormula, type ProvidedFont, type RawImage, type ReadPdfOptions, type ResolvedFace, type ResolvedFont, STANDARD_METRICS, type StandardFontMeasurerOptions, type StandardFontName, type StyledFragment, type StyledRun, type TextMeasurer, type UnderlineMetrics, type VerticalMetricPolicy, type WinAnsiSubstitution, type WrapOptions, type WrappedLine, type WritePdfOptions, assembleStretchyGlyph, concatBytes, crc32, createFontMeasurer, createFontRegistry, createStandardFontMeasurer, decodeCcittFax, decodeJbig2Embedded, decodeJpeg2000, decodePng, deflate, encodePng, filterScanlines, inflate, inflateTolerant, isAsciiWhitespace, loadMathFont, looksLikeBareCodestream, parseJp2Container, pdfCodec, readJpeg2000Metadata, readJpegInfo, readPdf, resolveFaceWithRegistry, resolveStandardFont, rotatePointAboutCenter, scaleMathStretchConstruction, unfilterScanlines, wrapRunsToWidth, writePdf };
|
|
@@ -40,6 +40,37 @@ function writeGlyphRun(writer, positioned, item, ctx) {
|
|
|
40
40
|
writer.writeAscii(" Tj\n");
|
|
41
41
|
writer.writeAscii("ET\n");
|
|
42
42
|
}
|
|
43
|
+
function cidBytes(glyphId) {
|
|
44
|
+
return new Uint8Array([glyphId >> 8 & 255, glyphId & 255]);
|
|
45
|
+
}
|
|
46
|
+
function utf16BeWithBom(text) {
|
|
47
|
+
const bytes = new Uint8Array(2 + text.length * 2);
|
|
48
|
+
bytes[0] = 254;
|
|
49
|
+
bytes[1] = 255;
|
|
50
|
+
for (let i = 0; i < text.length; i++) {
|
|
51
|
+
const unit = text.charCodeAt(i);
|
|
52
|
+
bytes[2 + i * 2] = unit >> 8 & 255;
|
|
53
|
+
bytes[3 + i * 2] = unit & 255;
|
|
54
|
+
}
|
|
55
|
+
return bytes;
|
|
56
|
+
}
|
|
57
|
+
function writeAssembledGlyphs(writer, positioned, item, ctx) {
|
|
58
|
+
if (item.placements.length === 0) return;
|
|
59
|
+
require_serialize.writeObject(writer, require_objects.pdfName("Span"));
|
|
60
|
+
writer.writeAscii(" ");
|
|
61
|
+
require_serialize.writeObject(writer, require_objects.pdfDict({ ActualText: require_objects.pdfHexString(utf16BeWithBom(item.text)) }));
|
|
62
|
+
writer.writeAscii(" BDC\n");
|
|
63
|
+
for (const placement of item.placements) {
|
|
64
|
+
writer.writeAscii("BT\n");
|
|
65
|
+
writer.writeAscii(`/${ctx.resourceName} ${require_serialize.formatNumber(item.sizePt)} Tf\n`);
|
|
66
|
+
writeRgbOperator(writer, item.color, "rg");
|
|
67
|
+
writer.writeAscii(`1 0 0 1 ${require_serialize.formatNumber(toPdfX(positioned, placement.xPt))} ${require_serialize.formatNumber(toPdfY(positioned, placement.yPt))} Tm\n`);
|
|
68
|
+
require_serialize.writeObject(writer, require_objects.pdfHexString(cidBytes(placement.glyphId)));
|
|
69
|
+
writer.writeAscii(" Tj\n");
|
|
70
|
+
writer.writeAscii("ET\n");
|
|
71
|
+
}
|
|
72
|
+
writer.writeAscii("EMC\n");
|
|
73
|
+
}
|
|
43
74
|
function writeRule(writer, positioned, item) {
|
|
44
75
|
const x = toPdfX(positioned, item.xPt);
|
|
45
76
|
const topY = toPdfY(positioned, item.yPt);
|
|
@@ -62,18 +93,23 @@ function writeFormulaContentStream(formulas, ctx) {
|
|
|
62
93
|
const writer = new require_bytes_writer.ByteWriter();
|
|
63
94
|
for (const positioned of formulas) for (const item of positioned.box.items) if (item.kind === "glyphs") writeGlyphRun(writer, positioned, item, ctx);
|
|
64
95
|
else if (item.kind === "rule") writeRule(writer, positioned, item);
|
|
96
|
+
else if (item.kind === "assembled-glyphs") writeAssembledGlyphs(writer, positioned, item, ctx);
|
|
65
97
|
else writeStroke(writer, positioned, item);
|
|
66
98
|
return writer.toBytes();
|
|
67
99
|
}
|
|
68
100
|
function collectUsedGlyphs(formulas, font) {
|
|
69
101
|
const used = /* @__PURE__ */ new Map();
|
|
70
102
|
for (const positioned of formulas) for (const item of positioned.box.items) {
|
|
103
|
+
if (item.kind === "assembled-glyphs") {
|
|
104
|
+
for (const placement of item.placements) if (!used.has(placement.glyphId)) used.set(placement.glyphId, void 0);
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
71
107
|
if (item.kind !== "glyphs") continue;
|
|
72
108
|
for (const ch of item.text) {
|
|
73
109
|
const codePoint = ch.codePointAt(0);
|
|
74
110
|
if (codePoint === void 0) continue;
|
|
75
111
|
const glyphId = font.glyphId(codePoint);
|
|
76
|
-
if (glyphId !== void 0 &&
|
|
112
|
+
if (glyphId !== void 0 && used.get(glyphId) === void 0) used.set(glyphId, codePoint);
|
|
77
113
|
}
|
|
78
114
|
}
|
|
79
115
|
return used;
|
|
@@ -6,6 +6,6 @@ interface MathContentWriteContext {
|
|
|
6
6
|
readonly resourceName: string;
|
|
7
7
|
}
|
|
8
8
|
declare function writeFormulaContentStream(formulas: readonly PositionedFormula[], ctx: MathContentWriteContext): Uint8Array<ArrayBuffer>;
|
|
9
|
-
declare function collectUsedGlyphs(formulas: readonly PositionedFormula[], font: MathFont): ReadonlyMap<number, number>;
|
|
9
|
+
declare function collectUsedGlyphs(formulas: readonly PositionedFormula[], font: MathFont): ReadonlyMap<number, number | undefined>;
|
|
10
10
|
//#endregion
|
|
11
11
|
export { MathContentWriteContext, collectUsedGlyphs, writeFormulaContentStream };
|
|
@@ -6,6 +6,6 @@ interface MathContentWriteContext {
|
|
|
6
6
|
readonly resourceName: string;
|
|
7
7
|
}
|
|
8
8
|
declare function writeFormulaContentStream(formulas: readonly PositionedFormula[], ctx: MathContentWriteContext): Uint8Array<ArrayBuffer>;
|
|
9
|
-
declare function collectUsedGlyphs(formulas: readonly PositionedFormula[], font: MathFont): ReadonlyMap<number, number>;
|
|
9
|
+
declare function collectUsedGlyphs(formulas: readonly PositionedFormula[], font: MathFont): ReadonlyMap<number, number | undefined>;
|
|
10
10
|
//#endregion
|
|
11
11
|
export { MathContentWriteContext, collectUsedGlyphs, writeFormulaContentStream };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ByteWriter } from "./bytes/writer.js";
|
|
2
|
-
import { pdfHexString } from "./objects.js";
|
|
2
|
+
import { pdfDict, pdfHexString, pdfName } from "./objects.js";
|
|
3
3
|
import { formatNumber, writeObject } from "./serialize.js";
|
|
4
4
|
//#region src/math-content-write.ts
|
|
5
5
|
function toPdfX(positioned, itemXPt) {
|
|
@@ -39,6 +39,37 @@ function writeGlyphRun(writer, positioned, item, ctx) {
|
|
|
39
39
|
writer.writeAscii(" Tj\n");
|
|
40
40
|
writer.writeAscii("ET\n");
|
|
41
41
|
}
|
|
42
|
+
function cidBytes(glyphId) {
|
|
43
|
+
return new Uint8Array([glyphId >> 8 & 255, glyphId & 255]);
|
|
44
|
+
}
|
|
45
|
+
function utf16BeWithBom(text) {
|
|
46
|
+
const bytes = new Uint8Array(2 + text.length * 2);
|
|
47
|
+
bytes[0] = 254;
|
|
48
|
+
bytes[1] = 255;
|
|
49
|
+
for (let i = 0; i < text.length; i++) {
|
|
50
|
+
const unit = text.charCodeAt(i);
|
|
51
|
+
bytes[2 + i * 2] = unit >> 8 & 255;
|
|
52
|
+
bytes[3 + i * 2] = unit & 255;
|
|
53
|
+
}
|
|
54
|
+
return bytes;
|
|
55
|
+
}
|
|
56
|
+
function writeAssembledGlyphs(writer, positioned, item, ctx) {
|
|
57
|
+
if (item.placements.length === 0) return;
|
|
58
|
+
writeObject(writer, pdfName("Span"));
|
|
59
|
+
writer.writeAscii(" ");
|
|
60
|
+
writeObject(writer, pdfDict({ ActualText: pdfHexString(utf16BeWithBom(item.text)) }));
|
|
61
|
+
writer.writeAscii(" BDC\n");
|
|
62
|
+
for (const placement of item.placements) {
|
|
63
|
+
writer.writeAscii("BT\n");
|
|
64
|
+
writer.writeAscii(`/${ctx.resourceName} ${formatNumber(item.sizePt)} Tf\n`);
|
|
65
|
+
writeRgbOperator(writer, item.color, "rg");
|
|
66
|
+
writer.writeAscii(`1 0 0 1 ${formatNumber(toPdfX(positioned, placement.xPt))} ${formatNumber(toPdfY(positioned, placement.yPt))} Tm\n`);
|
|
67
|
+
writeObject(writer, pdfHexString(cidBytes(placement.glyphId)));
|
|
68
|
+
writer.writeAscii(" Tj\n");
|
|
69
|
+
writer.writeAscii("ET\n");
|
|
70
|
+
}
|
|
71
|
+
writer.writeAscii("EMC\n");
|
|
72
|
+
}
|
|
42
73
|
function writeRule(writer, positioned, item) {
|
|
43
74
|
const x = toPdfX(positioned, item.xPt);
|
|
44
75
|
const topY = toPdfY(positioned, item.yPt);
|
|
@@ -61,18 +92,23 @@ function writeFormulaContentStream(formulas, ctx) {
|
|
|
61
92
|
const writer = new ByteWriter();
|
|
62
93
|
for (const positioned of formulas) for (const item of positioned.box.items) if (item.kind === "glyphs") writeGlyphRun(writer, positioned, item, ctx);
|
|
63
94
|
else if (item.kind === "rule") writeRule(writer, positioned, item);
|
|
95
|
+
else if (item.kind === "assembled-glyphs") writeAssembledGlyphs(writer, positioned, item, ctx);
|
|
64
96
|
else writeStroke(writer, positioned, item);
|
|
65
97
|
return writer.toBytes();
|
|
66
98
|
}
|
|
67
99
|
function collectUsedGlyphs(formulas, font) {
|
|
68
100
|
const used = /* @__PURE__ */ new Map();
|
|
69
101
|
for (const positioned of formulas) for (const item of positioned.box.items) {
|
|
102
|
+
if (item.kind === "assembled-glyphs") {
|
|
103
|
+
for (const placement of item.placements) if (!used.has(placement.glyphId)) used.set(placement.glyphId, void 0);
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
70
106
|
if (item.kind !== "glyphs") continue;
|
|
71
107
|
for (const ch of item.text) {
|
|
72
108
|
const codePoint = ch.codePointAt(0);
|
|
73
109
|
if (codePoint === void 0) continue;
|
|
74
110
|
const glyphId = font.glyphId(codePoint);
|
|
75
|
-
if (glyphId !== void 0 &&
|
|
111
|
+
if (glyphId !== void 0 && used.get(glyphId) === void 0) used.set(glyphId, codePoint);
|
|
76
112
|
}
|
|
77
113
|
}
|
|
78
114
|
return used;
|
package/dist/math-font-write.cjs
CHANGED
|
@@ -38,6 +38,11 @@ function buildFontFileStream(font, compress) {
|
|
|
38
38
|
} : { Subtype: require_objects.pdfName("CIDFontType0C") });
|
|
39
39
|
return require_objects.pdfStream(dict, compress ? require_bytes_flate.deflate(font.cffBytes) : font.cffBytes);
|
|
40
40
|
}
|
|
41
|
+
function toUnicodeEntries(usedGlyphs) {
|
|
42
|
+
const entries = /* @__PURE__ */ new Map();
|
|
43
|
+
for (const [glyphId, codePoint] of usedGlyphs) if (codePoint !== void 0) entries.set(glyphId, codePoint);
|
|
44
|
+
return entries;
|
|
45
|
+
}
|
|
41
46
|
function buildMathFontObjects(font, usedGlyphs, refs, compress) {
|
|
42
47
|
const cidFont = require_objects.pdfDict({
|
|
43
48
|
Type: require_objects.pdfName("Font"),
|
|
@@ -64,7 +69,7 @@ function buildMathFontObjects(font, usedGlyphs, refs, compress) {
|
|
|
64
69
|
cidFont,
|
|
65
70
|
descriptor: buildFontDescriptor(font, refs.fontFileRef),
|
|
66
71
|
fontFile: buildFontFileStream(font, compress),
|
|
67
|
-
toUnicode: require_tounicode.buildToUnicodeCMap(usedGlyphs)
|
|
72
|
+
toUnicode: require_tounicode.buildToUnicodeCMap(toUnicodeEntries(usedGlyphs))
|
|
68
73
|
};
|
|
69
74
|
}
|
|
70
75
|
//#endregion
|
|
@@ -14,6 +14,6 @@ interface MathFontObjects {
|
|
|
14
14
|
readonly fontFile: PdfObject;
|
|
15
15
|
readonly toUnicode: PdfObject;
|
|
16
16
|
}
|
|
17
|
-
declare function buildMathFontObjects(font: MathFont, usedGlyphs: ReadonlyMap<number, number>, refs: MathFontObjectRefs, compress: boolean): MathFontObjects;
|
|
17
|
+
declare function buildMathFontObjects(font: MathFont, usedGlyphs: ReadonlyMap<number, number | undefined>, refs: MathFontObjectRefs, compress: boolean): MathFontObjects;
|
|
18
18
|
//#endregion
|
|
19
19
|
export { MathFontObjectRefs, MathFontObjects, buildMathFontObjects };
|
|
@@ -14,6 +14,6 @@ interface MathFontObjects {
|
|
|
14
14
|
readonly fontFile: PdfObject;
|
|
15
15
|
readonly toUnicode: PdfObject;
|
|
16
16
|
}
|
|
17
|
-
declare function buildMathFontObjects(font: MathFont, usedGlyphs: ReadonlyMap<number, number>, refs: MathFontObjectRefs, compress: boolean): MathFontObjects;
|
|
17
|
+
declare function buildMathFontObjects(font: MathFont, usedGlyphs: ReadonlyMap<number, number | undefined>, refs: MathFontObjectRefs, compress: boolean): MathFontObjects;
|
|
18
18
|
//#endregion
|
|
19
19
|
export { MathFontObjectRefs, MathFontObjects, buildMathFontObjects };
|
package/dist/math-font-write.js
CHANGED
|
@@ -37,6 +37,11 @@ function buildFontFileStream(font, compress) {
|
|
|
37
37
|
} : { Subtype: pdfName("CIDFontType0C") });
|
|
38
38
|
return pdfStream(dict, compress ? deflate(font.cffBytes) : font.cffBytes);
|
|
39
39
|
}
|
|
40
|
+
function toUnicodeEntries(usedGlyphs) {
|
|
41
|
+
const entries = /* @__PURE__ */ new Map();
|
|
42
|
+
for (const [glyphId, codePoint] of usedGlyphs) if (codePoint !== void 0) entries.set(glyphId, codePoint);
|
|
43
|
+
return entries;
|
|
44
|
+
}
|
|
40
45
|
function buildMathFontObjects(font, usedGlyphs, refs, compress) {
|
|
41
46
|
const cidFont = pdfDict({
|
|
42
47
|
Type: pdfName("Font"),
|
|
@@ -63,7 +68,7 @@ function buildMathFontObjects(font, usedGlyphs, refs, compress) {
|
|
|
63
68
|
cidFont,
|
|
64
69
|
descriptor: buildFontDescriptor(font, refs.fontFileRef),
|
|
65
70
|
fontFile: buildFontFileStream(font, compress),
|
|
66
|
-
toUnicode: buildToUnicodeCMap(usedGlyphs)
|
|
71
|
+
toUnicode: buildToUnicodeCMap(toUnicodeEntries(usedGlyphs))
|
|
67
72
|
};
|
|
68
73
|
}
|
|
69
74
|
//#endregion
|
package/dist/math-font.cjs
CHANGED
|
@@ -11,6 +11,51 @@ const require_math_table = require("./math-table.cjs");
|
|
|
11
11
|
function toPt(designUnits, unitsPerEm, sizePt) {
|
|
12
12
|
return designUnits / unitsPerEm * sizePt;
|
|
13
13
|
}
|
|
14
|
+
function measureConstruction(placements, axis, inkBounds, hmtx) {
|
|
15
|
+
let inkAscent = Number.NEGATIVE_INFINITY;
|
|
16
|
+
let inkDescent = Number.NEGATIVE_INFINITY;
|
|
17
|
+
let advanceWidth = 0;
|
|
18
|
+
for (const placement of placements) {
|
|
19
|
+
advanceWidth = Math.max(advanceWidth, hmtx.advanceWidth(placement.glyphId));
|
|
20
|
+
const ink = inkBounds?.bounds(placement.glyphId);
|
|
21
|
+
if (ink === void 0) continue;
|
|
22
|
+
const alongY = axis === "vertical" ? placement.offset : 0;
|
|
23
|
+
inkAscent = Math.max(inkAscent, alongY + ink.yMax);
|
|
24
|
+
inkDescent = Math.max(inkDescent, -(alongY + ink.yMin));
|
|
25
|
+
}
|
|
26
|
+
return inkAscent === Number.NEGATIVE_INFINITY ? void 0 : {
|
|
27
|
+
inkAscent,
|
|
28
|
+
inkDescent,
|
|
29
|
+
advanceWidth
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
function stretchAtSize(cmap, hmtx, math, inkBounds, unitsPerEm, codePoint, axis, targetSizePt, sizePt) {
|
|
33
|
+
const glyphId = cmap(codePoint);
|
|
34
|
+
if (glyphId === void 0) return;
|
|
35
|
+
const construction = (axis === "vertical" ? math.variants.vertical : math.variants.horizontal).get(glyphId);
|
|
36
|
+
if (construction === void 0) return;
|
|
37
|
+
const designUnitsPerPt = unitsPerEm / sizePt;
|
|
38
|
+
const assembled = require_math_stretch.assembleStretchyGlyph(construction, {
|
|
39
|
+
axis,
|
|
40
|
+
targetSize: targetSizePt * designUnitsPerPt,
|
|
41
|
+
minConnectorOverlap: math.variants.minConnectorOverlap
|
|
42
|
+
});
|
|
43
|
+
if (assembled === void 0) return;
|
|
44
|
+
const measured = measureConstruction(assembled.placements, axis, inkBounds, hmtx);
|
|
45
|
+
if (measured === void 0) return;
|
|
46
|
+
const pt = (designUnits) => toPt(designUnits, unitsPerEm, sizePt);
|
|
47
|
+
return {
|
|
48
|
+
kind: assembled.kind,
|
|
49
|
+
sizePt: pt(assembled.size),
|
|
50
|
+
advanceWidthPt: pt(measured.advanceWidth),
|
|
51
|
+
inkAscentPt: pt(measured.inkAscent),
|
|
52
|
+
inkDescentPt: pt(measured.inkDescent),
|
|
53
|
+
placements: assembled.placements.map((placement) => ({
|
|
54
|
+
glyphId: placement.glyphId,
|
|
55
|
+
offsetPt: pt(placement.offset)
|
|
56
|
+
}))
|
|
57
|
+
};
|
|
58
|
+
}
|
|
14
59
|
function metricsAtSize(cmap, hmtx, math, inkBounds, unitsPerEm, ascentDesignUnits, descentDesignUnits, sizePt) {
|
|
15
60
|
const c = math.constants;
|
|
16
61
|
const pt = (designUnits) => toPt(designUnits, unitsPerEm, sizePt);
|
|
@@ -62,6 +107,9 @@ function metricsAtSize(cmap, hmtx, math, inkBounds, unitsPerEm, ascentDesignUnit
|
|
|
62
107
|
inkAscentPt: ink === void 0 ? void 0 : toPt(ink.yMax, unitsPerEm, glyphSizePt),
|
|
63
108
|
inkDescentPt: ink === void 0 ? void 0 : toPt(-ink.yMin, unitsPerEm, glyphSizePt)
|
|
64
109
|
};
|
|
110
|
+
},
|
|
111
|
+
stretch(codePoint, axis, targetSizePt, glyphSizePt) {
|
|
112
|
+
return stretchAtSize(cmap, hmtx, math, inkBounds, unitsPerEm, codePoint, axis, targetSizePt, glyphSizePt);
|
|
65
113
|
}
|
|
66
114
|
};
|
|
67
115
|
}
|
package/dist/math-font.d.cts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { t as GlyphInkBounds } from "./glyph-bounds-BV_Z40KS.cjs";
|
|
2
|
-
import { r as MathFontMetrics } from "./math-types-YSQUTviw.cjs";
|
|
3
2
|
import { r as MathGlyphConstruction } from "./math-table-gFNB8DmQ.cjs";
|
|
4
3
|
import { n as MathStretchConstruction, t as MathStretchAxis } from "./math-stretch-DXWjs8gL.cjs";
|
|
4
|
+
import { i as MathFontMetrics } from "./math-types-BZkWO5Ow.cjs";
|
|
5
5
|
//#region src/math-font.d.ts
|
|
6
6
|
interface MathFontDescriptorMetrics {
|
|
7
7
|
readonly unitsPerEm: number;
|
package/dist/math-font.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { t as GlyphInkBounds } from "./glyph-bounds-BV_Z40KS.js";
|
|
2
|
-
import { r as MathFontMetrics } from "./math-types-YSQUTviw.js";
|
|
3
2
|
import { r as MathGlyphConstruction } from "./math-table-DhPrNoPa.js";
|
|
4
3
|
import { n as MathStretchConstruction, t as MathStretchAxis } from "./math-stretch-Bwk_bxh1.js";
|
|
4
|
+
import { i as MathFontMetrics } from "./math-types-Bq7tyV4g.js";
|
|
5
5
|
//#region src/math-font.d.ts
|
|
6
6
|
interface MathFontDescriptorMetrics {
|
|
7
7
|
readonly unitsPerEm: number;
|
package/dist/math-font.js
CHANGED
|
@@ -10,6 +10,51 @@ import { parseMathTable } from "./math-table.js";
|
|
|
10
10
|
function toPt(designUnits, unitsPerEm, sizePt) {
|
|
11
11
|
return designUnits / unitsPerEm * sizePt;
|
|
12
12
|
}
|
|
13
|
+
function measureConstruction(placements, axis, inkBounds, hmtx) {
|
|
14
|
+
let inkAscent = Number.NEGATIVE_INFINITY;
|
|
15
|
+
let inkDescent = Number.NEGATIVE_INFINITY;
|
|
16
|
+
let advanceWidth = 0;
|
|
17
|
+
for (const placement of placements) {
|
|
18
|
+
advanceWidth = Math.max(advanceWidth, hmtx.advanceWidth(placement.glyphId));
|
|
19
|
+
const ink = inkBounds?.bounds(placement.glyphId);
|
|
20
|
+
if (ink === void 0) continue;
|
|
21
|
+
const alongY = axis === "vertical" ? placement.offset : 0;
|
|
22
|
+
inkAscent = Math.max(inkAscent, alongY + ink.yMax);
|
|
23
|
+
inkDescent = Math.max(inkDescent, -(alongY + ink.yMin));
|
|
24
|
+
}
|
|
25
|
+
return inkAscent === Number.NEGATIVE_INFINITY ? void 0 : {
|
|
26
|
+
inkAscent,
|
|
27
|
+
inkDescent,
|
|
28
|
+
advanceWidth
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
function stretchAtSize(cmap, hmtx, math, inkBounds, unitsPerEm, codePoint, axis, targetSizePt, sizePt) {
|
|
32
|
+
const glyphId = cmap(codePoint);
|
|
33
|
+
if (glyphId === void 0) return;
|
|
34
|
+
const construction = (axis === "vertical" ? math.variants.vertical : math.variants.horizontal).get(glyphId);
|
|
35
|
+
if (construction === void 0) return;
|
|
36
|
+
const designUnitsPerPt = unitsPerEm / sizePt;
|
|
37
|
+
const assembled = assembleStretchyGlyph(construction, {
|
|
38
|
+
axis,
|
|
39
|
+
targetSize: targetSizePt * designUnitsPerPt,
|
|
40
|
+
minConnectorOverlap: math.variants.minConnectorOverlap
|
|
41
|
+
});
|
|
42
|
+
if (assembled === void 0) return;
|
|
43
|
+
const measured = measureConstruction(assembled.placements, axis, inkBounds, hmtx);
|
|
44
|
+
if (measured === void 0) return;
|
|
45
|
+
const pt = (designUnits) => toPt(designUnits, unitsPerEm, sizePt);
|
|
46
|
+
return {
|
|
47
|
+
kind: assembled.kind,
|
|
48
|
+
sizePt: pt(assembled.size),
|
|
49
|
+
advanceWidthPt: pt(measured.advanceWidth),
|
|
50
|
+
inkAscentPt: pt(measured.inkAscent),
|
|
51
|
+
inkDescentPt: pt(measured.inkDescent),
|
|
52
|
+
placements: assembled.placements.map((placement) => ({
|
|
53
|
+
glyphId: placement.glyphId,
|
|
54
|
+
offsetPt: pt(placement.offset)
|
|
55
|
+
}))
|
|
56
|
+
};
|
|
57
|
+
}
|
|
13
58
|
function metricsAtSize(cmap, hmtx, math, inkBounds, unitsPerEm, ascentDesignUnits, descentDesignUnits, sizePt) {
|
|
14
59
|
const c = math.constants;
|
|
15
60
|
const pt = (designUnits) => toPt(designUnits, unitsPerEm, sizePt);
|
|
@@ -61,6 +106,9 @@ function metricsAtSize(cmap, hmtx, math, inkBounds, unitsPerEm, ascentDesignUnit
|
|
|
61
106
|
inkAscentPt: ink === void 0 ? void 0 : toPt(ink.yMax, unitsPerEm, glyphSizePt),
|
|
62
107
|
inkDescentPt: ink === void 0 ? void 0 : toPt(-ink.yMin, unitsPerEm, glyphSizePt)
|
|
63
108
|
};
|
|
109
|
+
},
|
|
110
|
+
stretch(codePoint, axis, targetSizePt, glyphSizePt) {
|
|
111
|
+
return stretchAtSize(cmap, hmtx, math, inkBounds, unitsPerEm, codePoint, axis, targetSizePt, glyphSizePt);
|
|
64
112
|
}
|
|
65
113
|
};
|
|
66
114
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { t as MathStretchAxis } from "./math-stretch-DXWjs8gL.cjs";
|
|
1
2
|
//#region src/math-types.d.ts
|
|
2
3
|
interface MathColor {
|
|
3
4
|
readonly r: number;
|
|
@@ -29,7 +30,19 @@ interface MathStroke {
|
|
|
29
30
|
readonly widthPt: number;
|
|
30
31
|
readonly color: MathColor;
|
|
31
32
|
}
|
|
32
|
-
|
|
33
|
+
interface MathGlyphPlacement {
|
|
34
|
+
readonly glyphId: number;
|
|
35
|
+
readonly xPt: number;
|
|
36
|
+
readonly yPt: number;
|
|
37
|
+
}
|
|
38
|
+
interface MathAssembledGlyphs {
|
|
39
|
+
readonly kind: 'assembled-glyphs';
|
|
40
|
+
readonly placements: readonly MathGlyphPlacement[];
|
|
41
|
+
readonly text: string;
|
|
42
|
+
readonly sizePt: number;
|
|
43
|
+
readonly color: MathColor;
|
|
44
|
+
}
|
|
45
|
+
type MathLayoutItem = MathGlyphRun | MathRule | MathStroke | MathAssembledGlyphs;
|
|
33
46
|
interface MathBox {
|
|
34
47
|
readonly widthPt: number;
|
|
35
48
|
readonly heightPt: number;
|
|
@@ -44,6 +57,18 @@ interface MathGlyphMetrics {
|
|
|
44
57
|
readonly inkAscentPt?: number;
|
|
45
58
|
readonly inkDescentPt?: number;
|
|
46
59
|
}
|
|
60
|
+
interface MathStretchGlyph {
|
|
61
|
+
readonly glyphId: number;
|
|
62
|
+
readonly offsetPt: number;
|
|
63
|
+
}
|
|
64
|
+
interface MathStretchResult {
|
|
65
|
+
readonly kind: 'base' | 'variant' | 'assembly';
|
|
66
|
+
readonly sizePt: number;
|
|
67
|
+
readonly advanceWidthPt: number;
|
|
68
|
+
readonly inkAscentPt: number;
|
|
69
|
+
readonly inkDescentPt: number;
|
|
70
|
+
readonly placements: readonly MathStretchGlyph[];
|
|
71
|
+
}
|
|
47
72
|
interface MathFontMetrics {
|
|
48
73
|
readonly ascentPerEm: number;
|
|
49
74
|
readonly descentPerEm: number;
|
|
@@ -79,6 +104,7 @@ interface MathFontMetrics {
|
|
|
79
104
|
readonly scriptScriptPercentScaleDown: number;
|
|
80
105
|
readonly defaultRuleThicknessPt: number;
|
|
81
106
|
glyph(codePoint: number, sizePt: number): MathGlyphMetrics | undefined;
|
|
107
|
+
stretch(codePoint: number, axis: MathStretchAxis, targetSizePt: number, sizePt: number): MathStretchResult | undefined;
|
|
82
108
|
}
|
|
83
109
|
//#endregion
|
|
84
|
-
export {
|
|
110
|
+
export { MathGlyphMetrics as a, MathLayoutItem as c, MathStretchResult as d, MathStroke as f, MathFontMetrics as i, MathRule as l, MathBox as n, MathGlyphPlacement as o, MathColor as r, MathGlyphRun as s, MathAssembledGlyphs as t, MathStretchGlyph as u };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { t as MathStretchAxis } from "./math-stretch-Bwk_bxh1.js";
|
|
1
2
|
//#region src/math-types.d.ts
|
|
2
3
|
interface MathColor {
|
|
3
4
|
readonly r: number;
|
|
@@ -29,7 +30,19 @@ interface MathStroke {
|
|
|
29
30
|
readonly widthPt: number;
|
|
30
31
|
readonly color: MathColor;
|
|
31
32
|
}
|
|
32
|
-
|
|
33
|
+
interface MathGlyphPlacement {
|
|
34
|
+
readonly glyphId: number;
|
|
35
|
+
readonly xPt: number;
|
|
36
|
+
readonly yPt: number;
|
|
37
|
+
}
|
|
38
|
+
interface MathAssembledGlyphs {
|
|
39
|
+
readonly kind: 'assembled-glyphs';
|
|
40
|
+
readonly placements: readonly MathGlyphPlacement[];
|
|
41
|
+
readonly text: string;
|
|
42
|
+
readonly sizePt: number;
|
|
43
|
+
readonly color: MathColor;
|
|
44
|
+
}
|
|
45
|
+
type MathLayoutItem = MathGlyphRun | MathRule | MathStroke | MathAssembledGlyphs;
|
|
33
46
|
interface MathBox {
|
|
34
47
|
readonly widthPt: number;
|
|
35
48
|
readonly heightPt: number;
|
|
@@ -44,6 +57,18 @@ interface MathGlyphMetrics {
|
|
|
44
57
|
readonly inkAscentPt?: number;
|
|
45
58
|
readonly inkDescentPt?: number;
|
|
46
59
|
}
|
|
60
|
+
interface MathStretchGlyph {
|
|
61
|
+
readonly glyphId: number;
|
|
62
|
+
readonly offsetPt: number;
|
|
63
|
+
}
|
|
64
|
+
interface MathStretchResult {
|
|
65
|
+
readonly kind: 'base' | 'variant' | 'assembly';
|
|
66
|
+
readonly sizePt: number;
|
|
67
|
+
readonly advanceWidthPt: number;
|
|
68
|
+
readonly inkAscentPt: number;
|
|
69
|
+
readonly inkDescentPt: number;
|
|
70
|
+
readonly placements: readonly MathStretchGlyph[];
|
|
71
|
+
}
|
|
47
72
|
interface MathFontMetrics {
|
|
48
73
|
readonly ascentPerEm: number;
|
|
49
74
|
readonly descentPerEm: number;
|
|
@@ -79,6 +104,7 @@ interface MathFontMetrics {
|
|
|
79
104
|
readonly scriptScriptPercentScaleDown: number;
|
|
80
105
|
readonly defaultRuleThicknessPt: number;
|
|
81
106
|
glyph(codePoint: number, sizePt: number): MathGlyphMetrics | undefined;
|
|
107
|
+
stretch(codePoint: number, axis: MathStretchAxis, targetSizePt: number, sizePt: number): MathStretchResult | undefined;
|
|
82
108
|
}
|
|
83
109
|
//#endregion
|
|
84
|
-
export {
|
|
110
|
+
export { MathGlyphMetrics as a, MathLayoutItem as c, MathStretchResult as d, MathStroke as f, MathFontMetrics as i, MathRule as l, MathBox as n, MathGlyphPlacement as o, MathColor as r, MathGlyphRun as s, MathAssembledGlyphs as t, MathStretchGlyph as u };
|
package/dist/math-types.d.cts
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { t as MathStretchAxis } from "./math-stretch-DXWjs8gL.cjs";
|
|
2
|
+
import { a as MathGlyphMetrics, c as MathLayoutItem, d as MathStretchResult, f as MathStroke, i as MathFontMetrics, l as MathRule, n as MathBox, o as MathGlyphPlacement, r as MathColor, s as MathGlyphRun, t as MathAssembledGlyphs, u as MathStretchGlyph } from "./math-types-BZkWO5Ow.cjs";
|
|
3
|
+
export { MathAssembledGlyphs, MathBox, MathColor, MathFontMetrics, MathGlyphMetrics, MathGlyphPlacement, MathGlyphRun, MathLayoutItem, MathRule, type MathStretchAxis, MathStretchGlyph, MathStretchResult, MathStroke };
|
package/dist/math-types.d.ts
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { t as MathStretchAxis } from "./math-stretch-Bwk_bxh1.js";
|
|
2
|
+
import { a as MathGlyphMetrics, c as MathLayoutItem, d as MathStretchResult, f as MathStroke, i as MathFontMetrics, l as MathRule, n as MathBox, o as MathGlyphPlacement, r as MathColor, s as MathGlyphRun, t as MathAssembledGlyphs, u as MathStretchGlyph } from "./math-types-Bq7tyV4g.js";
|
|
3
|
+
export { MathAssembledGlyphs, MathBox, MathColor, MathFontMetrics, MathGlyphMetrics, MathGlyphPlacement, MathGlyphRun, MathLayoutItem, MathRule, type MathStretchAxis, MathStretchGlyph, MathStretchResult, MathStroke };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pdf-codec",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.0",
|
|
4
4
|
"description": "Hand-written, dependency-minimal PDF codec: parses arbitrary real-world PDFs and generates new ones, built on document-schema.js's LayoutDocument pivot and Zod 4 codecs.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|