@pixldocs/canvas-renderer 0.5.213 → 0.5.215

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.
@@ -6902,9 +6902,9 @@ function buildTextShadow(element) {
6902
6902
  if (!color || color === "transparent") return null;
6903
6903
  const type = element.textShadowType;
6904
6904
  if (type && type !== "drop") return null;
6905
- const { passAlphas } = resolveShadowStrength(element);
6906
- const firstAlpha = passAlphas.length > 0 ? passAlphas[0] : 0;
6907
- const finalColor = applyAlphaMultiplier(String(color), firstAlpha);
6905
+ const alpha = resolveShadowAlpha(element);
6906
+ if (alpha <= 0) return null;
6907
+ const finalColor = applyAlphaMultiplier(String(color), alpha);
6908
6908
  return new fabric__namespace.Shadow({
6909
6909
  color: finalColor,
6910
6910
  blur: blur || 0,
@@ -6914,67 +6914,39 @@ function buildTextShadow(element) {
6914
6914
  nonScaling: false
6915
6915
  });
6916
6916
  }
6917
- function resolveShadowStrength(element) {
6917
+ function readShadowStrength(element) {
6918
6918
  const raw = element.textShadowStrength;
6919
- const s = typeof raw === "number" && Number.isFinite(raw) ? Math.max(0, Math.min(100, raw)) : 33.34;
6920
- if (s <= 0) return { passAlphas: [] };
6921
- const intensity = Math.min(3, s / 33.34);
6922
- if (intensity <= 1) return { passAlphas: [intensity] };
6923
- const full = Math.floor(intensity);
6924
- const frac = intensity - full;
6925
- const arr = new Array(full).fill(1);
6926
- if (frac > 0.01) arr.push(frac);
6927
- return { passAlphas: arr };
6919
+ return typeof raw === "number" && Number.isFinite(raw) ? Math.max(0, Math.min(100, raw)) : 100;
6920
+ }
6921
+ function resolveShadowSourceSpread(element) {
6922
+ const strength = readShadowStrength(element);
6923
+ const blur = Math.max(0, Number(element.textShadowBlur ?? 0) || 0);
6924
+ const fontSize = Math.max(1, Number(element.fontSize ?? 16) || 16);
6925
+ const t = Math.max(0, (strength - 35) / 65);
6926
+ return Math.min(8, blur * 0.16, fontSize * 0.08) * t * t;
6927
+ }
6928
+ function resolveShadowAlpha(element) {
6929
+ const s = readShadowStrength(element);
6930
+ return s / 100;
6928
6931
  }
6929
6932
  function applyTextShadow(textbox, element) {
6930
6933
  const canonicalShadow = buildTextShadow(element);
6931
- const { passAlphas } = resolveShadowStrength(element);
6932
- const baseColor = element.textShadowColor;
6933
- const blur = Number(element.textShadowBlur ?? 0) || 0;
6934
- const ox = Number(element.textShadowOffsetX ?? 0) || 0;
6935
- const oy = Number(element.textShadowOffsetY ?? 0) || 0;
6936
- const hasShadow = !!canonicalShadow && passAlphas.length > 0;
6937
6934
  const obj = textbox;
6938
- if (!obj.__pdShadowOrigRender) {
6939
- obj.__pdShadowOrigRender = obj.render.bind(obj);
6940
- obj.render = function(ctx) {
6941
- const alphas = obj.__pdShadowPassAlphas;
6942
- if (!alphas || alphas.length <= 1) {
6943
- obj.__pdShadowOrigRender(ctx);
6944
- return;
6945
- }
6946
- const orig = obj.shadow;
6947
- const baseC = obj.__pdShadowBaseColor || "#000";
6948
- const b = obj.__pdShadowBlur || 0;
6949
- const x = obj.__pdShadowOX || 0;
6950
- const y = obj.__pdShadowOY || 0;
6951
- for (let i = 0; i < alphas.length; i++) {
6952
- obj.shadow = new fabric__namespace.Shadow({
6953
- color: applyAlphaMultiplier(String(baseC), alphas[i]),
6954
- blur: b,
6955
- offsetX: x,
6956
- offsetY: y,
6957
- affectStroke: false,
6958
- nonScaling: false
6959
- });
6960
- obj.__pdShadowOrigRender(ctx);
6961
- }
6962
- obj.shadow = orig;
6963
- };
6964
- }
6965
- if (hasShadow) {
6966
- obj.__pdShadowPassAlphas = passAlphas;
6967
- obj.__pdShadowBaseColor = baseColor;
6968
- obj.__pdShadowBlur = blur;
6969
- obj.__pdShadowOX = ox;
6970
- obj.__pdShadowOY = oy;
6971
- obj.__pdShadowPasses = passAlphas.length;
6972
- obj.__pdShadowLastAlpha = passAlphas[passAlphas.length - 1];
6973
- } else {
6935
+ if (obj.__pdShadowOrigRender) {
6936
+ try {
6937
+ obj.render = obj.__pdShadowOrigRender;
6938
+ } catch {
6939
+ }
6940
+ obj.__pdShadowOrigRender = void 0;
6974
6941
  obj.__pdShadowPassAlphas = void 0;
6975
- obj.__pdShadowPasses = 0;
6976
- obj.__pdShadowLastAlpha = 1;
6977
- }
6942
+ obj.__pdShadowBaseColor = void 0;
6943
+ obj.__pdShadowBlur = void 0;
6944
+ obj.__pdShadowOX = void 0;
6945
+ obj.__pdShadowOY = void 0;
6946
+ }
6947
+ obj.__pdShadowAlpha = canonicalShadow ? resolveShadowAlpha(element) : 1;
6948
+ obj.__pdShadowBaseColor = canonicalShadow ? String(element.textShadowColor || "") : void 0;
6949
+ obj.__pdShadowSourceSpread = canonicalShadow ? resolveShadowSourceSpread(element) : 0;
6978
6950
  textbox.set("shadow", canonicalShadow ?? null);
6979
6951
  }
6980
6952
  function applyAlphaMultiplier(c, mult) {
@@ -7258,6 +7230,8 @@ function applyTextBackground(obj, cfg) {
7258
7230
  }
7259
7231
  }
7260
7232
  const suppressShadowOnText = bg && bg.shadowAffectsText === false;
7233
+ const dropShadowSpread = Math.max(0, Number(this.__pdShadowSourceSpread) || 0);
7234
+ const dropShadowActive = dropShadowSpread > 0 && !!this.shadow && !suppressShadowOnText && !blockShadowActive && !lineShadowActive;
7261
7235
  if (suppressShadowOnText) {
7262
7236
  ctx.save();
7263
7237
  ctx.shadowColor = "transparent";
@@ -7266,6 +7240,44 @@ function applyTextBackground(obj, cfg) {
7266
7240
  ctx.shadowOffsetY = 0;
7267
7241
  originalRender(ctx);
7268
7242
  ctx.restore();
7243
+ } else if (dropShadowActive) {
7244
+ const self = this;
7245
+ const shadow = self.shadow;
7246
+ const shadowColor = String((shadow == null ? void 0 : shadow.color) || this.__pdShadowBaseColor || "rgba(0,0,0,1)");
7247
+ const shadowBlur = Math.max(0, Number((shadow == null ? void 0 : shadow.blur) ?? 0) || 0);
7248
+ const shadowOffsetX = Number((shadow == null ? void 0 : shadow.offsetX) ?? 0) || 0;
7249
+ const shadowOffsetY = Number((shadow == null ? void 0 : shadow.offsetY) ?? 0) || 0;
7250
+ const origFill = self.fill;
7251
+ const origStroke = self.stroke;
7252
+ const origStrokeWidth = self.strokeWidth;
7253
+ const origStyles = self.styles;
7254
+ const origShadow = self.shadow;
7255
+ try {
7256
+ ctx.save();
7257
+ self.shadow = null;
7258
+ self.fill = shadowColor;
7259
+ self.styles = {};
7260
+ self.stroke = shadowColor;
7261
+ self.strokeWidth = dropShadowSpread;
7262
+ ctx.translate(shadowOffsetX, shadowOffsetY);
7263
+ if (shadowBlur > 0) ctx.filter = `blur(${shadowBlur / 2}px)`;
7264
+ ctx.lineJoin = "round";
7265
+ ctx.lineCap = "round";
7266
+ originalRender(ctx);
7267
+ ctx.restore();
7268
+ self.fill = origFill;
7269
+ self.stroke = origStroke;
7270
+ self.strokeWidth = origStrokeWidth;
7271
+ self.styles = origStyles;
7272
+ self.shadow = null;
7273
+ originalRender(ctx);
7274
+ } finally {
7275
+ self.fill = origFill;
7276
+ self.stroke = origStroke;
7277
+ self.strokeWidth = origStrokeWidth;
7278
+ self.styles = origStyles;
7279
+ self.shadow = origShadow;
7280
+ }
7269
7281
  } else {
7270
7282
  originalRender(ctx);
7271
7283
  }
@@ -7347,7 +7359,8 @@ function applyTextBackground(obj, cfg) {
7347
7359
  const oy = Number(shadow.offsetY ?? 0) || 0;
7348
7360
  const blur = Math.max(0, Number(shadow.blur ?? 0));
7349
7361
  const shadowColor = String(shadow.color);
7350
- const pad = Math.max(16, Math.ceil(blur * 4) + Math.ceil(Math.max(Math.abs(ox), Math.abs(oy))) + 8);
7362
+ const sourceSpread = Math.max(0, Number(this.__pdShadowSourceSpread) || 0);
7363
+ const pad = Math.max(16, Math.ceil((blur + sourceSpread) * 4) + Math.ceil(Math.max(Math.abs(ox), Math.abs(oy))) + 8);
7351
7364
  const shadowBounds = unionBounds([
7352
7365
  ...rects,
7353
7366
  computeTextVisualBounds(this, w, h)
@@ -7356,10 +7369,9 @@ function applyTextBackground(obj, cfg) {
7356
7369
  const by = shadowBounds.y - pad;
7357
7370
  const bw = shadowBounds.w + pad * 2;
7358
7371
  const bh = shadowBounds.h + pad * 2;
7359
- const passes = Math.max(1, Math.min(8, Number(this.__pdShadowPasses) || 1));
7360
- const lastAlphaRaw = Number(this.__pdShadowLastAlpha);
7361
- const lastAlpha = Number.isFinite(lastAlphaRaw) ? Math.max(0, Math.min(1, lastAlphaRaw)) : 1;
7362
- const dataAttrs = `data-blur="${blur.toFixed(3)}" data-ox="${ox.toFixed(3)}" data-oy="${oy.toFixed(3)}" data-bx="${bx.toFixed(3)}" data-by="${by.toFixed(3)}" data-bw="${bw.toFixed(3)}" data-bh="${bh.toFixed(3)}" data-color="${escapeXmlAttr(shadowColor)}" data-passes="${passes}" data-last-alpha="${lastAlpha.toFixed(3)}"`;
7372
+ const alphaRaw = Number(this.__pdShadowAlpha);
7373
+ const shadowAlpha = Number.isFinite(alphaRaw) ? Math.max(0, Math.min(1, alphaRaw)) : 1;
7374
+ const dataAttrs = `data-blur="${blur.toFixed(3)}" data-spread="${sourceSpread.toFixed(3)}" data-ox="${ox.toFixed(3)}" data-oy="${oy.toFixed(3)}" data-bx="${bx.toFixed(3)}" data-by="${by.toFixed(3)}" data-bw="${bw.toFixed(3)}" data-bh="${bh.toFixed(3)}" data-color="${escapeXmlAttr(shadowColor)}" data-alpha="${shadowAlpha.toFixed(3)}"`;
7363
7375
  const wrapShadow = (markup) => blur <= 0 ? `<g transform="translate(${ox.toFixed(3)} ${oy.toFixed(3)})">${markup}</g>` : `<g class="__pdShadowRaster" ${dataAttrs}>${markup}</g>`;
7364
7376
  if (hasBg && (bg == null ? void 0 : bg.shadowAffectsBg) !== false) {
7365
7377
  const shadowOpacityAttr = bgOpacity < 1 ? ` fill-opacity="${bgOpacity}"` : "";
@@ -7368,7 +7380,7 @@ function applyTextBackground(obj, cfg) {
7368
7380
  }
7369
7381
  if ((bg == null ? void 0 : bg.shadowAffectsText) !== false && !hasActiveTextPath2) {
7370
7382
  const inner = extractGInnerMarkup(svg);
7371
- const recoloredText = recolorSvgFills(inner, shadowColor);
7383
+ const recoloredText = recolorSvgFills(inner, shadowColor, sourceSpread);
7372
7384
  if (recoloredText) textShadowMarker = wrapShadow(recoloredText);
7373
7385
  }
7374
7386
  }
@@ -7438,12 +7450,13 @@ function applyTextBackground(obj, cfg) {
7438
7450
  };
7439
7451
  }
7440
7452
  }
7441
- function recolorSvgFills(svg, color) {
7442
- return _recolorSvgFills(svg, color);
7453
+ function recolorSvgFills(svg, color, strokeWidth = 0) {
7454
+ return _recolorSvgFills(svg, color, strokeWidth);
7443
7455
  }
7444
- function _recolorSvgFills(svg, color) {
7456
+ function _recolorSvgFills(svg, color, strokeWidth = 0) {
7445
7457
  var _a;
7446
7458
  const safe = escapeXmlAttr(color);
7459
+ const spread = Math.max(0, Number(strokeWidth) || 0);
7447
7460
  try {
7448
7461
  const wrapped = `<svg xmlns="http://www.w3.org/2000/svg">${svg}</svg>`;
7449
7462
  const doc = new DOMParser().parseFromString(wrapped, "image/svg+xml");
@@ -7465,6 +7478,12 @@ function _recolorSvgFills(svg, color) {
7465
7478
  else el.removeAttribute("style");
7466
7479
  }
7467
7480
  el.setAttribute("fill", color);
7481
+ if (spread > 0 && /^(text|tspan|path)$/i.test(el.tagName)) {
7482
+ el.setAttribute("stroke", color);
7483
+ el.setAttribute("stroke-width", String(Number(spread.toFixed(3))));
7484
+ el.setAttribute("stroke-linejoin", "round");
7485
+ el.setAttribute("stroke-linecap", "round");
7486
+ }
7468
7487
  }
7469
7488
  let out2 = "";
7470
7489
  for (const child of Array.from(root.childNodes)) {
@@ -7494,6 +7513,13 @@ function _recolorSvgFills(svg, color) {
7494
7513
  if (/style="[^"]*\bfill\s*:/i.test(attrs)) return m;
7495
7514
  return `<${tag}${attrs} fill="${safe}">`;
7496
7515
  });
7516
+ if (spread > 0) {
7517
+ const strokeAttrs = ` stroke="${safe}" stroke-width="${Number(spread.toFixed(3))}" stroke-linejoin="round" stroke-linecap="round"`;
7518
+ out = out.replace(/<(text|tspan|path)\b([^>]*)>/gi, (m, tag, attrs) => {
7519
+ let nextAttrs = String(attrs).replace(/\s(?:stroke|stroke-width|stroke-linejoin|stroke-linecap)="[^"]*"/gi, "");
7520
+ return `<${tag}${nextAttrs}${strokeAttrs}>`;
7521
+ });
7522
+ }
7497
7523
  return out;
7498
7524
  }
7499
7525
  function buildRoundedRectPathD(x, y, w, h, rTL, rTR, rBR, rBL) {
@@ -19075,9 +19101,9 @@ function captureFabricCanvasSvgForPdf(fabricInstance, canvasWidth, canvasHeight)
19075
19101
  }
19076
19102
  return svgString;
19077
19103
  }
19078
- const resolvedPackageVersion = "0.5.213";
19104
+ const resolvedPackageVersion = "0.5.215";
19079
19105
  const PACKAGE_VERSION = resolvedPackageVersion;
19080
- const DEPLOYMENT_VERSION_MARKER = "__PIXLDOCS_CANVAS_RENDERER_VERSION__:0.5.213";
19106
+ const DEPLOYMENT_VERSION_MARKER = "__PIXLDOCS_CANVAS_RENDERER_VERSION__:0.5.215";
19081
19107
  const roundParityValue = (value) => {
19082
19108
  if (typeof value !== "number") return value;
19083
19109
  return Number.isFinite(value) ? Number(value.toFixed(3)) : value;
@@ -19769,7 +19795,7 @@ class PixldocsRenderer {
19769
19795
  await this.waitForCanvasScene(container, cloned, i);
19770
19796
  }
19771
19797
  console.log(`[canvas-renderer][pdf-unified] mounted ${cloned.pages.length} page(s), handing off to client exportMultiPagePdf`);
19772
- const { exportMultiPagePdf, preparePagesForExport } = await Promise.resolve().then(() => require("./vectorPdfExport-krI8SwbX.cjs"));
19798
+ const { exportMultiPagePdf, preparePagesForExport } = await Promise.resolve().then(() => require("./vectorPdfExport-DUohXw5V.cjs"));
19773
19799
  const prepared = preparePagesForExport(
19774
19800
  cloned.pages,
19775
19801
  canvasWidth,
@@ -20624,7 +20650,7 @@ const SVG_STYLE_PROPS = /* @__PURE__ */ new Set([
20624
20650
  const GRADIENT_ATTRS_LINEAR = ["x1", "y1", "x2", "y2", "gradientUnits", "gradientTransform", "spreadMethod"];
20625
20651
  const GRADIENT_ATTRS_RADIAL = ["cx", "cy", "r", "fx", "fy", "gradientUnits", "gradientTransform", "spreadMethod"];
20626
20652
  const URL_GRADIENT_RE = /^\s*url\s*\(\s*(['"]?)([^)]+?)\1\s*\)/i;
20627
- const SHADOW_RASTER_ALPHA_COMPENSATION = 0.84;
20653
+ const SHADOW_RASTER_ALPHA_COMPENSATION = 1;
20628
20654
  function collectFontSpecsFromMarkup(markup) {
20629
20655
  const specs = /* @__PURE__ */ new Set();
20630
20656
  const re = /<(?:text|tspan)\b[^>]*>/gi;
@@ -21691,7 +21717,7 @@ async function convertSvgTextDecorationsToLinesString(svgStr) {
21691
21717
  }
21692
21718
  }
21693
21719
  async function rasterizeShadowMarkers(svg) {
21694
- var _a, _b, _c, _d, _e, _f, _g;
21720
+ var _a, _b, _c, _d, _e, _f;
21695
21721
  if (typeof window === "undefined" || typeof document === "undefined") return;
21696
21722
  const markers = Array.from(svg.querySelectorAll("g.__pdShadowRaster"));
21697
21723
  if (markers.length === 0) return;
@@ -21746,29 +21772,15 @@ async function rasterizeShadowMarkers(svg) {
21746
21772
  img.setAttribute("y", String(by));
21747
21773
  img.setAttribute("width", String(bw));
21748
21774
  img.setAttribute("height", String(bh));
21749
- img.setAttribute("opacity", String(SHADOW_RASTER_ALPHA_COMPENSATION));
21750
21775
  img.setAttribute("preserveAspectRatio", "none");
21751
21776
  img.setAttributeNS(XLINK_NS, "xlink:href", dataUrl);
21752
21777
  img.setAttribute("href", dataUrl);
21753
- const passes = Math.max(1, Math.min(8, parseInt(marker.getAttribute("data-passes") || "1", 10) || 1));
21754
- const lastAlphaRaw = parseFloat(marker.getAttribute("data-last-alpha") || "1");
21755
- const lastAlpha = Number.isFinite(lastAlphaRaw) ? Math.max(0, Math.min(1, lastAlphaRaw)) : 1;
21756
- const baseOpacity = Number(img.getAttribute("opacity") || "1") || 1;
21778
+ img.setAttribute("opacity", String(SHADOW_RASTER_ALPHA_COMPENSATION));
21757
21779
  (_e = marker.parentNode) == null ? void 0 : _e.replaceChild(img, marker);
21758
- for (let i = 1; i < passes; i++) {
21759
- const extra = img.cloneNode(true);
21760
- if (i === passes - 1 && lastAlpha < 1) {
21761
- extra.setAttribute("opacity", String(baseOpacity * lastAlpha));
21762
- }
21763
- (_f = img.parentNode) == null ? void 0 : _f.insertBefore(extra, img.nextSibling);
21764
- }
21765
- if (passes === 1 && lastAlpha < 1) {
21766
- img.setAttribute("opacity", String(baseOpacity * lastAlpha));
21767
- }
21768
21780
  } catch (e) {
21769
21781
  console.warn("[pdf-export] rasterizeShadowMarkers failed for one marker:", e);
21770
21782
  try {
21771
- (_g = marker.parentNode) == null ? void 0 : _g.removeChild(marker);
21783
+ (_f = marker.parentNode) == null ? void 0 : _f.removeChild(marker);
21772
21784
  } catch {
21773
21785
  }
21774
21786
  }
@@ -21969,7 +21981,7 @@ async function prepareLiveCanvasSvgForPdf(rawSvg, pageWidth, pageHeight, pageKey
21969
21981
  if (options == null ? void 0 : options.stripPageBackground) stripRootPageBackgroundFromSvg(svgToDraw);
21970
21982
  sanitizeSvgTreeForPdf(svgToDraw);
21971
21983
  try {
21972
- const { bakeTextAnchorPositionsFromLiveSvg, logTextMeasurementDiagnostic } = await Promise.resolve().then(() => require("./vectorPdfExport-krI8SwbX.cjs"));
21984
+ const { bakeTextAnchorPositionsFromLiveSvg, logTextMeasurementDiagnostic } = await Promise.resolve().then(() => require("./vectorPdfExport-DUohXw5V.cjs"));
21973
21985
  try {
21974
21986
  await logTextMeasurementDiagnostic(svgToDraw);
21975
21987
  } catch {
@@ -22366,4 +22378,4 @@ exports.setAutoShrinkDebug = setAutoShrinkDebug;
22366
22378
  exports.setBundledAssetPrefixes = setBundledAssetPrefixes;
22367
22379
  exports.warmResolvedTemplateForPreview = warmResolvedTemplateForPreview;
22368
22380
  exports.warmTemplateFromForm = warmTemplateFromForm;
22369
- //# sourceMappingURL=index-zkVpb-YL.cjs.map
22381
+ //# sourceMappingURL=index-CzwZcfGF.cjs.map