pptx-glimpse 0.9.0 → 0.10.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/dist/index.cjs CHANGED
@@ -21,6 +21,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
23
  DEFAULT_FONT_MAPPING: () => DEFAULT_FONT_MAPPING,
24
+ clearFontCache: () => clearFontCache,
24
25
  collectUsedFonts: () => collectUsedFonts,
25
26
  convertPptxToPng: () => convertPptxToPng,
26
27
  convertPptxToSvg: () => convertPptxToSvg,
@@ -1544,7 +1545,23 @@ function collectFontNames(font) {
1544
1545
  }
1545
1546
  return names;
1546
1547
  }
1548
+ function buildCacheKey(additionalFontDirs, fontMapping) {
1549
+ const dirsKey = additionalFontDirs ? [...additionalFontDirs].sort().join("\0") : "";
1550
+ const mappingKey = fontMapping ? JSON.stringify(fontMapping, Object.keys(fontMapping).sort()) : "";
1551
+ return `${dirsKey}
1552
+ ${mappingKey}`;
1553
+ }
1554
+ var cachedSetup = null;
1555
+ var cachedSetupKey = null;
1556
+ function clearFontCache() {
1557
+ cachedSetup = null;
1558
+ cachedSetupKey = null;
1559
+ }
1547
1560
  async function createOpentypeSetupFromSystem(additionalFontDirs, fontMapping) {
1561
+ const key = buildCacheKey(additionalFontDirs, fontMapping);
1562
+ if (cachedSetup && cachedSetupKey === key) {
1563
+ return cachedSetup;
1564
+ }
1548
1565
  const opentype = await tryLoadOpentype();
1549
1566
  if (!opentype) return null;
1550
1567
  const fontFilePaths = collectFontFilePaths(additionalFontDirs);
@@ -1576,7 +1593,10 @@ async function createOpentypeSetupFromSystem(additionalFontDirs, fontMapping) {
1576
1593
  resolverFonts,
1577
1594
  firstResolverFont ?? void 0
1578
1595
  );
1579
- return { measurer, fontResolver };
1596
+ const setup = { measurer, fontResolver };
1597
+ cachedSetup = setup;
1598
+ cachedSetupKey = key;
1599
+ return setup;
1580
1600
  }
1581
1601
 
1582
1602
  // src/font/script-font-context.ts
@@ -2024,6 +2044,17 @@ function parseDefaultRunProperties(defRPr, colorResolver) {
2024
2044
  }
2025
2045
  return Object.keys(result).length > 0 ? result : void 0;
2026
2046
  }
2047
+ var VALID_AUTO_NUM_SCHEMES = /* @__PURE__ */ new Set([
2048
+ "arabicPeriod",
2049
+ "arabicParenR",
2050
+ "romanUcPeriod",
2051
+ "romanLcPeriod",
2052
+ "alphaUcPeriod",
2053
+ "alphaLcPeriod",
2054
+ "alphaLcParenR",
2055
+ "alphaUcParenR",
2056
+ "arabicPlain"
2057
+ ]);
2027
2058
  function parseParagraphLevelProperties(node, colorResolver) {
2028
2059
  if (!node) return void 0;
2029
2060
  const result = {};
@@ -2036,6 +2067,36 @@ function parseParagraphLevelProperties(node, colorResolver) {
2036
2067
  if (node["@_indent"] !== void 0) {
2037
2068
  result.indent = asEmu(Number(node["@_indent"]));
2038
2069
  }
2070
+ if (node.buNone !== void 0) {
2071
+ result.bullet = { type: "none" };
2072
+ } else if (node.buChar) {
2073
+ const buChar = node.buChar;
2074
+ result.bullet = { type: "char", char: buChar["@_char"] ?? "\u2022" };
2075
+ } else if (node.buAutoNum) {
2076
+ const buAutoNum = node.buAutoNum;
2077
+ const scheme = buAutoNum["@_type"] ?? "arabicPeriod";
2078
+ result.bullet = {
2079
+ type: "autoNum",
2080
+ scheme: VALID_AUTO_NUM_SCHEMES.has(scheme) ? scheme : "arabicPeriod",
2081
+ startAt: Number(buAutoNum["@_startAt"] ?? 1)
2082
+ };
2083
+ }
2084
+ if (node.buFont) {
2085
+ const buFont = node.buFont;
2086
+ const typeface = buFont["@_typeface"] ?? null;
2087
+ if (typeface) result.bulletFont = typeface;
2088
+ }
2089
+ if (colorResolver) {
2090
+ const buClr = node.buClr;
2091
+ if (buClr) {
2092
+ const color = colorResolver.resolve(buClr);
2093
+ if (color) result.bulletColor = color;
2094
+ }
2095
+ }
2096
+ const buSzPct = node.buSzPct;
2097
+ if (buSzPct) {
2098
+ result.bulletSizePct = Number(buSzPct["@_val"]);
2099
+ }
2039
2100
  const defRPr = parseDefaultRunProperties(node.defRPr, colorResolver);
2040
2101
  if (defRPr) {
2041
2102
  result.defaultRunProperties = defRPr;
@@ -3901,7 +3962,7 @@ function parseTextBody(txBody, colorResolver, rels, fontScheme, lstStyleOverride
3901
3962
  if (paragraphs.length === 0) return null;
3902
3963
  return { paragraphs, bodyProperties };
3903
3964
  }
3904
- var VALID_AUTO_NUM_SCHEMES = /* @__PURE__ */ new Set([
3965
+ var VALID_AUTO_NUM_SCHEMES2 = /* @__PURE__ */ new Set([
3905
3966
  "arabicPeriod",
3906
3967
  "arabicParenR",
3907
3968
  "romanUcPeriod",
@@ -3930,7 +3991,7 @@ function parseBullet(pPr, colorResolver) {
3930
3991
  const scheme = buAutoNum["@_type"] ?? "arabicPeriod";
3931
3992
  bullet = {
3932
3993
  type: "autoNum",
3933
- scheme: VALID_AUTO_NUM_SCHEMES.has(scheme) ? scheme : "arabicPeriod",
3994
+ scheme: VALID_AUTO_NUM_SCHEMES2.has(scheme) ? scheme : "arabicPeriod",
3934
3995
  startAt: Number(buAutoNum["@_startAt"] ?? 1)
3935
3996
  };
3936
3997
  }
@@ -4004,12 +4065,12 @@ function parseParagraph(p, colorResolver, rels, fontScheme, lstStyle, orderedPCh
4004
4065
  spaceBefore: parseSpacing(pPr?.spcBef),
4005
4066
  spaceAfter: parseSpacing(pPr?.spcAft),
4006
4067
  level,
4007
- bullet,
4008
- bulletFont,
4009
- bulletColor,
4010
- bulletSizePct,
4011
- marginLeft: pPr?.["@_marL"] !== void 0 ? asEmu(Number(pPr["@_marL"])) : lstLevelProps?.marginLeft ?? asEmu(0),
4012
- indent: pPr?.["@_indent"] !== void 0 ? asEmu(Number(pPr["@_indent"])) : lstLevelProps?.indent ?? asEmu(0),
4068
+ bullet: bullet ?? lstLevelProps?.bullet ?? null,
4069
+ bulletFont: bulletFont ?? lstLevelProps?.bulletFont ?? null,
4070
+ bulletColor: bulletColor ?? lstLevelProps?.bulletColor ?? null,
4071
+ bulletSizePct: bulletSizePct ?? lstLevelProps?.bulletSizePct ?? null,
4072
+ marginLeft: pPr?.["@_marL"] !== void 0 ? asEmu(Number(pPr["@_marL"])) : lstLevelProps?.marginLeft ?? null,
4073
+ indent: pPr?.["@_indent"] !== void 0 ? asEmu(Number(pPr["@_indent"])) : lstLevelProps?.indent ?? null,
4013
4074
  tabStops
4014
4075
  };
4015
4076
  const pPrDefRPr = parseDefaultRunProperties(pPr?.defRPr);
@@ -4166,7 +4227,8 @@ function parseRunProperties(rPr, colorResolver, rels, fontScheme, defaults) {
4166
4227
  );
4167
4228
  const bold = rPr["@_b"] !== void 0 ? rPr["@_b"] === "1" || rPr["@_b"] === "true" : defaults?.bold ?? false;
4168
4229
  const italic = rPr["@_i"] !== void 0 ? rPr["@_i"] === "1" || rPr["@_i"] === "true" : defaults?.italic ?? false;
4169
- const underline = rPr["@_u"] !== void 0 ? rPr["@_u"] !== "none" : defaults?.underline ?? false;
4230
+ const hasExplicitUnderline = rPr["@_u"] !== void 0;
4231
+ let underline = hasExplicitUnderline ? rPr["@_u"] !== "none" : defaults?.underline ?? false;
4170
4232
  const strikethrough = rPr["@_strike"] !== void 0 ? rPr["@_strike"] !== "noStrike" : defaults?.strikethrough ?? false;
4171
4233
  const baseline = rPr["@_baseline"] ? Number(rPr["@_baseline"]) / 1e3 : 0;
4172
4234
  const solidFill = rPr.solidFill;
@@ -4175,6 +4237,14 @@ function parseRunProperties(rPr, colorResolver, rels, fontScheme, defaults) {
4175
4237
  color = null;
4176
4238
  }
4177
4239
  const hyperlink = parseHyperlink(rPr.hlinkClick, rels);
4240
+ if (hyperlink) {
4241
+ if (!color) {
4242
+ color = colorResolver.resolve({ schemeClr: { "@_val": "hlink" } });
4243
+ }
4244
+ if (!hasExplicitUnderline && !underline) {
4245
+ underline = true;
4246
+ }
4247
+ }
4178
4248
  const ln = rPr.ln;
4179
4249
  let outline = null;
4180
4250
  if (ln) {
@@ -4696,6 +4766,51 @@ function resolveShapeTextInheritance(shape, context) {
4696
4766
  paragraph.properties.alignment = "l";
4697
4767
  }
4698
4768
  }
4769
+ if (paragraph.properties.bullet === null) {
4770
+ for (const source of chainSources) {
4771
+ if (!source) continue;
4772
+ const levelProps = source.levels[level] ?? source.defaultParagraph;
4773
+ if (!levelProps?.bullet) continue;
4774
+ paragraph.properties.bullet = levelProps.bullet;
4775
+ break;
4776
+ }
4777
+ }
4778
+ const hasBullet = paragraph.properties.bullet !== null && paragraph.properties.bullet.type !== "none";
4779
+ if (hasBullet && (paragraph.properties.bulletFont === null || paragraph.properties.bulletColor === null || paragraph.properties.bulletSizePct === null)) {
4780
+ for (const source of chainSources) {
4781
+ if (!source) continue;
4782
+ const levelProps = source.levels[level] ?? source.defaultParagraph;
4783
+ if (!levelProps) continue;
4784
+ if (paragraph.properties.bulletFont === null && levelProps.bulletFont) {
4785
+ paragraph.properties.bulletFont = levelProps.bulletFont;
4786
+ }
4787
+ if (paragraph.properties.bulletColor === null && levelProps.bulletColor) {
4788
+ paragraph.properties.bulletColor = levelProps.bulletColor;
4789
+ }
4790
+ if (paragraph.properties.bulletSizePct === null && levelProps.bulletSizePct) {
4791
+ paragraph.properties.bulletSizePct = levelProps.bulletSizePct;
4792
+ }
4793
+ if (paragraph.properties.bulletFont !== null && paragraph.properties.bulletColor !== null && paragraph.properties.bulletSizePct !== null) {
4794
+ break;
4795
+ }
4796
+ }
4797
+ }
4798
+ if (paragraph.properties.marginLeft === null || paragraph.properties.indent === null) {
4799
+ for (const source of chainSources) {
4800
+ if (!source) continue;
4801
+ const levelProps = source.levels[level] ?? source.defaultParagraph;
4802
+ if (!levelProps) continue;
4803
+ if (paragraph.properties.marginLeft === null && levelProps.marginLeft !== void 0) {
4804
+ paragraph.properties.marginLeft = levelProps.marginLeft;
4805
+ }
4806
+ if (paragraph.properties.indent === null && levelProps.indent !== void 0) {
4807
+ paragraph.properties.indent = levelProps.indent;
4808
+ }
4809
+ if (paragraph.properties.marginLeft !== null && paragraph.properties.indent !== null) {
4810
+ break;
4811
+ }
4812
+ }
4813
+ }
4699
4814
  for (const run of paragraph.runs) {
4700
4815
  const props = run.properties;
4701
4816
  for (const source of chainSources) {
@@ -7671,8 +7786,8 @@ function renderTextBody(textBody, transform) {
7671
7786
  const autoNumCounters = /* @__PURE__ */ new Map();
7672
7787
  let prevSpaceAfterPx = 0;
7673
7788
  for (const para of paragraphs) {
7674
- const paraMarginLeft = emuToPixels(para.properties.marginLeft);
7675
- const paraIndent = emuToPixels(para.properties.indent);
7789
+ const paraMarginLeft = emuToPixels(para.properties.marginLeft ?? asEmu(0));
7790
+ const paraIndent = emuToPixels(para.properties.indent ?? asEmu(0));
7676
7791
  const textStartX = marginLeftPx + paraMarginLeft;
7677
7792
  const bulletX = textStartX + paraIndent;
7678
7793
  const effectiveTextWidth = textWidth - paraMarginLeft;
@@ -8373,13 +8488,13 @@ function renderSegmentAsPath(text, props, x, y, fontScale, defaultFontSize, font
8373
8488
  }
8374
8489
  return { svg, width: totalWidth };
8375
8490
  }
8376
- function renderBulletAsPath(bulletText, x, y, paraProps, textFontSizePt, fontScale, fontResolver) {
8491
+ function renderBulletAsPath(bulletText, x, y, paraProps, textFontSizePt, fontScale, fontResolver, runFontFamily, runFontFamilyEa) {
8377
8492
  let bulletFontSize = textFontSizePt;
8378
8493
  if (paraProps.bulletSizePct !== null) {
8379
8494
  bulletFontSize = textFontSizePt * (paraProps.bulletSizePct / 1e5);
8380
8495
  }
8381
8496
  const fontSizePx = bulletFontSize * PX_PER_PT3;
8382
- const font = fontResolver.resolveFont(paraProps.bulletFont, null);
8497
+ const font = paraProps.bulletFont ? fontResolver.resolveFont(paraProps.bulletFont, null) : fontResolver.resolveFont(runFontFamily ?? null, runFontFamilyEa ?? null);
8383
8498
  if (!font) return [];
8384
8499
  const path = font.getPath(bulletText, x, y, fontSizePx);
8385
8500
  const pathData = path.toPathData(2);
@@ -8447,8 +8562,8 @@ function renderTextBodyAsPath(textBody, transform, fontResolver) {
8447
8562
  const autoNumCounters = /* @__PURE__ */ new Map();
8448
8563
  let prevSpaceAfterPx = 0;
8449
8564
  for (const para of paragraphs) {
8450
- const paraMarginLeft = emuToPixels(para.properties.marginLeft);
8451
- const paraIndent = emuToPixels(para.properties.indent);
8565
+ const paraMarginLeft = emuToPixels(para.properties.marginLeft ?? asEmu(0));
8566
+ const paraIndent = emuToPixels(para.properties.indent ?? asEmu(0));
8452
8567
  const textStartX = marginLeftPx + paraMarginLeft;
8453
8568
  const bulletX = textStartX + paraIndent;
8454
8569
  const effectiveTextWidth = textWidth - paraMarginLeft;
@@ -8502,6 +8617,7 @@ function renderTextBodyAsPath(textBody, transform, fontResolver) {
8502
8617
  let currentX = lineStartX;
8503
8618
  if (lineIdx === 0 && bulletText) {
8504
8619
  const lineFontSize = getLineFontSize(line.segments, defaultFontSize) * fontScale;
8620
+ const firstSeg = line.segments[0];
8505
8621
  elements.push(
8506
8622
  ...renderBulletAsPath(
8507
8623
  bulletText,
@@ -8510,7 +8626,9 @@ function renderTextBodyAsPath(textBody, transform, fontResolver) {
8510
8626
  para.properties,
8511
8627
  lineFontSize,
8512
8628
  fontScale,
8513
- fontResolver
8629
+ fontResolver,
8630
+ firstSeg?.properties.fontFamily,
8631
+ firstSeg?.properties.fontFamilyEa
8514
8632
  )
8515
8633
  );
8516
8634
  }
@@ -8557,7 +8675,9 @@ function renderTextBodyAsPath(textBody, transform, fontResolver) {
8557
8675
  para.properties,
8558
8676
  fontSize,
8559
8677
  fontScale,
8560
- fontResolver
8678
+ fontResolver,
8679
+ firstRun?.properties.fontFamily,
8680
+ firstRun?.properties.fontFamilyEa
8561
8681
  )
8562
8682
  );
8563
8683
  }
@@ -9004,6 +9124,7 @@ function collectFontsFromTextBody(textBody, fonts) {
9004
9124
  // Annotate the CommonJS export names for ESM import in node:
9005
9125
  0 && (module.exports = {
9006
9126
  DEFAULT_FONT_MAPPING,
9127
+ clearFontCache,
9007
9128
  collectUsedFonts,
9008
9129
  convertPptxToPng,
9009
9130
  convertPptxToSvg,
package/dist/index.d.cts CHANGED
@@ -177,6 +177,12 @@ interface OpentypeSetup {
177
177
  * 同じ Font オブジェクトを measurer と fontResolver の両方に渡す。
178
178
  */
179
179
  declare function createOpentypeSetupFromBuffers(fontBuffers: FontBuffer[], fontMapping?: FontMapping): Promise<OpentypeSetup | null>;
180
+ /**
181
+ * フォントオブジェクトキャッシュをクリアする。
182
+ * 通常は呼び出す必要はないが、フォントのインストール/アンインストール後に
183
+ * 強制的に再読み込みしたい場合に使用する。
184
+ */
185
+ declare function clearFontCache(): void;
180
186
 
181
187
  /**
182
188
  * resvg-wasm の WASM モジュールを初期化する。
@@ -185,4 +191,4 @@ declare function createOpentypeSetupFromBuffers(fontBuffers: FontBuffer[], fontM
185
191
  */
186
192
  declare function initResvgWasm(): Promise<void>;
187
193
 
188
- export { type ConvertOptions, DEFAULT_FONT_MAPPING, type FontBuffer, type FontMapping, type LogLevel, type OpentypeSetup, type SlideImage, type SlideSvg, type UsedFonts, type WarningEntry, type WarningSummary, collectUsedFonts, convertPptxToPng, convertPptxToSvg, createFontMapping, createOpentypeSetupFromBuffers, createOpentypeTextMeasurerFromBuffers, getMappedFont, getWarningEntries, getWarningSummary, initResvgWasm };
194
+ export { type ConvertOptions, DEFAULT_FONT_MAPPING, type FontBuffer, type FontMapping, type LogLevel, type OpentypeSetup, type SlideImage, type SlideSvg, type UsedFonts, type WarningEntry, type WarningSummary, clearFontCache, collectUsedFonts, convertPptxToPng, convertPptxToSvg, createFontMapping, createOpentypeSetupFromBuffers, createOpentypeTextMeasurerFromBuffers, getMappedFont, getWarningEntries, getWarningSummary, initResvgWasm };
package/dist/index.d.ts CHANGED
@@ -177,6 +177,12 @@ interface OpentypeSetup {
177
177
  * 同じ Font オブジェクトを measurer と fontResolver の両方に渡す。
178
178
  */
179
179
  declare function createOpentypeSetupFromBuffers(fontBuffers: FontBuffer[], fontMapping?: FontMapping): Promise<OpentypeSetup | null>;
180
+ /**
181
+ * フォントオブジェクトキャッシュをクリアする。
182
+ * 通常は呼び出す必要はないが、フォントのインストール/アンインストール後に
183
+ * 強制的に再読み込みしたい場合に使用する。
184
+ */
185
+ declare function clearFontCache(): void;
180
186
 
181
187
  /**
182
188
  * resvg-wasm の WASM モジュールを初期化する。
@@ -185,4 +191,4 @@ declare function createOpentypeSetupFromBuffers(fontBuffers: FontBuffer[], fontM
185
191
  */
186
192
  declare function initResvgWasm(): Promise<void>;
187
193
 
188
- export { type ConvertOptions, DEFAULT_FONT_MAPPING, type FontBuffer, type FontMapping, type LogLevel, type OpentypeSetup, type SlideImage, type SlideSvg, type UsedFonts, type WarningEntry, type WarningSummary, collectUsedFonts, convertPptxToPng, convertPptxToSvg, createFontMapping, createOpentypeSetupFromBuffers, createOpentypeTextMeasurerFromBuffers, getMappedFont, getWarningEntries, getWarningSummary, initResvgWasm };
194
+ export { type ConvertOptions, DEFAULT_FONT_MAPPING, type FontBuffer, type FontMapping, type LogLevel, type OpentypeSetup, type SlideImage, type SlideSvg, type UsedFonts, type WarningEntry, type WarningSummary, clearFontCache, collectUsedFonts, convertPptxToPng, convertPptxToSvg, createFontMapping, createOpentypeSetupFromBuffers, createOpentypeTextMeasurerFromBuffers, getMappedFont, getWarningEntries, getWarningSummary, initResvgWasm };
package/dist/index.js CHANGED
@@ -1508,7 +1508,23 @@ function collectFontNames(font) {
1508
1508
  }
1509
1509
  return names;
1510
1510
  }
1511
+ function buildCacheKey(additionalFontDirs, fontMapping) {
1512
+ const dirsKey = additionalFontDirs ? [...additionalFontDirs].sort().join("\0") : "";
1513
+ const mappingKey = fontMapping ? JSON.stringify(fontMapping, Object.keys(fontMapping).sort()) : "";
1514
+ return `${dirsKey}
1515
+ ${mappingKey}`;
1516
+ }
1517
+ var cachedSetup = null;
1518
+ var cachedSetupKey = null;
1519
+ function clearFontCache() {
1520
+ cachedSetup = null;
1521
+ cachedSetupKey = null;
1522
+ }
1511
1523
  async function createOpentypeSetupFromSystem(additionalFontDirs, fontMapping) {
1524
+ const key = buildCacheKey(additionalFontDirs, fontMapping);
1525
+ if (cachedSetup && cachedSetupKey === key) {
1526
+ return cachedSetup;
1527
+ }
1512
1528
  const opentype = await tryLoadOpentype();
1513
1529
  if (!opentype) return null;
1514
1530
  const fontFilePaths = collectFontFilePaths(additionalFontDirs);
@@ -1540,7 +1556,10 @@ async function createOpentypeSetupFromSystem(additionalFontDirs, fontMapping) {
1540
1556
  resolverFonts,
1541
1557
  firstResolverFont ?? void 0
1542
1558
  );
1543
- return { measurer, fontResolver };
1559
+ const setup = { measurer, fontResolver };
1560
+ cachedSetup = setup;
1561
+ cachedSetupKey = key;
1562
+ return setup;
1544
1563
  }
1545
1564
 
1546
1565
  // src/font/script-font-context.ts
@@ -1987,6 +2006,17 @@ function parseDefaultRunProperties(defRPr, colorResolver) {
1987
2006
  }
1988
2007
  return Object.keys(result).length > 0 ? result : void 0;
1989
2008
  }
2009
+ var VALID_AUTO_NUM_SCHEMES = /* @__PURE__ */ new Set([
2010
+ "arabicPeriod",
2011
+ "arabicParenR",
2012
+ "romanUcPeriod",
2013
+ "romanLcPeriod",
2014
+ "alphaUcPeriod",
2015
+ "alphaLcPeriod",
2016
+ "alphaLcParenR",
2017
+ "alphaUcParenR",
2018
+ "arabicPlain"
2019
+ ]);
1990
2020
  function parseParagraphLevelProperties(node, colorResolver) {
1991
2021
  if (!node) return void 0;
1992
2022
  const result = {};
@@ -1999,6 +2029,36 @@ function parseParagraphLevelProperties(node, colorResolver) {
1999
2029
  if (node["@_indent"] !== void 0) {
2000
2030
  result.indent = asEmu(Number(node["@_indent"]));
2001
2031
  }
2032
+ if (node.buNone !== void 0) {
2033
+ result.bullet = { type: "none" };
2034
+ } else if (node.buChar) {
2035
+ const buChar = node.buChar;
2036
+ result.bullet = { type: "char", char: buChar["@_char"] ?? "\u2022" };
2037
+ } else if (node.buAutoNum) {
2038
+ const buAutoNum = node.buAutoNum;
2039
+ const scheme = buAutoNum["@_type"] ?? "arabicPeriod";
2040
+ result.bullet = {
2041
+ type: "autoNum",
2042
+ scheme: VALID_AUTO_NUM_SCHEMES.has(scheme) ? scheme : "arabicPeriod",
2043
+ startAt: Number(buAutoNum["@_startAt"] ?? 1)
2044
+ };
2045
+ }
2046
+ if (node.buFont) {
2047
+ const buFont = node.buFont;
2048
+ const typeface = buFont["@_typeface"] ?? null;
2049
+ if (typeface) result.bulletFont = typeface;
2050
+ }
2051
+ if (colorResolver) {
2052
+ const buClr = node.buClr;
2053
+ if (buClr) {
2054
+ const color = colorResolver.resolve(buClr);
2055
+ if (color) result.bulletColor = color;
2056
+ }
2057
+ }
2058
+ const buSzPct = node.buSzPct;
2059
+ if (buSzPct) {
2060
+ result.bulletSizePct = Number(buSzPct["@_val"]);
2061
+ }
2002
2062
  const defRPr = parseDefaultRunProperties(node.defRPr, colorResolver);
2003
2063
  if (defRPr) {
2004
2064
  result.defaultRunProperties = defRPr;
@@ -3864,7 +3924,7 @@ function parseTextBody(txBody, colorResolver, rels, fontScheme, lstStyleOverride
3864
3924
  if (paragraphs.length === 0) return null;
3865
3925
  return { paragraphs, bodyProperties };
3866
3926
  }
3867
- var VALID_AUTO_NUM_SCHEMES = /* @__PURE__ */ new Set([
3927
+ var VALID_AUTO_NUM_SCHEMES2 = /* @__PURE__ */ new Set([
3868
3928
  "arabicPeriod",
3869
3929
  "arabicParenR",
3870
3930
  "romanUcPeriod",
@@ -3893,7 +3953,7 @@ function parseBullet(pPr, colorResolver) {
3893
3953
  const scheme = buAutoNum["@_type"] ?? "arabicPeriod";
3894
3954
  bullet = {
3895
3955
  type: "autoNum",
3896
- scheme: VALID_AUTO_NUM_SCHEMES.has(scheme) ? scheme : "arabicPeriod",
3956
+ scheme: VALID_AUTO_NUM_SCHEMES2.has(scheme) ? scheme : "arabicPeriod",
3897
3957
  startAt: Number(buAutoNum["@_startAt"] ?? 1)
3898
3958
  };
3899
3959
  }
@@ -3967,12 +4027,12 @@ function parseParagraph(p, colorResolver, rels, fontScheme, lstStyle, orderedPCh
3967
4027
  spaceBefore: parseSpacing(pPr?.spcBef),
3968
4028
  spaceAfter: parseSpacing(pPr?.spcAft),
3969
4029
  level,
3970
- bullet,
3971
- bulletFont,
3972
- bulletColor,
3973
- bulletSizePct,
3974
- marginLeft: pPr?.["@_marL"] !== void 0 ? asEmu(Number(pPr["@_marL"])) : lstLevelProps?.marginLeft ?? asEmu(0),
3975
- indent: pPr?.["@_indent"] !== void 0 ? asEmu(Number(pPr["@_indent"])) : lstLevelProps?.indent ?? asEmu(0),
4030
+ bullet: bullet ?? lstLevelProps?.bullet ?? null,
4031
+ bulletFont: bulletFont ?? lstLevelProps?.bulletFont ?? null,
4032
+ bulletColor: bulletColor ?? lstLevelProps?.bulletColor ?? null,
4033
+ bulletSizePct: bulletSizePct ?? lstLevelProps?.bulletSizePct ?? null,
4034
+ marginLeft: pPr?.["@_marL"] !== void 0 ? asEmu(Number(pPr["@_marL"])) : lstLevelProps?.marginLeft ?? null,
4035
+ indent: pPr?.["@_indent"] !== void 0 ? asEmu(Number(pPr["@_indent"])) : lstLevelProps?.indent ?? null,
3976
4036
  tabStops
3977
4037
  };
3978
4038
  const pPrDefRPr = parseDefaultRunProperties(pPr?.defRPr);
@@ -4129,7 +4189,8 @@ function parseRunProperties(rPr, colorResolver, rels, fontScheme, defaults) {
4129
4189
  );
4130
4190
  const bold = rPr["@_b"] !== void 0 ? rPr["@_b"] === "1" || rPr["@_b"] === "true" : defaults?.bold ?? false;
4131
4191
  const italic = rPr["@_i"] !== void 0 ? rPr["@_i"] === "1" || rPr["@_i"] === "true" : defaults?.italic ?? false;
4132
- const underline = rPr["@_u"] !== void 0 ? rPr["@_u"] !== "none" : defaults?.underline ?? false;
4192
+ const hasExplicitUnderline = rPr["@_u"] !== void 0;
4193
+ let underline = hasExplicitUnderline ? rPr["@_u"] !== "none" : defaults?.underline ?? false;
4133
4194
  const strikethrough = rPr["@_strike"] !== void 0 ? rPr["@_strike"] !== "noStrike" : defaults?.strikethrough ?? false;
4134
4195
  const baseline = rPr["@_baseline"] ? Number(rPr["@_baseline"]) / 1e3 : 0;
4135
4196
  const solidFill = rPr.solidFill;
@@ -4138,6 +4199,14 @@ function parseRunProperties(rPr, colorResolver, rels, fontScheme, defaults) {
4138
4199
  color = null;
4139
4200
  }
4140
4201
  const hyperlink = parseHyperlink(rPr.hlinkClick, rels);
4202
+ if (hyperlink) {
4203
+ if (!color) {
4204
+ color = colorResolver.resolve({ schemeClr: { "@_val": "hlink" } });
4205
+ }
4206
+ if (!hasExplicitUnderline && !underline) {
4207
+ underline = true;
4208
+ }
4209
+ }
4141
4210
  const ln = rPr.ln;
4142
4211
  let outline = null;
4143
4212
  if (ln) {
@@ -4659,6 +4728,51 @@ function resolveShapeTextInheritance(shape, context) {
4659
4728
  paragraph.properties.alignment = "l";
4660
4729
  }
4661
4730
  }
4731
+ if (paragraph.properties.bullet === null) {
4732
+ for (const source of chainSources) {
4733
+ if (!source) continue;
4734
+ const levelProps = source.levels[level] ?? source.defaultParagraph;
4735
+ if (!levelProps?.bullet) continue;
4736
+ paragraph.properties.bullet = levelProps.bullet;
4737
+ break;
4738
+ }
4739
+ }
4740
+ const hasBullet = paragraph.properties.bullet !== null && paragraph.properties.bullet.type !== "none";
4741
+ if (hasBullet && (paragraph.properties.bulletFont === null || paragraph.properties.bulletColor === null || paragraph.properties.bulletSizePct === null)) {
4742
+ for (const source of chainSources) {
4743
+ if (!source) continue;
4744
+ const levelProps = source.levels[level] ?? source.defaultParagraph;
4745
+ if (!levelProps) continue;
4746
+ if (paragraph.properties.bulletFont === null && levelProps.bulletFont) {
4747
+ paragraph.properties.bulletFont = levelProps.bulletFont;
4748
+ }
4749
+ if (paragraph.properties.bulletColor === null && levelProps.bulletColor) {
4750
+ paragraph.properties.bulletColor = levelProps.bulletColor;
4751
+ }
4752
+ if (paragraph.properties.bulletSizePct === null && levelProps.bulletSizePct) {
4753
+ paragraph.properties.bulletSizePct = levelProps.bulletSizePct;
4754
+ }
4755
+ if (paragraph.properties.bulletFont !== null && paragraph.properties.bulletColor !== null && paragraph.properties.bulletSizePct !== null) {
4756
+ break;
4757
+ }
4758
+ }
4759
+ }
4760
+ if (paragraph.properties.marginLeft === null || paragraph.properties.indent === null) {
4761
+ for (const source of chainSources) {
4762
+ if (!source) continue;
4763
+ const levelProps = source.levels[level] ?? source.defaultParagraph;
4764
+ if (!levelProps) continue;
4765
+ if (paragraph.properties.marginLeft === null && levelProps.marginLeft !== void 0) {
4766
+ paragraph.properties.marginLeft = levelProps.marginLeft;
4767
+ }
4768
+ if (paragraph.properties.indent === null && levelProps.indent !== void 0) {
4769
+ paragraph.properties.indent = levelProps.indent;
4770
+ }
4771
+ if (paragraph.properties.marginLeft !== null && paragraph.properties.indent !== null) {
4772
+ break;
4773
+ }
4774
+ }
4775
+ }
4662
4776
  for (const run of paragraph.runs) {
4663
4777
  const props = run.properties;
4664
4778
  for (const source of chainSources) {
@@ -7634,8 +7748,8 @@ function renderTextBody(textBody, transform) {
7634
7748
  const autoNumCounters = /* @__PURE__ */ new Map();
7635
7749
  let prevSpaceAfterPx = 0;
7636
7750
  for (const para of paragraphs) {
7637
- const paraMarginLeft = emuToPixels(para.properties.marginLeft);
7638
- const paraIndent = emuToPixels(para.properties.indent);
7751
+ const paraMarginLeft = emuToPixels(para.properties.marginLeft ?? asEmu(0));
7752
+ const paraIndent = emuToPixels(para.properties.indent ?? asEmu(0));
7639
7753
  const textStartX = marginLeftPx + paraMarginLeft;
7640
7754
  const bulletX = textStartX + paraIndent;
7641
7755
  const effectiveTextWidth = textWidth - paraMarginLeft;
@@ -8336,13 +8450,13 @@ function renderSegmentAsPath(text, props, x, y, fontScale, defaultFontSize, font
8336
8450
  }
8337
8451
  return { svg, width: totalWidth };
8338
8452
  }
8339
- function renderBulletAsPath(bulletText, x, y, paraProps, textFontSizePt, fontScale, fontResolver) {
8453
+ function renderBulletAsPath(bulletText, x, y, paraProps, textFontSizePt, fontScale, fontResolver, runFontFamily, runFontFamilyEa) {
8340
8454
  let bulletFontSize = textFontSizePt;
8341
8455
  if (paraProps.bulletSizePct !== null) {
8342
8456
  bulletFontSize = textFontSizePt * (paraProps.bulletSizePct / 1e5);
8343
8457
  }
8344
8458
  const fontSizePx = bulletFontSize * PX_PER_PT3;
8345
- const font = fontResolver.resolveFont(paraProps.bulletFont, null);
8459
+ const font = paraProps.bulletFont ? fontResolver.resolveFont(paraProps.bulletFont, null) : fontResolver.resolveFont(runFontFamily ?? null, runFontFamilyEa ?? null);
8346
8460
  if (!font) return [];
8347
8461
  const path = font.getPath(bulletText, x, y, fontSizePx);
8348
8462
  const pathData = path.toPathData(2);
@@ -8410,8 +8524,8 @@ function renderTextBodyAsPath(textBody, transform, fontResolver) {
8410
8524
  const autoNumCounters = /* @__PURE__ */ new Map();
8411
8525
  let prevSpaceAfterPx = 0;
8412
8526
  for (const para of paragraphs) {
8413
- const paraMarginLeft = emuToPixels(para.properties.marginLeft);
8414
- const paraIndent = emuToPixels(para.properties.indent);
8527
+ const paraMarginLeft = emuToPixels(para.properties.marginLeft ?? asEmu(0));
8528
+ const paraIndent = emuToPixels(para.properties.indent ?? asEmu(0));
8415
8529
  const textStartX = marginLeftPx + paraMarginLeft;
8416
8530
  const bulletX = textStartX + paraIndent;
8417
8531
  const effectiveTextWidth = textWidth - paraMarginLeft;
@@ -8465,6 +8579,7 @@ function renderTextBodyAsPath(textBody, transform, fontResolver) {
8465
8579
  let currentX = lineStartX;
8466
8580
  if (lineIdx === 0 && bulletText) {
8467
8581
  const lineFontSize = getLineFontSize(line.segments, defaultFontSize) * fontScale;
8582
+ const firstSeg = line.segments[0];
8468
8583
  elements.push(
8469
8584
  ...renderBulletAsPath(
8470
8585
  bulletText,
@@ -8473,7 +8588,9 @@ function renderTextBodyAsPath(textBody, transform, fontResolver) {
8473
8588
  para.properties,
8474
8589
  lineFontSize,
8475
8590
  fontScale,
8476
- fontResolver
8591
+ fontResolver,
8592
+ firstSeg?.properties.fontFamily,
8593
+ firstSeg?.properties.fontFamilyEa
8477
8594
  )
8478
8595
  );
8479
8596
  }
@@ -8520,7 +8637,9 @@ function renderTextBodyAsPath(textBody, transform, fontResolver) {
8520
8637
  para.properties,
8521
8638
  fontSize,
8522
8639
  fontScale,
8523
- fontResolver
8640
+ fontResolver,
8641
+ firstRun?.properties.fontFamily,
8642
+ firstRun?.properties.fontFamilyEa
8524
8643
  )
8525
8644
  );
8526
8645
  }
@@ -8966,6 +9085,7 @@ function collectFontsFromTextBody(textBody, fonts) {
8966
9085
  }
8967
9086
  export {
8968
9087
  DEFAULT_FONT_MAPPING,
9088
+ clearFontCache,
8969
9089
  collectUsedFonts,
8970
9090
  convertPptxToPng,
8971
9091
  convertPptxToSvg,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pptx-glimpse",
3
- "version": "0.9.0",
3
+ "version": "0.10.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",