@openpresentation/opf-render 0.13.0 → 0.14.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.
@@ -4,12 +4,14 @@
4
4
  // Microsoft Symbol cmap (U+F020..U+F0FF), not at Unicode code points. Office stores such text as private-use
5
5
  // characters (U+F0xx, what Insert > Symbol and `a:sym` runs write) or as the Windows-1252 character of each
6
6
  // code (the letter "l" typed in a Wingdings run, a `buChar` of "§" with `buFont` Wingdings). None of the five
7
- // fonts may be bundled (proprietary), so a preview maps each code to its Unicode equivalent (core
8
- // spec/reference/symbol-font-encodings.json, snapshot in symbol-encodings.js) and draws that character with the
9
- // first loaded open face that has it; the PPTX keeps the family name and the original characters. Browser-safe
10
- // and deterministic: no DOM, network or locale data.
11
- import { SYMBOL_ENCODINGS } from "./symbol-encodings.js";
12
- export { SYMBOL_ENCODINGS, SYMBOL_ENCODINGS_SOURCE } from "./symbol-encodings.js";
7
+ // fonts may be bundled (proprietary), so a preview maps each code to its Unicode equivalent with core's table
8
+ // (`@openpresentation/opf/symbol-font-encodings`, which also holds the verified font's advance for every code)
9
+ // and draws that character with the first loaded open face that has it; the PPTX keeps the family name and the
10
+ // original characters. Core owns the table and the code rules (`isSymbolEncodedFamily`, `symbolCodeOf`,
11
+ // `mapSymbolText`); this module adds the preview faces and the advance of each code. Browser-safe and
12
+ // deterministic: no DOM, network or locale data.
13
+ import { isSymbolEncodedFamily, mapSymbolText, symbolCodeOf, symbolFontEncodingFor } from "@openpresentation/opf/symbol-font-encodings";
14
+ export { isSymbolEncodedFamily, mapSymbolText, symbolCodeOf };
13
15
 
14
16
  const freeze = value => { if (value && typeof value === "object") { for (const child of Object.values(value)) freeze(child); Object.freeze(value); } return value; };
15
17
 
@@ -36,61 +38,26 @@ export const SYMBOL_PREVIEW_FACES = freeze({
36
38
  /** Every open face a symbol preview may draw with. */
37
39
  export const SYMBOL_FACE_FAMILIES = freeze([...new Set(Object.values(SYMBOL_PREVIEW_FACES).flat())]);
38
40
 
39
- const byFamily = new Map(SYMBOL_ENCODINGS.map(entry => [entry.family.toLowerCase(), entry]));
40
-
41
- /** The encoding snapshot of a symbol-encoded family (case-insensitive), or undefined for any other family. */
42
- export function symbolEncodingFor(family) {
43
- return typeof family === "string" ? byFamily.get(family.trim().toLowerCase()) : undefined;
44
- }
45
-
46
- /** True for Symbol, Wingdings, Wingdings 2, Wingdings 3 and Webdings (case-insensitive). */
47
- export function isSymbolEncodedFamily(family) {
48
- return symbolEncodingFor(family) !== undefined;
41
+ /** The canonical family name of a symbol-encoded family (case-insensitive), or undefined for any other family. */
42
+ export function symbolEncodingFamily(family) {
43
+ return symbolFontEncodingFor(family)?.family;
49
44
  }
50
45
 
51
46
  /** The faces a symbol-encoded family previews with, in order. */
52
47
  export function symbolPreviewFaces(family) {
53
- const entry = symbolEncodingFor(family);
54
- return entry ? SYMBOL_PREVIEW_FACES[entry.family] : [];
55
- }
56
-
57
- // Windows-1252 characters at 0x80..0x9F (the five unassigned bytes 0x81, 0x8D, 0x8F, 0x90 and 0x9D have no character).
58
- const CP1252_HIGH = freeze({
59
- 0x20ac: 0x80, 0x201a: 0x82, 0x0192: 0x83, 0x201e: 0x84, 0x2026: 0x85, 0x2020: 0x86, 0x2021: 0x87, 0x02c6: 0x88, 0x2030: 0x89,
60
- 0x0160: 0x8a, 0x2039: 0x8b, 0x0152: 0x8c, 0x017d: 0x8e, 0x2018: 0x91, 0x2019: 0x92, 0x201c: 0x93, 0x201d: 0x94, 0x2022: 0x95,
61
- 0x2013: 0x96, 0x2014: 0x97, 0x02dc: 0x98, 0x2122: 0x99, 0x0161: 0x9a, 0x203a: 0x9b, 0x0153: 0x9c, 0x017e: 0x9e, 0x0178: 0x9f,
62
- });
63
-
64
- /**
65
- * The symbol code of one character, or null when it is not a code (the same rule as core `symbolCodeOf`): a
66
- * private-use character U+F020..U+F0FF gives its low byte; U+0020..U+007E and U+00A0..U+00FF are their own
67
- * byte; the Windows-1252 characters at 0x80..0x9F give that byte. Any other character is not symbol-encoded
68
- * text and draws as itself.
69
- */
70
- export function symbolCodeOf(character) {
71
- if (typeof character !== "string" || !character) return null;
72
- const point = character.codePointAt(0);
73
- if (point >= 0xf020 && point <= 0xf0ff) return point - 0xf000;
74
- if ((point >= 0x20 && point <= 0x7e) || (point >= 0xa0 && point <= 0xff)) return point;
75
- return CP1252_HIGH[point] ?? null;
48
+ const name = symbolEncodingFamily(family);
49
+ return name ? SYMBOL_PREVIEW_FACES[name] : [];
76
50
  }
77
51
 
78
- const unicodeString = value => String.fromCodePoint(...value.split("+").map(hex => parseInt(hex, 16)));
79
-
80
52
  /**
81
- * Normalise text in a symbol-encoded family character by character: `{source, code, unicode, advance, reason?}`.
82
- * `code` is null for a character that is not symbol-encoded text (it draws as itself); `unicode` is the
83
- * equivalent to draw or null with the table's `reason`; `advance` is the verified font's advance for the code
84
- * in em (null when that font has no glyph there). An unknown family maps every character to `{code: null}`.
53
+ * Core `mapSymbolText` with the advance of each code added: `{source, code, unicode, advance, reason?}`. `advance` is the
54
+ * verified font's advance for the code in em (null when that font has no glyph there, or the character is not a code); the
55
+ * preview places each drawn character at it. An unknown family maps every character to `{code: null}`.
85
56
  */
86
- export function mapSymbolText(family, text) {
87
- const entry = symbolEncodingFor(family);
88
- const out = [];
89
- for (const source of String(text ?? "")) {
90
- const code = entry ? symbolCodeOf(source) : null;
91
- if (code === null) { out.push({source, code: null, unicode: null, advance: null}); continue; }
92
- const [unicode, advance, reason] = entry.codes[code - 0x20];
93
- out.push({source, code, unicode: unicode === null ? null : unicodeString(unicode), advance: advance === null ? null : advance / entry.unitsPerEm, ...(unicode === null ? {reason} : {})});
94
- }
95
- return out;
57
+ export function mapSymbolAdvances(family, text) {
58
+ const encoding = symbolFontEncodingFor(family);
59
+ return mapSymbolText(family, text).map(item => ({
60
+ ...item,
61
+ advance: encoding && item.code !== null && encoding.codes[item.code - 0x20]?.installed ? encoding.codes[item.code - 0x20].installed.advance / encoding.verifiedAgainst.unitsPerEm : null,
62
+ }));
96
63
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openpresentation/opf-render",
3
- "version": "0.13.0",
3
+ "version": "0.14.0",
4
4
  "description": "Deterministic local OPF renderer for SVG, PNG, and PDF output.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -138,13 +138,13 @@
138
138
  "@expo-google-fonts/roboto": "0.4.3",
139
139
  "@expo-google-fonts/roboto-mono": "0.4.2",
140
140
  "@expo-google-fonts/tinos": "0.4.2",
141
- "@openpresentation/opf": "^0.13.0",
141
+ "@openpresentation/opf": "^0.14.0",
142
142
  "@resvg/resvg-js": "^2.6.2",
143
143
  "bidi-js": "1.1.0",
144
144
  "fontkit": "^2.0.4",
145
145
  "pako": "1.0.11",
146
146
  "pdf-lib": "^1.17.1",
147
- "sharp": "0.35.4"
147
+ "sharp": "0.35.5"
148
148
  },
149
149
  "peerDependencies": {
150
150
  "@expo-google-fonts/noto-color-emoji": "0.4.6",