@pixldocs/canvas-renderer 0.5.46 → 0.5.48
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/index.cjs +141 -51
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +141 -51
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -4938,35 +4938,30 @@ function applyTextBackground(obj, cfg) {
|
|
|
4938
4938
|
const bgPath = hasBg ? `<path d="${bgD}" fill="${escapeXmlAttr(bgFill)}" />` : "";
|
|
4939
4939
|
svg = svg.replace(/style="[^"]*filter:\s*url\([^)]+\)[^"]*"/i, "");
|
|
4940
4940
|
svg = svg.replace(/<filter[\s\S]*?<\/filter>/gi, "");
|
|
4941
|
-
let
|
|
4942
|
-
let
|
|
4941
|
+
let bgShadowMarker = "";
|
|
4942
|
+
let textShadowMarker = "";
|
|
4943
4943
|
if (hasShadow) {
|
|
4944
4944
|
const ox = Number(shadow.offsetX ?? 0) || 0;
|
|
4945
4945
|
const oy = Number(shadow.offsetY ?? 0) || 0;
|
|
4946
4946
|
const blur = Math.max(0, Number(shadow.blur ?? 0));
|
|
4947
4947
|
const shadowColor = String(shadow.color);
|
|
4948
|
-
const
|
|
4948
|
+
const pad = Math.max(8, Math.ceil(blur * 3) + Math.ceil(Math.max(Math.abs(ox), Math.abs(oy))) + 4);
|
|
4949
|
+
const bx = -w / 2 - pL - pad;
|
|
4950
|
+
const by = -h / 2 - pT - pad;
|
|
4951
|
+
const bw = w + pL + pR + pad * 2;
|
|
4952
|
+
const bh = h + pT + pB + pad * 2;
|
|
4953
|
+
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)}"`;
|
|
4954
|
+
const wrapShadow = (markup) => blur <= 0 ? `<g transform="translate(${ox.toFixed(3)} ${oy.toFixed(3)})">${markup}</g>` : `<g class="__pdShadowRaster" ${dataAttrs}>${markup}</g>`;
|
|
4955
|
+
if (hasBg) {
|
|
4956
|
+
const shadowBgPath = `<path d="${bgD}" fill="${escapeXmlAttr(shadowColor)}" />`;
|
|
4957
|
+
bgShadowMarker = wrapShadow(shadowBgPath);
|
|
4958
|
+
}
|
|
4949
4959
|
const inner = extractGInnerMarkup(svg);
|
|
4950
4960
|
const recoloredText = recolorSvgFills(inner, shadowColor);
|
|
4951
|
-
|
|
4952
|
-
const textLayers = [];
|
|
4953
|
-
const pushShadowPass = (tx, ty, opacity) => {
|
|
4954
|
-
const attrs = `transform="translate(${tx.toFixed(3)} ${ty.toFixed(3)})"${opacity ? ` opacity="${opacity}"` : ""}`;
|
|
4955
|
-
if (shadowBgPath) bgLayers.push(`<g ${attrs}>${shadowBgPath}</g>`);
|
|
4956
|
-
if (recoloredText) textLayers.push(`<g ${attrs}>${recoloredText}</g>`);
|
|
4957
|
-
};
|
|
4958
|
-
if (blur > 0) {
|
|
4959
|
-
for (const pass of buildNormalizedShadowPasses(blur)) {
|
|
4960
|
-
pushShadowPass(ox + pass.dx, oy + pass.dy, pass.opacity);
|
|
4961
|
-
}
|
|
4962
|
-
} else {
|
|
4963
|
-
pushShadowPass(ox, oy);
|
|
4964
|
-
}
|
|
4965
|
-
bgShadowLayer = bgLayers.join("");
|
|
4966
|
-
textShadowLayer = textLayers.join("");
|
|
4961
|
+
if (recoloredText) textShadowMarker = wrapShadow(recoloredText);
|
|
4967
4962
|
}
|
|
4968
4963
|
const openTagMatch = svg.match(/^\s*<g\b[^>]*>/);
|
|
4969
|
-
const inserted =
|
|
4964
|
+
const inserted = bgShadowMarker + bgPath + textShadowMarker;
|
|
4970
4965
|
if (openTagMatch) {
|
|
4971
4966
|
const openTag = openTagMatch[0];
|
|
4972
4967
|
return svg.replace(openTag, openTag + inserted);
|
|
@@ -4994,36 +4989,6 @@ function recolorSvgFills(svg, color) {
|
|
|
4994
4989
|
);
|
|
4995
4990
|
return out;
|
|
4996
4991
|
}
|
|
4997
|
-
function buildNormalizedShadowPasses(blur) {
|
|
4998
|
-
const safeBlur = Math.max(0, Number(blur) || 0);
|
|
4999
|
-
const ringCount = Math.min(5, Math.max(2, Math.round(safeBlur / 5)));
|
|
5000
|
-
const targetOpacity = Math.max(0.16, Math.min(0.38, 0.46 - safeBlur * 0.01));
|
|
5001
|
-
const weighted = [
|
|
5002
|
-
{ dx: 0, dy: 0, weight: 0.7 }
|
|
5003
|
-
];
|
|
5004
|
-
for (let i = 1; i <= ringCount; i++) {
|
|
5005
|
-
const t = i / ringCount;
|
|
5006
|
-
const dist = safeBlur * t * 0.42;
|
|
5007
|
-
const weight = Math.exp(-2.4 * t * t);
|
|
5008
|
-
const diag = dist * 0.7071;
|
|
5009
|
-
weighted.push(
|
|
5010
|
-
{ dx: dist, dy: 0, weight },
|
|
5011
|
-
{ dx: -dist, dy: 0, weight },
|
|
5012
|
-
{ dx: 0, dy: dist, weight },
|
|
5013
|
-
{ dx: 0, dy: -dist, weight },
|
|
5014
|
-
{ dx: diag, dy: diag, weight: weight * 0.72 },
|
|
5015
|
-
{ dx: -diag, dy: diag, weight: weight * 0.72 },
|
|
5016
|
-
{ dx: diag, dy: -diag, weight: weight * 0.72 },
|
|
5017
|
-
{ dx: -diag, dy: -diag, weight: weight * 0.72 }
|
|
5018
|
-
);
|
|
5019
|
-
}
|
|
5020
|
-
const totalWeight = weighted.reduce((sum, pass) => sum + pass.weight, 0) || 1;
|
|
5021
|
-
return weighted.map((pass) => ({
|
|
5022
|
-
dx: pass.dx,
|
|
5023
|
-
dy: pass.dy,
|
|
5024
|
-
opacity: Math.max(3e-3, targetOpacity * pass.weight / totalWeight).toFixed(4)
|
|
5025
|
-
}));
|
|
5026
|
-
}
|
|
5027
4992
|
function buildRoundedRectPathD(x, y, w, h, rTL, rTR, rBR, rBL) {
|
|
5028
4993
|
const maxR = Math.min(w, h) / 2;
|
|
5029
4994
|
const tl = Math.min(Math.max(0, rTL), maxR);
|
|
@@ -12375,7 +12340,7 @@ function PixldocsPreview(props) {
|
|
|
12375
12340
|
!canvasSettled && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { position: "absolute", inset: 0, display: "flex", alignItems: "center", justifyContent: "center", minHeight: 200 }, children: /* @__PURE__ */ jsxRuntime.jsx("div", { style: { color: "#888", fontSize: 14 }, children: "Loading preview..." }) })
|
|
12376
12341
|
] });
|
|
12377
12342
|
}
|
|
12378
|
-
const PACKAGE_VERSION = "0.5.
|
|
12343
|
+
const PACKAGE_VERSION = "0.5.48";
|
|
12379
12344
|
let __underlineFixInstalled = false;
|
|
12380
12345
|
function installUnderlineFix(fab) {
|
|
12381
12346
|
var _a;
|
|
@@ -15041,6 +15006,130 @@ async function convertTextDecorationsToLines(svg) {
|
|
|
15041
15006
|
}
|
|
15042
15007
|
}
|
|
15043
15008
|
}
|
|
15009
|
+
async function rasterizeShadowMarkers(svg) {
|
|
15010
|
+
var _a, _b, _c, _d, _e;
|
|
15011
|
+
if (typeof window === "undefined" || typeof document === "undefined") return;
|
|
15012
|
+
const markers = Array.from(svg.querySelectorAll("g.__pdShadowRaster"));
|
|
15013
|
+
if (markers.length === 0) return;
|
|
15014
|
+
const SVG_NS = "http://www.w3.org/2000/svg";
|
|
15015
|
+
const XLINK_NS = "http://www.w3.org/1999/xlink";
|
|
15016
|
+
try {
|
|
15017
|
+
if ((_a = document.fonts) == null ? void 0 : _a.ready) await document.fonts.ready;
|
|
15018
|
+
} catch {
|
|
15019
|
+
}
|
|
15020
|
+
const fontFaceCss = collectDocumentFontFaceCss();
|
|
15021
|
+
for (const marker of markers) {
|
|
15022
|
+
try {
|
|
15023
|
+
const blur = parseFloat(marker.getAttribute("data-blur") || "0");
|
|
15024
|
+
const ox = parseFloat(marker.getAttribute("data-ox") || "0");
|
|
15025
|
+
const oy = parseFloat(marker.getAttribute("data-oy") || "0");
|
|
15026
|
+
const bx = parseFloat(marker.getAttribute("data-bx") || "0");
|
|
15027
|
+
const by = parseFloat(marker.getAttribute("data-by") || "0");
|
|
15028
|
+
const bw = parseFloat(marker.getAttribute("data-bw") || "0");
|
|
15029
|
+
const bh = parseFloat(marker.getAttribute("data-bh") || "0");
|
|
15030
|
+
if (!Number.isFinite(bw) || !Number.isFinite(bh) || bw <= 0 || bh <= 0) {
|
|
15031
|
+
(_b = marker.parentNode) == null ? void 0 : _b.removeChild(marker);
|
|
15032
|
+
continue;
|
|
15033
|
+
}
|
|
15034
|
+
const innerXml = Array.from(marker.childNodes).map((n) => n instanceof Element ? new XMLSerializer().serializeToString(n) : "").join("");
|
|
15035
|
+
const scale = 2;
|
|
15036
|
+
const pxW = Math.min(4096, Math.max(8, Math.ceil(bw * scale)));
|
|
15037
|
+
const pxH = Math.min(4096, Math.max(8, Math.ceil(bh * scale)));
|
|
15038
|
+
const stdDev = Math.max(0, blur);
|
|
15039
|
+
const filterId = `pdShadowBlur_${Math.random().toString(36).slice(2, 9)}`;
|
|
15040
|
+
const styleBlock = fontFaceCss ? `<style>${fontFaceCss}</style>` : "";
|
|
15041
|
+
const miniSvg = `<svg xmlns="${SVG_NS}" xmlns:xlink="${XLINK_NS}" width="${pxW}" height="${pxH}" viewBox="${bx} ${by} ${bw} ${bh}"><defs>${styleBlock}<filter id="${filterId}" x="-50%" y="-50%" width="200%" height="200%" 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>`;
|
|
15042
|
+
const dataUrl = await rasterSvgToPngDataUrl(miniSvg, pxW, pxH);
|
|
15043
|
+
if (!dataUrl) {
|
|
15044
|
+
(_c = marker.parentNode) == null ? void 0 : _c.removeChild(marker);
|
|
15045
|
+
continue;
|
|
15046
|
+
}
|
|
15047
|
+
const img = svg.ownerDocument.createElementNS(SVG_NS, "image");
|
|
15048
|
+
img.setAttribute("x", String(bx));
|
|
15049
|
+
img.setAttribute("y", String(by));
|
|
15050
|
+
img.setAttribute("width", String(bw));
|
|
15051
|
+
img.setAttribute("height", String(bh));
|
|
15052
|
+
img.setAttribute("preserveAspectRatio", "none");
|
|
15053
|
+
img.setAttributeNS(XLINK_NS, "xlink:href", dataUrl);
|
|
15054
|
+
img.setAttribute("href", dataUrl);
|
|
15055
|
+
(_d = marker.parentNode) == null ? void 0 : _d.replaceChild(img, marker);
|
|
15056
|
+
} catch (e) {
|
|
15057
|
+
console.warn("[pdf-export] rasterizeShadowMarkers failed for one marker:", e);
|
|
15058
|
+
try {
|
|
15059
|
+
(_e = marker.parentNode) == null ? void 0 : _e.removeChild(marker);
|
|
15060
|
+
} catch {
|
|
15061
|
+
}
|
|
15062
|
+
}
|
|
15063
|
+
}
|
|
15064
|
+
}
|
|
15065
|
+
function rasterSvgToPngDataUrl(svgMarkup, pxW, pxH) {
|
|
15066
|
+
return new Promise((resolve) => {
|
|
15067
|
+
try {
|
|
15068
|
+
const blob = new Blob([svgMarkup], { type: "image/svg+xml;charset=utf-8" });
|
|
15069
|
+
const url = URL.createObjectURL(blob);
|
|
15070
|
+
const img = new Image();
|
|
15071
|
+
img.crossOrigin = "anonymous";
|
|
15072
|
+
const cleanup = () => {
|
|
15073
|
+
try {
|
|
15074
|
+
URL.revokeObjectURL(url);
|
|
15075
|
+
} catch {
|
|
15076
|
+
}
|
|
15077
|
+
};
|
|
15078
|
+
img.onload = () => {
|
|
15079
|
+
try {
|
|
15080
|
+
const canvas = document.createElement("canvas");
|
|
15081
|
+
canvas.width = pxW;
|
|
15082
|
+
canvas.height = pxH;
|
|
15083
|
+
const ctx = canvas.getContext("2d");
|
|
15084
|
+
if (!ctx) {
|
|
15085
|
+
cleanup();
|
|
15086
|
+
resolve(null);
|
|
15087
|
+
return;
|
|
15088
|
+
}
|
|
15089
|
+
ctx.drawImage(img, 0, 0, pxW, pxH);
|
|
15090
|
+
const dataUrl = canvas.toDataURL("image/png");
|
|
15091
|
+
cleanup();
|
|
15092
|
+
resolve(dataUrl);
|
|
15093
|
+
} catch (e) {
|
|
15094
|
+
cleanup();
|
|
15095
|
+
resolve(null);
|
|
15096
|
+
}
|
|
15097
|
+
};
|
|
15098
|
+
img.onerror = () => {
|
|
15099
|
+
cleanup();
|
|
15100
|
+
resolve(null);
|
|
15101
|
+
};
|
|
15102
|
+
img.src = url;
|
|
15103
|
+
} catch {
|
|
15104
|
+
resolve(null);
|
|
15105
|
+
}
|
|
15106
|
+
});
|
|
15107
|
+
}
|
|
15108
|
+
let cachedFontFaceCss = null;
|
|
15109
|
+
function collectDocumentFontFaceCss() {
|
|
15110
|
+
if (cachedFontFaceCss !== null) return cachedFontFaceCss;
|
|
15111
|
+
const out = [];
|
|
15112
|
+
try {
|
|
15113
|
+
for (const sheet of Array.from(document.styleSheets)) {
|
|
15114
|
+
let rules = null;
|
|
15115
|
+
try {
|
|
15116
|
+
rules = sheet.cssRules;
|
|
15117
|
+
} catch {
|
|
15118
|
+
rules = null;
|
|
15119
|
+
}
|
|
15120
|
+
if (!rules) continue;
|
|
15121
|
+
for (const rule of Array.from(rules)) {
|
|
15122
|
+
const r = rule;
|
|
15123
|
+
if (r && (r.type === 5 || /@font-face/i.test(r.cssText || ""))) {
|
|
15124
|
+
if (r.cssText) out.push(r.cssText);
|
|
15125
|
+
}
|
|
15126
|
+
}
|
|
15127
|
+
}
|
|
15128
|
+
} catch {
|
|
15129
|
+
}
|
|
15130
|
+
cachedFontFaceCss = out.join("\n");
|
|
15131
|
+
return cachedFontFaceCss;
|
|
15132
|
+
}
|
|
15044
15133
|
async function prepareLiveCanvasSvgForPdf(rawSvg, pageWidth, pageHeight, pageKey, options) {
|
|
15045
15134
|
try {
|
|
15046
15135
|
const parser = new DOMParser();
|
|
@@ -15070,6 +15159,7 @@ async function prepareLiveCanvasSvgForPdf(rawSvg, pageWidth, pageHeight, pageKey
|
|
|
15070
15159
|
stripSuspiciousFullPageOverlayNodes(svgToDraw);
|
|
15071
15160
|
if (options == null ? void 0 : options.stripPageBackground) stripRootPageBackgroundFromSvg(svgToDraw);
|
|
15072
15161
|
sanitizeSvgTreeForPdf(svgToDraw);
|
|
15162
|
+
await rasterizeShadowMarkers(svgToDraw);
|
|
15073
15163
|
return svgToDraw;
|
|
15074
15164
|
} catch {
|
|
15075
15165
|
return null;
|