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/bundle.js CHANGED
@@ -67847,28 +67847,62 @@ ${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join("\n")}`;
67847
67847
  const a = Math.round(alpha100k / 1e5 * 100) / 100;
67848
67848
  return `rgba(${r},${g},${b},${a})`;
67849
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
+ }
67850
67886
  function resolveColor2(parent, themeColors) {
67851
67887
  const srgbClr = findChild2(parent, "srgbClr");
67852
67888
  if (srgbClr) {
67853
67889
  const hex = "#" + (srgbClr.getAttribute("val") ?? "000000");
67854
- const alphaEl = findChild2(srgbClr, "alpha");
67855
- if (alphaEl) {
67856
- const alphaVal = parseInt(alphaEl.getAttribute("val") ?? "100000", 10);
67857
- return hexToRgba(hex, alphaVal);
67890
+ const { color, alpha } = applyColorModifiers(srgbClr, hex);
67891
+ if (alpha !== void 0 && alpha < 1e5) {
67892
+ return hexToRgba(color, alpha);
67858
67893
  }
67859
- return hex;
67894
+ return color;
67860
67895
  }
67861
67896
  const schemeClr = findChild2(parent, "schemeClr");
67862
67897
  if (schemeClr) {
67863
67898
  const val = schemeClr.getAttribute("val");
67864
67899
  if (val && themeColors.has(val)) {
67865
67900
  const hex = themeColors.get(val);
67866
- const alphaEl = findChild2(schemeClr, "alpha");
67867
- if (alphaEl) {
67868
- const alphaVal = parseInt(alphaEl.getAttribute("val") ?? "100000", 10);
67869
- return hexToRgba(hex, alphaVal);
67901
+ const { color, alpha } = applyColorModifiers(schemeClr, hex);
67902
+ if (alpha !== void 0 && alpha < 1e5) {
67903
+ return hexToRgba(color, alpha);
67870
67904
  }
67871
- return hex;
67905
+ return color;
67872
67906
  }
67873
67907
  }
67874
67908
  return void 0;
@@ -67919,6 +67953,158 @@ ${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join("\n")}`;
67919
67953
  return resolveColor2(solidFill, themeColors);
67920
67954
  return extractGradientFill(spPr, themeColors);
67921
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
+ }
67922
68108
  function extractRunProps(rPr, scale, themeColors, themeFonts) {
67923
68109
  if (!rPr)
67924
68110
  return {};
@@ -67932,6 +68118,9 @@ ${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join("\n")}`;
67932
68118
  const i = rPr.getAttribute("i");
67933
68119
  if (i === "1" || i === "true")
67934
68120
  result.italic = true;
68121
+ const u = rPr.getAttribute("u");
68122
+ if (u && u !== "none")
68123
+ result.underline = true;
67935
68124
  const solidFill = findChild2(rPr, "solidFill");
67936
68125
  if (solidFill) {
67937
68126
  const color = resolveColor2(solidFill, themeColors);
@@ -68038,14 +68227,33 @@ ${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join("\n")}`;
68038
68227
  return null;
68039
68228
  const wEmu = parseInt(ext.getAttribute("cx") ?? "0", 10);
68040
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
+ }
68041
68243
  const shape = {
68042
68244
  x: Math.round(emuToPx2(parseInt(off.getAttribute("x") ?? "0", 10)) * scale),
68043
68245
  y: Math.round(emuToPx2(parseInt(off.getAttribute("y") ?? "0", 10)) * scale),
68044
68246
  w: Math.round(emuToPx2(wEmu) * scale),
68045
68247
  h: Math.round(emuToPx2(hEmu) * scale),
68046
- fill: extractFill(spPr, themeColors),
68248
+ fill,
68047
68249
  paragraphs: []
68048
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
+ }
68049
68257
  const prstGeom = findChild2(spPr, "prstGeom");
68050
68258
  const prstType = prstGeom?.getAttribute("prst");
68051
68259
  if (prstType === "roundRect" && prstGeom) {
@@ -68057,6 +68265,10 @@ ${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join("\n")}`;
68057
68265
  shape.borderRadius = Math.round(emuToPx2(radiusEmu) * scale);
68058
68266
  } else if (prstType === "ellipse") {
68059
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%)";
68060
68272
  }
68061
68273
  const ln = findChild2(spPr, "ln");
68062
68274
  if (ln) {
@@ -68151,6 +68363,10 @@ ${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join("\n")}`;
68151
68363
  if (buChar) {
68152
68364
  para.bulletChar = buChar.getAttribute("char") ?? void 0;
68153
68365
  }
68366
+ const buFont = findChild2(pPr, "buFont");
68367
+ if (buFont) {
68368
+ para.bulletFont = buFont.getAttribute("typeface") ?? void 0;
68369
+ }
68154
68370
  const buClr = findChild2(pPr, "buClr");
68155
68371
  if (buClr) {
68156
68372
  para.bulletColor = resolveColor2(buClr, themeColors);
@@ -68171,6 +68387,7 @@ ${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join("\n")}`;
68171
68387
  text,
68172
68388
  bold: props.bold ?? defaults?.bold,
68173
68389
  italic: props.italic ?? defaults?.italic,
68390
+ underline: props.underline ?? defaults?.underline,
68174
68391
  fontSize: props.fontSize ?? defaults?.fontSize,
68175
68392
  color: props.color ?? defaults?.color,
68176
68393
  fontFamily: props.fontFamily ?? defaults?.fontFamily,
@@ -68241,12 +68458,16 @@ ${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join("\n")}`;
68241
68458
  const alt = cNvPr?.getAttribute("descr") ?? void 0;
68242
68459
  const srcRect = findChild2(blipFill, "srcRect");
68243
68460
  let hasCrop = false;
68461
+ let cropLeft = 0;
68462
+ let cropTop = 0;
68463
+ let cropRight = 0;
68464
+ let cropBottom = 0;
68244
68465
  if (srcRect) {
68245
- const l = parseInt(srcRect.getAttribute("l") ?? "0", 10);
68246
- const r = parseInt(srcRect.getAttribute("r") ?? "0", 10);
68247
- const t = parseInt(srcRect.getAttribute("t") ?? "0", 10);
68248
- const b = parseInt(srcRect.getAttribute("b") ?? "0", 10);
68249
- 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;
68250
68471
  }
68251
68472
  let borderRadius;
68252
68473
  const prstGeom = findChild2(spPr, "prstGeom");
@@ -68260,6 +68481,13 @@ ${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join("\n")}`;
68260
68481
  const radiusEmu = minDim * Math.min(adjVal, 5e4) / 1e5;
68261
68482
  borderRadius = Math.round(emuToPx2(radiusEmu) * scale);
68262
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
+ }
68263
68491
  return {
68264
68492
  x: Math.round(emuToPx2(parseInt(off.getAttribute("x") ?? "0", 10)) * scale),
68265
68493
  y: Math.round(emuToPx2(parseInt(off.getAttribute("y") ?? "0", 10)) * scale),
@@ -68268,7 +68496,12 @@ ${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join("\n")}`;
68268
68496
  dataUri,
68269
68497
  alt,
68270
68498
  borderRadius,
68271
- 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
68272
68505
  };
68273
68506
  }
68274
68507
  async function parseTableStyles(zip, parser, themeColors) {
@@ -68396,6 +68629,10 @@ ${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join("\n")}`;
68396
68629
  if (buChar) {
68397
68630
  para.bulletChar = buChar.getAttribute("char") ?? void 0;
68398
68631
  }
68632
+ const buFont = findChild2(pPr, "buFont");
68633
+ if (buFont) {
68634
+ para.bulletFont = buFont.getAttribute("typeface") ?? void 0;
68635
+ }
68399
68636
  const buClr = findChild2(pPr, "buClr");
68400
68637
  if (buClr) {
68401
68638
  para.bulletColor = resolveColor2(buClr, themeColors);
@@ -68416,6 +68653,7 @@ ${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join("\n")}`;
68416
68653
  text,
68417
68654
  bold: props.bold ?? defaults?.bold,
68418
68655
  italic: props.italic ?? defaults?.italic,
68656
+ underline: props.underline ?? defaults?.underline,
68419
68657
  fontSize: props.fontSize ?? defaults?.fontSize,
68420
68658
  color: props.color ?? defaults?.color,
68421
68659
  fontFamily: props.fontFamily ?? defaults?.fontFamily,
@@ -68573,15 +68811,523 @@ ${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join("\n")}`;
68573
68811
  }
68574
68812
  return table;
68575
68813
  }
68576
- 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) {
68577
69291
  let inner = "";
68578
69292
  let elementIndex = 0;
68579
69293
  for (const el of elements) {
68580
69294
  const elId = `el-${elementIndex++}`;
68581
69295
  if (el.kind === "image") {
68582
69296
  const img = el.data;
69297
+ const altAttr = img.alt ? ` alt="${img.alt.replace(/"/g, "&quot;")}"` : "";
68583
69298
  const isFullbleed = img.x <= 10 && img.y <= 10 && img.w >= TARGET_WIDTH - 20 && img.h >= TARGET_HEIGHT - 20;
68584
- 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";
68585
69331
  const stylesList = [
68586
69332
  "position:absolute",
68587
69333
  `left:${img.x}px`,
@@ -68590,11 +69336,14 @@ ${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join("\n")}`;
68590
69336
  `height:${img.h}px`,
68591
69337
  `object-fit:${objectFit}`
68592
69338
  ];
69339
+ if (img.rotation) {
69340
+ stylesList.push(`transform:rotate(${img.rotation}deg)`);
69341
+ stylesList.push("transform-origin:center center");
69342
+ }
68593
69343
  if (img.borderRadius && img.borderRadius > 0) {
68594
69344
  stylesList.push(`border-radius:${img.borderRadius}px`);
68595
69345
  }
68596
69346
  const styles2 = stylesList.join(";");
68597
- const altAttr = img.alt ? ` alt="${img.alt.replace(/"/g, "&quot;")}"` : "";
68598
69347
  inner += `<img id="${elId}" data-elementType="image" src="${img.dataUri}"${altAttr} style="${styles2}" />
68599
69348
  `;
68600
69349
  continue;
@@ -68683,6 +69432,8 @@ ${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join("\n")}`;
68683
69432
  rStyles.push("font-weight:bold");
68684
69433
  if (run.italic)
68685
69434
  rStyles.push("font-style:italic");
69435
+ if (run.underline)
69436
+ rStyles.push("text-decoration:underline");
68686
69437
  if (run.fontFamily)
68687
69438
  rStyles.push(`font-family:${cssFontFamily(run.fontFamily)}`);
68688
69439
  if (run.textShadow)
@@ -68705,6 +69456,11 @@ ${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join("\n")}`;
68705
69456
  `;
68706
69457
  continue;
68707
69458
  }
69459
+ if (el.kind === "chart") {
69460
+ const chart = el.data;
69461
+ inner += renderChartSvg(chart, elId);
69462
+ continue;
69463
+ }
68708
69464
  const shape = el.data;
68709
69465
  const styles = [
68710
69466
  "position:absolute",
@@ -68717,6 +69473,12 @@ ${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join("\n")}`;
68717
69473
  if (shape.fill) {
68718
69474
  styles.push(`background:${shape.fill}`);
68719
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
+ }
68720
69482
  if (shape.borderRadius) {
68721
69483
  styles.push(`border-radius:${shape.borderRadius}px`);
68722
69484
  } else if (shape.isEllipse) {
@@ -68750,7 +69512,10 @@ ${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join("\n")}`;
68750
69512
  else if (shape.verticalAlign === "bottom")
68751
69513
  styles.push("justify-content:flex-end");
68752
69514
  }
68753
- 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) {
68754
69519
  continue;
68755
69520
  }
68756
69521
  const hasText = shape.paragraphs.length > 0;
@@ -68772,8 +69537,15 @@ ${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join("\n")}`;
68772
69537
  pStyles.push(`text-indent:${para.indentPx}px`);
68773
69538
  let runHtml = "";
68774
69539
  if (para.bulletChar) {
68775
- const bulletStyle = para.bulletColor ? `margin-right:4px;color:${para.bulletColor}` : "margin-right:4px";
68776
- 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>`;
68777
69549
  }
68778
69550
  for (const run of para.runs) {
68779
69551
  const rStyles = [];
@@ -68791,6 +69563,8 @@ ${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join("\n")}`;
68791
69563
  rStyles.push("font-weight:bold");
68792
69564
  if (run.italic)
68793
69565
  rStyles.push("font-style:italic");
69566
+ if (run.underline)
69567
+ rStyles.push("text-decoration:underline");
68794
69568
  if (run.fontFamily)
68795
69569
  rStyles.push(`font-family:${cssFontFamily(run.fontFamily)}`);
68796
69570
  if (run.textShadow)
@@ -68808,8 +69582,12 @@ ${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join("\n")}`;
68808
69582
  `;
68809
69583
  }
68810
69584
  const bg = bgColor ?? "#fff";
69585
+ const offsetPx = Math.round(contentOffsetX);
69586
+ const innerWrapStyle = offsetPx > 0 ? ` style="position:absolute;left:${offsetPx}px;top:0"` : "";
68811
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}">
68812
- ${inner}</div>`;
69588
+ <div${innerWrapStyle}>
69589
+ ${inner}</div>
69590
+ </div>`;
68813
69591
  }
68814
69592
  async function importPptx(arrayBuffer) {
68815
69593
  const zip = await import_jszip2.default.loadAsync(arrayBuffer);
@@ -68824,6 +69602,8 @@ ${inner}</div>`;
68824
69602
  const slideWPx = emuToPx2(slideWEmu);
68825
69603
  const slideHPx = emuToPx2(slideHEmu);
68826
69604
  const scale = Math.min(TARGET_WIDTH / slideWPx, TARGET_HEIGHT / slideHPx);
69605
+ const scaledContentW = slideWPx * scale;
69606
+ const contentOffsetX = (TARGET_WIDTH - scaledContentW) / 2;
68827
69607
  const sldIdLst = presDoc.getElementsByTagName("p:sldIdLst")[0];
68828
69608
  const visibleSlideRIds = [];
68829
69609
  if (sldIdLst) {
@@ -68872,6 +69652,7 @@ ${inner}</div>`;
68872
69652
  }
68873
69653
  const themeColors = /* @__PURE__ */ new Map();
68874
69654
  const themeXml = await zip.file("ppt/theme/theme1.xml")?.async("text");
69655
+ const bgFillStyles = [];
68875
69656
  if (themeXml) {
68876
69657
  const themeDoc = parser.parseFromString(themeXml, "application/xml");
68877
69658
  const clrScheme = themeDoc.getElementsByTagName("a:clrScheme")[0];
@@ -68917,6 +69698,12 @@ ${inner}</div>`;
68917
69698
  const lt2Color = themeColors.get("lt2");
68918
69699
  if (lt2Color)
68919
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
+ }
68920
69707
  }
68921
69708
  let themeFonts;
68922
69709
  if (themeXml) {
@@ -68953,6 +69740,96 @@ ${inner}</div>`;
68953
69740
  fontStyleBlock = `<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=${fontFamilies}&display=swap">`;
68954
69741
  }
68955
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
+ }
68956
69833
  for (const slideFile of slideFiles) {
68957
69834
  const slideXml = await zip.file(slideFile)?.async("text");
68958
69835
  if (!slideXml)
@@ -68962,24 +69839,47 @@ ${inner}</div>`;
68962
69839
  let slideBg = void 0;
68963
69840
  const bgEl = slideDoc.getElementsByTagName("p:bg")[0];
68964
69841
  if (bgEl) {
68965
- const bgPr = findChild2(bgEl, "bgPr");
68966
- if (bgPr) {
68967
- slideBg = extractFill(bgPr, themeColors);
68968
- }
69842
+ slideBg = extractBgFill(bgEl, bgFillStyles, themeColors);
68969
69843
  }
68970
- if (!spTree) {
68971
- slides.push(renderSlideHtml([], slideBg));
68972
- continue;
68973
- }
68974
- const imageMap = /* @__PURE__ */ new Map();
68975
69844
  const slideBaseName = slideFile.split("/").pop();
68976
69845
  const relsPath = slideFile.replace(slideBaseName, `_rels/${slideBaseName}.rels`);
68977
69846
  const relsXml = await zip.file(relsPath)?.async("text");
69847
+ let layoutPath;
68978
69848
  if (relsXml) {
68979
69849
  const relsDoc = parser.parseFromString(relsXml, "application/xml");
68980
69850
  const rels = relsDoc.getElementsByTagName("Relationship");
68981
- for (let i = 0; i < rels.length; i++) {
68982
- 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];
68983
69883
  const type2 = rel.getAttribute("Type") ?? "";
68984
69884
  if (!type2.includes("/image"))
68985
69885
  continue;
@@ -68998,6 +69898,12 @@ ${inner}</div>`;
68998
69898
  }
68999
69899
  }
69000
69900
  const elements = [];
69901
+ if (layoutInfo?.showMasterSp !== false) {
69902
+ elements.push(...masterDecorativeElements);
69903
+ }
69904
+ if (layoutInfo?.decorativeElements) {
69905
+ elements.push(...layoutInfo.decorativeElements);
69906
+ }
69001
69907
  for (let i = 0; i < spTree.children.length; i++) {
69002
69908
  const child = spTree.children[i];
69003
69909
  if (child.localName === "sp") {
@@ -69010,11 +69916,16 @@ ${inner}</div>`;
69010
69916
  elements.push({ kind: "image", data: img });
69011
69917
  } else if (child.localName === "graphicFrame") {
69012
69918
  const table = parseTable2(child, scale, themeColors, themeFonts, tableStyleMap);
69013
- if (table)
69919
+ if (table) {
69014
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
+ }
69015
69926
  }
69016
69927
  }
69017
- slides.push(renderSlideHtml(elements, slideBg));
69928
+ slides.push(renderSlideHtml(elements, slideBg, contentOffsetX));
69018
69929
  }
69019
69930
  if (fontStyleBlock && slides.length > 0) {
69020
69931
  slides[0] = fontStyleBlock + slides[0];