docgen-utils 1.0.14 → 1.0.15

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/cli.js CHANGED
@@ -69594,28 +69594,62 @@ function hexToRgba(hex, alpha100k) {
69594
69594
  const a = Math.round(alpha100k / 1e5 * 100) / 100;
69595
69595
  return `rgba(${r},${g},${b},${a})`;
69596
69596
  }
69597
+ function applyTint(hex, tintVal) {
69598
+ const factor = tintVal / 1e5;
69599
+ const r = parseInt(hex.slice(1, 3), 16);
69600
+ const g = parseInt(hex.slice(3, 5), 16);
69601
+ const b = parseInt(hex.slice(5, 7), 16);
69602
+ const nr = Math.round(r + (255 - r) * (1 - factor));
69603
+ const ng = Math.round(g + (255 - g) * (1 - factor));
69604
+ const nb = Math.round(b + (255 - b) * (1 - factor));
69605
+ return `#${nr.toString(16).padStart(2, "0")}${ng.toString(16).padStart(2, "0")}${nb.toString(16).padStart(2, "0")}`;
69606
+ }
69607
+ function applyShade(hex, shadeVal) {
69608
+ const factor = shadeVal / 1e5;
69609
+ const r = Math.round(parseInt(hex.slice(1, 3), 16) * factor);
69610
+ const g = Math.round(parseInt(hex.slice(3, 5), 16) * factor);
69611
+ const b = Math.round(parseInt(hex.slice(5, 7), 16) * factor);
69612
+ return `#${r.toString(16).padStart(2, "0")}${g.toString(16).padStart(2, "0")}${b.toString(16).padStart(2, "0")}`;
69613
+ }
69614
+ function applyColorModifiers(colorEl, hex) {
69615
+ let color = hex;
69616
+ let alphaVal;
69617
+ const tintEl = findChild2(colorEl, "tint");
69618
+ if (tintEl) {
69619
+ const val = parseInt(tintEl.getAttribute("val") ?? "100000", 10);
69620
+ color = applyTint(color, val);
69621
+ }
69622
+ const shadeEl = findChild2(colorEl, "shade");
69623
+ if (shadeEl) {
69624
+ const val = parseInt(shadeEl.getAttribute("val") ?? "100000", 10);
69625
+ color = applyShade(color, val);
69626
+ }
69627
+ const alphaEl = findChild2(colorEl, "alpha");
69628
+ if (alphaEl) {
69629
+ alphaVal = parseInt(alphaEl.getAttribute("val") ?? "100000", 10);
69630
+ }
69631
+ return { color, alpha: alphaVal };
69632
+ }
69597
69633
  function resolveColor2(parent, themeColors) {
69598
69634
  const srgbClr = findChild2(parent, "srgbClr");
69599
69635
  if (srgbClr) {
69600
69636
  const hex = "#" + (srgbClr.getAttribute("val") ?? "000000");
69601
- const alphaEl = findChild2(srgbClr, "alpha");
69602
- if (alphaEl) {
69603
- const alphaVal = parseInt(alphaEl.getAttribute("val") ?? "100000", 10);
69604
- return hexToRgba(hex, alphaVal);
69637
+ const { color, alpha } = applyColorModifiers(srgbClr, hex);
69638
+ if (alpha !== void 0 && alpha < 1e5) {
69639
+ return hexToRgba(color, alpha);
69605
69640
  }
69606
- return hex;
69641
+ return color;
69607
69642
  }
69608
69643
  const schemeClr = findChild2(parent, "schemeClr");
69609
69644
  if (schemeClr) {
69610
69645
  const val = schemeClr.getAttribute("val");
69611
69646
  if (val && themeColors.has(val)) {
69612
69647
  const hex = themeColors.get(val);
69613
- const alphaEl = findChild2(schemeClr, "alpha");
69614
- if (alphaEl) {
69615
- const alphaVal = parseInt(alphaEl.getAttribute("val") ?? "100000", 10);
69616
- return hexToRgba(hex, alphaVal);
69648
+ const { color, alpha } = applyColorModifiers(schemeClr, hex);
69649
+ if (alpha !== void 0 && alpha < 1e5) {
69650
+ return hexToRgba(color, alpha);
69617
69651
  }
69618
- return hex;
69652
+ return color;
69619
69653
  }
69620
69654
  }
69621
69655
  return void 0;
@@ -69661,6 +69695,144 @@ function extractFill(spPr, themeColors) {
69661
69695
  if (solidFill) return resolveColor2(solidFill, themeColors);
69662
69696
  return extractGradientFill(spPr, themeColors);
69663
69697
  }
69698
+ function resolveBgRef(bgRef, bgFillStyles, themeColors) {
69699
+ const idx = parseInt(bgRef.getAttribute("idx") ?? "0", 10);
69700
+ if (idx < 1001 || bgFillStyles.length === 0) return void 0;
69701
+ const styleIdx = idx - 1001;
69702
+ if (styleIdx >= bgFillStyles.length) return void 0;
69703
+ const fillStyle = bgFillStyles[styleIdx];
69704
+ const phColor = resolveColor2(bgRef, themeColors);
69705
+ if (fillStyle.localName === "solidFill") {
69706
+ const phClr = findChild2(fillStyle, "schemeClr");
69707
+ if (phClr?.getAttribute("val") === "phClr" && phColor) {
69708
+ return phColor;
69709
+ }
69710
+ return resolveColor2(fillStyle, themeColors) ?? phColor;
69711
+ }
69712
+ if (fillStyle.localName === "gradFill") {
69713
+ return extractGradientFill(
69714
+ // Wrap in a parent element for extractGradientFill
69715
+ { children: [fillStyle] },
69716
+ themeColors
69717
+ );
69718
+ }
69719
+ return phColor;
69720
+ }
69721
+ function extractBgFill(bgEl, bgFillStyles, themeColors) {
69722
+ const bgPr = findChild2(bgEl, "bgPr");
69723
+ if (bgPr) {
69724
+ return extractFill(bgPr, themeColors);
69725
+ }
69726
+ const bgRef = findChild2(bgEl, "bgRef");
69727
+ if (bgRef) {
69728
+ return resolveBgRef(bgRef, bgFillStyles, themeColors);
69729
+ }
69730
+ return void 0;
69731
+ }
69732
+ function extractCustGeomClipPath(custGeom) {
69733
+ const pathLst = findChild2(custGeom, "pathLst");
69734
+ if (!pathLst) return void 0;
69735
+ const pathEl = findChild2(pathLst, "path");
69736
+ if (!pathEl) return void 0;
69737
+ const pathW = parseInt(pathEl.getAttribute("w") ?? "0", 10);
69738
+ const pathH = parseInt(pathEl.getAttribute("h") ?? "0", 10);
69739
+ if (pathW <= 0 || pathH <= 0) return void 0;
69740
+ const points = [];
69741
+ for (let i = 0; i < pathEl.children.length; i++) {
69742
+ const cmd = pathEl.children[i];
69743
+ const localName = cmd.localName;
69744
+ if (localName === "moveTo" || localName === "lnTo") {
69745
+ const pt = findChild2(cmd, "pt");
69746
+ if (pt) {
69747
+ const x = parseInt(pt.getAttribute("x") ?? "0", 10);
69748
+ const y = parseInt(pt.getAttribute("y") ?? "0", 10);
69749
+ points.push({ x, y });
69750
+ }
69751
+ } else if (localName === "close") {
69752
+ } else {
69753
+ return void 0;
69754
+ }
69755
+ }
69756
+ if (points.length < 3) return void 0;
69757
+ const polygonPoints = points.map((p) => {
69758
+ const xPct = Math.round(p.x / pathW * 1e4) / 100;
69759
+ const yPct = Math.round(p.y / pathH * 1e4) / 100;
69760
+ return `${xPct}% ${yPct}%`;
69761
+ }).join(", ");
69762
+ return `polygon(${polygonPoints})`;
69763
+ }
69764
+ function parseDecorativeShapes(spTree, scale, themeColors, imageMap, themeFonts) {
69765
+ const elements = [];
69766
+ for (let i = 0; i < spTree.children.length; i++) {
69767
+ const child = spTree.children[i];
69768
+ if (child.localName === "sp") {
69769
+ const nvSpPr = findChild2(child, "nvSpPr");
69770
+ if (nvSpPr) {
69771
+ const phEl = findChild2(findChild2(nvSpPr, "nvPr") ?? nvSpPr, "ph");
69772
+ if (phEl) continue;
69773
+ }
69774
+ const spPr = findChild2(child, "spPr");
69775
+ if (spPr) {
69776
+ const custGeom = findChild2(spPr, "custGeom");
69777
+ if (custGeom) {
69778
+ const clipPath = extractCustGeomClipPath(custGeom);
69779
+ if (!clipPath) continue;
69780
+ const shape2 = parseShape(child, scale, themeColors, themeFonts);
69781
+ if (shape2) {
69782
+ shape2.clipPath = clipPath;
69783
+ elements.push({ kind: "shape", data: shape2 });
69784
+ }
69785
+ continue;
69786
+ }
69787
+ }
69788
+ const shape = parseShape(child, scale, themeColors, themeFonts);
69789
+ if (shape) elements.push({ kind: "shape", data: shape });
69790
+ } else if (child.localName === "pic") {
69791
+ const img = parsePicture(child, scale, imageMap);
69792
+ if (img) elements.push({ kind: "image", data: img });
69793
+ } else if (child.localName === "grpSp") {
69794
+ const grpElements = parseGroupShape(child, scale, themeColors, imageMap, themeFonts);
69795
+ elements.push(...grpElements);
69796
+ }
69797
+ }
69798
+ return elements;
69799
+ }
69800
+ function parseGroupShape(grpSp, scale, themeColors, imageMap, themeFonts) {
69801
+ const elements = [];
69802
+ for (let i = 0; i < grpSp.children.length; i++) {
69803
+ const child = grpSp.children[i];
69804
+ if (child.localName === "sp") {
69805
+ const nvSpPr = findChild2(child, "nvSpPr");
69806
+ if (nvSpPr) {
69807
+ const phEl = findChild2(findChild2(nvSpPr, "nvPr") ?? nvSpPr, "ph");
69808
+ if (phEl) continue;
69809
+ }
69810
+ const spPr = findChild2(child, "spPr");
69811
+ if (spPr) {
69812
+ const custGeom = findChild2(spPr, "custGeom");
69813
+ if (custGeom) {
69814
+ const clipPath = extractCustGeomClipPath(custGeom);
69815
+ if (!clipPath) continue;
69816
+ const shape2 = parseShape(child, scale, themeColors, themeFonts);
69817
+ if (shape2) {
69818
+ shape2.clipPath = clipPath;
69819
+ elements.push({ kind: "shape", data: shape2 });
69820
+ }
69821
+ continue;
69822
+ }
69823
+ }
69824
+ const shape = parseShape(child, scale, themeColors, themeFonts);
69825
+ if (shape) elements.push({ kind: "shape", data: shape });
69826
+ } else if (child.localName === "pic") {
69827
+ const img = parsePicture(child, scale, imageMap);
69828
+ if (img) elements.push({ kind: "image", data: img });
69829
+ } else if (child.localName === "grpSp") {
69830
+ const nested = parseGroupShape(child, scale, themeColors, imageMap, themeFonts);
69831
+ elements.push(...nested);
69832
+ }
69833
+ }
69834
+ return elements;
69835
+ }
69664
69836
  function extractRunProps(rPr, scale, themeColors, themeFonts) {
69665
69837
  if (!rPr) return {};
69666
69838
  const result = {};
@@ -69670,6 +69842,8 @@ function extractRunProps(rPr, scale, themeColors, themeFonts) {
69670
69842
  if (b === "1" || b === "true") result.bold = true;
69671
69843
  const i = rPr.getAttribute("i");
69672
69844
  if (i === "1" || i === "true") result.italic = true;
69845
+ const u = rPr.getAttribute("u");
69846
+ if (u && u !== "none") result.underline = true;
69673
69847
  const solidFill = findChild2(rPr, "solidFill");
69674
69848
  if (solidFill) {
69675
69849
  const color = resolveColor2(solidFill, themeColors);
@@ -69764,14 +69938,32 @@ function parseShape(sp, scale, themeColors, themeFonts) {
69764
69938
  if (!off || !ext) return null;
69765
69939
  const wEmu = parseInt(ext.getAttribute("cx") ?? "0", 10);
69766
69940
  const hEmu = parseInt(ext.getAttribute("cy") ?? "0", 10);
69941
+ let fill = extractFill(spPr, themeColors);
69942
+ if (!fill && !findChild2(spPr, "noFill")) {
69943
+ const styleEl = findChild2(sp, "style");
69944
+ if (styleEl) {
69945
+ const fillRef = findChild2(styleEl, "fillRef");
69946
+ if (fillRef) {
69947
+ const fillIdx = parseInt(fillRef.getAttribute("idx") ?? "0", 10);
69948
+ if (fillIdx > 0) {
69949
+ fill = resolveColor2(fillRef, themeColors) ?? void 0;
69950
+ }
69951
+ }
69952
+ }
69953
+ }
69767
69954
  const shape = {
69768
69955
  x: Math.round(emuToPx2(parseInt(off.getAttribute("x") ?? "0", 10)) * scale),
69769
69956
  y: Math.round(emuToPx2(parseInt(off.getAttribute("y") ?? "0", 10)) * scale),
69770
69957
  w: Math.round(emuToPx2(wEmu) * scale),
69771
69958
  h: Math.round(emuToPx2(hEmu) * scale),
69772
- fill: extractFill(spPr, themeColors),
69959
+ fill,
69773
69960
  paragraphs: []
69774
69961
  };
69962
+ const rotAttr = xfrm.getAttribute("rot");
69963
+ if (rotAttr) {
69964
+ const rotDeg = parseInt(rotAttr, 10) / 6e4;
69965
+ if (rotDeg !== 0) shape.rotation = rotDeg;
69966
+ }
69775
69967
  const prstGeom = findChild2(spPr, "prstGeom");
69776
69968
  const prstType = prstGeom?.getAttribute("prst");
69777
69969
  if (prstType === "roundRect" && prstGeom) {
@@ -69783,6 +69975,10 @@ function parseShape(sp, scale, themeColors, themeFonts) {
69783
69975
  shape.borderRadius = Math.round(emuToPx2(radiusEmu) * scale);
69784
69976
  } else if (prstType === "ellipse") {
69785
69977
  shape.isEllipse = true;
69978
+ } else if (prstType === "rtTriangle") {
69979
+ shape.clipPath = "polygon(0 0, 0 100%, 100% 100%)";
69980
+ } else if (prstType === "triangle" || prstType === "isoTriangle") {
69981
+ shape.clipPath = "polygon(50% 0, 0 100%, 100% 100%)";
69786
69982
  }
69787
69983
  const ln = findChild2(spPr, "ln");
69788
69984
  if (ln) {
@@ -69878,6 +70074,10 @@ function parseShape(sp, scale, themeColors, themeFonts) {
69878
70074
  if (buChar) {
69879
70075
  para.bulletChar = buChar.getAttribute("char") ?? void 0;
69880
70076
  }
70077
+ const buFont = findChild2(pPr, "buFont");
70078
+ if (buFont) {
70079
+ para.bulletFont = buFont.getAttribute("typeface") ?? void 0;
70080
+ }
69881
70081
  const buClr = findChild2(pPr, "buClr");
69882
70082
  if (buClr) {
69883
70083
  para.bulletColor = resolveColor2(buClr, themeColors);
@@ -69897,6 +70097,7 @@ function parseShape(sp, scale, themeColors, themeFonts) {
69897
70097
  text,
69898
70098
  bold: props.bold ?? defaults?.bold,
69899
70099
  italic: props.italic ?? defaults?.italic,
70100
+ underline: props.underline ?? defaults?.underline,
69900
70101
  fontSize: props.fontSize ?? defaults?.fontSize,
69901
70102
  color: props.color ?? defaults?.color,
69902
70103
  fontFamily: props.fontFamily ?? defaults?.fontFamily,
@@ -69965,12 +70166,16 @@ function parsePicture(pic, scale, imageMap) {
69965
70166
  const alt = cNvPr?.getAttribute("descr") ?? void 0;
69966
70167
  const srcRect = findChild2(blipFill, "srcRect");
69967
70168
  let hasCrop = false;
70169
+ let cropLeft = 0;
70170
+ let cropTop = 0;
70171
+ let cropRight = 0;
70172
+ let cropBottom = 0;
69968
70173
  if (srcRect) {
69969
- const l = parseInt(srcRect.getAttribute("l") ?? "0", 10);
69970
- const r = parseInt(srcRect.getAttribute("r") ?? "0", 10);
69971
- const t = parseInt(srcRect.getAttribute("t") ?? "0", 10);
69972
- const b = parseInt(srcRect.getAttribute("b") ?? "0", 10);
69973
- hasCrop = l > 0 || r > 0 || t > 0 || b > 0;
70174
+ cropLeft = parseInt(srcRect.getAttribute("l") ?? "0", 10) / 1e3;
70175
+ cropRight = parseInt(srcRect.getAttribute("r") ?? "0", 10) / 1e3;
70176
+ cropTop = parseInt(srcRect.getAttribute("t") ?? "0", 10) / 1e3;
70177
+ cropBottom = parseInt(srcRect.getAttribute("b") ?? "0", 10) / 1e3;
70178
+ hasCrop = cropLeft > 0 || cropRight > 0 || cropTop > 0 || cropBottom > 0;
69974
70179
  }
69975
70180
  let borderRadius;
69976
70181
  const prstGeom = findChild2(spPr, "prstGeom");
@@ -69984,6 +70189,12 @@ function parsePicture(pic, scale, imageMap) {
69984
70189
  const radiusEmu = minDim * Math.min(adjVal, 5e4) / 1e5;
69985
70190
  borderRadius = Math.round(emuToPx2(radiusEmu) * scale);
69986
70191
  }
70192
+ let rotation;
70193
+ const rotAttr = xfrm.getAttribute("rot");
70194
+ if (rotAttr) {
70195
+ const rotDeg = parseInt(rotAttr, 10) / 6e4;
70196
+ if (rotDeg !== 0) rotation = rotDeg;
70197
+ }
69987
70198
  return {
69988
70199
  x: Math.round(emuToPx2(parseInt(off.getAttribute("x") ?? "0", 10)) * scale),
69989
70200
  y: Math.round(emuToPx2(parseInt(off.getAttribute("y") ?? "0", 10)) * scale),
@@ -69992,7 +70203,12 @@ function parsePicture(pic, scale, imageMap) {
69992
70203
  dataUri,
69993
70204
  alt,
69994
70205
  borderRadius,
69995
- hasCrop
70206
+ hasCrop,
70207
+ cropLeft: hasCrop ? cropLeft : void 0,
70208
+ cropTop: hasCrop ? cropTop : void 0,
70209
+ cropRight: hasCrop ? cropRight : void 0,
70210
+ cropBottom: hasCrop ? cropBottom : void 0,
70211
+ rotation
69996
70212
  };
69997
70213
  }
69998
70214
  async function parseTableStyles(zip, parser, themeColors) {
@@ -70112,6 +70328,10 @@ function parseParagraphsFromTxBody(txBody, scale, themeColors, themeFonts) {
70112
70328
  if (buChar) {
70113
70329
  para.bulletChar = buChar.getAttribute("char") ?? void 0;
70114
70330
  }
70331
+ const buFont = findChild2(pPr, "buFont");
70332
+ if (buFont) {
70333
+ para.bulletFont = buFont.getAttribute("typeface") ?? void 0;
70334
+ }
70115
70335
  const buClr = findChild2(pPr, "buClr");
70116
70336
  if (buClr) {
70117
70337
  para.bulletColor = resolveColor2(buClr, themeColors);
@@ -70131,6 +70351,7 @@ function parseParagraphsFromTxBody(txBody, scale, themeColors, themeFonts) {
70131
70351
  text,
70132
70352
  bold: props.bold ?? defaults?.bold,
70133
70353
  italic: props.italic ?? defaults?.italic,
70354
+ underline: props.underline ?? defaults?.underline,
70134
70355
  fontSize: props.fontSize ?? defaults?.fontSize,
70135
70356
  color: props.color ?? defaults?.color,
70136
70357
  fontFamily: props.fontFamily ?? defaults?.fontFamily,
@@ -70276,15 +70497,492 @@ function parseTable2(graphicFrame, scale, themeColors, themeFonts, tableStyleMap
70276
70497
  }
70277
70498
  return table;
70278
70499
  }
70279
- function renderSlideHtml(elements, bgColor) {
70500
+ function resolveChartColor(parent, themeColors) {
70501
+ const solidFill = findChild2(parent, "solidFill");
70502
+ if (!solidFill) return void 0;
70503
+ return resolveColor2(solidFill, themeColors);
70504
+ }
70505
+ function parseChartRichText(richEl) {
70506
+ const paragraphs = findChildren2(richEl, "p");
70507
+ let text = "";
70508
+ let font;
70509
+ let color;
70510
+ let size;
70511
+ for (const p of paragraphs) {
70512
+ const runs = findChildren2(p, "r");
70513
+ for (const r of runs) {
70514
+ const tEl = findChild2(r, "t");
70515
+ if (tEl?.textContent) text += tEl.textContent;
70516
+ if (font === void 0) {
70517
+ const rPr = findChild2(r, "rPr");
70518
+ if (rPr) {
70519
+ const szAttr = rPr.getAttribute("sz");
70520
+ if (szAttr) size = hptToPx(parseInt(szAttr, 10));
70521
+ const latin = findChild2(rPr, "latin");
70522
+ if (latin) font = latin.getAttribute("typeface") ?? void 0;
70523
+ const fill = findChild2(rPr, "solidFill");
70524
+ if (fill) {
70525
+ const srgb = findChild2(fill, "srgbClr");
70526
+ if (srgb) color = "#" + (srgb.getAttribute("val") ?? "000000");
70527
+ }
70528
+ }
70529
+ }
70530
+ }
70531
+ }
70532
+ return { text, font, color, size };
70533
+ }
70534
+ function parseChartAxis(axEl, themeColors) {
70535
+ const axis = {
70536
+ position: "b"
70537
+ };
70538
+ const axPos = findChild2(axEl, "axPos");
70539
+ if (axPos) {
70540
+ const val = axPos.getAttribute("val");
70541
+ if (val === "b" || val === "l" || val === "r" || val === "t") {
70542
+ axis.position = val;
70543
+ }
70544
+ }
70545
+ const titleEl = findChild2(axEl, "title");
70546
+ if (titleEl) {
70547
+ const tx = findChild2(titleEl, "tx");
70548
+ if (tx) {
70549
+ const rich = findChild2(tx, "rich");
70550
+ if (rich) {
70551
+ const parsed = parseChartRichText(rich);
70552
+ axis.title = parsed.text;
70553
+ }
70554
+ }
70555
+ }
70556
+ const numFmt = findChild2(axEl, "numFmt");
70557
+ if (numFmt) {
70558
+ const fmt = numFmt.getAttribute("formatCode");
70559
+ if (fmt) axis.numFormat = fmt;
70560
+ }
70561
+ const txPr = findChild2(axEl, "txPr");
70562
+ if (txPr) {
70563
+ const pEls = findChildren2(txPr, "p");
70564
+ for (const p of pEls) {
70565
+ const pPr = findChild2(p, "pPr");
70566
+ if (pPr) {
70567
+ const defRPr = findChild2(pPr, "defRPr");
70568
+ if (defRPr) {
70569
+ const szAttr = defRPr.getAttribute("sz");
70570
+ if (szAttr) axis.labelSize = hptToPx(parseInt(szAttr, 10));
70571
+ const latin = findChild2(defRPr, "latin");
70572
+ if (latin) axis.labelFont = latin.getAttribute("typeface") ?? void 0;
70573
+ const fill = findChild2(defRPr, "solidFill");
70574
+ if (fill) {
70575
+ const srgb = findChild2(fill, "srgbClr");
70576
+ if (srgb) axis.labelColor = "#" + (srgb.getAttribute("val") ?? "000000");
70577
+ }
70578
+ }
70579
+ }
70580
+ }
70581
+ }
70582
+ const gridlines = findChild2(axEl, "majorGridlines");
70583
+ if (gridlines) {
70584
+ const spPr = findChild2(gridlines, "spPr");
70585
+ if (spPr) {
70586
+ const ln = findChild2(spPr, "ln");
70587
+ if (ln) {
70588
+ const fill = findChild2(ln, "solidFill");
70589
+ if (fill) {
70590
+ const srgb = findChild2(fill, "srgbClr");
70591
+ if (srgb) {
70592
+ axis.gridlineColor = "#" + (srgb.getAttribute("val") ?? "CCCCCC");
70593
+ const alphaEl = findChild2(srgb, "alpha");
70594
+ if (alphaEl) {
70595
+ axis.gridlineAlpha = parseInt(alphaEl.getAttribute("val") ?? "100000", 10) / 1e3;
70596
+ }
70597
+ }
70598
+ }
70599
+ }
70600
+ }
70601
+ }
70602
+ const scaling = findChild2(axEl, "scaling");
70603
+ if (scaling) {
70604
+ const minEl = findChild2(scaling, "min");
70605
+ if (minEl) {
70606
+ const val = minEl.getAttribute("val");
70607
+ if (val) axis.min = parseFloat(val);
70608
+ }
70609
+ }
70610
+ return axis;
70611
+ }
70612
+ async function parseChart(graphicFrame, scale, themeColors, zip, slideRelsDoc, parser) {
70613
+ const xfrm = findChild2(graphicFrame, "xfrm");
70614
+ if (!xfrm) return null;
70615
+ const off = findChild2(xfrm, "off");
70616
+ const ext = findChild2(xfrm, "ext");
70617
+ if (!off || !ext) return null;
70618
+ const graphic = findChild2(graphicFrame, "graphic");
70619
+ if (!graphic) return null;
70620
+ const graphicData = findChild2(graphic, "graphicData");
70621
+ if (!graphicData) return null;
70622
+ const uri2 = graphicData.getAttribute("uri") ?? "";
70623
+ if (!uri2.includes("chart")) return null;
70624
+ let chartRId;
70625
+ for (let i = 0; i < graphicData.children.length; i++) {
70626
+ const child = graphicData.children[i];
70627
+ if (child.localName === "chart") {
70628
+ chartRId = child.getAttribute("r:id") ?? child.getAttributeNS("http://schemas.openxmlformats.org/officeDocument/2006/relationships", "id") ?? void 0;
70629
+ break;
70630
+ }
70631
+ }
70632
+ if (!chartRId) return null;
70633
+ let chartTarget;
70634
+ const rels = slideRelsDoc.getElementsByTagName("Relationship");
70635
+ for (let ri = 0; ri < rels.length; ri++) {
70636
+ const rel = rels[ri];
70637
+ if (rel.getAttribute("Id") === chartRId) {
70638
+ chartTarget = rel.getAttribute("Target") ?? void 0;
70639
+ break;
70640
+ }
70641
+ }
70642
+ if (!chartTarget) return null;
70643
+ const chartPath = chartTarget.startsWith("../") ? "ppt/" + chartTarget.slice(3) : chartTarget;
70644
+ const chartXml = await zip.file(chartPath)?.async("text");
70645
+ if (!chartXml) return null;
70646
+ const chartDoc = parser.parseFromString(chartXml, "application/xml");
70647
+ const chartSpace = chartDoc.documentElement;
70648
+ const x = Math.round(emuToPx2(parseInt(off.getAttribute("x") ?? "0", 10)) * scale);
70649
+ const y = Math.round(emuToPx2(parseInt(off.getAttribute("y") ?? "0", 10)) * scale);
70650
+ const w = Math.round(emuToPx2(parseInt(ext.getAttribute("cx") ?? "0", 10)) * scale);
70651
+ const h = Math.round(emuToPx2(parseInt(ext.getAttribute("cy") ?? "0", 10)) * scale);
70652
+ const chartEl = findChild2(chartSpace, "chart");
70653
+ if (!chartEl) return null;
70654
+ let title;
70655
+ let titleFont;
70656
+ let titleColor;
70657
+ let titleSize;
70658
+ const titleEl = findChild2(chartEl, "title");
70659
+ if (titleEl) {
70660
+ const tx = findChild2(titleEl, "tx");
70661
+ if (tx) {
70662
+ const rich = findChild2(tx, "rich");
70663
+ if (rich) {
70664
+ const parsed = parseChartRichText(rich);
70665
+ title = parsed.text;
70666
+ titleFont = parsed.font;
70667
+ titleColor = parsed.color;
70668
+ titleSize = parsed.size;
70669
+ }
70670
+ }
70671
+ }
70672
+ const plotArea = findChild2(chartEl, "plotArea");
70673
+ if (!plotArea) return null;
70674
+ const barChart = findChild2(plotArea, "barChart");
70675
+ if (!barChart) return null;
70676
+ const barDirEl = findChild2(barChart, "barDir");
70677
+ const barDir = barDirEl?.getAttribute("val") ?? "col";
70678
+ const chartType = barDir === "bar" ? "bar" : "column";
70679
+ const gapWidthEl = findChild2(barChart, "gapWidth");
70680
+ const gapWidth = gapWidthEl ? parseInt(gapWidthEl.getAttribute("val") ?? "150", 10) : 150;
70681
+ const roundedCornersEl = findChild2(chartSpace, "roundedCorners");
70682
+ const roundedCorners = roundedCornersEl?.getAttribute("val") === "1";
70683
+ const series = [];
70684
+ const serEls = findChildren2(barChart, "ser");
70685
+ for (const ser of serEls) {
70686
+ const seriesData = {
70687
+ categories: [],
70688
+ values: [],
70689
+ fillColors: []
70690
+ };
70691
+ const txEl = findChild2(ser, "tx");
70692
+ if (txEl) {
70693
+ const strRef = findChild2(txEl, "strRef");
70694
+ if (strRef) {
70695
+ const strCache = findChild2(strRef, "strCache");
70696
+ if (strCache) {
70697
+ const pt = findChild2(strCache, "pt");
70698
+ if (pt) {
70699
+ const v = findChild2(pt, "v");
70700
+ if (v?.textContent) seriesData.name = v.textContent;
70701
+ }
70702
+ }
70703
+ }
70704
+ }
70705
+ const serSpPr = findChild2(ser, "spPr");
70706
+ if (serSpPr) {
70707
+ const color = resolveChartColor(serSpPr, themeColors);
70708
+ if (color) seriesData.seriesColor = color;
70709
+ }
70710
+ const dPtMap = /* @__PURE__ */ new Map();
70711
+ const dPtEls = findChildren2(ser, "dPt");
70712
+ for (const dPt of dPtEls) {
70713
+ const idxEl = findChild2(dPt, "idx");
70714
+ const idx = idxEl ? parseInt(idxEl.getAttribute("val") ?? "0", 10) : 0;
70715
+ const spPr = findChild2(dPt, "spPr");
70716
+ if (spPr) {
70717
+ const color = resolveChartColor(spPr, themeColors);
70718
+ if (color) dPtMap.set(idx, color);
70719
+ }
70720
+ }
70721
+ const catEl = findChild2(ser, "cat");
70722
+ if (catEl) {
70723
+ const strRef = findChild2(catEl, "strRef");
70724
+ if (strRef) {
70725
+ const strCache = findChild2(strRef, "strCache");
70726
+ if (strCache) {
70727
+ const pts = findChildren2(strCache, "pt");
70728
+ for (const pt of pts) {
70729
+ const v = findChild2(pt, "v");
70730
+ seriesData.categories.push(v?.textContent ?? "");
70731
+ }
70732
+ }
70733
+ }
70734
+ }
70735
+ const valEl = findChild2(ser, "val");
70736
+ if (valEl) {
70737
+ const numRef = findChild2(valEl, "numRef");
70738
+ if (numRef) {
70739
+ const numCache = findChild2(numRef, "numCache");
70740
+ if (numCache) {
70741
+ const pts = findChildren2(numCache, "pt");
70742
+ for (const pt of pts) {
70743
+ const v = findChild2(pt, "v");
70744
+ seriesData.values.push(parseFloat(v?.textContent ?? "0"));
70745
+ }
70746
+ }
70747
+ }
70748
+ }
70749
+ for (let i = 0; i < seriesData.values.length; i++) {
70750
+ seriesData.fillColors.push(dPtMap.get(i) ?? void 0);
70751
+ }
70752
+ series.push(seriesData);
70753
+ }
70754
+ if (series.length === 0) return null;
70755
+ let categoryAxis;
70756
+ let valueAxis;
70757
+ const catAx = findChild2(plotArea, "catAx");
70758
+ if (catAx) {
70759
+ categoryAxis = parseChartAxis(catAx, themeColors);
70760
+ }
70761
+ const valAx = findChild2(plotArea, "valAx");
70762
+ if (valAx) {
70763
+ valueAxis = parseChartAxis(valAx, themeColors);
70764
+ }
70765
+ return {
70766
+ x,
70767
+ y,
70768
+ w,
70769
+ h,
70770
+ chartType,
70771
+ title,
70772
+ titleFont,
70773
+ titleColor,
70774
+ titleSize,
70775
+ series,
70776
+ categoryAxis,
70777
+ valueAxis,
70778
+ gapWidth,
70779
+ roundedCorners
70780
+ };
70781
+ }
70782
+ function formatChartValue(value, numFormat) {
70783
+ if (!numFormat || numFormat === "General") {
70784
+ return Number.isInteger(value) ? value.toString() : value.toFixed(1);
70785
+ }
70786
+ let prefix = "";
70787
+ let suffix = "";
70788
+ let fmt = numFormat;
70789
+ const prefixMatch = fmt.match(/^"([^"]*)"(.*)$/);
70790
+ if (prefixMatch) {
70791
+ prefix = prefixMatch[1];
70792
+ fmt = prefixMatch[2];
70793
+ }
70794
+ const suffixMatch = fmt.match(/^(.*)"([^"]*)"$/);
70795
+ if (suffixMatch) {
70796
+ fmt = suffixMatch[1];
70797
+ suffix = suffixMatch[2];
70798
+ }
70799
+ const decimalMatch = fmt.match(/\.(0+)/);
70800
+ const decimals = decimalMatch ? decimalMatch[1].length : 0;
70801
+ const absVal = Math.abs(value);
70802
+ let formatted;
70803
+ if (fmt.includes(",")) {
70804
+ const parts = absVal.toFixed(decimals).split(".");
70805
+ parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
70806
+ formatted = parts.join(".");
70807
+ } else {
70808
+ formatted = absVal.toFixed(decimals);
70809
+ }
70810
+ const sign2 = value < 0 ? "-" : "";
70811
+ return sign2 + prefix + formatted + suffix;
70812
+ }
70813
+ function escSvg(text) {
70814
+ return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
70815
+ }
70816
+ function renderChartSvg(chart, elId) {
70817
+ const { x, y, w, h } = chart;
70818
+ const titleHeight = chart.title ? Math.max(24, (chart.titleSize ?? 16) + 12) : 0;
70819
+ const axisLabelHeight = 16;
70820
+ const axisTitleHeight = chart.categoryAxis?.title ? 18 : 0;
70821
+ const valAxisTitleWidth = chart.valueAxis?.title ? 20 : 0;
70822
+ const allValues = chart.series.flatMap((s) => s.values);
70823
+ const maxValue = Math.max(...allValues, 0);
70824
+ const valNumFormat = chart.valueAxis?.numFormat;
70825
+ const maxFormattedLabel = formatChartValue(maxValue, valNumFormat);
70826
+ const valLabelCharWidth = (chart.valueAxis?.labelSize ?? 11) * 0.6;
70827
+ const valLabelWidth = Math.max(30, maxFormattedLabel.length * valLabelCharWidth + 8);
70828
+ const marginTop = 8 + titleHeight;
70829
+ const marginBottom = 8 + axisLabelHeight + axisTitleHeight + 4;
70830
+ const marginLeft = 4 + valAxisTitleWidth + valLabelWidth;
70831
+ const marginRight = 12;
70832
+ const plotX = marginLeft;
70833
+ const plotY = marginTop;
70834
+ const plotW = w - marginLeft - marginRight;
70835
+ const plotH = h - marginTop - marginBottom;
70836
+ if (plotW <= 0 || plotH <= 0) return "";
70837
+ const minValue = chart.valueAxis?.min ?? 0;
70838
+ const valueRange = maxValue - minValue;
70839
+ if (valueRange <= 0) return "";
70840
+ const rawInterval = valueRange / 5;
70841
+ const magnitude = Math.pow(10, Math.floor(Math.log10(rawInterval)));
70842
+ const normalized = rawInterval / magnitude;
70843
+ let niceInterval;
70844
+ if (normalized <= 1) niceInterval = 1 * magnitude;
70845
+ else if (normalized <= 2) niceInterval = 2 * magnitude;
70846
+ else if (normalized <= 5) niceInterval = 5 * magnitude;
70847
+ else niceInterval = 10 * magnitude;
70848
+ const ticks = [];
70849
+ let tickVal = Math.ceil(minValue / niceInterval) * niceInterval;
70850
+ while (tickVal <= maxValue) {
70851
+ ticks.push(tickVal);
70852
+ tickVal += niceInterval;
70853
+ }
70854
+ if (minValue <= 0 && !ticks.includes(0)) {
70855
+ ticks.unshift(0);
70856
+ ticks.sort((a, b) => a - b);
70857
+ }
70858
+ const labelFont = chart.categoryAxis?.labelFont ?? chart.titleFont ?? "sans-serif";
70859
+ const labelColor = chart.categoryAxis?.labelColor ?? "#333";
70860
+ const labelSize = chart.categoryAxis?.labelSize ?? 11;
70861
+ const valLabelColor = chart.valueAxis?.labelColor ?? labelColor;
70862
+ const valLabelSize = chart.valueAxis?.labelSize ?? 11;
70863
+ let svg = `<svg xmlns="http://www.w3.org/2000/svg" width="${w}" height="${h}" viewBox="0 0 ${w} ${h}" style="overflow:visible">`;
70864
+ if (chart.title) {
70865
+ const tFont = chart.titleFont ? `font-family:${cssFontFamily(chart.titleFont)};` : `font-family:${cssFontFamily(labelFont)};`;
70866
+ const tColor = chart.titleColor ?? "#000";
70867
+ const tSize = chart.titleSize ?? 16;
70868
+ svg += `<text x="${w / 2}" y="${8 + tSize}" text-anchor="middle" style="${tFont}font-size:${tSize}px;font-weight:bold;fill:${tColor}">${escSvg(chart.title)}</text>`;
70869
+ }
70870
+ if (chart.valueAxis) {
70871
+ const gColor = chart.valueAxis.gridlineColor ?? "#e0e0e0";
70872
+ const gAlpha = chart.valueAxis.gridlineAlpha !== void 0 ? chart.valueAxis.gridlineAlpha / 100 : 0.3;
70873
+ for (const tick of ticks) {
70874
+ const tickY = plotY + plotH - (tick - minValue) / valueRange * plotH;
70875
+ svg += `<line x1="${plotX}" y1="${tickY}" x2="${plotX + plotW}" y2="${tickY}" stroke="${gColor}" stroke-opacity="${gAlpha}" stroke-width="1"/>`;
70876
+ }
70877
+ }
70878
+ const numCategories = chart.series[0]?.categories.length ?? 0;
70879
+ const numSeries = chart.series.length;
70880
+ if (numCategories > 0) {
70881
+ const gapFraction = (chart.gapWidth ?? 150) / 100;
70882
+ const categoryWidth = plotW / numCategories;
70883
+ const barGroupWidth = categoryWidth / (1 + gapFraction);
70884
+ const gapSpace = categoryWidth - barGroupWidth;
70885
+ const barWidth = barGroupWidth / numSeries;
70886
+ const cornerRadius = chart.roundedCorners ? Math.min(barWidth * 0.15, 4) : 0;
70887
+ for (let si = 0; si < numSeries; si++) {
70888
+ const s = chart.series[si];
70889
+ for (let ci = 0; ci < s.values.length; ci++) {
70890
+ const val = s.values[ci];
70891
+ const barH = (val - minValue) / valueRange * plotH;
70892
+ const barX = plotX + ci * categoryWidth + gapSpace / 2 + si * barWidth;
70893
+ const barY = plotY + plotH - barH;
70894
+ const fillColor = s.fillColors[ci] ?? s.seriesColor ?? "#4472C4";
70895
+ if (cornerRadius > 0) {
70896
+ const r = Math.min(cornerRadius, barH / 2, barWidth / 2);
70897
+ svg += `<path d="M${barX},${barY + barH} L${barX},${barY + r} Q${barX},${barY} ${barX + r},${barY} L${barX + barWidth - r},${barY} Q${barX + barWidth},${barY} ${barX + barWidth},${barY + r} L${barX + barWidth},${barY + barH} Z" fill="${fillColor}"/>`;
70898
+ } else {
70899
+ svg += `<rect x="${barX}" y="${barY}" width="${barWidth}" height="${barH}" fill="${fillColor}"/>`;
70900
+ }
70901
+ }
70902
+ }
70903
+ }
70904
+ svg += `<line x1="${plotX}" y1="${plotY + plotH}" x2="${plotX + plotW}" y2="${plotY + plotH}" stroke="${labelColor}" stroke-width="1"/>`;
70905
+ svg += `<line x1="${plotX}" y1="${plotY}" x2="${plotX}" y2="${plotY + plotH}" stroke="${valLabelColor}" stroke-width="1"/>`;
70906
+ if (numCategories > 0) {
70907
+ const categoryWidth = plotW / numCategories;
70908
+ const cats = chart.series[0]?.categories ?? [];
70909
+ for (let ci = 0; ci < cats.length; ci++) {
70910
+ const labelX = plotX + ci * categoryWidth + categoryWidth / 2;
70911
+ const labelY = plotY + plotH + 4;
70912
+ const catText = cats[ci];
70913
+ const lines = catText.split("\n");
70914
+ const lineH = labelSize + 2;
70915
+ for (let li = 0; li < lines.length; li++) {
70916
+ svg += `<text x="${labelX}" y="${labelY + labelSize + li * lineH}" text-anchor="middle" style="font-family:${cssFontFamily(labelFont)};font-size:${labelSize}px;fill:${labelColor}">${escSvg(lines[li])}</text>`;
70917
+ }
70918
+ }
70919
+ }
70920
+ for (const tick of ticks) {
70921
+ const tickY = plotY + plotH - (tick - minValue) / valueRange * plotH;
70922
+ const label = formatChartValue(tick, valNumFormat);
70923
+ svg += `<text x="${plotX - 6}" y="${tickY + valLabelSize * 0.35}" text-anchor="end" style="font-family:${cssFontFamily(labelFont)};font-size:${valLabelSize}px;fill:${valLabelColor}">${escSvg(label)}</text>`;
70924
+ }
70925
+ if (chart.categoryAxis?.title) {
70926
+ const axTitleY = plotY + plotH + axisLabelHeight + axisTitleHeight + 2;
70927
+ svg += `<text x="${plotX + plotW / 2}" y="${axTitleY}" text-anchor="middle" style="font-family:${cssFontFamily(labelFont)};font-size:${labelSize}px;fill:${labelColor}">${escSvg(chart.categoryAxis.title)}</text>`;
70928
+ }
70929
+ if (chart.valueAxis?.title) {
70930
+ const axTitleX = 4 + (chart.titleSize ?? 12) * 0.5;
70931
+ const axTitleY = plotY + plotH / 2;
70932
+ svg += `<text x="${axTitleX}" y="${axTitleY}" text-anchor="middle" transform="rotate(-90, ${axTitleX}, ${axTitleY})" style="font-family:${cssFontFamily(labelFont)};font-size:${labelSize}px;fill:${valLabelColor}">${escSvg(chart.valueAxis.title)}</text>`;
70933
+ }
70934
+ svg += `</svg>`;
70935
+ const wrapperStyles = [
70936
+ "position:absolute",
70937
+ `left:${x}px`,
70938
+ `top:${y}px`,
70939
+ `width:${w}px`,
70940
+ `height:${h}px`
70941
+ ];
70942
+ return `<div id="${elId}" data-elementType="chart" style="${wrapperStyles.join(";")}">${svg}</div>
70943
+ `;
70944
+ }
70945
+ function renderSlideHtml(elements, bgColor, contentOffsetX = 0) {
70280
70946
  let inner = "";
70281
70947
  let elementIndex = 0;
70282
70948
  for (const el of elements) {
70283
70949
  const elId = `el-${elementIndex++}`;
70284
70950
  if (el.kind === "image") {
70285
70951
  const img = el.data;
70952
+ const altAttr = img.alt ? ` alt="${img.alt.replace(/"/g, "&quot;")}"` : "";
70286
70953
  const isFullbleed = img.x <= 10 && img.y <= 10 && img.w >= TARGET_WIDTH - 20 && img.h >= TARGET_HEIGHT - 20;
70287
- const objectFit = isFullbleed || img.hasCrop ? "cover" : "contain";
70954
+ if (img.hasCrop && img.cropLeft !== void 0 && img.cropTop !== void 0 && img.cropRight !== void 0 && img.cropBottom !== void 0) {
70955
+ const visW = (100 - img.cropLeft - img.cropRight) / 100;
70956
+ const visH = (100 - img.cropTop - img.cropBottom) / 100;
70957
+ if (visW > 0 && visH > 0) {
70958
+ const displayW = img.w / visW;
70959
+ const displayH = img.h / visH;
70960
+ const offsetX = -(img.cropLeft / 100) * displayW;
70961
+ const offsetY = -(img.cropTop / 100) * displayH;
70962
+ const wrapperStyles = [
70963
+ "position:absolute",
70964
+ `left:${img.x}px`,
70965
+ `top:${img.y}px`,
70966
+ `width:${img.w}px`,
70967
+ `height:${img.h}px`,
70968
+ "overflow:hidden"
70969
+ ];
70970
+ if (img.rotation) {
70971
+ wrapperStyles.push(`transform:rotate(${img.rotation}deg)`);
70972
+ wrapperStyles.push("transform-origin:center center");
70973
+ }
70974
+ if (img.borderRadius && img.borderRadius > 0) {
70975
+ wrapperStyles.push(`border-radius:${img.borderRadius}px`);
70976
+ }
70977
+ const imgStyle = `position:absolute;width:${Math.round(displayW)}px;height:${Math.round(displayH)}px;left:${Math.round(offsetX)}px;top:${Math.round(offsetY)}px`;
70978
+ inner += `<div id="${elId}" data-elementType="image" style="${wrapperStyles.join(";")}">`;
70979
+ inner += `<img src="${img.dataUri}"${altAttr} style="${imgStyle}" />`;
70980
+ inner += `</div>
70981
+ `;
70982
+ continue;
70983
+ }
70984
+ }
70985
+ const objectFit = isFullbleed ? "cover" : "contain";
70288
70986
  const stylesList = [
70289
70987
  "position:absolute",
70290
70988
  `left:${img.x}px`,
@@ -70293,11 +70991,14 @@ function renderSlideHtml(elements, bgColor) {
70293
70991
  `height:${img.h}px`,
70294
70992
  `object-fit:${objectFit}`
70295
70993
  ];
70994
+ if (img.rotation) {
70995
+ stylesList.push(`transform:rotate(${img.rotation}deg)`);
70996
+ stylesList.push("transform-origin:center center");
70997
+ }
70296
70998
  if (img.borderRadius && img.borderRadius > 0) {
70297
70999
  stylesList.push(`border-radius:${img.borderRadius}px`);
70298
71000
  }
70299
71001
  const styles2 = stylesList.join(";");
70300
- const altAttr = img.alt ? ` alt="${img.alt.replace(/"/g, "&quot;")}"` : "";
70301
71002
  inner += `<img id="${elId}" data-elementType="image" src="${img.dataUri}"${altAttr} style="${styles2}" />
70302
71003
  `;
70303
71004
  continue;
@@ -70380,6 +71081,7 @@ function renderSlideHtml(elements, bgColor) {
70380
71081
  }
70381
71082
  if (run.bold) rStyles.push("font-weight:bold");
70382
71083
  if (run.italic) rStyles.push("font-style:italic");
71084
+ if (run.underline) rStyles.push("text-decoration:underline");
70383
71085
  if (run.fontFamily)
70384
71086
  rStyles.push(`font-family:${cssFontFamily(run.fontFamily)}`);
70385
71087
  if (run.textShadow) rStyles.push(`text-shadow:${run.textShadow}`);
@@ -70401,6 +71103,11 @@ function renderSlideHtml(elements, bgColor) {
70401
71103
  `;
70402
71104
  continue;
70403
71105
  }
71106
+ if (el.kind === "chart") {
71107
+ const chart = el.data;
71108
+ inner += renderChartSvg(chart, elId);
71109
+ continue;
71110
+ }
70404
71111
  const shape = el.data;
70405
71112
  const styles = [
70406
71113
  "position:absolute",
@@ -70413,6 +71120,12 @@ function renderSlideHtml(elements, bgColor) {
70413
71120
  if (shape.fill) {
70414
71121
  styles.push(`background:${shape.fill}`);
70415
71122
  }
71123
+ if (shape.clipPath) {
71124
+ styles.push(`clip-path:${shape.clipPath}`);
71125
+ }
71126
+ if (shape.rotation) {
71127
+ styles.push(`transform:rotate(${shape.rotation}deg)`);
71128
+ }
70416
71129
  if (shape.borderRadius) {
70417
71130
  styles.push(`border-radius:${shape.borderRadius}px`);
70418
71131
  } else if (shape.isEllipse) {
@@ -70448,7 +71161,10 @@ function renderSlideHtml(elements, bgColor) {
70448
71161
  else if (shape.verticalAlign === "bottom")
70449
71162
  styles.push("justify-content:flex-end");
70450
71163
  }
70451
- if (shape.paragraphs.length === 0 && !shape.fill) {
71164
+ if (shape.w <= 0 || shape.h <= 0) {
71165
+ continue;
71166
+ }
71167
+ if (shape.paragraphs.length === 0 && !shape.fill && !shape.borderWidth && !shape.isEllipse) {
70452
71168
  continue;
70453
71169
  }
70454
71170
  const hasText = shape.paragraphs.length > 0;
@@ -70468,8 +71184,12 @@ function renderSlideHtml(elements, bgColor) {
70468
71184
  if (para.indentPx) pStyles.push(`text-indent:${para.indentPx}px`);
70469
71185
  let runHtml = "";
70470
71186
  if (para.bulletChar) {
70471
- const bulletStyle = para.bulletColor ? `margin-right:4px;color:${para.bulletColor}` : "margin-right:4px";
70472
- runHtml += `<span style="${bulletStyle}">${para.bulletChar}</span>`;
71187
+ const bulletStyleParts = ["margin-right:4px"];
71188
+ if (para.bulletColor) bulletStyleParts.push(`color:${para.bulletColor}`);
71189
+ if (para.bulletFont) bulletStyleParts.push(`font-family:${cssFontFamily(para.bulletFont)}`);
71190
+ const firstRunFontSize = para.runs[0]?.fontSize;
71191
+ if (firstRunFontSize) bulletStyleParts.push(`font-size:${firstRunFontSize}px`);
71192
+ runHtml += `<span style="${bulletStyleParts.join(";")}">${para.bulletChar}</span>`;
70473
71193
  }
70474
71194
  for (const run of para.runs) {
70475
71195
  const rStyles = [];
@@ -70484,6 +71204,7 @@ function renderSlideHtml(elements, bgColor) {
70484
71204
  }
70485
71205
  if (run.bold) rStyles.push("font-weight:bold");
70486
71206
  if (run.italic) rStyles.push("font-style:italic");
71207
+ if (run.underline) rStyles.push("text-decoration:underline");
70487
71208
  if (run.fontFamily)
70488
71209
  rStyles.push(`font-family:${cssFontFamily(run.fontFamily)}`);
70489
71210
  if (run.textShadow) rStyles.push(`text-shadow:${run.textShadow}`);
@@ -70500,8 +71221,12 @@ function renderSlideHtml(elements, bgColor) {
70500
71221
  `;
70501
71222
  }
70502
71223
  const bg = bgColor ?? "#fff";
71224
+ const offsetPx = Math.round(contentOffsetX);
71225
+ const innerWrapStyle = offsetPx > 0 ? ` style="position:absolute;left:${offsetPx}px;top:0"` : "";
70503
71226
  return `<div style="position:relative;width:${TARGET_WIDTH}px;height:${TARGET_HEIGHT}px;overflow:hidden;font-family:'Segoe UI',Arial,sans-serif;background:${bg}">
70504
- ${inner}</div>`;
71227
+ <div${innerWrapStyle}>
71228
+ ${inner}</div>
71229
+ </div>`;
70505
71230
  }
70506
71231
  async function importPptx(arrayBuffer) {
70507
71232
  const zip = await import_jszip2.default.loadAsync(arrayBuffer);
@@ -70515,6 +71240,8 @@ async function importPptx(arrayBuffer) {
70515
71240
  const slideWPx = emuToPx2(slideWEmu);
70516
71241
  const slideHPx = emuToPx2(slideHEmu);
70517
71242
  const scale = Math.min(TARGET_WIDTH / slideWPx, TARGET_HEIGHT / slideHPx);
71243
+ const scaledContentW = slideWPx * scale;
71244
+ const contentOffsetX = (TARGET_WIDTH - scaledContentW) / 2;
70518
71245
  const sldIdLst = presDoc.getElementsByTagName("p:sldIdLst")[0];
70519
71246
  const visibleSlideRIds = [];
70520
71247
  if (sldIdLst) {
@@ -70563,6 +71290,7 @@ async function importPptx(arrayBuffer) {
70563
71290
  }
70564
71291
  const themeColors = /* @__PURE__ */ new Map();
70565
71292
  const themeXml = await zip.file("ppt/theme/theme1.xml")?.async("text");
71293
+ const bgFillStyles = [];
70566
71294
  if (themeXml) {
70567
71295
  const themeDoc = parser.parseFromString(themeXml, "application/xml");
70568
71296
  const clrScheme = themeDoc.getElementsByTagName("a:clrScheme")[0];
@@ -70609,6 +71337,12 @@ async function importPptx(arrayBuffer) {
70609
71337
  if (lt1Color) themeColors.set("bg1", lt1Color);
70610
71338
  const lt2Color = themeColors.get("lt2");
70611
71339
  if (lt2Color) themeColors.set("bg2", lt2Color);
71340
+ const bgFillStyleLst = themeDoc.getElementsByTagName("a:bgFillStyleLst")[0];
71341
+ if (bgFillStyleLst) {
71342
+ for (let i = 0; i < bgFillStyleLst.children.length; i++) {
71343
+ bgFillStyles.push(bgFillStyleLst.children[i]);
71344
+ }
71345
+ }
70612
71346
  }
70613
71347
  let themeFonts;
70614
71348
  if (themeXml) {
@@ -70644,6 +71378,89 @@ async function importPptx(arrayBuffer) {
70644
71378
  fontStyleBlock = `<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=${fontFamilies}&display=swap">`;
70645
71379
  }
70646
71380
  const slides = [];
71381
+ let masterBg;
71382
+ let masterDecorativeElements = [];
71383
+ const masterXml = await zip.file("ppt/slideMasters/slideMaster1.xml")?.async("text");
71384
+ if (masterXml) {
71385
+ const masterDoc = parser.parseFromString(masterXml, "application/xml");
71386
+ const masterBgEl = masterDoc.getElementsByTagName("p:bg")[0];
71387
+ if (masterBgEl) {
71388
+ masterBg = extractBgFill(masterBgEl, bgFillStyles, themeColors);
71389
+ }
71390
+ const masterImageMap = /* @__PURE__ */ new Map();
71391
+ const masterRelsXml = await zip.file("ppt/slideMasters/_rels/slideMaster1.xml.rels")?.async("text");
71392
+ if (masterRelsXml) {
71393
+ const relsDoc = parser.parseFromString(masterRelsXml, "application/xml");
71394
+ const rels = relsDoc.getElementsByTagName("Relationship");
71395
+ for (let ri = 0; ri < rels.length; ri++) {
71396
+ const rel = rels[ri];
71397
+ const type2 = rel.getAttribute("Type") ?? "";
71398
+ if (!type2.includes("/image")) continue;
71399
+ const rId = rel.getAttribute("Id");
71400
+ const target = rel.getAttribute("Target");
71401
+ if (!rId || !target) continue;
71402
+ const mediaPath = target.startsWith("../") ? "ppt/" + target.slice(3) : target;
71403
+ const imgFile = zip.file(mediaPath);
71404
+ if (!imgFile) continue;
71405
+ const imgData = await imgFile.async("base64");
71406
+ const ext = mediaPath.split(".").pop()?.toLowerCase() ?? "png";
71407
+ const mime = ext === "jpg" || ext === "jpeg" ? "image/jpeg" : ext === "svg" ? "image/svg+xml" : `image/${ext}`;
71408
+ masterImageMap.set(rId, `data:${mime};base64,${imgData}`);
71409
+ }
71410
+ }
71411
+ const masterSpTree = masterDoc.getElementsByTagName("p:spTree")[0];
71412
+ if (masterSpTree) {
71413
+ masterDecorativeElements = parseDecorativeShapes(masterSpTree, scale, themeColors, masterImageMap, themeFonts);
71414
+ }
71415
+ }
71416
+ const layoutCache = /* @__PURE__ */ new Map();
71417
+ async function getLayoutInfo(layoutPath) {
71418
+ if (layoutCache.has(layoutPath)) return layoutCache.get(layoutPath);
71419
+ const result = { bg: void 0, showMasterSp: true, decorativeElements: [] };
71420
+ const layoutXml = await zip.file(layoutPath)?.async("text");
71421
+ if (layoutXml) {
71422
+ const layoutDoc = parser.parseFromString(layoutXml, "application/xml");
71423
+ const cSld = layoutDoc.getElementsByTagName("p:cSld")[0];
71424
+ const rootEl = layoutDoc.documentElement;
71425
+ const showMasterSpAttr = rootEl.getAttribute("showMasterSp");
71426
+ if (showMasterSpAttr === "0") {
71427
+ result.showMasterSp = false;
71428
+ }
71429
+ const layoutBgEl = layoutDoc.getElementsByTagName("p:bg")[0];
71430
+ if (layoutBgEl) {
71431
+ result.bg = extractBgFill(layoutBgEl, bgFillStyles, themeColors);
71432
+ }
71433
+ const layoutImageMap = /* @__PURE__ */ new Map();
71434
+ const layoutBaseName = layoutPath.split("/").pop();
71435
+ const layoutRelsPath = layoutPath.replace(layoutBaseName, `_rels/${layoutBaseName}.rels`);
71436
+ const layoutRelsXml = await zip.file(layoutRelsPath)?.async("text");
71437
+ if (layoutRelsXml) {
71438
+ const relsDoc = parser.parseFromString(layoutRelsXml, "application/xml");
71439
+ const rels = relsDoc.getElementsByTagName("Relationship");
71440
+ for (let ri = 0; ri < rels.length; ri++) {
71441
+ const rel = rels[ri];
71442
+ const type2 = rel.getAttribute("Type") ?? "";
71443
+ if (!type2.includes("/image")) continue;
71444
+ const rId = rel.getAttribute("Id");
71445
+ const target = rel.getAttribute("Target");
71446
+ if (!rId || !target) continue;
71447
+ const mediaPath = target.startsWith("../") ? "ppt/" + target.slice(3) : target;
71448
+ const imgFile = zip.file(mediaPath);
71449
+ if (!imgFile) continue;
71450
+ const imgData = await imgFile.async("base64");
71451
+ const ext = mediaPath.split(".").pop()?.toLowerCase() ?? "png";
71452
+ const mime = ext === "jpg" || ext === "jpeg" ? "image/jpeg" : ext === "svg" ? "image/svg+xml" : `image/${ext}`;
71453
+ layoutImageMap.set(rId, `data:${mime};base64,${imgData}`);
71454
+ }
71455
+ }
71456
+ const layoutSpTree = layoutDoc.getElementsByTagName("p:spTree")[0];
71457
+ if (layoutSpTree) {
71458
+ result.decorativeElements = parseDecorativeShapes(layoutSpTree, scale, themeColors, layoutImageMap, themeFonts);
71459
+ }
71460
+ }
71461
+ layoutCache.set(layoutPath, result);
71462
+ return result;
71463
+ }
70647
71464
  for (const slideFile of slideFiles) {
70648
71465
  const slideXml = await zip.file(slideFile)?.async("text");
70649
71466
  if (!slideXml) continue;
@@ -70652,27 +71469,47 @@ async function importPptx(arrayBuffer) {
70652
71469
  let slideBg = void 0;
70653
71470
  const bgEl = slideDoc.getElementsByTagName("p:bg")[0];
70654
71471
  if (bgEl) {
70655
- const bgPr = findChild2(bgEl, "bgPr");
70656
- if (bgPr) {
70657
- slideBg = extractFill(bgPr, themeColors);
70658
- }
71472
+ slideBg = extractBgFill(bgEl, bgFillStyles, themeColors);
70659
71473
  }
70660
- if (!spTree) {
70661
- slides.push(renderSlideHtml([], slideBg));
70662
- continue;
70663
- }
70664
- const imageMap = /* @__PURE__ */ new Map();
70665
71474
  const slideBaseName = slideFile.split("/").pop();
70666
- const relsPath = slideFile.replace(
70667
- slideBaseName,
70668
- `_rels/${slideBaseName}.rels`
70669
- );
71475
+ const relsPath = slideFile.replace(slideBaseName, `_rels/${slideBaseName}.rels`);
70670
71476
  const relsXml = await zip.file(relsPath)?.async("text");
71477
+ let layoutPath;
70671
71478
  if (relsXml) {
70672
71479
  const relsDoc = parser.parseFromString(relsXml, "application/xml");
70673
71480
  const rels = relsDoc.getElementsByTagName("Relationship");
70674
- for (let i = 0; i < rels.length; i++) {
70675
- const rel = rels[i];
71481
+ for (let ri = 0; ri < rels.length; ri++) {
71482
+ const rel = rels[ri];
71483
+ const type2 = rel.getAttribute("Type") ?? "";
71484
+ if (type2.includes("/slideLayout")) {
71485
+ const target = rel.getAttribute("Target");
71486
+ if (target) {
71487
+ layoutPath = target.startsWith("../") ? "ppt/" + target.slice(3) : "ppt/slides/" + target;
71488
+ }
71489
+ break;
71490
+ }
71491
+ }
71492
+ }
71493
+ let layoutInfo;
71494
+ if (layoutPath) {
71495
+ layoutInfo = await getLayoutInfo(layoutPath);
71496
+ }
71497
+ if (!slideBg && layoutInfo?.bg) {
71498
+ slideBg = layoutInfo.bg;
71499
+ }
71500
+ if (!slideBg && masterBg) {
71501
+ slideBg = masterBg;
71502
+ }
71503
+ if (!spTree) {
71504
+ slides.push(renderSlideHtml([], slideBg, contentOffsetX));
71505
+ continue;
71506
+ }
71507
+ const imageMap = /* @__PURE__ */ new Map();
71508
+ const slideRelsDoc = relsXml ? parser.parseFromString(relsXml, "application/xml") : null;
71509
+ if (slideRelsDoc) {
71510
+ const rels = slideRelsDoc.getElementsByTagName("Relationship");
71511
+ for (let ri = 0; ri < rels.length; ri++) {
71512
+ const rel = rels[ri];
70676
71513
  const type2 = rel.getAttribute("Type") ?? "";
70677
71514
  if (!type2.includes("/image")) continue;
70678
71515
  const rId = rel.getAttribute("Id");
@@ -70688,6 +71525,12 @@ async function importPptx(arrayBuffer) {
70688
71525
  }
70689
71526
  }
70690
71527
  const elements = [];
71528
+ if (layoutInfo?.showMasterSp !== false) {
71529
+ elements.push(...masterDecorativeElements);
71530
+ }
71531
+ if (layoutInfo?.decorativeElements) {
71532
+ elements.push(...layoutInfo.decorativeElements);
71533
+ }
70691
71534
  for (let i = 0; i < spTree.children.length; i++) {
70692
71535
  const child = spTree.children[i];
70693
71536
  if (child.localName === "sp") {
@@ -70698,10 +71541,15 @@ async function importPptx(arrayBuffer) {
70698
71541
  if (img) elements.push({ kind: "image", data: img });
70699
71542
  } else if (child.localName === "graphicFrame") {
70700
71543
  const table = parseTable2(child, scale, themeColors, themeFonts, tableStyleMap);
70701
- if (table) elements.push({ kind: "table", data: table });
71544
+ if (table) {
71545
+ elements.push({ kind: "table", data: table });
71546
+ } else if (slideRelsDoc) {
71547
+ const chart = await parseChart(child, scale, themeColors, zip, slideRelsDoc, parser);
71548
+ if (chart) elements.push({ kind: "chart", data: chart });
71549
+ }
70702
71550
  }
70703
71551
  }
70704
- slides.push(renderSlideHtml(elements, slideBg));
71552
+ slides.push(renderSlideHtml(elements, slideBg, contentOffsetX));
70705
71553
  }
70706
71554
  if (fontStyleBlock && slides.length > 0) {
70707
71555
  slides[0] = fontStyleBlock + slides[0];
@@ -96278,6 +97126,28 @@ async function createDocxBuffer(html, options = {}) {
96278
97126
  return Packer.toBuffer(doc);
96279
97127
  }
96280
97128
 
97129
+ // packages/cli/commands/common.ts
97130
+ var userAgent = "Mozilla/5.0 (compatible; Copilot/1.0)";
97131
+ async function fetchWithProxy(url) {
97132
+ const proxyUrl = process.env.HTTPS_PROXY || process.env.HTTP_PROXY || process.env.https_proxy || process.env.http_proxy;
97133
+ if (proxyUrl) {
97134
+ const undici = await Promise.resolve().then(() => __toESM(require_undici(), 1));
97135
+ const agent = new undici.ProxyAgent(proxyUrl);
97136
+ const response = await undici.fetch(url, {
97137
+ dispatcher: agent,
97138
+ headers: {
97139
+ "User-Agent": userAgent
97140
+ }
97141
+ });
97142
+ return response;
97143
+ }
97144
+ return fetch(url, {
97145
+ headers: {
97146
+ "User-Agent": userAgent
97147
+ }
97148
+ });
97149
+ }
97150
+
96281
97151
  // packages/cli/commands/export-docs.ts
96282
97152
  function findAllImageElements(elements) {
96283
97153
  const images = [];
@@ -96309,12 +97179,7 @@ async function fetchExternalImages(elements) {
96309
97179
  for (const imgEl of externalImages) {
96310
97180
  try {
96311
97181
  const src = imgEl.src;
96312
- const response = await fetch(src, {
96313
- headers: {
96314
- // Some servers require a User-Agent
96315
- "User-Agent": "Mozilla/5.0 (compatible; DocxExporter/1.0)"
96316
- }
96317
- });
97182
+ const response = await fetchWithProxy(src);
96318
97183
  if (!response.ok) {
96319
97184
  console.warn(`Failed to fetch image: ${src} (${response.status})`);
96320
97185
  continue;
@@ -96598,25 +97463,6 @@ import { fileURLToPath } from "node:url";
96598
97463
  import { chromium as chromium2 } from "playwright";
96599
97464
  var __filename2 = fileURLToPath(import.meta.url);
96600
97465
  var __dirname = path4.dirname(__filename2);
96601
- async function fetchWithProxy(url) {
96602
- const proxyUrl = process.env.HTTPS_PROXY || process.env.HTTP_PROXY || process.env.https_proxy || process.env.http_proxy;
96603
- if (proxyUrl) {
96604
- const undici = await Promise.resolve().then(() => __toESM(require_undici(), 1));
96605
- const agent = new undici.ProxyAgent(proxyUrl);
96606
- const response = await undici.fetch(url, {
96607
- dispatcher: agent,
96608
- headers: {
96609
- "User-Agent": "Mozilla/5.0 (compatible; DocGen/1.0)"
96610
- }
96611
- });
96612
- return response;
96613
- }
96614
- return fetch(url, {
96615
- headers: {
96616
- "User-Agent": "Mozilla/5.0 (compatible; DocGen/1.0)"
96617
- }
96618
- });
96619
- }
96620
97466
  async function embedExternalImages(html) {
96621
97467
  const imgRegex = /<img\s+([^>]*?)src="(https?:\/\/[^"]+)"([^>]*)>/gi;
96622
97468
  const matches2 = [...html.matchAll(imgRegex)];