docgen-utils 1.0.6 → 1.0.7

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
@@ -28641,6 +28641,16 @@ ${generateStylesCss(styleMap, themeFonts)}
28641
28641
  return "FFFFFF";
28642
28642
  return match.slice(1).map((n) => parseInt(n).toString(16).padStart(2, "0")).join("");
28643
28643
  }
28644
+ function isFullyTransparent(colorStr) {
28645
+ if (colorStr === "transparent" || colorStr === "rgba(0, 0, 0, 0)")
28646
+ return true;
28647
+ const match = colorStr.match(/rgba\(\d+,\s*\d+,\s*\d+,\s*([\d.]+)\)/);
28648
+ if (match) {
28649
+ const alpha = parseFloat(match[1]);
28650
+ return alpha <= 0;
28651
+ }
28652
+ return false;
28653
+ }
28644
28654
  function extractAlpha(rgbStr) {
28645
28655
  const match = rgbStr.match(/rgba\((\d+),\s*(\d+),\s*(\d+),\s*([\d.]+)\)/);
28646
28656
  if (!match || !match[4])
@@ -28650,7 +28660,10 @@ ${generateStylesCss(styleMap, themeFonts)}
28650
28660
  }
28651
28661
  function parseCssGradient(gradientStr) {
28652
28662
  const colorToHex = (colorStr) => {
28653
- colorStr = colorStr.trim();
28663
+ colorStr = colorStr.trim().toLowerCase();
28664
+ if (colorStr === "transparent") {
28665
+ return "000000";
28666
+ }
28654
28667
  if (colorStr.startsWith("#")) {
28655
28668
  let hex = colorStr.slice(1);
28656
28669
  if (hex.length === 3)
@@ -28664,7 +28677,10 @@ ${generateStylesCss(styleMap, themeFonts)}
28664
28677
  return "FFFFFF";
28665
28678
  };
28666
28679
  const extractTransparency = (colorStr) => {
28667
- colorStr = colorStr.trim();
28680
+ colorStr = colorStr.trim().toLowerCase();
28681
+ if (colorStr === "transparent") {
28682
+ return 100;
28683
+ }
28668
28684
  const rgbaMatch = colorStr.match(/rgba\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*,\s*([\d.]+)\s*\)/);
28669
28685
  if (rgbaMatch) {
28670
28686
  const alpha = parseFloat(rgbaMatch[1]);
@@ -28785,6 +28801,89 @@ ${generateStylesCss(styleMap, themeFonts)}
28785
28801
  const normalizedFont = fontFamily.toLowerCase().replace(/['"]/g, "").split(",")[0].trim();
28786
28802
  return SINGLE_WEIGHT_FONTS.includes(normalizedFont);
28787
28803
  }
28804
+ function extractLetterSpacing(computed) {
28805
+ const ls = computed.letterSpacing;
28806
+ if (!ls || ls === "normal" || ls === "0px")
28807
+ return null;
28808
+ const pxVal = parseFloat(ls);
28809
+ if (isNaN(pxVal) || pxVal === 0)
28810
+ return null;
28811
+ return pxVal * PT_PER_PX;
28812
+ }
28813
+ function parseTextShadow(textShadow) {
28814
+ if (!textShadow || textShadow === "none")
28815
+ return { glow: null, shadow: null };
28816
+ const shadows = [];
28817
+ let current = "";
28818
+ let depth = 0;
28819
+ for (const char of textShadow) {
28820
+ if (char === "(")
28821
+ depth++;
28822
+ else if (char === ")")
28823
+ depth--;
28824
+ if (char === "," && depth === 0) {
28825
+ shadows.push(current.trim());
28826
+ current = "";
28827
+ } else {
28828
+ current += char;
28829
+ }
28830
+ }
28831
+ if (current.trim())
28832
+ shadows.push(current.trim());
28833
+ let bestGlow = null;
28834
+ let bestShadow = null;
28835
+ let bestGlowBlur = 0;
28836
+ let bestShadowOffset = 0;
28837
+ for (const shadowStr of shadows) {
28838
+ const colorMatch = shadowStr.match(/rgba?\([^)]+\)/);
28839
+ const numericParts = shadowStr.match(/([-\d.]+)px/g);
28840
+ if (!numericParts || numericParts.length < 2)
28841
+ continue;
28842
+ const offsetX = parseFloat(numericParts[0]);
28843
+ const offsetY = parseFloat(numericParts[1]);
28844
+ const blur = numericParts.length > 2 ? parseFloat(numericParts[2]) : 0;
28845
+ if (blur <= 0)
28846
+ continue;
28847
+ let opacity = 1;
28848
+ if (colorMatch) {
28849
+ const alphaMatch = colorMatch[0].match(/rgba\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*,\s*([\d.]+)\s*\)/);
28850
+ if (alphaMatch) {
28851
+ opacity = parseFloat(alphaMatch[1]);
28852
+ }
28853
+ }
28854
+ const color = colorMatch ? rgbToHex(colorMatch[0]) : "000000";
28855
+ const isGlow = Math.abs(offsetX) < 1 && Math.abs(offsetY) < 1;
28856
+ if (isGlow) {
28857
+ const GLOW_SIZE_SCALE = 2.5;
28858
+ const GLOW_OPACITY_SCALE = 0.3;
28859
+ if (blur > bestGlowBlur) {
28860
+ bestGlowBlur = blur;
28861
+ bestGlow = {
28862
+ size: blur * PT_PER_PX * GLOW_SIZE_SCALE,
28863
+ color,
28864
+ opacity: Math.min(opacity * GLOW_OPACITY_SCALE, 1)
28865
+ };
28866
+ }
28867
+ } else {
28868
+ const offset = Math.sqrt(offsetX * offsetX + offsetY * offsetY);
28869
+ if (offset > bestShadowOffset) {
28870
+ bestShadowOffset = offset;
28871
+ let angle = Math.atan2(offsetY, offsetX) * (180 / Math.PI);
28872
+ if (angle < 0)
28873
+ angle += 360;
28874
+ bestShadow = {
28875
+ type: "outer",
28876
+ angle: Math.round(angle),
28877
+ blur: blur * PT_PER_PX,
28878
+ color,
28879
+ offset: offset * PT_PER_PX,
28880
+ opacity
28881
+ };
28882
+ }
28883
+ }
28884
+ }
28885
+ return { glow: bestGlow, shadow: bestShadow };
28886
+ }
28788
28887
  function applyTextTransform(text, textTransform) {
28789
28888
  if (textTransform === "uppercase")
28790
28889
  return text.toUpperCase();
@@ -28844,6 +28943,134 @@ ${generateStylesCss(styleMap, themeFonts)}
28844
28943
  h: el.offsetHeight
28845
28944
  };
28846
28945
  }
28946
+ function applyImageFilter(img, filter) {
28947
+ try {
28948
+ if (!img.naturalWidth || !img.naturalHeight)
28949
+ return img.src;
28950
+ if (!filter || filter === "none")
28951
+ return img.src;
28952
+ const canvas = document.createElement("canvas");
28953
+ canvas.width = img.naturalWidth;
28954
+ canvas.height = img.naturalHeight;
28955
+ const ctx = canvas.getContext("2d");
28956
+ if (!ctx)
28957
+ return img.src;
28958
+ ctx.filter = filter;
28959
+ ctx.drawImage(img, 0, 0);
28960
+ return canvas.toDataURL("image/jpeg", 0.9);
28961
+ } catch {
28962
+ return img.src;
28963
+ }
28964
+ }
28965
+ function applyImageMask(img, maskGradient, displayWidth, displayHeight, cssOpacity) {
28966
+ try {
28967
+ if (!img.naturalWidth || !img.naturalHeight)
28968
+ return null;
28969
+ if (!img.complete)
28970
+ return null;
28971
+ const canvas = document.createElement("canvas");
28972
+ canvas.width = Math.round(displayWidth);
28973
+ canvas.height = Math.round(displayHeight);
28974
+ const ctx = canvas.getContext("2d");
28975
+ if (!ctx)
28976
+ return null;
28977
+ if (cssOpacity !== void 0 && cssOpacity < 1) {
28978
+ ctx.globalAlpha = cssOpacity;
28979
+ }
28980
+ ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
28981
+ ctx.globalAlpha = 1;
28982
+ try {
28983
+ ctx.getImageData(0, 0, 1, 1);
28984
+ } catch {
28985
+ return null;
28986
+ }
28987
+ applyMaskGradientToCanvas(ctx, canvas.width, canvas.height, maskGradient);
28988
+ return canvas.toDataURL("image/png");
28989
+ } catch {
28990
+ return null;
28991
+ }
28992
+ }
28993
+ function applyMaskGradientToCanvas(ctx, width, height, maskGradient) {
28994
+ ctx.globalCompositeOperation = "destination-in";
28995
+ let gradient;
28996
+ if (maskGradient.type === "radial") {
28997
+ const cx = (maskGradient.centerX ?? 50) / 100 * width;
28998
+ const cy = (maskGradient.centerY ?? 50) / 100 * height;
28999
+ const radius = Math.max(width, height);
29000
+ gradient = ctx.createRadialGradient(cx, cy, 0, cx, cy, radius);
29001
+ } else {
29002
+ const cssAngle = maskGradient.angle ?? 180;
29003
+ const angleRad = (cssAngle - 90) * Math.PI / 180;
29004
+ let x1, y1, x2, y2;
29005
+ if (cssAngle === 0) {
29006
+ x1 = width / 2;
29007
+ y1 = height;
29008
+ x2 = width / 2;
29009
+ y2 = 0;
29010
+ } else if (cssAngle === 90) {
29011
+ x1 = 0;
29012
+ y1 = height / 2;
29013
+ x2 = width;
29014
+ y2 = height / 2;
29015
+ } else if (cssAngle === 180) {
29016
+ x1 = width / 2;
29017
+ y1 = 0;
29018
+ x2 = width / 2;
29019
+ y2 = height;
29020
+ } else if (cssAngle === 270) {
29021
+ x1 = width;
29022
+ y1 = height / 2;
29023
+ x2 = 0;
29024
+ y2 = height / 2;
29025
+ } else {
29026
+ const halfDiag = Math.sqrt(width * width + height * height) / 2;
29027
+ const cx = width / 2;
29028
+ const cy = height / 2;
29029
+ x1 = cx - Math.cos(angleRad) * halfDiag;
29030
+ y1 = cy - Math.sin(angleRad) * halfDiag;
29031
+ x2 = cx + Math.cos(angleRad) * halfDiag;
29032
+ y2 = cy + Math.sin(angleRad) * halfDiag;
29033
+ }
29034
+ gradient = ctx.createLinearGradient(x1, y1, x2, y2);
29035
+ }
29036
+ for (const stop of maskGradient.stops) {
29037
+ const alpha = stop.transparency !== void 0 ? (100 - stop.transparency) / 100 : 1;
29038
+ gradient.addColorStop(stop.position / 100, `rgba(255,255,255,${alpha})`);
29039
+ }
29040
+ ctx.fillStyle = gradient;
29041
+ ctx.fillRect(0, 0, width, height);
29042
+ }
29043
+ function parseCssFilter(filter) {
29044
+ if (!filter || filter === "none")
29045
+ return null;
29046
+ const result = {};
29047
+ let hasValues = false;
29048
+ const brightnessMatch = filter.match(/brightness\(([\d.]+)\)/);
29049
+ if (brightnessMatch) {
29050
+ const val = parseFloat(brightnessMatch[1]);
29051
+ if (val !== 1) {
29052
+ result.brightness = Math.round((val - 1) * 100);
29053
+ hasValues = true;
29054
+ }
29055
+ }
29056
+ const contrastMatch = filter.match(/contrast\(([\d.]+)\)/);
29057
+ if (contrastMatch) {
29058
+ const val = parseFloat(contrastMatch[1]);
29059
+ if (val !== 1) {
29060
+ result.contrast = Math.round((val - 1) * 100);
29061
+ hasValues = true;
29062
+ }
29063
+ }
29064
+ const saturateMatch = filter.match(/saturate\(([\d.]+)\)/);
29065
+ if (saturateMatch) {
29066
+ const val = parseFloat(saturateMatch[1]);
29067
+ if (val !== 1) {
29068
+ result.saturation = Math.round(val * 100);
29069
+ hasValues = true;
29070
+ }
29071
+ }
29072
+ return hasValues ? result : null;
29073
+ }
28847
29074
  function parseBoxShadow(boxShadow) {
28848
29075
  if (!boxShadow || boxShadow === "none")
28849
29076
  return null;
@@ -28880,6 +29107,103 @@ ${generateStylesCss(styleMap, themeFonts)}
28880
29107
  opacity
28881
29108
  };
28882
29109
  }
29110
+ function extractPseudoElements(el, win) {
29111
+ const results = [];
29112
+ const parentRect = el.getBoundingClientRect();
29113
+ if (parentRect.width <= 0 || parentRect.height <= 0)
29114
+ return results;
29115
+ for (const pseudo of ["::before", "::after"]) {
29116
+ const pComputed = win.getComputedStyle(el, pseudo);
29117
+ const content = pComputed.content;
29118
+ if (!content || content === "none" || content === "normal")
29119
+ continue;
29120
+ if (pComputed.display === "none")
29121
+ continue;
29122
+ let pWidth = parseFloat(pComputed.width);
29123
+ let pHeight = parseFloat(pComputed.height);
29124
+ if (isNaN(pWidth) || pWidth <= 0) {
29125
+ const left = parseFloat(pComputed.left);
29126
+ const right = parseFloat(pComputed.right);
29127
+ if (!isNaN(left) && !isNaN(right)) {
29128
+ pWidth = parentRect.width - left - right;
29129
+ } else {
29130
+ pWidth = parentRect.width;
29131
+ }
29132
+ }
29133
+ if (isNaN(pHeight) || pHeight <= 0) {
29134
+ const top = parseFloat(pComputed.top);
29135
+ const bottom = parseFloat(pComputed.bottom);
29136
+ if (!isNaN(top) && !isNaN(bottom)) {
29137
+ pHeight = parentRect.height - top - bottom;
29138
+ } else {
29139
+ pHeight = parentRect.height;
29140
+ }
29141
+ }
29142
+ if (pWidth < 1 || pHeight < 1)
29143
+ continue;
29144
+ let pLeft = parseFloat(pComputed.left);
29145
+ let pTop = parseFloat(pComputed.top);
29146
+ if (isNaN(pLeft))
29147
+ pLeft = 0;
29148
+ if (isNaN(pTop))
29149
+ pTop = 0;
29150
+ const absLeft = parentRect.left + pLeft;
29151
+ const absTop = parentRect.top + pTop;
29152
+ const hasBg = pComputed.backgroundColor && pComputed.backgroundColor !== "rgba(0, 0, 0, 0)";
29153
+ const bgImage = pComputed.backgroundImage;
29154
+ const hasGradient = bgImage && bgImage !== "none" && (bgImage.includes("linear-gradient") || bgImage.includes("radial-gradient"));
29155
+ const hasBgImage = bgImage && bgImage !== "none" && bgImage.includes("url(");
29156
+ if (!hasBg && !hasGradient && !hasBgImage)
29157
+ continue;
29158
+ let gradient = null;
29159
+ if (hasGradient) {
29160
+ gradient = parseCssGradient(bgImage);
29161
+ }
29162
+ const elementOpacity = parseFloat(pComputed.opacity);
29163
+ const hasOpacity = !isNaN(elementOpacity) && elementOpacity < 1;
29164
+ let rectRadius = 0;
29165
+ const borderRadius = pComputed.borderRadius;
29166
+ const radiusValue = parseFloat(borderRadius);
29167
+ if (radiusValue > 0) {
29168
+ if (borderRadius.includes("%")) {
29169
+ if (radiusValue >= 50) {
29170
+ rectRadius = 1;
29171
+ } else {
29172
+ const minDim = Math.min(pWidth, pHeight);
29173
+ rectRadius = radiusValue / 100 * pxToInch(minDim);
29174
+ }
29175
+ } else {
29176
+ rectRadius = pxToInch(radiusValue);
29177
+ }
29178
+ }
29179
+ const shadow = parseBoxShadow(pComputed.boxShadow);
29180
+ const shapeElement = {
29181
+ type: "shape",
29182
+ text: "",
29183
+ textRuns: null,
29184
+ style: null,
29185
+ position: {
29186
+ x: pxToInch(absLeft),
29187
+ y: pxToInch(absTop),
29188
+ w: pxToInch(pWidth),
29189
+ h: pxToInch(pHeight)
29190
+ },
29191
+ shape: {
29192
+ fill: hasBg ? rgbToHex(pComputed.backgroundColor) : null,
29193
+ gradient,
29194
+ transparency: hasBg ? extractAlpha(pComputed.backgroundColor) : null,
29195
+ line: null,
29196
+ rectRadius,
29197
+ shadow,
29198
+ opacity: hasOpacity ? elementOpacity : null,
29199
+ isEllipse: false,
29200
+ softEdge: null
29201
+ }
29202
+ };
29203
+ results.push(shapeElement);
29204
+ }
29205
+ return results;
29206
+ }
28883
29207
  function parseInlineFormatting(element, baseOptions, runs, baseTextTransform, win) {
28884
29208
  let prevNodeIsText = false;
28885
29209
  let pendingSoftBreak = false;
@@ -28906,7 +29230,32 @@ ${generateStylesCss(styleMap, themeFonts)}
28906
29230
  const el = node;
28907
29231
  const options = { ...baseOptions };
28908
29232
  const computed = win.getComputedStyle(el);
28909
- if (el.tagName === "SPAN" || el.tagName === "B" || el.tagName === "STRONG" || el.tagName === "I" || el.tagName === "EM" || el.tagName === "U") {
29233
+ const inlineTags = /* @__PURE__ */ new Set([
29234
+ "SPAN",
29235
+ "B",
29236
+ "STRONG",
29237
+ "I",
29238
+ "EM",
29239
+ "U",
29240
+ "CODE",
29241
+ "A",
29242
+ "MARK",
29243
+ "SUB",
29244
+ "SUP",
29245
+ "SMALL",
29246
+ "S",
29247
+ "DEL",
29248
+ "INS",
29249
+ "ABBR",
29250
+ "TIME",
29251
+ "CITE",
29252
+ "Q",
29253
+ "DFN",
29254
+ "KBD",
29255
+ "SAMP",
29256
+ "VAR"
29257
+ ]);
29258
+ if (inlineTags.has(el.tagName)) {
28910
29259
  const isBold = computed.fontWeight === "bold" || parseInt(computed.fontWeight) >= 600;
28911
29260
  if (isBold && !shouldSkipBold(computed.fontFamily))
28912
29261
  options.bold = true;
@@ -28922,6 +29271,12 @@ ${generateStylesCss(styleMap, themeFonts)}
28922
29271
  }
28923
29272
  if (computed.fontSize)
28924
29273
  options.fontSize = pxToPoints(computed.fontSize);
29274
+ if (computed.fontFamily) {
29275
+ options.fontFace = computed.fontFamily.split(",")[0].replace(/['"]/g, "").trim();
29276
+ }
29277
+ const runLetterSpacing = extractLetterSpacing(computed);
29278
+ if (runLetterSpacing !== null)
29279
+ options.charSpacing = runLetterSpacing;
28925
29280
  if (computed.textTransform && computed.textTransform !== "none") {
28926
29281
  const transformStr = computed.textTransform;
28927
29282
  textTransform = (text) => applyTextTransform(text, transformStr);
@@ -28968,6 +29323,8 @@ ${generateStylesCss(styleMap, themeFonts)}
28968
29323
  const placeholders = [];
28969
29324
  const textTags = ["P", "H1", "H2", "H3", "H4", "H5", "H6", "UL", "OL", "LI", "SPAN"];
28970
29325
  const processed = /* @__PURE__ */ new Set();
29326
+ const bodyPseudoElements = extractPseudoElements(body, win);
29327
+ elements.push(...bodyPseudoElements);
28971
29328
  doc.querySelectorAll("*").forEach((el) => {
28972
29329
  if (processed.has(el))
28973
29330
  return;
@@ -28986,7 +29343,9 @@ ${generateStylesCss(styleMap, themeFonts)}
28986
29343
  const computed2 = win.getComputedStyle(el);
28987
29344
  const hasBg = computed2.backgroundColor && computed2.backgroundColor !== "rgba(0, 0, 0, 0)";
28988
29345
  const hasBorder = computed2.borderWidth && parseFloat(computed2.borderWidth) > 0 || computed2.borderTopWidth && parseFloat(computed2.borderTopWidth) > 0 || computed2.borderRightWidth && parseFloat(computed2.borderRightWidth) > 0 || computed2.borderBottomWidth && parseFloat(computed2.borderBottomWidth) > 0 || computed2.borderLeftWidth && parseFloat(computed2.borderLeftWidth) > 0;
28989
- if (hasBg || hasBorder) {
29346
+ const spanBgImage = computed2.backgroundImage;
29347
+ const hasGradientBg = spanBgImage && spanBgImage !== "none" && (spanBgImage.includes("linear-gradient") || spanBgImage.includes("radial-gradient"));
29348
+ if (hasBg || hasBorder || hasGradientBg) {
28990
29349
  const rect2 = htmlEl.getBoundingClientRect();
28991
29350
  if (rect2.width > 0 && rect2.height > 0) {
28992
29351
  const text2 = el.textContent.trim();
@@ -28994,7 +29353,10 @@ ${generateStylesCss(styleMap, themeFonts)}
28994
29353
  const borderRadius = computed2.borderRadius;
28995
29354
  const radiusValue = parseFloat(borderRadius);
28996
29355
  let rectRadius = 0;
28997
- if (radiusValue > 0) {
29356
+ const isCircularRadius = borderRadius.includes("%") ? radiusValue >= 50 : radiusValue > 0 && radiusValue >= Math.min(rect2.width, rect2.height) / 2 - 1;
29357
+ const aspectRatio = rect2.width / rect2.height;
29358
+ const spanIsEllipse = isCircularRadius && aspectRatio > 0.5 && aspectRatio < 2;
29359
+ if (radiusValue > 0 && !spanIsEllipse) {
28998
29360
  if (borderRadius.includes("%")) {
28999
29361
  const minDim = Math.min(rect2.width, rect2.height);
29000
29362
  rectRadius = radiusValue / 100 * pxToInch(minDim);
@@ -29007,6 +29369,9 @@ ${generateStylesCss(styleMap, themeFonts)}
29007
29369
  const borderBottom = computed2.borderBottomWidth;
29008
29370
  const borderLeft = computed2.borderLeftWidth;
29009
29371
  const hasUniformBorder = hasBorder && borderTop === borderRight && borderRight === borderBottom && borderBottom === borderLeft;
29372
+ const spanOpacity = parseFloat(computed2.opacity);
29373
+ const hasSpanOpacity = !isNaN(spanOpacity) && spanOpacity < 1;
29374
+ const spanShadow = parseBoxShadow(computed2.boxShadow);
29010
29375
  const shapeElement = {
29011
29376
  type: "shape",
29012
29377
  position: {
@@ -29017,24 +29382,28 @@ ${generateStylesCss(styleMap, themeFonts)}
29017
29382
  },
29018
29383
  text: text2,
29019
29384
  textRuns: null,
29020
- style: {
29385
+ style: text2 ? {
29021
29386
  fontSize: pxToPoints(computed2.fontSize),
29022
29387
  fontFace: computed2.fontFamily.split(",")[0].replace(/['"]/g, "").trim(),
29023
29388
  color: rgbToHex(computed2.color),
29024
29389
  bold: parseInt(computed2.fontWeight) >= 600,
29025
29390
  align: "center",
29026
29391
  valign: "middle"
29027
- },
29392
+ } : null,
29028
29393
  shape: {
29029
29394
  fill: hasBg ? rgbToHex(computed2.backgroundColor) : null,
29030
29395
  gradient: bgGradient,
29031
- transparency: null,
29396
+ transparency: hasBg ? extractAlpha(computed2.backgroundColor) : null,
29032
29397
  line: hasUniformBorder ? {
29033
29398
  color: rgbToHex(computed2.borderColor),
29034
- width: pxToPoints(borderTop)
29399
+ width: pxToPoints(borderTop),
29400
+ transparency: extractAlpha(computed2.borderColor)
29035
29401
  } : null,
29036
- rectRadius,
29037
- shadow: null
29402
+ rectRadius: spanIsEllipse ? 0 : rectRadius,
29403
+ shadow: spanShadow,
29404
+ opacity: hasSpanOpacity ? spanOpacity : null,
29405
+ isEllipse: spanIsEllipse,
29406
+ softEdge: null
29038
29407
  }
29039
29408
  };
29040
29409
  elements.push(shapeElement);
@@ -29104,47 +29473,198 @@ ${generateStylesCss(styleMap, themeFonts)}
29104
29473
  const isFullSlideImage = coversWidth && coversHeight && nearOrigin;
29105
29474
  const objectFit = imgComputed.objectFit;
29106
29475
  let imgRectRadius = null;
29476
+ let clipLeft = rect2.left;
29477
+ let clipTop = rect2.top;
29478
+ let clipRight = rect2.right;
29479
+ let clipBottom = rect2.bottom;
29107
29480
  let ancestor = el.parentElement;
29108
29481
  while (ancestor && ancestor !== doc.body) {
29109
29482
  const ancestorComputed = win.getComputedStyle(ancestor);
29110
29483
  const ancestorOverflow = ancestorComputed.overflow;
29111
- const ancestorBorderRadius = ancestorComputed.borderRadius;
29112
- if ((ancestorOverflow === "hidden" || ancestorOverflow === "clip") && ancestorBorderRadius) {
29113
- const radiusValue = parseFloat(ancestorBorderRadius);
29114
- if (radiusValue > 0) {
29115
- if (ancestorBorderRadius.includes("%")) {
29116
- const ancestorRect = ancestor.getBoundingClientRect();
29117
- const minDim = Math.min(ancestorRect.width, ancestorRect.height);
29118
- imgRectRadius = radiusValue / 100 * pxToInch(minDim);
29119
- } else if (ancestorBorderRadius.includes("pt")) {
29120
- imgRectRadius = radiusValue / 72;
29121
- } else {
29122
- imgRectRadius = pxToInch(radiusValue);
29484
+ if (ancestorOverflow === "hidden" || ancestorOverflow === "clip") {
29485
+ const ancestorRect = ancestor.getBoundingClientRect();
29486
+ clipLeft = Math.max(clipLeft, ancestorRect.left);
29487
+ clipTop = Math.max(clipTop, ancestorRect.top);
29488
+ clipRight = Math.min(clipRight, ancestorRect.right);
29489
+ clipBottom = Math.min(clipBottom, ancestorRect.bottom);
29490
+ const ancestorBorderRadius = ancestorComputed.borderRadius;
29491
+ if (ancestorBorderRadius && imgRectRadius === null) {
29492
+ const radiusValue = parseFloat(ancestorBorderRadius);
29493
+ if (radiusValue > 0) {
29494
+ if (ancestorBorderRadius.includes("%")) {
29495
+ const minDim = Math.min(ancestorRect.width, ancestorRect.height);
29496
+ imgRectRadius = radiusValue / 100 * pxToInch(minDim);
29497
+ } else if (ancestorBorderRadius.includes("pt")) {
29498
+ imgRectRadius = radiusValue / 72;
29499
+ } else {
29500
+ imgRectRadius = pxToInch(radiusValue);
29501
+ }
29123
29502
  }
29124
- break;
29125
29503
  }
29126
29504
  }
29127
29505
  ancestor = ancestor.parentElement;
29128
29506
  }
29507
+ const clippedW = Math.max(0, clipRight - clipLeft);
29508
+ const clippedH = Math.max(0, clipBottom - clipTop);
29509
+ const wasClipped = clippedW < rect2.width - 1 || clippedH < rect2.height - 1;
29510
+ const cssFilter = imgComputed.filter;
29511
+ let imgSrc = el.src;
29512
+ let filterPreBaked = false;
29513
+ if (cssFilter && cssFilter !== "none") {
29514
+ const bakedSrc = applyImageFilter(el, cssFilter);
29515
+ if (bakedSrc !== imgSrc) {
29516
+ imgSrc = bakedSrc;
29517
+ filterPreBaked = true;
29518
+ }
29519
+ }
29520
+ const maskImageProp = imgComputed.maskImage || imgComputed.webkitMaskImage || imgComputed.getPropertyValue("mask-image") || imgComputed.getPropertyValue("-webkit-mask-image");
29521
+ const imgOpacity = parseFloat(imgComputed.opacity);
29522
+ const hasOpacity = !isNaN(imgOpacity) && imgOpacity < 1 && imgOpacity >= 0;
29523
+ let maskApplied = false;
29524
+ if (maskImageProp && maskImageProp !== "none" && (maskImageProp.includes("linear-gradient") || maskImageProp.includes("radial-gradient"))) {
29525
+ const maskGradient = parseCssGradient(maskImageProp);
29526
+ if (maskGradient) {
29527
+ const displayW = wasClipped ? clippedW : rect2.width;
29528
+ const displayH = wasClipped ? clippedH : rect2.height;
29529
+ const maskedSrc = applyImageMask(el, maskGradient, displayW, displayH, hasOpacity ? imgOpacity : void 0);
29530
+ if (maskedSrc) {
29531
+ imgSrc = maskedSrc;
29532
+ maskApplied = true;
29533
+ }
29534
+ }
29535
+ }
29536
+ const imgEl = el;
29537
+ const natW = imgEl.naturalWidth;
29538
+ const natH = imgEl.naturalHeight;
29129
29539
  const imageElement = {
29130
29540
  type: isFullSlideImage ? "slideBackgroundImage" : "image",
29131
- src: el.src,
29541
+ src: imgSrc,
29132
29542
  position: {
29133
- x: pxToInch(rect2.left),
29134
- y: pxToInch(rect2.top),
29135
- w: pxToInch(rect2.width),
29136
- h: pxToInch(rect2.height)
29543
+ x: pxToInch(wasClipped ? clipLeft : rect2.left),
29544
+ y: pxToInch(wasClipped ? clipTop : rect2.top),
29545
+ w: pxToInch(wasClipped ? clippedW : rect2.width),
29546
+ h: pxToInch(wasClipped ? clippedH : rect2.height)
29137
29547
  },
29138
29548
  sizing: objectFit === "cover" ? { type: "cover" } : null
29139
29549
  };
29550
+ if (objectFit === "cover" && natW > 0 && natH > 0 && !isFullSlideImage) {
29551
+ imageElement.naturalWidth = natW;
29552
+ imageElement.naturalHeight = natH;
29553
+ }
29140
29554
  if (imgRectRadius !== null) {
29141
29555
  imageElement.rectRadius = imgRectRadius;
29142
29556
  }
29557
+ if (!filterPreBaked && cssFilter && cssFilter !== "none") {
29558
+ const filterValues = parseCssFilter(cssFilter);
29559
+ if (filterValues) {
29560
+ if (filterValues.brightness !== void 0) {
29561
+ imageElement.brightness = filterValues.brightness;
29562
+ }
29563
+ if (filterValues.contrast !== void 0) {
29564
+ imageElement.contrast = filterValues.contrast;
29565
+ }
29566
+ if (filterValues.saturation !== void 0) {
29567
+ imageElement.saturation = filterValues.saturation;
29568
+ }
29569
+ }
29570
+ }
29571
+ if (hasOpacity && !maskApplied) {
29572
+ imageElement.transparency = Math.round((1 - imgOpacity) * 100);
29573
+ }
29574
+ elements.push(imageElement);
29575
+ processed.add(el);
29576
+ return;
29577
+ }
29578
+ }
29579
+ if (el.tagName === "svg") {
29580
+ const rect2 = htmlEl.getBoundingClientRect();
29581
+ if (rect2.width > 0 && rect2.height > 0) {
29582
+ const computedStyle = win.getComputedStyle(htmlEl);
29583
+ const opacity = parseFloat(computedStyle.opacity || "1");
29584
+ if (opacity < 0.1) {
29585
+ processed.add(el);
29586
+ el.querySelectorAll("*").forEach((child) => processed.add(child));
29587
+ return;
29588
+ }
29589
+ const svgEl = el;
29590
+ const hasFilter = svgEl.querySelector("filter, pattern");
29591
+ const hasRenderableContent = svgEl.querySelector("path, circle, ellipse, line, polyline, polygon, text, image");
29592
+ const allRects = svgEl.querySelectorAll("rect");
29593
+ const hasRectWithoutFilter = Array.from(allRects).some((r) => !r.getAttribute("filter")?.startsWith("url("));
29594
+ const hasOnlyFilterPattern = hasFilter && !hasRenderableContent && !hasRectWithoutFilter;
29595
+ if (hasOnlyFilterPattern) {
29596
+ processed.add(el);
29597
+ el.querySelectorAll("*").forEach((child) => processed.add(child));
29598
+ return;
29599
+ }
29600
+ const usesFilterRef = svgEl.querySelector('[filter^="url("]');
29601
+ if (hasFilter && usesFilterRef && !hasRenderableContent) {
29602
+ processed.add(el);
29603
+ el.querySelectorAll("*").forEach((child) => processed.add(child));
29604
+ return;
29605
+ }
29606
+ const svgClone = el.cloneNode(true);
29607
+ if (!svgClone.hasAttribute("xmlns")) {
29608
+ svgClone.setAttribute("xmlns", "http://www.w3.org/2000/svg");
29609
+ }
29610
+ svgClone.setAttribute("width", String(rect2.width));
29611
+ svgClone.setAttribute("height", String(rect2.height));
29612
+ const computedColor = win.getComputedStyle(htmlEl).color;
29613
+ const rootStyles = win.getComputedStyle(doc.documentElement);
29614
+ const resolveColorValue = (value) => {
29615
+ if (!value)
29616
+ return null;
29617
+ if (value === "currentColor") {
29618
+ return computedColor || null;
29619
+ }
29620
+ const varMatch = value.match(/^var\(\s*(--[\w-]+)(?:\s*,\s*(.+))?\s*\)$/);
29621
+ if (varMatch) {
29622
+ const propName = varMatch[1];
29623
+ const fallback = varMatch[2];
29624
+ const resolvedValue = rootStyles.getPropertyValue(propName).trim();
29625
+ return resolvedValue || fallback || null;
29626
+ }
29627
+ return null;
29628
+ };
29629
+ const resolveDynamicColors = (element) => {
29630
+ const fill = element.getAttribute("fill");
29631
+ const resolvedFill = resolveColorValue(fill);
29632
+ if (resolvedFill) {
29633
+ element.setAttribute("fill", resolvedFill);
29634
+ }
29635
+ const stroke = element.getAttribute("stroke");
29636
+ const resolvedStroke = resolveColorValue(stroke);
29637
+ if (resolvedStroke) {
29638
+ element.setAttribute("stroke", resolvedStroke);
29639
+ }
29640
+ element.querySelectorAll("*").forEach(resolveDynamicColors);
29641
+ };
29642
+ resolveDynamicColors(svgClone);
29643
+ const serializer = new XMLSerializer();
29644
+ const svgString = serializer.serializeToString(svgClone);
29645
+ const svgBase64 = btoa(unescape(encodeURIComponent(svgString)));
29646
+ const dataUri = `data:image/svg+xml;base64,${svgBase64}`;
29647
+ const imageElement = {
29648
+ type: "image",
29649
+ src: dataUri,
29650
+ position: {
29651
+ x: pxToInch(rect2.left),
29652
+ y: pxToInch(rect2.top),
29653
+ w: pxToInch(rect2.width),
29654
+ h: pxToInch(rect2.height)
29655
+ },
29656
+ sizing: null
29657
+ };
29143
29658
  elements.push(imageElement);
29144
29659
  processed.add(el);
29660
+ el.querySelectorAll("*").forEach((child) => processed.add(child));
29145
29661
  return;
29146
29662
  }
29147
29663
  }
29664
+ if (el.tagName === "I") {
29665
+ processed.add(el);
29666
+ return;
29667
+ }
29148
29668
  const isContainer = el.tagName === "DIV" && !textTags.includes(el.tagName);
29149
29669
  if (isContainer) {
29150
29670
  const computed2 = win.getComputedStyle(el);
@@ -29180,7 +29700,7 @@ ${generateStylesCss(styleMap, themeFonts)}
29180
29700
  const y2 = pxToInch(rect2.top);
29181
29701
  const w2 = pxToInch(rect2.width);
29182
29702
  const h2 = pxToInch(rect2.height);
29183
- if (parseFloat(borderTop) > 0) {
29703
+ if (parseFloat(borderTop) > 0 && !isFullyTransparent(computed2.borderTopColor)) {
29184
29704
  const widthPt = pxToPoints(borderTop);
29185
29705
  const inset = widthPt / 72 / 2;
29186
29706
  borderLines.push({
@@ -29190,10 +29710,11 @@ ${generateStylesCss(styleMap, themeFonts)}
29190
29710
  x2: x2 + w2,
29191
29711
  y2: y2 + inset,
29192
29712
  width: widthPt,
29193
- color: rgbToHex(computed2.borderTopColor)
29713
+ color: rgbToHex(computed2.borderTopColor),
29714
+ transparency: extractAlpha(computed2.borderTopColor)
29194
29715
  });
29195
29716
  }
29196
- if (parseFloat(borderRight) > 0) {
29717
+ if (parseFloat(borderRight) > 0 && !isFullyTransparent(computed2.borderRightColor)) {
29197
29718
  const widthPt = pxToPoints(borderRight);
29198
29719
  const inset = widthPt / 72 / 2;
29199
29720
  borderLines.push({
@@ -29203,10 +29724,11 @@ ${generateStylesCss(styleMap, themeFonts)}
29203
29724
  x2: x2 + w2 - inset,
29204
29725
  y2: y2 + h2,
29205
29726
  width: widthPt,
29206
- color: rgbToHex(computed2.borderRightColor)
29727
+ color: rgbToHex(computed2.borderRightColor),
29728
+ transparency: extractAlpha(computed2.borderRightColor)
29207
29729
  });
29208
29730
  }
29209
- if (parseFloat(borderBottom) > 0) {
29731
+ if (parseFloat(borderBottom) > 0 && !isFullyTransparent(computed2.borderBottomColor)) {
29210
29732
  const widthPt = pxToPoints(borderBottom);
29211
29733
  const inset = widthPt / 72 / 2;
29212
29734
  borderLines.push({
@@ -29216,10 +29738,11 @@ ${generateStylesCss(styleMap, themeFonts)}
29216
29738
  x2: x2 + w2,
29217
29739
  y2: y2 + h2 - inset,
29218
29740
  width: widthPt,
29219
- color: rgbToHex(computed2.borderBottomColor)
29741
+ color: rgbToHex(computed2.borderBottomColor),
29742
+ transparency: extractAlpha(computed2.borderBottomColor)
29220
29743
  });
29221
29744
  }
29222
- if (parseFloat(borderLeft) > 0) {
29745
+ if (parseFloat(borderLeft) > 0 && !isFullyTransparent(computed2.borderLeftColor)) {
29223
29746
  const widthPt = pxToPoints(borderLeft);
29224
29747
  const inset = widthPt / 72 / 2;
29225
29748
  borderLines.push({
@@ -29229,7 +29752,8 @@ ${generateStylesCss(styleMap, themeFonts)}
29229
29752
  x2: x2 + inset,
29230
29753
  y2: y2 + h2,
29231
29754
  width: widthPt,
29232
- color: rgbToHex(computed2.borderLeftColor)
29755
+ color: rgbToHex(computed2.borderLeftColor),
29756
+ transparency: extractAlpha(computed2.borderLeftColor)
29233
29757
  });
29234
29758
  }
29235
29759
  }
@@ -29254,16 +29778,47 @@ ${generateStylesCss(styleMap, themeFonts)}
29254
29778
  };
29255
29779
  elements.push(bgImgElement);
29256
29780
  }
29257
- const textChildren = Array.from(el.children).filter((child) => ["P", "H1", "H2", "H3", "H4", "H5", "H6", "SPAN"].includes(child.tagName));
29258
- const nonTextChildren = Array.from(el.children).filter((child) => !["P", "H1", "H2", "H3", "H4", "H5", "H6", "SPAN"].includes(child.tagName));
29259
- const isSingleTextChild = textChildren.length === 1 && textChildren[0].children.length === 0 && nonTextChildren.length === 0;
29781
+ const textTagSet = /* @__PURE__ */ new Set(["P", "H1", "H2", "H3", "H4", "H5", "H6", "SPAN"]);
29782
+ const allChildren = Array.from(el.children);
29783
+ const textChildren = allChildren.filter((child) => {
29784
+ if (textTagSet.has(child.tagName))
29785
+ return true;
29786
+ if (child.tagName === "DIV") {
29787
+ const childElements = Array.from(child.children);
29788
+ const isTextOnlyDiv = childElements.length === 0 || childElements.every((ce) => ce.tagName === "BR") || childElements.length === 1 && childElements[0].tagName === "P" && childElements[0].children.length === 0;
29789
+ if (!isTextOnlyDiv)
29790
+ return false;
29791
+ const childText = child.textContent?.trim();
29792
+ if (!childText)
29793
+ return false;
29794
+ const childComputed = win.getComputedStyle(child);
29795
+ const childHasBg = childComputed.backgroundColor && childComputed.backgroundColor !== "rgba(0, 0, 0, 0)";
29796
+ const childHasBgImg = childComputed.backgroundImage && childComputed.backgroundImage !== "none";
29797
+ const childBorders = [
29798
+ childComputed.borderTopWidth,
29799
+ childComputed.borderRightWidth,
29800
+ childComputed.borderBottomWidth,
29801
+ childComputed.borderLeftWidth
29802
+ ].map((b) => parseFloat(b) || 0);
29803
+ const childHasBorder = childBorders.some((b) => b > 0);
29804
+ return !childHasBg && !childHasBgImg && !childHasBorder;
29805
+ }
29806
+ return false;
29807
+ });
29808
+ const decorativeTags = /* @__PURE__ */ new Set(["I", "SVG", "CANVAS", "VIDEO", "AUDIO", "IFRAME"]);
29809
+ const nonTextChildren = allChildren.filter((child) => !textTagSet.has(child.tagName) && !decorativeTags.has(child.tagName) && !(child.tagName === "DIV" && textChildren.includes(child)));
29810
+ const isSingleTextChild = textChildren.length === 1 && (() => {
29811
+ const tc = textChildren[0];
29812
+ const tcChildren = Array.from(tc.children);
29813
+ return tcChildren.length === 0 || tcChildren.every((ce) => ce.tagName === "BR") || tcChildren.length === 1 && tcChildren[0].tagName === "P" && tcChildren[0].children.length === 0;
29814
+ })() && nonTextChildren.length === 0;
29260
29815
  const display = computed2.display;
29261
- const isFlexContainer = display === "flex" || display === "inline-flex";
29816
+ const isFlexContainer2 = display === "flex" || display === "inline-flex";
29262
29817
  const alignItems = computed2.alignItems;
29263
29818
  const justifyContent = computed2.justifyContent;
29264
29819
  let valign2 = "top";
29265
29820
  let align = "left";
29266
- if (isFlexContainer) {
29821
+ if (isFlexContainer2) {
29267
29822
  const flexDirection = computed2.flexDirection || "row";
29268
29823
  if (flexDirection === "row" || flexDirection === "row-reverse") {
29269
29824
  if (alignItems === "center")
@@ -29312,8 +29867,9 @@ ${generateStylesCss(styleMap, themeFonts)}
29312
29867
  let shapeText = "";
29313
29868
  let shapeTextRuns = null;
29314
29869
  let shapeStyle = null;
29315
- const hasTextChildren = textChildren.length > 0 && nonTextChildren.length === 0;
29316
- if (hasTextChildren) {
29870
+ const hasTextChildren = textChildren.length > 0;
29871
+ const shouldMergeText = hasTextChildren && (isSingleTextChild || nonTextChildren.length === 0);
29872
+ if (shouldMergeText) {
29317
29873
  if (isSingleTextChild) {
29318
29874
  const textEl = textChildren[0];
29319
29875
  const textComputed = win.getComputedStyle(textEl);
@@ -29357,31 +29913,71 @@ ${generateStylesCss(styleMap, themeFonts)}
29357
29913
  inset: 0,
29358
29914
  wrap: !shouldNotWrap
29359
29915
  };
29916
+ const shapeLetterSpacing = extractLetterSpacing(textComputed);
29917
+ if (shapeLetterSpacing !== null)
29918
+ shapeStyle.charSpacing = shapeLetterSpacing;
29919
+ const shapeTextShadow = parseTextShadow(textComputed.textShadow);
29920
+ if (shapeTextShadow.glow)
29921
+ shapeStyle.glow = shapeTextShadow.glow;
29922
+ if (shapeTextShadow.shadow)
29923
+ shapeStyle.textShadow = shapeTextShadow.shadow;
29360
29924
  processed.add(textEl);
29925
+ textEl.querySelectorAll("*").forEach((desc) => processed.add(desc));
29361
29926
  } else {
29362
29927
  shapeTextRuns = [];
29363
29928
  textChildren.forEach((textChild, idx) => {
29364
29929
  const textEl = textChild;
29365
29930
  const textComputed = win.getComputedStyle(textEl);
29366
- const text2 = textEl.textContent.trim();
29367
- if (!text2)
29931
+ const fullText = textEl.textContent.trim();
29932
+ if (!fullText)
29368
29933
  return;
29369
29934
  const isBold = textComputed.fontWeight === "bold" || parseInt(textComputed.fontWeight) >= 600;
29370
29935
  const isItalic = textComputed.fontStyle === "italic";
29371
29936
  const isUnderline = textComputed.textDecoration && textComputed.textDecoration.includes("underline");
29372
- const runText = idx > 0 && shapeTextRuns.length > 0 ? " " + text2 : text2;
29373
- shapeTextRuns.push({
29374
- text: runText,
29375
- options: {
29376
- fontSize: pxToPoints(textComputed.fontSize),
29377
- fontFace: textComputed.fontFamily.split(",")[0].replace(/['"]/g, "").trim(),
29378
- color: rgbToHex(textComputed.color),
29379
- bold: isBold,
29380
- italic: isItalic,
29381
- underline: isUnderline || false
29937
+ const baseRunOptions = {
29938
+ fontSize: pxToPoints(textComputed.fontSize),
29939
+ fontFace: textComputed.fontFamily.split(",")[0].replace(/['"]/g, "").trim(),
29940
+ color: rgbToHex(textComputed.color),
29941
+ bold: isBold,
29942
+ italic: isItalic,
29943
+ underline: isUnderline || false,
29944
+ ...extractLetterSpacing(textComputed) !== null ? { charSpacing: extractLetterSpacing(textComputed) } : {},
29945
+ ...(() => {
29946
+ const ts = parseTextShadow(textComputed.textShadow);
29947
+ return ts.glow ? { glow: ts.glow } : {};
29948
+ })()
29949
+ };
29950
+ const hasBrChildren = textEl.querySelector("br") !== null;
29951
+ if (hasBrChildren) {
29952
+ let segments = [];
29953
+ let currentSegment = "";
29954
+ for (const node of Array.from(textEl.childNodes)) {
29955
+ if (node.tagName === "BR") {
29956
+ segments.push(currentSegment.trim());
29957
+ currentSegment = "";
29958
+ } else {
29959
+ currentSegment += node.textContent || "";
29960
+ }
29382
29961
  }
29383
- });
29962
+ if (currentSegment.trim())
29963
+ segments.push(currentSegment.trim());
29964
+ segments = segments.filter((s) => s.length > 0);
29965
+ segments.forEach((segment, segIdx) => {
29966
+ const prefix = segIdx === 0 && idx > 0 && shapeTextRuns.length > 0 ? "\n" : "";
29967
+ const runText = prefix + segment;
29968
+ const options = { ...baseRunOptions };
29969
+ if (segIdx > 0) {
29970
+ options.softBreakBefore = true;
29971
+ }
29972
+ shapeTextRuns.push({ text: runText, options });
29973
+ });
29974
+ } else {
29975
+ const runText = idx > 0 && shapeTextRuns.length > 0 ? "\n" + fullText : fullText;
29976
+ const options = idx > 0 && shapeTextRuns.length > 0 ? { ...baseRunOptions, breakLine: true } : baseRunOptions;
29977
+ shapeTextRuns.push({ text: runText, options });
29978
+ }
29384
29979
  processed.add(textEl);
29980
+ textEl.querySelectorAll("*").forEach((desc) => processed.add(desc));
29385
29981
  });
29386
29982
  shapeStyle = {
29387
29983
  align,
@@ -29391,6 +29987,29 @@ ${generateStylesCss(styleMap, themeFonts)}
29391
29987
  }
29392
29988
  }
29393
29989
  if (hasBg || hasUniformBorder || bgGradient) {
29990
+ const elementOpacity = parseFloat(computed2.opacity);
29991
+ const hasOpacity = !isNaN(elementOpacity) && elementOpacity < 1;
29992
+ let softEdgePt = null;
29993
+ const filterStr = computed2.filter;
29994
+ if (filterStr && filterStr !== "none") {
29995
+ const blurMatch = filterStr.match(/blur\(([\d.]+)px\)/);
29996
+ if (blurMatch) {
29997
+ const blurPx = parseFloat(blurMatch[1]);
29998
+ if (blurPx > 0) {
29999
+ softEdgePt = blurPx * PT_PER_PX;
30000
+ }
30001
+ }
30002
+ }
30003
+ const borderRadiusStr = computed2.borderRadius;
30004
+ const borderRadiusVal = parseFloat(borderRadiusStr);
30005
+ const isCircularRadius = borderRadiusStr.includes("%") ? borderRadiusVal >= 50 : borderRadiusVal > 0 && borderRadiusVal >= Math.min(rect2.width, rect2.height) / 2 - 1;
30006
+ const aspectRatio = rect2.width / rect2.height;
30007
+ const isEllipse = isCircularRadius && aspectRatio > 0.5 && aspectRatio < 2;
30008
+ const paddingTop = parseFloat(computed2.paddingTop) || 0;
30009
+ const paddingRight = parseFloat(computed2.paddingRight) || 0;
30010
+ const paddingBottom = parseFloat(computed2.paddingBottom) || 0;
30011
+ const paddingLeft = parseFloat(computed2.paddingLeft) || 0;
30012
+ const hasPadding = paddingTop > 2 || paddingRight > 2 || paddingBottom > 2 || paddingLeft > 2;
29394
30013
  const shapeElement = {
29395
30014
  type: "shape",
29396
30015
  text: shapeText,
@@ -29408,9 +30027,12 @@ ${generateStylesCss(styleMap, themeFonts)}
29408
30027
  transparency: hasBg ? extractAlpha(computed2.backgroundColor) : null,
29409
30028
  line: hasUniformBorder ? {
29410
30029
  color: rgbToHex(computed2.borderColor),
29411
- width: pxToPoints(computed2.borderWidth)
30030
+ width: pxToPoints(computed2.borderWidth),
30031
+ transparency: extractAlpha(computed2.borderColor)
29412
30032
  } : null,
29413
30033
  rectRadius: (() => {
30034
+ if (isEllipse)
30035
+ return 0;
29414
30036
  const radius = computed2.borderRadius;
29415
30037
  const radiusValue = parseFloat(radius);
29416
30038
  if (radiusValue === 0)
@@ -29425,9 +30047,24 @@ ${generateStylesCss(styleMap, themeFonts)}
29425
30047
  return radiusValue / 72;
29426
30048
  return radiusValue / PX_PER_IN;
29427
30049
  })(),
29428
- shadow
30050
+ shadow,
30051
+ opacity: hasOpacity ? elementOpacity : null,
30052
+ isEllipse,
30053
+ softEdge: softEdgePt
29429
30054
  }
29430
30055
  };
30056
+ if (hasPadding && shapeElement.style && (shapeText || shapeTextRuns && shapeTextRuns.length > 0)) {
30057
+ shapeElement.style.margin = [
30058
+ paddingLeft * PT_PER_PX,
30059
+ // left
30060
+ paddingRight * PT_PER_PX,
30061
+ // right
30062
+ paddingBottom * PT_PER_PX,
30063
+ // bottom
30064
+ paddingTop * PT_PER_PX
30065
+ // top
30066
+ ];
30067
+ }
29431
30068
  elements.push(shapeElement);
29432
30069
  } else if (shapeStyle && shapeStyle.fontFill) {
29433
30070
  const fontFillTextElement = {
@@ -29450,6 +30087,60 @@ ${generateStylesCss(styleMap, themeFonts)}
29450
30087
  return;
29451
30088
  }
29452
30089
  }
30090
+ if (isContainer) {
30091
+ const rect2 = htmlEl.getBoundingClientRect();
30092
+ if (rect2.width > 0 && rect2.height > 0) {
30093
+ let directText = "";
30094
+ for (const child of Array.from(el.childNodes)) {
30095
+ if (child.nodeType === Node.TEXT_NODE) {
30096
+ directText += child.textContent || "";
30097
+ }
30098
+ }
30099
+ directText = directText.trim();
30100
+ const childElements = Array.from(el.children);
30101
+ if (!directText && childElements.length === 1 && childElements[0].tagName === "P" && childElements[0].children.length === 0) {
30102
+ directText = childElements[0].textContent?.trim() || "";
30103
+ }
30104
+ const hasStructuralChildren = childElements.length > 0 && !childElements.every((ce) => ce.tagName === "BR") && !(childElements.length === 1 && childElements[0].tagName === "P" && childElements[0].children.length === 0);
30105
+ if (directText && !hasStructuralChildren) {
30106
+ const computed22 = win.getComputedStyle(el);
30107
+ const fontSizePx2 = parseFloat(computed22.fontSize);
30108
+ const lineHeightPx2 = parseFloat(computed22.lineHeight);
30109
+ const lineHeightMultiplier2 = fontSizePx2 > 0 && !isNaN(lineHeightPx2) ? lineHeightPx2 / fontSizePx2 : 1;
30110
+ const textElement = {
30111
+ type: "p",
30112
+ text: [{ text: directText, options: {} }],
30113
+ position: {
30114
+ x: pxToInch(rect2.left),
30115
+ y: pxToInch(rect2.top),
30116
+ w: pxToInch(rect2.width),
30117
+ h: pxToInch(rect2.height)
30118
+ },
30119
+ style: {
30120
+ fontSize: pxToPoints(computed22.fontSize),
30121
+ fontFace: computed22.fontFamily.split(",")[0].replace(/['"]/g, "").trim(),
30122
+ color: rgbToHex(computed22.color),
30123
+ bold: parseInt(computed22.fontWeight) >= 600,
30124
+ italic: computed22.fontStyle === "italic",
30125
+ align: computed22.textAlign === "center" ? "center" : computed22.textAlign === "right" || computed22.textAlign === "end" ? "right" : "left",
30126
+ valign: "middle",
30127
+ lineSpacing: lineHeightMultiplier2 * pxToPoints(computed22.fontSize)
30128
+ }
30129
+ };
30130
+ const textTransparency = extractAlpha(computed22.color);
30131
+ if (textTransparency !== null) {
30132
+ textElement.style.transparency = textTransparency;
30133
+ }
30134
+ const ls = extractLetterSpacing(computed22);
30135
+ if (ls !== null)
30136
+ textElement.style.charSpacing = ls;
30137
+ elements.push(textElement);
30138
+ processed.add(el);
30139
+ el.querySelectorAll("*").forEach((desc) => processed.add(desc));
30140
+ return;
30141
+ }
30142
+ }
30143
+ }
29453
30144
  }
29454
30145
  if (el.tagName === "UL" || el.tagName === "OL") {
29455
30146
  const rect2 = htmlEl.getBoundingClientRect();
@@ -29461,12 +30152,23 @@ ${generateStylesCss(styleMap, themeFonts)}
29461
30152
  const ulPaddingLeftPt = pxToPoints(ulComputed.paddingLeft);
29462
30153
  const marginLeft = ulPaddingLeftPt * 0.5;
29463
30154
  const textIndent = ulPaddingLeftPt * 0.5;
30155
+ const listStyleType = ulComputed.listStyleType;
30156
+ const hasNativeBullets = listStyleType !== "none";
30157
+ const hasFlexLiItems = liElements.some((li) => {
30158
+ const liComputed2 = win.getComputedStyle(li);
30159
+ return liComputed2.display === "flex" || liComputed2.display === "inline-flex";
30160
+ });
30161
+ if (hasFlexLiItems && !hasNativeBullets) {
30162
+ return;
30163
+ }
29464
30164
  liElements.forEach((li, idx) => {
29465
30165
  const isLast = idx === liElements.length - 1;
29466
30166
  const runs = parseInlineFormatting(li, { breakLine: false }, [], (x2) => x2, win);
29467
30167
  if (runs.length > 0) {
29468
30168
  runs[0].text = runs[0].text.replace(/^[•\-\*\u25AA\u25B8]\s*/, "");
29469
- runs[0].options.bullet = { indent: textIndent };
30169
+ if (hasNativeBullets) {
30170
+ runs[0].options.bullet = { indent: textIndent };
30171
+ }
29470
30172
  }
29471
30173
  if (runs.length > 0 && !isLast) {
29472
30174
  runs[runs.length - 1].options.breakLine = true;
@@ -29505,15 +30207,34 @@ ${generateStylesCss(styleMap, themeFonts)}
29505
30207
  }
29506
30208
  if (!textTags.includes(el.tagName) || el.tagName === "SPAN")
29507
30209
  return;
29508
- const rect = htmlEl.getBoundingClientRect();
29509
- const text = el.textContent.trim();
30210
+ let rect = htmlEl.getBoundingClientRect();
30211
+ let text = el.textContent.trim();
29510
30212
  if (rect.width === 0 || rect.height === 0 || !text)
29511
30213
  return;
30214
+ const computed = win.getComputedStyle(el);
30215
+ const isFlexContainer = computed.display === "flex" || computed.display === "inline-flex";
30216
+ if (isFlexContainer && el.children.length > 0) {
30217
+ const textNodes = [];
30218
+ el.childNodes.forEach((node) => {
30219
+ if (node.nodeType === Node.TEXT_NODE && node.textContent.trim()) {
30220
+ textNodes.push(node);
30221
+ }
30222
+ });
30223
+ if (textNodes.length > 0) {
30224
+ const range2 = doc.createRange();
30225
+ range2.setStartBefore(textNodes[0]);
30226
+ range2.setEndAfter(textNodes[textNodes.length - 1]);
30227
+ const textRect = range2.getBoundingClientRect();
30228
+ if (textRect.width > 0 && textRect.height > 0) {
30229
+ rect = textRect;
30230
+ text = textNodes.map((n) => n.textContent.trim()).join(" ").trim();
30231
+ }
30232
+ }
30233
+ }
29512
30234
  if (el.tagName !== "LI" && /^[•\-\*\u25AA\u25B8\u25CB\u25CF\u25C6\u25C7\u25A0\u25A1]\s/.test(text.trimStart())) {
29513
30235
  errors.push(`Text element <${el.tagName.toLowerCase()}> starts with bullet symbol "${text.substring(0, 20)}...". Use <ul> or <ol> lists instead of manual bullet symbols.`);
29514
30236
  return;
29515
30237
  }
29516
- const computed = win.getComputedStyle(el);
29517
30238
  const rotation = getRotation(computed.transform, computed.writingMode);
29518
30239
  const { x, y, w, h } = getPositionAndSize(htmlEl, rect, rotation);
29519
30240
  const fontSizePx = parseFloat(computed.fontSize);
@@ -29564,6 +30285,14 @@ ${generateStylesCss(styleMap, themeFonts)}
29564
30285
  const transparency = extractAlpha(computed.color);
29565
30286
  if (transparency !== null)
29566
30287
  baseStyle.transparency = transparency;
30288
+ const letterSpacing = extractLetterSpacing(computed);
30289
+ if (letterSpacing !== null)
30290
+ baseStyle.charSpacing = letterSpacing;
30291
+ const textShadowResult = parseTextShadow(computed.textShadow);
30292
+ if (textShadowResult.glow)
30293
+ baseStyle.glow = textShadowResult.glow;
30294
+ if (textShadowResult.shadow)
30295
+ baseStyle.textShadow = textShadowResult.shadow;
29567
30296
  if (rotation !== null)
29568
30297
  baseStyle.rotate = rotation;
29569
30298
  const bgClip = computed.webkitBackgroundClip || computed.backgroundClip;
@@ -29579,7 +30308,7 @@ ${generateStylesCss(styleMap, themeFonts)}
29579
30308
  }
29580
30309
  }
29581
30310
  }
29582
- const hasFormatting = el.querySelector("b, i, u, strong, em, span, br");
30311
+ const hasFormatting = el.querySelector("b, i, u, strong, em, span, br, code, a, mark, sub, sup, small, s, del, ins, abbr, time, cite, q, dfn, kbd, samp, var");
29583
30312
  if (hasFormatting) {
29584
30313
  const transformStr = computed.textTransform;
29585
30314
  const runs = parseInlineFormatting(el, {}, [], (str) => applyTextTransform(str, transformStr), win);
@@ -29609,10 +30338,64 @@ ${generateStylesCss(styleMap, themeFonts)}
29609
30338
  }
29610
30339
  processed.add(el);
29611
30340
  });
30341
+ processed.forEach((processedEl) => {
30342
+ const htmlEl = processedEl;
30343
+ if (htmlEl.tagName === "BODY")
30344
+ return;
30345
+ const pseudoElements = extractPseudoElements(htmlEl, win);
30346
+ elements.push(...pseudoElements);
30347
+ });
30348
+ doc.querySelectorAll("div").forEach((divEl) => {
30349
+ if (processed.has(divEl))
30350
+ return;
30351
+ const htmlDiv = divEl;
30352
+ if (htmlDiv === body)
30353
+ return;
30354
+ const rect = htmlDiv.getBoundingClientRect();
30355
+ if (rect.width <= 0 || rect.height <= 0)
30356
+ return;
30357
+ const pseudoElements = extractPseudoElements(htmlDiv, win);
30358
+ elements.push(...pseudoElements);
30359
+ });
29612
30360
  return { background, elements, placeholders, errors };
29613
30361
  }
29614
30362
 
29615
30363
  // packages/slides/convert.js
30364
+ function hexToRgb(hex) {
30365
+ const h = hex.replace("#", "");
30366
+ return {
30367
+ r: parseInt(h.substring(0, 2), 16),
30368
+ g: parseInt(h.substring(2, 4), 16),
30369
+ b: parseInt(h.substring(4, 6), 16)
30370
+ };
30371
+ }
30372
+ function rgbToHex2(r, g, b) {
30373
+ const toHex = (n) => Math.round(Math.max(0, Math.min(255, n))).toString(16).padStart(2, "0");
30374
+ return `${toHex(r)}${toHex(g)}${toHex(b)}`.toUpperCase();
30375
+ }
30376
+ function blendColors(fgHex, bgHex, opacity) {
30377
+ const fg = hexToRgb(fgHex);
30378
+ const bg = hexToRgb(bgHex);
30379
+ const r = fg.r * opacity + bg.r * (1 - opacity);
30380
+ const g = fg.g * opacity + bg.g * (1 - opacity);
30381
+ const b = fg.b * opacity + bg.b * (1 - opacity);
30382
+ return rgbToHex2(r, g, b);
30383
+ }
30384
+ function applyOpacityToGradient(gradient, opacity, bgColor) {
30385
+ return {
30386
+ ...gradient,
30387
+ stops: gradient.stops.map((stop) => {
30388
+ const stopOpacity = stop.transparency !== void 0 ? (100 - stop.transparency) / 100 : 1;
30389
+ const effectiveOpacity = opacity * stopOpacity;
30390
+ return {
30391
+ ...stop,
30392
+ color: blendColors(stop.color, bgColor, effectiveOpacity),
30393
+ // Remove transparency since it's now baked into the color
30394
+ transparency: void 0
30395
+ };
30396
+ })
30397
+ };
30398
+ }
29616
30399
  async function fetchImageAsDataUrl(url) {
29617
30400
  try {
29618
30401
  const response = await fetch(url, { mode: "cors" });
@@ -29663,7 +30446,7 @@ ${generateStylesCss(styleMap, themeFonts)}
29663
30446
  }
29664
30447
  }
29665
30448
  }
29666
- async function addElementsToSlide(elements, slide, pres) {
30449
+ async function addElementsToSlide(elements, slide, pres, bgColor) {
29667
30450
  for (const el of elements) {
29668
30451
  if (el.type === "slideBackgroundImage") {
29669
30452
  const imgSrc = await getImageSource(el.src);
@@ -29681,6 +30464,14 @@ ${generateStylesCss(styleMap, themeFonts)}
29681
30464
  if (el.sizing && el.sizing.type) {
29682
30465
  imageOptions.sizing = { type: el.sizing.type, w: el.position.w, h: el.position.h };
29683
30466
  }
30467
+ if (el.brightness !== void 0)
30468
+ imageOptions.brightness = el.brightness;
30469
+ if (el.contrast !== void 0)
30470
+ imageOptions.contrast = el.contrast;
30471
+ if (el.saturation !== void 0)
30472
+ imageOptions.saturation = el.saturation;
30473
+ if (el.transparency !== void 0)
30474
+ imageOptions.transparency = el.transparency;
29684
30475
  slide.addImage(imageOptions);
29685
30476
  }
29686
30477
  }
@@ -29700,12 +30491,37 @@ ${generateStylesCss(styleMap, themeFonts)}
29700
30491
  w: el.position.w,
29701
30492
  h: el.position.h
29702
30493
  };
29703
- if (el.sizing && el.sizing.type) {
30494
+ if (el.sizing && el.sizing.type === "cover" && el.naturalWidth && el.naturalHeight) {
30495
+ const imgRatio = el.naturalHeight / el.naturalWidth;
30496
+ const boxRatio = el.position.h / el.position.w;
30497
+ const isBoxBased = boxRatio > imgRatio;
30498
+ const effW = isBoxBased ? el.position.h / imgRatio : el.position.w;
30499
+ const effH = isBoxBased ? el.position.h : el.position.w * imgRatio;
30500
+ const cropX = (effW - el.position.w) / 2;
30501
+ const cropY = (effH - el.position.h) / 2;
30502
+ imageOptions.w = effW;
30503
+ imageOptions.h = effH;
30504
+ imageOptions.sizing = {
30505
+ type: "crop",
30506
+ x: cropX,
30507
+ y: cropY,
30508
+ w: el.position.w,
30509
+ h: el.position.h
30510
+ };
30511
+ } else if (el.sizing && el.sizing.type) {
29704
30512
  imageOptions.sizing = { type: el.sizing.type, w: el.position.w, h: el.position.h };
29705
30513
  }
29706
30514
  if (el.rectRadius) {
29707
30515
  imageOptions.rectRadius = el.rectRadius;
29708
30516
  }
30517
+ if (el.brightness !== void 0)
30518
+ imageOptions.brightness = el.brightness;
30519
+ if (el.contrast !== void 0)
30520
+ imageOptions.contrast = el.contrast;
30521
+ if (el.saturation !== void 0)
30522
+ imageOptions.saturation = el.saturation;
30523
+ if (el.transparency !== void 0)
30524
+ imageOptions.transparency = el.transparency;
29709
30525
  slide.addImage(imageOptions);
29710
30526
  } else if (el.type === "backgroundImage") {
29711
30527
  const imgSrc = await getImageSource(el.src);
@@ -29725,34 +30541,93 @@ ${generateStylesCss(styleMap, themeFonts)}
29725
30541
  }
29726
30542
  slide.addImage(imageOptions);
29727
30543
  } else if (el.type === "line") {
30544
+ const lineOpts = {
30545
+ color: el.color,
30546
+ width: el.width
30547
+ };
30548
+ if (el.transparency != null)
30549
+ lineOpts.transparency = el.transparency;
29728
30550
  slide.addShape(pres.ShapeType.line, {
29729
30551
  x: el.x1,
29730
30552
  y: el.y1,
29731
30553
  w: el.x2 - el.x1,
29732
30554
  h: el.y2 - el.y1,
29733
- line: { color: el.color, width: el.width }
30555
+ line: lineOpts
29734
30556
  });
29735
30557
  } else if (el.type === "shape") {
30558
+ let shapeType = pres.ShapeType.rect;
30559
+ if (el.shape.isEllipse) {
30560
+ shapeType = pres.ShapeType.ellipse;
30561
+ } else if (el.shape.rectRadius > 0) {
30562
+ shapeType = pres.ShapeType.roundRect;
30563
+ }
30564
+ const lineHeightPt = el.style?.lineSpacing || (el.style?.fontSize ?? 12) * 1.2;
30565
+ const verticalPaddingPt = el.style?.margin ? (el.style.margin[2] || 0) + (el.style.margin[3] || 0) : 0;
30566
+ const heightPt = el.position.h * 72 - verticalPaddingPt;
30567
+ const isSingleLine = heightPt <= lineHeightPt * 1.5;
30568
+ const hasText = el.text || el.textRuns && el.textRuns.length > 0;
30569
+ let adjustedX = el.position.x;
30570
+ let adjustedW = el.position.w;
30571
+ if (isSingleLine && hasText) {
30572
+ const widthIncrease = el.position.w * 0.02;
30573
+ const align = el.style?.align;
30574
+ if (align === "center") {
30575
+ adjustedX = el.position.x - widthIncrease / 2;
30576
+ adjustedW = el.position.w + widthIncrease;
30577
+ } else if (align === "right") {
30578
+ adjustedX = el.position.x - widthIncrease;
30579
+ adjustedW = el.position.w + widthIncrease;
30580
+ } else {
30581
+ adjustedW = el.position.w + widthIncrease;
30582
+ }
30583
+ }
29736
30584
  const shapeOptions = {
29737
- x: el.position.x,
30585
+ x: adjustedX,
29738
30586
  y: el.position.y,
29739
- w: el.position.w,
30587
+ w: adjustedW,
29740
30588
  h: el.position.h,
29741
- shape: el.shape.rectRadius > 0 ? pres.ShapeType.roundRect : pres.ShapeType.rect
30589
+ shape: shapeType,
30590
+ // Disable text wrapping for single-line shapes to prevent unwanted line breaks
30591
+ wrap: !isSingleLine
29742
30592
  };
30593
+ let fillTransparency = el.shape.transparency;
30594
+ const elementOpacity = el.shape.opacity !== null && el.shape.opacity < 1 ? el.shape.opacity : 1;
30595
+ if (elementOpacity < 1) {
30596
+ const opacityTransparency = Math.round((1 - elementOpacity) * 100);
30597
+ if (fillTransparency !== null) {
30598
+ const rgbaOpaque = (100 - fillTransparency) / 100;
30599
+ fillTransparency = Math.round((1 - rgbaOpaque * elementOpacity) * 100);
30600
+ } else {
30601
+ fillTransparency = opacityTransparency;
30602
+ }
30603
+ }
29743
30604
  if (el.shape.gradient) {
29744
- shapeOptions.fill = { type: "gradient", gradient: el.shape.gradient };
30605
+ if (elementOpacity < 1 && bgColor) {
30606
+ const blendedGradient = applyOpacityToGradient(el.shape.gradient, elementOpacity, bgColor);
30607
+ shapeOptions.fill = { type: "gradient", gradient: blendedGradient };
30608
+ } else {
30609
+ shapeOptions.fill = { type: "gradient", gradient: el.shape.gradient };
30610
+ }
29745
30611
  } else if (el.shape.fill) {
29746
30612
  shapeOptions.fill = { color: el.shape.fill };
29747
- if (el.shape.transparency != null)
29748
- shapeOptions.fill.transparency = el.shape.transparency;
30613
+ if (fillTransparency != null)
30614
+ shapeOptions.fill.transparency = fillTransparency;
30615
+ }
30616
+ if (el.shape.line) {
30617
+ const lineOpts = {
30618
+ color: el.shape.line.color,
30619
+ width: el.shape.line.width
30620
+ };
30621
+ if (el.shape.line.transparency != null)
30622
+ lineOpts.transparency = el.shape.line.transparency;
30623
+ shapeOptions.line = lineOpts;
29749
30624
  }
29750
- if (el.shape.line)
29751
- shapeOptions.line = el.shape.line;
29752
30625
  if (el.shape.rectRadius > 0)
29753
30626
  shapeOptions.rectRadius = el.shape.rectRadius;
29754
30627
  if (el.shape.shadow)
29755
30628
  shapeOptions.shadow = el.shape.shadow;
30629
+ if (el.shape.softEdge)
30630
+ shapeOptions.softEdgeRad = el.shape.softEdge;
29756
30631
  if (el.style) {
29757
30632
  if (el.style.fontSize)
29758
30633
  shapeOptions.fontSize = el.style.fontSize;
@@ -29772,8 +30647,18 @@ ${generateStylesCss(styleMap, themeFonts)}
29772
30647
  shapeOptions.margin = el.style.margin;
29773
30648
  if (el.style.inset !== void 0)
29774
30649
  shapeOptions.inset = el.style.inset;
29775
- if (el.style.wrap !== void 0)
29776
- shapeOptions.wrap = el.style.wrap;
30650
+ if (el.style.charSpacing)
30651
+ shapeOptions.charSpacing = el.style.charSpacing;
30652
+ if (el.style.glow) {
30653
+ shapeOptions.glow = {
30654
+ size: el.style.glow.size,
30655
+ color: el.style.glow.color,
30656
+ opacity: el.style.glow.opacity
30657
+ };
30658
+ }
30659
+ if (el.style.textShadow && !el.shape.shadow) {
30660
+ shapeOptions.shadow = el.style.textShadow;
30661
+ }
29777
30662
  }
29778
30663
  if (el.textRuns && el.textRuns.length > 0) {
29779
30664
  slide.addText(el.textRuns, shapeOptions);
@@ -29801,7 +30686,8 @@ ${generateStylesCss(styleMap, themeFonts)}
29801
30686
  slide.addText(el.items, listOptions);
29802
30687
  } else {
29803
30688
  const lineHeightPt = el.style.lineSpacing || (el.style.fontSize ?? 0) * 1.2;
29804
- const isSingleLine = el.position.h <= lineHeightPt * 1.5;
30689
+ const heightPt = el.position.h * 72;
30690
+ const isSingleLine = heightPt <= lineHeightPt * 1.5;
29805
30691
  let adjustedX = el.position.x;
29806
30692
  let adjustedW = el.position.w;
29807
30693
  if (isSingleLine) {
@@ -29832,7 +30718,9 @@ ${generateStylesCss(styleMap, themeFonts)}
29832
30718
  lineSpacing: el.style.lineSpacing,
29833
30719
  paraSpaceBefore: el.style.paraSpaceBefore,
29834
30720
  paraSpaceAfter: el.style.paraSpaceAfter,
29835
- inset: 0
30721
+ inset: 0,
30722
+ // Disable text wrapping for single-line text to prevent unwanted line breaks
30723
+ wrap: !isSingleLine
29836
30724
  };
29837
30725
  if (el.style.align)
29838
30726
  textOptions.align = el.style.align;
@@ -29843,10 +30731,22 @@ ${generateStylesCss(styleMap, themeFonts)}
29843
30731
  if (el.style.transparency !== null && el.style.transparency !== void 0) {
29844
30732
  textOptions.transparency = el.style.transparency;
29845
30733
  }
30734
+ if (el.style.charSpacing)
30735
+ textOptions.charSpacing = el.style.charSpacing;
29846
30736
  if (el.style.fontFill) {
29847
30737
  textOptions.fontFill = el.style.fontFill;
29848
30738
  delete textOptions.color;
29849
30739
  }
30740
+ if (el.style.glow) {
30741
+ textOptions.glow = {
30742
+ size: el.style.glow.size,
30743
+ color: el.style.glow.color,
30744
+ opacity: el.style.glow.opacity
30745
+ };
30746
+ }
30747
+ if (el.style.textShadow) {
30748
+ textOptions.shadow = el.style.textShadow;
30749
+ }
29850
30750
  slide.addText(el.text, textOptions);
29851
30751
  }
29852
30752
  }
@@ -29994,8 +30894,14 @@ ${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join("\n")}`;
29994
30894
  throw new Error(errorMessage);
29995
30895
  }
29996
30896
  const targetSlide = slide || pres.addSlide();
30897
+ let bgColor;
30898
+ if (slideData.background.type === "color") {
30899
+ bgColor = slideData.background.value;
30900
+ } else if (slideData.background.type === "gradient" && slideData.background.gradient.stops.length > 0) {
30901
+ bgColor = slideData.background.gradient.stops[0].color;
30902
+ }
29997
30903
  await applyBackground(slideData.background, targetSlide);
29998
- await addElementsToSlide(slideData.elements, targetSlide, pres);
30904
+ await addElementsToSlide(slideData.elements, targetSlide, pres, bgColor);
29999
30905
  return { slide: targetSlide, placeholders: slideData.placeholders };
30000
30906
  } finally {
30001
30907
  if (cleanupIframe?.parentNode) {
@@ -30022,24 +30928,34 @@ ${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join("\n")}`;
30022
30928
  }
30023
30929
 
30024
30930
  // packages/slides/transform.js
30025
- var NON_WEB_SAFE_FONTS = [
30026
- "Inter",
30027
- "Roboto",
30028
- "Open Sans",
30029
- "Lato",
30030
- "Montserrat",
30031
- "Poppins",
30032
- "Source Sans Pro",
30033
- "Nunito",
30034
- "Raleway",
30035
- "Ubuntu",
30036
- "Playfair Display",
30037
- "Merriweather",
30038
- "PT Sans",
30039
- "Noto Sans",
30040
- "Fira Sans",
30041
- "Work Sans"
30042
- ];
30931
+ var FONT_FAMILY_MAP = {
30932
+ // Serif fonts → Georgia (closest web-safe serif)
30933
+ "Playfair Display": "Georgia, serif",
30934
+ "Merriweather": "Georgia, serif",
30935
+ "Libre Baskerville": "Georgia, serif",
30936
+ "PT Serif": "Georgia, serif",
30937
+ "Noto Serif": "Georgia, serif",
30938
+ "Lora": "Georgia, serif",
30939
+ // Sans-serif fonts → Calibri (modern sans-serif, widely available in PowerPoint)
30940
+ "Inter": "Calibri, sans-serif",
30941
+ "Roboto": "Calibri, sans-serif",
30942
+ "Open Sans": "Calibri, sans-serif",
30943
+ "Lato": "Calibri, sans-serif",
30944
+ "Montserrat": "Calibri, sans-serif",
30945
+ "Poppins": "Calibri, sans-serif",
30946
+ "Source Sans Pro": "Calibri, sans-serif",
30947
+ "Nunito": "Calibri, sans-serif",
30948
+ "Raleway": "Calibri, sans-serif",
30949
+ "Ubuntu": "Calibri, sans-serif",
30950
+ "PT Sans": "Calibri, sans-serif",
30951
+ "Noto Sans": "Calibri, sans-serif",
30952
+ "Fira Sans": "Calibri, sans-serif",
30953
+ "Work Sans": "Calibri, sans-serif",
30954
+ // Monospace fonts → Courier New (standard monospace)
30955
+ "Fira Code": "Courier New, monospace",
30956
+ "Source Code Pro": "Courier New, monospace",
30957
+ "JetBrains Mono": "Courier New, monospace"
30958
+ };
30043
30959
  function transformHtmlForPptx(html, options = {}) {
30044
30960
  const targetWidth = options.targetWidth || 720;
30045
30961
  const targetHeight = options.targetHeight || 405;
@@ -30058,9 +30974,9 @@ ${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join("\n")}`;
30058
30974
  const scaleFactor = targetWidth / sourceWidth;
30059
30975
  html = html.replace(/(body\s*\{[^}]*?)width:\s*\d+px/s, `$1width: ${targetWidth}pt`);
30060
30976
  html = html.replace(/(body\s*\{[^}]*?)height:\s*\d+px/s, `$1height: ${targetHeight}pt`);
30061
- for (const font of NON_WEB_SAFE_FONTS) {
30062
- const fontRegex = new RegExp(`font-family:\\s*["']?${font}["']?,?\\s*(sans-serif|serif)?`, "gi");
30063
- html = html.replace(fontRegex, "font-family: Arial, sans-serif");
30977
+ for (const [font, replacement] of Object.entries(FONT_FAMILY_MAP)) {
30978
+ const fontRegex = new RegExp(`font-family:\\s*["']?${font}["']?,?\\s*(sans-serif|serif|monospace)?`, "gi");
30979
+ html = html.replace(fontRegex, `font-family: ${replacement}`);
30064
30980
  }
30065
30981
  html = html.replace(/<link[^>]*fonts\.googleapis\.com[^>]*>/g, "");
30066
30982
  const dataUriPlaceholders = [];
@@ -30076,6 +30992,16 @@ ${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join("\n")}`;
30076
30992
  html = html.replace(/__DATA_URI_PLACEHOLDER_(\d+)__/g, (_match, index) => {
30077
30993
  return dataUriPlaceholders[parseInt(index, 10)];
30078
30994
  });
30995
+ html = html.replace(/(<svg[^>]*\s)width="(\d+(?:\.\d+)?)"([^>]*\s)height="(\d+(?:\.\d+)?)"/g, (_match, pre, w, mid, h) => {
30996
+ const scaledW = Math.round(parseFloat(w) * scaleFactor * 10) / 10;
30997
+ const scaledH = Math.round(parseFloat(h) * scaleFactor * 10) / 10;
30998
+ return `${pre}width="${scaledW}"${mid}height="${scaledH}"`;
30999
+ });
31000
+ html = html.replace(/(<svg[^>]*\s)height="(\d+(?:\.\d+)?)"([^>]*\s)width="(\d+(?:\.\d+)?)"/g, (_match, pre, h, mid, w) => {
31001
+ const scaledW = Math.round(parseFloat(w) * scaleFactor * 10) / 10;
31002
+ const scaledH = Math.round(parseFloat(h) * scaleFactor * 10) / 10;
31003
+ return `${pre}height="${scaledH}"${mid}width="${scaledW}"`;
31004
+ });
30079
31005
  html = html.replace(/<div(\s+[^>]*)?>([^<]+)<\/div>/g, (match, attrs, text) => {
30080
31006
  if (!text.trim())
30081
31007
  return match;
@@ -30084,14 +31010,9 @@ ${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join("\n")}`;
30084
31010
  html = html.replace(/<div(\s+[^>]*)?>([^<]+)(<span[^>]*>[^<]*<\/span>)<\/div>/g, (_match, attrs, text, span) => {
30085
31011
  return `<div${attrs || ""}><p>${text}${span}</p></div>`;
30086
31012
  });
30087
- html = html.replace(/\}[^{}]*::before\s*\{[^}]+\}/g, "}");
30088
- html = html.replace(/\}[^{}]*::after\s*\{[^}]+\}/g, "}");
31013
+ html = html.replace(/-webkit-backdrop-filter:\s*[^;]+;/g, "");
30089
31014
  html = html.replace(/backdrop-filter:\s*[^;]+;/g, "");
30090
- html = html.replace(/text-shadow:\s*[^;]+;/g, "");
30091
- html = html.replace(/letter-spacing:\s*[^;]+;/g, "");
30092
- html = html.replace(/box-shadow:\s*[^;]+;/g, "");
30093
- html = html.replace(/animation[^:]*:\s*[^;]+;/g, "");
30094
- html = html.replace(/animation-delay:\s*[^;]+;/g, "");
31015
+ html = html.replace(/animation[\w-]*:\s*[^;]+;/g, "");
30095
31016
  let keyframeMatch;
30096
31017
  while (keyframeMatch = html.match(/@keyframes\s+[\w-]+\s*\{/)) {
30097
31018
  const start = keyframeMatch.index;
@@ -30106,7 +31027,7 @@ ${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join("\n")}`;
30106
31027
  }
30107
31028
  html = html.slice(0, start) + html.slice(i);
30108
31029
  }
30109
- html = html.replace(/opacity:\s*0;/g, "");
31030
+ html = html.replace(/opacity:\s*0;/g, "opacity: 1;");
30110
31031
  html = html.replace(/transition:\s*[^;]+;/g, "");
30111
31032
  html = html.replace(/pointer-events:\s*[^;]+;/g, "");
30112
31033
  return html;
@@ -31324,7 +32245,7 @@ ${inner}</div>`;
31324
32245
  const hex = c.toString(16);
31325
32246
  return hex.length === 1 ? "0" + hex : hex;
31326
32247
  }
31327
- function rgbToHex2(r, g, b) {
32248
+ function rgbToHex3(r, g, b) {
31328
32249
  return (componentToHex(r) + componentToHex(g) + componentToHex(b)).toUpperCase();
31329
32250
  }
31330
32251
  function createColorElement(colorStr, innerElements) {
@@ -31365,7 +32286,7 @@ ${inner}</div>`;
31365
32286
  strXml += "</a:gsLst>";
31366
32287
  if (gradient.type === "linear") {
31367
32288
  const cssAngle = (_a = gradient.angle) !== null && _a !== void 0 ? _a : 0;
31368
- const ooxmlAngle = (450 - cssAngle) % 360 * 6e4;
32289
+ const ooxmlAngle = (cssAngle + 270) % 360 * 6e4;
31369
32290
  strXml += `<a:lin ang="${ooxmlAngle}" scaled="1"/>`;
31370
32291
  } else if (gradient.type === "radial") {
31371
32292
  const centerX = (_b = gradient.centerX) !== null && _b !== void 0 ? _b : 50;
@@ -31843,8 +32764,8 @@ ${inner}</div>`;
31843
32764
  align: null,
31844
32765
  bold: !!(window.getComputedStyle(cell).getPropertyValue("font-weight") === "bold" || Number(window.getComputedStyle(cell).getPropertyValue("font-weight")) >= 500),
31845
32766
  border: null,
31846
- color: rgbToHex2(Number(arrRGB1[0]), Number(arrRGB1[1]), Number(arrRGB1[2])),
31847
- fill: { color: rgbToHex2(Number(arrRGB2[0]), Number(arrRGB2[1]), Number(arrRGB2[2])) },
32767
+ color: rgbToHex3(Number(arrRGB1[0]), Number(arrRGB1[1]), Number(arrRGB1[2])),
32768
+ fill: { color: rgbToHex3(Number(arrRGB2[0]), Number(arrRGB2[1]), Number(arrRGB2[2])) },
31848
32769
  fontFace: (window.getComputedStyle(cell).getPropertyValue("font-family") || "").split(",")[0].replace(/"/g, "").replace("inherit", "").replace("initial", "") || null,
31849
32770
  fontSize: Number(window.getComputedStyle(cell).getPropertyValue("font-size").replace(/[a-z]/gi, "")),
31850
32771
  margin: null,
@@ -31874,7 +32795,7 @@ ${inner}</div>`;
31874
32795
  const intBorderW = Math.round(Number(window.getComputedStyle(cell).getPropertyValue("border-" + val + "-width").replace("px", "")));
31875
32796
  let arrRGB = [];
31876
32797
  arrRGB = window.getComputedStyle(cell).getPropertyValue("border-" + val + "-color").replace(/\s+/gi, "").replace("rgba(", "").replace("rgb(", "").replace(")", "").split(",");
31877
- const strBorderC = rgbToHex2(Number(arrRGB[0]), Number(arrRGB[1]), Number(arrRGB[2]));
32798
+ const strBorderC = rgbToHex3(Number(arrRGB[0]), Number(arrRGB[1]), Number(arrRGB[2]));
31878
32799
  cellOpts.border[idxb] = { pt: intBorderW, color: strBorderC };
31879
32800
  });
31880
32801
  }
@@ -32228,7 +33149,10 @@ ${inner}</div>`;
32228
33149
  flipH: opt.flipH || false,
32229
33150
  transparency: opt.transparency || 0,
32230
33151
  objectName,
32231
- shadow: correctShadowOptions(opt.shadow)
33152
+ shadow: correctShadowOptions(opt.shadow),
33153
+ // CUSTOM PATCH: Image filter effects
33154
+ brightness: opt.brightness,
33155
+ contrast: opt.contrast
32232
33156
  };
32233
33157
  if (strImgExtn === "svg") {
32234
33158
  target._relsMedia.push({
@@ -33335,7 +34259,7 @@ ${inner}</div>`;
33335
34259
  } else if (opts.dataBorder) {
33336
34260
  strXml += `<a:ln w="${valToPts(opts.dataBorder.pt)}" cap="${createLineCap(opts.lineCap)}"><a:solidFill>${createColorElement(opts.dataBorder.color)}</a:solidFill><a:prstDash val="solid"/><a:round/></a:ln>`;
33337
34261
  }
33338
- strXml += createShadowElement(opts.shadow, DEF_SHAPE_SHADOW);
34262
+ strXml += createShadowElement(opts.shadow, DEF_SHAPE_SHADOW, opts.softEdgeRad);
33339
34263
  strXml += " </c:spPr>";
33340
34264
  strXml += ' <c:invertIfNegative val="0"/>';
33341
34265
  if (chartType !== CHART_TYPE.RADAR) {
@@ -33389,7 +34313,7 @@ ${inner}</div>`;
33389
34313
  strXml += " </a:solidFill>";
33390
34314
  strXml += "</a:ln>";
33391
34315
  }
33392
- strXml += createShadowElement(opts.shadow, DEF_SHAPE_SHADOW);
34316
+ strXml += createShadowElement(opts.shadow, DEF_SHAPE_SHADOW, opts.softEdgeRad);
33393
34317
  strXml += " </c:spPr>";
33394
34318
  strXml += " </c:dPt>";
33395
34319
  });
@@ -33505,7 +34429,7 @@ ${inner}</div>`;
33505
34429
  strXml += `<a:ln w="${valToPts(opts.lineSize)}" cap="${createLineCap(opts.lineCap)}"><a:solidFill>${createColorElement(tmpSerColor)}</a:solidFill>`;
33506
34430
  strXml += `<a:prstDash val="${opts.lineDash || "solid"}"/><a:round/></a:ln>`;
33507
34431
  }
33508
- strXml += createShadowElement(opts.shadow, DEF_SHAPE_SHADOW);
34432
+ strXml += createShadowElement(opts.shadow, DEF_SHAPE_SHADOW, opts.softEdgeRad);
33509
34433
  }
33510
34434
  strXml += " </c:spPr>";
33511
34435
  {
@@ -33654,7 +34578,7 @@ ${inner}</div>`;
33654
34578
  strXml += ' <a:srgbClr val="' + arrColors[index % arrColors.length] + '"/>';
33655
34579
  strXml += "</a:solidFill>";
33656
34580
  }
33657
- strXml += createShadowElement(opts.shadow, DEF_SHAPE_SHADOW);
34581
+ strXml += createShadowElement(opts.shadow, DEF_SHAPE_SHADOW, opts.softEdgeRad);
33658
34582
  strXml += " </c:spPr>";
33659
34583
  strXml += " </c:dPt>";
33660
34584
  });
@@ -33748,7 +34672,7 @@ ${inner}</div>`;
33748
34672
  strXml += `<a:ln w="${valToPts(opts.lineSize)}" cap="flat"><a:solidFill>${createColorElement(tmpSerColor)}</a:solidFill>`;
33749
34673
  strXml += `<a:prstDash val="${opts.lineDash || "solid"}"/><a:round/></a:ln>`;
33750
34674
  }
33751
- strXml += createShadowElement(opts.shadow, DEF_SHAPE_SHADOW);
34675
+ strXml += createShadowElement(opts.shadow, DEF_SHAPE_SHADOW, opts.softEdgeRad);
33752
34676
  strXml += "</c:spPr>";
33753
34677
  }
33754
34678
  {
@@ -33840,7 +34764,7 @@ ${inner}</div>`;
33840
34764
  if (opts.dataNoEffects) {
33841
34765
  strXml += "<a:effectLst/>";
33842
34766
  } else {
33843
- strXml += createShadowElement(opts.shadow, DEF_SHAPE_SHADOW);
34767
+ strXml += createShadowElement(opts.shadow, DEF_SHAPE_SHADOW, opts.softEdgeRad);
33844
34768
  }
33845
34769
  strXml += " </c:spPr>";
33846
34770
  optsChartData.labels[0].forEach((_label, idx) => {
@@ -33852,7 +34776,7 @@ ${inner}</div>`;
33852
34776
  if (opts.dataBorder) {
33853
34777
  strXml += `<a:ln w="${valToPts(opts.dataBorder.pt)}" cap="flat"><a:solidFill>${createColorElement(opts.dataBorder.color)}</a:solidFill><a:prstDash val="solid"/><a:round/></a:ln>`;
33854
34778
  }
33855
- strXml += createShadowElement(opts.shadow, DEF_SHAPE_SHADOW);
34779
+ strXml += createShadowElement(opts.shadow, DEF_SHAPE_SHADOW, opts.softEdgeRad);
33856
34780
  strXml += " </c:spPr>";
33857
34781
  strXml += "</c:dPt>";
33858
34782
  });
@@ -34236,26 +35160,32 @@ ${inner}</div>`;
34236
35160
  }
34237
35161
  return colStr;
34238
35162
  }
34239
- function createShadowElement(options, defaults) {
34240
- if (!options) {
35163
+ function createShadowElement(options, defaults, softEdgeRad) {
35164
+ if (!options && !softEdgeRad) {
34241
35165
  return "<a:effectLst/>";
34242
- } else if (typeof options !== "object") {
35166
+ } else if (options && typeof options !== "object") {
34243
35167
  console.warn("`shadow` options must be an object. Ex: `{shadow: {type:'none'}}`");
34244
- return "<a:effectLst/>";
35168
+ if (!softEdgeRad) return "<a:effectLst/>";
34245
35169
  }
34246
35170
  let strXml = "<a:effectLst>";
34247
- const opts = Object.assign(Object.assign({}, defaults), options);
34248
- const type2 = opts.type || "outer";
34249
- const blur = valToPts(opts.blur);
34250
- const offset = valToPts(opts.offset);
34251
- const angle = Math.round(opts.angle * 6e4);
34252
- const color = opts.color;
34253
- const opacity = Math.round(opts.opacity * 1e5);
34254
- const rotShape = opts.rotateWithShape ? 1 : 0;
34255
- strXml += `<a:${type2}Shdw sx="100000" sy="100000" kx="0" ky="0" algn="bl" blurRad="${blur}" rotWithShape="${rotShape}" dist="${offset}" dir="${angle}">`;
34256
- strXml += `<a:srgbClr val="${color}">`;
34257
- strXml += `<a:alpha val="${opacity}"/></a:srgbClr>`;
34258
- strXml += `</a:${type2}Shdw>`;
35171
+ if (options && typeof options === "object") {
35172
+ const opts = Object.assign(Object.assign({}, defaults), options);
35173
+ const type2 = opts.type || "outer";
35174
+ const blur = valToPts(opts.blur);
35175
+ const offset = valToPts(opts.offset);
35176
+ const angle = Math.round(opts.angle * 6e4);
35177
+ const color = opts.color;
35178
+ const opacity = Math.round(opts.opacity * 1e5);
35179
+ const rotShape = opts.rotateWithShape ? 1 : 0;
35180
+ strXml += `<a:${type2}Shdw sx="100000" sy="100000" kx="0" ky="0" algn="bl" blurRad="${blur}" rotWithShape="${rotShape}" dist="${offset}" dir="${angle}">`;
35181
+ strXml += `<a:srgbClr val="${color}">`;
35182
+ strXml += `<a:alpha val="${opacity}"/></a:srgbClr>`;
35183
+ strXml += `</a:${type2}Shdw>`;
35184
+ }
35185
+ if (softEdgeRad) {
35186
+ const radEmu = Math.round(softEdgeRad * 12700);
35187
+ strXml += `<a:softEdge rad="${radEmu}"/>`;
35188
+ }
34259
35189
  strXml += "</a:effectLst>";
34260
35190
  return strXml;
34261
35191
  }
@@ -34750,18 +35680,24 @@ ${String(ex)}`);
34750
35680
  strSlideXml += `<a:tailEnd type="${slideItemObj.options.line.endArrowType}"/>`;
34751
35681
  strSlideXml += "</a:ln>";
34752
35682
  }
34753
- if (slideItemObj.options.shadow && slideItemObj.options.shadow.type !== "none") {
34754
- slideItemObj.options.shadow.type = slideItemObj.options.shadow.type || "outer";
34755
- slideItemObj.options.shadow.blur = valToPts(slideItemObj.options.shadow.blur || 8);
34756
- slideItemObj.options.shadow.offset = valToPts(slideItemObj.options.shadow.offset || 4);
34757
- slideItemObj.options.shadow.angle = Math.round((slideItemObj.options.shadow.angle || 270) * 6e4);
34758
- slideItemObj.options.shadow.opacity = Math.round((slideItemObj.options.shadow.opacity || 0.75) * 1e5);
34759
- slideItemObj.options.shadow.color = slideItemObj.options.shadow.color || DEF_TEXT_SHADOW.color;
35683
+ if (slideItemObj.options.shadow && slideItemObj.options.shadow.type !== "none" || slideItemObj.options.softEdgeRad) {
34760
35684
  strSlideXml += "<a:effectLst>";
34761
- strSlideXml += ` <a:${slideItemObj.options.shadow.type}Shdw ${slideItemObj.options.shadow.type === "outer" ? 'sx="100000" sy="100000" kx="0" ky="0" algn="bl" rotWithShape="0"' : ""} blurRad="${slideItemObj.options.shadow.blur}" dist="${slideItemObj.options.shadow.offset}" dir="${slideItemObj.options.shadow.angle}">`;
34762
- strSlideXml += ` <a:srgbClr val="${slideItemObj.options.shadow.color}">`;
34763
- strSlideXml += ` <a:alpha val="${slideItemObj.options.shadow.opacity}"/></a:srgbClr>`;
34764
- strSlideXml += " </a:outerShdw>";
35685
+ if (slideItemObj.options.shadow && slideItemObj.options.shadow.type !== "none") {
35686
+ slideItemObj.options.shadow.type = slideItemObj.options.shadow.type || "outer";
35687
+ slideItemObj.options.shadow.blur = valToPts(slideItemObj.options.shadow.blur || 8);
35688
+ slideItemObj.options.shadow.offset = valToPts(slideItemObj.options.shadow.offset || 4);
35689
+ slideItemObj.options.shadow.angle = Math.round((slideItemObj.options.shadow.angle || 270) * 6e4);
35690
+ slideItemObj.options.shadow.opacity = Math.round((slideItemObj.options.shadow.opacity || 0.75) * 1e5);
35691
+ slideItemObj.options.shadow.color = slideItemObj.options.shadow.color || DEF_TEXT_SHADOW.color;
35692
+ strSlideXml += ` <a:${slideItemObj.options.shadow.type}Shdw ${slideItemObj.options.shadow.type === "outer" ? 'sx="100000" sy="100000" kx="0" ky="0" algn="bl" rotWithShape="0"' : ""} blurRad="${slideItemObj.options.shadow.blur}" dist="${slideItemObj.options.shadow.offset}" dir="${slideItemObj.options.shadow.angle}">`;
35693
+ strSlideXml += ` <a:srgbClr val="${slideItemObj.options.shadow.color}">`;
35694
+ strSlideXml += ` <a:alpha val="${slideItemObj.options.shadow.opacity}"/></a:srgbClr>`;
35695
+ strSlideXml += " </a:outerShdw>";
35696
+ }
35697
+ if (slideItemObj.options.softEdgeRad) {
35698
+ var softRadEmu = Math.round(slideItemObj.options.softEdgeRad * 12700);
35699
+ strSlideXml += '<a:softEdge rad="' + softRadEmu + '"/>';
35700
+ }
34765
35701
  strSlideXml += "</a:effectLst>";
34766
35702
  }
34767
35703
  strSlideXml += "</p:spPr>";
@@ -34795,6 +35731,11 @@ ${String(ex)}`);
34795
35731
  } else {
34796
35732
  strSlideXml += `<a:blip r:embed="rId${slideItemObj.imageRid}">`;
34797
35733
  strSlideXml += slideItemObj.options.transparency ? `<a:alphaModFix amt="${Math.round((100 - slideItemObj.options.transparency) * 1e3)}"/>` : "";
35734
+ if (slideItemObj.options.brightness !== void 0 || slideItemObj.options.contrast !== void 0) {
35735
+ const bright = slideItemObj.options.brightness ? Math.round(slideItemObj.options.brightness * 1e3) : 0;
35736
+ const contrast = slideItemObj.options.contrast ? Math.round(slideItemObj.options.contrast * 1e3) : 0;
35737
+ strSlideXml += `<a:lum bright="${bright}" contrast="${contrast}"/>`;
35738
+ }
34798
35739
  strSlideXml += "</a:blip>";
34799
35740
  }
34800
35741
  if (sizing === null || sizing === void 0 ? void 0 : sizing.type) {
@@ -34822,18 +35763,24 @@ ${String(ex)}`);
34822
35763
  } else {
34823
35764
  strSlideXml += ` <a:prstGeom prst="${rounding ? "ellipse" : "rect"}"><a:avLst/></a:prstGeom>`;
34824
35765
  }
34825
- if (slideItemObj.options.shadow && slideItemObj.options.shadow.type !== "none") {
34826
- slideItemObj.options.shadow.type = slideItemObj.options.shadow.type || "outer";
34827
- slideItemObj.options.shadow.blur = valToPts(slideItemObj.options.shadow.blur || 8);
34828
- slideItemObj.options.shadow.offset = valToPts(slideItemObj.options.shadow.offset || 4);
34829
- slideItemObj.options.shadow.angle = Math.round((slideItemObj.options.shadow.angle || 270) * 6e4);
34830
- slideItemObj.options.shadow.opacity = Math.round((slideItemObj.options.shadow.opacity || 0.75) * 1e5);
34831
- slideItemObj.options.shadow.color = slideItemObj.options.shadow.color || DEF_TEXT_SHADOW.color;
35766
+ if (slideItemObj.options.shadow && slideItemObj.options.shadow.type !== "none" || slideItemObj.options.softEdgeRad) {
34832
35767
  strSlideXml += "<a:effectLst>";
34833
- strSlideXml += `<a:${slideItemObj.options.shadow.type}Shdw ${slideItemObj.options.shadow.type === "outer" ? 'sx="100000" sy="100000" kx="0" ky="0" algn="bl" rotWithShape="0"' : ""} blurRad="${slideItemObj.options.shadow.blur}" dist="${slideItemObj.options.shadow.offset}" dir="${slideItemObj.options.shadow.angle}">`;
34834
- strSlideXml += `<a:srgbClr val="${slideItemObj.options.shadow.color}">`;
34835
- strSlideXml += `<a:alpha val="${slideItemObj.options.shadow.opacity}"/></a:srgbClr>`;
34836
- strSlideXml += `</a:${slideItemObj.options.shadow.type}Shdw>`;
35768
+ if (slideItemObj.options.shadow && slideItemObj.options.shadow.type !== "none") {
35769
+ slideItemObj.options.shadow.type = slideItemObj.options.shadow.type || "outer";
35770
+ slideItemObj.options.shadow.blur = valToPts(slideItemObj.options.shadow.blur || 8);
35771
+ slideItemObj.options.shadow.offset = valToPts(slideItemObj.options.shadow.offset || 4);
35772
+ slideItemObj.options.shadow.angle = Math.round((slideItemObj.options.shadow.angle || 270) * 6e4);
35773
+ slideItemObj.options.shadow.opacity = Math.round((slideItemObj.options.shadow.opacity || 0.75) * 1e5);
35774
+ slideItemObj.options.shadow.color = slideItemObj.options.shadow.color || DEF_TEXT_SHADOW.color;
35775
+ strSlideXml += `<a:${slideItemObj.options.shadow.type}Shdw ${slideItemObj.options.shadow.type === "outer" ? 'sx="100000" sy="100000" kx="0" ky="0" algn="bl" rotWithShape="0"' : ""} blurRad="${slideItemObj.options.shadow.blur}" dist="${slideItemObj.options.shadow.offset}" dir="${slideItemObj.options.shadow.angle}">`;
35776
+ strSlideXml += `<a:srgbClr val="${slideItemObj.options.shadow.color}">`;
35777
+ strSlideXml += `<a:alpha val="${slideItemObj.options.shadow.opacity}"/></a:srgbClr>`;
35778
+ strSlideXml += `</a:${slideItemObj.options.shadow.type}Shdw>`;
35779
+ }
35780
+ if (slideItemObj.options.softEdgeRad) {
35781
+ var softRadEmu2 = Math.round(slideItemObj.options.softEdgeRad * 12700);
35782
+ strSlideXml += '<a:softEdge rad="' + softRadEmu2 + '"/>';
35783
+ }
34837
35784
  strSlideXml += "</a:effectLst>";
34838
35785
  }
34839
35786
  strSlideXml += "</p:spPr>";