@pixldocs/canvas-renderer 0.5.45 → 0.5.47
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 -37
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +141 -37
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -4938,52 +4938,31 @@ 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
|
+
if (hasBg) {
|
|
4955
|
+
const shadowBgPath = `<path d="${bgD}" fill="${escapeXmlAttr(shadowColor)}" />`;
|
|
4956
|
+
bgShadowMarker = `<g class="__pdShadowRaster" ${dataAttrs}>${shadowBgPath}</g>`;
|
|
4957
|
+
}
|
|
4949
4958
|
const inner = extractGInnerMarkup(svg);
|
|
4950
4959
|
const recoloredText = recolorSvgFills(inner, shadowColor);
|
|
4951
|
-
|
|
4952
|
-
|
|
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
|
-
const ringCount = Math.min(6, Math.max(2, Math.round(blur / 2)));
|
|
4960
|
-
for (let i = 1; i <= ringCount; i++) {
|
|
4961
|
-
const t = i / ringCount;
|
|
4962
|
-
const dist = blur * t * 0.6;
|
|
4963
|
-
const op = (0.18 * (1 - t * 0.7)).toFixed(3);
|
|
4964
|
-
const ringOffsets = [
|
|
4965
|
-
[dist, 0],
|
|
4966
|
-
[-dist, 0],
|
|
4967
|
-
[0, dist],
|
|
4968
|
-
[0, -dist],
|
|
4969
|
-
[dist * 0.7, dist * 0.7],
|
|
4970
|
-
[-dist * 0.7, dist * 0.7],
|
|
4971
|
-
[dist * 0.7, -dist * 0.7],
|
|
4972
|
-
[-dist * 0.7, -dist * 0.7]
|
|
4973
|
-
];
|
|
4974
|
-
for (const [dx, dy] of ringOffsets) {
|
|
4975
|
-
pushShadowPass(ox + dx, oy + dy, op);
|
|
4976
|
-
}
|
|
4977
|
-
}
|
|
4978
|
-
pushShadowPass(ox, oy, "0.25");
|
|
4979
|
-
} else {
|
|
4980
|
-
pushShadowPass(ox, oy);
|
|
4960
|
+
if (recoloredText) {
|
|
4961
|
+
textShadowMarker = `<g class="__pdShadowRaster" ${dataAttrs}>${recoloredText}</g>`;
|
|
4981
4962
|
}
|
|
4982
|
-
bgShadowLayer = bgLayers.join("");
|
|
4983
|
-
textShadowLayer = textLayers.join("");
|
|
4984
4963
|
}
|
|
4985
4964
|
const openTagMatch = svg.match(/^\s*<g\b[^>]*>/);
|
|
4986
|
-
const inserted =
|
|
4965
|
+
const inserted = bgShadowMarker + bgPath + textShadowMarker;
|
|
4987
4966
|
if (openTagMatch) {
|
|
4988
4967
|
const openTag = openTagMatch[0];
|
|
4989
4968
|
return svg.replace(openTag, openTag + inserted);
|
|
@@ -12362,7 +12341,7 @@ function PixldocsPreview(props) {
|
|
|
12362
12341
|
!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..." }) })
|
|
12363
12342
|
] });
|
|
12364
12343
|
}
|
|
12365
|
-
const PACKAGE_VERSION = "0.5.
|
|
12344
|
+
const PACKAGE_VERSION = "0.5.47";
|
|
12366
12345
|
let __underlineFixInstalled = false;
|
|
12367
12346
|
function installUnderlineFix(fab) {
|
|
12368
12347
|
var _a;
|
|
@@ -15028,6 +15007,130 @@ async function convertTextDecorationsToLines(svg) {
|
|
|
15028
15007
|
}
|
|
15029
15008
|
}
|
|
15030
15009
|
}
|
|
15010
|
+
async function rasterizeShadowMarkers(svg) {
|
|
15011
|
+
var _a, _b, _c, _d, _e;
|
|
15012
|
+
if (typeof window === "undefined" || typeof document === "undefined") return;
|
|
15013
|
+
const markers = Array.from(svg.querySelectorAll("g.__pdShadowRaster"));
|
|
15014
|
+
if (markers.length === 0) return;
|
|
15015
|
+
const SVG_NS = "http://www.w3.org/2000/svg";
|
|
15016
|
+
const XLINK_NS = "http://www.w3.org/1999/xlink";
|
|
15017
|
+
try {
|
|
15018
|
+
if ((_a = document.fonts) == null ? void 0 : _a.ready) await document.fonts.ready;
|
|
15019
|
+
} catch {
|
|
15020
|
+
}
|
|
15021
|
+
const fontFaceCss = collectDocumentFontFaceCss();
|
|
15022
|
+
for (const marker of markers) {
|
|
15023
|
+
try {
|
|
15024
|
+
const blur = parseFloat(marker.getAttribute("data-blur") || "0");
|
|
15025
|
+
const ox = parseFloat(marker.getAttribute("data-ox") || "0");
|
|
15026
|
+
const oy = parseFloat(marker.getAttribute("data-oy") || "0");
|
|
15027
|
+
const bx = parseFloat(marker.getAttribute("data-bx") || "0");
|
|
15028
|
+
const by = parseFloat(marker.getAttribute("data-by") || "0");
|
|
15029
|
+
const bw = parseFloat(marker.getAttribute("data-bw") || "0");
|
|
15030
|
+
const bh = parseFloat(marker.getAttribute("data-bh") || "0");
|
|
15031
|
+
if (!Number.isFinite(bw) || !Number.isFinite(bh) || bw <= 0 || bh <= 0) {
|
|
15032
|
+
(_b = marker.parentNode) == null ? void 0 : _b.removeChild(marker);
|
|
15033
|
+
continue;
|
|
15034
|
+
}
|
|
15035
|
+
const innerXml = Array.from(marker.childNodes).map((n) => n instanceof Element ? new XMLSerializer().serializeToString(n) : "").join("");
|
|
15036
|
+
const scale = 2;
|
|
15037
|
+
const pxW = Math.min(4096, Math.max(8, Math.ceil(bw * scale)));
|
|
15038
|
+
const pxH = Math.min(4096, Math.max(8, Math.ceil(bh * scale)));
|
|
15039
|
+
const stdDev = Math.max(0, blur / 2);
|
|
15040
|
+
const filterId = `pdShadowBlur_${Math.random().toString(36).slice(2, 9)}`;
|
|
15041
|
+
const styleBlock = fontFaceCss ? `<style>${fontFaceCss}</style>` : "";
|
|
15042
|
+
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"><feGaussianBlur stdDeviation="${stdDev}" /></filter></defs><g filter="url(#${filterId})">${innerXml}</g></svg>`;
|
|
15043
|
+
const dataUrl = await rasterSvgToPngDataUrl(miniSvg, pxW, pxH);
|
|
15044
|
+
if (!dataUrl) {
|
|
15045
|
+
(_c = marker.parentNode) == null ? void 0 : _c.removeChild(marker);
|
|
15046
|
+
continue;
|
|
15047
|
+
}
|
|
15048
|
+
const img = svg.ownerDocument.createElementNS(SVG_NS, "image");
|
|
15049
|
+
img.setAttribute("x", String(bx + ox));
|
|
15050
|
+
img.setAttribute("y", String(by + oy));
|
|
15051
|
+
img.setAttribute("width", String(bw));
|
|
15052
|
+
img.setAttribute("height", String(bh));
|
|
15053
|
+
img.setAttribute("preserveAspectRatio", "none");
|
|
15054
|
+
img.setAttributeNS(XLINK_NS, "xlink:href", dataUrl);
|
|
15055
|
+
img.setAttribute("href", dataUrl);
|
|
15056
|
+
(_d = marker.parentNode) == null ? void 0 : _d.replaceChild(img, marker);
|
|
15057
|
+
} catch (e) {
|
|
15058
|
+
console.warn("[pdf-export] rasterizeShadowMarkers failed for one marker:", e);
|
|
15059
|
+
try {
|
|
15060
|
+
(_e = marker.parentNode) == null ? void 0 : _e.removeChild(marker);
|
|
15061
|
+
} catch {
|
|
15062
|
+
}
|
|
15063
|
+
}
|
|
15064
|
+
}
|
|
15065
|
+
}
|
|
15066
|
+
function rasterSvgToPngDataUrl(svgMarkup, pxW, pxH) {
|
|
15067
|
+
return new Promise((resolve) => {
|
|
15068
|
+
try {
|
|
15069
|
+
const blob = new Blob([svgMarkup], { type: "image/svg+xml;charset=utf-8" });
|
|
15070
|
+
const url = URL.createObjectURL(blob);
|
|
15071
|
+
const img = new Image();
|
|
15072
|
+
img.crossOrigin = "anonymous";
|
|
15073
|
+
const cleanup = () => {
|
|
15074
|
+
try {
|
|
15075
|
+
URL.revokeObjectURL(url);
|
|
15076
|
+
} catch {
|
|
15077
|
+
}
|
|
15078
|
+
};
|
|
15079
|
+
img.onload = () => {
|
|
15080
|
+
try {
|
|
15081
|
+
const canvas = document.createElement("canvas");
|
|
15082
|
+
canvas.width = pxW;
|
|
15083
|
+
canvas.height = pxH;
|
|
15084
|
+
const ctx = canvas.getContext("2d");
|
|
15085
|
+
if (!ctx) {
|
|
15086
|
+
cleanup();
|
|
15087
|
+
resolve(null);
|
|
15088
|
+
return;
|
|
15089
|
+
}
|
|
15090
|
+
ctx.drawImage(img, 0, 0, pxW, pxH);
|
|
15091
|
+
const dataUrl = canvas.toDataURL("image/png");
|
|
15092
|
+
cleanup();
|
|
15093
|
+
resolve(dataUrl);
|
|
15094
|
+
} catch (e) {
|
|
15095
|
+
cleanup();
|
|
15096
|
+
resolve(null);
|
|
15097
|
+
}
|
|
15098
|
+
};
|
|
15099
|
+
img.onerror = () => {
|
|
15100
|
+
cleanup();
|
|
15101
|
+
resolve(null);
|
|
15102
|
+
};
|
|
15103
|
+
img.src = url;
|
|
15104
|
+
} catch {
|
|
15105
|
+
resolve(null);
|
|
15106
|
+
}
|
|
15107
|
+
});
|
|
15108
|
+
}
|
|
15109
|
+
let cachedFontFaceCss = null;
|
|
15110
|
+
function collectDocumentFontFaceCss() {
|
|
15111
|
+
if (cachedFontFaceCss !== null) return cachedFontFaceCss;
|
|
15112
|
+
const out = [];
|
|
15113
|
+
try {
|
|
15114
|
+
for (const sheet of Array.from(document.styleSheets)) {
|
|
15115
|
+
let rules = null;
|
|
15116
|
+
try {
|
|
15117
|
+
rules = sheet.cssRules;
|
|
15118
|
+
} catch {
|
|
15119
|
+
rules = null;
|
|
15120
|
+
}
|
|
15121
|
+
if (!rules) continue;
|
|
15122
|
+
for (const rule of Array.from(rules)) {
|
|
15123
|
+
const r = rule;
|
|
15124
|
+
if (r && (r.type === 5 || /@font-face/i.test(r.cssText || ""))) {
|
|
15125
|
+
if (r.cssText) out.push(r.cssText);
|
|
15126
|
+
}
|
|
15127
|
+
}
|
|
15128
|
+
}
|
|
15129
|
+
} catch {
|
|
15130
|
+
}
|
|
15131
|
+
cachedFontFaceCss = out.join("\n");
|
|
15132
|
+
return cachedFontFaceCss;
|
|
15133
|
+
}
|
|
15031
15134
|
async function prepareLiveCanvasSvgForPdf(rawSvg, pageWidth, pageHeight, pageKey, options) {
|
|
15032
15135
|
try {
|
|
15033
15136
|
const parser = new DOMParser();
|
|
@@ -15057,6 +15160,7 @@ async function prepareLiveCanvasSvgForPdf(rawSvg, pageWidth, pageHeight, pageKey
|
|
|
15057
15160
|
stripSuspiciousFullPageOverlayNodes(svgToDraw);
|
|
15058
15161
|
if (options == null ? void 0 : options.stripPageBackground) stripRootPageBackgroundFromSvg(svgToDraw);
|
|
15059
15162
|
sanitizeSvgTreeForPdf(svgToDraw);
|
|
15163
|
+
await rasterizeShadowMarkers(svgToDraw);
|
|
15060
15164
|
return svgToDraw;
|
|
15061
15165
|
} catch {
|
|
15062
15166
|
return null;
|