pptx-glimpse 0.11.1 → 0.11.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/dist/index.cjs CHANGED
@@ -1163,16 +1163,35 @@ var OpentypeTextMeasurer = class {
1163
1163
  return measureTextWidth(text, fontSizePt, bold, fontFamily, fontFamilyEa);
1164
1164
  }
1165
1165
  const fontSizePx = fontSizePt * PX_PER_PT2;
1166
+ const latinFontResolved = latinFont ?? fallbackFont;
1167
+ const eaFontResolved = eaFont ?? fallbackFont;
1168
+ const boldLatinFont = bold ? this.resolveBoldFont(fontFamily) : null;
1169
+ const latinGlyphCache = /* @__PURE__ */ new Map();
1170
+ const eaGlyphCache = eaFontResolved !== latinFontResolved ? /* @__PURE__ */ new Map() : latinGlyphCache;
1171
+ const boldGlyphCache = /* @__PURE__ */ new Map();
1166
1172
  let totalWidth = 0;
1167
1173
  for (const char of text) {
1168
1174
  const codePoint = char.codePointAt(0);
1169
1175
  const isEa = isCjkCodePoint(codePoint);
1170
- const font = isEa ? eaFont ?? fallbackFont : latinFont ?? fallbackFont;
1176
+ const font = isEa ? eaFontResolved : latinFontResolved;
1177
+ const cache = isEa ? eaGlyphCache : latinGlyphCache;
1178
+ if (!cache.has(char)) {
1179
+ cache.set(char, font.stringToGlyphs(char)[0]);
1180
+ }
1171
1181
  const scale = fontSizePx / font.unitsPerEm;
1172
- const glyphs = font.stringToGlyphs(char);
1173
- let charWidth = (glyphs[0]?.advanceWidth ?? font.unitsPerEm * 0.6) * scale;
1182
+ const glyph = cache.get(char);
1183
+ let charWidth = (glyph?.advanceWidth ?? font.unitsPerEm * 0.6) * scale;
1174
1184
  if (bold && !isEa) {
1175
- charWidth *= BOLD_FACTOR2;
1185
+ if (boldLatinFont) {
1186
+ if (!boldGlyphCache.has(char)) {
1187
+ boldGlyphCache.set(char, boldLatinFont.stringToGlyphs(char)[0]);
1188
+ }
1189
+ const boldGlyph = boldGlyphCache.get(char);
1190
+ const boldScale = fontSizePx / boldLatinFont.unitsPerEm;
1191
+ charWidth = (boldGlyph?.advanceWidth ?? boldLatinFont.unitsPerEm * 0.6) * boldScale;
1192
+ } else {
1193
+ charWidth *= BOLD_FACTOR2;
1194
+ }
1176
1195
  }
1177
1196
  totalWidth += charWidth;
1178
1197
  }
@@ -1188,6 +1207,24 @@ var OpentypeTextMeasurer = class {
1188
1207
  if (!font) return 1;
1189
1208
  return font.ascender / font.unitsPerEm;
1190
1209
  }
1210
+ resolveBoldFont(name) {
1211
+ if (!name) return null;
1212
+ const bases = [name];
1213
+ const mappedBase = getCurrentMappedFont(name);
1214
+ if (mappedBase && mappedBase !== name) bases.push(mappedBase);
1215
+ for (const base of bases) {
1216
+ for (const boldName of [`${base} Bold`, `${base}-Bold`]) {
1217
+ const direct = this.fonts.get(boldName);
1218
+ if (direct) return direct;
1219
+ const mapped = getCurrentMappedFont(boldName);
1220
+ if (mapped) {
1221
+ const mappedFont = this.fonts.get(mapped);
1222
+ if (mappedFont) return mappedFont;
1223
+ }
1224
+ }
1225
+ }
1226
+ return null;
1227
+ }
1191
1228
  resolveFont(name) {
1192
1229
  if (!name) return null;
1193
1230
  const direct = this.fonts.get(name);
@@ -1883,6 +1920,8 @@ var ColorResolver = class {
1883
1920
  this.colorScheme = colorScheme;
1884
1921
  this.colorMap = colorMap;
1885
1922
  }
1923
+ colorScheme;
1924
+ colorMap;
1886
1925
  resolve(colorNode) {
1887
1926
  if (!colorNode) return null;
1888
1927
  if (colorNode.srgbClr) {
@@ -4183,7 +4222,7 @@ function extractMathText(node) {
4183
4222
  if (key === "t") {
4184
4223
  if (typeof value === "object" && value !== null) {
4185
4224
  text += value["#text"] ?? "";
4186
- } else if (value !== void 0 && value !== null) {
4225
+ } else if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
4187
4226
  text += String(value);
4188
4227
  }
4189
4228
  } else if (typeof value === "object" && value !== null) {
@@ -4202,7 +4241,7 @@ function extractTextContent(node) {
4202
4241
  if (typeof text === "object") {
4203
4242
  return text["#text"] ?? "";
4204
4243
  }
4205
- return text !== void 0 && text !== null ? String(text) : "";
4244
+ return typeof text === "string" || typeof text === "number" || typeof text === "boolean" ? String(text) : "";
4206
4245
  }
4207
4246
  function parseParagraph(p, colorResolver, rels, fontScheme, lstStyle, orderedPChildren) {
4208
4247
  const pPr = p.pPr;
@@ -6891,7 +6930,7 @@ var presetGeometries = {
6891
6930
  const shaftEnd = h - headLength;
6892
6931
  return `<polygon points="${bodyLeft},0 ${bodyRight},0 ${bodyRight},${shaftEnd} ${w},${shaftEnd} ${w / 2},${h} 0,${shaftEnd} ${bodyLeft},${shaftEnd}"/>`;
6893
6932
  },
6894
- line: () => "",
6933
+ line: (w, h) => `<line x1="0" y1="0" x2="${w}" y2="${h}"/>`,
6895
6934
  // =====================
6896
6935
  // Connector shapes
6897
6936
  // =====================
package/dist/index.d.cts CHANGED
@@ -136,6 +136,7 @@ declare class OpentypeTextMeasurer implements TextMeasurer {
136
136
  measureTextWidth(text: string, fontSizePt: number, bold: boolean, fontFamily?: string | null, fontFamilyEa?: string | null): number;
137
137
  getLineHeightRatio(fontFamily?: string | null, fontFamilyEa?: string | null): number;
138
138
  getAscenderRatio(fontFamily?: string | null, fontFamilyEa?: string | null): number;
139
+ private resolveBoldFont;
139
140
  private resolveFont;
140
141
  }
141
142
 
package/dist/index.d.ts CHANGED
@@ -136,6 +136,7 @@ declare class OpentypeTextMeasurer implements TextMeasurer {
136
136
  measureTextWidth(text: string, fontSizePt: number, bold: boolean, fontFamily?: string | null, fontFamilyEa?: string | null): number;
137
137
  getLineHeightRatio(fontFamily?: string | null, fontFamilyEa?: string | null): number;
138
138
  getAscenderRatio(fontFamily?: string | null, fontFamilyEa?: string | null): number;
139
+ private resolveBoldFont;
139
140
  private resolveFont;
140
141
  }
141
142
 
package/dist/index.js CHANGED
@@ -1126,16 +1126,35 @@ var OpentypeTextMeasurer = class {
1126
1126
  return measureTextWidth(text, fontSizePt, bold, fontFamily, fontFamilyEa);
1127
1127
  }
1128
1128
  const fontSizePx = fontSizePt * PX_PER_PT2;
1129
+ const latinFontResolved = latinFont ?? fallbackFont;
1130
+ const eaFontResolved = eaFont ?? fallbackFont;
1131
+ const boldLatinFont = bold ? this.resolveBoldFont(fontFamily) : null;
1132
+ const latinGlyphCache = /* @__PURE__ */ new Map();
1133
+ const eaGlyphCache = eaFontResolved !== latinFontResolved ? /* @__PURE__ */ new Map() : latinGlyphCache;
1134
+ const boldGlyphCache = /* @__PURE__ */ new Map();
1129
1135
  let totalWidth = 0;
1130
1136
  for (const char of text) {
1131
1137
  const codePoint = char.codePointAt(0);
1132
1138
  const isEa = isCjkCodePoint(codePoint);
1133
- const font = isEa ? eaFont ?? fallbackFont : latinFont ?? fallbackFont;
1139
+ const font = isEa ? eaFontResolved : latinFontResolved;
1140
+ const cache = isEa ? eaGlyphCache : latinGlyphCache;
1141
+ if (!cache.has(char)) {
1142
+ cache.set(char, font.stringToGlyphs(char)[0]);
1143
+ }
1134
1144
  const scale = fontSizePx / font.unitsPerEm;
1135
- const glyphs = font.stringToGlyphs(char);
1136
- let charWidth = (glyphs[0]?.advanceWidth ?? font.unitsPerEm * 0.6) * scale;
1145
+ const glyph = cache.get(char);
1146
+ let charWidth = (glyph?.advanceWidth ?? font.unitsPerEm * 0.6) * scale;
1137
1147
  if (bold && !isEa) {
1138
- charWidth *= BOLD_FACTOR2;
1148
+ if (boldLatinFont) {
1149
+ if (!boldGlyphCache.has(char)) {
1150
+ boldGlyphCache.set(char, boldLatinFont.stringToGlyphs(char)[0]);
1151
+ }
1152
+ const boldGlyph = boldGlyphCache.get(char);
1153
+ const boldScale = fontSizePx / boldLatinFont.unitsPerEm;
1154
+ charWidth = (boldGlyph?.advanceWidth ?? boldLatinFont.unitsPerEm * 0.6) * boldScale;
1155
+ } else {
1156
+ charWidth *= BOLD_FACTOR2;
1157
+ }
1139
1158
  }
1140
1159
  totalWidth += charWidth;
1141
1160
  }
@@ -1151,6 +1170,24 @@ var OpentypeTextMeasurer = class {
1151
1170
  if (!font) return 1;
1152
1171
  return font.ascender / font.unitsPerEm;
1153
1172
  }
1173
+ resolveBoldFont(name) {
1174
+ if (!name) return null;
1175
+ const bases = [name];
1176
+ const mappedBase = getCurrentMappedFont(name);
1177
+ if (mappedBase && mappedBase !== name) bases.push(mappedBase);
1178
+ for (const base of bases) {
1179
+ for (const boldName of [`${base} Bold`, `${base}-Bold`]) {
1180
+ const direct = this.fonts.get(boldName);
1181
+ if (direct) return direct;
1182
+ const mapped = getCurrentMappedFont(boldName);
1183
+ if (mapped) {
1184
+ const mappedFont = this.fonts.get(mapped);
1185
+ if (mappedFont) return mappedFont;
1186
+ }
1187
+ }
1188
+ }
1189
+ return null;
1190
+ }
1154
1191
  resolveFont(name) {
1155
1192
  if (!name) return null;
1156
1193
  const direct = this.fonts.get(name);
@@ -1845,6 +1882,8 @@ var ColorResolver = class {
1845
1882
  this.colorScheme = colorScheme;
1846
1883
  this.colorMap = colorMap;
1847
1884
  }
1885
+ colorScheme;
1886
+ colorMap;
1848
1887
  resolve(colorNode) {
1849
1888
  if (!colorNode) return null;
1850
1889
  if (colorNode.srgbClr) {
@@ -4145,7 +4184,7 @@ function extractMathText(node) {
4145
4184
  if (key === "t") {
4146
4185
  if (typeof value === "object" && value !== null) {
4147
4186
  text += value["#text"] ?? "";
4148
- } else if (value !== void 0 && value !== null) {
4187
+ } else if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
4149
4188
  text += String(value);
4150
4189
  }
4151
4190
  } else if (typeof value === "object" && value !== null) {
@@ -4164,7 +4203,7 @@ function extractTextContent(node) {
4164
4203
  if (typeof text === "object") {
4165
4204
  return text["#text"] ?? "";
4166
4205
  }
4167
- return text !== void 0 && text !== null ? String(text) : "";
4206
+ return typeof text === "string" || typeof text === "number" || typeof text === "boolean" ? String(text) : "";
4168
4207
  }
4169
4208
  function parseParagraph(p, colorResolver, rels, fontScheme, lstStyle, orderedPChildren) {
4170
4209
  const pPr = p.pPr;
@@ -6853,7 +6892,7 @@ var presetGeometries = {
6853
6892
  const shaftEnd = h - headLength;
6854
6893
  return `<polygon points="${bodyLeft},0 ${bodyRight},0 ${bodyRight},${shaftEnd} ${w},${shaftEnd} ${w / 2},${h} 0,${shaftEnd} ${bodyLeft},${shaftEnd}"/>`;
6855
6894
  },
6856
- line: () => "",
6895
+ line: (w, h) => `<line x1="0" y1="0" x2="${w}" y2="${h}"/>`,
6857
6896
  // =====================
6858
6897
  // Connector shapes
6859
6898
  // =====================
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pptx-glimpse",
3
- "version": "0.11.1",
3
+ "version": "0.11.2",
4
4
  "description": "A lightweight JavaScript library for rendering PowerPoint (.pptx) files as SVG or PNG in Node.js. No LibreOffice required.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -13,36 +13,9 @@
13
13
  "require": "./dist/index.cjs"
14
14
  }
15
15
  },
16
- "scripts": {
17
- "build": "tsup src/index.ts --format cjs,esm --dts",
18
- "bench": "vitest bench",
19
- "lint": "eslint src/ vrt/ scripts/ bench/ e2e/",
20
- "lint:fix": "eslint src/ vrt/ scripts/ bench/ e2e/ --fix",
21
- "format": "prettier --write 'src/**/*.ts' 'vrt/**/*.ts' 'scripts/**/*.ts' 'bench/**/*.ts' 'e2e/**/*.ts'",
22
- "format:check": "prettier --check 'src/**/*.ts' 'vrt/**/*.ts' 'scripts/**/*.ts' 'bench/**/*.ts' 'e2e/**/*.ts'",
23
- "test": "vitest run",
24
- "test:coverage": "vitest run --coverage",
25
- "test:watch": "vitest",
26
- "typecheck": "tsc --noEmit",
27
- "knip": "knip",
28
- "dev": "tsx scripts/dev-server.ts",
29
- "render": "tsx scripts/test-render.ts",
30
- "inspect": "tsx scripts/inspect-pptx.ts",
31
- "vrt:snapshot:docker-build": "docker build -t pptx-glimpse-snapshot-vrt docker/snapshot-vrt",
32
- "vrt:snapshot:fixtures": "tsx vrt/snapshot/create-fixtures.ts",
33
- "vrt:snapshot:update": "docker run --rm -v \"$(pwd)\":/workspace -v pptx-glimpse-snapshot-vrt-nm:/workspace/node_modules pptx-glimpse-snapshot-vrt bash /workspace/vrt/snapshot/docker-run.sh bash -c \"npx tsx vrt/snapshot/create-fixtures.ts && npx tsx vrt/snapshot/update-snapshots.ts\"",
34
- "vrt:lo:docker-build": "docker build -t pptx-glimpse-vrt docker/libreoffice-vrt",
35
- "vrt:lo:fixtures": "docker run --rm -v \"$(pwd)\":/workspace pptx-glimpse-vrt python3 /workspace/vrt/libreoffice/create_fixtures.py",
36
- "vrt:lo:update": "npm run vrt:lo:docker-build && npm run vrt:lo:fixtures && docker run --rm -v \"$(pwd)\":/workspace pptx-glimpse-vrt bash /workspace/vrt/libreoffice/update_snapshots.sh",
37
- "test:package": "npm run build && bash scripts/test-package.sh",
38
- "changeset": "changeset",
39
- "demo:dev": "cd demo && npm run dev",
40
- "demo:build": "npm run build && cd demo && npm install && npm run build"
41
- },
42
16
  "files": [
43
17
  "dist"
44
18
  ],
45
- "packageManager": "npm@10.9.6",
46
19
  "engines": {
47
20
  "node": ">=20"
48
21
  },
@@ -67,7 +40,7 @@
67
40
  "@resvg/resvg-wasm": "^2.6.2",
68
41
  "fast-xml-parser": "^5.7.3",
69
42
  "fflate": "^0.8.2",
70
- "opentype.js": "^1.3.4"
43
+ "opentype.js": "1.3.4"
71
44
  },
72
45
  "devDependencies": {
73
46
  "@changesets/cli": "^2.29.8",
@@ -88,5 +61,31 @@
88
61
  "typescript-eslint": "^8.55.0",
89
62
  "vitest": "^3.0.0",
90
63
  "ws": "^8.19.0"
64
+ },
65
+ "scripts": {
66
+ "build": "tsup src/index.ts --format cjs,esm --dts",
67
+ "bench": "vitest bench",
68
+ "lint": "eslint src/ vrt/ scripts/ bench/ e2e/",
69
+ "lint:fix": "eslint src/ vrt/ scripts/ bench/ e2e/ --fix",
70
+ "format": "prettier --write 'src/**/*.ts' 'vrt/**/*.ts' 'scripts/**/*.ts' 'bench/**/*.ts' 'e2e/**/*.ts'",
71
+ "format:check": "prettier --check 'src/**/*.ts' 'vrt/**/*.ts' 'scripts/**/*.ts' 'bench/**/*.ts' 'e2e/**/*.ts'",
72
+ "test": "vitest run",
73
+ "test:coverage": "vitest run --coverage",
74
+ "test:watch": "vitest",
75
+ "typecheck": "tsc --noEmit",
76
+ "knip": "knip",
77
+ "dev": "tsx scripts/dev-server.ts",
78
+ "render": "tsx scripts/test-render.ts",
79
+ "inspect": "tsx scripts/inspect-pptx.ts",
80
+ "vrt:snapshot:docker-build": "docker build -t pptx-glimpse-snapshot-vrt docker/snapshot-vrt",
81
+ "vrt:snapshot:fixtures": "tsx vrt/snapshot/create-fixtures.ts",
82
+ "vrt:snapshot:update": "docker run --rm -v \"$(pwd)\":/workspace -v pptx-glimpse-snapshot-vrt-nm:/workspace/node_modules pptx-glimpse-snapshot-vrt bash /workspace/vrt/snapshot/docker-run.sh bash -c \"npx tsx vrt/snapshot/create-fixtures.ts && npx tsx vrt/snapshot/update-snapshots.ts\"",
83
+ "vrt:lo:docker-build": "docker build -t pptx-glimpse-vrt docker/libreoffice-vrt",
84
+ "vrt:lo:fixtures": "docker run --rm -v \"$(pwd)\":/workspace pptx-glimpse-vrt python3 /workspace/vrt/libreoffice/create_fixtures.py",
85
+ "vrt:lo:update": "pnpm run vrt:lo:docker-build && pnpm run vrt:lo:fixtures && docker run --rm -v \"$(pwd)\":/workspace pptx-glimpse-vrt bash /workspace/vrt/libreoffice/update_snapshots.sh",
86
+ "test:package": "pnpm run build && bash scripts/test-package.sh",
87
+ "changeset": "changeset",
88
+ "demo:dev": "cd demo && npm run dev",
89
+ "demo:build": "pnpm run build && cd demo && npm install && npm run build"
91
90
  }
92
- }
91
+ }