pdf-codec 5.8.0 โ†’ 5.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -332,6 +332,10 @@ Reading a program's built-in encoding is what stops a symbol-encoded subset โ€”
332
332
 
333
333
  A TrueType subset can lose its glyph names and its `cmap` both and keep nothing but outlines, metrics and its `name` table, while still numbering its glyphs as the full face does. Producers write exactly that for the core faces they embed most (the Arial, Times New Roman and Courier New families) as composite subsets with no `/ToUnicode`, and then the face's published glyph order is the only statement of what each glyph draws. `core-font-glyph-orders.ts` carries that order for those faces, with each glyph's advance width, and a program that names itself as one of them (its own `name` table's PostScript name, or `/BaseFont` when the table states none) is read through it glyph by glyph only where the program's own advance width for the glyph equals the face's on the same design grid. A renumbered subset, another face under the same name or a glyph a later release redrew to a new width therefore stays unmapped instead of being read as the wrong character. The data is generated by `scripts/generate-core-font-glyph-orders.mjs` from installed copies of the faces (the newest release found of each): a glyph's text comes from the face's Unicode `cmap`, or for a ligature glyph no code point reaches, from the components its `GSUB` ligature substitution joins.
334
334
 
335
+ A `/ToUnicode` CMap that a producer writes for the Symbol or Wingdings font (Word does, for a bullet, a tick or an arrow it draws in them) gives each glyph the private-use code point its 8-bit code makes in the 0xF000 range, which identifies the glyph in that one font and nothing else: 0xFC is a check mark in Wingdings and a piece of a right brace in Symbol. `symbol-font-private-use.ts` reads such a code point as the character the named font draws at that code, applied to the text a `/ToUnicode` CMap gave for a Symbol, SymbolMT or Wingdings font, by name, and to no other font: Symbol through its published encoding (the assembly pieces of a tall bracket and the integral extension as their Unicode characters), Wingdings through `wingdings-characters.ts`, the table of Unicode's own Wingdings document. A code the font has no character at, and Wingdings 2 and 3, Webdings and ZapfDingbats, stay as the producer wrote them.
336
+
337
+ Two ways a producer names a core face other than the PostScript name the face's own tables carry are read through the same carried glyph order. A TrueType program Windows-era producers embed under the face's Windows name (`TimesNewRoman`, `Arial,Bold`) is the face `TimesNewRomanPSMT` or `Arial-BoldMT`, still accepted glyph by glyph against the program's own advance widths. And Adobe Acrobat's optimiser rewrites a TrueType face as a CFF subset that names each glyph `G` followed by its glyph id in the face (`G36` is the capital A of Times New Roman) under a font name carrying a size suffix (`Times.New.Roman092`, `Arial.Bold0133`): `coreFaceTextsOfNumberedGlyphs` reads those names through the face's order, but only for a font whose dictionary widths agree with the face's advances over at least five numbered glyphs and nine in ten of them, so a subset of another face, or one too small to tell, is read as before. The Symbol face and the Type 3 fonts such producers also write are not covered: the first has no carried order, and a Type 3 glyph is a drawing procedure with no character.
338
+
335
339
  **Where nothing states an answer, the answer is the replacement character plus a `text/unmapped-encoding` diagnostic, never a guess.** Cases that reach it in practice: a symbolic font with no embedded program and no `/ToUnicode`; a subsetted font that both strips its glyph names and maps its glyphs only from private-use code points; a nameless, `cmap`-less subset of a face whose glyph order this package does not carry, or of a carried face at a glyph its recorded releases do not number; and a composite font whose `/Encoding` is a CMap other than Identity-H or Identity-V, whose codes reach CIDs this reader does not map. A private-use code point identifies a glyph inside one font and says nothing about the character it draws, so it is treated as no answer rather than a wrong one.
336
340
 
337
341
  ## Grouping text runs into lines and words
@@ -92,7 +92,7 @@ function coreFaceSource(font, fontName) {
92
92
  const unitsPerEm = require_font_tables.parseHead(font)?.unitsPerEm;
93
93
  const advanceOf = advanceWidths(font);
94
94
  if (name === void 0 || unitsPerEm === void 0 || advanceOf === void 0) return;
95
- const order = require_core_font_glyph_orders.coreFaceGlyphOrder(require_font_style.withoutSubsetTag(name), unitsPerEm);
95
+ const order = require_core_font_glyph_orders.coreFaceGlyphOrder(require_core_font_glyph_orders.coreFaceNameOfFontName(name) ?? require_font_style.withoutSubsetTag(name), unitsPerEm);
96
96
  if (order === void 0) return;
97
97
  return (glyphId) => order(glyphId, advanceOf(glyphId));
98
98
  }
@@ -2,7 +2,7 @@ import { standardGlyphName } from "./encoding-standard-tables.js";
2
2
  import { hasBytes, parseSfnt, sfntTableBytes, u16, u8 } from "./sfnt.js";
3
3
  import { cffStringForSid, parseCffDict, readCffIndex } from "./cff.js";
4
4
  import { readCmapSubtables } from "./cmap-table.js";
5
- import { coreFaceGlyphOrder } from "./core-font-glyph-orders.js";
5
+ import { coreFaceGlyphOrder, coreFaceNameOfFontName } from "./core-font-glyph-orders.js";
6
6
  import { withoutSubsetTag } from "./font-style.js";
7
7
  import { parseHead, parseMaxp, parseName, parsePostGlyphNames } from "./font-tables.js";
8
8
  import { glyphNameToUnicode } from "./glyph-names.js";
@@ -91,7 +91,7 @@ function coreFaceSource(font, fontName) {
91
91
  const unitsPerEm = parseHead(font)?.unitsPerEm;
92
92
  const advanceOf = advanceWidths(font);
93
93
  if (name === void 0 || unitsPerEm === void 0 || advanceOf === void 0) return;
94
- const order = coreFaceGlyphOrder(withoutSubsetTag(name), unitsPerEm);
94
+ const order = coreFaceGlyphOrder(coreFaceNameOfFontName(name) ?? withoutSubsetTag(name), unitsPerEm);
95
95
  if (order === void 0) return;
96
96
  return (glyphId) => order(glyphId, advanceOf(glyphId));
97
97
  }
@@ -58,5 +58,102 @@ function coreFaceGlyphOrder(postScriptName, unitsPerEm) {
58
58
  if (face?.unitsPerEm !== unitsPerEm) return;
59
59
  return (glyphId, advanceWidth) => face.advances[glyphId] === advanceWidth ? face.texts[glyphId] : void 0;
60
60
  }
61
+ /** The PostScript names of the core faces, by the family and style a font name spells with its punctuation, subset tag and Distiller size suffix taken off. */
62
+ const CORE_FACE_BY_SPELLING = /* @__PURE__ */ new Map([
63
+ ["arial", "ArialMT"],
64
+ ["arialmt", "ArialMT"],
65
+ ["arialbold", "Arial-BoldMT"],
66
+ ["arialboldmt", "Arial-BoldMT"],
67
+ ["arialitalic", "Arial-ItalicMT"],
68
+ ["arialitalicmt", "Arial-ItalicMT"],
69
+ ["arialbolditalic", "Arial-BoldItalicMT"],
70
+ ["arialbolditalicmt", "Arial-BoldItalicMT"],
71
+ ["timesnewroman", "TimesNewRomanPSMT"],
72
+ ["timesnewromanpsmt", "TimesNewRomanPSMT"],
73
+ ["timesnewromanbold", "TimesNewRomanPS-BoldMT"],
74
+ ["timesnewromanpsboldmt", "TimesNewRomanPS-BoldMT"],
75
+ ["timesnewromanitalic", "TimesNewRomanPS-ItalicMT"],
76
+ ["timesnewromanpsitalicmt", "TimesNewRomanPS-ItalicMT"],
77
+ ["timesnewromanbolditalic", "TimesNewRomanPS-BoldItalicMT"],
78
+ ["timesnewromanpsbolditalicmt", "TimesNewRomanPS-BoldItalicMT"],
79
+ ["couriernew", "CourierNewPSMT"],
80
+ ["couriernewpsmt", "CourierNewPSMT"],
81
+ ["couriernewbold", "CourierNewPS-BoldMT"],
82
+ ["couriernewpsboldmt", "CourierNewPS-BoldMT"],
83
+ ["couriernewitalic", "CourierNewPS-ItalicMT"],
84
+ ["couriernewpsitalicmt", "CourierNewPS-ItalicMT"],
85
+ ["couriernewbolditalic", "CourierNewPS-BoldItalicMT"],
86
+ ["couriernewpsbolditalicmt", "CourierNewPS-BoldItalicMT"]
87
+ ]);
88
+ const ZERO_CODE = 48;
89
+ const NINE_CODE = 57;
90
+ const FULL_STOP_CODE = 46;
91
+ function isDigitAt(name, index) {
92
+ const code = name.charCodeAt(index);
93
+ return code >= ZERO_CODE && code <= NINE_CODE;
94
+ }
95
+ function digitRunStart(name, end) {
96
+ let start = end;
97
+ while (start > 0 && isDigitAt(name, start - 1)) start -= 1;
98
+ return start;
99
+ }
100
+ /**
101
+ * `name` without a trailing size or version number a producer appends to a font name ("Arial.Bold0133", "Arial086.75"): digits, optionally a fraction. Found by one scan back from the end, so the work is the length of the number and not of the name: the end-anchored pattern this replaces (a digit run followed by an optional fraction, then the end) is retried from every offset of a long digit run that a letter follows, which takes time quadratic in its length.
102
+ * @param name - A `/BaseFont` name.
103
+ * @returns The name with its trailing number cut off, or the name itself when it does not end in one.
104
+ */
105
+ function withoutTrailingNumber(name) {
106
+ const fractionStart = digitRunStart(name, name.length);
107
+ if (fractionStart === name.length) return name;
108
+ const point = fractionStart - 1;
109
+ if (point > 0 && name.charCodeAt(point) === FULL_STOP_CODE) {
110
+ const wholeStart = digitRunStart(name, point);
111
+ if (wholeStart < point) return name.slice(0, wholeStart);
112
+ }
113
+ return name.slice(0, fractionStart);
114
+ }
115
+ /**
116
+ * The PostScript name of the core face a font name spells, or `undefined` when it spells none: `TimesNewRoman` and `Times.New.Roman.Bold092` are `TimesNewRomanPSMT` and `TimesNewRomanPS-BoldMT`. A spelling is only a candidate: the glyph order is accepted per glyph, against the font dictionary's own widths (`coreFaceTextOfNumberedGlyph`).
117
+ * @param fontName - A `/BaseFont` name, with or without its subset tag.
118
+ * @returns The face's PostScript name, or `undefined`.
119
+ */
120
+ function coreFaceNameOfFontName(fontName) {
121
+ const spelled = withoutTrailingNumber(fontName.replace(/^[A-Z]{6}\+/u, "")).replace(/[^A-Za-z]/gu, "").toLowerCase();
122
+ return CORE_FACE_BY_SPELLING.get(spelled);
123
+ }
124
+ const NUMBERED_GLYPH_NAME = /^G(\d+)$/u;
125
+ const WIDTH_AGREEMENT_TOLERANCE = 25;
126
+ const THOUSANDTHS_PER_EM = 1e3;
127
+ const MIN_AGREEING_SHARE = .9;
128
+ const MIN_NUMBERED_GLYPHS = 5;
129
+ /**
130
+ * What a core face draws at the glyphs of a CFF subset that names each `G<id>`, accepted for the whole font only when the font dictionary's widths agree with the face's advances over at least `MIN_NUMBERED_GLYPHS` glyphs and `MIN_AGREEING_SHARE` of them, so a subset of any other face, or of another release of this one, is read as before.
131
+ * @param fontName - The font's `/BaseFont`.
132
+ * @param glyphs - Each glyph of the font a `/Differences` array names, with the width, in thousandths of an em, the dictionary gives its code.
133
+ * @returns The character each numbered glyph name draws, or `undefined` when the font is not taken for a core face.
134
+ */
135
+ function coreFaceTextsOfNumberedGlyphs(fontName, glyphs) {
136
+ const faceName = coreFaceNameOfFontName(fontName);
137
+ const face = faceName === void 0 ? void 0 : readFaces().get(faceName);
138
+ if (face === void 0) return;
139
+ const texts = /* @__PURE__ */ new Map();
140
+ let numbered = 0;
141
+ let agreeing = 0;
142
+ for (const { name, width } of glyphs) {
143
+ const id = NUMBERED_GLYPH_NAME.exec(name)?.[1];
144
+ const advance = id === void 0 ? void 0 : face.advances[Number.parseInt(id, 10)];
145
+ if (id === void 0 || advance === void 0) continue;
146
+ numbered++;
147
+ const text = face.texts[Number.parseInt(id, 10)];
148
+ if (Math.abs(advance * THOUSANDTHS_PER_EM / face.unitsPerEm - width) <= WIDTH_AGREEMENT_TOLERANCE) {
149
+ agreeing++;
150
+ if (text !== void 0) texts.set(name, text);
151
+ }
152
+ }
153
+ return numbered >= MIN_NUMBERED_GLYPHS && agreeing >= numbered * MIN_AGREEING_SHARE ? texts : void 0;
154
+ }
61
155
  //#endregion
62
156
  exports.coreFaceGlyphOrder = coreFaceGlyphOrder;
157
+ exports.coreFaceNameOfFontName = coreFaceNameOfFontName;
158
+ exports.coreFaceTextsOfNumberedGlyphs = coreFaceTextsOfNumberedGlyphs;
159
+ exports.withoutTrailingNumber = withoutTrailingNumber;
@@ -6,5 +6,27 @@
6
6
  * @returns a lookup from a glyph id and the program's own advance width for that glyph to the character the face draws there, answering undefined wherever the width disagrees with the face's or the face draws no character; or undefined when the name is not a core face or the grid is not the face's
7
7
  */
8
8
  declare function coreFaceGlyphOrder(postScriptName: string, unitsPerEm: number): ((glyphId: number, advanceWidth: number) => string | undefined) | undefined;
9
+ /**
10
+ * `name` without a trailing size or version number a producer appends to a font name ("Arial.Bold0133", "Arial086.75"): digits, optionally a fraction. Found by one scan back from the end, so the work is the length of the number and not of the name: the end-anchored pattern this replaces (a digit run followed by an optional fraction, then the end) is retried from every offset of a long digit run that a letter follows, which takes time quadratic in its length.
11
+ * @param name - A `/BaseFont` name.
12
+ * @returns The name with its trailing number cut off, or the name itself when it does not end in one.
13
+ */
14
+ declare function withoutTrailingNumber(name: string): string;
15
+ /**
16
+ * The PostScript name of the core face a font name spells, or `undefined` when it spells none: `TimesNewRoman` and `Times.New.Roman.Bold092` are `TimesNewRomanPSMT` and `TimesNewRomanPS-BoldMT`. A spelling is only a candidate: the glyph order is accepted per glyph, against the font dictionary's own widths (`coreFaceTextOfNumberedGlyph`).
17
+ * @param fontName - A `/BaseFont` name, with or without its subset tag.
18
+ * @returns The face's PostScript name, or `undefined`.
19
+ */
20
+ declare function coreFaceNameOfFontName(fontName: string): string | undefined;
21
+ /**
22
+ * What a core face draws at the glyphs of a CFF subset that names each `G<id>`, accepted for the whole font only when the font dictionary's widths agree with the face's advances over at least `MIN_NUMBERED_GLYPHS` glyphs and `MIN_AGREEING_SHARE` of them, so a subset of any other face, or of another release of this one, is read as before.
23
+ * @param fontName - The font's `/BaseFont`.
24
+ * @param glyphs - Each glyph of the font a `/Differences` array names, with the width, in thousandths of an em, the dictionary gives its code.
25
+ * @returns The character each numbered glyph name draws, or `undefined` when the font is not taken for a core face.
26
+ */
27
+ declare function coreFaceTextsOfNumberedGlyphs(fontName: string, glyphs: readonly {
28
+ readonly name: string;
29
+ readonly width: number;
30
+ }[]): ReadonlyMap<string, string> | undefined;
9
31
  //#endregion
10
- export { coreFaceGlyphOrder };
32
+ export { coreFaceGlyphOrder, coreFaceNameOfFontName, coreFaceTextsOfNumberedGlyphs, withoutTrailingNumber };
@@ -6,5 +6,27 @@
6
6
  * @returns a lookup from a glyph id and the program's own advance width for that glyph to the character the face draws there, answering undefined wherever the width disagrees with the face's or the face draws no character; or undefined when the name is not a core face or the grid is not the face's
7
7
  */
8
8
  declare function coreFaceGlyphOrder(postScriptName: string, unitsPerEm: number): ((glyphId: number, advanceWidth: number) => string | undefined) | undefined;
9
+ /**
10
+ * `name` without a trailing size or version number a producer appends to a font name ("Arial.Bold0133", "Arial086.75"): digits, optionally a fraction. Found by one scan back from the end, so the work is the length of the number and not of the name: the end-anchored pattern this replaces (a digit run followed by an optional fraction, then the end) is retried from every offset of a long digit run that a letter follows, which takes time quadratic in its length.
11
+ * @param name - A `/BaseFont` name.
12
+ * @returns The name with its trailing number cut off, or the name itself when it does not end in one.
13
+ */
14
+ declare function withoutTrailingNumber(name: string): string;
15
+ /**
16
+ * The PostScript name of the core face a font name spells, or `undefined` when it spells none: `TimesNewRoman` and `Times.New.Roman.Bold092` are `TimesNewRomanPSMT` and `TimesNewRomanPS-BoldMT`. A spelling is only a candidate: the glyph order is accepted per glyph, against the font dictionary's own widths (`coreFaceTextOfNumberedGlyph`).
17
+ * @param fontName - A `/BaseFont` name, with or without its subset tag.
18
+ * @returns The face's PostScript name, or `undefined`.
19
+ */
20
+ declare function coreFaceNameOfFontName(fontName: string): string | undefined;
21
+ /**
22
+ * What a core face draws at the glyphs of a CFF subset that names each `G<id>`, accepted for the whole font only when the font dictionary's widths agree with the face's advances over at least `MIN_NUMBERED_GLYPHS` glyphs and `MIN_AGREEING_SHARE` of them, so a subset of any other face, or of another release of this one, is read as before.
23
+ * @param fontName - The font's `/BaseFont`.
24
+ * @param glyphs - Each glyph of the font a `/Differences` array names, with the width, in thousandths of an em, the dictionary gives its code.
25
+ * @returns The character each numbered glyph name draws, or `undefined` when the font is not taken for a core face.
26
+ */
27
+ declare function coreFaceTextsOfNumberedGlyphs(fontName: string, glyphs: readonly {
28
+ readonly name: string;
29
+ readonly width: number;
30
+ }[]): ReadonlyMap<string, string> | undefined;
9
31
  //#endregion
10
- export { coreFaceGlyphOrder };
32
+ export { coreFaceGlyphOrder, coreFaceNameOfFontName, coreFaceTextsOfNumberedGlyphs, withoutTrailingNumber };
@@ -57,5 +57,99 @@ function coreFaceGlyphOrder(postScriptName, unitsPerEm) {
57
57
  if (face?.unitsPerEm !== unitsPerEm) return;
58
58
  return (glyphId, advanceWidth) => face.advances[glyphId] === advanceWidth ? face.texts[glyphId] : void 0;
59
59
  }
60
+ /** The PostScript names of the core faces, by the family and style a font name spells with its punctuation, subset tag and Distiller size suffix taken off. */
61
+ const CORE_FACE_BY_SPELLING = /* @__PURE__ */ new Map([
62
+ ["arial", "ArialMT"],
63
+ ["arialmt", "ArialMT"],
64
+ ["arialbold", "Arial-BoldMT"],
65
+ ["arialboldmt", "Arial-BoldMT"],
66
+ ["arialitalic", "Arial-ItalicMT"],
67
+ ["arialitalicmt", "Arial-ItalicMT"],
68
+ ["arialbolditalic", "Arial-BoldItalicMT"],
69
+ ["arialbolditalicmt", "Arial-BoldItalicMT"],
70
+ ["timesnewroman", "TimesNewRomanPSMT"],
71
+ ["timesnewromanpsmt", "TimesNewRomanPSMT"],
72
+ ["timesnewromanbold", "TimesNewRomanPS-BoldMT"],
73
+ ["timesnewromanpsboldmt", "TimesNewRomanPS-BoldMT"],
74
+ ["timesnewromanitalic", "TimesNewRomanPS-ItalicMT"],
75
+ ["timesnewromanpsitalicmt", "TimesNewRomanPS-ItalicMT"],
76
+ ["timesnewromanbolditalic", "TimesNewRomanPS-BoldItalicMT"],
77
+ ["timesnewromanpsbolditalicmt", "TimesNewRomanPS-BoldItalicMT"],
78
+ ["couriernew", "CourierNewPSMT"],
79
+ ["couriernewpsmt", "CourierNewPSMT"],
80
+ ["couriernewbold", "CourierNewPS-BoldMT"],
81
+ ["couriernewpsboldmt", "CourierNewPS-BoldMT"],
82
+ ["couriernewitalic", "CourierNewPS-ItalicMT"],
83
+ ["couriernewpsitalicmt", "CourierNewPS-ItalicMT"],
84
+ ["couriernewbolditalic", "CourierNewPS-BoldItalicMT"],
85
+ ["couriernewpsbolditalicmt", "CourierNewPS-BoldItalicMT"]
86
+ ]);
87
+ const ZERO_CODE = 48;
88
+ const NINE_CODE = 57;
89
+ const FULL_STOP_CODE = 46;
90
+ function isDigitAt(name, index) {
91
+ const code = name.charCodeAt(index);
92
+ return code >= ZERO_CODE && code <= NINE_CODE;
93
+ }
94
+ function digitRunStart(name, end) {
95
+ let start = end;
96
+ while (start > 0 && isDigitAt(name, start - 1)) start -= 1;
97
+ return start;
98
+ }
99
+ /**
100
+ * `name` without a trailing size or version number a producer appends to a font name ("Arial.Bold0133", "Arial086.75"): digits, optionally a fraction. Found by one scan back from the end, so the work is the length of the number and not of the name: the end-anchored pattern this replaces (a digit run followed by an optional fraction, then the end) is retried from every offset of a long digit run that a letter follows, which takes time quadratic in its length.
101
+ * @param name - A `/BaseFont` name.
102
+ * @returns The name with its trailing number cut off, or the name itself when it does not end in one.
103
+ */
104
+ function withoutTrailingNumber(name) {
105
+ const fractionStart = digitRunStart(name, name.length);
106
+ if (fractionStart === name.length) return name;
107
+ const point = fractionStart - 1;
108
+ if (point > 0 && name.charCodeAt(point) === FULL_STOP_CODE) {
109
+ const wholeStart = digitRunStart(name, point);
110
+ if (wholeStart < point) return name.slice(0, wholeStart);
111
+ }
112
+ return name.slice(0, fractionStart);
113
+ }
114
+ /**
115
+ * The PostScript name of the core face a font name spells, or `undefined` when it spells none: `TimesNewRoman` and `Times.New.Roman.Bold092` are `TimesNewRomanPSMT` and `TimesNewRomanPS-BoldMT`. A spelling is only a candidate: the glyph order is accepted per glyph, against the font dictionary's own widths (`coreFaceTextOfNumberedGlyph`).
116
+ * @param fontName - A `/BaseFont` name, with or without its subset tag.
117
+ * @returns The face's PostScript name, or `undefined`.
118
+ */
119
+ function coreFaceNameOfFontName(fontName) {
120
+ const spelled = withoutTrailingNumber(fontName.replace(/^[A-Z]{6}\+/u, "")).replace(/[^A-Za-z]/gu, "").toLowerCase();
121
+ return CORE_FACE_BY_SPELLING.get(spelled);
122
+ }
123
+ const NUMBERED_GLYPH_NAME = /^G(\d+)$/u;
124
+ const WIDTH_AGREEMENT_TOLERANCE = 25;
125
+ const THOUSANDTHS_PER_EM = 1e3;
126
+ const MIN_AGREEING_SHARE = .9;
127
+ const MIN_NUMBERED_GLYPHS = 5;
128
+ /**
129
+ * What a core face draws at the glyphs of a CFF subset that names each `G<id>`, accepted for the whole font only when the font dictionary's widths agree with the face's advances over at least `MIN_NUMBERED_GLYPHS` glyphs and `MIN_AGREEING_SHARE` of them, so a subset of any other face, or of another release of this one, is read as before.
130
+ * @param fontName - The font's `/BaseFont`.
131
+ * @param glyphs - Each glyph of the font a `/Differences` array names, with the width, in thousandths of an em, the dictionary gives its code.
132
+ * @returns The character each numbered glyph name draws, or `undefined` when the font is not taken for a core face.
133
+ */
134
+ function coreFaceTextsOfNumberedGlyphs(fontName, glyphs) {
135
+ const faceName = coreFaceNameOfFontName(fontName);
136
+ const face = faceName === void 0 ? void 0 : readFaces().get(faceName);
137
+ if (face === void 0) return;
138
+ const texts = /* @__PURE__ */ new Map();
139
+ let numbered = 0;
140
+ let agreeing = 0;
141
+ for (const { name, width } of glyphs) {
142
+ const id = NUMBERED_GLYPH_NAME.exec(name)?.[1];
143
+ const advance = id === void 0 ? void 0 : face.advances[Number.parseInt(id, 10)];
144
+ if (id === void 0 || advance === void 0) continue;
145
+ numbered++;
146
+ const text = face.texts[Number.parseInt(id, 10)];
147
+ if (Math.abs(advance * THOUSANDTHS_PER_EM / face.unitsPerEm - width) <= WIDTH_AGREEMENT_TOLERANCE) {
148
+ agreeing++;
149
+ if (text !== void 0) texts.set(name, text);
150
+ }
151
+ }
152
+ return numbered >= MIN_NUMBERED_GLYPHS && agreeing >= numbered * MIN_AGREEING_SHARE ? texts : void 0;
153
+ }
60
154
  //#endregion
61
- export { coreFaceGlyphOrder };
155
+ export { coreFaceGlyphOrder, coreFaceNameOfFontName, coreFaceTextsOfNumberedGlyphs, withoutTrailingNumber };
@@ -3,12 +3,14 @@ const require_encoding = require("./encoding.cjs");
3
3
  const require_afm_widths = require("./afm-widths.cjs");
4
4
  const require_objects = require("./objects.cjs");
5
5
  const require_filters = require("./filters.cjs");
6
+ const require_core_font_glyph_orders = require("./core-font-glyph-orders.cjs");
6
7
  const require_font_style = require("./font-style.cjs");
7
8
  const require_glyph_names = require("./glyph-names.cjs");
8
9
  const require_builtin_encoding = require("./builtin-encoding.cjs");
9
10
  const require_cmap = require("./cmap.cjs");
10
11
  const require_encoding_symbol_tables = require("./encoding-symbol-tables.cjs");
11
12
  const require_fonts = require("./fonts.cjs");
13
+ const require_symbol_font_private_use = require("./symbol-font-private-use.cjs");
12
14
  //#region src/font-read.ts
13
15
  const BITS_PER_BYTE = 8;
14
16
  const SYMBOLIC_FLAG_BIT = 4;
@@ -84,6 +86,7 @@ function buildSimpleFont(fontDict, context) {
84
86
  const { baseFamily, bold, italic } = require_font_style.styleFromBaseFontName(baseFont, styleFlags);
85
87
  const symbolic = styleFlags.symbolic ?? false;
86
88
  const builtinGlyphName = builtinSymbolGlyphNameLookup(baseFamily);
89
+ const symbolFont = require_symbol_font_private_use.symbolFontOf(baseFamily);
87
90
  const widthsArr = resolvedArray(require_objects.dictGet(fontDict, "Widths"), context);
88
91
  const firstChar = require_objects.asNumber(require_objects.dictGet(fontDict, "FirstChar")) ?? 0;
89
92
  const missingWidth = (descriptor !== void 0 ? require_objects.asNumber(require_objects.dictGet(descriptor, "MissingWidth")) : void 0) ?? 0;
@@ -123,9 +126,19 @@ function buildSimpleFont(fontDict, context) {
123
126
  });
124
127
  const differencesMap = readDifferencesMap(encodingDict !== void 0 ? resolvedArray(require_objects.dictGet(encodingDict, "Differences"), context) : void 0);
125
128
  const programEncoding = lazyFontProgram(descriptor, baseFont, context);
129
+ let numberedTexts;
130
+ const numberedCoreFaceTexts = () => {
131
+ numberedTexts ??= require_core_font_glyph_orders.coreFaceTextsOfNumberedGlyphs(baseFont, [...differencesMap].map(([code, name]) => ({
132
+ name,
133
+ width: widthOf(code)
134
+ }))) ?? /* @__PURE__ */ new Map();
135
+ return numberedTexts;
136
+ };
126
137
  const unicodeForDifferencesName = (name) => {
127
138
  const named = require_glyph_names.glyphNameToUnicode(name);
128
139
  if (named !== void 0) return named;
140
+ const ofCoreFace = numberedCoreFaceTexts().get(name);
141
+ if (ofCoreFace !== void 0) return ofCoreFace;
129
142
  const program = programEncoding();
130
143
  const glyphId = program?.glyphIdOfName(name);
131
144
  return glyphId === void 0 ? void 0 : program?.glyphIdToUnicode(glyphId);
@@ -160,7 +173,7 @@ function buildSimpleFont(fontDict, context) {
160
173
  for (const code of codes) {
161
174
  const viaToUnicode = toUnicode?.lookup(code);
162
175
  if (viaToUnicode !== void 0) {
163
- out += viaToUnicode;
176
+ out += require_symbol_font_private_use.withSymbolFontCharacters(symbolFont, viaToUnicode);
164
177
  continue;
165
178
  }
166
179
  const unicode = unicodeForCode(code);
@@ -321,6 +334,7 @@ function buildCompositeFont(fontDict, context) {
321
334
  };
322
335
  };
323
336
  const toUnicode = readToUnicodeCMap(fontDict, context);
337
+ const symbolFont = require_symbol_font_private_use.symbolFontOf(baseFamily);
324
338
  const glyphIdOf = cidToGlyphId(fontDict, descendantDict, context);
325
339
  const programEncoding = glyphIdOf !== void 0 ? lazyFontProgram(descriptor, baseFont, context) : void 0;
326
340
  const decodeToUnicode = (codes) => {
@@ -332,7 +346,7 @@ function buildCompositeFont(fontDict, context) {
332
346
  const cid = (codes[i] ?? 0) << BITS_PER_BYTE | (codes[i + 1] ?? 0);
333
347
  const mapped = toUnicode?.lookup(cid);
334
348
  if (mapped !== void 0) {
335
- out += mapped;
349
+ out += require_symbol_font_private_use.withSymbolFontCharacters(symbolFont, mapped);
336
350
  continue;
337
351
  }
338
352
  const glyphId = glyphIdOf?.(cid);
package/dist/font-read.js CHANGED
@@ -2,12 +2,14 @@ import { namedEncodingGlyphName, winAnsiGlyphName } from "./encoding.js";
2
2
  import { afmWidthOfCode } from "./afm-widths.js";
3
3
  import { asArray, asName, asNumber, dictGet, isName } from "./objects.js";
4
4
  import { decodeStream } from "./filters.js";
5
+ import { coreFaceTextsOfNumberedGlyphs } from "./core-font-glyph-orders.js";
5
6
  import { styleFromBaseFontName } from "./font-style.js";
6
7
  import { glyphNameToUnicode } from "./glyph-names.js";
7
8
  import { readFontProgramEncoding } from "./builtin-encoding.js";
8
9
  import { parseToUnicodeCMap } from "./cmap.js";
9
10
  import { symbolGlyphName, zapfDingbatsGlyphName } from "./encoding-symbol-tables.js";
10
11
  import { resolveStandardFont } from "./fonts.js";
12
+ import { symbolFontOf, withSymbolFontCharacters } from "./symbol-font-private-use.js";
11
13
  //#region src/font-read.ts
12
14
  const BITS_PER_BYTE = 8;
13
15
  const SYMBOLIC_FLAG_BIT = 4;
@@ -83,6 +85,7 @@ function buildSimpleFont(fontDict, context) {
83
85
  const { baseFamily, bold, italic } = styleFromBaseFontName(baseFont, styleFlags);
84
86
  const symbolic = styleFlags.symbolic ?? false;
85
87
  const builtinGlyphName = builtinSymbolGlyphNameLookup(baseFamily);
88
+ const symbolFont = symbolFontOf(baseFamily);
86
89
  const widthsArr = resolvedArray(dictGet(fontDict, "Widths"), context);
87
90
  const firstChar = asNumber(dictGet(fontDict, "FirstChar")) ?? 0;
88
91
  const missingWidth = (descriptor !== void 0 ? asNumber(dictGet(descriptor, "MissingWidth")) : void 0) ?? 0;
@@ -122,9 +125,19 @@ function buildSimpleFont(fontDict, context) {
122
125
  });
123
126
  const differencesMap = readDifferencesMap(encodingDict !== void 0 ? resolvedArray(dictGet(encodingDict, "Differences"), context) : void 0);
124
127
  const programEncoding = lazyFontProgram(descriptor, baseFont, context);
128
+ let numberedTexts;
129
+ const numberedCoreFaceTexts = () => {
130
+ numberedTexts ??= coreFaceTextsOfNumberedGlyphs(baseFont, [...differencesMap].map(([code, name]) => ({
131
+ name,
132
+ width: widthOf(code)
133
+ }))) ?? /* @__PURE__ */ new Map();
134
+ return numberedTexts;
135
+ };
125
136
  const unicodeForDifferencesName = (name) => {
126
137
  const named = glyphNameToUnicode(name);
127
138
  if (named !== void 0) return named;
139
+ const ofCoreFace = numberedCoreFaceTexts().get(name);
140
+ if (ofCoreFace !== void 0) return ofCoreFace;
128
141
  const program = programEncoding();
129
142
  const glyphId = program?.glyphIdOfName(name);
130
143
  return glyphId === void 0 ? void 0 : program?.glyphIdToUnicode(glyphId);
@@ -159,7 +172,7 @@ function buildSimpleFont(fontDict, context) {
159
172
  for (const code of codes) {
160
173
  const viaToUnicode = toUnicode?.lookup(code);
161
174
  if (viaToUnicode !== void 0) {
162
- out += viaToUnicode;
175
+ out += withSymbolFontCharacters(symbolFont, viaToUnicode);
163
176
  continue;
164
177
  }
165
178
  const unicode = unicodeForCode(code);
@@ -320,6 +333,7 @@ function buildCompositeFont(fontDict, context) {
320
333
  };
321
334
  };
322
335
  const toUnicode = readToUnicodeCMap(fontDict, context);
336
+ const symbolFont = symbolFontOf(baseFamily);
323
337
  const glyphIdOf = cidToGlyphId(fontDict, descendantDict, context);
324
338
  const programEncoding = glyphIdOf !== void 0 ? lazyFontProgram(descriptor, baseFont, context) : void 0;
325
339
  const decodeToUnicode = (codes) => {
@@ -331,7 +345,7 @@ function buildCompositeFont(fontDict, context) {
331
345
  const cid = (codes[i] ?? 0) << BITS_PER_BYTE | (codes[i + 1] ?? 0);
332
346
  const mapped = toUnicode?.lookup(cid);
333
347
  if (mapped !== void 0) {
334
- out += mapped;
348
+ out += withSymbolFontCharacters(symbolFont, mapped);
335
349
  continue;
336
350
  }
337
351
  const glyphId = glyphIdOf?.(cid);
@@ -0,0 +1,86 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_glyph_names = require("./glyph-names.cjs");
3
+ const require_encoding_symbol_tables = require("./encoding-symbol-tables.cjs");
4
+ const require_wingdings_characters = require("./wingdings-characters.cjs");
5
+ //#region src/symbol-font-private-use.ts
6
+ const SYMBOL_FONT_PRIVATE_USE_BASE = 61440;
7
+ /**
8
+ * The symbol font a font family name stands for, whichever way the producer spells it ("Symbol", "SymbolMT", "Wingdings"), or `undefined` for any other font.
9
+ * @param family - The font's family as `styleFromBaseFontName` reads it from `/BaseFont`: the subset tag and style suffix already removed.
10
+ * @returns The symbol font the family names, or `undefined`.
11
+ */
12
+ function symbolFontOf(family) {
13
+ const name = family.replace(/[\s_-]/gu, "").toLowerCase();
14
+ if (name === "symbol" || name === "symbolmt") return "symbol";
15
+ return name === "wingdings" ? "wingdings" : void 0;
16
+ }
17
+ function isSymbolFontCode(codePoint) {
18
+ return codePoint >= 61472 && codePoint <= 61695;
19
+ }
20
+ function isPrivateUse(text) {
21
+ return /^\p{Co}/u.test(text);
22
+ }
23
+ /**
24
+ * The Symbol glyphs that the Adobe Glyph List gives code points of Adobe's own Private Use Area (U+F6xx and U+F8xx), which name no character, and the Unicode characters that are the same glyphs: the pieces a tall bracket, parenthesis or brace is assembled from, the extensions of the integral, vertical-arrow and horizontal-arrow signs, and the serif and sans-serif registered, copyright and trade mark signs. Keyed by the glyph's PostScript name in the Symbol font's built-in encoding (Adobe's `symbol.txt`, https://www.unicode.org/Public/MAPPINGS/VENDORS/ADOBE/symbol.txt, archived at https://web.archive.org/web/20261011050748/http://www.unicode.org/Public/MAPPINGS/VENDORS/ADOBE/symbol.txt), valued by the character of the Unicode Miscellaneous Technical block (https://www.unicode.org/charts/PDF/U2300.pdf, archived at https://web.archive.org/web/2026/https://www.unicode.org/charts/PDF/U2300.pdf) or Latin-1 and Letterlike Symbols block the glyph is. `radicalex`, the extension of the radical sign, is the one such glyph with no Unicode character, and stays as it was written.
25
+ */
26
+ const SYMBOL_ASSEMBLY_PIECES = /* @__PURE__ */ new Map([
27
+ ["parenlefttp", "โŽ›"],
28
+ ["parenleftex", "โŽœ"],
29
+ ["parenleftbt", "โŽ"],
30
+ ["parenrighttp", "โŽž"],
31
+ ["parenrightex", "โŽŸ"],
32
+ ["parenrightbt", "โŽ "],
33
+ ["bracketlefttp", "โŽก"],
34
+ ["bracketleftex", "โŽข"],
35
+ ["bracketleftbt", "โŽฃ"],
36
+ ["bracketrighttp", "โŽค"],
37
+ ["bracketrightex", "โŽฅ"],
38
+ ["bracketrightbt", "โŽฆ"],
39
+ ["bracelefttp", "โŽง"],
40
+ ["braceleftmid", "โŽจ"],
41
+ ["braceleftbt", "โŽฉ"],
42
+ ["braceex", "โŽช"],
43
+ ["bracerighttp", "โŽซ"],
44
+ ["bracerightmid", "โŽฌ"],
45
+ ["bracerightbt", "โŽญ"],
46
+ ["integralex", "โŽฎ"],
47
+ ["arrowhorizex", "โŽฏ"],
48
+ ["arrowvertex", "โ"],
49
+ ["registerserif", "ยฎ"],
50
+ ["registersans", "ยฎ"],
51
+ ["copyrightserif", "ยฉ"],
52
+ ["copyrightsans", "ยฉ"],
53
+ ["trademarkserif", "โ„ข"],
54
+ ["trademarksans", "โ„ข"]
55
+ ]);
56
+ function symbolCharacter(code) {
57
+ const name = require_encoding_symbol_tables.symbolGlyphName(code);
58
+ if (name === void 0) return;
59
+ const piece = SYMBOL_ASSEMBLY_PIECES.get(name);
60
+ if (piece !== void 0) return piece;
61
+ const text = require_glyph_names.glyphNameToUnicode(name);
62
+ return text !== void 0 && text !== "" && !isPrivateUse(text) ? text : void 0;
63
+ }
64
+ function wingdingsCharacter(code) {
65
+ const character = require_wingdings_characters.WINGDINGS_CHARACTERS[code];
66
+ return character === void 0 || character === "" ? void 0 : character;
67
+ }
68
+ /**
69
+ * `text`, the Unicode a font's /ToUnicode CMap gave for a run of its codes, with each Private Use Area code point that is one of the font's own 8-bit codes (0xF020 to 0xF0FF) replaced by the character the font's glyph at that code is. Nothing else changes: a code point outside that range, one the font has no character at, and every character of a font that is not a symbol font stay as they were.
70
+ * @param font - The symbol font the text was read through, `undefined` for any other font, whose text is returned as it is.
71
+ * @param text - The text a CMap gave for one or more codes.
72
+ * @returns The text with the font's own characters in place of its private-use code points.
73
+ */
74
+ function withSymbolFontCharacters(font, text) {
75
+ if (font === void 0) return text;
76
+ const character = font === "symbol" ? symbolCharacter : wingdingsCharacter;
77
+ let out = "";
78
+ for (const char of text) {
79
+ const codePoint = char.codePointAt(0);
80
+ out += codePoint !== void 0 && isSymbolFontCode(codePoint) ? character(codePoint - SYMBOL_FONT_PRIVATE_USE_BASE) ?? char : char;
81
+ }
82
+ return out;
83
+ }
84
+ //#endregion
85
+ exports.symbolFontOf = symbolFontOf;
86
+ exports.withSymbolFontCharacters = withSymbolFontCharacters;
@@ -0,0 +1,18 @@
1
+ //#region src/symbol-font-private-use.d.ts
2
+ /** The symbol fonts whose 8-bit codes are mapped: the two a Word document uses for bullets, ticks, arrows and mathematical signs. Wingdings 2 and 3, Webdings and ZapfDingbats are different fonts with their own tables and are left as the producer wrote them. */
3
+ type SymbolFont = "symbol" | "wingdings";
4
+ /**
5
+ * The symbol font a font family name stands for, whichever way the producer spells it ("Symbol", "SymbolMT", "Wingdings"), or `undefined` for any other font.
6
+ * @param family - The font's family as `styleFromBaseFontName` reads it from `/BaseFont`: the subset tag and style suffix already removed.
7
+ * @returns The symbol font the family names, or `undefined`.
8
+ */
9
+ declare function symbolFontOf(family: string): SymbolFont | undefined;
10
+ /**
11
+ * `text`, the Unicode a font's /ToUnicode CMap gave for a run of its codes, with each Private Use Area code point that is one of the font's own 8-bit codes (0xF020 to 0xF0FF) replaced by the character the font's glyph at that code is. Nothing else changes: a code point outside that range, one the font has no character at, and every character of a font that is not a symbol font stay as they were.
12
+ * @param font - The symbol font the text was read through, `undefined` for any other font, whose text is returned as it is.
13
+ * @param text - The text a CMap gave for one or more codes.
14
+ * @returns The text with the font's own characters in place of its private-use code points.
15
+ */
16
+ declare function withSymbolFontCharacters(font: SymbolFont | undefined, text: string): string;
17
+ //#endregion
18
+ export { SymbolFont, symbolFontOf, withSymbolFontCharacters };
@@ -0,0 +1,18 @@
1
+ //#region src/symbol-font-private-use.d.ts
2
+ /** The symbol fonts whose 8-bit codes are mapped: the two a Word document uses for bullets, ticks, arrows and mathematical signs. Wingdings 2 and 3, Webdings and ZapfDingbats are different fonts with their own tables and are left as the producer wrote them. */
3
+ type SymbolFont = "symbol" | "wingdings";
4
+ /**
5
+ * The symbol font a font family name stands for, whichever way the producer spells it ("Symbol", "SymbolMT", "Wingdings"), or `undefined` for any other font.
6
+ * @param family - The font's family as `styleFromBaseFontName` reads it from `/BaseFont`: the subset tag and style suffix already removed.
7
+ * @returns The symbol font the family names, or `undefined`.
8
+ */
9
+ declare function symbolFontOf(family: string): SymbolFont | undefined;
10
+ /**
11
+ * `text`, the Unicode a font's /ToUnicode CMap gave for a run of its codes, with each Private Use Area code point that is one of the font's own 8-bit codes (0xF020 to 0xF0FF) replaced by the character the font's glyph at that code is. Nothing else changes: a code point outside that range, one the font has no character at, and every character of a font that is not a symbol font stay as they were.
12
+ * @param font - The symbol font the text was read through, `undefined` for any other font, whose text is returned as it is.
13
+ * @param text - The text a CMap gave for one or more codes.
14
+ * @returns The text with the font's own characters in place of its private-use code points.
15
+ */
16
+ declare function withSymbolFontCharacters(font: SymbolFont | undefined, text: string): string;
17
+ //#endregion
18
+ export { SymbolFont, symbolFontOf, withSymbolFontCharacters };
@@ -0,0 +1,84 @@
1
+ import { glyphNameToUnicode } from "./glyph-names.js";
2
+ import { symbolGlyphName } from "./encoding-symbol-tables.js";
3
+ import { WINGDINGS_CHARACTERS } from "./wingdings-characters.js";
4
+ //#region src/symbol-font-private-use.ts
5
+ const SYMBOL_FONT_PRIVATE_USE_BASE = 61440;
6
+ /**
7
+ * The symbol font a font family name stands for, whichever way the producer spells it ("Symbol", "SymbolMT", "Wingdings"), or `undefined` for any other font.
8
+ * @param family - The font's family as `styleFromBaseFontName` reads it from `/BaseFont`: the subset tag and style suffix already removed.
9
+ * @returns The symbol font the family names, or `undefined`.
10
+ */
11
+ function symbolFontOf(family) {
12
+ const name = family.replace(/[\s_-]/gu, "").toLowerCase();
13
+ if (name === "symbol" || name === "symbolmt") return "symbol";
14
+ return name === "wingdings" ? "wingdings" : void 0;
15
+ }
16
+ function isSymbolFontCode(codePoint) {
17
+ return codePoint >= 61472 && codePoint <= 61695;
18
+ }
19
+ function isPrivateUse(text) {
20
+ return /^\p{Co}/u.test(text);
21
+ }
22
+ /**
23
+ * The Symbol glyphs that the Adobe Glyph List gives code points of Adobe's own Private Use Area (U+F6xx and U+F8xx), which name no character, and the Unicode characters that are the same glyphs: the pieces a tall bracket, parenthesis or brace is assembled from, the extensions of the integral, vertical-arrow and horizontal-arrow signs, and the serif and sans-serif registered, copyright and trade mark signs. Keyed by the glyph's PostScript name in the Symbol font's built-in encoding (Adobe's `symbol.txt`, https://www.unicode.org/Public/MAPPINGS/VENDORS/ADOBE/symbol.txt, archived at https://web.archive.org/web/20261011050748/http://www.unicode.org/Public/MAPPINGS/VENDORS/ADOBE/symbol.txt), valued by the character of the Unicode Miscellaneous Technical block (https://www.unicode.org/charts/PDF/U2300.pdf, archived at https://web.archive.org/web/2026/https://www.unicode.org/charts/PDF/U2300.pdf) or Latin-1 and Letterlike Symbols block the glyph is. `radicalex`, the extension of the radical sign, is the one such glyph with no Unicode character, and stays as it was written.
24
+ */
25
+ const SYMBOL_ASSEMBLY_PIECES = /* @__PURE__ */ new Map([
26
+ ["parenlefttp", "โŽ›"],
27
+ ["parenleftex", "โŽœ"],
28
+ ["parenleftbt", "โŽ"],
29
+ ["parenrighttp", "โŽž"],
30
+ ["parenrightex", "โŽŸ"],
31
+ ["parenrightbt", "โŽ "],
32
+ ["bracketlefttp", "โŽก"],
33
+ ["bracketleftex", "โŽข"],
34
+ ["bracketleftbt", "โŽฃ"],
35
+ ["bracketrighttp", "โŽค"],
36
+ ["bracketrightex", "โŽฅ"],
37
+ ["bracketrightbt", "โŽฆ"],
38
+ ["bracelefttp", "โŽง"],
39
+ ["braceleftmid", "โŽจ"],
40
+ ["braceleftbt", "โŽฉ"],
41
+ ["braceex", "โŽช"],
42
+ ["bracerighttp", "โŽซ"],
43
+ ["bracerightmid", "โŽฌ"],
44
+ ["bracerightbt", "โŽญ"],
45
+ ["integralex", "โŽฎ"],
46
+ ["arrowhorizex", "โŽฏ"],
47
+ ["arrowvertex", "โ"],
48
+ ["registerserif", "ยฎ"],
49
+ ["registersans", "ยฎ"],
50
+ ["copyrightserif", "ยฉ"],
51
+ ["copyrightsans", "ยฉ"],
52
+ ["trademarkserif", "โ„ข"],
53
+ ["trademarksans", "โ„ข"]
54
+ ]);
55
+ function symbolCharacter(code) {
56
+ const name = symbolGlyphName(code);
57
+ if (name === void 0) return;
58
+ const piece = SYMBOL_ASSEMBLY_PIECES.get(name);
59
+ if (piece !== void 0) return piece;
60
+ const text = glyphNameToUnicode(name);
61
+ return text !== void 0 && text !== "" && !isPrivateUse(text) ? text : void 0;
62
+ }
63
+ function wingdingsCharacter(code) {
64
+ const character = WINGDINGS_CHARACTERS[code];
65
+ return character === void 0 || character === "" ? void 0 : character;
66
+ }
67
+ /**
68
+ * `text`, the Unicode a font's /ToUnicode CMap gave for a run of its codes, with each Private Use Area code point that is one of the font's own 8-bit codes (0xF020 to 0xF0FF) replaced by the character the font's glyph at that code is. Nothing else changes: a code point outside that range, one the font has no character at, and every character of a font that is not a symbol font stay as they were.
69
+ * @param font - The symbol font the text was read through, `undefined` for any other font, whose text is returned as it is.
70
+ * @param text - The text a CMap gave for one or more codes.
71
+ * @returns The text with the font's own characters in place of its private-use code points.
72
+ */
73
+ function withSymbolFontCharacters(font, text) {
74
+ if (font === void 0) return text;
75
+ const character = font === "symbol" ? symbolCharacter : wingdingsCharacter;
76
+ let out = "";
77
+ for (const char of text) {
78
+ const codePoint = char.codePointAt(0);
79
+ out += codePoint !== void 0 && isSymbolFontCode(codePoint) ? character(codePoint - SYMBOL_FONT_PRIVATE_USE_BASE) ?? char : char;
80
+ }
81
+ return out;
82
+ }
83
+ //#endregion
84
+ export { symbolFontOf, withSymbolFontCharacters };
@@ -0,0 +1,262 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ //#region src/wingdings-characters.ts
3
+ const WINGDINGS_CHARACTERS = [
4
+ "",
5
+ "",
6
+ "",
7
+ "",
8
+ "",
9
+ "",
10
+ "",
11
+ "",
12
+ "",
13
+ "",
14
+ "",
15
+ "",
16
+ "",
17
+ "",
18
+ "",
19
+ "",
20
+ "",
21
+ "",
22
+ "",
23
+ "",
24
+ "",
25
+ "",
26
+ "",
27
+ "",
28
+ "",
29
+ "",
30
+ "",
31
+ "",
32
+ "",
33
+ "",
34
+ "",
35
+ "",
36
+ " ",
37
+ "๐Ÿ–‰",
38
+ "โœ‚",
39
+ "โœ",
40
+ "๐Ÿ‘“",
41
+ "๐Ÿ•ญ",
42
+ "๐Ÿ•ฎ",
43
+ "๐Ÿ•ฏ",
44
+ "๐Ÿ•ฟ",
45
+ "โœ†",
46
+ "๐Ÿ–‚",
47
+ "๐Ÿ–ƒ",
48
+ "๐Ÿ“ช",
49
+ "๐Ÿ“ซ",
50
+ "๐Ÿ“ฌ",
51
+ "๐Ÿ“ญ",
52
+ "๐Ÿ—€",
53
+ "๐Ÿ—",
54
+ "๐Ÿ—Ž",
55
+ "๐Ÿ—",
56
+ "๐Ÿ—",
57
+ "๐Ÿ—„",
58
+ "โณ",
59
+ "๐Ÿ–ฎ",
60
+ "๐Ÿ–ฐ",
61
+ "๐Ÿ–ฒ",
62
+ "๐Ÿ–ณ",
63
+ "๐Ÿ–ด",
64
+ "๐Ÿ–ซ",
65
+ "๐Ÿ–ฌ",
66
+ "โœ‡",
67
+ "โœ",
68
+ "๐Ÿ–Ž",
69
+ "โœŒ",
70
+ "๐Ÿ–",
71
+ "๐Ÿ‘",
72
+ "๐Ÿ‘Ž",
73
+ "โ˜œ",
74
+ "โ˜ž",
75
+ "โ˜",
76
+ "๐Ÿ–—",
77
+ "๐Ÿ–",
78
+ "โ˜บ",
79
+ "๐Ÿ˜",
80
+ "โ˜น",
81
+ "๐Ÿ’ฃ",
82
+ "๐Ÿ•ฑ",
83
+ "๐Ÿณ",
84
+ "๐Ÿฑ",
85
+ "โœˆ",
86
+ "โ˜ผ",
87
+ "๐ŸŒข",
88
+ "โ„",
89
+ "๐Ÿ•†",
90
+ "โœž",
91
+ "๐Ÿ•ˆ",
92
+ "โœ ",
93
+ "โœก",
94
+ "โ˜ช",
95
+ "โ˜ฏ",
96
+ "๐Ÿ•‰",
97
+ "โ˜ธ",
98
+ "โ™ˆ",
99
+ "โ™‰",
100
+ "โ™Š",
101
+ "โ™‹",
102
+ "โ™Œ",
103
+ "โ™",
104
+ "โ™Ž",
105
+ "โ™",
106
+ "โ™",
107
+ "โ™‘",
108
+ "โ™’",
109
+ "โ™“",
110
+ "๐Ÿ™ฐ",
111
+ "๐Ÿ™ต",
112
+ "โšซ",
113
+ "๐Ÿ”พ",
114
+ "โ—ผ",
115
+ "๐Ÿž",
116
+ "๐Ÿž",
117
+ "โ‘",
118
+ "โ’",
119
+ "๐ŸžŸ",
120
+ "โงซ",
121
+ "โ—†",
122
+ "โ–",
123
+ "๐Ÿž™",
124
+ "โŒง",
125
+ "โฎน",
126
+ "โŒ˜",
127
+ "๐Ÿต",
128
+ "๐Ÿถ",
129
+ "๐Ÿ™ถ",
130
+ "๐Ÿ™ท",
131
+ "",
132
+ "๐Ÿ„‹",
133
+ "โž€",
134
+ "โž",
135
+ "โž‚",
136
+ "โžƒ",
137
+ "โž„",
138
+ "โž…",
139
+ "โž†",
140
+ "โž‡",
141
+ "โžˆ",
142
+ "โž‰",
143
+ "๐Ÿ„Œ",
144
+ "โžŠ",
145
+ "โž‹",
146
+ "โžŒ",
147
+ "โž",
148
+ "โžŽ",
149
+ "โž",
150
+ "โž",
151
+ "โž‘",
152
+ "โž’",
153
+ "โž“",
154
+ "๐Ÿ™ข",
155
+ "๐Ÿ™ ",
156
+ "๐Ÿ™ก",
157
+ "๐Ÿ™ฃ",
158
+ "๐Ÿ™ž",
159
+ "๐Ÿ™œ",
160
+ "๐Ÿ™",
161
+ "๐Ÿ™Ÿ",
162
+ "โˆ™",
163
+ "โ€ข",
164
+ "โฌ",
165
+ "โญ˜",
166
+ "๐Ÿž†",
167
+ "๐Ÿžˆ",
168
+ "๐ŸžŠ",
169
+ "๐Ÿž‹",
170
+ "๐Ÿ”ฟ",
171
+ "โ–ช",
172
+ "๐ŸžŽ",
173
+ "๐ŸŸ",
174
+ "๐ŸŸ…",
175
+ "โ˜…",
176
+ "๐ŸŸ‹",
177
+ "๐ŸŸ",
178
+ "๐ŸŸ“",
179
+ "๐ŸŸ‘",
180
+ "โฏ",
181
+ "โŒ–",
182
+ "โฏŽ",
183
+ "โฏ",
184
+ "โฏ‘",
185
+ "โœช",
186
+ "โœฐ",
187
+ "๐Ÿ•",
188
+ "๐Ÿ•‘",
189
+ "๐Ÿ•’",
190
+ "๐Ÿ•“",
191
+ "๐Ÿ•”",
192
+ "๐Ÿ••",
193
+ "๐Ÿ•–",
194
+ "๐Ÿ•—",
195
+ "๐Ÿ•˜",
196
+ "๐Ÿ•™",
197
+ "๐Ÿ•š",
198
+ "๐Ÿ•›",
199
+ "โฎฐ",
200
+ "โฎฑ",
201
+ "โฎฒ",
202
+ "โฎณ",
203
+ "โฎด",
204
+ "โฎต",
205
+ "โฎถ",
206
+ "โฎท",
207
+ "๐Ÿ™ช",
208
+ "๐Ÿ™ซ",
209
+ "๐Ÿ™•",
210
+ "๐Ÿ™”",
211
+ "๐Ÿ™—",
212
+ "๐Ÿ™–",
213
+ "๐Ÿ™",
214
+ "๐Ÿ™‘",
215
+ "๐Ÿ™’",
216
+ "๐Ÿ™“",
217
+ "โŒซ",
218
+ "โŒฆ",
219
+ "โฎ˜",
220
+ "โฎš",
221
+ "โฎ™",
222
+ "โฎ›",
223
+ "โฎˆ",
224
+ "โฎŠ",
225
+ "โฎ‰",
226
+ "โฎ‹",
227
+ "๐Ÿกจ",
228
+ "๐Ÿกช",
229
+ "๐Ÿกฉ",
230
+ "๐Ÿกซ",
231
+ "๐Ÿกฌ",
232
+ "๐Ÿกญ",
233
+ "๐Ÿกฏ",
234
+ "๐Ÿกฎ",
235
+ "๐Ÿกธ",
236
+ "๐Ÿกบ",
237
+ "๐Ÿกน",
238
+ "๐Ÿกป",
239
+ "๐Ÿกผ",
240
+ "๐Ÿกฝ",
241
+ "๐Ÿกฟ",
242
+ "๐Ÿกพ",
243
+ "โ‡ฆ",
244
+ "โ‡จ",
245
+ "โ‡ง",
246
+ "โ‡ฉ",
247
+ "โฌ„",
248
+ "โ‡ณ",
249
+ "โฌ",
250
+ "โฌ€",
251
+ "โฌƒ",
252
+ "โฌ‚",
253
+ "๐Ÿขฌ",
254
+ "๐Ÿขญ",
255
+ "๐Ÿ—ถ",
256
+ "โœ“",
257
+ "๐Ÿ—ท",
258
+ "๐Ÿ—น",
259
+ ""
260
+ ];
261
+ //#endregion
262
+ exports.WINGDINGS_CHARACTERS = WINGDINGS_CHARACTERS;
@@ -0,0 +1,4 @@
1
+ //#region src/wingdings-characters.d.ts
2
+ declare const WINGDINGS_CHARACTERS: readonly string[];
3
+ //#endregion
4
+ export { WINGDINGS_CHARACTERS };
@@ -0,0 +1,4 @@
1
+ //#region src/wingdings-characters.d.ts
2
+ declare const WINGDINGS_CHARACTERS: readonly string[];
3
+ //#endregion
4
+ export { WINGDINGS_CHARACTERS };
@@ -0,0 +1,261 @@
1
+ //#region src/wingdings-characters.ts
2
+ const WINGDINGS_CHARACTERS = [
3
+ "",
4
+ "",
5
+ "",
6
+ "",
7
+ "",
8
+ "",
9
+ "",
10
+ "",
11
+ "",
12
+ "",
13
+ "",
14
+ "",
15
+ "",
16
+ "",
17
+ "",
18
+ "",
19
+ "",
20
+ "",
21
+ "",
22
+ "",
23
+ "",
24
+ "",
25
+ "",
26
+ "",
27
+ "",
28
+ "",
29
+ "",
30
+ "",
31
+ "",
32
+ "",
33
+ "",
34
+ "",
35
+ " ",
36
+ "๐Ÿ–‰",
37
+ "โœ‚",
38
+ "โœ",
39
+ "๐Ÿ‘“",
40
+ "๐Ÿ•ญ",
41
+ "๐Ÿ•ฎ",
42
+ "๐Ÿ•ฏ",
43
+ "๐Ÿ•ฟ",
44
+ "โœ†",
45
+ "๐Ÿ–‚",
46
+ "๐Ÿ–ƒ",
47
+ "๐Ÿ“ช",
48
+ "๐Ÿ“ซ",
49
+ "๐Ÿ“ฌ",
50
+ "๐Ÿ“ญ",
51
+ "๐Ÿ—€",
52
+ "๐Ÿ—",
53
+ "๐Ÿ—Ž",
54
+ "๐Ÿ—",
55
+ "๐Ÿ—",
56
+ "๐Ÿ—„",
57
+ "โณ",
58
+ "๐Ÿ–ฎ",
59
+ "๐Ÿ–ฐ",
60
+ "๐Ÿ–ฒ",
61
+ "๐Ÿ–ณ",
62
+ "๐Ÿ–ด",
63
+ "๐Ÿ–ซ",
64
+ "๐Ÿ–ฌ",
65
+ "โœ‡",
66
+ "โœ",
67
+ "๐Ÿ–Ž",
68
+ "โœŒ",
69
+ "๐Ÿ–",
70
+ "๐Ÿ‘",
71
+ "๐Ÿ‘Ž",
72
+ "โ˜œ",
73
+ "โ˜ž",
74
+ "โ˜",
75
+ "๐Ÿ–—",
76
+ "๐Ÿ–",
77
+ "โ˜บ",
78
+ "๐Ÿ˜",
79
+ "โ˜น",
80
+ "๐Ÿ’ฃ",
81
+ "๐Ÿ•ฑ",
82
+ "๐Ÿณ",
83
+ "๐Ÿฑ",
84
+ "โœˆ",
85
+ "โ˜ผ",
86
+ "๐ŸŒข",
87
+ "โ„",
88
+ "๐Ÿ•†",
89
+ "โœž",
90
+ "๐Ÿ•ˆ",
91
+ "โœ ",
92
+ "โœก",
93
+ "โ˜ช",
94
+ "โ˜ฏ",
95
+ "๐Ÿ•‰",
96
+ "โ˜ธ",
97
+ "โ™ˆ",
98
+ "โ™‰",
99
+ "โ™Š",
100
+ "โ™‹",
101
+ "โ™Œ",
102
+ "โ™",
103
+ "โ™Ž",
104
+ "โ™",
105
+ "โ™",
106
+ "โ™‘",
107
+ "โ™’",
108
+ "โ™“",
109
+ "๐Ÿ™ฐ",
110
+ "๐Ÿ™ต",
111
+ "โšซ",
112
+ "๐Ÿ”พ",
113
+ "โ—ผ",
114
+ "๐Ÿž",
115
+ "๐Ÿž",
116
+ "โ‘",
117
+ "โ’",
118
+ "๐ŸžŸ",
119
+ "โงซ",
120
+ "โ—†",
121
+ "โ–",
122
+ "๐Ÿž™",
123
+ "โŒง",
124
+ "โฎน",
125
+ "โŒ˜",
126
+ "๐Ÿต",
127
+ "๐Ÿถ",
128
+ "๐Ÿ™ถ",
129
+ "๐Ÿ™ท",
130
+ "",
131
+ "๐Ÿ„‹",
132
+ "โž€",
133
+ "โž",
134
+ "โž‚",
135
+ "โžƒ",
136
+ "โž„",
137
+ "โž…",
138
+ "โž†",
139
+ "โž‡",
140
+ "โžˆ",
141
+ "โž‰",
142
+ "๐Ÿ„Œ",
143
+ "โžŠ",
144
+ "โž‹",
145
+ "โžŒ",
146
+ "โž",
147
+ "โžŽ",
148
+ "โž",
149
+ "โž",
150
+ "โž‘",
151
+ "โž’",
152
+ "โž“",
153
+ "๐Ÿ™ข",
154
+ "๐Ÿ™ ",
155
+ "๐Ÿ™ก",
156
+ "๐Ÿ™ฃ",
157
+ "๐Ÿ™ž",
158
+ "๐Ÿ™œ",
159
+ "๐Ÿ™",
160
+ "๐Ÿ™Ÿ",
161
+ "โˆ™",
162
+ "โ€ข",
163
+ "โฌ",
164
+ "โญ˜",
165
+ "๐Ÿž†",
166
+ "๐Ÿžˆ",
167
+ "๐ŸžŠ",
168
+ "๐Ÿž‹",
169
+ "๐Ÿ”ฟ",
170
+ "โ–ช",
171
+ "๐ŸžŽ",
172
+ "๐ŸŸ",
173
+ "๐ŸŸ…",
174
+ "โ˜…",
175
+ "๐ŸŸ‹",
176
+ "๐ŸŸ",
177
+ "๐ŸŸ“",
178
+ "๐ŸŸ‘",
179
+ "โฏ",
180
+ "โŒ–",
181
+ "โฏŽ",
182
+ "โฏ",
183
+ "โฏ‘",
184
+ "โœช",
185
+ "โœฐ",
186
+ "๐Ÿ•",
187
+ "๐Ÿ•‘",
188
+ "๐Ÿ•’",
189
+ "๐Ÿ•“",
190
+ "๐Ÿ•”",
191
+ "๐Ÿ••",
192
+ "๐Ÿ•–",
193
+ "๐Ÿ•—",
194
+ "๐Ÿ•˜",
195
+ "๐Ÿ•™",
196
+ "๐Ÿ•š",
197
+ "๐Ÿ•›",
198
+ "โฎฐ",
199
+ "โฎฑ",
200
+ "โฎฒ",
201
+ "โฎณ",
202
+ "โฎด",
203
+ "โฎต",
204
+ "โฎถ",
205
+ "โฎท",
206
+ "๐Ÿ™ช",
207
+ "๐Ÿ™ซ",
208
+ "๐Ÿ™•",
209
+ "๐Ÿ™”",
210
+ "๐Ÿ™—",
211
+ "๐Ÿ™–",
212
+ "๐Ÿ™",
213
+ "๐Ÿ™‘",
214
+ "๐Ÿ™’",
215
+ "๐Ÿ™“",
216
+ "โŒซ",
217
+ "โŒฆ",
218
+ "โฎ˜",
219
+ "โฎš",
220
+ "โฎ™",
221
+ "โฎ›",
222
+ "โฎˆ",
223
+ "โฎŠ",
224
+ "โฎ‰",
225
+ "โฎ‹",
226
+ "๐Ÿกจ",
227
+ "๐Ÿกช",
228
+ "๐Ÿกฉ",
229
+ "๐Ÿกซ",
230
+ "๐Ÿกฌ",
231
+ "๐Ÿกญ",
232
+ "๐Ÿกฏ",
233
+ "๐Ÿกฎ",
234
+ "๐Ÿกธ",
235
+ "๐Ÿกบ",
236
+ "๐Ÿกน",
237
+ "๐Ÿกป",
238
+ "๐Ÿกผ",
239
+ "๐Ÿกฝ",
240
+ "๐Ÿกฟ",
241
+ "๐Ÿกพ",
242
+ "โ‡ฆ",
243
+ "โ‡จ",
244
+ "โ‡ง",
245
+ "โ‡ฉ",
246
+ "โฌ„",
247
+ "โ‡ณ",
248
+ "โฌ",
249
+ "โฌ€",
250
+ "โฌƒ",
251
+ "โฌ‚",
252
+ "๐Ÿขฌ",
253
+ "๐Ÿขญ",
254
+ "๐Ÿ—ถ",
255
+ "โœ“",
256
+ "๐Ÿ—ท",
257
+ "๐Ÿ—น",
258
+ ""
259
+ ];
260
+ //#endregion
261
+ export { WINGDINGS_CHARACTERS };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pdf-codec",
3
- "version": "5.8.0",
3
+ "version": "5.8.2",
4
4
  "description": "Hand-written, dependency-minimal PDF codec: parses arbitrary real-world PDFs and generates new ones, built on its own codec-owned LayoutDocument item model and Zod 4 codecs.",
5
5
  "type": "module",
6
6
  "repository": {