docgen-utils 1.0.9 → 1.0.11
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 +1282 -124
- package/dist/bundle.min.js +82 -80
- package/dist/cli.js +322 -29
- package/dist/packages/docs/convert.d.ts.map +1 -1
- package/dist/packages/docs/convert.js +18 -2
- package/dist/packages/docs/convert.js.map +1 -1
- package/dist/packages/slides/common.d.ts +17 -0
- package/dist/packages/slides/common.d.ts.map +1 -1
- package/dist/packages/slides/convert.d.ts +5 -2
- package/dist/packages/slides/convert.d.ts.map +1 -1
- package/dist/packages/slides/convert.js +122 -28
- package/dist/packages/slides/convert.js.map +1 -1
- package/dist/packages/slides/createPresentation.d.ts.map +1 -1
- package/dist/packages/slides/createPresentation.js +18 -1
- package/dist/packages/slides/createPresentation.js.map +1 -1
- package/dist/packages/slides/import-pptx.d.ts.map +1 -1
- package/dist/packages/slides/import-pptx.js +388 -25
- package/dist/packages/slides/import-pptx.js.map +1 -1
- package/dist/packages/slides/parse.d.ts.map +1 -1
- package/dist/packages/slides/parse.js +1103 -89
- package/dist/packages/slides/parse.js.map +1 -1
- package/dist/packages/slides/transform.d.ts.map +1 -1
- package/dist/packages/slides/transform.js +60 -10
- package/dist/packages/slides/transform.js.map +1 -1
- package/package.json +9 -4
package/dist/bundle.js
CHANGED
|
@@ -25609,7 +25609,7 @@ var docgen = (() => {
|
|
|
25609
25609
|
};
|
|
25610
25610
|
return new TableRow({
|
|
25611
25611
|
tableHeader: isHeaderRow,
|
|
25612
|
-
children: cells.map((cell) => {
|
|
25612
|
+
children: cells.map((cell, cellIndex) => {
|
|
25613
25613
|
const textRuns = typeof cell === "string" ? [new TextRun({
|
|
25614
25614
|
text: cell,
|
|
25615
25615
|
bold: isHeaderRow,
|
|
@@ -25649,6 +25649,10 @@ var docgen = (() => {
|
|
|
25649
25649
|
fill: "F9FAFB"
|
|
25650
25650
|
};
|
|
25651
25651
|
}
|
|
25652
|
+
const isLastCell = cellIndex === cells.length - 1;
|
|
25653
|
+
const remainingColumns = columnCount - cells.length;
|
|
25654
|
+
const needsSpan = isLastCell && remainingColumns > 0;
|
|
25655
|
+
const cellColumnSpan = needsSpan ? remainingColumns + 1 : void 0;
|
|
25652
25656
|
return new TableCell({
|
|
25653
25657
|
children: [
|
|
25654
25658
|
new Paragraph({
|
|
@@ -25659,6 +25663,7 @@ var docgen = (() => {
|
|
|
25659
25663
|
size: 100 / columnCount,
|
|
25660
25664
|
type: WidthType.PERCENTAGE
|
|
25661
25665
|
},
|
|
25666
|
+
columnSpan: cellColumnSpan,
|
|
25662
25667
|
shading,
|
|
25663
25668
|
// Apply cell padding from CSS
|
|
25664
25669
|
margins: cellPadding ? {
|
|
@@ -25801,10 +25806,11 @@ var docgen = (() => {
|
|
|
25801
25806
|
}
|
|
25802
25807
|
case "table": {
|
|
25803
25808
|
const useHeaderStyling = element.noBorders ? false : element.hasHeader !== false;
|
|
25809
|
+
const maxColumnCount = Math.max(...element.rows.map((row) => row.length));
|
|
25804
25810
|
const tableRows = element.rows.map((row, rowIndex) => createTableRow(
|
|
25805
25811
|
row,
|
|
25806
25812
|
useHeaderStyling && rowIndex === 0,
|
|
25807
|
-
|
|
25813
|
+
maxColumnCount,
|
|
25808
25814
|
element.cellPadding,
|
|
25809
25815
|
element.headerBackgroundColor,
|
|
25810
25816
|
element.headerTextColor,
|
|
@@ -28627,6 +28633,45 @@ ${generateStylesCss(styleMap, themeFonts)}
|
|
|
28627
28633
|
var PT_PER_PX = 0.75;
|
|
28628
28634
|
var PX_PER_IN = 96;
|
|
28629
28635
|
var SINGLE_WEIGHT_FONTS = ["impact"];
|
|
28636
|
+
var FONT_FAMILY_MAP = {
|
|
28637
|
+
// Common sans-serif web fonts → Calibri (default Office sans-serif)
|
|
28638
|
+
// Fonts that are commonly available via Google Fonts CDN are NOT mapped here,
|
|
28639
|
+
// to preserve original font names for systems that have them installed.
|
|
28640
|
+
"roboto": "Calibri",
|
|
28641
|
+
"open sans": "Calibri",
|
|
28642
|
+
"lato": "Calibri",
|
|
28643
|
+
"montserrat": "Calibri",
|
|
28644
|
+
"poppins": "Calibri",
|
|
28645
|
+
"source sans pro": "Calibri",
|
|
28646
|
+
"nunito": "Calibri",
|
|
28647
|
+
"raleway": "Calibri",
|
|
28648
|
+
"ubuntu": "Calibri",
|
|
28649
|
+
"pt sans": "Calibri",
|
|
28650
|
+
"noto sans": "Calibri",
|
|
28651
|
+
"fira sans": "Calibri",
|
|
28652
|
+
"work sans": "Calibri",
|
|
28653
|
+
// Serif fonts → Georgia (closest web-safe serif)
|
|
28654
|
+
"playfair display": "Georgia",
|
|
28655
|
+
"merriweather": "Georgia",
|
|
28656
|
+
"libre baskerville": "Georgia",
|
|
28657
|
+
"pt serif": "Georgia",
|
|
28658
|
+
"noto serif": "Georgia",
|
|
28659
|
+
"lora": "Georgia",
|
|
28660
|
+
// Monospace fonts → Courier New (standard monospace)
|
|
28661
|
+
"fira code": "Courier New",
|
|
28662
|
+
"source code pro": "Courier New",
|
|
28663
|
+
"jetbrains mono": "Courier New"
|
|
28664
|
+
};
|
|
28665
|
+
function mapFontFamily(fontFamily) {
|
|
28666
|
+
const normalized = fontFamily.toLowerCase().trim();
|
|
28667
|
+
return FONT_FAMILY_MAP[normalized] || fontFamily;
|
|
28668
|
+
}
|
|
28669
|
+
function extractFontFace(fontFamily) {
|
|
28670
|
+
if (!fontFamily)
|
|
28671
|
+
return void 0;
|
|
28672
|
+
const firstFont = fontFamily.split(",")[0].replace(/['"]/g, "").trim();
|
|
28673
|
+
return mapFontFamily(firstFont);
|
|
28674
|
+
}
|
|
28630
28675
|
function pxToInch(px) {
|
|
28631
28676
|
return px / PX_PER_IN;
|
|
28632
28677
|
}
|
|
@@ -28634,6 +28679,7 @@ ${generateStylesCss(styleMap, themeFonts)}
|
|
|
28634
28679
|
return parseFloat(pxStr) * PT_PER_PX;
|
|
28635
28680
|
}
|
|
28636
28681
|
function rgbToHex(rgbStr) {
|
|
28682
|
+
rgbStr = rgbStr.replace(/\s*!important\s*$/i, "").trim();
|
|
28637
28683
|
if (rgbStr === "rgba(0, 0, 0, 0)" || rgbStr === "transparent")
|
|
28638
28684
|
return "FFFFFF";
|
|
28639
28685
|
const match = rgbStr.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/);
|
|
@@ -28658,14 +28704,27 @@ ${generateStylesCss(styleMap, themeFonts)}
|
|
|
28658
28704
|
const alpha = parseFloat(match[4]);
|
|
28659
28705
|
return Math.round((1 - alpha) * 100);
|
|
28660
28706
|
}
|
|
28707
|
+
function extractDashType(borderStyle) {
|
|
28708
|
+
switch (borderStyle.toLowerCase()) {
|
|
28709
|
+
case "dashed":
|
|
28710
|
+
return "dash";
|
|
28711
|
+
case "dotted":
|
|
28712
|
+
return "sysDot";
|
|
28713
|
+
case "solid":
|
|
28714
|
+
default:
|
|
28715
|
+
return void 0;
|
|
28716
|
+
}
|
|
28717
|
+
}
|
|
28661
28718
|
function parseCssGradient(gradientStr) {
|
|
28662
28719
|
const colorToHex = (colorStr) => {
|
|
28663
28720
|
colorStr = colorStr.trim().toLowerCase();
|
|
28721
|
+
colorStr = colorStr.replace(/\s*!important\s*$/i, "");
|
|
28664
28722
|
if (colorStr === "transparent") {
|
|
28665
28723
|
return "000000";
|
|
28666
28724
|
}
|
|
28667
28725
|
if (colorStr.startsWith("#")) {
|
|
28668
28726
|
let hex = colorStr.slice(1);
|
|
28727
|
+
hex = hex.replace(/[^0-9a-f]/gi, "");
|
|
28669
28728
|
if (hex.length === 3)
|
|
28670
28729
|
hex = hex.split("").map((c) => c + c).join("");
|
|
28671
28730
|
return hex.toUpperCase();
|
|
@@ -28678,6 +28737,7 @@ ${generateStylesCss(styleMap, themeFonts)}
|
|
|
28678
28737
|
};
|
|
28679
28738
|
const extractTransparency = (colorStr) => {
|
|
28680
28739
|
colorStr = colorStr.trim().toLowerCase();
|
|
28740
|
+
colorStr = colorStr.replace(/\s*!important\s*$/i, "");
|
|
28681
28741
|
if (colorStr === "transparent") {
|
|
28682
28742
|
return 100;
|
|
28683
28743
|
}
|
|
@@ -28894,6 +28954,14 @@ ${generateStylesCss(styleMap, themeFonts)}
|
|
|
28894
28954
|
}
|
|
28895
28955
|
return text;
|
|
28896
28956
|
}
|
|
28957
|
+
function getTransformedText(element, computed) {
|
|
28958
|
+
const rawText = element.textContent?.trim() || "";
|
|
28959
|
+
const textTransform = computed.textTransform;
|
|
28960
|
+
if (textTransform && textTransform !== "none") {
|
|
28961
|
+
return applyTextTransform(rawText, textTransform);
|
|
28962
|
+
}
|
|
28963
|
+
return rawText;
|
|
28964
|
+
}
|
|
28897
28965
|
function getRotation(transform, writingMode) {
|
|
28898
28966
|
let angle = 0;
|
|
28899
28967
|
if (writingMode === "vertical-rl") {
|
|
@@ -29107,6 +29175,332 @@ ${generateStylesCss(styleMap, themeFonts)}
|
|
|
29107
29175
|
opacity
|
|
29108
29176
|
};
|
|
29109
29177
|
}
|
|
29178
|
+
function parseClipPathPolygon(clipPath) {
|
|
29179
|
+
if (!clipPath || clipPath === "none")
|
|
29180
|
+
return null;
|
|
29181
|
+
const polygonMatch = clipPath.match(/polygon\(([^)]+)\)/);
|
|
29182
|
+
if (!polygonMatch)
|
|
29183
|
+
return null;
|
|
29184
|
+
const points = [];
|
|
29185
|
+
const pairs = polygonMatch[1].split(",");
|
|
29186
|
+
for (const pair of pairs) {
|
|
29187
|
+
const coords = pair.trim().split(/\s+/);
|
|
29188
|
+
if (coords.length < 2)
|
|
29189
|
+
continue;
|
|
29190
|
+
const x = parseFloat(coords[0]) / 100;
|
|
29191
|
+
const y = parseFloat(coords[1]) / 100;
|
|
29192
|
+
if (isNaN(x) || isNaN(y))
|
|
29193
|
+
continue;
|
|
29194
|
+
points.push({ x, y });
|
|
29195
|
+
}
|
|
29196
|
+
return points.length >= 3 ? points : null;
|
|
29197
|
+
}
|
|
29198
|
+
function renderConicGradientAsImage(conicGradientCSS, width, height, isCircle, doc) {
|
|
29199
|
+
try {
|
|
29200
|
+
const canvas = doc.createElement("canvas");
|
|
29201
|
+
const scale = 2;
|
|
29202
|
+
canvas.width = Math.round(width * scale);
|
|
29203
|
+
canvas.height = Math.round(height * scale);
|
|
29204
|
+
const ctx = canvas.getContext("2d");
|
|
29205
|
+
if (!ctx)
|
|
29206
|
+
return null;
|
|
29207
|
+
const conicIdx = conicGradientCSS.indexOf("conic-gradient(");
|
|
29208
|
+
if (conicIdx === -1)
|
|
29209
|
+
return null;
|
|
29210
|
+
let depth = 0;
|
|
29211
|
+
let startIdx = -1;
|
|
29212
|
+
let endIdx = -1;
|
|
29213
|
+
for (let i = conicIdx + "conic-gradient".length; i < conicGradientCSS.length; i++) {
|
|
29214
|
+
if (conicGradientCSS[i] === "(") {
|
|
29215
|
+
if (depth === 0)
|
|
29216
|
+
startIdx = i + 1;
|
|
29217
|
+
depth++;
|
|
29218
|
+
} else if (conicGradientCSS[i] === ")") {
|
|
29219
|
+
depth--;
|
|
29220
|
+
if (depth === 0) {
|
|
29221
|
+
endIdx = i;
|
|
29222
|
+
break;
|
|
29223
|
+
}
|
|
29224
|
+
}
|
|
29225
|
+
}
|
|
29226
|
+
if (startIdx === -1 || endIdx === -1)
|
|
29227
|
+
return null;
|
|
29228
|
+
let innerContent = conicGradientCSS.substring(startIdx, endIdx).trim();
|
|
29229
|
+
let startAngleDeg = 0;
|
|
29230
|
+
const fromMatch = innerContent.match(/^from\s+([\d.]+)(deg|rad|turn|grad)/i);
|
|
29231
|
+
if (fromMatch) {
|
|
29232
|
+
const val = parseFloat(fromMatch[1]);
|
|
29233
|
+
const unit = fromMatch[2].toLowerCase();
|
|
29234
|
+
if (unit === "deg")
|
|
29235
|
+
startAngleDeg = val;
|
|
29236
|
+
else if (unit === "rad")
|
|
29237
|
+
startAngleDeg = val * (180 / Math.PI);
|
|
29238
|
+
else if (unit === "turn")
|
|
29239
|
+
startAngleDeg = val * 360;
|
|
29240
|
+
else if (unit === "grad")
|
|
29241
|
+
startAngleDeg = val * 0.9;
|
|
29242
|
+
innerContent = innerContent.substring(fromMatch[0].length).replace(/^\s*,\s*/, "");
|
|
29243
|
+
}
|
|
29244
|
+
let centerXFrac = 0.5;
|
|
29245
|
+
let centerYFrac = 0.5;
|
|
29246
|
+
const atMatch = innerContent.match(/^at\s+([\d.]+)(%|px)?\s+([\d.]+)(%|px)?/i);
|
|
29247
|
+
if (atMatch) {
|
|
29248
|
+
const xVal = parseFloat(atMatch[1]);
|
|
29249
|
+
const xUnit = atMatch[2] || "%";
|
|
29250
|
+
const yVal = parseFloat(atMatch[3]);
|
|
29251
|
+
const yUnit = atMatch[4] || "%";
|
|
29252
|
+
centerXFrac = xUnit === "%" ? xVal / 100 : xVal / width;
|
|
29253
|
+
centerYFrac = yUnit === "%" ? yVal / 100 : yVal / height;
|
|
29254
|
+
innerContent = innerContent.substring(atMatch[0].length).replace(/^\s*,\s*/, "");
|
|
29255
|
+
}
|
|
29256
|
+
const stopParts = [];
|
|
29257
|
+
let current = "";
|
|
29258
|
+
let parenDepth = 0;
|
|
29259
|
+
for (let i = 0; i < innerContent.length; i++) {
|
|
29260
|
+
const ch = innerContent[i];
|
|
29261
|
+
if (ch === "(")
|
|
29262
|
+
parenDepth++;
|
|
29263
|
+
else if (ch === ")")
|
|
29264
|
+
parenDepth--;
|
|
29265
|
+
else if (ch === "," && parenDepth === 0) {
|
|
29266
|
+
stopParts.push(current.trim());
|
|
29267
|
+
current = "";
|
|
29268
|
+
continue;
|
|
29269
|
+
}
|
|
29270
|
+
current += ch;
|
|
29271
|
+
}
|
|
29272
|
+
if (current.trim())
|
|
29273
|
+
stopParts.push(current.trim());
|
|
29274
|
+
if (stopParts.length === 0)
|
|
29275
|
+
return null;
|
|
29276
|
+
const rawStops = [];
|
|
29277
|
+
for (const part of stopParts) {
|
|
29278
|
+
const trimmed = part.trim();
|
|
29279
|
+
const posPattern = /([\d.]+)(deg|%|turn|rad|grad)/gi;
|
|
29280
|
+
const positions = [];
|
|
29281
|
+
let m;
|
|
29282
|
+
while ((m = posPattern.exec(trimmed)) !== null) {
|
|
29283
|
+
positions.push({ value: parseFloat(m[1]), unit: m[2].toLowerCase(), index: m.index });
|
|
29284
|
+
}
|
|
29285
|
+
const trailingPositions = [];
|
|
29286
|
+
if (positions.length > 0) {
|
|
29287
|
+
const lastPos = positions[positions.length - 1];
|
|
29288
|
+
const lastEnd = lastPos.index + `${lastPos.value}${lastPos.unit}`.length;
|
|
29289
|
+
if (Math.abs(lastEnd - trimmed.length) <= 1) {
|
|
29290
|
+
for (let i = positions.length - 1; i >= 0; i--) {
|
|
29291
|
+
const p = positions[i];
|
|
29292
|
+
const lastParen = trimmed.lastIndexOf(")");
|
|
29293
|
+
if (p.index > lastParen) {
|
|
29294
|
+
trailingPositions.unshift({ value: p.value, unit: p.unit });
|
|
29295
|
+
}
|
|
29296
|
+
}
|
|
29297
|
+
}
|
|
29298
|
+
}
|
|
29299
|
+
let color;
|
|
29300
|
+
if (trailingPositions.length > 0) {
|
|
29301
|
+
const firstPosIdx = positions.find((p) => trailingPositions.some((tp) => tp.value === p.value && tp.unit === p.unit))?.index ?? trimmed.length;
|
|
29302
|
+
color = trimmed.substring(0, firstPosIdx).trim();
|
|
29303
|
+
} else {
|
|
29304
|
+
color = trimmed;
|
|
29305
|
+
}
|
|
29306
|
+
const toFraction = (val, unit) => {
|
|
29307
|
+
switch (unit) {
|
|
29308
|
+
case "%":
|
|
29309
|
+
return val / 100;
|
|
29310
|
+
case "deg":
|
|
29311
|
+
return val / 360;
|
|
29312
|
+
case "turn":
|
|
29313
|
+
return val;
|
|
29314
|
+
case "rad":
|
|
29315
|
+
return val / (Math.PI * 2);
|
|
29316
|
+
case "grad":
|
|
29317
|
+
return val / 400;
|
|
29318
|
+
default:
|
|
29319
|
+
return val / 100;
|
|
29320
|
+
}
|
|
29321
|
+
};
|
|
29322
|
+
if (trailingPositions.length >= 2) {
|
|
29323
|
+
rawStops.push({ color, position: toFraction(trailingPositions[0].value, trailingPositions[0].unit) });
|
|
29324
|
+
rawStops.push({ color, position: toFraction(trailingPositions[1].value, trailingPositions[1].unit) });
|
|
29325
|
+
} else if (trailingPositions.length === 1) {
|
|
29326
|
+
rawStops.push({ color, position: toFraction(trailingPositions[0].value, trailingPositions[0].unit) });
|
|
29327
|
+
} else {
|
|
29328
|
+
rawStops.push({ color, position: null });
|
|
29329
|
+
}
|
|
29330
|
+
}
|
|
29331
|
+
if (rawStops.length === 0)
|
|
29332
|
+
return null;
|
|
29333
|
+
if (rawStops[0].position === null)
|
|
29334
|
+
rawStops[0].position = 0;
|
|
29335
|
+
if (rawStops[rawStops.length - 1].position === null)
|
|
29336
|
+
rawStops[rawStops.length - 1].position = 1;
|
|
29337
|
+
let lastKnownIdx = 0;
|
|
29338
|
+
for (let i = 1; i < rawStops.length; i++) {
|
|
29339
|
+
if (rawStops[i].position !== null) {
|
|
29340
|
+
const gapCount = i - lastKnownIdx;
|
|
29341
|
+
if (gapCount > 1) {
|
|
29342
|
+
const startVal = rawStops[lastKnownIdx].position;
|
|
29343
|
+
const endVal = rawStops[i].position;
|
|
29344
|
+
for (let j = lastKnownIdx + 1; j < i; j++) {
|
|
29345
|
+
rawStops[j].position = startVal + (endVal - startVal) * ((j - lastKnownIdx) / gapCount);
|
|
29346
|
+
}
|
|
29347
|
+
}
|
|
29348
|
+
lastKnownIdx = i;
|
|
29349
|
+
}
|
|
29350
|
+
}
|
|
29351
|
+
ctx.scale(scale, scale);
|
|
29352
|
+
const cx = width * centerXFrac;
|
|
29353
|
+
const cy = height * centerYFrac;
|
|
29354
|
+
const startAngleRad = startAngleDeg * Math.PI / 180;
|
|
29355
|
+
if (typeof ctx.createConicGradient === "function") {
|
|
29356
|
+
const grad = ctx.createConicGradient(startAngleRad, cx, cy);
|
|
29357
|
+
for (const stop of rawStops) {
|
|
29358
|
+
try {
|
|
29359
|
+
grad.addColorStop(Math.max(0, Math.min(1, stop.position)), stop.color);
|
|
29360
|
+
} catch {
|
|
29361
|
+
}
|
|
29362
|
+
}
|
|
29363
|
+
ctx.fillStyle = grad;
|
|
29364
|
+
ctx.fillRect(0, 0, width, height);
|
|
29365
|
+
} else {
|
|
29366
|
+
const scaledCx = cx;
|
|
29367
|
+
const scaledCy = cy;
|
|
29368
|
+
const radius = Math.max(width, height) * 1.5;
|
|
29369
|
+
const angleOffset = startAngleRad - Math.PI / 2;
|
|
29370
|
+
for (let i = 0; i < rawStops.length - 1; i++) {
|
|
29371
|
+
const startFrac = rawStops[i].position;
|
|
29372
|
+
const endFrac = rawStops[i + 1].position;
|
|
29373
|
+
if (endFrac <= startFrac)
|
|
29374
|
+
continue;
|
|
29375
|
+
const slices = Math.max(1, Math.ceil((endFrac - startFrac) * 360));
|
|
29376
|
+
for (let s = 0; s < slices; s++) {
|
|
29377
|
+
const t = s / slices;
|
|
29378
|
+
const fracStart = startFrac + (endFrac - startFrac) * t;
|
|
29379
|
+
const fracEnd = startFrac + (endFrac - startFrac) * ((s + 1) / slices);
|
|
29380
|
+
const a1 = fracStart * Math.PI * 2 + angleOffset;
|
|
29381
|
+
const a2 = fracEnd * Math.PI * 2 + angleOffset;
|
|
29382
|
+
const c1 = rawStops[i].color;
|
|
29383
|
+
const c2 = rawStops[i + 1].color;
|
|
29384
|
+
const blendColor = t < 0.5 ? c1 : c2;
|
|
29385
|
+
ctx.beginPath();
|
|
29386
|
+
ctx.moveTo(scaledCx, scaledCy);
|
|
29387
|
+
ctx.arc(scaledCx, scaledCy, radius, a1, a2);
|
|
29388
|
+
ctx.closePath();
|
|
29389
|
+
ctx.fillStyle = blendColor;
|
|
29390
|
+
ctx.fill();
|
|
29391
|
+
}
|
|
29392
|
+
}
|
|
29393
|
+
}
|
|
29394
|
+
if (isCircle) {
|
|
29395
|
+
ctx.globalCompositeOperation = "destination-in";
|
|
29396
|
+
ctx.beginPath();
|
|
29397
|
+
ctx.arc(cx, cy, Math.min(cx, cy), 0, Math.PI * 2);
|
|
29398
|
+
ctx.fill();
|
|
29399
|
+
ctx.globalCompositeOperation = "source-over";
|
|
29400
|
+
}
|
|
29401
|
+
return canvas.toDataURL("image/png");
|
|
29402
|
+
} catch {
|
|
29403
|
+
return null;
|
|
29404
|
+
}
|
|
29405
|
+
}
|
|
29406
|
+
function renderBlurredElementAsImage(el, blurPx, win) {
|
|
29407
|
+
try {
|
|
29408
|
+
const rect = el.getBoundingClientRect();
|
|
29409
|
+
if (rect.width <= 0 || rect.height <= 0)
|
|
29410
|
+
return null;
|
|
29411
|
+
const doc = win.document;
|
|
29412
|
+
const computed = win.getComputedStyle(el);
|
|
29413
|
+
const spread = blurPx * 3;
|
|
29414
|
+
const canvasW = rect.width + spread * 2;
|
|
29415
|
+
const canvasH = rect.height + spread * 2;
|
|
29416
|
+
const scale = 2;
|
|
29417
|
+
const canvas = doc.createElement("canvas");
|
|
29418
|
+
canvas.width = Math.round(canvasW * scale);
|
|
29419
|
+
canvas.height = Math.round(canvasH * scale);
|
|
29420
|
+
const ctx = canvas.getContext("2d");
|
|
29421
|
+
if (!ctx)
|
|
29422
|
+
return null;
|
|
29423
|
+
ctx.scale(scale, scale);
|
|
29424
|
+
const opacity = parseFloat(computed.opacity);
|
|
29425
|
+
if (!isNaN(opacity) && opacity < 1) {
|
|
29426
|
+
ctx.globalAlpha = opacity;
|
|
29427
|
+
}
|
|
29428
|
+
ctx.filter = `blur(${blurPx}px)`;
|
|
29429
|
+
const bgImage = computed.backgroundImage;
|
|
29430
|
+
const bgColor = computed.backgroundColor;
|
|
29431
|
+
const borderRadius = parseFloat(computed.borderRadius) || 0;
|
|
29432
|
+
const isCircle = borderRadius >= Math.min(rect.width, rect.height) / 2 - 1;
|
|
29433
|
+
const offsetX = spread;
|
|
29434
|
+
const offsetY = spread;
|
|
29435
|
+
if (bgImage && bgImage !== "none" && bgImage.includes("gradient")) {
|
|
29436
|
+
if (bgImage.includes("radial-gradient")) {
|
|
29437
|
+
const centerX = offsetX + rect.width / 2;
|
|
29438
|
+
const centerY = offsetY + rect.height / 2;
|
|
29439
|
+
const gradientRadius = Math.max(rect.width, rect.height) / 2;
|
|
29440
|
+
const canvasGrad = ctx.createRadialGradient(centerX, centerY, 0, centerX, centerY, gradientRadius);
|
|
29441
|
+
const colorRegex = /rgba?\([^)]+\)|transparent|#[0-9a-fA-F]+/g;
|
|
29442
|
+
const pctRegex = /([\d.]+)%/g;
|
|
29443
|
+
const colors = Array.from(bgImage.matchAll(colorRegex)).map((m) => m[0]);
|
|
29444
|
+
const percents = Array.from(bgImage.matchAll(pctRegex)).map((m) => parseFloat(m[1]) / 100);
|
|
29445
|
+
for (let i = 0; i < colors.length; i++) {
|
|
29446
|
+
const pct = percents[i] !== void 0 ? percents[i] : i / Math.max(colors.length - 1, 1);
|
|
29447
|
+
try {
|
|
29448
|
+
canvasGrad.addColorStop(Math.min(1, Math.max(0, pct)), colors[i]);
|
|
29449
|
+
} catch {
|
|
29450
|
+
}
|
|
29451
|
+
}
|
|
29452
|
+
ctx.fillStyle = canvasGrad;
|
|
29453
|
+
} else if (bgImage.includes("linear-gradient")) {
|
|
29454
|
+
const canvasGrad = ctx.createLinearGradient(offsetX, offsetY, offsetX + rect.width, offsetY + rect.height);
|
|
29455
|
+
const colorRegex = /rgba?\([^)]+\)|transparent|#[0-9a-fA-F]+/g;
|
|
29456
|
+
const pctRegex = /([\d.]+)%/g;
|
|
29457
|
+
const colors = Array.from(bgImage.matchAll(colorRegex)).map((m) => m[0]);
|
|
29458
|
+
const percents = Array.from(bgImage.matchAll(pctRegex)).map((m) => parseFloat(m[1]) / 100);
|
|
29459
|
+
for (let i = 0; i < colors.length; i++) {
|
|
29460
|
+
const pct = percents[i] !== void 0 ? percents[i] : i / Math.max(colors.length - 1, 1);
|
|
29461
|
+
try {
|
|
29462
|
+
canvasGrad.addColorStop(Math.min(1, Math.max(0, pct)), colors[i]);
|
|
29463
|
+
} catch {
|
|
29464
|
+
}
|
|
29465
|
+
}
|
|
29466
|
+
ctx.fillStyle = canvasGrad;
|
|
29467
|
+
}
|
|
29468
|
+
} else if (bgColor && bgColor !== "rgba(0, 0, 0, 0)") {
|
|
29469
|
+
ctx.fillStyle = bgColor;
|
|
29470
|
+
}
|
|
29471
|
+
if (isCircle) {
|
|
29472
|
+
ctx.beginPath();
|
|
29473
|
+
ctx.arc(offsetX + rect.width / 2, offsetY + rect.height / 2, Math.min(rect.width, rect.height) / 2, 0, Math.PI * 2);
|
|
29474
|
+
ctx.fill();
|
|
29475
|
+
} else if (borderRadius > 0) {
|
|
29476
|
+
const r = Math.min(borderRadius, rect.width / 2, rect.height / 2);
|
|
29477
|
+
ctx.beginPath();
|
|
29478
|
+
ctx.moveTo(offsetX + r, offsetY);
|
|
29479
|
+
ctx.lineTo(offsetX + rect.width - r, offsetY);
|
|
29480
|
+
ctx.quadraticCurveTo(offsetX + rect.width, offsetY, offsetX + rect.width, offsetY + r);
|
|
29481
|
+
ctx.lineTo(offsetX + rect.width, offsetY + rect.height - r);
|
|
29482
|
+
ctx.quadraticCurveTo(offsetX + rect.width, offsetY + rect.height, offsetX + rect.width - r, offsetY + rect.height);
|
|
29483
|
+
ctx.lineTo(offsetX + r, offsetY + rect.height);
|
|
29484
|
+
ctx.quadraticCurveTo(offsetX, offsetY + rect.height, offsetX, offsetY + rect.height - r);
|
|
29485
|
+
ctx.lineTo(offsetX, offsetY + r);
|
|
29486
|
+
ctx.quadraticCurveTo(offsetX, offsetY, offsetX + r, offsetY);
|
|
29487
|
+
ctx.closePath();
|
|
29488
|
+
ctx.fill();
|
|
29489
|
+
} else {
|
|
29490
|
+
ctx.fillRect(offsetX, offsetY, rect.width, rect.height);
|
|
29491
|
+
}
|
|
29492
|
+
const dataUri = canvas.toDataURL("image/png");
|
|
29493
|
+
return {
|
|
29494
|
+
dataUri,
|
|
29495
|
+
x: rect.left - spread,
|
|
29496
|
+
y: rect.top - spread,
|
|
29497
|
+
w: canvasW,
|
|
29498
|
+
h: canvasH
|
|
29499
|
+
};
|
|
29500
|
+
} catch {
|
|
29501
|
+
return null;
|
|
29502
|
+
}
|
|
29503
|
+
}
|
|
29110
29504
|
function extractPseudoElements(el, win) {
|
|
29111
29505
|
const results = [];
|
|
29112
29506
|
const parentRect = el.getBoundingClientRect();
|
|
@@ -29164,14 +29558,13 @@ ${generateStylesCss(styleMap, themeFonts)}
|
|
|
29164
29558
|
let rectRadius = 0;
|
|
29165
29559
|
const borderRadius = pComputed.borderRadius;
|
|
29166
29560
|
const radiusValue = parseFloat(borderRadius);
|
|
29167
|
-
|
|
29561
|
+
const isCircularRadius = borderRadius.includes("%") ? radiusValue >= 50 : radiusValue > 0 && radiusValue >= Math.min(pWidth, pHeight) / 2 - 1;
|
|
29562
|
+
const aspectRatio = pWidth / pHeight;
|
|
29563
|
+
const isEllipse = isCircularRadius && aspectRatio > 0.5 && aspectRatio < 2;
|
|
29564
|
+
if (radiusValue > 0 && !isEllipse) {
|
|
29168
29565
|
if (borderRadius.includes("%")) {
|
|
29169
|
-
|
|
29170
|
-
|
|
29171
|
-
} else {
|
|
29172
|
-
const minDim = Math.min(pWidth, pHeight);
|
|
29173
|
-
rectRadius = radiusValue / 100 * pxToInch(minDim);
|
|
29174
|
-
}
|
|
29566
|
+
const minDim = Math.min(pWidth, pHeight);
|
|
29567
|
+
rectRadius = radiusValue / 100 * pxToInch(minDim);
|
|
29175
29568
|
} else {
|
|
29176
29569
|
rectRadius = pxToInch(radiusValue);
|
|
29177
29570
|
}
|
|
@@ -29193,11 +29586,12 @@ ${generateStylesCss(styleMap, themeFonts)}
|
|
|
29193
29586
|
gradient,
|
|
29194
29587
|
transparency: hasBg ? extractAlpha(pComputed.backgroundColor) : null,
|
|
29195
29588
|
line: null,
|
|
29196
|
-
rectRadius,
|
|
29589
|
+
rectRadius: isEllipse ? 0 : rectRadius,
|
|
29197
29590
|
shadow,
|
|
29198
29591
|
opacity: hasOpacity ? elementOpacity : null,
|
|
29199
|
-
isEllipse
|
|
29200
|
-
softEdge: null
|
|
29592
|
+
isEllipse,
|
|
29593
|
+
softEdge: null,
|
|
29594
|
+
customGeometry: null
|
|
29201
29595
|
}
|
|
29202
29596
|
};
|
|
29203
29597
|
results.push(shapeElement);
|
|
@@ -29269,10 +29663,23 @@ ${generateStylesCss(styleMap, themeFonts)}
|
|
|
29269
29663
|
if (transparency !== null)
|
|
29270
29664
|
options.transparency = transparency;
|
|
29271
29665
|
}
|
|
29666
|
+
const bgClip = computed.webkitBackgroundClip || computed.backgroundClip;
|
|
29667
|
+
const textFillColor = computed.webkitTextFillColor;
|
|
29668
|
+
const isTextFillTransparent = textFillColor === "transparent" || textFillColor === "rgba(0, 0, 0, 0)" || textFillColor && textFillColor.includes("rgba") && textFillColor.endsWith(", 0)");
|
|
29669
|
+
if (bgClip === "text" && isTextFillTransparent) {
|
|
29670
|
+
const bgImage = computed.backgroundImage;
|
|
29671
|
+
if (bgImage && bgImage !== "none" && (bgImage.includes("linear-gradient") || bgImage.includes("radial-gradient"))) {
|
|
29672
|
+
const textGradient = parseCssGradient(bgImage);
|
|
29673
|
+
if (textGradient) {
|
|
29674
|
+
options.fontFill = { type: "gradient", gradient: textGradient };
|
|
29675
|
+
delete options.color;
|
|
29676
|
+
}
|
|
29677
|
+
}
|
|
29678
|
+
}
|
|
29272
29679
|
if (computed.fontSize)
|
|
29273
29680
|
options.fontSize = pxToPoints(computed.fontSize);
|
|
29274
29681
|
if (computed.fontFamily) {
|
|
29275
|
-
options.fontFace = computed.fontFamily
|
|
29682
|
+
options.fontFace = extractFontFace(computed.fontFamily);
|
|
29276
29683
|
}
|
|
29277
29684
|
const runLetterSpacing = extractLetterSpacing(computed);
|
|
29278
29685
|
if (runLetterSpacing !== null)
|
|
@@ -29345,10 +29752,14 @@ ${generateStylesCss(styleMap, themeFonts)}
|
|
|
29345
29752
|
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;
|
|
29346
29753
|
const spanBgImage = computed2.backgroundImage;
|
|
29347
29754
|
const hasGradientBg = spanBgImage && spanBgImage !== "none" && (spanBgImage.includes("linear-gradient") || spanBgImage.includes("radial-gradient"));
|
|
29348
|
-
|
|
29755
|
+
const spanBgClip = computed2.webkitBackgroundClip || computed2.backgroundClip;
|
|
29756
|
+
const spanTextFillColor = computed2.webkitTextFillColor;
|
|
29757
|
+
const isGradientTextFill = hasGradientBg && spanBgClip === "text" && (spanTextFillColor === "transparent" || spanTextFillColor === "rgba(0, 0, 0, 0)" || spanTextFillColor && spanTextFillColor.includes("rgba") && spanTextFillColor.endsWith(", 0)"));
|
|
29758
|
+
if (isGradientTextFill) {
|
|
29759
|
+
} else if (hasBg || hasBorder || hasGradientBg) {
|
|
29349
29760
|
const rect2 = htmlEl.getBoundingClientRect();
|
|
29350
29761
|
if (rect2.width > 0 && rect2.height > 0) {
|
|
29351
|
-
const text2 =
|
|
29762
|
+
const text2 = getTransformedText(htmlEl, computed2);
|
|
29352
29763
|
const bgGradient = parseCssGradient(computed2.backgroundImage);
|
|
29353
29764
|
const borderRadius = computed2.borderRadius;
|
|
29354
29765
|
const radiusValue = parseFloat(borderRadius);
|
|
@@ -29372,6 +29783,8 @@ ${generateStylesCss(styleMap, themeFonts)}
|
|
|
29372
29783
|
const spanOpacity = parseFloat(computed2.opacity);
|
|
29373
29784
|
const hasSpanOpacity = !isNaN(spanOpacity) && spanOpacity < 1;
|
|
29374
29785
|
const spanShadow = parseBoxShadow(computed2.boxShadow);
|
|
29786
|
+
const spanWhiteSpace = computed2.whiteSpace;
|
|
29787
|
+
const spanShouldNotWrap = spanWhiteSpace === "nowrap" || spanWhiteSpace === "pre" || rect2.width < 100 || rect2.height < 50;
|
|
29375
29788
|
const shapeElement = {
|
|
29376
29789
|
type: "shape",
|
|
29377
29790
|
position: {
|
|
@@ -29384,11 +29797,12 @@ ${generateStylesCss(styleMap, themeFonts)}
|
|
|
29384
29797
|
textRuns: null,
|
|
29385
29798
|
style: text2 ? {
|
|
29386
29799
|
fontSize: pxToPoints(computed2.fontSize),
|
|
29387
|
-
fontFace: computed2.fontFamily
|
|
29800
|
+
fontFace: extractFontFace(computed2.fontFamily),
|
|
29388
29801
|
color: rgbToHex(computed2.color),
|
|
29389
29802
|
bold: parseInt(computed2.fontWeight) >= 600,
|
|
29390
29803
|
align: "center",
|
|
29391
|
-
valign: "middle"
|
|
29804
|
+
valign: "middle",
|
|
29805
|
+
wrap: !spanShouldNotWrap
|
|
29392
29806
|
} : null,
|
|
29393
29807
|
shape: {
|
|
29394
29808
|
fill: hasBg ? rgbToHex(computed2.backgroundColor) : null,
|
|
@@ -29397,13 +29811,15 @@ ${generateStylesCss(styleMap, themeFonts)}
|
|
|
29397
29811
|
line: hasUniformBorder ? {
|
|
29398
29812
|
color: rgbToHex(computed2.borderColor),
|
|
29399
29813
|
width: pxToPoints(borderTop),
|
|
29400
|
-
transparency: extractAlpha(computed2.borderColor)
|
|
29814
|
+
transparency: extractAlpha(computed2.borderColor),
|
|
29815
|
+
dashType: extractDashType(computed2.borderStyle)
|
|
29401
29816
|
} : null,
|
|
29402
29817
|
rectRadius: spanIsEllipse ? 0 : rectRadius,
|
|
29403
29818
|
shadow: spanShadow,
|
|
29404
29819
|
opacity: hasSpanOpacity ? spanOpacity : null,
|
|
29405
29820
|
isEllipse: spanIsEllipse,
|
|
29406
|
-
softEdge: null
|
|
29821
|
+
softEdge: null,
|
|
29822
|
+
customGeometry: null
|
|
29407
29823
|
}
|
|
29408
29824
|
};
|
|
29409
29825
|
elements.push(shapeElement);
|
|
@@ -29414,15 +29830,29 @@ ${generateStylesCss(styleMap, themeFonts)}
|
|
|
29414
29830
|
const parent = el.parentElement;
|
|
29415
29831
|
if (parent && parent.tagName === "DIV") {
|
|
29416
29832
|
const rect2 = htmlEl.getBoundingClientRect();
|
|
29417
|
-
const
|
|
29833
|
+
const computed22 = win.getComputedStyle(el);
|
|
29834
|
+
const text2 = getTransformedText(htmlEl, computed22);
|
|
29418
29835
|
if (rect2.width > 0 && rect2.height > 0 && text2) {
|
|
29419
|
-
const computed22 = win.getComputedStyle(el);
|
|
29420
29836
|
const fontSizePx2 = parseFloat(computed22.fontSize);
|
|
29421
29837
|
const lineHeightPx2 = parseFloat(computed22.lineHeight);
|
|
29422
29838
|
const lineHeightMultiplier2 = fontSizePx2 > 0 && !isNaN(lineHeightPx2) ? lineHeightPx2 / fontSizePx2 : 1;
|
|
29839
|
+
const span2BgClip = computed22.webkitBackgroundClip || computed22.backgroundClip;
|
|
29840
|
+
const span2TextFillColor = computed22.webkitTextFillColor;
|
|
29841
|
+
const span2IsGradientText = span2BgClip === "text" && (span2TextFillColor === "transparent" || span2TextFillColor === "rgba(0, 0, 0, 0)" || span2TextFillColor && span2TextFillColor.includes("rgba") && span2TextFillColor.endsWith(", 0)"));
|
|
29842
|
+
const span2BgImage = computed22.backgroundImage;
|
|
29843
|
+
const span2HasGradientBg = span2BgImage && span2BgImage !== "none" && (span2BgImage.includes("linear-gradient") || span2BgImage.includes("radial-gradient"));
|
|
29844
|
+
let spanFontFill = void 0;
|
|
29845
|
+
let spanTextColor = rgbToHex(computed22.color);
|
|
29846
|
+
if (span2IsGradientText && span2HasGradientBg) {
|
|
29847
|
+
const spanGradient = parseCssGradient(span2BgImage);
|
|
29848
|
+
if (spanGradient) {
|
|
29849
|
+
spanFontFill = { type: "gradient", gradient: spanGradient };
|
|
29850
|
+
spanTextColor = null;
|
|
29851
|
+
}
|
|
29852
|
+
}
|
|
29423
29853
|
const textElement = {
|
|
29424
29854
|
type: "p",
|
|
29425
|
-
text: [{ text: text2, options: {} }],
|
|
29855
|
+
text: [{ text: text2, options: spanFontFill ? { fontFill: spanFontFill } : {} }],
|
|
29426
29856
|
position: {
|
|
29427
29857
|
x: pxToInch(rect2.left),
|
|
29428
29858
|
y: pxToInch(rect2.top),
|
|
@@ -29431,13 +29861,14 @@ ${generateStylesCss(styleMap, themeFonts)}
|
|
|
29431
29861
|
},
|
|
29432
29862
|
style: {
|
|
29433
29863
|
fontSize: pxToPoints(computed22.fontSize),
|
|
29434
|
-
fontFace: computed22.fontFamily
|
|
29435
|
-
color:
|
|
29864
|
+
fontFace: extractFontFace(computed22.fontFamily),
|
|
29865
|
+
color: spanTextColor,
|
|
29436
29866
|
bold: parseInt(computed22.fontWeight) >= 600,
|
|
29437
29867
|
italic: computed22.fontStyle === "italic",
|
|
29438
29868
|
align: computed22.textAlign === "center" ? "center" : computed22.textAlign === "right" ? "right" : "left",
|
|
29439
29869
|
valign: "middle",
|
|
29440
|
-
lineSpacing: lineHeightMultiplier2 * pxToPoints(computed22.fontSize)
|
|
29870
|
+
lineSpacing: lineHeightMultiplier2 * pxToPoints(computed22.fontSize),
|
|
29871
|
+
fontFill: spanFontFill
|
|
29441
29872
|
}
|
|
29442
29873
|
};
|
|
29443
29874
|
elements.push(textElement);
|
|
@@ -29576,7 +30007,7 @@ ${generateStylesCss(styleMap, themeFonts)}
|
|
|
29576
30007
|
return;
|
|
29577
30008
|
}
|
|
29578
30009
|
}
|
|
29579
|
-
if (el.tagName === "svg") {
|
|
30010
|
+
if (el.tagName.toLowerCase() === "svg") {
|
|
29580
30011
|
const rect2 = htmlEl.getBoundingClientRect();
|
|
29581
30012
|
if (rect2.width > 0 && rect2.height > 0) {
|
|
29582
30013
|
const computedStyle = win.getComputedStyle(htmlEl);
|
|
@@ -29626,30 +30057,73 @@ ${generateStylesCss(styleMap, themeFonts)}
|
|
|
29626
30057
|
}
|
|
29627
30058
|
return null;
|
|
29628
30059
|
};
|
|
29629
|
-
const
|
|
29630
|
-
|
|
30060
|
+
const originalElements = [el, ...Array.from(el.querySelectorAll("*"))];
|
|
30061
|
+
const computedStylesMap = /* @__PURE__ */ new Map();
|
|
30062
|
+
originalElements.forEach((origEl, index) => {
|
|
30063
|
+
const isSvgElement = origEl.namespaceURI === "http://www.w3.org/2000/svg";
|
|
30064
|
+
if (isSvgElement) {
|
|
30065
|
+
const style = win.getComputedStyle(origEl);
|
|
30066
|
+
computedStylesMap.set(index, {
|
|
30067
|
+
fill: style.fill || "",
|
|
30068
|
+
stroke: style.stroke || "",
|
|
30069
|
+
strokeWidth: style.strokeWidth || ""
|
|
30070
|
+
});
|
|
30071
|
+
}
|
|
30072
|
+
});
|
|
30073
|
+
const cloneElements = [svgClone, ...Array.from(svgClone.querySelectorAll("*"))];
|
|
30074
|
+
cloneElements.forEach((cloneEl, index) => {
|
|
30075
|
+
const isSvgElement = cloneEl.namespaceURI === "http://www.w3.org/2000/svg";
|
|
30076
|
+
const fill = cloneEl.getAttribute("fill");
|
|
29631
30077
|
const resolvedFill = resolveColorValue(fill);
|
|
29632
30078
|
if (resolvedFill) {
|
|
29633
|
-
|
|
30079
|
+
cloneEl.setAttribute("fill", resolvedFill);
|
|
30080
|
+
} else if (!fill && isSvgElement) {
|
|
30081
|
+
const computed2 = computedStylesMap.get(index);
|
|
30082
|
+
if (computed2 && computed2.fill) {
|
|
30083
|
+
if (computed2.fill === "none") {
|
|
30084
|
+
cloneEl.setAttribute("fill", "none");
|
|
30085
|
+
} else if (computed2.fill !== "rgb(0, 0, 0)") {
|
|
30086
|
+
cloneEl.setAttribute("fill", computed2.fill);
|
|
30087
|
+
}
|
|
30088
|
+
}
|
|
29634
30089
|
}
|
|
29635
|
-
const stroke =
|
|
30090
|
+
const stroke = cloneEl.getAttribute("stroke");
|
|
29636
30091
|
const resolvedStroke = resolveColorValue(stroke);
|
|
29637
30092
|
if (resolvedStroke) {
|
|
29638
|
-
|
|
30093
|
+
cloneEl.setAttribute("stroke", resolvedStroke);
|
|
30094
|
+
} else if (!stroke && isSvgElement) {
|
|
30095
|
+
const computed2 = computedStylesMap.get(index);
|
|
30096
|
+
if (computed2 && computed2.stroke && computed2.stroke !== "none") {
|
|
30097
|
+
cloneEl.setAttribute("stroke", computed2.stroke);
|
|
30098
|
+
}
|
|
30099
|
+
if (computed2 && computed2.strokeWidth && computed2.strokeWidth !== "1px" && !cloneEl.getAttribute("stroke-width")) {
|
|
30100
|
+
cloneEl.setAttribute("stroke-width", computed2.strokeWidth);
|
|
30101
|
+
}
|
|
29639
30102
|
}
|
|
29640
|
-
|
|
29641
|
-
};
|
|
29642
|
-
resolveDynamicColors(svgClone);
|
|
30103
|
+
});
|
|
29643
30104
|
const serializer = new XMLSerializer();
|
|
29644
30105
|
const svgString = serializer.serializeToString(svgClone);
|
|
29645
30106
|
const svgBase64 = btoa(unescape(encodeURIComponent(svgString)));
|
|
29646
30107
|
const dataUri = `data:image/svg+xml;base64,${svgBase64}`;
|
|
30108
|
+
let svgY = rect2.top;
|
|
30109
|
+
const computedAlign = win.getComputedStyle(htmlEl);
|
|
30110
|
+
const verticalAlign = computedAlign.verticalAlign;
|
|
30111
|
+
if (verticalAlign === "middle" && el.parentElement) {
|
|
30112
|
+
const parentComputed = win.getComputedStyle(el.parentElement);
|
|
30113
|
+
const parentIsFlex = parentComputed.display === "flex" || parentComputed.display === "inline-flex";
|
|
30114
|
+
if (!parentIsFlex) {
|
|
30115
|
+
const parentRect = el.parentElement.getBoundingClientRect();
|
|
30116
|
+
if (parentRect.height > rect2.height) {
|
|
30117
|
+
svgY = parentRect.top + (parentRect.height - rect2.height) / 2;
|
|
30118
|
+
}
|
|
30119
|
+
}
|
|
30120
|
+
}
|
|
29647
30121
|
const imageElement = {
|
|
29648
30122
|
type: "image",
|
|
29649
30123
|
src: dataUri,
|
|
29650
30124
|
position: {
|
|
29651
30125
|
x: pxToInch(rect2.left),
|
|
29652
|
-
y: pxToInch(
|
|
30126
|
+
y: pxToInch(svgY),
|
|
29653
30127
|
w: pxToInch(rect2.width),
|
|
29654
30128
|
h: pxToInch(rect2.height)
|
|
29655
30129
|
},
|
|
@@ -29662,13 +30136,131 @@ ${generateStylesCss(styleMap, themeFonts)}
|
|
|
29662
30136
|
}
|
|
29663
30137
|
}
|
|
29664
30138
|
if (el.tagName === "I") {
|
|
30139
|
+
const rect2 = htmlEl.getBoundingClientRect();
|
|
30140
|
+
if (rect2.width > 0 && rect2.height > 0) {
|
|
30141
|
+
const computed2 = win.getComputedStyle(htmlEl);
|
|
30142
|
+
const beforeComputed = win.getComputedStyle(htmlEl, "::before");
|
|
30143
|
+
const fontFamily = beforeComputed.fontFamily || computed2.fontFamily;
|
|
30144
|
+
const content = beforeComputed.content;
|
|
30145
|
+
const isFontIcon = fontFamily.toLowerCase().includes("font awesome") || fontFamily.toLowerCase().includes("fontawesome") || fontFamily.toLowerCase().includes("fa ") || fontFamily.toLowerCase().includes("material") || fontFamily.toLowerCase().includes("icon");
|
|
30146
|
+
if (isFontIcon && content && content !== "none" && content !== "normal") {
|
|
30147
|
+
try {
|
|
30148
|
+
const scale = 8;
|
|
30149
|
+
const w2 = Math.ceil(rect2.width);
|
|
30150
|
+
const h2 = Math.ceil(rect2.height);
|
|
30151
|
+
const iframeDoc = win.document;
|
|
30152
|
+
const canvas = iframeDoc.createElement("canvas");
|
|
30153
|
+
canvas.width = w2 * scale;
|
|
30154
|
+
canvas.height = h2 * scale;
|
|
30155
|
+
const ctx = canvas.getContext("2d");
|
|
30156
|
+
if (ctx) {
|
|
30157
|
+
ctx.scale(scale, scale);
|
|
30158
|
+
let iconChar = content.replace(/['"]/g, "");
|
|
30159
|
+
if (iconChar.startsWith("\\")) {
|
|
30160
|
+
const codePoint = parseInt(iconChar.slice(1), 16);
|
|
30161
|
+
if (!isNaN(codePoint)) {
|
|
30162
|
+
iconChar = String.fromCodePoint(codePoint);
|
|
30163
|
+
}
|
|
30164
|
+
}
|
|
30165
|
+
const fontSize = parseFloat(beforeComputed.fontSize) || parseFloat(computed2.fontSize) || 16;
|
|
30166
|
+
const fontWeight = beforeComputed.fontWeight || computed2.fontWeight || "900";
|
|
30167
|
+
const fontFamilies = fontFamily.split(",").map((f) => f.trim().replace(/['"]/g, ""));
|
|
30168
|
+
let fontSet = false;
|
|
30169
|
+
for (const ff of fontFamilies) {
|
|
30170
|
+
const fontSpec = `${fontWeight} ${fontSize}px "${ff}"`;
|
|
30171
|
+
if (iframeDoc.fonts && iframeDoc.fonts.check(fontSpec)) {
|
|
30172
|
+
ctx.font = fontSpec;
|
|
30173
|
+
fontSet = true;
|
|
30174
|
+
break;
|
|
30175
|
+
}
|
|
30176
|
+
}
|
|
30177
|
+
if (!fontSet) {
|
|
30178
|
+
ctx.font = `${fontWeight} ${fontSize}px ${fontFamily}`;
|
|
30179
|
+
}
|
|
30180
|
+
ctx.fillStyle = computed2.color || "white";
|
|
30181
|
+
ctx.textAlign = "center";
|
|
30182
|
+
ctx.textBaseline = "middle";
|
|
30183
|
+
ctx.fillText(iconChar, w2 / 2, h2 / 2);
|
|
30184
|
+
const dataUri = canvas.toDataURL("image/png");
|
|
30185
|
+
const imageElement = {
|
|
30186
|
+
type: "image",
|
|
30187
|
+
src: dataUri,
|
|
30188
|
+
position: {
|
|
30189
|
+
x: pxToInch(rect2.left),
|
|
30190
|
+
y: pxToInch(rect2.top),
|
|
30191
|
+
w: pxToInch(rect2.width),
|
|
30192
|
+
h: pxToInch(rect2.height)
|
|
30193
|
+
},
|
|
30194
|
+
sizing: null
|
|
30195
|
+
};
|
|
30196
|
+
elements.push(imageElement);
|
|
30197
|
+
}
|
|
30198
|
+
} catch {
|
|
30199
|
+
}
|
|
30200
|
+
}
|
|
30201
|
+
}
|
|
29665
30202
|
processed.add(el);
|
|
29666
30203
|
return;
|
|
29667
30204
|
}
|
|
29668
30205
|
const isContainer = el.tagName === "DIV" && !textTags.includes(el.tagName);
|
|
29669
30206
|
if (isContainer) {
|
|
29670
30207
|
const computed2 = win.getComputedStyle(el);
|
|
30208
|
+
const divFilterStr = computed2.filter;
|
|
30209
|
+
if (divFilterStr && divFilterStr !== "none") {
|
|
30210
|
+
const divBlurMatch = divFilterStr.match(/blur\(([\d.]+)px\)/);
|
|
30211
|
+
if (divBlurMatch) {
|
|
30212
|
+
const divBlurPx = parseFloat(divBlurMatch[1]);
|
|
30213
|
+
if (divBlurPx > 20) {
|
|
30214
|
+
const blurResult = renderBlurredElementAsImage(htmlEl, divBlurPx, win);
|
|
30215
|
+
if (blurResult) {
|
|
30216
|
+
const imgElement = {
|
|
30217
|
+
type: "image",
|
|
30218
|
+
src: blurResult.dataUri,
|
|
30219
|
+
position: {
|
|
30220
|
+
x: pxToInch(blurResult.x),
|
|
30221
|
+
y: pxToInch(blurResult.y),
|
|
30222
|
+
w: pxToInch(blurResult.w),
|
|
30223
|
+
h: pxToInch(blurResult.h)
|
|
30224
|
+
},
|
|
30225
|
+
sizing: null,
|
|
30226
|
+
rectRadius: 0
|
|
30227
|
+
};
|
|
30228
|
+
elements.push(imgElement);
|
|
30229
|
+
processed.add(el);
|
|
30230
|
+
el.querySelectorAll("*").forEach((child) => processed.add(child));
|
|
30231
|
+
return;
|
|
30232
|
+
}
|
|
30233
|
+
}
|
|
30234
|
+
}
|
|
30235
|
+
}
|
|
30236
|
+
const divBgImageForConic = computed2.backgroundImage;
|
|
30237
|
+
if (divBgImageForConic && divBgImageForConic.includes("conic-gradient")) {
|
|
30238
|
+
const rect2 = htmlEl.getBoundingClientRect();
|
|
30239
|
+
if (rect2.width > 0 && rect2.height > 0) {
|
|
30240
|
+
const borderRadiusStr = computed2.borderRadius;
|
|
30241
|
+
const radiusVal = parseFloat(borderRadiusStr);
|
|
30242
|
+
const isCircular = borderRadiusStr.includes("%") ? radiusVal >= 50 : radiusVal > 0 && radiusVal >= Math.min(rect2.width, rect2.height) / 2 - 1;
|
|
30243
|
+
const conicDataUri = renderConicGradientAsImage(divBgImageForConic, rect2.width, rect2.height, isCircular, win.document);
|
|
30244
|
+
if (conicDataUri) {
|
|
30245
|
+
const imgElement = {
|
|
30246
|
+
type: "image",
|
|
30247
|
+
src: conicDataUri,
|
|
30248
|
+
position: {
|
|
30249
|
+
x: pxToInch(rect2.left),
|
|
30250
|
+
y: pxToInch(rect2.top),
|
|
30251
|
+
w: pxToInch(rect2.width),
|
|
30252
|
+
h: pxToInch(rect2.height)
|
|
30253
|
+
},
|
|
30254
|
+
sizing: null,
|
|
30255
|
+
rectRadius: 0
|
|
30256
|
+
};
|
|
30257
|
+
elements.push(imgElement);
|
|
30258
|
+
}
|
|
30259
|
+
}
|
|
30260
|
+
}
|
|
29671
30261
|
const hasBg = computed2.backgroundColor && computed2.backgroundColor !== "rgba(0, 0, 0, 0)";
|
|
30262
|
+
const clipPathValue = computed2.clipPath || computed2.webkitClipPath;
|
|
30263
|
+
const clipPathPolygon = parseClipPathPolygon(clipPathValue);
|
|
29672
30264
|
const elBgImage = computed2.backgroundImage;
|
|
29673
30265
|
let bgImageUrl = null;
|
|
29674
30266
|
let bgImageSize = null;
|
|
@@ -29784,14 +30376,22 @@ ${generateStylesCss(styleMap, themeFonts)}
|
|
|
29784
30376
|
if (textTagSet.has(child.tagName))
|
|
29785
30377
|
return true;
|
|
29786
30378
|
if (child.tagName === "DIV") {
|
|
30379
|
+
const childComputed = win.getComputedStyle(child);
|
|
30380
|
+
const childDisplay = childComputed.display;
|
|
30381
|
+
const childFlexDir = childComputed.flexDirection || "row";
|
|
30382
|
+
const childChildCount = child.children.length;
|
|
30383
|
+
const isFlexRowLayout = (childDisplay === "flex" || childDisplay === "inline-flex") && (childFlexDir === "row" || childFlexDir === "row-reverse") && childChildCount > 1;
|
|
30384
|
+
const isGridLayout = childDisplay === "grid" || childDisplay === "inline-grid";
|
|
30385
|
+
if (isFlexRowLayout || isGridLayout)
|
|
30386
|
+
return false;
|
|
29787
30387
|
const childElements = Array.from(child.children);
|
|
29788
|
-
const
|
|
30388
|
+
const inlineTextTags = /* @__PURE__ */ new Set(["STRONG", "EM", "B", "I", "A", "BR", "SPAN", "MARK", "SMALL", "SUB", "SUP", "CODE", "U", "S", "Q", "CITE", "ABBR", "TIME", "DATA"]);
|
|
30389
|
+
const isTextOnlyDiv = childElements.length === 0 || childElements.every((ce) => inlineTextTags.has(ce.tagName)) || childElements.length === 1 && childElements[0].tagName === "P" && (childElements[0].children.length === 0 || Array.from(childElements[0].children).every((ce) => inlineTextTags.has(ce.tagName)));
|
|
29789
30390
|
if (!isTextOnlyDiv)
|
|
29790
30391
|
return false;
|
|
29791
30392
|
const childText = child.textContent?.trim();
|
|
29792
30393
|
if (!childText)
|
|
29793
30394
|
return false;
|
|
29794
|
-
const childComputed = win.getComputedStyle(child);
|
|
29795
30395
|
const childHasBg = childComputed.backgroundColor && childComputed.backgroundColor !== "rgba(0, 0, 0, 0)";
|
|
29796
30396
|
const childHasBgImg = childComputed.backgroundImage && childComputed.backgroundImage !== "none";
|
|
29797
30397
|
const childBorders = [
|
|
@@ -29807,10 +30407,11 @@ ${generateStylesCss(styleMap, themeFonts)}
|
|
|
29807
30407
|
});
|
|
29808
30408
|
const decorativeTags = /* @__PURE__ */ new Set(["I", "SVG", "CANVAS", "VIDEO", "AUDIO", "IFRAME"]);
|
|
29809
30409
|
const nonTextChildren = allChildren.filter((child) => !textTagSet.has(child.tagName) && !decorativeTags.has(child.tagName) && !(child.tagName === "DIV" && textChildren.includes(child)));
|
|
30410
|
+
const inlineTextTagsForSimple = /* @__PURE__ */ new Set(["STRONG", "EM", "B", "I", "A", "BR", "SPAN", "MARK", "SMALL", "SUB", "SUP", "CODE", "U", "S", "Q", "CITE", "ABBR", "TIME", "DATA"]);
|
|
29810
30411
|
const isSingleTextChild = textChildren.length === 1 && (() => {
|
|
29811
30412
|
const tc = textChildren[0];
|
|
29812
30413
|
const tcChildren = Array.from(tc.children);
|
|
29813
|
-
return tcChildren.length === 0 || tcChildren.every((ce) => ce.tagName
|
|
30414
|
+
return tcChildren.length === 0 || tcChildren.every((ce) => inlineTextTagsForSimple.has(ce.tagName)) || tcChildren.length === 1 && tcChildren[0].tagName === "P" && (tcChildren[0].children.length === 0 || Array.from(tcChildren[0].children).every((ce) => inlineTextTagsForSimple.has(ce.tagName)));
|
|
29814
30415
|
})() && nonTextChildren.length === 0;
|
|
29815
30416
|
const display = computed2.display;
|
|
29816
30417
|
const isFlexContainer2 = display === "flex" || display === "inline-flex";
|
|
@@ -29854,26 +30455,32 @@ ${generateStylesCss(styleMap, themeFonts)}
|
|
|
29854
30455
|
} else if (textAlign2 === "right" || textAlign2 === "end") {
|
|
29855
30456
|
align = "right";
|
|
29856
30457
|
} else {
|
|
29857
|
-
|
|
29858
|
-
const paddingRight = parseFloat(computed2.paddingRight) || 0;
|
|
29859
|
-
const paddingDiff = Math.abs(paddingLeft - paddingRight);
|
|
29860
|
-
if (paddingLeft > 0 && paddingDiff < 2) {
|
|
29861
|
-
align = "center";
|
|
29862
|
-
} else {
|
|
29863
|
-
align = "left";
|
|
29864
|
-
}
|
|
30458
|
+
align = "left";
|
|
29865
30459
|
}
|
|
29866
30460
|
}
|
|
29867
30461
|
let shapeText = "";
|
|
29868
30462
|
let shapeTextRuns = null;
|
|
29869
30463
|
let shapeStyle = null;
|
|
29870
30464
|
const hasTextChildren = textChildren.length > 0;
|
|
29871
|
-
|
|
30465
|
+
let directTextContent = "";
|
|
30466
|
+
if (!hasTextChildren) {
|
|
30467
|
+
for (const node of Array.from(el.childNodes)) {
|
|
30468
|
+
if (node.nodeType === Node.TEXT_NODE) {
|
|
30469
|
+
directTextContent += node.textContent || "";
|
|
30470
|
+
}
|
|
30471
|
+
}
|
|
30472
|
+
directTextContent = directTextContent.trim();
|
|
30473
|
+
if (directTextContent && computed2.textTransform && computed2.textTransform !== "none") {
|
|
30474
|
+
directTextContent = applyTextTransform(directTextContent, computed2.textTransform);
|
|
30475
|
+
}
|
|
30476
|
+
}
|
|
30477
|
+
const hasDirectText = directTextContent.length > 0;
|
|
30478
|
+
const shouldMergeText = hasTextChildren && (isSingleTextChild || nonTextChildren.length === 0) || hasDirectText;
|
|
29872
30479
|
if (shouldMergeText) {
|
|
29873
30480
|
if (isSingleTextChild) {
|
|
29874
30481
|
const textEl = textChildren[0];
|
|
29875
30482
|
const textComputed = win.getComputedStyle(textEl);
|
|
29876
|
-
shapeText = textEl
|
|
30483
|
+
shapeText = getTransformedText(textEl, textComputed);
|
|
29877
30484
|
let fontFill = null;
|
|
29878
30485
|
const textBgClip = textComputed.webkitBackgroundClip || textComputed.backgroundClip;
|
|
29879
30486
|
const textFillColor2 = textComputed.webkitTextFillColor;
|
|
@@ -29904,7 +30511,7 @@ ${generateStylesCss(styleMap, themeFonts)}
|
|
|
29904
30511
|
const shouldNotWrap = whiteSpace === "nowrap" || whiteSpace === "pre" || rect2.width < 100 || rect2.height < 50;
|
|
29905
30512
|
shapeStyle = {
|
|
29906
30513
|
fontSize: pxToPoints(textComputed.fontSize || computed2.fontSize),
|
|
29907
|
-
fontFace: (textComputed.fontFamily || computed2.fontFamily)
|
|
30514
|
+
fontFace: extractFontFace(textComputed.fontFamily || computed2.fontFamily),
|
|
29908
30515
|
color: fontFill ? null : rgbToHex(effectiveColor),
|
|
29909
30516
|
fontFill,
|
|
29910
30517
|
bold: isBold,
|
|
@@ -29923,12 +30530,12 @@ ${generateStylesCss(styleMap, themeFonts)}
|
|
|
29923
30530
|
shapeStyle.textShadow = shapeTextShadow.shadow;
|
|
29924
30531
|
processed.add(textEl);
|
|
29925
30532
|
textEl.querySelectorAll("*").forEach((desc) => processed.add(desc));
|
|
29926
|
-
} else {
|
|
30533
|
+
} else if (hasTextChildren) {
|
|
29927
30534
|
shapeTextRuns = [];
|
|
29928
30535
|
textChildren.forEach((textChild, idx) => {
|
|
29929
30536
|
const textEl = textChild;
|
|
29930
30537
|
const textComputed = win.getComputedStyle(textEl);
|
|
29931
|
-
const fullText = textEl
|
|
30538
|
+
const fullText = getTransformedText(textEl, textComputed);
|
|
29932
30539
|
if (!fullText)
|
|
29933
30540
|
return;
|
|
29934
30541
|
const isBold = textComputed.fontWeight === "bold" || parseInt(textComputed.fontWeight) >= 600;
|
|
@@ -29936,7 +30543,7 @@ ${generateStylesCss(styleMap, themeFonts)}
|
|
|
29936
30543
|
const isUnderline = textComputed.textDecoration && textComputed.textDecoration.includes("underline");
|
|
29937
30544
|
const baseRunOptions = {
|
|
29938
30545
|
fontSize: pxToPoints(textComputed.fontSize),
|
|
29939
|
-
fontFace: textComputed.fontFamily
|
|
30546
|
+
fontFace: extractFontFace(textComputed.fontFamily),
|
|
29940
30547
|
color: rgbToHex(textComputed.color),
|
|
29941
30548
|
bold: isBold,
|
|
29942
30549
|
italic: isItalic,
|
|
@@ -29962,6 +30569,9 @@ ${generateStylesCss(styleMap, themeFonts)}
|
|
|
29962
30569
|
if (currentSegment.trim())
|
|
29963
30570
|
segments.push(currentSegment.trim());
|
|
29964
30571
|
segments = segments.filter((s) => s.length > 0);
|
|
30572
|
+
if (textComputed.textTransform && textComputed.textTransform !== "none") {
|
|
30573
|
+
segments = segments.map((s) => applyTextTransform(s, textComputed.textTransform));
|
|
30574
|
+
}
|
|
29965
30575
|
segments.forEach((segment, segIdx) => {
|
|
29966
30576
|
const prefix = segIdx === 0 && idx > 0 && shapeTextRuns.length > 0 ? "\n" : "";
|
|
29967
30577
|
const runText = prefix + segment;
|
|
@@ -29984,6 +30594,26 @@ ${generateStylesCss(styleMap, themeFonts)}
|
|
|
29984
30594
|
valign: valign2,
|
|
29985
30595
|
inset: 0
|
|
29986
30596
|
};
|
|
30597
|
+
} else if (hasDirectText) {
|
|
30598
|
+
shapeText = directTextContent;
|
|
30599
|
+
const isBold = parseInt(computed2.fontWeight) >= 600;
|
|
30600
|
+
const isItalic = computed2.fontStyle === "italic";
|
|
30601
|
+
const whiteSpace = computed2.whiteSpace;
|
|
30602
|
+
const shouldNotWrap = whiteSpace === "nowrap" || whiteSpace === "pre" || rect2.width < 100 || rect2.height < 50;
|
|
30603
|
+
shapeStyle = {
|
|
30604
|
+
fontSize: pxToPoints(computed2.fontSize),
|
|
30605
|
+
fontFace: extractFontFace(computed2.fontFamily),
|
|
30606
|
+
color: rgbToHex(computed2.color),
|
|
30607
|
+
bold: isBold,
|
|
30608
|
+
italic: isItalic,
|
|
30609
|
+
align,
|
|
30610
|
+
valign: valign2,
|
|
30611
|
+
inset: 0,
|
|
30612
|
+
wrap: !shouldNotWrap
|
|
30613
|
+
};
|
|
30614
|
+
const ls = extractLetterSpacing(computed2);
|
|
30615
|
+
if (ls !== null)
|
|
30616
|
+
shapeStyle.charSpacing = ls;
|
|
29987
30617
|
}
|
|
29988
30618
|
}
|
|
29989
30619
|
if (hasBg || hasUniformBorder || bgGradient) {
|
|
@@ -30028,7 +30658,8 @@ ${generateStylesCss(styleMap, themeFonts)}
|
|
|
30028
30658
|
line: hasUniformBorder ? {
|
|
30029
30659
|
color: rgbToHex(computed2.borderColor),
|
|
30030
30660
|
width: pxToPoints(computed2.borderWidth),
|
|
30031
|
-
transparency: extractAlpha(computed2.borderColor)
|
|
30661
|
+
transparency: extractAlpha(computed2.borderColor),
|
|
30662
|
+
dashType: extractDashType(computed2.borderStyle)
|
|
30032
30663
|
} : null,
|
|
30033
30664
|
rectRadius: (() => {
|
|
30034
30665
|
if (isEllipse)
|
|
@@ -30050,12 +30681,43 @@ ${generateStylesCss(styleMap, themeFonts)}
|
|
|
30050
30681
|
shadow,
|
|
30051
30682
|
opacity: hasOpacity ? elementOpacity : null,
|
|
30052
30683
|
isEllipse,
|
|
30053
|
-
softEdge: softEdgePt
|
|
30684
|
+
softEdge: softEdgePt,
|
|
30685
|
+
customGeometry: clipPathPolygon ? (() => {
|
|
30686
|
+
const EMU2 = 914400;
|
|
30687
|
+
const pathW = Math.round(rect2.width / PX_PER_IN * EMU2);
|
|
30688
|
+
const pathH = Math.round(rect2.height / PX_PER_IN * EMU2);
|
|
30689
|
+
const points = [];
|
|
30690
|
+
clipPathPolygon.forEach((pt, i) => {
|
|
30691
|
+
points.push({
|
|
30692
|
+
x: Math.round(pt.x * pathW),
|
|
30693
|
+
y: Math.round(pt.y * pathH),
|
|
30694
|
+
...i === 0 ? { moveTo: true } : {}
|
|
30695
|
+
});
|
|
30696
|
+
});
|
|
30697
|
+
points.push({ x: 0, y: 0, close: true });
|
|
30698
|
+
return points;
|
|
30699
|
+
})() : null
|
|
30054
30700
|
}
|
|
30055
30701
|
};
|
|
30056
30702
|
if (hasPadding && shapeElement.style && (shapeText || shapeTextRuns && shapeTextRuns.length > 0)) {
|
|
30703
|
+
let effectiveLeftPadding = paddingLeft;
|
|
30704
|
+
if (hasDirectText && allChildren.length > 0) {
|
|
30705
|
+
for (const child of allChildren) {
|
|
30706
|
+
if (child.nodeType === Node.ELEMENT_NODE) {
|
|
30707
|
+
const childEl = child;
|
|
30708
|
+
const childRect = childEl.getBoundingClientRect();
|
|
30709
|
+
const childComputed = win.getComputedStyle(childEl);
|
|
30710
|
+
const marginRight = parseFloat(childComputed.marginRight) || 0;
|
|
30711
|
+
effectiveLeftPadding += childRect.width + marginRight;
|
|
30712
|
+
}
|
|
30713
|
+
}
|
|
30714
|
+
const gap = parseFloat(computed2.gap) || 0;
|
|
30715
|
+
if (gap > 0 && allChildren.length > 0) {
|
|
30716
|
+
effectiveLeftPadding += gap;
|
|
30717
|
+
}
|
|
30718
|
+
}
|
|
30057
30719
|
shapeElement.style.margin = [
|
|
30058
|
-
|
|
30720
|
+
effectiveLeftPadding * PT_PER_PX,
|
|
30059
30721
|
// left
|
|
30060
30722
|
paddingRight * PT_PER_PX,
|
|
30061
30723
|
// right
|
|
@@ -30081,6 +30743,11 @@ ${generateStylesCss(styleMap, themeFonts)}
|
|
|
30081
30743
|
elements.push(fontFillTextElement);
|
|
30082
30744
|
} else if (isSingleTextChild) {
|
|
30083
30745
|
processed.delete(textChildren[0]);
|
|
30746
|
+
} else if (textChildren.length > 0) {
|
|
30747
|
+
textChildren.forEach((tc) => {
|
|
30748
|
+
processed.delete(tc);
|
|
30749
|
+
tc.querySelectorAll("*").forEach((desc) => processed.delete(desc));
|
|
30750
|
+
});
|
|
30084
30751
|
}
|
|
30085
30752
|
elements.push(...borderLines);
|
|
30086
30753
|
processed.add(el);
|
|
@@ -30090,6 +30757,7 @@ ${generateStylesCss(styleMap, themeFonts)}
|
|
|
30090
30757
|
if (isContainer) {
|
|
30091
30758
|
const rect2 = htmlEl.getBoundingClientRect();
|
|
30092
30759
|
if (rect2.width > 0 && rect2.height > 0) {
|
|
30760
|
+
const inlineTextTagsSet = /* @__PURE__ */ new Set(["STRONG", "EM", "B", "I", "A", "BR", "SPAN", "MARK", "SMALL", "SUB", "SUP", "CODE", "U", "S", "Q", "CITE", "ABBR", "TIME", "DATA"]);
|
|
30093
30761
|
let directText = "";
|
|
30094
30762
|
for (const child of Array.from(el.childNodes)) {
|
|
30095
30763
|
if (child.nodeType === Node.TEXT_NODE) {
|
|
@@ -30098,33 +30766,107 @@ ${generateStylesCss(styleMap, themeFonts)}
|
|
|
30098
30766
|
}
|
|
30099
30767
|
directText = directText.trim();
|
|
30100
30768
|
const childElements = Array.from(el.children);
|
|
30101
|
-
|
|
30769
|
+
const singlePInlineCheck = /* @__PURE__ */ new Set(["STRONG", "EM", "B", "I", "A", "BR", "SPAN", "MARK", "SMALL", "SUB", "SUP", "CODE", "U", "S"]);
|
|
30770
|
+
if (!directText && childElements.length === 1 && childElements[0].tagName === "P" && (childElements[0].children.length === 0 || Array.from(childElements[0].children).every((ce) => singlePInlineCheck.has(ce.tagName)))) {
|
|
30102
30771
|
directText = childElements[0].textContent?.trim() || "";
|
|
30103
30772
|
}
|
|
30104
|
-
|
|
30105
|
-
|
|
30773
|
+
if (directText) {
|
|
30774
|
+
const directTextComputed = win.getComputedStyle(el);
|
|
30775
|
+
if (directTextComputed.textTransform && directTextComputed.textTransform !== "none") {
|
|
30776
|
+
directText = applyTextTransform(directText, directTextComputed.textTransform);
|
|
30777
|
+
}
|
|
30778
|
+
}
|
|
30779
|
+
const plainDivComputed = win.getComputedStyle(el);
|
|
30780
|
+
const plainDivDisplay = plainDivComputed.display;
|
|
30781
|
+
const plainDivFlexDir = plainDivComputed.flexDirection || "row";
|
|
30782
|
+
const plainDivChildCount = el.children.length;
|
|
30783
|
+
const isPlainDivFlexRow = (plainDivDisplay === "flex" || plainDivDisplay === "inline-flex") && (plainDivFlexDir === "row" || plainDivFlexDir === "row-reverse") && plainDivChildCount > 1;
|
|
30784
|
+
const isPlainDivGrid = plainDivDisplay === "grid" || plainDivDisplay === "inline-grid";
|
|
30785
|
+
const allChildrenAreInlineText = !isPlainDivFlexRow && !isPlainDivGrid && (childElements.length === 0 || childElements.every((ce) => inlineTextTagsSet.has(ce.tagName.toUpperCase())));
|
|
30786
|
+
const structuralChildElements = childElements.filter((ce) => {
|
|
30787
|
+
const tagName = ce.tagName.toUpperCase();
|
|
30788
|
+
return tagName !== "BR" && tagName !== "SVG" && !inlineTextTagsSet.has(tagName);
|
|
30789
|
+
});
|
|
30790
|
+
const hasStructuralChildren = structuralChildElements.length > 0;
|
|
30791
|
+
let extractedText = "";
|
|
30792
|
+
if (allChildrenAreInlineText) {
|
|
30793
|
+
extractedText = el.textContent?.trim() || "";
|
|
30794
|
+
const inlineTextComputed = win.getComputedStyle(el);
|
|
30795
|
+
if (extractedText && inlineTextComputed.textTransform && inlineTextComputed.textTransform !== "none") {
|
|
30796
|
+
extractedText = applyTextTransform(extractedText, inlineTextComputed.textTransform);
|
|
30797
|
+
}
|
|
30798
|
+
} else if (directText) {
|
|
30799
|
+
extractedText = directText;
|
|
30800
|
+
}
|
|
30801
|
+
if (extractedText && !hasStructuralChildren) {
|
|
30106
30802
|
const computed22 = win.getComputedStyle(el);
|
|
30107
30803
|
const fontSizePx2 = parseFloat(computed22.fontSize);
|
|
30108
30804
|
const lineHeightPx2 = parseFloat(computed22.lineHeight);
|
|
30109
30805
|
const lineHeightMultiplier2 = fontSizePx2 > 0 && !isNaN(lineHeightPx2) ? lineHeightPx2 / fontSizePx2 : 1;
|
|
30806
|
+
let textLeft = rect2.left;
|
|
30807
|
+
let textWidth = rect2.width;
|
|
30808
|
+
if (directText && !allChildrenAreInlineText) {
|
|
30809
|
+
for (const child of Array.from(el.childNodes)) {
|
|
30810
|
+
if (child.nodeType === Node.TEXT_NODE && (child.textContent || "").trim()) {
|
|
30811
|
+
const range2 = document.createRange();
|
|
30812
|
+
range2.selectNodeContents(child);
|
|
30813
|
+
const textRect = range2.getBoundingClientRect();
|
|
30814
|
+
if (textRect.width > 0) {
|
|
30815
|
+
textLeft = textRect.left;
|
|
30816
|
+
textWidth = textRect.width;
|
|
30817
|
+
}
|
|
30818
|
+
break;
|
|
30819
|
+
}
|
|
30820
|
+
}
|
|
30821
|
+
}
|
|
30822
|
+
const textTop = rect2.top;
|
|
30823
|
+
const textHeight = rect2.height;
|
|
30824
|
+
let textRuns;
|
|
30825
|
+
if (allChildrenAreInlineText && childElements.length > 0) {
|
|
30826
|
+
const baseRunOptions = {
|
|
30827
|
+
fontSize: pxToPoints(computed22.fontSize),
|
|
30828
|
+
fontFace: extractFontFace(computed22.fontFamily),
|
|
30829
|
+
color: rgbToHex(computed22.color)
|
|
30830
|
+
};
|
|
30831
|
+
if (parseInt(computed22.fontWeight) >= 600)
|
|
30832
|
+
baseRunOptions.bold = true;
|
|
30833
|
+
if (computed22.fontStyle === "italic")
|
|
30834
|
+
baseRunOptions.italic = true;
|
|
30835
|
+
let textTransformFn = (s) => s;
|
|
30836
|
+
if (computed22.textTransform && computed22.textTransform !== "none") {
|
|
30837
|
+
textTransformFn = (text2) => applyTextTransform(text2, computed22.textTransform);
|
|
30838
|
+
}
|
|
30839
|
+
textRuns = parseInlineFormatting(el, baseRunOptions, [], textTransformFn, win);
|
|
30840
|
+
if (textRuns.length === 0) {
|
|
30841
|
+
textRuns = [{ text: extractedText, options: {} }];
|
|
30842
|
+
}
|
|
30843
|
+
} else {
|
|
30844
|
+
textRuns = [{ text: extractedText, options: {} }];
|
|
30845
|
+
}
|
|
30846
|
+
const paddingTop = parseFloat(computed22.paddingTop) || 0;
|
|
30847
|
+
const paddingRight = parseFloat(computed22.paddingRight) || 0;
|
|
30848
|
+
const paddingBottom = parseFloat(computed22.paddingBottom) || 0;
|
|
30849
|
+
const paddingLeft = parseFloat(computed22.paddingLeft) || 0;
|
|
30850
|
+
const hasPadding = paddingTop > 0 || paddingRight > 0 || paddingBottom > 0 || paddingLeft > 0;
|
|
30110
30851
|
const textElement = {
|
|
30111
30852
|
type: "p",
|
|
30112
|
-
text:
|
|
30853
|
+
text: textRuns,
|
|
30113
30854
|
position: {
|
|
30114
|
-
x: pxToInch(
|
|
30115
|
-
y: pxToInch(
|
|
30116
|
-
w: pxToInch(
|
|
30117
|
-
h: pxToInch(
|
|
30855
|
+
x: pxToInch(textLeft),
|
|
30856
|
+
y: pxToInch(textTop),
|
|
30857
|
+
w: pxToInch(textWidth),
|
|
30858
|
+
h: pxToInch(textHeight)
|
|
30118
30859
|
},
|
|
30119
30860
|
style: {
|
|
30120
30861
|
fontSize: pxToPoints(computed22.fontSize),
|
|
30121
|
-
fontFace: computed22.fontFamily
|
|
30862
|
+
fontFace: extractFontFace(computed22.fontFamily),
|
|
30122
30863
|
color: rgbToHex(computed22.color),
|
|
30123
30864
|
bold: parseInt(computed22.fontWeight) >= 600,
|
|
30124
30865
|
italic: computed22.fontStyle === "italic",
|
|
30125
30866
|
align: computed22.textAlign === "center" ? "center" : computed22.textAlign === "right" || computed22.textAlign === "end" ? "right" : "left",
|
|
30126
|
-
valign: "middle",
|
|
30127
|
-
lineSpacing: lineHeightMultiplier2 * pxToPoints(computed22.fontSize)
|
|
30867
|
+
valign: hasPadding ? "top" : "middle",
|
|
30868
|
+
lineSpacing: lineHeightMultiplier2 * pxToPoints(computed22.fontSize),
|
|
30869
|
+
margin: hasPadding ? [paddingLeft * PT_PER_PX, paddingRight * PT_PER_PX, paddingBottom * PT_PER_PX, paddingTop * PT_PER_PX] : void 0
|
|
30128
30870
|
}
|
|
30129
30871
|
};
|
|
30130
30872
|
const textTransparency = extractAlpha(computed22.color);
|
|
@@ -30136,7 +30878,11 @@ ${generateStylesCss(styleMap, themeFonts)}
|
|
|
30136
30878
|
textElement.style.charSpacing = ls;
|
|
30137
30879
|
elements.push(textElement);
|
|
30138
30880
|
processed.add(el);
|
|
30139
|
-
el.querySelectorAll("*").forEach((desc) =>
|
|
30881
|
+
el.querySelectorAll("*").forEach((desc) => {
|
|
30882
|
+
if (desc.tagName.toUpperCase() !== "SVG") {
|
|
30883
|
+
processed.add(desc);
|
|
30884
|
+
}
|
|
30885
|
+
});
|
|
30140
30886
|
return;
|
|
30141
30887
|
}
|
|
30142
30888
|
}
|
|
@@ -30190,7 +30936,7 @@ ${generateStylesCss(styleMap, themeFonts)}
|
|
|
30190
30936
|
},
|
|
30191
30937
|
style: {
|
|
30192
30938
|
fontSize: pxToPoints(liComputed.fontSize),
|
|
30193
|
-
fontFace: liComputed.fontFamily
|
|
30939
|
+
fontFace: extractFontFace(liComputed.fontFamily),
|
|
30194
30940
|
color: rgbToHex(liComputed.color),
|
|
30195
30941
|
transparency: extractAlpha(liComputed.color),
|
|
30196
30942
|
align: liComputed.textAlign === "start" ? "left" : liComputed.textAlign,
|
|
@@ -30208,10 +30954,10 @@ ${generateStylesCss(styleMap, themeFonts)}
|
|
|
30208
30954
|
if (!textTags.includes(el.tagName) || el.tagName === "SPAN")
|
|
30209
30955
|
return;
|
|
30210
30956
|
let rect = htmlEl.getBoundingClientRect();
|
|
30211
|
-
|
|
30957
|
+
const computed = win.getComputedStyle(el);
|
|
30958
|
+
let text = getTransformedText(htmlEl, computed);
|
|
30212
30959
|
if (rect.width === 0 || rect.height === 0 || !text)
|
|
30213
30960
|
return;
|
|
30214
|
-
const computed = win.getComputedStyle(el);
|
|
30215
30961
|
const isFlexContainer = computed.display === "flex" || computed.display === "inline-flex";
|
|
30216
30962
|
if (isFlexContainer && el.children.length > 0) {
|
|
30217
30963
|
const textNodes = [];
|
|
@@ -30227,7 +30973,20 @@ ${generateStylesCss(styleMap, themeFonts)}
|
|
|
30227
30973
|
const textRect = range2.getBoundingClientRect();
|
|
30228
30974
|
if (textRect.width > 0 && textRect.height > 0) {
|
|
30229
30975
|
rect = textRect;
|
|
30230
|
-
|
|
30976
|
+
const rawText = textNodes.map((n) => n.textContent.trim()).join(" ").trim();
|
|
30977
|
+
text = applyTextTransform(rawText, computed.textTransform || "none");
|
|
30978
|
+
}
|
|
30979
|
+
} else {
|
|
30980
|
+
for (const child of Array.from(el.children)) {
|
|
30981
|
+
if (child.tagName === "SPAN" && child.textContent?.trim()) {
|
|
30982
|
+
const childRect = child.getBoundingClientRect();
|
|
30983
|
+
if (childRect.width > 0 && childRect.height > 0) {
|
|
30984
|
+
rect = childRect;
|
|
30985
|
+
const childComputed = win.getComputedStyle(child);
|
|
30986
|
+
text = getTransformedText(child, childComputed);
|
|
30987
|
+
break;
|
|
30988
|
+
}
|
|
30989
|
+
}
|
|
30231
30990
|
}
|
|
30232
30991
|
}
|
|
30233
30992
|
}
|
|
@@ -30268,7 +31027,7 @@ ${generateStylesCss(styleMap, themeFonts)}
|
|
|
30268
31027
|
}
|
|
30269
31028
|
const baseStyle = {
|
|
30270
31029
|
fontSize: pxToPoints(computed.fontSize),
|
|
30271
|
-
fontFace: computed.fontFamily
|
|
31030
|
+
fontFace: extractFontFace(computed.fontFamily),
|
|
30272
31031
|
color: rgbToHex(computed.color),
|
|
30273
31032
|
align: textAlign,
|
|
30274
31033
|
valign,
|
|
@@ -30396,23 +31155,44 @@ ${generateStylesCss(styleMap, themeFonts)}
|
|
|
30396
31155
|
})
|
|
30397
31156
|
};
|
|
30398
31157
|
}
|
|
30399
|
-
|
|
30400
|
-
|
|
30401
|
-
|
|
30402
|
-
|
|
30403
|
-
|
|
30404
|
-
|
|
30405
|
-
|
|
30406
|
-
|
|
30407
|
-
|
|
30408
|
-
|
|
30409
|
-
|
|
30410
|
-
|
|
30411
|
-
|
|
30412
|
-
|
|
30413
|
-
|
|
30414
|
-
|
|
31158
|
+
function sleep(ms) {
|
|
31159
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
31160
|
+
}
|
|
31161
|
+
async function fetchImageAsDataUrl(url, maxRetries = 3, initialDelayMs = 500) {
|
|
31162
|
+
let lastError = null;
|
|
31163
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
31164
|
+
try {
|
|
31165
|
+
const response = await fetch(url, { mode: "cors" });
|
|
31166
|
+
if (response.status === 429 || response.status >= 500 && response.status < 600) {
|
|
31167
|
+
if (attempt < maxRetries) {
|
|
31168
|
+
const delay = initialDelayMs * Math.pow(2, attempt);
|
|
31169
|
+
console.warn(`Image fetch returned ${response.status}, retrying in ${delay}ms... (${url})`);
|
|
31170
|
+
await sleep(delay);
|
|
31171
|
+
continue;
|
|
31172
|
+
}
|
|
31173
|
+
}
|
|
31174
|
+
if (!response.ok) {
|
|
31175
|
+
throw new Error(`Failed to fetch image: ${response.status}`);
|
|
31176
|
+
}
|
|
31177
|
+
const blob = await response.blob();
|
|
31178
|
+
return new Promise((resolve, reject) => {
|
|
31179
|
+
const reader = new FileReader();
|
|
31180
|
+
reader.onloadend = () => resolve(reader.result);
|
|
31181
|
+
reader.onerror = reject;
|
|
31182
|
+
reader.readAsDataURL(blob);
|
|
31183
|
+
});
|
|
31184
|
+
} catch (error) {
|
|
31185
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
31186
|
+
if (attempt < maxRetries) {
|
|
31187
|
+
const delay = initialDelayMs * Math.pow(2, attempt);
|
|
31188
|
+
console.warn(`Image fetch failed, retrying in ${delay}ms... (${url}): ${lastError.message}`);
|
|
31189
|
+
await sleep(delay);
|
|
31190
|
+
continue;
|
|
31191
|
+
}
|
|
31192
|
+
}
|
|
30415
31193
|
}
|
|
31194
|
+
const message = lastError?.message ?? "Unknown error";
|
|
31195
|
+
throw new Error(`Failed to fetch image ${url}: ${message}`);
|
|
30416
31196
|
}
|
|
30417
31197
|
async function applyBackground(background, slide) {
|
|
30418
31198
|
if (background.type === "image" && background.path) {
|
|
@@ -30556,7 +31336,11 @@ ${generateStylesCss(styleMap, themeFonts)}
|
|
|
30556
31336
|
});
|
|
30557
31337
|
} else if (el.type === "shape") {
|
|
30558
31338
|
let shapeType = pres.ShapeType.rect;
|
|
30559
|
-
|
|
31339
|
+
let customGeometryPoints;
|
|
31340
|
+
if (el.shape.customGeometry && el.shape.customGeometry.length > 0) {
|
|
31341
|
+
shapeType = pres.ShapeType.custGeom;
|
|
31342
|
+
customGeometryPoints = el.shape.customGeometry;
|
|
31343
|
+
} else if (el.shape.isEllipse) {
|
|
30560
31344
|
shapeType = pres.ShapeType.ellipse;
|
|
30561
31345
|
} else if (el.shape.rectRadius > 0) {
|
|
30562
31346
|
shapeType = pres.ShapeType.roundRect;
|
|
@@ -30568,8 +31352,11 @@ ${generateStylesCss(styleMap, themeFonts)}
|
|
|
30568
31352
|
const hasText = el.text || el.textRuns && el.textRuns.length > 0;
|
|
30569
31353
|
let adjustedX = el.position.x;
|
|
30570
31354
|
let adjustedW = el.position.w;
|
|
31355
|
+
let adjustedH = el.position.h;
|
|
30571
31356
|
if (isSingleLine && hasText) {
|
|
30572
|
-
const
|
|
31357
|
+
const fontSize = el.style?.fontSize ?? 12;
|
|
31358
|
+
const bufferPercent = fontSize > 36 ? 0.05 : fontSize > 24 ? 0.04 : fontSize > 16 ? 0.03 : 0.02;
|
|
31359
|
+
const widthIncrease = el.position.w * bufferPercent;
|
|
30573
31360
|
const align = el.style?.align;
|
|
30574
31361
|
if (align === "center") {
|
|
30575
31362
|
adjustedX = el.position.x - widthIncrease / 2;
|
|
@@ -30580,16 +31367,25 @@ ${generateStylesCss(styleMap, themeFonts)}
|
|
|
30580
31367
|
} else {
|
|
30581
31368
|
adjustedW = el.position.w + widthIncrease;
|
|
30582
31369
|
}
|
|
31370
|
+
} else if (hasText && !isSingleLine) {
|
|
31371
|
+
const hasInternalPadding = el.style?.margin && el.style.margin.some((m) => m > 3);
|
|
31372
|
+
const heightBufferPercent = hasInternalPadding ? 0.03 : 0.1;
|
|
31373
|
+
const heightIncrease = el.position.h * heightBufferPercent;
|
|
31374
|
+
adjustedH = el.position.h + heightIncrease;
|
|
30583
31375
|
}
|
|
30584
31376
|
const shapeOptions = {
|
|
30585
31377
|
x: adjustedX,
|
|
30586
31378
|
y: el.position.y,
|
|
30587
31379
|
w: adjustedW,
|
|
30588
|
-
h:
|
|
31380
|
+
h: adjustedH,
|
|
30589
31381
|
shape: shapeType,
|
|
30590
31382
|
// Disable text wrapping for single-line shapes to prevent unwanted line breaks
|
|
30591
|
-
wrap:
|
|
31383
|
+
// Also respect explicit wrap: false from parse.ts (for small badges/labels)
|
|
31384
|
+
wrap: el.style?.wrap === false ? false : !isSingleLine
|
|
30592
31385
|
};
|
|
31386
|
+
if (customGeometryPoints) {
|
|
31387
|
+
shapeOptions.points = customGeometryPoints;
|
|
31388
|
+
}
|
|
30593
31389
|
let fillTransparency = el.shape.transparency;
|
|
30594
31390
|
const elementOpacity = el.shape.opacity !== null && el.shape.opacity < 1 ? el.shape.opacity : 1;
|
|
30595
31391
|
if (elementOpacity < 1) {
|
|
@@ -30620,6 +31416,8 @@ ${generateStylesCss(styleMap, themeFonts)}
|
|
|
30620
31416
|
};
|
|
30621
31417
|
if (el.shape.line.transparency != null)
|
|
30622
31418
|
lineOpts.transparency = el.shape.line.transparency;
|
|
31419
|
+
if (el.shape.line.dashType)
|
|
31420
|
+
lineOpts.dashType = el.shape.line.dashType;
|
|
30623
31421
|
shapeOptions.line = lineOpts;
|
|
30624
31422
|
}
|
|
30625
31423
|
if (el.shape.rectRadius > 0)
|
|
@@ -30643,6 +31441,7 @@ ${generateStylesCss(styleMap, themeFonts)}
|
|
|
30643
31441
|
shapeOptions.valign = el.style.valign;
|
|
30644
31442
|
if (el.style.fontFill)
|
|
30645
31443
|
shapeOptions.fontFill = el.style.fontFill;
|
|
31444
|
+
shapeOptions.inset = 0;
|
|
30646
31445
|
if (el.style.margin)
|
|
30647
31446
|
shapeOptions.margin = el.style.margin;
|
|
30648
31447
|
if (el.style.inset !== void 0)
|
|
@@ -30666,11 +31465,13 @@ ${generateStylesCss(styleMap, themeFonts)}
|
|
|
30666
31465
|
slide.addText(el.text || "", shapeOptions);
|
|
30667
31466
|
}
|
|
30668
31467
|
} else if (el.type === "list") {
|
|
31468
|
+
const heightIncrease = el.position.h * 0.15;
|
|
31469
|
+
const adjustedH = el.position.h + heightIncrease;
|
|
30669
31470
|
const listOptions = {
|
|
30670
31471
|
x: el.position.x,
|
|
30671
31472
|
y: el.position.y,
|
|
30672
31473
|
w: el.position.w,
|
|
30673
|
-
h:
|
|
31474
|
+
h: adjustedH,
|
|
30674
31475
|
fontSize: el.style.fontSize,
|
|
30675
31476
|
fontFace: el.style.fontFace,
|
|
30676
31477
|
color: el.style.color ?? void 0,
|
|
@@ -30679,7 +31480,8 @@ ${generateStylesCss(styleMap, themeFonts)}
|
|
|
30679
31480
|
lineSpacing: el.style.lineSpacing,
|
|
30680
31481
|
paraSpaceBefore: el.style.paraSpaceBefore,
|
|
30681
31482
|
paraSpaceAfter: el.style.paraSpaceAfter,
|
|
30682
|
-
margin: el.style.margin
|
|
31483
|
+
margin: el.style.margin,
|
|
31484
|
+
inset: 0
|
|
30683
31485
|
};
|
|
30684
31486
|
if (el.style.margin)
|
|
30685
31487
|
listOptions.margin = el.style.margin;
|
|
@@ -30690,7 +31492,22 @@ ${generateStylesCss(styleMap, themeFonts)}
|
|
|
30690
31492
|
const isSingleLine = heightPt <= lineHeightPt * 1.5;
|
|
30691
31493
|
let adjustedX = el.position.x;
|
|
30692
31494
|
let adjustedW = el.position.w;
|
|
31495
|
+
let adjustedH = el.position.h;
|
|
30693
31496
|
if (isSingleLine) {
|
|
31497
|
+
const fontSize = el.style.fontSize ?? 12;
|
|
31498
|
+
const bufferPercent = fontSize > 36 ? 0.02 : fontSize > 24 ? 0.015 : 0.01;
|
|
31499
|
+
const widthIncrease = el.position.w * bufferPercent;
|
|
31500
|
+
const align = el.style.align;
|
|
31501
|
+
if (align === "center") {
|
|
31502
|
+
adjustedX = el.position.x - widthIncrease / 2;
|
|
31503
|
+
adjustedW = el.position.w + widthIncrease;
|
|
31504
|
+
} else if (align === "right") {
|
|
31505
|
+
adjustedX = el.position.x - widthIncrease;
|
|
31506
|
+
adjustedW = el.position.w + widthIncrease;
|
|
31507
|
+
} else {
|
|
31508
|
+
adjustedW = el.position.w + widthIncrease;
|
|
31509
|
+
}
|
|
31510
|
+
} else {
|
|
30694
31511
|
const widthIncrease = el.position.w * 0.02;
|
|
30695
31512
|
const align = el.style.align;
|
|
30696
31513
|
if (align === "center") {
|
|
@@ -30702,12 +31519,14 @@ ${generateStylesCss(styleMap, themeFonts)}
|
|
|
30702
31519
|
} else {
|
|
30703
31520
|
adjustedW = el.position.w + widthIncrease;
|
|
30704
31521
|
}
|
|
31522
|
+
const heightIncrease = el.position.h * 0.05;
|
|
31523
|
+
adjustedH = el.position.h + heightIncrease;
|
|
30705
31524
|
}
|
|
30706
31525
|
const textOptions = {
|
|
30707
31526
|
x: adjustedX,
|
|
30708
31527
|
y: el.position.y,
|
|
30709
31528
|
w: adjustedW,
|
|
30710
|
-
h:
|
|
31529
|
+
h: adjustedH,
|
|
30711
31530
|
fontSize: el.style.fontSize,
|
|
30712
31531
|
fontFace: el.style.fontFace,
|
|
30713
31532
|
color: el.style.color ?? void 0,
|
|
@@ -30850,9 +31669,17 @@ ${generateStylesCss(styleMap, themeFonts)}
|
|
|
30850
31669
|
resolve();
|
|
30851
31670
|
};
|
|
30852
31671
|
iframe.onload = resolveOnce;
|
|
30853
|
-
setTimeout(resolveOnce,
|
|
31672
|
+
setTimeout(resolveOnce, 2e3);
|
|
30854
31673
|
});
|
|
30855
31674
|
const doc = iframe.contentDocument || iframe.contentWindow.document;
|
|
31675
|
+
const iframeWin = iframe.contentWindow;
|
|
31676
|
+
if (iframeWin && iframeWin.document.fonts && iframeWin.document.fonts.ready) {
|
|
31677
|
+
await Promise.race([
|
|
31678
|
+
iframeWin.document.fonts.ready,
|
|
31679
|
+
new Promise((r) => setTimeout(r, 3e3))
|
|
31680
|
+
// 3s timeout for slow CDN
|
|
31681
|
+
]);
|
|
31682
|
+
}
|
|
30856
31683
|
return { iframe, doc };
|
|
30857
31684
|
}
|
|
30858
31685
|
async function addSlideFromHtml(source, pres, options = {}) {
|
|
@@ -30871,6 +31698,10 @@ ${generateStylesCss(styleMap, themeFonts)}
|
|
|
30871
31698
|
} else {
|
|
30872
31699
|
throw new Error("Source must be a Document, HTMLIFrameElement, or HTML string");
|
|
30873
31700
|
}
|
|
31701
|
+
const win = doc.defaultView;
|
|
31702
|
+
if (win && win.document.fonts && win.document.fonts.ready) {
|
|
31703
|
+
await win.document.fonts.ready;
|
|
31704
|
+
}
|
|
30874
31705
|
const validationErrors = [];
|
|
30875
31706
|
const bodyDimensions = getBodyDimensions(doc);
|
|
30876
31707
|
const slideData = parseSlideHtml(doc);
|
|
@@ -30928,7 +31759,7 @@ ${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join("\n")}`;
|
|
|
30928
31759
|
}
|
|
30929
31760
|
|
|
30930
31761
|
// packages/slides/transform.js
|
|
30931
|
-
var
|
|
31762
|
+
var FONT_FAMILY_MAP2 = {
|
|
30932
31763
|
// Serif fonts → Georgia (closest web-safe serif)
|
|
30933
31764
|
"Playfair Display": "Georgia, serif",
|
|
30934
31765
|
"Merriweather": "Georgia, serif",
|
|
@@ -30937,7 +31768,8 @@ ${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join("\n")}`;
|
|
|
30937
31768
|
"Noto Serif": "Georgia, serif",
|
|
30938
31769
|
"Lora": "Georgia, serif",
|
|
30939
31770
|
// Sans-serif fonts → Calibri (modern sans-serif, widely available in PowerPoint)
|
|
30940
|
-
|
|
31771
|
+
// Note: fonts loaded via Google Fonts CDN are NOT mapped here, as they will
|
|
31772
|
+
// be available at render time and should keep their original names in the PPTX.
|
|
30941
31773
|
"Roboto": "Calibri, sans-serif",
|
|
30942
31774
|
"Open Sans": "Calibri, sans-serif",
|
|
30943
31775
|
"Lato": "Calibri, sans-serif",
|
|
@@ -30974,7 +31806,7 @@ ${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join("\n")}`;
|
|
|
30974
31806
|
const scaleFactor = targetWidth / sourceWidth;
|
|
30975
31807
|
html = html.replace(/(body\s*\{[^}]*?)width:\s*\d+px/s, `$1width: ${targetWidth}pt`);
|
|
30976
31808
|
html = html.replace(/(body\s*\{[^}]*?)height:\s*\d+px/s, `$1height: ${targetHeight}pt`);
|
|
30977
|
-
for (const [font, replacement] of Object.entries(
|
|
31809
|
+
for (const [font, replacement] of Object.entries(FONT_FAMILY_MAP2)) {
|
|
30978
31810
|
const fontRegex = new RegExp(`font-family:\\s*["']?${font}["']?,?\\s*(sans-serif|serif|monospace)?`, "gi");
|
|
30979
31811
|
html = html.replace(fontRegex, `font-family: ${replacement}`);
|
|
30980
31812
|
}
|
|
@@ -31012,7 +31844,43 @@ ${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join("\n")}`;
|
|
|
31012
31844
|
});
|
|
31013
31845
|
html = html.replace(/-webkit-backdrop-filter:\s*[^;]+;/g, "");
|
|
31014
31846
|
html = html.replace(/backdrop-filter:\s*[^;]+;/g, "");
|
|
31015
|
-
|
|
31847
|
+
const keyframeFinalTransforms = {};
|
|
31848
|
+
{
|
|
31849
|
+
const kfPattern = /@keyframes\s+([\w-]+)\s*\{/g;
|
|
31850
|
+
let kfScan;
|
|
31851
|
+
while ((kfScan = kfPattern.exec(html)) !== null) {
|
|
31852
|
+
const name = kfScan[1];
|
|
31853
|
+
const bodyStart = kfScan.index + kfScan[0].length;
|
|
31854
|
+
let depth = 1;
|
|
31855
|
+
let idx = bodyStart;
|
|
31856
|
+
while (idx < html.length && depth > 0) {
|
|
31857
|
+
if (html[idx] === "{")
|
|
31858
|
+
depth++;
|
|
31859
|
+
else if (html[idx] === "}")
|
|
31860
|
+
depth--;
|
|
31861
|
+
idx++;
|
|
31862
|
+
}
|
|
31863
|
+
const kfBody = html.substring(bodyStart, idx - 1);
|
|
31864
|
+
const finalBlock = kfBody.match(/(?:to|100%)\s*\{\s*([^}]*)\}/);
|
|
31865
|
+
if (finalBlock) {
|
|
31866
|
+
const transformInFinal = finalBlock[1].match(/transform:\s*([^;]+)/);
|
|
31867
|
+
if (transformInFinal) {
|
|
31868
|
+
keyframeFinalTransforms[name] = transformInFinal[1].trim();
|
|
31869
|
+
}
|
|
31870
|
+
}
|
|
31871
|
+
}
|
|
31872
|
+
}
|
|
31873
|
+
html = html.replace(/(?<![a-zA-Z-])animation:\s*([^;]+);/g, (_match, value) => {
|
|
31874
|
+
if (/forwards/.test(value)) {
|
|
31875
|
+
for (const [name, finalTransform] of Object.entries(keyframeFinalTransforms)) {
|
|
31876
|
+
if (value.includes(name)) {
|
|
31877
|
+
return `transform: ${finalTransform} !important;`;
|
|
31878
|
+
}
|
|
31879
|
+
}
|
|
31880
|
+
}
|
|
31881
|
+
return "";
|
|
31882
|
+
});
|
|
31883
|
+
html = html.replace(/animation-[\w-]+:\s*[^;]+;/g, "");
|
|
31016
31884
|
let keyframeMatch;
|
|
31017
31885
|
while (keyframeMatch = html.match(/@keyframes\s+[\w-]+\s*\{/)) {
|
|
31018
31886
|
const start = keyframeMatch.index;
|
|
@@ -31082,6 +31950,109 @@ ${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join("\n")}`;
|
|
|
31082
31950
|
var TARGET_WIDTH = 1280;
|
|
31083
31951
|
var TARGET_HEIGHT = 720;
|
|
31084
31952
|
var EMU_PER_PX2 = 914400 / 96;
|
|
31953
|
+
var FONT_FALLBACK_MAP = {
|
|
31954
|
+
// Microsoft Office fonts → metrically compatible open-source alternatives
|
|
31955
|
+
"Calibri": "'Calibri','Carlito','Helvetica Neue',Helvetica,Arial,sans-serif",
|
|
31956
|
+
"Calibri Light": "'Calibri Light','Carlito','Helvetica Neue Light','Helvetica Neue',Arial,sans-serif",
|
|
31957
|
+
"Cambria": "'Cambria','Caladea','Times New Roman',Georgia,serif",
|
|
31958
|
+
"Cambria Math": "'Cambria Math','Caladea','Times New Roman',serif",
|
|
31959
|
+
"Consolas": "'Consolas','Courier New',monospace",
|
|
31960
|
+
"Aptos": "'Aptos','Carlito','Helvetica Neue',Arial,sans-serif",
|
|
31961
|
+
"Times New Roman": "'Times New Roman','Liberation Serif',Georgia,serif",
|
|
31962
|
+
// Handwriting / decorative fonts
|
|
31963
|
+
"MV Boli": "'MV Boli','Comic Sans MS','Marker Felt',cursive",
|
|
31964
|
+
"Kristen ITC": "'Kristen ITC','Comic Sans MS','Marker Felt',cursive",
|
|
31965
|
+
"Stylus BT": "'Stylus BT','Brush Script MT','Snell Roundhand',cursive",
|
|
31966
|
+
// Japanese sans-serif fonts → Noto Sans CJK JP (commonly installed)
|
|
31967
|
+
"MS Gothic": "'MS Gothic','Noto Sans CJK JP','Hiragino Kaku Gothic ProN','Yu Gothic',sans-serif",
|
|
31968
|
+
"MS PGothic": "'MS PGothic','Noto Sans CJK JP','Hiragino Kaku Gothic ProN','Yu Gothic',sans-serif",
|
|
31969
|
+
"\uFF2D\uFF33 \uFF30\u30B4\u30B7\u30C3\u30AF": "'\uFF2D\uFF33 \uFF30\u30B4\u30B7\u30C3\u30AF','Noto Sans CJK JP','Hiragino Kaku Gothic ProN','Yu Gothic',sans-serif",
|
|
31970
|
+
"\uFF2D\uFF33 \u30B4\u30B7\u30C3\u30AF": "'\uFF2D\uFF33 \u30B4\u30B7\u30C3\u30AF','Noto Sans CJK JP','Hiragino Kaku Gothic ProN','Yu Gothic',sans-serif",
|
|
31971
|
+
"Kozuka Gothic Pro R": "'Kozuka Gothic Pro R','Noto Sans CJK JP','Hiragino Kaku Gothic ProN',sans-serif",
|
|
31972
|
+
"Kozuka Gothic Pro B": "'Kozuka Gothic Pro B','Noto Sans CJK JP Bold','Hiragino Kaku Gothic ProN',sans-serif",
|
|
31973
|
+
"Kozuka Gothic Pro M": "'Kozuka Gothic Pro M','Noto Sans CJK JP Medium','Hiragino Kaku Gothic ProN',sans-serif",
|
|
31974
|
+
"Kozuka Gothic Pro EL": "'Kozuka Gothic Pro EL','Noto Sans CJK JP Light','Hiragino Kaku Gothic ProN',sans-serif",
|
|
31975
|
+
"HGSKyokashotai": "'HGSKyokashotai','Noto Sans CJK JP','Hiragino Kaku Gothic ProN',sans-serif",
|
|
31976
|
+
// Japanese serif fonts → Noto Serif CJK JP
|
|
31977
|
+
"MS Mincho": "'MS Mincho','Noto Serif CJK JP','Hiragino Mincho ProN','Yu Mincho',serif",
|
|
31978
|
+
"MS PMincho": "'MS PMincho','Noto Serif CJK JP','Hiragino Mincho ProN','Yu Mincho',serif",
|
|
31979
|
+
// CJK fonts
|
|
31980
|
+
"\u5B8B\u4F53": "'\u5B8B\u4F53','Noto Serif CJK SC','Songti SC','STSong',serif",
|
|
31981
|
+
"\u65B0\u7D30\u660E\u9AD4": "'\u65B0\u7D30\u660E\u9AD4','Noto Serif CJK TC','Songti TC',serif",
|
|
31982
|
+
"\u9ED1\u4F53": "'\u9ED1\u4F53','Noto Sans CJK SC','Heiti SC','STHeiti',sans-serif",
|
|
31983
|
+
"\u5FAE\u8EDF\u6B63\u9ED1\u9AD4": "'\u5FAE\u8EDF\u6B63\u9ED1\u9AD4','Noto Sans CJK TC','Heiti TC',sans-serif",
|
|
31984
|
+
"\uB9D1\uC740 \uACE0\uB515": "'\uB9D1\uC740 \uACE0\uB515','Apple SD Gothic Neo',sans-serif",
|
|
31985
|
+
// UI / system fonts
|
|
31986
|
+
"Lucida Sans Unicode": "'Lucida Sans Unicode','Lucida Grande','Lucida Sans',sans-serif",
|
|
31987
|
+
"Segoe UI": "'Segoe UI','-apple-system','Helvetica Neue',sans-serif",
|
|
31988
|
+
"Segoe Sans Display": "'Segoe Sans Display','-apple-system','Helvetica Neue',Arial,sans-serif",
|
|
31989
|
+
"Segoe Sans Display Semibold": "'Segoe Sans Display Semibold','-apple-system','Helvetica Neue',Arial,sans-serif",
|
|
31990
|
+
// Google Fonts / web fonts commonly used in presentations
|
|
31991
|
+
"Inter": "'Inter','Helvetica Neue',Helvetica,Arial,sans-serif",
|
|
31992
|
+
"Inter Light": "'Inter Light','Inter','Helvetica Neue',Arial,sans-serif",
|
|
31993
|
+
"Inter ExtraBold": "'Inter ExtraBold','Inter','Helvetica Neue',Arial,sans-serif",
|
|
31994
|
+
"Space Grotesk": "'Space Grotesk','Helvetica Neue',Helvetica,Arial,sans-serif",
|
|
31995
|
+
"Montserrat": "'Montserrat','Helvetica Neue',Helvetica,Arial,sans-serif",
|
|
31996
|
+
"Open Sans": "'Open Sans','Helvetica Neue',Helvetica,Arial,sans-serif",
|
|
31997
|
+
"Lato": "'Lato','Helvetica Neue',Helvetica,Arial,sans-serif",
|
|
31998
|
+
"Oswald": "'Oswald','Helvetica Neue',Helvetica,Arial,sans-serif",
|
|
31999
|
+
"Archivo": "'Archivo','Helvetica Neue',Helvetica,Arial,sans-serif",
|
|
32000
|
+
"Economica": "'Economica','Helvetica Neue',Arial,sans-serif",
|
|
32001
|
+
"Libre Baskerville": "'Libre Baskerville','Georgia','Times New Roman',serif",
|
|
32002
|
+
// GitHub Copilot fonts
|
|
32003
|
+
"Ginto Copilot": "'Ginto Copilot','Helvetica Neue',Helvetica,Arial,sans-serif",
|
|
32004
|
+
"Ginto Copilot Light": "'Ginto Copilot Light','Helvetica Neue Light','Helvetica Neue',Arial,sans-serif",
|
|
32005
|
+
"Ginto Copilot 400": "'Ginto Copilot 400','Helvetica Neue',Helvetica,Arial,sans-serif",
|
|
32006
|
+
// Google Fonts / decorative (serif & display)
|
|
32007
|
+
"Playfair Display": "'Playfair Display','Georgia','Times New Roman',serif",
|
|
32008
|
+
"Playfair Display SemiBold": "'Playfair Display SemiBold','Playfair Display','Georgia',serif",
|
|
32009
|
+
"Caveat": "'Caveat','Comic Sans MS','Marker Felt',cursive",
|
|
32010
|
+
"Syncopate": "'Syncopate','Helvetica Neue',Helvetica,Arial,sans-serif",
|
|
32011
|
+
// Montserrat weight variants
|
|
32012
|
+
"Montserrat SemiBold": "'Montserrat SemiBold','Montserrat','Helvetica Neue',Arial,sans-serif",
|
|
32013
|
+
"Montserrat ExtraBold": "'Montserrat ExtraBold','Montserrat','Helvetica Neue',Arial,sans-serif",
|
|
32014
|
+
// GitHub Copilot font variants
|
|
32015
|
+
"Ginto Copilot Medium": "'Ginto Copilot Medium','Ginto Copilot','Helvetica Neue',Arial,sans-serif",
|
|
32016
|
+
"Ginto Copilot Black": "'Ginto Copilot Black','Ginto Copilot','Helvetica Neue',Arial,sans-serif",
|
|
32017
|
+
"Ginto Copilot Thin": "'Ginto Copilot Thin','Ginto Copilot Light','Helvetica Neue',Arial,sans-serif",
|
|
32018
|
+
// Microsoft UI fonts
|
|
32019
|
+
"Segoe Sans Small Regular": "'Segoe Sans Small Regular','Segoe UI','-apple-system','Helvetica Neue',sans-serif",
|
|
32020
|
+
"Segoe Sans Text Regular": "'Segoe Sans Text Regular','Segoe UI','-apple-system','Helvetica Neue',sans-serif",
|
|
32021
|
+
"Grandview": "'Grandview','Helvetica Neue',Arial,sans-serif",
|
|
32022
|
+
"Nirmala UI": "'Nirmala UI','Helvetica Neue',Arial,sans-serif",
|
|
32023
|
+
"Ebrima": "'Ebrima','Helvetica Neue',Arial,sans-serif",
|
|
32024
|
+
// Common system fonts with fallbacks
|
|
32025
|
+
"Arial": "Arial,'Helvetica Neue',Helvetica,sans-serif",
|
|
32026
|
+
"Arial Black": "'Arial Black','Helvetica Neue',Helvetica,Arial,sans-serif",
|
|
32027
|
+
"Georgia": "Georgia,'Times New Roman',serif",
|
|
32028
|
+
"Georgia Regular": "'Georgia Regular',Georgia,'Times New Roman',serif",
|
|
32029
|
+
"Courier New": "'Courier New',Courier,monospace",
|
|
32030
|
+
"Times": "Times,'Times New Roman',serif",
|
|
32031
|
+
// Symbol fonts (preserved as-is with system fallback)
|
|
32032
|
+
"Wingdings": "'Wingdings','Zapf Dingbats',sans-serif",
|
|
32033
|
+
"Wingdings 2": "'Wingdings 2','Zapf Dingbats',sans-serif",
|
|
32034
|
+
"Wingdings 3": "'Wingdings 3','Zapf Dingbats',sans-serif",
|
|
32035
|
+
// Common fallbacks
|
|
32036
|
+
"Tahoma": "'Tahoma','Verdana','Geneva',sans-serif",
|
|
32037
|
+
"Verdana": "'Verdana','Geneva',sans-serif",
|
|
32038
|
+
"Helvetica Neue Light": "'Helvetica Neue Light','Helvetica Neue',Helvetica,Arial,sans-serif"
|
|
32039
|
+
};
|
|
32040
|
+
function cssFontFamily(fontName) {
|
|
32041
|
+
const mapped = FONT_FALLBACK_MAP[fontName];
|
|
32042
|
+
if (mapped)
|
|
32043
|
+
return mapped;
|
|
32044
|
+
if (fontName.includes(",")) {
|
|
32045
|
+
return fontName.split(",").map((f) => {
|
|
32046
|
+
const trimmed = f.trim();
|
|
32047
|
+
const lower = trimmed.toLowerCase();
|
|
32048
|
+
if (lower === "sans-serif" || lower === "serif" || lower === "monospace" || lower === "cursive" || lower === "fantasy") {
|
|
32049
|
+
return lower;
|
|
32050
|
+
}
|
|
32051
|
+
return `'${trimmed}'`;
|
|
32052
|
+
}).join(",");
|
|
32053
|
+
}
|
|
32054
|
+
return `'${fontName}',sans-serif`;
|
|
32055
|
+
}
|
|
31085
32056
|
function emuToPx2(emu) {
|
|
31086
32057
|
return emu / EMU_PER_PX2;
|
|
31087
32058
|
}
|
|
@@ -31160,6 +32131,20 @@ ${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join("\n")}`;
|
|
|
31160
32131
|
}
|
|
31161
32132
|
if (stops.length === 0)
|
|
31162
32133
|
return void 0;
|
|
32134
|
+
const pathEl = findChild2(gradFill, "path");
|
|
32135
|
+
if (pathEl && pathEl.getAttribute("path") === "circle") {
|
|
32136
|
+
const fillToRect = findChild2(pathEl, "fillToRect");
|
|
32137
|
+
let centerX = 50;
|
|
32138
|
+
let centerY = 50;
|
|
32139
|
+
if (fillToRect) {
|
|
32140
|
+
const l = parseInt(fillToRect.getAttribute("l") ?? "50000", 10) / 1e3;
|
|
32141
|
+
const t = parseInt(fillToRect.getAttribute("t") ?? "50000", 10) / 1e3;
|
|
32142
|
+
centerX = l;
|
|
32143
|
+
centerY = t;
|
|
32144
|
+
}
|
|
32145
|
+
const stopStr2 = stops.map((s) => `${s.color} ${s.pos}%`).join(",");
|
|
32146
|
+
return `radial-gradient(ellipse at ${centerX}% ${centerY}%,${stopStr2})`;
|
|
32147
|
+
}
|
|
31163
32148
|
const lin = findChild2(gradFill, "lin");
|
|
31164
32149
|
const angAttr = lin?.getAttribute("ang");
|
|
31165
32150
|
const cssDeg = angAttr ? ooxmlAngleToCss(parseInt(angAttr, 10)) : 180;
|
|
@@ -31191,12 +32176,71 @@ ${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join("\n")}`;
|
|
|
31191
32176
|
if (color)
|
|
31192
32177
|
result.color = color;
|
|
31193
32178
|
}
|
|
32179
|
+
if (!result.color) {
|
|
32180
|
+
const gradFill = findChild2(rPr, "gradFill");
|
|
32181
|
+
if (gradFill) {
|
|
32182
|
+
const gsLst = findChild2(gradFill, "gsLst");
|
|
32183
|
+
if (gsLst) {
|
|
32184
|
+
const gsEls = findChildren2(gsLst, "gs");
|
|
32185
|
+
if (gsEls.length > 0) {
|
|
32186
|
+
const stops = [];
|
|
32187
|
+
for (const gs of gsEls) {
|
|
32188
|
+
const pos = parseInt(gs.getAttribute("pos") ?? "0", 10) / 1e3;
|
|
32189
|
+
const color = resolveColor2(gs, themeColors);
|
|
32190
|
+
if (color)
|
|
32191
|
+
stops.push({ pos, color });
|
|
32192
|
+
}
|
|
32193
|
+
if (stops.length >= 2) {
|
|
32194
|
+
const lin = findChild2(gradFill, "lin");
|
|
32195
|
+
const angAttr = lin?.getAttribute("ang");
|
|
32196
|
+
const cssDeg = angAttr ? ooxmlAngleToCss(parseInt(angAttr, 10)) : 135;
|
|
32197
|
+
const stopStr = stops.map((s) => `${s.color} ${s.pos}%`).join(",");
|
|
32198
|
+
result.gradientFill = `linear-gradient(${cssDeg}deg,${stopStr})`;
|
|
32199
|
+
}
|
|
32200
|
+
const firstColor = resolveColor2(gsEls[0], themeColors);
|
|
32201
|
+
if (firstColor)
|
|
32202
|
+
result.color = firstColor;
|
|
32203
|
+
}
|
|
32204
|
+
}
|
|
32205
|
+
}
|
|
32206
|
+
}
|
|
31194
32207
|
const latin = findChild2(rPr, "latin");
|
|
31195
32208
|
if (latin) {
|
|
31196
32209
|
const typeface = latin.getAttribute("typeface");
|
|
31197
32210
|
if (typeface)
|
|
31198
32211
|
result.fontFamily = typeface;
|
|
31199
32212
|
}
|
|
32213
|
+
const effectLst = findChild2(rPr, "effectLst");
|
|
32214
|
+
if (effectLst) {
|
|
32215
|
+
const glow = findChild2(effectLst, "glow");
|
|
32216
|
+
if (glow) {
|
|
32217
|
+
const radAttr = glow.getAttribute("rad");
|
|
32218
|
+
const radiusEmu = radAttr ? parseInt(radAttr, 10) : 0;
|
|
32219
|
+
const radiusPx = Math.round(emuToPx2(radiusEmu) * scale);
|
|
32220
|
+
const glowColor = resolveColor2(glow, themeColors);
|
|
32221
|
+
if (glowColor && radiusPx > 0) {
|
|
32222
|
+
const INVERSE_GLOW_SIZE_SCALE = 0.4;
|
|
32223
|
+
const INVERSE_GLOW_OPACITY_SCALE = 3.33;
|
|
32224
|
+
const cssRadius = Math.round(radiusPx * INVERSE_GLOW_SIZE_SCALE);
|
|
32225
|
+
const rgbaMatch = glowColor.match(/rgba?\((\d+),(\d+),(\d+)(?:,([0-9.]+))?\)/);
|
|
32226
|
+
if (rgbaMatch) {
|
|
32227
|
+
const r = rgbaMatch[1];
|
|
32228
|
+
const g = rgbaMatch[2];
|
|
32229
|
+
const b2 = rgbaMatch[3];
|
|
32230
|
+
const originalAlpha = rgbaMatch[4] ? parseFloat(rgbaMatch[4]) : 1;
|
|
32231
|
+
const scaledAlpha = Math.min(originalAlpha * INVERSE_GLOW_OPACITY_SCALE, 1);
|
|
32232
|
+
result.textShadow = `0 0 ${cssRadius}px rgba(${r},${g},${b2},${scaledAlpha.toFixed(2)})`;
|
|
32233
|
+
} else if (glowColor.startsWith("#")) {
|
|
32234
|
+
const r = parseInt(glowColor.slice(1, 3), 16);
|
|
32235
|
+
const g = parseInt(glowColor.slice(3, 5), 16);
|
|
32236
|
+
const b2 = parseInt(glowColor.slice(5, 7), 16);
|
|
32237
|
+
result.textShadow = `0 0 ${cssRadius}px rgba(${r},${g},${b2},1)`;
|
|
32238
|
+
} else {
|
|
32239
|
+
result.textShadow = `0 0 ${cssRadius}px ${glowColor}`;
|
|
32240
|
+
}
|
|
32241
|
+
}
|
|
32242
|
+
}
|
|
32243
|
+
}
|
|
31200
32244
|
return result;
|
|
31201
32245
|
}
|
|
31202
32246
|
function parseShape(sp, scale, themeColors) {
|
|
@@ -31221,13 +32265,16 @@ ${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join("\n")}`;
|
|
|
31221
32265
|
paragraphs: []
|
|
31222
32266
|
};
|
|
31223
32267
|
const prstGeom = findChild2(spPr, "prstGeom");
|
|
31224
|
-
|
|
32268
|
+
const prstType = prstGeom?.getAttribute("prst");
|
|
32269
|
+
if (prstType === "roundRect" && prstGeom) {
|
|
31225
32270
|
const avLst = findChild2(prstGeom, "avLst");
|
|
31226
32271
|
const gd = avLst ? findChild2(avLst, "gd") : null;
|
|
31227
32272
|
const adjVal = gd ? parseInt(gd.getAttribute("fmla")?.replace("val ", "") ?? "16667", 10) : 16667;
|
|
31228
32273
|
const minDim = Math.min(wEmu, hEmu);
|
|
31229
32274
|
const radiusEmu = minDim * Math.min(adjVal, 5e4) / 1e5;
|
|
31230
32275
|
shape.borderRadius = Math.round(emuToPx2(radiusEmu) * scale);
|
|
32276
|
+
} else if (prstType === "ellipse") {
|
|
32277
|
+
shape.isEllipse = true;
|
|
31231
32278
|
}
|
|
31232
32279
|
const ln = findChild2(spPr, "ln");
|
|
31233
32280
|
if (ln) {
|
|
@@ -31238,6 +32285,13 @@ ${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join("\n")}`;
|
|
|
31238
32285
|
if (lnFill) {
|
|
31239
32286
|
shape.borderColor = resolveColor2(lnFill, themeColors);
|
|
31240
32287
|
}
|
|
32288
|
+
const prstDash = findChild2(ln, "prstDash");
|
|
32289
|
+
if (prstDash) {
|
|
32290
|
+
const dashVal = prstDash.getAttribute("val");
|
|
32291
|
+
if (dashVal && dashVal !== "solid") {
|
|
32292
|
+
shape.borderDashType = dashVal;
|
|
32293
|
+
}
|
|
32294
|
+
}
|
|
31241
32295
|
}
|
|
31242
32296
|
}
|
|
31243
32297
|
const txBody = findChild2(sp, "txBody");
|
|
@@ -31308,21 +32362,34 @@ ${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join("\n")}`;
|
|
|
31308
32362
|
para.bulletChar = buChar.getAttribute("char") ?? void 0;
|
|
31309
32363
|
}
|
|
31310
32364
|
}
|
|
31311
|
-
const
|
|
31312
|
-
|
|
31313
|
-
|
|
31314
|
-
const
|
|
31315
|
-
const
|
|
31316
|
-
|
|
31317
|
-
|
|
31318
|
-
|
|
31319
|
-
|
|
31320
|
-
|
|
31321
|
-
|
|
31322
|
-
|
|
31323
|
-
|
|
31324
|
-
|
|
31325
|
-
|
|
32365
|
+
for (const child of Array.from(p.childNodes)) {
|
|
32366
|
+
if (child.nodeType !== 1)
|
|
32367
|
+
continue;
|
|
32368
|
+
const el = child;
|
|
32369
|
+
const localName = el.localName || el.nodeName.split(":").pop();
|
|
32370
|
+
if (localName === "r") {
|
|
32371
|
+
const rPr = findChild2(el, "rPr");
|
|
32372
|
+
const props = extractRunProps(rPr, scale, themeColors);
|
|
32373
|
+
const tEls = findChildren2(el, "t");
|
|
32374
|
+
const text = tEls.map((t) => t.textContent ?? "").join("");
|
|
32375
|
+
if (text) {
|
|
32376
|
+
para.runs.push({
|
|
32377
|
+
text,
|
|
32378
|
+
bold: props.bold ?? defaults?.bold,
|
|
32379
|
+
italic: props.italic ?? defaults?.italic,
|
|
32380
|
+
fontSize: props.fontSize ?? defaults?.fontSize,
|
|
32381
|
+
color: props.color ?? defaults?.color,
|
|
32382
|
+
fontFamily: props.fontFamily ?? defaults?.fontFamily,
|
|
32383
|
+
textShadow: props.textShadow ?? defaults?.textShadow,
|
|
32384
|
+
gradientFill: props.gradientFill ?? defaults?.gradientFill
|
|
32385
|
+
});
|
|
32386
|
+
}
|
|
32387
|
+
} else if (localName === "br") {
|
|
32388
|
+
if (para.runs.length > 0) {
|
|
32389
|
+
para.runs[para.runs.length - 1].text += "\n";
|
|
32390
|
+
} else {
|
|
32391
|
+
para.runs.push({ text: "\n" });
|
|
32392
|
+
}
|
|
31326
32393
|
}
|
|
31327
32394
|
}
|
|
31328
32395
|
if (para.runs.length > 0) {
|
|
@@ -31349,7 +32416,27 @@ ${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join("\n")}`;
|
|
|
31349
32416
|
const blip = findChild2(blipFill, "blip");
|
|
31350
32417
|
if (!blip)
|
|
31351
32418
|
return null;
|
|
31352
|
-
|
|
32419
|
+
let rEmbed = null;
|
|
32420
|
+
const extLst = findChild2(blip, "extLst");
|
|
32421
|
+
if (extLst) {
|
|
32422
|
+
for (let i = 0; i < extLst.children.length; i++) {
|
|
32423
|
+
const ext2 = extLst.children[i];
|
|
32424
|
+
if (ext2.localName === "ext") {
|
|
32425
|
+
for (let j = 0; j < ext2.children.length; j++) {
|
|
32426
|
+
const child = ext2.children[j];
|
|
32427
|
+
if (child.localName === "svgBlip") {
|
|
32428
|
+
rEmbed = child.getAttribute("r:embed") ?? child.getAttributeNS("http://schemas.openxmlformats.org/officeDocument/2006/relationships", "embed");
|
|
32429
|
+
break;
|
|
32430
|
+
}
|
|
32431
|
+
}
|
|
32432
|
+
if (rEmbed)
|
|
32433
|
+
break;
|
|
32434
|
+
}
|
|
32435
|
+
}
|
|
32436
|
+
}
|
|
32437
|
+
if (!rEmbed) {
|
|
32438
|
+
rEmbed = blip.getAttribute("r:embed") ?? blip.getAttributeNS("http://schemas.openxmlformats.org/officeDocument/2006/relationships", "embed");
|
|
32439
|
+
}
|
|
31353
32440
|
if (!rEmbed)
|
|
31354
32441
|
return null;
|
|
31355
32442
|
const dataUri = imageMap.get(rEmbed);
|
|
@@ -31358,13 +32445,36 @@ ${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join("\n")}`;
|
|
|
31358
32445
|
const nvPicPr = findChild2(pic, "nvPicPr");
|
|
31359
32446
|
const cNvPr = nvPicPr ? findChild2(nvPicPr, "cNvPr") : null;
|
|
31360
32447
|
const alt = cNvPr?.getAttribute("descr") ?? void 0;
|
|
32448
|
+
const srcRect = findChild2(blipFill, "srcRect");
|
|
32449
|
+
let hasCrop = false;
|
|
32450
|
+
if (srcRect) {
|
|
32451
|
+
const l = parseInt(srcRect.getAttribute("l") ?? "0", 10);
|
|
32452
|
+
const r = parseInt(srcRect.getAttribute("r") ?? "0", 10);
|
|
32453
|
+
const t = parseInt(srcRect.getAttribute("t") ?? "0", 10);
|
|
32454
|
+
const b = parseInt(srcRect.getAttribute("b") ?? "0", 10);
|
|
32455
|
+
hasCrop = l > 0 || r > 0 || t > 0 || b > 0;
|
|
32456
|
+
}
|
|
32457
|
+
let borderRadius;
|
|
32458
|
+
const prstGeom = findChild2(spPr, "prstGeom");
|
|
32459
|
+
if (prstGeom?.getAttribute("prst") === "roundRect") {
|
|
32460
|
+
const avLst = findChild2(prstGeom, "avLst");
|
|
32461
|
+
const gd = avLst ? findChild2(avLst, "gd") : null;
|
|
32462
|
+
const adjVal = gd ? parseInt(gd.getAttribute("fmla")?.replace("val ", "") ?? "16667", 10) : 16667;
|
|
32463
|
+
const wEmu = parseInt(ext.getAttribute("cx") ?? "0", 10);
|
|
32464
|
+
const hEmu = parseInt(ext.getAttribute("cy") ?? "0", 10);
|
|
32465
|
+
const minDim = Math.min(wEmu, hEmu);
|
|
32466
|
+
const radiusEmu = minDim * Math.min(adjVal, 5e4) / 1e5;
|
|
32467
|
+
borderRadius = Math.round(emuToPx2(radiusEmu) * scale);
|
|
32468
|
+
}
|
|
31361
32469
|
return {
|
|
31362
32470
|
x: Math.round(emuToPx2(parseInt(off.getAttribute("x") ?? "0", 10)) * scale),
|
|
31363
32471
|
y: Math.round(emuToPx2(parseInt(off.getAttribute("y") ?? "0", 10)) * scale),
|
|
31364
32472
|
w: Math.round(emuToPx2(parseInt(ext.getAttribute("cx") ?? "0", 10)) * scale),
|
|
31365
32473
|
h: Math.round(emuToPx2(parseInt(ext.getAttribute("cy") ?? "0", 10)) * scale),
|
|
31366
32474
|
dataUri,
|
|
31367
|
-
alt
|
|
32475
|
+
alt,
|
|
32476
|
+
borderRadius,
|
|
32477
|
+
hasCrop
|
|
31368
32478
|
};
|
|
31369
32479
|
}
|
|
31370
32480
|
function renderSlideHtml(elements, bgColor) {
|
|
@@ -31374,14 +32484,20 @@ ${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join("\n")}`;
|
|
|
31374
32484
|
const elId = `el-${elementIndex++}`;
|
|
31375
32485
|
if (el.kind === "image") {
|
|
31376
32486
|
const img = el.data;
|
|
31377
|
-
const
|
|
32487
|
+
const isFullbleed = img.x <= 10 && img.y <= 10 && img.w >= TARGET_WIDTH - 20 && img.h >= TARGET_HEIGHT - 20;
|
|
32488
|
+
const objectFit = isFullbleed || img.hasCrop ? "cover" : "contain";
|
|
32489
|
+
const stylesList = [
|
|
31378
32490
|
"position:absolute",
|
|
31379
32491
|
`left:${img.x}px`,
|
|
31380
32492
|
`top:${img.y}px`,
|
|
31381
32493
|
`width:${img.w}px`,
|
|
31382
32494
|
`height:${img.h}px`,
|
|
31383
|
-
|
|
31384
|
-
]
|
|
32495
|
+
`object-fit:${objectFit}`
|
|
32496
|
+
];
|
|
32497
|
+
if (img.borderRadius && img.borderRadius > 0) {
|
|
32498
|
+
stylesList.push(`border-radius:${img.borderRadius}px`);
|
|
32499
|
+
}
|
|
32500
|
+
const styles2 = stylesList.join(";");
|
|
31385
32501
|
const altAttr = img.alt ? ` alt="${img.alt.replace(/"/g, """)}"` : "";
|
|
31386
32502
|
inner += `<img id="${elId}" data-elementType="image" src="${img.dataUri}"${altAttr} style="${styles2}" />
|
|
31387
32503
|
`;
|
|
@@ -31401,9 +32517,25 @@ ${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join("\n")}`;
|
|
|
31401
32517
|
}
|
|
31402
32518
|
if (shape.borderRadius) {
|
|
31403
32519
|
styles.push(`border-radius:${shape.borderRadius}px`);
|
|
32520
|
+
} else if (shape.isEllipse) {
|
|
32521
|
+
styles.push(`border-radius:50%`);
|
|
31404
32522
|
}
|
|
31405
32523
|
if (shape.borderWidth && shape.borderColor) {
|
|
31406
|
-
|
|
32524
|
+
let borderStyle = "solid";
|
|
32525
|
+
if (shape.borderDashType) {
|
|
32526
|
+
switch (shape.borderDashType) {
|
|
32527
|
+
case "dash":
|
|
32528
|
+
case "lgDash":
|
|
32529
|
+
case "sysDash":
|
|
32530
|
+
borderStyle = "dashed";
|
|
32531
|
+
break;
|
|
32532
|
+
case "sysDot":
|
|
32533
|
+
case "dot":
|
|
32534
|
+
borderStyle = "dotted";
|
|
32535
|
+
break;
|
|
32536
|
+
}
|
|
32537
|
+
}
|
|
32538
|
+
styles.push(`border:${shape.borderWidth}px ${borderStyle} ${shape.borderColor}`);
|
|
31407
32539
|
styles.push("box-sizing:border-box");
|
|
31408
32540
|
}
|
|
31409
32541
|
if (shape.padding) {
|
|
@@ -31444,14 +32576,22 @@ ${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join("\n")}`;
|
|
|
31444
32576
|
const rStyles = [];
|
|
31445
32577
|
if (run.fontSize)
|
|
31446
32578
|
rStyles.push(`font-size:${run.fontSize}px`);
|
|
31447
|
-
if (run.
|
|
32579
|
+
if (run.gradientFill) {
|
|
32580
|
+
rStyles.push(`background:${run.gradientFill}`);
|
|
32581
|
+
rStyles.push("-webkit-background-clip:text");
|
|
32582
|
+
rStyles.push("-webkit-text-fill-color:transparent");
|
|
32583
|
+
rStyles.push("background-clip:text");
|
|
32584
|
+
} else if (run.color) {
|
|
31448
32585
|
rStyles.push(`color:${run.color}`);
|
|
32586
|
+
}
|
|
31449
32587
|
if (run.bold)
|
|
31450
32588
|
rStyles.push("font-weight:bold");
|
|
31451
32589
|
if (run.italic)
|
|
31452
32590
|
rStyles.push("font-style:italic");
|
|
31453
32591
|
if (run.fontFamily)
|
|
31454
|
-
rStyles.push(`font-family
|
|
32592
|
+
rStyles.push(`font-family:${cssFontFamily(run.fontFamily)}`);
|
|
32593
|
+
if (run.textShadow)
|
|
32594
|
+
rStyles.push(`text-shadow:${run.textShadow}`);
|
|
31455
32595
|
const escapedText = run.text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
31456
32596
|
if (rStyles.length > 0) {
|
|
31457
32597
|
runHtml += `<span style="${rStyles.join(";")}">${escapedText}</span>`;
|
|
@@ -31563,6 +32703,21 @@ ${inner}</div>`;
|
|
|
31563
32703
|
}
|
|
31564
32704
|
}
|
|
31565
32705
|
}
|
|
32706
|
+
const embeddedFontNames = /* @__PURE__ */ new Set();
|
|
32707
|
+
const embeddedFontEls = presDoc.getElementsByTagName("p:embeddedFont");
|
|
32708
|
+
for (let i = 0; i < embeddedFontEls.length; i++) {
|
|
32709
|
+
const fontEl = embeddedFontEls[i].getElementsByTagName("p:font")[0];
|
|
32710
|
+
if (fontEl) {
|
|
32711
|
+
const typeface = fontEl.getAttribute("typeface");
|
|
32712
|
+
if (typeface)
|
|
32713
|
+
embeddedFontNames.add(typeface);
|
|
32714
|
+
}
|
|
32715
|
+
}
|
|
32716
|
+
let fontStyleBlock = "";
|
|
32717
|
+
if (embeddedFontNames.size > 0) {
|
|
32718
|
+
const fontFamilies = Array.from(embeddedFontNames).map((name) => name.replace(/ /g, "+") + ":ital,wght@0,400;0,700;1,400;1,700").join("&family=");
|
|
32719
|
+
fontStyleBlock = `<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=${fontFamilies}&display=swap">`;
|
|
32720
|
+
}
|
|
31566
32721
|
const slides = [];
|
|
31567
32722
|
for (const slideFile of slideFiles) {
|
|
31568
32723
|
const slideXml = await zip.file(slideFile)?.async("text");
|
|
@@ -31623,6 +32778,9 @@ ${inner}</div>`;
|
|
|
31623
32778
|
}
|
|
31624
32779
|
slides.push(renderSlideHtml(elements, slideBg));
|
|
31625
32780
|
}
|
|
32781
|
+
if (fontStyleBlock && slides.length > 0) {
|
|
32782
|
+
slides[0] = fontStyleBlock + slides[0];
|
|
32783
|
+
}
|
|
31626
32784
|
return slides;
|
|
31627
32785
|
}
|
|
31628
32786
|
|