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 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
- const unzipped = (0, import_fflate.unzipSync)(rawInput, {
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
- return false;
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 true;
2003
+ return false;
1972
2004
  }
1973
2005
  });
1974
- const files = /* @__PURE__ */ new Map();
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"] === "http://schemas.openxmlformats.org/drawingml/2006/diagram") {
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(options?.fontDirs, options?.fontMapping);
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
- const unzipped = unzipSync(rawInput, {
1958
+ unzipSync(rawInput, {
1928
1959
  filter: (file) => {
1929
1960
  if (file.name.startsWith("ppt/media/")) {
1930
1961
  mediaEntryNames.add(file.name);
1931
- return false;
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 true;
1965
+ return false;
1934
1966
  }
1935
1967
  });
1936
- const files = /* @__PURE__ */ new Map();
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"] === "http://schemas.openxmlformats.org/drawingml/2006/diagram") {
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(options?.fontDirs, options?.fontMapping);
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pptx-glimpse",
3
- "version": "0.10.4",
3
+ "version": "0.11.1",
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",