pptx-glimpse 0.10.4 → 0.11.1
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 +2 -1
- package/dist/index.cjs +72 -25
- package/dist/index.d.cts +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +72 -25
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -81,6 +81,7 @@ const results = await convertPptxToPng(pptx, {
|
|
|
81
81
|
height: 1080, // Output height in pixels (width takes priority if both set)
|
|
82
82
|
logLevel: "warn", // Warning log level: "off" | "warn" | "debug"
|
|
83
83
|
fontDirs: ["/custom/fonts"], // Additional font directories to search
|
|
84
|
+
skipSystemFonts: true, // Skip OS system font directories; use fontDirs only
|
|
84
85
|
fontMapping: {
|
|
85
86
|
"Custom Corp Font": "Noto Sans", // Custom font name mapping
|
|
86
87
|
},
|
|
@@ -154,7 +155,7 @@ Default system font directories:
|
|
|
154
155
|
| macOS | `/System/Library/Fonts`, `/Library/Fonts`, `~/Library/Fonts` |
|
|
155
156
|
| Windows | `C:\Windows\Fonts` |
|
|
156
157
|
|
|
157
|
-
Use the `fontDirs` option to add custom font directories.
|
|
158
|
+
Use the `fontDirs` option to add custom font directories. To skip system font scanning entirely and use only `fontDirs` (useful in containers, serverless environments, or when you want to bundle specific fonts to reduce startup time), set `skipSystemFonts: true`.
|
|
158
159
|
|
|
159
160
|
### Font Mapping
|
|
160
161
|
|
package/dist/index.cjs
CHANGED
|
@@ -1229,6 +1229,7 @@ var CJK_TTC_PATTERNS = [
|
|
|
1229
1229
|
];
|
|
1230
1230
|
var cachedPaths = null;
|
|
1231
1231
|
var cachedAdditionalDirs = null;
|
|
1232
|
+
var cachedSkipSystemFonts = null;
|
|
1232
1233
|
function getSystemFontDirs() {
|
|
1233
1234
|
const os = (0, import_node_os2.platform)();
|
|
1234
1235
|
switch (os) {
|
|
@@ -1260,20 +1261,21 @@ function walk(dir, result) {
|
|
|
1260
1261
|
} catch {
|
|
1261
1262
|
}
|
|
1262
1263
|
}
|
|
1263
|
-
function collectFontFilePaths(additionalDirs) {
|
|
1264
|
+
function collectFontFilePaths(additionalDirs, skipSystemFonts = false) {
|
|
1264
1265
|
const dirs = additionalDirs ?? [];
|
|
1265
1266
|
const dirsKey = dirs.join("\0");
|
|
1266
1267
|
const cachedKey = cachedAdditionalDirs?.join("\0") ?? null;
|
|
1267
|
-
if (cachedPaths !== null && dirsKey === cachedKey) {
|
|
1268
|
+
if (cachedPaths !== null && dirsKey === cachedKey && cachedSkipSystemFonts === skipSystemFonts) {
|
|
1268
1269
|
return cachedPaths;
|
|
1269
1270
|
}
|
|
1270
|
-
const allDirs = [...getSystemFontDirs(), ...dirs];
|
|
1271
|
+
const allDirs = skipSystemFonts ? dirs : [...getSystemFontDirs(), ...dirs];
|
|
1271
1272
|
const result = [];
|
|
1272
1273
|
for (const dir of allDirs) {
|
|
1273
1274
|
walk(dir, result);
|
|
1274
1275
|
}
|
|
1275
1276
|
cachedPaths = result;
|
|
1276
1277
|
cachedAdditionalDirs = dirs;
|
|
1278
|
+
cachedSkipSystemFonts = skipSystemFonts;
|
|
1277
1279
|
return result;
|
|
1278
1280
|
}
|
|
1279
1281
|
|
|
@@ -1545,11 +1547,12 @@ function collectFontNames(font) {
|
|
|
1545
1547
|
}
|
|
1546
1548
|
return names;
|
|
1547
1549
|
}
|
|
1548
|
-
function buildCacheKey(additionalFontDirs, fontMapping) {
|
|
1550
|
+
function buildCacheKey(additionalFontDirs, fontMapping, skipSystemFonts = false) {
|
|
1549
1551
|
const dirsKey = additionalFontDirs ? [...additionalFontDirs].sort().join("\0") : "";
|
|
1550
1552
|
const mappingKey = fontMapping ? JSON.stringify(fontMapping, Object.keys(fontMapping).sort()) : "";
|
|
1551
1553
|
return `${dirsKey}
|
|
1552
|
-
${mappingKey}
|
|
1554
|
+
${mappingKey}
|
|
1555
|
+
${skipSystemFonts}`;
|
|
1553
1556
|
}
|
|
1554
1557
|
var cachedSetup = null;
|
|
1555
1558
|
var cachedSetupKey = null;
|
|
@@ -1557,14 +1560,14 @@ function clearFontCache() {
|
|
|
1557
1560
|
cachedSetup = null;
|
|
1558
1561
|
cachedSetupKey = null;
|
|
1559
1562
|
}
|
|
1560
|
-
async function createOpentypeSetupFromSystem(additionalFontDirs, fontMapping) {
|
|
1561
|
-
const key = buildCacheKey(additionalFontDirs, fontMapping);
|
|
1563
|
+
async function createOpentypeSetupFromSystem(additionalFontDirs, fontMapping, skipSystemFonts = false) {
|
|
1564
|
+
const key = buildCacheKey(additionalFontDirs, fontMapping, skipSystemFonts);
|
|
1562
1565
|
if (cachedSetup && cachedSetupKey === key) {
|
|
1563
1566
|
return cachedSetup;
|
|
1564
1567
|
}
|
|
1565
1568
|
const opentype = await tryLoadOpentype();
|
|
1566
1569
|
if (!opentype) return null;
|
|
1567
|
-
const fontFilePaths = collectFontFilePaths(additionalFontDirs);
|
|
1570
|
+
const fontFilePaths = collectFontFilePaths(additionalFontDirs, skipSystemFonts);
|
|
1568
1571
|
if (fontFilePaths.length === 0) return null;
|
|
1569
1572
|
const mapping = createFontMapping(fontMapping);
|
|
1570
1573
|
const reverseMap = buildReverseMapping(mapping);
|
|
@@ -1959,25 +1962,48 @@ var LazyMediaMap = class {
|
|
|
1959
1962
|
return data;
|
|
1960
1963
|
}
|
|
1961
1964
|
};
|
|
1965
|
+
var LazyXmlMap = class {
|
|
1966
|
+
rawInput;
|
|
1967
|
+
cache = /* @__PURE__ */ new Map();
|
|
1968
|
+
entryIndex;
|
|
1969
|
+
constructor(rawInput, xmlEntryNames) {
|
|
1970
|
+
this.rawInput = rawInput;
|
|
1971
|
+
this.entryIndex = xmlEntryNames;
|
|
1972
|
+
}
|
|
1973
|
+
has(path) {
|
|
1974
|
+
return this.entryIndex.has(path);
|
|
1975
|
+
}
|
|
1976
|
+
get(path) {
|
|
1977
|
+
if (!this.entryIndex.has(path)) return void 0;
|
|
1978
|
+
const cached = this.cache.get(path);
|
|
1979
|
+
if (cached !== void 0) return cached;
|
|
1980
|
+
const result = (0, import_fflate.unzipSync)(this.rawInput, {
|
|
1981
|
+
filter: (file) => file.name === path
|
|
1982
|
+
});
|
|
1983
|
+
const data = result[path];
|
|
1984
|
+
if (data) {
|
|
1985
|
+
const str = (0, import_fflate.strFromU8)(data);
|
|
1986
|
+
this.cache.set(path, str);
|
|
1987
|
+
return str;
|
|
1988
|
+
}
|
|
1989
|
+
return void 0;
|
|
1990
|
+
}
|
|
1991
|
+
};
|
|
1962
1992
|
function readPptx(input) {
|
|
1963
1993
|
const rawInput = new Uint8Array(input);
|
|
1994
|
+
const xmlEntryNames = /* @__PURE__ */ new Set();
|
|
1964
1995
|
const mediaEntryNames = /* @__PURE__ */ new Set();
|
|
1965
|
-
|
|
1996
|
+
(0, import_fflate.unzipSync)(rawInput, {
|
|
1966
1997
|
filter: (file) => {
|
|
1967
1998
|
if (file.name.startsWith("ppt/media/")) {
|
|
1968
1999
|
mediaEntryNames.add(file.name);
|
|
1969
|
-
|
|
2000
|
+
} else if (file.name.endsWith(".xml") || file.name.endsWith(".rels") || file.name === "[Content_Types].xml") {
|
|
2001
|
+
xmlEntryNames.add(file.name);
|
|
1970
2002
|
}
|
|
1971
|
-
return
|
|
2003
|
+
return false;
|
|
1972
2004
|
}
|
|
1973
2005
|
});
|
|
1974
|
-
const files =
|
|
1975
|
-
for (const [relativePath, data] of Object.entries(unzipped)) {
|
|
1976
|
-
if (relativePath.endsWith("/")) continue;
|
|
1977
|
-
if (relativePath.endsWith(".xml") || relativePath.endsWith(".rels") || relativePath === "[Content_Types].xml") {
|
|
1978
|
-
files.set(relativePath, (0, import_fflate.strFromU8)(data));
|
|
1979
|
-
}
|
|
1980
|
-
}
|
|
2006
|
+
const files = new LazyXmlMap(rawInput, xmlEntryNames);
|
|
1981
2007
|
const media = new LazyMediaMap(rawInput, mediaEntryNames);
|
|
1982
2008
|
return { files, media };
|
|
1983
2009
|
}
|
|
@@ -3173,6 +3199,10 @@ function createDefaultBorders() {
|
|
|
3173
3199
|
|
|
3174
3200
|
// src/parser/slide-parser.ts
|
|
3175
3201
|
var SHAPE_TAGS = /* @__PURE__ */ new Set(["sp", "pic", "cxnSp", "grpSp", "graphicFrame"]);
|
|
3202
|
+
var SMARTART_DIAGRAM_URIS = /* @__PURE__ */ new Set([
|
|
3203
|
+
"http://schemas.openxmlformats.org/drawingml/2006/diagram",
|
|
3204
|
+
"http://purl.oclc.org/ooxml/drawingml/diagram"
|
|
3205
|
+
]);
|
|
3176
3206
|
function navigateOrdered(ordered, path) {
|
|
3177
3207
|
let current = ordered;
|
|
3178
3208
|
for (const key of path) {
|
|
@@ -3720,7 +3750,7 @@ function parseGraphicFrame(gf, rels, slidePath, archive, colorResolver, fontSche
|
|
|
3720
3750
|
if (!tableData) return null;
|
|
3721
3751
|
return { type: "table", transform, table: tableData };
|
|
3722
3752
|
}
|
|
3723
|
-
if (graphicData["@_uri"]
|
|
3753
|
+
if (SMARTART_DIAGRAM_URIS.has(graphicData["@_uri"])) {
|
|
3724
3754
|
return parseSmartArt(
|
|
3725
3755
|
graphicData,
|
|
3726
3756
|
transform,
|
|
@@ -8472,10 +8502,23 @@ function computePathLineX(alignment, textStartX, effectiveTextWidth, width, marg
|
|
|
8472
8502
|
return textStartX;
|
|
8473
8503
|
}
|
|
8474
8504
|
}
|
|
8475
|
-
function measureLineWidth(segments, defaultFontSize, fontScale) {
|
|
8505
|
+
function measureLineWidth(segments, defaultFontSize, fontScale, fontResolver) {
|
|
8476
8506
|
let totalWidth = 0;
|
|
8507
|
+
const jpanFallback = fontResolver ? getJpanFallbackFont() : null;
|
|
8477
8508
|
for (const seg of segments) {
|
|
8478
8509
|
const fontSize = (seg.properties.fontSize ?? defaultFontSize) * fontScale;
|
|
8510
|
+
if (fontResolver) {
|
|
8511
|
+
const fontSizePx = fontSize * PX_PER_PT3;
|
|
8512
|
+
const font = fontResolver.resolveFont(
|
|
8513
|
+
seg.properties.fontFamily,
|
|
8514
|
+
seg.properties.fontFamilyEa,
|
|
8515
|
+
jpanFallback
|
|
8516
|
+
);
|
|
8517
|
+
if (font) {
|
|
8518
|
+
totalWidth += font.getAdvanceWidth(seg.text, fontSizePx);
|
|
8519
|
+
continue;
|
|
8520
|
+
}
|
|
8521
|
+
}
|
|
8479
8522
|
totalWidth += getTextMeasurer().measureTextWidth(
|
|
8480
8523
|
seg.text,
|
|
8481
8524
|
fontSize,
|
|
@@ -8531,7 +8574,7 @@ function renderSegmentAsPath(text, props, x, y, fontScale, defaultFontSize, font
|
|
|
8531
8574
|
const processSegment = (segText, fontFamily, fontFamilyEa) => {
|
|
8532
8575
|
if (segText.length === 0) return;
|
|
8533
8576
|
const font = fontResolver.resolveFont(fontFamily, fontFamilyEa, jpanFallback);
|
|
8534
|
-
const segWidth = getTextMeasurer().measureTextWidth(
|
|
8577
|
+
const segWidth = font ? font.getAdvanceWidth(segText, fontSizePx) : getTextMeasurer().measureTextWidth(
|
|
8535
8578
|
segText,
|
|
8536
8579
|
fontSize,
|
|
8537
8580
|
props.bold,
|
|
@@ -8556,7 +8599,7 @@ function renderSegmentAsPath(text, props, x, y, fontScale, defaultFontSize, font
|
|
|
8556
8599
|
const font = fontResolver.resolveFont(fontFamily, fontFamilyEa, jpanFallback);
|
|
8557
8600
|
const fillAttrs = buildPathFillAttrs(props);
|
|
8558
8601
|
for (const char of segText) {
|
|
8559
|
-
const charWidth = getTextMeasurer().measureTextWidth(
|
|
8602
|
+
const charWidth = font ? font.getAdvanceWidth(char, fontSizePx) : getTextMeasurer().measureTextWidth(
|
|
8560
8603
|
char,
|
|
8561
8604
|
fontSize,
|
|
8562
8605
|
props.bold,
|
|
@@ -8728,7 +8771,7 @@ function renderTextBodyAsPath(textBody, transform, fontResolver) {
|
|
|
8728
8771
|
if (!isFirstLine) {
|
|
8729
8772
|
currentY += lineNaturalHeightPt * PX_PER_PT3 * getLineSpacing(para, lnSpcReduction) + lineGapPx;
|
|
8730
8773
|
}
|
|
8731
|
-
const lineWidth = measureLineWidth(line.segments, defaultFontSize, fontScale);
|
|
8774
|
+
const lineWidth = measureLineWidth(line.segments, defaultFontSize, fontScale, fontResolver);
|
|
8732
8775
|
const lineStartX = computePathLineX(
|
|
8733
8776
|
para.properties.alignment,
|
|
8734
8777
|
textStartX,
|
|
@@ -8777,7 +8820,7 @@ function renderTextBodyAsPath(textBody, transform, fontResolver) {
|
|
|
8777
8820
|
currentY += naturalHeightPt * PX_PER_PT3 * getLineSpacing(para, lnSpcReduction) + paragraphGapPx;
|
|
8778
8821
|
}
|
|
8779
8822
|
const runsAsSegments = para.runs.filter((r) => r.text.length > 0).map((r) => ({ text: r.text, properties: r.properties }));
|
|
8780
|
-
const lineWidth = measureLineWidth(runsAsSegments, defaultFontSize, fontScale);
|
|
8823
|
+
const lineWidth = measureLineWidth(runsAsSegments, defaultFontSize, fontScale, fontResolver);
|
|
8781
8824
|
const lineStartX = computePathLineX(
|
|
8782
8825
|
para.properties.alignment,
|
|
8783
8826
|
textStartX,
|
|
@@ -9113,7 +9156,11 @@ function escapeXmlAttr(str) {
|
|
|
9113
9156
|
|
|
9114
9157
|
// src/converter.ts
|
|
9115
9158
|
async function convertPptxToSvg(input, options) {
|
|
9116
|
-
const setup = await createOpentypeSetupFromSystem(
|
|
9159
|
+
const setup = await createOpentypeSetupFromSystem(
|
|
9160
|
+
options?.fontDirs,
|
|
9161
|
+
options?.fontMapping,
|
|
9162
|
+
options?.skipSystemFonts
|
|
9163
|
+
);
|
|
9117
9164
|
if (setup) {
|
|
9118
9165
|
setTextMeasurer(setup.measurer);
|
|
9119
9166
|
setTextPathFontResolver(setup.fontResolver);
|
package/dist/index.d.cts
CHANGED
|
@@ -46,6 +46,8 @@ interface ConvertOptions {
|
|
|
46
46
|
fontDirs?: string[];
|
|
47
47
|
/** PPTX フォント名 → OSS 代替フォントのカスタムマッピング。デフォルトマッピングにマージされる */
|
|
48
48
|
fontMapping?: FontMapping;
|
|
49
|
+
/** true のとき OS のシステムフォントをスキャンせず fontDirs のみを使用する */
|
|
50
|
+
skipSystemFonts?: boolean;
|
|
49
51
|
}
|
|
50
52
|
interface SlideSvg {
|
|
51
53
|
slideNumber: number;
|
|
@@ -149,6 +151,7 @@ interface OpentypeFullFont {
|
|
|
149
151
|
ascender: number;
|
|
150
152
|
descender: number;
|
|
151
153
|
getPath(text: string, x: number, y: number, fontSize: number): OpentypePath;
|
|
154
|
+
getAdvanceWidth(text: string, fontSize: number): number;
|
|
152
155
|
}
|
|
153
156
|
interface TextPathFontResolver {
|
|
154
157
|
resolveFont(fontFamily: string | null | undefined, fontFamilyEa: string | null | undefined, jpanFallback?: string | null): OpentypeFullFont | null;
|
package/dist/index.d.ts
CHANGED
|
@@ -46,6 +46,8 @@ interface ConvertOptions {
|
|
|
46
46
|
fontDirs?: string[];
|
|
47
47
|
/** PPTX フォント名 → OSS 代替フォントのカスタムマッピング。デフォルトマッピングにマージされる */
|
|
48
48
|
fontMapping?: FontMapping;
|
|
49
|
+
/** true のとき OS のシステムフォントをスキャンせず fontDirs のみを使用する */
|
|
50
|
+
skipSystemFonts?: boolean;
|
|
49
51
|
}
|
|
50
52
|
interface SlideSvg {
|
|
51
53
|
slideNumber: number;
|
|
@@ -149,6 +151,7 @@ interface OpentypeFullFont {
|
|
|
149
151
|
ascender: number;
|
|
150
152
|
descender: number;
|
|
151
153
|
getPath(text: string, x: number, y: number, fontSize: number): OpentypePath;
|
|
154
|
+
getAdvanceWidth(text: string, fontSize: number): number;
|
|
152
155
|
}
|
|
153
156
|
interface TextPathFontResolver {
|
|
154
157
|
resolveFont(fontFamily: string | null | undefined, fontFamilyEa: string | null | undefined, jpanFallback?: string | null): OpentypeFullFont | null;
|
package/dist/index.js
CHANGED
|
@@ -1192,6 +1192,7 @@ var CJK_TTC_PATTERNS = [
|
|
|
1192
1192
|
];
|
|
1193
1193
|
var cachedPaths = null;
|
|
1194
1194
|
var cachedAdditionalDirs = null;
|
|
1195
|
+
var cachedSkipSystemFonts = null;
|
|
1195
1196
|
function getSystemFontDirs() {
|
|
1196
1197
|
const os = platform2();
|
|
1197
1198
|
switch (os) {
|
|
@@ -1223,20 +1224,21 @@ function walk(dir, result) {
|
|
|
1223
1224
|
} catch {
|
|
1224
1225
|
}
|
|
1225
1226
|
}
|
|
1226
|
-
function collectFontFilePaths(additionalDirs) {
|
|
1227
|
+
function collectFontFilePaths(additionalDirs, skipSystemFonts = false) {
|
|
1227
1228
|
const dirs = additionalDirs ?? [];
|
|
1228
1229
|
const dirsKey = dirs.join("\0");
|
|
1229
1230
|
const cachedKey = cachedAdditionalDirs?.join("\0") ?? null;
|
|
1230
|
-
if (cachedPaths !== null && dirsKey === cachedKey) {
|
|
1231
|
+
if (cachedPaths !== null && dirsKey === cachedKey && cachedSkipSystemFonts === skipSystemFonts) {
|
|
1231
1232
|
return cachedPaths;
|
|
1232
1233
|
}
|
|
1233
|
-
const allDirs = [...getSystemFontDirs(), ...dirs];
|
|
1234
|
+
const allDirs = skipSystemFonts ? dirs : [...getSystemFontDirs(), ...dirs];
|
|
1234
1235
|
const result = [];
|
|
1235
1236
|
for (const dir of allDirs) {
|
|
1236
1237
|
walk(dir, result);
|
|
1237
1238
|
}
|
|
1238
1239
|
cachedPaths = result;
|
|
1239
1240
|
cachedAdditionalDirs = dirs;
|
|
1241
|
+
cachedSkipSystemFonts = skipSystemFonts;
|
|
1240
1242
|
return result;
|
|
1241
1243
|
}
|
|
1242
1244
|
|
|
@@ -1508,11 +1510,12 @@ function collectFontNames(font) {
|
|
|
1508
1510
|
}
|
|
1509
1511
|
return names;
|
|
1510
1512
|
}
|
|
1511
|
-
function buildCacheKey(additionalFontDirs, fontMapping) {
|
|
1513
|
+
function buildCacheKey(additionalFontDirs, fontMapping, skipSystemFonts = false) {
|
|
1512
1514
|
const dirsKey = additionalFontDirs ? [...additionalFontDirs].sort().join("\0") : "";
|
|
1513
1515
|
const mappingKey = fontMapping ? JSON.stringify(fontMapping, Object.keys(fontMapping).sort()) : "";
|
|
1514
1516
|
return `${dirsKey}
|
|
1515
|
-
${mappingKey}
|
|
1517
|
+
${mappingKey}
|
|
1518
|
+
${skipSystemFonts}`;
|
|
1516
1519
|
}
|
|
1517
1520
|
var cachedSetup = null;
|
|
1518
1521
|
var cachedSetupKey = null;
|
|
@@ -1520,14 +1523,14 @@ function clearFontCache() {
|
|
|
1520
1523
|
cachedSetup = null;
|
|
1521
1524
|
cachedSetupKey = null;
|
|
1522
1525
|
}
|
|
1523
|
-
async function createOpentypeSetupFromSystem(additionalFontDirs, fontMapping) {
|
|
1524
|
-
const key = buildCacheKey(additionalFontDirs, fontMapping);
|
|
1526
|
+
async function createOpentypeSetupFromSystem(additionalFontDirs, fontMapping, skipSystemFonts = false) {
|
|
1527
|
+
const key = buildCacheKey(additionalFontDirs, fontMapping, skipSystemFonts);
|
|
1525
1528
|
if (cachedSetup && cachedSetupKey === key) {
|
|
1526
1529
|
return cachedSetup;
|
|
1527
1530
|
}
|
|
1528
1531
|
const opentype = await tryLoadOpentype();
|
|
1529
1532
|
if (!opentype) return null;
|
|
1530
|
-
const fontFilePaths = collectFontFilePaths(additionalFontDirs);
|
|
1533
|
+
const fontFilePaths = collectFontFilePaths(additionalFontDirs, skipSystemFonts);
|
|
1531
1534
|
if (fontFilePaths.length === 0) return null;
|
|
1532
1535
|
const mapping = createFontMapping(fontMapping);
|
|
1533
1536
|
const reverseMap = buildReverseMapping(mapping);
|
|
@@ -1921,25 +1924,48 @@ var LazyMediaMap = class {
|
|
|
1921
1924
|
return data;
|
|
1922
1925
|
}
|
|
1923
1926
|
};
|
|
1927
|
+
var LazyXmlMap = class {
|
|
1928
|
+
rawInput;
|
|
1929
|
+
cache = /* @__PURE__ */ new Map();
|
|
1930
|
+
entryIndex;
|
|
1931
|
+
constructor(rawInput, xmlEntryNames) {
|
|
1932
|
+
this.rawInput = rawInput;
|
|
1933
|
+
this.entryIndex = xmlEntryNames;
|
|
1934
|
+
}
|
|
1935
|
+
has(path) {
|
|
1936
|
+
return this.entryIndex.has(path);
|
|
1937
|
+
}
|
|
1938
|
+
get(path) {
|
|
1939
|
+
if (!this.entryIndex.has(path)) return void 0;
|
|
1940
|
+
const cached = this.cache.get(path);
|
|
1941
|
+
if (cached !== void 0) return cached;
|
|
1942
|
+
const result = unzipSync(this.rawInput, {
|
|
1943
|
+
filter: (file) => file.name === path
|
|
1944
|
+
});
|
|
1945
|
+
const data = result[path];
|
|
1946
|
+
if (data) {
|
|
1947
|
+
const str = strFromU8(data);
|
|
1948
|
+
this.cache.set(path, str);
|
|
1949
|
+
return str;
|
|
1950
|
+
}
|
|
1951
|
+
return void 0;
|
|
1952
|
+
}
|
|
1953
|
+
};
|
|
1924
1954
|
function readPptx(input) {
|
|
1925
1955
|
const rawInput = new Uint8Array(input);
|
|
1956
|
+
const xmlEntryNames = /* @__PURE__ */ new Set();
|
|
1926
1957
|
const mediaEntryNames = /* @__PURE__ */ new Set();
|
|
1927
|
-
|
|
1958
|
+
unzipSync(rawInput, {
|
|
1928
1959
|
filter: (file) => {
|
|
1929
1960
|
if (file.name.startsWith("ppt/media/")) {
|
|
1930
1961
|
mediaEntryNames.add(file.name);
|
|
1931
|
-
|
|
1962
|
+
} else if (file.name.endsWith(".xml") || file.name.endsWith(".rels") || file.name === "[Content_Types].xml") {
|
|
1963
|
+
xmlEntryNames.add(file.name);
|
|
1932
1964
|
}
|
|
1933
|
-
return
|
|
1965
|
+
return false;
|
|
1934
1966
|
}
|
|
1935
1967
|
});
|
|
1936
|
-
const files =
|
|
1937
|
-
for (const [relativePath, data] of Object.entries(unzipped)) {
|
|
1938
|
-
if (relativePath.endsWith("/")) continue;
|
|
1939
|
-
if (relativePath.endsWith(".xml") || relativePath.endsWith(".rels") || relativePath === "[Content_Types].xml") {
|
|
1940
|
-
files.set(relativePath, strFromU8(data));
|
|
1941
|
-
}
|
|
1942
|
-
}
|
|
1968
|
+
const files = new LazyXmlMap(rawInput, xmlEntryNames);
|
|
1943
1969
|
const media = new LazyMediaMap(rawInput, mediaEntryNames);
|
|
1944
1970
|
return { files, media };
|
|
1945
1971
|
}
|
|
@@ -3135,6 +3161,10 @@ function createDefaultBorders() {
|
|
|
3135
3161
|
|
|
3136
3162
|
// src/parser/slide-parser.ts
|
|
3137
3163
|
var SHAPE_TAGS = /* @__PURE__ */ new Set(["sp", "pic", "cxnSp", "grpSp", "graphicFrame"]);
|
|
3164
|
+
var SMARTART_DIAGRAM_URIS = /* @__PURE__ */ new Set([
|
|
3165
|
+
"http://schemas.openxmlformats.org/drawingml/2006/diagram",
|
|
3166
|
+
"http://purl.oclc.org/ooxml/drawingml/diagram"
|
|
3167
|
+
]);
|
|
3138
3168
|
function navigateOrdered(ordered, path) {
|
|
3139
3169
|
let current = ordered;
|
|
3140
3170
|
for (const key of path) {
|
|
@@ -3682,7 +3712,7 @@ function parseGraphicFrame(gf, rels, slidePath, archive, colorResolver, fontSche
|
|
|
3682
3712
|
if (!tableData) return null;
|
|
3683
3713
|
return { type: "table", transform, table: tableData };
|
|
3684
3714
|
}
|
|
3685
|
-
if (graphicData["@_uri"]
|
|
3715
|
+
if (SMARTART_DIAGRAM_URIS.has(graphicData["@_uri"])) {
|
|
3686
3716
|
return parseSmartArt(
|
|
3687
3717
|
graphicData,
|
|
3688
3718
|
transform,
|
|
@@ -8434,10 +8464,23 @@ function computePathLineX(alignment, textStartX, effectiveTextWidth, width, marg
|
|
|
8434
8464
|
return textStartX;
|
|
8435
8465
|
}
|
|
8436
8466
|
}
|
|
8437
|
-
function measureLineWidth(segments, defaultFontSize, fontScale) {
|
|
8467
|
+
function measureLineWidth(segments, defaultFontSize, fontScale, fontResolver) {
|
|
8438
8468
|
let totalWidth = 0;
|
|
8469
|
+
const jpanFallback = fontResolver ? getJpanFallbackFont() : null;
|
|
8439
8470
|
for (const seg of segments) {
|
|
8440
8471
|
const fontSize = (seg.properties.fontSize ?? defaultFontSize) * fontScale;
|
|
8472
|
+
if (fontResolver) {
|
|
8473
|
+
const fontSizePx = fontSize * PX_PER_PT3;
|
|
8474
|
+
const font = fontResolver.resolveFont(
|
|
8475
|
+
seg.properties.fontFamily,
|
|
8476
|
+
seg.properties.fontFamilyEa,
|
|
8477
|
+
jpanFallback
|
|
8478
|
+
);
|
|
8479
|
+
if (font) {
|
|
8480
|
+
totalWidth += font.getAdvanceWidth(seg.text, fontSizePx);
|
|
8481
|
+
continue;
|
|
8482
|
+
}
|
|
8483
|
+
}
|
|
8441
8484
|
totalWidth += getTextMeasurer().measureTextWidth(
|
|
8442
8485
|
seg.text,
|
|
8443
8486
|
fontSize,
|
|
@@ -8493,7 +8536,7 @@ function renderSegmentAsPath(text, props, x, y, fontScale, defaultFontSize, font
|
|
|
8493
8536
|
const processSegment = (segText, fontFamily, fontFamilyEa) => {
|
|
8494
8537
|
if (segText.length === 0) return;
|
|
8495
8538
|
const font = fontResolver.resolveFont(fontFamily, fontFamilyEa, jpanFallback);
|
|
8496
|
-
const segWidth = getTextMeasurer().measureTextWidth(
|
|
8539
|
+
const segWidth = font ? font.getAdvanceWidth(segText, fontSizePx) : getTextMeasurer().measureTextWidth(
|
|
8497
8540
|
segText,
|
|
8498
8541
|
fontSize,
|
|
8499
8542
|
props.bold,
|
|
@@ -8518,7 +8561,7 @@ function renderSegmentAsPath(text, props, x, y, fontScale, defaultFontSize, font
|
|
|
8518
8561
|
const font = fontResolver.resolveFont(fontFamily, fontFamilyEa, jpanFallback);
|
|
8519
8562
|
const fillAttrs = buildPathFillAttrs(props);
|
|
8520
8563
|
for (const char of segText) {
|
|
8521
|
-
const charWidth = getTextMeasurer().measureTextWidth(
|
|
8564
|
+
const charWidth = font ? font.getAdvanceWidth(char, fontSizePx) : getTextMeasurer().measureTextWidth(
|
|
8522
8565
|
char,
|
|
8523
8566
|
fontSize,
|
|
8524
8567
|
props.bold,
|
|
@@ -8690,7 +8733,7 @@ function renderTextBodyAsPath(textBody, transform, fontResolver) {
|
|
|
8690
8733
|
if (!isFirstLine) {
|
|
8691
8734
|
currentY += lineNaturalHeightPt * PX_PER_PT3 * getLineSpacing(para, lnSpcReduction) + lineGapPx;
|
|
8692
8735
|
}
|
|
8693
|
-
const lineWidth = measureLineWidth(line.segments, defaultFontSize, fontScale);
|
|
8736
|
+
const lineWidth = measureLineWidth(line.segments, defaultFontSize, fontScale, fontResolver);
|
|
8694
8737
|
const lineStartX = computePathLineX(
|
|
8695
8738
|
para.properties.alignment,
|
|
8696
8739
|
textStartX,
|
|
@@ -8739,7 +8782,7 @@ function renderTextBodyAsPath(textBody, transform, fontResolver) {
|
|
|
8739
8782
|
currentY += naturalHeightPt * PX_PER_PT3 * getLineSpacing(para, lnSpcReduction) + paragraphGapPx;
|
|
8740
8783
|
}
|
|
8741
8784
|
const runsAsSegments = para.runs.filter((r) => r.text.length > 0).map((r) => ({ text: r.text, properties: r.properties }));
|
|
8742
|
-
const lineWidth = measureLineWidth(runsAsSegments, defaultFontSize, fontScale);
|
|
8785
|
+
const lineWidth = measureLineWidth(runsAsSegments, defaultFontSize, fontScale, fontResolver);
|
|
8743
8786
|
const lineStartX = computePathLineX(
|
|
8744
8787
|
para.properties.alignment,
|
|
8745
8788
|
textStartX,
|
|
@@ -9075,7 +9118,11 @@ function escapeXmlAttr(str) {
|
|
|
9075
9118
|
|
|
9076
9119
|
// src/converter.ts
|
|
9077
9120
|
async function convertPptxToSvg(input, options) {
|
|
9078
|
-
const setup = await createOpentypeSetupFromSystem(
|
|
9121
|
+
const setup = await createOpentypeSetupFromSystem(
|
|
9122
|
+
options?.fontDirs,
|
|
9123
|
+
options?.fontMapping,
|
|
9124
|
+
options?.skipSystemFonts
|
|
9125
|
+
);
|
|
9079
9126
|
if (setup) {
|
|
9080
9127
|
setTextMeasurer(setup.measurer);
|
|
9081
9128
|
setTextPathFontResolver(setup.fontResolver);
|
package/package.json
CHANGED