@pixldocs/canvas-renderer 0.5.214 → 0.5.216

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.
@@ -6914,9 +6914,19 @@ function buildTextShadow(element) {
6914
6914
  nonScaling: false
6915
6915
  });
6916
6916
  }
6917
- function resolveShadowAlpha(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)) : 100;
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);
6920
6930
  return s / 100;
6921
6931
  }
6922
6932
  function applyTextShadow(textbox, element) {
@@ -6935,6 +6945,8 @@ function applyTextShadow(textbox, element) {
6935
6945
  obj.__pdShadowOY = void 0;
6936
6946
  }
6937
6947
  obj.__pdShadowAlpha = canonicalShadow ? resolveShadowAlpha(element) : 1;
6948
+ obj.__pdShadowBaseColor = canonicalShadow ? String(element.textShadowColor || "") : void 0;
6949
+ obj.__pdShadowSourceSpread = canonicalShadow ? resolveShadowSourceSpread(element) : 0;
6938
6950
  textbox.set("shadow", canonicalShadow ?? null);
6939
6951
  }
6940
6952
  function applyAlphaMultiplier(c, mult) {
@@ -7218,6 +7230,8 @@ function applyTextBackground(obj, cfg) {
7218
7230
  }
7219
7231
  }
7220
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;
7221
7235
  if (suppressShadowOnText) {
7222
7236
  ctx.save();
7223
7237
  ctx.shadowColor = "transparent";
@@ -7226,6 +7240,44 @@ function applyTextBackground(obj, cfg) {
7226
7240
  ctx.shadowOffsetY = 0;
7227
7241
  originalRender(ctx);
7228
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
+ }
7229
7281
  } else {
7230
7282
  originalRender(ctx);
7231
7283
  }
@@ -7307,7 +7359,8 @@ function applyTextBackground(obj, cfg) {
7307
7359
  const oy = Number(shadow.offsetY ?? 0) || 0;
7308
7360
  const blur = Math.max(0, Number(shadow.blur ?? 0));
7309
7361
  const shadowColor = String(shadow.color);
7310
- 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);
7311
7364
  const shadowBounds = unionBounds([
7312
7365
  ...rects,
7313
7366
  computeTextVisualBounds(this, w, h)
@@ -7318,7 +7371,7 @@ function applyTextBackground(obj, cfg) {
7318
7371
  const bh = shadowBounds.h + pad * 2;
7319
7372
  const alphaRaw = Number(this.__pdShadowAlpha);
7320
7373
  const shadowAlpha = Number.isFinite(alphaRaw) ? Math.max(0, Math.min(1, alphaRaw)) : 1;
7321
- 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-alpha="${shadowAlpha.toFixed(3)}"`;
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)}"`;
7322
7375
  const wrapShadow = (markup) => blur <= 0 ? `<g transform="translate(${ox.toFixed(3)} ${oy.toFixed(3)})">${markup}</g>` : `<g class="__pdShadowRaster" ${dataAttrs}>${markup}</g>`;
7323
7376
  if (hasBg && (bg == null ? void 0 : bg.shadowAffectsBg) !== false) {
7324
7377
  const shadowOpacityAttr = bgOpacity < 1 ? ` fill-opacity="${bgOpacity}"` : "";
@@ -7327,7 +7380,7 @@ function applyTextBackground(obj, cfg) {
7327
7380
  }
7328
7381
  if ((bg == null ? void 0 : bg.shadowAffectsText) !== false && !hasActiveTextPath2) {
7329
7382
  const inner = extractGInnerMarkup(svg);
7330
- const recoloredText = recolorSvgFills(inner, shadowColor);
7383
+ const recoloredText = recolorSvgFills(inner, shadowColor, sourceSpread);
7331
7384
  if (recoloredText) textShadowMarker = wrapShadow(recoloredText);
7332
7385
  }
7333
7386
  }
@@ -7397,12 +7450,13 @@ function applyTextBackground(obj, cfg) {
7397
7450
  };
7398
7451
  }
7399
7452
  }
7400
- function recolorSvgFills(svg, color) {
7401
- return _recolorSvgFills(svg, color);
7453
+ function recolorSvgFills(svg, color, strokeWidth = 0) {
7454
+ return _recolorSvgFills(svg, color, strokeWidth);
7402
7455
  }
7403
- function _recolorSvgFills(svg, color) {
7456
+ function _recolorSvgFills(svg, color, strokeWidth = 0) {
7404
7457
  var _a;
7405
7458
  const safe = escapeXmlAttr(color);
7459
+ const spread = Math.max(0, Number(strokeWidth) || 0);
7406
7460
  try {
7407
7461
  const wrapped = `<svg xmlns="http://www.w3.org/2000/svg">${svg}</svg>`;
7408
7462
  const doc = new DOMParser().parseFromString(wrapped, "image/svg+xml");
@@ -7424,6 +7478,12 @@ function _recolorSvgFills(svg, color) {
7424
7478
  else el.removeAttribute("style");
7425
7479
  }
7426
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
+ }
7427
7487
  }
7428
7488
  let out2 = "";
7429
7489
  for (const child of Array.from(root.childNodes)) {
@@ -7453,6 +7513,13 @@ function _recolorSvgFills(svg, color) {
7453
7513
  if (/style="[^"]*\bfill\s*:/i.test(attrs)) return m;
7454
7514
  return `<${tag}${attrs} fill="${safe}">`;
7455
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
+ }
7456
7523
  return out;
7457
7524
  }
7458
7525
  function buildRoundedRectPathD(x, y, w, h, rTL, rTR, rBR, rBL) {
@@ -19034,9 +19101,9 @@ function captureFabricCanvasSvgForPdf(fabricInstance, canvasWidth, canvasHeight)
19034
19101
  }
19035
19102
  return svgString;
19036
19103
  }
19037
- const resolvedPackageVersion = "0.5.214";
19104
+ const resolvedPackageVersion = "0.5.216";
19038
19105
  const PACKAGE_VERSION = resolvedPackageVersion;
19039
- const DEPLOYMENT_VERSION_MARKER = "__PIXLDOCS_CANVAS_RENDERER_VERSION__:0.5.214";
19106
+ const DEPLOYMENT_VERSION_MARKER = "__PIXLDOCS_CANVAS_RENDERER_VERSION__:0.5.216";
19040
19107
  const roundParityValue = (value) => {
19041
19108
  if (typeof value !== "number") return value;
19042
19109
  return Number.isFinite(value) ? Number(value.toFixed(3)) : value;
@@ -19728,7 +19795,7 @@ class PixldocsRenderer {
19728
19795
  await this.waitForCanvasScene(container, cloned, i);
19729
19796
  }
19730
19797
  console.log(`[canvas-renderer][pdf-unified] mounted ${cloned.pages.length} page(s), handing off to client exportMultiPagePdf`);
19731
- const { exportMultiPagePdf, preparePagesForExport } = await Promise.resolve().then(() => require("./vectorPdfExport-BBG0QRse.cjs"));
19798
+ const { exportMultiPagePdf, preparePagesForExport } = await Promise.resolve().then(() => require("./vectorPdfExport-K3LAdOXU.cjs"));
19732
19799
  const prepared = preparePagesForExport(
19733
19800
  cloned.pages,
19734
19801
  canvasWidth,
@@ -20583,7 +20650,7 @@ const SVG_STYLE_PROPS = /* @__PURE__ */ new Set([
20583
20650
  const GRADIENT_ATTRS_LINEAR = ["x1", "y1", "x2", "y2", "gradientUnits", "gradientTransform", "spreadMethod"];
20584
20651
  const GRADIENT_ATTRS_RADIAL = ["cx", "cy", "r", "fx", "fy", "gradientUnits", "gradientTransform", "spreadMethod"];
20585
20652
  const URL_GRADIENT_RE = /^\s*url\s*\(\s*(['"]?)([^)]+?)\1\s*\)/i;
20586
- const SHADOW_RASTER_ALPHA_COMPENSATION = 0.84;
20653
+ const SHADOW_RASTER_ALPHA_COMPENSATION = 1;
20587
20654
  function collectFontSpecsFromMarkup(markup) {
20588
20655
  const specs = /* @__PURE__ */ new Set();
20589
20656
  const re = /<(?:text|tspan)\b[^>]*>/gi;
@@ -21670,6 +21737,9 @@ async function rasterizeShadowMarkers(svg) {
21670
21737
  const by = parseFloat(marker.getAttribute("data-by") || "0");
21671
21738
  const bw = parseFloat(marker.getAttribute("data-bw") || "0");
21672
21739
  const bh = parseFloat(marker.getAttribute("data-bh") || "0");
21740
+ const spread = parseFloat(marker.getAttribute("data-spread") || "0");
21741
+ const alphaRaw = parseFloat(marker.getAttribute("data-alpha") || "1");
21742
+ const shadowAlpha = Number.isFinite(alphaRaw) ? Math.max(0, Math.min(1, alphaRaw)) : 1;
21673
21743
  if (!Number.isFinite(bw) || !Number.isFinite(bh) || bw <= 0 || bh <= 0) {
21674
21744
  (_b = marker.parentNode) == null ? void 0 : _b.removeChild(marker);
21675
21745
  continue;
@@ -21693,7 +21763,8 @@ async function rasterizeShadowMarkers(svg) {
21693
21763
  const pxH = Math.min(4096, Math.max(8, Math.ceil(bh * scale)));
21694
21764
  const stdDev = Math.max(0, blur / 2);
21695
21765
  const filterId = `pdShadowBlur_${Math.random().toString(36).slice(2, 9)}`;
21696
- const styleBlock = fontFaceCss ? `<style>${fontFaceCss}</style>` : "";
21766
+ const spreadCss = spread > 0 ? `text,tspan,path{paint-order:stroke fill;stroke:currentColor;stroke-width:${spread.toFixed(3)}px;stroke-linejoin:round;stroke-linecap:round;}` : "";
21767
+ const styleBlock = fontFaceCss || spreadCss ? `<style>${fontFaceCss}${spreadCss}</style>` : "";
21697
21768
  const miniSvg = `<svg xmlns="${SVG_NS}" xmlns:xlink="${XLINK_NS}" width="${pxW}" height="${pxH}" viewBox="${bx} ${by} ${bw} ${bh}">${styleBlock}<defs><filter id="${filterId}" filterUnits="userSpaceOnUse" x="${bx}" y="${by}" width="${bw}" height="${bh}" color-interpolation-filters="sRGB"><feOffset dx="${ox}" dy="${oy}" result="offsetShadow" /><feGaussianBlur in="offsetShadow" stdDeviation="${stdDev}" /></filter></defs><g filter="url(#${filterId})">${innerXml}</g></svg>`;
21698
21769
  const dataUrl = await rasterSvgToPngDataUrl(miniSvg, pxW, pxH);
21699
21770
  if (!dataUrl) {
@@ -21708,8 +21779,6 @@ async function rasterizeShadowMarkers(svg) {
21708
21779
  img.setAttribute("preserveAspectRatio", "none");
21709
21780
  img.setAttributeNS(XLINK_NS, "xlink:href", dataUrl);
21710
21781
  img.setAttribute("href", dataUrl);
21711
- const alphaRaw = parseFloat(marker.getAttribute("data-alpha") || "1");
21712
- const shadowAlpha = Number.isFinite(alphaRaw) ? Math.max(0, Math.min(1, alphaRaw)) : 1;
21713
21782
  img.setAttribute("opacity", String(SHADOW_RASTER_ALPHA_COMPENSATION * shadowAlpha));
21714
21783
  (_e = marker.parentNode) == null ? void 0 : _e.replaceChild(img, marker);
21715
21784
  } catch (e) {
@@ -21916,7 +21985,7 @@ async function prepareLiveCanvasSvgForPdf(rawSvg, pageWidth, pageHeight, pageKey
21916
21985
  if (options == null ? void 0 : options.stripPageBackground) stripRootPageBackgroundFromSvg(svgToDraw);
21917
21986
  sanitizeSvgTreeForPdf(svgToDraw);
21918
21987
  try {
21919
- const { bakeTextAnchorPositionsFromLiveSvg, logTextMeasurementDiagnostic } = await Promise.resolve().then(() => require("./vectorPdfExport-BBG0QRse.cjs"));
21988
+ const { bakeTextAnchorPositionsFromLiveSvg, logTextMeasurementDiagnostic } = await Promise.resolve().then(() => require("./vectorPdfExport-K3LAdOXU.cjs"));
21920
21989
  try {
21921
21990
  await logTextMeasurementDiagnostic(svgToDraw);
21922
21991
  } catch {
@@ -22313,4 +22382,4 @@ exports.setAutoShrinkDebug = setAutoShrinkDebug;
22313
22382
  exports.setBundledAssetPrefixes = setBundledAssetPrefixes;
22314
22383
  exports.warmResolvedTemplateForPreview = warmResolvedTemplateForPreview;
22315
22384
  exports.warmTemplateFromForm = warmTemplateFromForm;
22316
- //# sourceMappingURL=index-Cy2_ElDZ.cjs.map
22385
+ //# sourceMappingURL=index-C5McWFUS.cjs.map