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 +46 -7
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +46 -7
- package/package.json +29 -30
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 ?
|
|
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
|
|
1173
|
-
let charWidth = (
|
|
1182
|
+
const glyph = cache.get(char);
|
|
1183
|
+
let charWidth = (glyph?.advanceWidth ?? font.unitsPerEm * 0.6) * scale;
|
|
1174
1184
|
if (bold && !isEa) {
|
|
1175
|
-
|
|
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
|
|
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
|
|
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 ?
|
|
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
|
|
1136
|
-
let charWidth = (
|
|
1145
|
+
const glyph = cache.get(char);
|
|
1146
|
+
let charWidth = (glyph?.advanceWidth ?? font.unitsPerEm * 0.6) * scale;
|
|
1137
1147
|
if (bold && !isEa) {
|
|
1138
|
-
|
|
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
|
|
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
|
|
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.
|
|
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": "
|
|
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
|
+
}
|