docgen-utils 1.0.13 → 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.
Files changed (38) hide show
  1. package/dist/bundle.js +994 -38
  2. package/dist/bundle.min.js +94 -89
  3. package/dist/cli.js +24908 -119
  4. package/dist/packages/cli/commands/common.d.ts +2 -0
  5. package/dist/packages/cli/commands/common.d.ts.map +1 -0
  6. package/dist/packages/cli/commands/common.js +22 -0
  7. package/dist/packages/cli/commands/common.js.map +1 -0
  8. package/dist/packages/cli/commands/export-docs.d.ts +10 -1
  9. package/dist/packages/cli/commands/export-docs.d.ts.map +1 -1
  10. package/dist/packages/cli/commands/export-docs.js +258 -44
  11. package/dist/packages/cli/commands/export-docs.js.map +1 -1
  12. package/dist/packages/cli/commands/export-slides.d.ts +1 -1
  13. package/dist/packages/cli/commands/export-slides.d.ts.map +1 -1
  14. package/dist/packages/cli/commands/export-slides.js +58 -25
  15. package/dist/packages/cli/commands/export-slides.js.map +1 -1
  16. package/dist/packages/cli/commands/import-docx.d.ts +1 -1
  17. package/dist/packages/cli/commands/import-docx.d.ts.map +1 -1
  18. package/dist/packages/cli/commands/import-docx.js +3 -3
  19. package/dist/packages/cli/commands/import-docx.js.map +1 -1
  20. package/dist/packages/cli/commands/import-pptx.d.ts +1 -1
  21. package/dist/packages/cli/commands/import-pptx.d.ts.map +1 -1
  22. package/dist/packages/cli/commands/import-pptx.js +2 -2
  23. package/dist/packages/cli/commands/import-pptx.js.map +1 -1
  24. package/dist/packages/cli/index.js +14 -8
  25. package/dist/packages/cli/index.js.map +1 -1
  26. package/dist/packages/docs/parse-helpers.d.ts.map +1 -1
  27. package/dist/packages/docs/parse-helpers.js +7 -1
  28. package/dist/packages/docs/parse-helpers.js.map +1 -1
  29. package/dist/packages/slides/createPresentation.d.ts.map +1 -1
  30. package/dist/packages/slides/createPresentation.js +20 -0
  31. package/dist/packages/slides/createPresentation.js.map +1 -1
  32. package/dist/packages/slides/import-pptx.d.ts.map +1 -1
  33. package/dist/packages/slides/import-pptx.js +1180 -47
  34. package/dist/packages/slides/import-pptx.js.map +1 -1
  35. package/dist/packages/slides/transform.d.ts.map +1 -1
  36. package/dist/packages/slides/transform.js +45 -0
  37. package/dist/packages/slides/transform.js.map +1 -1
  38. package/package.json +3 -2
package/dist/bundle.js CHANGED
@@ -48969,7 +48969,9 @@ var docgen = (() => {
48969
48969
  }
48970
48970
  const cssBorder = styles.border || "";
48971
48971
  const hasCssBorder = cssBorder.includes("solid") || cssBorder.includes("px");
48972
- const hasBackground = !!styles.backgroundColor && styles.backgroundColor !== "transparent" && styles.backgroundColor !== "inherit";
48972
+ const bgColor = styles.backgroundColor?.toLowerCase() || "";
48973
+ const isWhiteBackground = bgColor === "#ffffff" || bgColor === "#fff" || bgColor === "white" || bgColor === "rgb(255, 255, 255)" || bgColor === "rgba(255, 255, 255, 1)";
48974
+ const hasBackground = !!styles.backgroundColor && styles.backgroundColor !== "transparent" && styles.backgroundColor !== "inherit" && !isWhiteBackground;
48973
48975
  if (hasBackground && (hasBorderLeft || hasCssBorder)) {
48974
48976
  return true;
48975
48977
  }
@@ -67530,6 +67532,23 @@ ${generateStylesCss(styleMap, themeFonts)}
67530
67532
  // 3s timeout for slow CDN
67531
67533
  ]);
67532
67534
  }
67535
+ const images = doc.querySelectorAll("img");
67536
+ if (images.length > 0) {
67537
+ const imagePromises = Array.from(images).map((img) => {
67538
+ if (img.complete && img.naturalWidth > 0) {
67539
+ return Promise.resolve();
67540
+ }
67541
+ return new Promise((resolve) => {
67542
+ img.onload = () => resolve();
67543
+ img.onerror = () => resolve();
67544
+ });
67545
+ });
67546
+ await Promise.race([
67547
+ Promise.all(imagePromises),
67548
+ new Promise((r) => setTimeout(r, 5e3))
67549
+ // 5s timeout for slow images
67550
+ ]);
67551
+ }
67533
67552
  return { iframe, doc };
67534
67553
  }
67535
67554
  async function addSlideFromHtml(source, pres, options = {}) {
@@ -67737,6 +67756,32 @@ ${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join("\n")}`;
67737
67756
  html = html.replace(/<\/style>/i, `body { width: ${targetWidth}pt; height: ${targetHeight}pt; overflow: hidden; margin: 0; }
67738
67757
  </style>`);
67739
67758
  }
67759
+ const maskImagePattern = /mask-image|--webkit-mask-image/i;
67760
+ const cssRules = html.match(/<style[^>]*>([\s\S]*?)<\/style>/gi) || [];
67761
+ const classesWithMask = /* @__PURE__ */ new Set();
67762
+ for (const styleBlock of cssRules) {
67763
+ const classMatches = styleBlock.matchAll(/\.([a-zA-Z_][\w-]*)\s*\{[^}]*mask-image[^}]*\}/gi);
67764
+ for (const m of classMatches) {
67765
+ classesWithMask.add(m[1]);
67766
+ }
67767
+ }
67768
+ html = html.replace(/<img\s+([^>]*?)src="(https?:\/\/[^"]+)"([^>]*)>/gi, (match, before2, url, after2) => {
67769
+ if (/crossorigin\s*=/i.test(before2 + after2)) {
67770
+ return match;
67771
+ }
67772
+ const fullAttrs = before2 + after2;
67773
+ const hasInlineMask = maskImagePattern.test(fullAttrs);
67774
+ let hasClassMask = false;
67775
+ const classMatch = fullAttrs.match(/class\s*=\s*["']([^"']+)["']/i);
67776
+ if (classMatch) {
67777
+ const classes = classMatch[1].split(/\s+/);
67778
+ hasClassMask = classes.some((c) => classesWithMask.has(c));
67779
+ }
67780
+ if (hasInlineMask || hasClassMask) {
67781
+ return `<img ${before2}src="${url}"${after2} crossorigin="anonymous">`;
67782
+ }
67783
+ return match;
67784
+ });
67740
67785
  return html;
67741
67786
  }
67742
67787
 
@@ -67802,28 +67847,62 @@ ${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join("\n")}`;
67802
67847
  const a = Math.round(alpha100k / 1e5 * 100) / 100;
67803
67848
  return `rgba(${r},${g},${b},${a})`;
67804
67849
  }
67850
+ function applyTint(hex, tintVal) {
67851
+ const factor = tintVal / 1e5;
67852
+ const r = parseInt(hex.slice(1, 3), 16);
67853
+ const g = parseInt(hex.slice(3, 5), 16);
67854
+ const b = parseInt(hex.slice(5, 7), 16);
67855
+ const nr = Math.round(r + (255 - r) * (1 - factor));
67856
+ const ng = Math.round(g + (255 - g) * (1 - factor));
67857
+ const nb = Math.round(b + (255 - b) * (1 - factor));
67858
+ return `#${nr.toString(16).padStart(2, "0")}${ng.toString(16).padStart(2, "0")}${nb.toString(16).padStart(2, "0")}`;
67859
+ }
67860
+ function applyShade(hex, shadeVal) {
67861
+ const factor = shadeVal / 1e5;
67862
+ const r = Math.round(parseInt(hex.slice(1, 3), 16) * factor);
67863
+ const g = Math.round(parseInt(hex.slice(3, 5), 16) * factor);
67864
+ const b = Math.round(parseInt(hex.slice(5, 7), 16) * factor);
67865
+ return `#${r.toString(16).padStart(2, "0")}${g.toString(16).padStart(2, "0")}${b.toString(16).padStart(2, "0")}`;
67866
+ }
67867
+ function applyColorModifiers(colorEl, hex) {
67868
+ let color = hex;
67869
+ let alphaVal;
67870
+ const tintEl = findChild2(colorEl, "tint");
67871
+ if (tintEl) {
67872
+ const val = parseInt(tintEl.getAttribute("val") ?? "100000", 10);
67873
+ color = applyTint(color, val);
67874
+ }
67875
+ const shadeEl = findChild2(colorEl, "shade");
67876
+ if (shadeEl) {
67877
+ const val = parseInt(shadeEl.getAttribute("val") ?? "100000", 10);
67878
+ color = applyShade(color, val);
67879
+ }
67880
+ const alphaEl = findChild2(colorEl, "alpha");
67881
+ if (alphaEl) {
67882
+ alphaVal = parseInt(alphaEl.getAttribute("val") ?? "100000", 10);
67883
+ }
67884
+ return { color, alpha: alphaVal };
67885
+ }
67805
67886
  function resolveColor2(parent, themeColors) {
67806
67887
  const srgbClr = findChild2(parent, "srgbClr");
67807
67888
  if (srgbClr) {
67808
67889
  const hex = "#" + (srgbClr.getAttribute("val") ?? "000000");
67809
- const alphaEl = findChild2(srgbClr, "alpha");
67810
- if (alphaEl) {
67811
- const alphaVal = parseInt(alphaEl.getAttribute("val") ?? "100000", 10);
67812
- return hexToRgba(hex, alphaVal);
67890
+ const { color, alpha } = applyColorModifiers(srgbClr, hex);
67891
+ if (alpha !== void 0 && alpha < 1e5) {
67892
+ return hexToRgba(color, alpha);
67813
67893
  }
67814
- return hex;
67894
+ return color;
67815
67895
  }
67816
67896
  const schemeClr = findChild2(parent, "schemeClr");
67817
67897
  if (schemeClr) {
67818
67898
  const val = schemeClr.getAttribute("val");
67819
67899
  if (val && themeColors.has(val)) {
67820
67900
  const hex = themeColors.get(val);
67821
- const alphaEl = findChild2(schemeClr, "alpha");
67822
- if (alphaEl) {
67823
- const alphaVal = parseInt(alphaEl.getAttribute("val") ?? "100000", 10);
67824
- return hexToRgba(hex, alphaVal);
67901
+ const { color, alpha } = applyColorModifiers(schemeClr, hex);
67902
+ if (alpha !== void 0 && alpha < 1e5) {
67903
+ return hexToRgba(color, alpha);
67825
67904
  }
67826
- return hex;
67905
+ return color;
67827
67906
  }
67828
67907
  }
67829
67908
  return void 0;
@@ -67874,6 +67953,158 @@ ${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join("\n")}`;
67874
67953
  return resolveColor2(solidFill, themeColors);
67875
67954
  return extractGradientFill(spPr, themeColors);
67876
67955
  }
67956
+ function resolveBgRef(bgRef, bgFillStyles, themeColors) {
67957
+ const idx = parseInt(bgRef.getAttribute("idx") ?? "0", 10);
67958
+ if (idx < 1001 || bgFillStyles.length === 0)
67959
+ return void 0;
67960
+ const styleIdx = idx - 1001;
67961
+ if (styleIdx >= bgFillStyles.length)
67962
+ return void 0;
67963
+ const fillStyle = bgFillStyles[styleIdx];
67964
+ const phColor = resolveColor2(bgRef, themeColors);
67965
+ if (fillStyle.localName === "solidFill") {
67966
+ const phClr = findChild2(fillStyle, "schemeClr");
67967
+ if (phClr?.getAttribute("val") === "phClr" && phColor) {
67968
+ return phColor;
67969
+ }
67970
+ return resolveColor2(fillStyle, themeColors) ?? phColor;
67971
+ }
67972
+ if (fillStyle.localName === "gradFill") {
67973
+ return extractGradientFill(
67974
+ // Wrap in a parent element for extractGradientFill
67975
+ { children: [fillStyle] },
67976
+ themeColors
67977
+ );
67978
+ }
67979
+ return phColor;
67980
+ }
67981
+ function extractBgFill(bgEl, bgFillStyles, themeColors) {
67982
+ const bgPr = findChild2(bgEl, "bgPr");
67983
+ if (bgPr) {
67984
+ return extractFill(bgPr, themeColors);
67985
+ }
67986
+ const bgRef = findChild2(bgEl, "bgRef");
67987
+ if (bgRef) {
67988
+ return resolveBgRef(bgRef, bgFillStyles, themeColors);
67989
+ }
67990
+ return void 0;
67991
+ }
67992
+ function extractCustGeomClipPath(custGeom) {
67993
+ const pathLst = findChild2(custGeom, "pathLst");
67994
+ if (!pathLst)
67995
+ return void 0;
67996
+ const pathEl = findChild2(pathLst, "path");
67997
+ if (!pathEl)
67998
+ return void 0;
67999
+ const pathW = parseInt(pathEl.getAttribute("w") ?? "0", 10);
68000
+ const pathH = parseInt(pathEl.getAttribute("h") ?? "0", 10);
68001
+ if (pathW <= 0 || pathH <= 0)
68002
+ return void 0;
68003
+ const points = [];
68004
+ for (let i = 0; i < pathEl.children.length; i++) {
68005
+ const cmd = pathEl.children[i];
68006
+ const localName = cmd.localName;
68007
+ if (localName === "moveTo" || localName === "lnTo") {
68008
+ const pt = findChild2(cmd, "pt");
68009
+ if (pt) {
68010
+ const x = parseInt(pt.getAttribute("x") ?? "0", 10);
68011
+ const y = parseInt(pt.getAttribute("y") ?? "0", 10);
68012
+ points.push({ x, y });
68013
+ }
68014
+ } else if (localName === "close") {
68015
+ } else {
68016
+ return void 0;
68017
+ }
68018
+ }
68019
+ if (points.length < 3)
68020
+ return void 0;
68021
+ const polygonPoints = points.map((p) => {
68022
+ const xPct = Math.round(p.x / pathW * 1e4) / 100;
68023
+ const yPct = Math.round(p.y / pathH * 1e4) / 100;
68024
+ return `${xPct}% ${yPct}%`;
68025
+ }).join(", ");
68026
+ return `polygon(${polygonPoints})`;
68027
+ }
68028
+ function parseDecorativeShapes(spTree, scale, themeColors, imageMap, themeFonts) {
68029
+ const elements = [];
68030
+ for (let i = 0; i < spTree.children.length; i++) {
68031
+ const child = spTree.children[i];
68032
+ if (child.localName === "sp") {
68033
+ const nvSpPr = findChild2(child, "nvSpPr");
68034
+ if (nvSpPr) {
68035
+ const phEl = findChild2(findChild2(nvSpPr, "nvPr") ?? nvSpPr, "ph");
68036
+ if (phEl)
68037
+ continue;
68038
+ }
68039
+ const spPr = findChild2(child, "spPr");
68040
+ if (spPr) {
68041
+ const custGeom = findChild2(spPr, "custGeom");
68042
+ if (custGeom) {
68043
+ const clipPath = extractCustGeomClipPath(custGeom);
68044
+ if (!clipPath)
68045
+ continue;
68046
+ const shape2 = parseShape(child, scale, themeColors, themeFonts);
68047
+ if (shape2) {
68048
+ shape2.clipPath = clipPath;
68049
+ elements.push({ kind: "shape", data: shape2 });
68050
+ }
68051
+ continue;
68052
+ }
68053
+ }
68054
+ const shape = parseShape(child, scale, themeColors, themeFonts);
68055
+ if (shape)
68056
+ elements.push({ kind: "shape", data: shape });
68057
+ } else if (child.localName === "pic") {
68058
+ const img = parsePicture(child, scale, imageMap);
68059
+ if (img)
68060
+ elements.push({ kind: "image", data: img });
68061
+ } else if (child.localName === "grpSp") {
68062
+ const grpElements = parseGroupShape(child, scale, themeColors, imageMap, themeFonts);
68063
+ elements.push(...grpElements);
68064
+ }
68065
+ }
68066
+ return elements;
68067
+ }
68068
+ function parseGroupShape(grpSp, scale, themeColors, imageMap, themeFonts) {
68069
+ const elements = [];
68070
+ for (let i = 0; i < grpSp.children.length; i++) {
68071
+ const child = grpSp.children[i];
68072
+ if (child.localName === "sp") {
68073
+ const nvSpPr = findChild2(child, "nvSpPr");
68074
+ if (nvSpPr) {
68075
+ const phEl = findChild2(findChild2(nvSpPr, "nvPr") ?? nvSpPr, "ph");
68076
+ if (phEl)
68077
+ continue;
68078
+ }
68079
+ const spPr = findChild2(child, "spPr");
68080
+ if (spPr) {
68081
+ const custGeom = findChild2(spPr, "custGeom");
68082
+ if (custGeom) {
68083
+ const clipPath = extractCustGeomClipPath(custGeom);
68084
+ if (!clipPath)
68085
+ continue;
68086
+ const shape2 = parseShape(child, scale, themeColors, themeFonts);
68087
+ if (shape2) {
68088
+ shape2.clipPath = clipPath;
68089
+ elements.push({ kind: "shape", data: shape2 });
68090
+ }
68091
+ continue;
68092
+ }
68093
+ }
68094
+ const shape = parseShape(child, scale, themeColors, themeFonts);
68095
+ if (shape)
68096
+ elements.push({ kind: "shape", data: shape });
68097
+ } else if (child.localName === "pic") {
68098
+ const img = parsePicture(child, scale, imageMap);
68099
+ if (img)
68100
+ elements.push({ kind: "image", data: img });
68101
+ } else if (child.localName === "grpSp") {
68102
+ const nested = parseGroupShape(child, scale, themeColors, imageMap, themeFonts);
68103
+ elements.push(...nested);
68104
+ }
68105
+ }
68106
+ return elements;
68107
+ }
67877
68108
  function extractRunProps(rPr, scale, themeColors, themeFonts) {
67878
68109
  if (!rPr)
67879
68110
  return {};
@@ -67887,6 +68118,9 @@ ${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join("\n")}`;
67887
68118
  const i = rPr.getAttribute("i");
67888
68119
  if (i === "1" || i === "true")
67889
68120
  result.italic = true;
68121
+ const u = rPr.getAttribute("u");
68122
+ if (u && u !== "none")
68123
+ result.underline = true;
67890
68124
  const solidFill = findChild2(rPr, "solidFill");
67891
68125
  if (solidFill) {
67892
68126
  const color = resolveColor2(solidFill, themeColors);
@@ -67993,14 +68227,33 @@ ${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join("\n")}`;
67993
68227
  return null;
67994
68228
  const wEmu = parseInt(ext.getAttribute("cx") ?? "0", 10);
67995
68229
  const hEmu = parseInt(ext.getAttribute("cy") ?? "0", 10);
68230
+ let fill = extractFill(spPr, themeColors);
68231
+ if (!fill && !findChild2(spPr, "noFill")) {
68232
+ const styleEl = findChild2(sp, "style");
68233
+ if (styleEl) {
68234
+ const fillRef = findChild2(styleEl, "fillRef");
68235
+ if (fillRef) {
68236
+ const fillIdx = parseInt(fillRef.getAttribute("idx") ?? "0", 10);
68237
+ if (fillIdx > 0) {
68238
+ fill = resolveColor2(fillRef, themeColors) ?? void 0;
68239
+ }
68240
+ }
68241
+ }
68242
+ }
67996
68243
  const shape = {
67997
68244
  x: Math.round(emuToPx2(parseInt(off.getAttribute("x") ?? "0", 10)) * scale),
67998
68245
  y: Math.round(emuToPx2(parseInt(off.getAttribute("y") ?? "0", 10)) * scale),
67999
68246
  w: Math.round(emuToPx2(wEmu) * scale),
68000
68247
  h: Math.round(emuToPx2(hEmu) * scale),
68001
- fill: extractFill(spPr, themeColors),
68248
+ fill,
68002
68249
  paragraphs: []
68003
68250
  };
68251
+ const rotAttr = xfrm.getAttribute("rot");
68252
+ if (rotAttr) {
68253
+ const rotDeg = parseInt(rotAttr, 10) / 6e4;
68254
+ if (rotDeg !== 0)
68255
+ shape.rotation = rotDeg;
68256
+ }
68004
68257
  const prstGeom = findChild2(spPr, "prstGeom");
68005
68258
  const prstType = prstGeom?.getAttribute("prst");
68006
68259
  if (prstType === "roundRect" && prstGeom) {
@@ -68012,6 +68265,10 @@ ${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join("\n")}`;
68012
68265
  shape.borderRadius = Math.round(emuToPx2(radiusEmu) * scale);
68013
68266
  } else if (prstType === "ellipse") {
68014
68267
  shape.isEllipse = true;
68268
+ } else if (prstType === "rtTriangle") {
68269
+ shape.clipPath = "polygon(0 0, 0 100%, 100% 100%)";
68270
+ } else if (prstType === "triangle" || prstType === "isoTriangle") {
68271
+ shape.clipPath = "polygon(50% 0, 0 100%, 100% 100%)";
68015
68272
  }
68016
68273
  const ln = findChild2(spPr, "ln");
68017
68274
  if (ln) {
@@ -68106,6 +68363,10 @@ ${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join("\n")}`;
68106
68363
  if (buChar) {
68107
68364
  para.bulletChar = buChar.getAttribute("char") ?? void 0;
68108
68365
  }
68366
+ const buFont = findChild2(pPr, "buFont");
68367
+ if (buFont) {
68368
+ para.bulletFont = buFont.getAttribute("typeface") ?? void 0;
68369
+ }
68109
68370
  const buClr = findChild2(pPr, "buClr");
68110
68371
  if (buClr) {
68111
68372
  para.bulletColor = resolveColor2(buClr, themeColors);
@@ -68126,6 +68387,7 @@ ${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join("\n")}`;
68126
68387
  text,
68127
68388
  bold: props.bold ?? defaults?.bold,
68128
68389
  italic: props.italic ?? defaults?.italic,
68390
+ underline: props.underline ?? defaults?.underline,
68129
68391
  fontSize: props.fontSize ?? defaults?.fontSize,
68130
68392
  color: props.color ?? defaults?.color,
68131
68393
  fontFamily: props.fontFamily ?? defaults?.fontFamily,
@@ -68196,12 +68458,16 @@ ${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join("\n")}`;
68196
68458
  const alt = cNvPr?.getAttribute("descr") ?? void 0;
68197
68459
  const srcRect = findChild2(blipFill, "srcRect");
68198
68460
  let hasCrop = false;
68461
+ let cropLeft = 0;
68462
+ let cropTop = 0;
68463
+ let cropRight = 0;
68464
+ let cropBottom = 0;
68199
68465
  if (srcRect) {
68200
- const l = parseInt(srcRect.getAttribute("l") ?? "0", 10);
68201
- const r = parseInt(srcRect.getAttribute("r") ?? "0", 10);
68202
- const t = parseInt(srcRect.getAttribute("t") ?? "0", 10);
68203
- const b = parseInt(srcRect.getAttribute("b") ?? "0", 10);
68204
- hasCrop = l > 0 || r > 0 || t > 0 || b > 0;
68466
+ cropLeft = parseInt(srcRect.getAttribute("l") ?? "0", 10) / 1e3;
68467
+ cropRight = parseInt(srcRect.getAttribute("r") ?? "0", 10) / 1e3;
68468
+ cropTop = parseInt(srcRect.getAttribute("t") ?? "0", 10) / 1e3;
68469
+ cropBottom = parseInt(srcRect.getAttribute("b") ?? "0", 10) / 1e3;
68470
+ hasCrop = cropLeft > 0 || cropRight > 0 || cropTop > 0 || cropBottom > 0;
68205
68471
  }
68206
68472
  let borderRadius;
68207
68473
  const prstGeom = findChild2(spPr, "prstGeom");
@@ -68215,6 +68481,13 @@ ${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join("\n")}`;
68215
68481
  const radiusEmu = minDim * Math.min(adjVal, 5e4) / 1e5;
68216
68482
  borderRadius = Math.round(emuToPx2(radiusEmu) * scale);
68217
68483
  }
68484
+ let rotation;
68485
+ const rotAttr = xfrm.getAttribute("rot");
68486
+ if (rotAttr) {
68487
+ const rotDeg = parseInt(rotAttr, 10) / 6e4;
68488
+ if (rotDeg !== 0)
68489
+ rotation = rotDeg;
68490
+ }
68218
68491
  return {
68219
68492
  x: Math.round(emuToPx2(parseInt(off.getAttribute("x") ?? "0", 10)) * scale),
68220
68493
  y: Math.round(emuToPx2(parseInt(off.getAttribute("y") ?? "0", 10)) * scale),
@@ -68223,7 +68496,12 @@ ${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join("\n")}`;
68223
68496
  dataUri,
68224
68497
  alt,
68225
68498
  borderRadius,
68226
- hasCrop
68499
+ hasCrop,
68500
+ cropLeft: hasCrop ? cropLeft : void 0,
68501
+ cropTop: hasCrop ? cropTop : void 0,
68502
+ cropRight: hasCrop ? cropRight : void 0,
68503
+ cropBottom: hasCrop ? cropBottom : void 0,
68504
+ rotation
68227
68505
  };
68228
68506
  }
68229
68507
  async function parseTableStyles(zip, parser, themeColors) {
@@ -68351,6 +68629,10 @@ ${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join("\n")}`;
68351
68629
  if (buChar) {
68352
68630
  para.bulletChar = buChar.getAttribute("char") ?? void 0;
68353
68631
  }
68632
+ const buFont = findChild2(pPr, "buFont");
68633
+ if (buFont) {
68634
+ para.bulletFont = buFont.getAttribute("typeface") ?? void 0;
68635
+ }
68354
68636
  const buClr = findChild2(pPr, "buClr");
68355
68637
  if (buClr) {
68356
68638
  para.bulletColor = resolveColor2(buClr, themeColors);
@@ -68371,6 +68653,7 @@ ${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join("\n")}`;
68371
68653
  text,
68372
68654
  bold: props.bold ?? defaults?.bold,
68373
68655
  italic: props.italic ?? defaults?.italic,
68656
+ underline: props.underline ?? defaults?.underline,
68374
68657
  fontSize: props.fontSize ?? defaults?.fontSize,
68375
68658
  color: props.color ?? defaults?.color,
68376
68659
  fontFamily: props.fontFamily ?? defaults?.fontFamily,
@@ -68528,15 +68811,523 @@ ${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join("\n")}`;
68528
68811
  }
68529
68812
  return table;
68530
68813
  }
68531
- function renderSlideHtml(elements, bgColor) {
68814
+ function resolveChartColor(parent, themeColors) {
68815
+ const solidFill = findChild2(parent, "solidFill");
68816
+ if (!solidFill)
68817
+ return void 0;
68818
+ return resolveColor2(solidFill, themeColors);
68819
+ }
68820
+ function parseChartRichText(richEl) {
68821
+ const paragraphs = findChildren2(richEl, "p");
68822
+ let text = "";
68823
+ let font;
68824
+ let color;
68825
+ let size;
68826
+ for (const p of paragraphs) {
68827
+ const runs = findChildren2(p, "r");
68828
+ for (const r of runs) {
68829
+ const tEl = findChild2(r, "t");
68830
+ if (tEl?.textContent)
68831
+ text += tEl.textContent;
68832
+ if (font === void 0) {
68833
+ const rPr = findChild2(r, "rPr");
68834
+ if (rPr) {
68835
+ const szAttr = rPr.getAttribute("sz");
68836
+ if (szAttr)
68837
+ size = hptToPx(parseInt(szAttr, 10));
68838
+ const latin = findChild2(rPr, "latin");
68839
+ if (latin)
68840
+ font = latin.getAttribute("typeface") ?? void 0;
68841
+ const fill = findChild2(rPr, "solidFill");
68842
+ if (fill) {
68843
+ const srgb = findChild2(fill, "srgbClr");
68844
+ if (srgb)
68845
+ color = "#" + (srgb.getAttribute("val") ?? "000000");
68846
+ }
68847
+ }
68848
+ }
68849
+ }
68850
+ }
68851
+ return { text, font, color, size };
68852
+ }
68853
+ function parseChartAxis(axEl, themeColors) {
68854
+ const axis = {
68855
+ position: "b"
68856
+ };
68857
+ const axPos = findChild2(axEl, "axPos");
68858
+ if (axPos) {
68859
+ const val = axPos.getAttribute("val");
68860
+ if (val === "b" || val === "l" || val === "r" || val === "t") {
68861
+ axis.position = val;
68862
+ }
68863
+ }
68864
+ const titleEl = findChild2(axEl, "title");
68865
+ if (titleEl) {
68866
+ const tx = findChild2(titleEl, "tx");
68867
+ if (tx) {
68868
+ const rich = findChild2(tx, "rich");
68869
+ if (rich) {
68870
+ const parsed = parseChartRichText(rich);
68871
+ axis.title = parsed.text;
68872
+ }
68873
+ }
68874
+ }
68875
+ const numFmt = findChild2(axEl, "numFmt");
68876
+ if (numFmt) {
68877
+ const fmt = numFmt.getAttribute("formatCode");
68878
+ if (fmt)
68879
+ axis.numFormat = fmt;
68880
+ }
68881
+ const txPr = findChild2(axEl, "txPr");
68882
+ if (txPr) {
68883
+ const pEls = findChildren2(txPr, "p");
68884
+ for (const p of pEls) {
68885
+ const pPr = findChild2(p, "pPr");
68886
+ if (pPr) {
68887
+ const defRPr = findChild2(pPr, "defRPr");
68888
+ if (defRPr) {
68889
+ const szAttr = defRPr.getAttribute("sz");
68890
+ if (szAttr)
68891
+ axis.labelSize = hptToPx(parseInt(szAttr, 10));
68892
+ const latin = findChild2(defRPr, "latin");
68893
+ if (latin)
68894
+ axis.labelFont = latin.getAttribute("typeface") ?? void 0;
68895
+ const fill = findChild2(defRPr, "solidFill");
68896
+ if (fill) {
68897
+ const srgb = findChild2(fill, "srgbClr");
68898
+ if (srgb)
68899
+ axis.labelColor = "#" + (srgb.getAttribute("val") ?? "000000");
68900
+ }
68901
+ }
68902
+ }
68903
+ }
68904
+ }
68905
+ const gridlines = findChild2(axEl, "majorGridlines");
68906
+ if (gridlines) {
68907
+ const spPr = findChild2(gridlines, "spPr");
68908
+ if (spPr) {
68909
+ const ln = findChild2(spPr, "ln");
68910
+ if (ln) {
68911
+ const fill = findChild2(ln, "solidFill");
68912
+ if (fill) {
68913
+ const srgb = findChild2(fill, "srgbClr");
68914
+ if (srgb) {
68915
+ axis.gridlineColor = "#" + (srgb.getAttribute("val") ?? "CCCCCC");
68916
+ const alphaEl = findChild2(srgb, "alpha");
68917
+ if (alphaEl) {
68918
+ axis.gridlineAlpha = parseInt(alphaEl.getAttribute("val") ?? "100000", 10) / 1e3;
68919
+ }
68920
+ }
68921
+ }
68922
+ }
68923
+ }
68924
+ }
68925
+ const scaling = findChild2(axEl, "scaling");
68926
+ if (scaling) {
68927
+ const minEl = findChild2(scaling, "min");
68928
+ if (minEl) {
68929
+ const val = minEl.getAttribute("val");
68930
+ if (val)
68931
+ axis.min = parseFloat(val);
68932
+ }
68933
+ }
68934
+ return axis;
68935
+ }
68936
+ async function parseChart(graphicFrame, scale, themeColors, zip, slideRelsDoc, parser) {
68937
+ const xfrm = findChild2(graphicFrame, "xfrm");
68938
+ if (!xfrm)
68939
+ return null;
68940
+ const off = findChild2(xfrm, "off");
68941
+ const ext = findChild2(xfrm, "ext");
68942
+ if (!off || !ext)
68943
+ return null;
68944
+ const graphic = findChild2(graphicFrame, "graphic");
68945
+ if (!graphic)
68946
+ return null;
68947
+ const graphicData = findChild2(graphic, "graphicData");
68948
+ if (!graphicData)
68949
+ return null;
68950
+ const uri2 = graphicData.getAttribute("uri") ?? "";
68951
+ if (!uri2.includes("chart"))
68952
+ return null;
68953
+ let chartRId;
68954
+ for (let i = 0; i < graphicData.children.length; i++) {
68955
+ const child = graphicData.children[i];
68956
+ if (child.localName === "chart") {
68957
+ chartRId = child.getAttribute("r:id") ?? child.getAttributeNS("http://schemas.openxmlformats.org/officeDocument/2006/relationships", "id") ?? void 0;
68958
+ break;
68959
+ }
68960
+ }
68961
+ if (!chartRId)
68962
+ return null;
68963
+ let chartTarget;
68964
+ const rels = slideRelsDoc.getElementsByTagName("Relationship");
68965
+ for (let ri = 0; ri < rels.length; ri++) {
68966
+ const rel = rels[ri];
68967
+ if (rel.getAttribute("Id") === chartRId) {
68968
+ chartTarget = rel.getAttribute("Target") ?? void 0;
68969
+ break;
68970
+ }
68971
+ }
68972
+ if (!chartTarget)
68973
+ return null;
68974
+ const chartPath = chartTarget.startsWith("../") ? "ppt/" + chartTarget.slice(3) : chartTarget;
68975
+ const chartXml = await zip.file(chartPath)?.async("text");
68976
+ if (!chartXml)
68977
+ return null;
68978
+ const chartDoc = parser.parseFromString(chartXml, "application/xml");
68979
+ const chartSpace = chartDoc.documentElement;
68980
+ const x = Math.round(emuToPx2(parseInt(off.getAttribute("x") ?? "0", 10)) * scale);
68981
+ const y = Math.round(emuToPx2(parseInt(off.getAttribute("y") ?? "0", 10)) * scale);
68982
+ const w = Math.round(emuToPx2(parseInt(ext.getAttribute("cx") ?? "0", 10)) * scale);
68983
+ const h = Math.round(emuToPx2(parseInt(ext.getAttribute("cy") ?? "0", 10)) * scale);
68984
+ const chartEl = findChild2(chartSpace, "chart");
68985
+ if (!chartEl)
68986
+ return null;
68987
+ let title;
68988
+ let titleFont;
68989
+ let titleColor;
68990
+ let titleSize;
68991
+ const titleEl = findChild2(chartEl, "title");
68992
+ if (titleEl) {
68993
+ const tx = findChild2(titleEl, "tx");
68994
+ if (tx) {
68995
+ const rich = findChild2(tx, "rich");
68996
+ if (rich) {
68997
+ const parsed = parseChartRichText(rich);
68998
+ title = parsed.text;
68999
+ titleFont = parsed.font;
69000
+ titleColor = parsed.color;
69001
+ titleSize = parsed.size;
69002
+ }
69003
+ }
69004
+ }
69005
+ const plotArea = findChild2(chartEl, "plotArea");
69006
+ if (!plotArea)
69007
+ return null;
69008
+ const barChart = findChild2(plotArea, "barChart");
69009
+ if (!barChart)
69010
+ return null;
69011
+ const barDirEl = findChild2(barChart, "barDir");
69012
+ const barDir = barDirEl?.getAttribute("val") ?? "col";
69013
+ const chartType = barDir === "bar" ? "bar" : "column";
69014
+ const gapWidthEl = findChild2(barChart, "gapWidth");
69015
+ const gapWidth = gapWidthEl ? parseInt(gapWidthEl.getAttribute("val") ?? "150", 10) : 150;
69016
+ const roundedCornersEl = findChild2(chartSpace, "roundedCorners");
69017
+ const roundedCorners = roundedCornersEl?.getAttribute("val") === "1";
69018
+ const series = [];
69019
+ const serEls = findChildren2(barChart, "ser");
69020
+ for (const ser of serEls) {
69021
+ const seriesData = {
69022
+ categories: [],
69023
+ values: [],
69024
+ fillColors: []
69025
+ };
69026
+ const txEl = findChild2(ser, "tx");
69027
+ if (txEl) {
69028
+ const strRef = findChild2(txEl, "strRef");
69029
+ if (strRef) {
69030
+ const strCache = findChild2(strRef, "strCache");
69031
+ if (strCache) {
69032
+ const pt = findChild2(strCache, "pt");
69033
+ if (pt) {
69034
+ const v = findChild2(pt, "v");
69035
+ if (v?.textContent)
69036
+ seriesData.name = v.textContent;
69037
+ }
69038
+ }
69039
+ }
69040
+ }
69041
+ const serSpPr = findChild2(ser, "spPr");
69042
+ if (serSpPr) {
69043
+ const color = resolveChartColor(serSpPr, themeColors);
69044
+ if (color)
69045
+ seriesData.seriesColor = color;
69046
+ }
69047
+ const dPtMap = /* @__PURE__ */ new Map();
69048
+ const dPtEls = findChildren2(ser, "dPt");
69049
+ for (const dPt of dPtEls) {
69050
+ const idxEl = findChild2(dPt, "idx");
69051
+ const idx = idxEl ? parseInt(idxEl.getAttribute("val") ?? "0", 10) : 0;
69052
+ const spPr = findChild2(dPt, "spPr");
69053
+ if (spPr) {
69054
+ const color = resolveChartColor(spPr, themeColors);
69055
+ if (color)
69056
+ dPtMap.set(idx, color);
69057
+ }
69058
+ }
69059
+ const catEl = findChild2(ser, "cat");
69060
+ if (catEl) {
69061
+ const strRef = findChild2(catEl, "strRef");
69062
+ if (strRef) {
69063
+ const strCache = findChild2(strRef, "strCache");
69064
+ if (strCache) {
69065
+ const pts = findChildren2(strCache, "pt");
69066
+ for (const pt of pts) {
69067
+ const v = findChild2(pt, "v");
69068
+ seriesData.categories.push(v?.textContent ?? "");
69069
+ }
69070
+ }
69071
+ }
69072
+ }
69073
+ const valEl = findChild2(ser, "val");
69074
+ if (valEl) {
69075
+ const numRef = findChild2(valEl, "numRef");
69076
+ if (numRef) {
69077
+ const numCache = findChild2(numRef, "numCache");
69078
+ if (numCache) {
69079
+ const pts = findChildren2(numCache, "pt");
69080
+ for (const pt of pts) {
69081
+ const v = findChild2(pt, "v");
69082
+ seriesData.values.push(parseFloat(v?.textContent ?? "0"));
69083
+ }
69084
+ }
69085
+ }
69086
+ }
69087
+ for (let i = 0; i < seriesData.values.length; i++) {
69088
+ seriesData.fillColors.push(dPtMap.get(i) ?? void 0);
69089
+ }
69090
+ series.push(seriesData);
69091
+ }
69092
+ if (series.length === 0)
69093
+ return null;
69094
+ let categoryAxis;
69095
+ let valueAxis;
69096
+ const catAx = findChild2(plotArea, "catAx");
69097
+ if (catAx) {
69098
+ categoryAxis = parseChartAxis(catAx, themeColors);
69099
+ }
69100
+ const valAx = findChild2(plotArea, "valAx");
69101
+ if (valAx) {
69102
+ valueAxis = parseChartAxis(valAx, themeColors);
69103
+ }
69104
+ return {
69105
+ x,
69106
+ y,
69107
+ w,
69108
+ h,
69109
+ chartType,
69110
+ title,
69111
+ titleFont,
69112
+ titleColor,
69113
+ titleSize,
69114
+ series,
69115
+ categoryAxis,
69116
+ valueAxis,
69117
+ gapWidth,
69118
+ roundedCorners
69119
+ };
69120
+ }
69121
+ function formatChartValue(value, numFormat) {
69122
+ if (!numFormat || numFormat === "General") {
69123
+ return Number.isInteger(value) ? value.toString() : value.toFixed(1);
69124
+ }
69125
+ let prefix = "";
69126
+ let suffix = "";
69127
+ let fmt = numFormat;
69128
+ const prefixMatch = fmt.match(/^"([^"]*)"(.*)$/);
69129
+ if (prefixMatch) {
69130
+ prefix = prefixMatch[1];
69131
+ fmt = prefixMatch[2];
69132
+ }
69133
+ const suffixMatch = fmt.match(/^(.*)"([^"]*)"$/);
69134
+ if (suffixMatch) {
69135
+ fmt = suffixMatch[1];
69136
+ suffix = suffixMatch[2];
69137
+ }
69138
+ const decimalMatch = fmt.match(/\.(0+)/);
69139
+ const decimals = decimalMatch ? decimalMatch[1].length : 0;
69140
+ const absVal = Math.abs(value);
69141
+ let formatted;
69142
+ if (fmt.includes(",")) {
69143
+ const parts = absVal.toFixed(decimals).split(".");
69144
+ parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
69145
+ formatted = parts.join(".");
69146
+ } else {
69147
+ formatted = absVal.toFixed(decimals);
69148
+ }
69149
+ const sign2 = value < 0 ? "-" : "";
69150
+ return sign2 + prefix + formatted + suffix;
69151
+ }
69152
+ function escSvg(text) {
69153
+ return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
69154
+ }
69155
+ function renderChartSvg(chart, elId) {
69156
+ const { x, y, w, h } = chart;
69157
+ const titleHeight = chart.title ? Math.max(24, (chart.titleSize ?? 16) + 12) : 0;
69158
+ const axisLabelHeight = 16;
69159
+ const axisTitleHeight = chart.categoryAxis?.title ? 18 : 0;
69160
+ const valAxisTitleWidth = chart.valueAxis?.title ? 20 : 0;
69161
+ const allValues = chart.series.flatMap((s) => s.values);
69162
+ const maxValue = Math.max(...allValues, 0);
69163
+ const valNumFormat = chart.valueAxis?.numFormat;
69164
+ const maxFormattedLabel = formatChartValue(maxValue, valNumFormat);
69165
+ const valLabelCharWidth = (chart.valueAxis?.labelSize ?? 11) * 0.6;
69166
+ const valLabelWidth = Math.max(30, maxFormattedLabel.length * valLabelCharWidth + 8);
69167
+ const marginTop = 8 + titleHeight;
69168
+ const marginBottom = 8 + axisLabelHeight + axisTitleHeight + 4;
69169
+ const marginLeft = 4 + valAxisTitleWidth + valLabelWidth;
69170
+ const marginRight = 12;
69171
+ const plotX = marginLeft;
69172
+ const plotY = marginTop;
69173
+ const plotW = w - marginLeft - marginRight;
69174
+ const plotH = h - marginTop - marginBottom;
69175
+ if (plotW <= 0 || plotH <= 0)
69176
+ return "";
69177
+ const minValue = chart.valueAxis?.min ?? 0;
69178
+ const valueRange = maxValue - minValue;
69179
+ if (valueRange <= 0)
69180
+ return "";
69181
+ const rawInterval = valueRange / 5;
69182
+ const magnitude = Math.pow(10, Math.floor(Math.log10(rawInterval)));
69183
+ const normalized = rawInterval / magnitude;
69184
+ let niceInterval;
69185
+ if (normalized <= 1)
69186
+ niceInterval = 1 * magnitude;
69187
+ else if (normalized <= 2)
69188
+ niceInterval = 2 * magnitude;
69189
+ else if (normalized <= 5)
69190
+ niceInterval = 5 * magnitude;
69191
+ else
69192
+ niceInterval = 10 * magnitude;
69193
+ const ticks = [];
69194
+ let tickVal = Math.ceil(minValue / niceInterval) * niceInterval;
69195
+ while (tickVal <= maxValue) {
69196
+ ticks.push(tickVal);
69197
+ tickVal += niceInterval;
69198
+ }
69199
+ if (minValue <= 0 && !ticks.includes(0)) {
69200
+ ticks.unshift(0);
69201
+ ticks.sort((a, b) => a - b);
69202
+ }
69203
+ const labelFont = chart.categoryAxis?.labelFont ?? chart.titleFont ?? "sans-serif";
69204
+ const labelColor = chart.categoryAxis?.labelColor ?? "#333";
69205
+ const labelSize = chart.categoryAxis?.labelSize ?? 11;
69206
+ const valLabelColor = chart.valueAxis?.labelColor ?? labelColor;
69207
+ const valLabelSize = chart.valueAxis?.labelSize ?? 11;
69208
+ let svg = `<svg xmlns="http://www.w3.org/2000/svg" width="${w}" height="${h}" viewBox="0 0 ${w} ${h}" style="overflow:visible">`;
69209
+ if (chart.title) {
69210
+ const tFont = chart.titleFont ? `font-family:${cssFontFamily(chart.titleFont)};` : `font-family:${cssFontFamily(labelFont)};`;
69211
+ const tColor = chart.titleColor ?? "#000";
69212
+ const tSize = chart.titleSize ?? 16;
69213
+ 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>`;
69214
+ }
69215
+ if (chart.valueAxis) {
69216
+ const gColor = chart.valueAxis.gridlineColor ?? "#e0e0e0";
69217
+ const gAlpha = chart.valueAxis.gridlineAlpha !== void 0 ? chart.valueAxis.gridlineAlpha / 100 : 0.3;
69218
+ for (const tick of ticks) {
69219
+ const tickY = plotY + plotH - (tick - minValue) / valueRange * plotH;
69220
+ svg += `<line x1="${plotX}" y1="${tickY}" x2="${plotX + plotW}" y2="${tickY}" stroke="${gColor}" stroke-opacity="${gAlpha}" stroke-width="1"/>`;
69221
+ }
69222
+ }
69223
+ const numCategories = chart.series[0]?.categories.length ?? 0;
69224
+ const numSeries = chart.series.length;
69225
+ if (numCategories > 0) {
69226
+ const gapFraction = (chart.gapWidth ?? 150) / 100;
69227
+ const categoryWidth = plotW / numCategories;
69228
+ const barGroupWidth = categoryWidth / (1 + gapFraction);
69229
+ const gapSpace = categoryWidth - barGroupWidth;
69230
+ const barWidth = barGroupWidth / numSeries;
69231
+ const cornerRadius = chart.roundedCorners ? Math.min(barWidth * 0.15, 4) : 0;
69232
+ for (let si = 0; si < numSeries; si++) {
69233
+ const s = chart.series[si];
69234
+ for (let ci = 0; ci < s.values.length; ci++) {
69235
+ const val = s.values[ci];
69236
+ const barH = (val - minValue) / valueRange * plotH;
69237
+ const barX = plotX + ci * categoryWidth + gapSpace / 2 + si * barWidth;
69238
+ const barY = plotY + plotH - barH;
69239
+ const fillColor = s.fillColors[ci] ?? s.seriesColor ?? "#4472C4";
69240
+ if (cornerRadius > 0) {
69241
+ const r = Math.min(cornerRadius, barH / 2, barWidth / 2);
69242
+ 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}"/>`;
69243
+ } else {
69244
+ svg += `<rect x="${barX}" y="${barY}" width="${barWidth}" height="${barH}" fill="${fillColor}"/>`;
69245
+ }
69246
+ }
69247
+ }
69248
+ }
69249
+ svg += `<line x1="${plotX}" y1="${plotY + plotH}" x2="${plotX + plotW}" y2="${plotY + plotH}" stroke="${labelColor}" stroke-width="1"/>`;
69250
+ svg += `<line x1="${plotX}" y1="${plotY}" x2="${plotX}" y2="${plotY + plotH}" stroke="${valLabelColor}" stroke-width="1"/>`;
69251
+ if (numCategories > 0) {
69252
+ const categoryWidth = plotW / numCategories;
69253
+ const cats = chart.series[0]?.categories ?? [];
69254
+ for (let ci = 0; ci < cats.length; ci++) {
69255
+ const labelX = plotX + ci * categoryWidth + categoryWidth / 2;
69256
+ const labelY = plotY + plotH + 4;
69257
+ const catText = cats[ci];
69258
+ const lines = catText.split("\n");
69259
+ const lineH = labelSize + 2;
69260
+ for (let li = 0; li < lines.length; li++) {
69261
+ 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>`;
69262
+ }
69263
+ }
69264
+ }
69265
+ for (const tick of ticks) {
69266
+ const tickY = plotY + plotH - (tick - minValue) / valueRange * plotH;
69267
+ const label = formatChartValue(tick, valNumFormat);
69268
+ 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>`;
69269
+ }
69270
+ if (chart.categoryAxis?.title) {
69271
+ const axTitleY = plotY + plotH + axisLabelHeight + axisTitleHeight + 2;
69272
+ 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>`;
69273
+ }
69274
+ if (chart.valueAxis?.title) {
69275
+ const axTitleX = 4 + (chart.titleSize ?? 12) * 0.5;
69276
+ const axTitleY = plotY + plotH / 2;
69277
+ 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>`;
69278
+ }
69279
+ svg += `</svg>`;
69280
+ const wrapperStyles = [
69281
+ "position:absolute",
69282
+ `left:${x}px`,
69283
+ `top:${y}px`,
69284
+ `width:${w}px`,
69285
+ `height:${h}px`
69286
+ ];
69287
+ return `<div id="${elId}" data-elementType="chart" style="${wrapperStyles.join(";")}">${svg}</div>
69288
+ `;
69289
+ }
69290
+ function renderSlideHtml(elements, bgColor, contentOffsetX = 0) {
68532
69291
  let inner = "";
68533
69292
  let elementIndex = 0;
68534
69293
  for (const el of elements) {
68535
69294
  const elId = `el-${elementIndex++}`;
68536
69295
  if (el.kind === "image") {
68537
69296
  const img = el.data;
69297
+ const altAttr = img.alt ? ` alt="${img.alt.replace(/"/g, "&quot;")}"` : "";
68538
69298
  const isFullbleed = img.x <= 10 && img.y <= 10 && img.w >= TARGET_WIDTH - 20 && img.h >= TARGET_HEIGHT - 20;
68539
- const objectFit = isFullbleed || img.hasCrop ? "cover" : "contain";
69299
+ if (img.hasCrop && img.cropLeft !== void 0 && img.cropTop !== void 0 && img.cropRight !== void 0 && img.cropBottom !== void 0) {
69300
+ const visW = (100 - img.cropLeft - img.cropRight) / 100;
69301
+ const visH = (100 - img.cropTop - img.cropBottom) / 100;
69302
+ if (visW > 0 && visH > 0) {
69303
+ const displayW = img.w / visW;
69304
+ const displayH = img.h / visH;
69305
+ const offsetX = -(img.cropLeft / 100) * displayW;
69306
+ const offsetY = -(img.cropTop / 100) * displayH;
69307
+ const wrapperStyles = [
69308
+ "position:absolute",
69309
+ `left:${img.x}px`,
69310
+ `top:${img.y}px`,
69311
+ `width:${img.w}px`,
69312
+ `height:${img.h}px`,
69313
+ "overflow:hidden"
69314
+ ];
69315
+ if (img.rotation) {
69316
+ wrapperStyles.push(`transform:rotate(${img.rotation}deg)`);
69317
+ wrapperStyles.push("transform-origin:center center");
69318
+ }
69319
+ if (img.borderRadius && img.borderRadius > 0) {
69320
+ wrapperStyles.push(`border-radius:${img.borderRadius}px`);
69321
+ }
69322
+ const imgStyle = `position:absolute;width:${Math.round(displayW)}px;height:${Math.round(displayH)}px;left:${Math.round(offsetX)}px;top:${Math.round(offsetY)}px`;
69323
+ inner += `<div id="${elId}" data-elementType="image" style="${wrapperStyles.join(";")}">`;
69324
+ inner += `<img src="${img.dataUri}"${altAttr} style="${imgStyle}" />`;
69325
+ inner += `</div>
69326
+ `;
69327
+ continue;
69328
+ }
69329
+ }
69330
+ const objectFit = isFullbleed ? "cover" : "contain";
68540
69331
  const stylesList = [
68541
69332
  "position:absolute",
68542
69333
  `left:${img.x}px`,
@@ -68545,11 +69336,14 @@ ${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join("\n")}`;
68545
69336
  `height:${img.h}px`,
68546
69337
  `object-fit:${objectFit}`
68547
69338
  ];
69339
+ if (img.rotation) {
69340
+ stylesList.push(`transform:rotate(${img.rotation}deg)`);
69341
+ stylesList.push("transform-origin:center center");
69342
+ }
68548
69343
  if (img.borderRadius && img.borderRadius > 0) {
68549
69344
  stylesList.push(`border-radius:${img.borderRadius}px`);
68550
69345
  }
68551
69346
  const styles2 = stylesList.join(";");
68552
- const altAttr = img.alt ? ` alt="${img.alt.replace(/"/g, "&quot;")}"` : "";
68553
69347
  inner += `<img id="${elId}" data-elementType="image" src="${img.dataUri}"${altAttr} style="${styles2}" />
68554
69348
  `;
68555
69349
  continue;
@@ -68638,6 +69432,8 @@ ${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join("\n")}`;
68638
69432
  rStyles.push("font-weight:bold");
68639
69433
  if (run.italic)
68640
69434
  rStyles.push("font-style:italic");
69435
+ if (run.underline)
69436
+ rStyles.push("text-decoration:underline");
68641
69437
  if (run.fontFamily)
68642
69438
  rStyles.push(`font-family:${cssFontFamily(run.fontFamily)}`);
68643
69439
  if (run.textShadow)
@@ -68660,6 +69456,11 @@ ${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join("\n")}`;
68660
69456
  `;
68661
69457
  continue;
68662
69458
  }
69459
+ if (el.kind === "chart") {
69460
+ const chart = el.data;
69461
+ inner += renderChartSvg(chart, elId);
69462
+ continue;
69463
+ }
68663
69464
  const shape = el.data;
68664
69465
  const styles = [
68665
69466
  "position:absolute",
@@ -68672,6 +69473,12 @@ ${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join("\n")}`;
68672
69473
  if (shape.fill) {
68673
69474
  styles.push(`background:${shape.fill}`);
68674
69475
  }
69476
+ if (shape.clipPath) {
69477
+ styles.push(`clip-path:${shape.clipPath}`);
69478
+ }
69479
+ if (shape.rotation) {
69480
+ styles.push(`transform:rotate(${shape.rotation}deg)`);
69481
+ }
68675
69482
  if (shape.borderRadius) {
68676
69483
  styles.push(`border-radius:${shape.borderRadius}px`);
68677
69484
  } else if (shape.isEllipse) {
@@ -68705,7 +69512,10 @@ ${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join("\n")}`;
68705
69512
  else if (shape.verticalAlign === "bottom")
68706
69513
  styles.push("justify-content:flex-end");
68707
69514
  }
68708
- if (shape.paragraphs.length === 0 && !shape.fill) {
69515
+ if (shape.w <= 0 || shape.h <= 0) {
69516
+ continue;
69517
+ }
69518
+ if (shape.paragraphs.length === 0 && !shape.fill && !shape.borderWidth && !shape.isEllipse) {
68709
69519
  continue;
68710
69520
  }
68711
69521
  const hasText = shape.paragraphs.length > 0;
@@ -68727,8 +69537,15 @@ ${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join("\n")}`;
68727
69537
  pStyles.push(`text-indent:${para.indentPx}px`);
68728
69538
  let runHtml = "";
68729
69539
  if (para.bulletChar) {
68730
- const bulletStyle = para.bulletColor ? `margin-right:4px;color:${para.bulletColor}` : "margin-right:4px";
68731
- runHtml += `<span style="${bulletStyle}">${para.bulletChar}</span>`;
69540
+ const bulletStyleParts = ["margin-right:4px"];
69541
+ if (para.bulletColor)
69542
+ bulletStyleParts.push(`color:${para.bulletColor}`);
69543
+ if (para.bulletFont)
69544
+ bulletStyleParts.push(`font-family:${cssFontFamily(para.bulletFont)}`);
69545
+ const firstRunFontSize = para.runs[0]?.fontSize;
69546
+ if (firstRunFontSize)
69547
+ bulletStyleParts.push(`font-size:${firstRunFontSize}px`);
69548
+ runHtml += `<span style="${bulletStyleParts.join(";")}">${para.bulletChar}</span>`;
68732
69549
  }
68733
69550
  for (const run of para.runs) {
68734
69551
  const rStyles = [];
@@ -68746,6 +69563,8 @@ ${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join("\n")}`;
68746
69563
  rStyles.push("font-weight:bold");
68747
69564
  if (run.italic)
68748
69565
  rStyles.push("font-style:italic");
69566
+ if (run.underline)
69567
+ rStyles.push("text-decoration:underline");
68749
69568
  if (run.fontFamily)
68750
69569
  rStyles.push(`font-family:${cssFontFamily(run.fontFamily)}`);
68751
69570
  if (run.textShadow)
@@ -68763,8 +69582,12 @@ ${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join("\n")}`;
68763
69582
  `;
68764
69583
  }
68765
69584
  const bg = bgColor ?? "#fff";
69585
+ const offsetPx = Math.round(contentOffsetX);
69586
+ const innerWrapStyle = offsetPx > 0 ? ` style="position:absolute;left:${offsetPx}px;top:0"` : "";
68766
69587
  return `<div style="position:relative;width:${TARGET_WIDTH}px;height:${TARGET_HEIGHT}px;overflow:hidden;font-family:'Segoe UI',Arial,sans-serif;background:${bg}">
68767
- ${inner}</div>`;
69588
+ <div${innerWrapStyle}>
69589
+ ${inner}</div>
69590
+ </div>`;
68768
69591
  }
68769
69592
  async function importPptx(arrayBuffer) {
68770
69593
  const zip = await import_jszip2.default.loadAsync(arrayBuffer);
@@ -68779,6 +69602,8 @@ ${inner}</div>`;
68779
69602
  const slideWPx = emuToPx2(slideWEmu);
68780
69603
  const slideHPx = emuToPx2(slideHEmu);
68781
69604
  const scale = Math.min(TARGET_WIDTH / slideWPx, TARGET_HEIGHT / slideHPx);
69605
+ const scaledContentW = slideWPx * scale;
69606
+ const contentOffsetX = (TARGET_WIDTH - scaledContentW) / 2;
68782
69607
  const sldIdLst = presDoc.getElementsByTagName("p:sldIdLst")[0];
68783
69608
  const visibleSlideRIds = [];
68784
69609
  if (sldIdLst) {
@@ -68827,6 +69652,7 @@ ${inner}</div>`;
68827
69652
  }
68828
69653
  const themeColors = /* @__PURE__ */ new Map();
68829
69654
  const themeXml = await zip.file("ppt/theme/theme1.xml")?.async("text");
69655
+ const bgFillStyles = [];
68830
69656
  if (themeXml) {
68831
69657
  const themeDoc = parser.parseFromString(themeXml, "application/xml");
68832
69658
  const clrScheme = themeDoc.getElementsByTagName("a:clrScheme")[0];
@@ -68872,6 +69698,12 @@ ${inner}</div>`;
68872
69698
  const lt2Color = themeColors.get("lt2");
68873
69699
  if (lt2Color)
68874
69700
  themeColors.set("bg2", lt2Color);
69701
+ const bgFillStyleLst = themeDoc.getElementsByTagName("a:bgFillStyleLst")[0];
69702
+ if (bgFillStyleLst) {
69703
+ for (let i = 0; i < bgFillStyleLst.children.length; i++) {
69704
+ bgFillStyles.push(bgFillStyleLst.children[i]);
69705
+ }
69706
+ }
68875
69707
  }
68876
69708
  let themeFonts;
68877
69709
  if (themeXml) {
@@ -68908,6 +69740,96 @@ ${inner}</div>`;
68908
69740
  fontStyleBlock = `<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=${fontFamilies}&display=swap">`;
68909
69741
  }
68910
69742
  const slides = [];
69743
+ let masterBg;
69744
+ let masterDecorativeElements = [];
69745
+ const masterXml = await zip.file("ppt/slideMasters/slideMaster1.xml")?.async("text");
69746
+ if (masterXml) {
69747
+ const masterDoc = parser.parseFromString(masterXml, "application/xml");
69748
+ const masterBgEl = masterDoc.getElementsByTagName("p:bg")[0];
69749
+ if (masterBgEl) {
69750
+ masterBg = extractBgFill(masterBgEl, bgFillStyles, themeColors);
69751
+ }
69752
+ const masterImageMap = /* @__PURE__ */ new Map();
69753
+ const masterRelsXml = await zip.file("ppt/slideMasters/_rels/slideMaster1.xml.rels")?.async("text");
69754
+ if (masterRelsXml) {
69755
+ const relsDoc = parser.parseFromString(masterRelsXml, "application/xml");
69756
+ const rels = relsDoc.getElementsByTagName("Relationship");
69757
+ for (let ri = 0; ri < rels.length; ri++) {
69758
+ const rel = rels[ri];
69759
+ const type2 = rel.getAttribute("Type") ?? "";
69760
+ if (!type2.includes("/image"))
69761
+ continue;
69762
+ const rId = rel.getAttribute("Id");
69763
+ const target = rel.getAttribute("Target");
69764
+ if (!rId || !target)
69765
+ continue;
69766
+ const mediaPath = target.startsWith("../") ? "ppt/" + target.slice(3) : target;
69767
+ const imgFile = zip.file(mediaPath);
69768
+ if (!imgFile)
69769
+ continue;
69770
+ const imgData = await imgFile.async("base64");
69771
+ const ext = mediaPath.split(".").pop()?.toLowerCase() ?? "png";
69772
+ const mime = ext === "jpg" || ext === "jpeg" ? "image/jpeg" : ext === "svg" ? "image/svg+xml" : `image/${ext}`;
69773
+ masterImageMap.set(rId, `data:${mime};base64,${imgData}`);
69774
+ }
69775
+ }
69776
+ const masterSpTree = masterDoc.getElementsByTagName("p:spTree")[0];
69777
+ if (masterSpTree) {
69778
+ masterDecorativeElements = parseDecorativeShapes(masterSpTree, scale, themeColors, masterImageMap, themeFonts);
69779
+ }
69780
+ }
69781
+ const layoutCache = /* @__PURE__ */ new Map();
69782
+ async function getLayoutInfo(layoutPath) {
69783
+ if (layoutCache.has(layoutPath))
69784
+ return layoutCache.get(layoutPath);
69785
+ const result = { bg: void 0, showMasterSp: true, decorativeElements: [] };
69786
+ const layoutXml = await zip.file(layoutPath)?.async("text");
69787
+ if (layoutXml) {
69788
+ const layoutDoc = parser.parseFromString(layoutXml, "application/xml");
69789
+ const cSld = layoutDoc.getElementsByTagName("p:cSld")[0];
69790
+ const rootEl = layoutDoc.documentElement;
69791
+ const showMasterSpAttr = rootEl.getAttribute("showMasterSp");
69792
+ if (showMasterSpAttr === "0") {
69793
+ result.showMasterSp = false;
69794
+ }
69795
+ const layoutBgEl = layoutDoc.getElementsByTagName("p:bg")[0];
69796
+ if (layoutBgEl) {
69797
+ result.bg = extractBgFill(layoutBgEl, bgFillStyles, themeColors);
69798
+ }
69799
+ const layoutImageMap = /* @__PURE__ */ new Map();
69800
+ const layoutBaseName = layoutPath.split("/").pop();
69801
+ const layoutRelsPath = layoutPath.replace(layoutBaseName, `_rels/${layoutBaseName}.rels`);
69802
+ const layoutRelsXml = await zip.file(layoutRelsPath)?.async("text");
69803
+ if (layoutRelsXml) {
69804
+ const relsDoc = parser.parseFromString(layoutRelsXml, "application/xml");
69805
+ const rels = relsDoc.getElementsByTagName("Relationship");
69806
+ for (let ri = 0; ri < rels.length; ri++) {
69807
+ const rel = rels[ri];
69808
+ const type2 = rel.getAttribute("Type") ?? "";
69809
+ if (!type2.includes("/image"))
69810
+ continue;
69811
+ const rId = rel.getAttribute("Id");
69812
+ const target = rel.getAttribute("Target");
69813
+ if (!rId || !target)
69814
+ continue;
69815
+ const mediaPath = target.startsWith("../") ? "ppt/" + target.slice(3) : target;
69816
+ const imgFile = zip.file(mediaPath);
69817
+ if (!imgFile)
69818
+ continue;
69819
+ const imgData = await imgFile.async("base64");
69820
+ const ext = mediaPath.split(".").pop()?.toLowerCase() ?? "png";
69821
+ const mime = ext === "jpg" || ext === "jpeg" ? "image/jpeg" : ext === "svg" ? "image/svg+xml" : `image/${ext}`;
69822
+ layoutImageMap.set(rId, `data:${mime};base64,${imgData}`);
69823
+ }
69824
+ }
69825
+ const layoutSpTree = layoutDoc.getElementsByTagName("p:spTree")[0];
69826
+ if (layoutSpTree) {
69827
+ result.decorativeElements = parseDecorativeShapes(layoutSpTree, scale, themeColors, layoutImageMap, themeFonts);
69828
+ }
69829
+ }
69830
+ layoutCache.set(layoutPath, result);
69831
+ return result;
69832
+ }
68911
69833
  for (const slideFile of slideFiles) {
68912
69834
  const slideXml = await zip.file(slideFile)?.async("text");
68913
69835
  if (!slideXml)
@@ -68917,24 +69839,47 @@ ${inner}</div>`;
68917
69839
  let slideBg = void 0;
68918
69840
  const bgEl = slideDoc.getElementsByTagName("p:bg")[0];
68919
69841
  if (bgEl) {
68920
- const bgPr = findChild2(bgEl, "bgPr");
68921
- if (bgPr) {
68922
- slideBg = extractFill(bgPr, themeColors);
68923
- }
68924
- }
68925
- if (!spTree) {
68926
- slides.push(renderSlideHtml([], slideBg));
68927
- continue;
69842
+ slideBg = extractBgFill(bgEl, bgFillStyles, themeColors);
68928
69843
  }
68929
- const imageMap = /* @__PURE__ */ new Map();
68930
69844
  const slideBaseName = slideFile.split("/").pop();
68931
69845
  const relsPath = slideFile.replace(slideBaseName, `_rels/${slideBaseName}.rels`);
68932
69846
  const relsXml = await zip.file(relsPath)?.async("text");
69847
+ let layoutPath;
68933
69848
  if (relsXml) {
68934
69849
  const relsDoc = parser.parseFromString(relsXml, "application/xml");
68935
69850
  const rels = relsDoc.getElementsByTagName("Relationship");
68936
- for (let i = 0; i < rels.length; i++) {
68937
- const rel = rels[i];
69851
+ for (let ri = 0; ri < rels.length; ri++) {
69852
+ const rel = rels[ri];
69853
+ const type2 = rel.getAttribute("Type") ?? "";
69854
+ if (type2.includes("/slideLayout")) {
69855
+ const target = rel.getAttribute("Target");
69856
+ if (target) {
69857
+ layoutPath = target.startsWith("../") ? "ppt/" + target.slice(3) : "ppt/slides/" + target;
69858
+ }
69859
+ break;
69860
+ }
69861
+ }
69862
+ }
69863
+ let layoutInfo;
69864
+ if (layoutPath) {
69865
+ layoutInfo = await getLayoutInfo(layoutPath);
69866
+ }
69867
+ if (!slideBg && layoutInfo?.bg) {
69868
+ slideBg = layoutInfo.bg;
69869
+ }
69870
+ if (!slideBg && masterBg) {
69871
+ slideBg = masterBg;
69872
+ }
69873
+ if (!spTree) {
69874
+ slides.push(renderSlideHtml([], slideBg, contentOffsetX));
69875
+ continue;
69876
+ }
69877
+ const imageMap = /* @__PURE__ */ new Map();
69878
+ const slideRelsDoc = relsXml ? parser.parseFromString(relsXml, "application/xml") : null;
69879
+ if (slideRelsDoc) {
69880
+ const rels = slideRelsDoc.getElementsByTagName("Relationship");
69881
+ for (let ri = 0; ri < rels.length; ri++) {
69882
+ const rel = rels[ri];
68938
69883
  const type2 = rel.getAttribute("Type") ?? "";
68939
69884
  if (!type2.includes("/image"))
68940
69885
  continue;
@@ -68953,6 +69898,12 @@ ${inner}</div>`;
68953
69898
  }
68954
69899
  }
68955
69900
  const elements = [];
69901
+ if (layoutInfo?.showMasterSp !== false) {
69902
+ elements.push(...masterDecorativeElements);
69903
+ }
69904
+ if (layoutInfo?.decorativeElements) {
69905
+ elements.push(...layoutInfo.decorativeElements);
69906
+ }
68956
69907
  for (let i = 0; i < spTree.children.length; i++) {
68957
69908
  const child = spTree.children[i];
68958
69909
  if (child.localName === "sp") {
@@ -68965,11 +69916,16 @@ ${inner}</div>`;
68965
69916
  elements.push({ kind: "image", data: img });
68966
69917
  } else if (child.localName === "graphicFrame") {
68967
69918
  const table = parseTable2(child, scale, themeColors, themeFonts, tableStyleMap);
68968
- if (table)
69919
+ if (table) {
68969
69920
  elements.push({ kind: "table", data: table });
69921
+ } else if (slideRelsDoc) {
69922
+ const chart = await parseChart(child, scale, themeColors, zip, slideRelsDoc, parser);
69923
+ if (chart)
69924
+ elements.push({ kind: "chart", data: chart });
69925
+ }
68970
69926
  }
68971
69927
  }
68972
- slides.push(renderSlideHtml(elements, slideBg));
69928
+ slides.push(renderSlideHtml(elements, slideBg, contentOffsetX));
68973
69929
  }
68974
69930
  if (fontStyleBlock && slides.length > 0) {
68975
69931
  slides[0] = fontStyleBlock + slides[0];