@pixldocs/canvas-renderer 0.5.194 → 0.5.196

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.
@@ -16919,9 +16919,9 @@ function captureFabricCanvasSvgForPdf(fabricInstance, canvasWidth, canvasHeight)
16919
16919
  }
16920
16920
  return svgString;
16921
16921
  }
16922
- const resolvedPackageVersion = "0.5.194";
16922
+ const resolvedPackageVersion = "0.5.196";
16923
16923
  const PACKAGE_VERSION = resolvedPackageVersion;
16924
- const DEPLOYMENT_VERSION_MARKER = "__PIXLDOCS_CANVAS_RENDERER_VERSION__:0.5.194";
16924
+ const DEPLOYMENT_VERSION_MARKER = "__PIXLDOCS_CANVAS_RENDERER_VERSION__:0.5.196";
16925
16925
  const roundParityValue = (value) => {
16926
16926
  if (typeof value !== "number") return value;
16927
16927
  return Number.isFinite(value) ? Number(value.toFixed(3)) : value;
@@ -16981,11 +16981,16 @@ function detectSafariOrIos() {
16981
16981
  return false;
16982
16982
  }
16983
16983
  }
16984
- async function downscaleConfigRasterImages(config, maxEdgePx) {
16984
+ async function downscaleConfigRasterImages(config, maxEdgePx, maxDataUrlBytes = 2e6) {
16985
16985
  if (!maxEdgePx || maxEdgePx <= 0) return 0;
16986
16986
  if (typeof document === "undefined") return 0;
16987
16987
  const targets = [];
16988
16988
  const isRasterDataUrl = (u) => typeof u === "string" && /^data:image\/(jpeg|jpg|png|webp)[;,]/i.test(u);
16989
+ const estimateDataUrlBytes = (u) => {
16990
+ const comma = u.indexOf(",");
16991
+ const payload = comma >= 0 ? u.slice(comma + 1) : u;
16992
+ return Math.floor(payload.length * 0.75);
16993
+ };
16989
16994
  const walk = (nodes) => {
16990
16995
  if (!Array.isArray(nodes)) return;
16991
16996
  for (const node of nodes) {
@@ -17011,28 +17016,43 @@ async function downscaleConfigRasterImages(config, maxEdgePx) {
17011
17016
  const w = img.naturalWidth, h = img.naturalHeight;
17012
17017
  if (!w || !h) return null;
17013
17018
  const longest = Math.max(w, h);
17014
- if (longest <= maxEdgePx) return null;
17015
- const scale = maxEdgePx / longest;
17016
- const tw = Math.max(1, Math.round(w * scale));
17017
- const th = Math.max(1, Math.round(h * scale));
17018
- const canvas = document.createElement("canvas");
17019
- canvas.width = tw;
17020
- canvas.height = th;
17021
- const ctx = canvas.getContext("2d");
17022
- if (!ctx) return null;
17023
- ctx.fillStyle = "#ffffff";
17024
- ctx.fillRect(0, 0, tw, th);
17025
- ctx.drawImage(img, 0, 0, tw, th);
17026
- return canvas.toDataURL("image/jpeg", 0.85);
17019
+ const tooLargeByEdge = longest > maxEdgePx;
17020
+ const tooLargeByBytes = estimateDataUrlBytes(dataUrl) > maxDataUrlBytes;
17021
+ if (!tooLargeByEdge && !tooLargeByBytes) return null;
17022
+ let scale = tooLargeByEdge ? maxEdgePx / longest : 1;
17023
+ let quality = 0.85;
17024
+ let best = null;
17025
+ for (let attempt = 0; attempt < 4; attempt++) {
17026
+ const tw = Math.max(1, Math.round(w * scale));
17027
+ const th = Math.max(1, Math.round(h * scale));
17028
+ const canvas = document.createElement("canvas");
17029
+ canvas.width = tw;
17030
+ canvas.height = th;
17031
+ const ctx = canvas.getContext("2d");
17032
+ if (!ctx) return best;
17033
+ ctx.fillStyle = "#ffffff";
17034
+ ctx.fillRect(0, 0, tw, th);
17035
+ ctx.drawImage(img, 0, 0, tw, th);
17036
+ best = canvas.toDataURL("image/jpeg", quality);
17037
+ const outBytes = estimateDataUrlBytes(best);
17038
+ if (outBytes <= maxDataUrlBytes || attempt === 3) return best;
17039
+ const byteScale = Math.sqrt(maxDataUrlBytes / Math.max(1, outBytes)) * 0.92;
17040
+ scale = Math.max(0.1, scale * Math.min(0.95, byteScale));
17041
+ quality = Math.max(0.68, quality - 0.06);
17042
+ }
17043
+ return best;
17027
17044
  } catch {
17028
17045
  return null;
17029
17046
  }
17030
17047
  };
17031
17048
  let shrunk = 0;
17032
17049
  for (const { node, field } of targets) {
17050
+ const before = String(node[field]);
17033
17051
  const next = await shrinkOne(String(node[field]));
17034
17052
  if (next) {
17035
17053
  node[field] = next;
17054
+ const twin = field === "src" ? "imageUrl" : "src";
17055
+ if (node[twin] === before) node[twin] = next;
17036
17056
  shrunk++;
17037
17057
  }
17038
17058
  }
@@ -17471,7 +17491,7 @@ class PixldocsRenderer {
17471
17491
  const isSafariLike = detectSafariOrIos();
17472
17492
  const shouldForcePerElement = forceMode === true ? true : forceMode === false ? false : hasUserDataImage && isSafariLike;
17473
17493
  const maxEdgeOpt = options.maxImageEdgePx ?? this.config.maxImageEdgePx;
17474
- const effectiveMaxEdge = typeof maxEdgeOpt === "number" ? Math.max(0, maxEdgeOpt | 0) : shouldForcePerElement ? 2048 : 0;
17494
+ const effectiveMaxEdge = typeof maxEdgeOpt === "number" ? Math.max(0, maxEdgeOpt | 0) : hasUserDataImage ? 2048 : 0;
17475
17495
  if (effectiveMaxEdge > 0) {
17476
17496
  try {
17477
17497
  const downscaled = await downscaleConfigRasterImages(cloned, effectiveMaxEdge);
@@ -17548,7 +17568,7 @@ class PixldocsRenderer {
17548
17568
  await this.waitForCanvasScene(container, cloned, i);
17549
17569
  }
17550
17570
  console.log(`[canvas-renderer][pdf-unified] mounted ${cloned.pages.length} page(s), handing off to client exportMultiPagePdf`);
17551
- const { exportMultiPagePdf, preparePagesForExport } = await import("./vectorPdfExport-CuD_Ax0x.js");
17571
+ const { exportMultiPagePdf, preparePagesForExport } = await import("./vectorPdfExport-BBQHeFKb.js");
17552
17572
  const prepared = preparePagesForExport(
17553
17573
  cloned.pages,
17554
17574
  canvasWidth,
@@ -17570,11 +17590,10 @@ class PixldocsRenderer {
17570
17590
  // correct. v0.5.191 shipped with this skip enabled and produced exactly
17571
17591
  // that regression.
17572
17592
  //
17573
- // The Safari/iOS "missing photo" issue is solved end-to-end by the
17574
- // `downscaleConfigRasterImages()` pre-pass above, which shrinks large
17575
- // `data:image/*` JPEGs to a safe edge length before the canvas mounts.
17576
- // That alone keeps Safari's SVG capture reliable without altering the
17577
- // layout pipeline.
17593
+ // The large-photo missing/corrupt image issue is solved by the
17594
+ // `downscaleConfigRasterImages()` pre-pass above, which shrinks and
17595
+ // recompresses oversized `data:image/*` sources before the canvas
17596
+ // mounts. That keeps SVG capture reliable without altering layout.
17578
17597
  //
17579
17598
  // We still honor an explicit `forcePerElementPdf: true` from the host
17580
17599
  // app (advanced opt-in for niche cases), but the auto path no longer
@@ -17763,8 +17782,9 @@ class PixldocsRenderer {
17763
17782
  console.warn("[canvas-renderer][asset-wait-timeout][dom-images]", domImageDebug);
17764
17783
  console.warn("[canvas-renderer][asset-wait-timeout][fabric-images]", fabricImageDebug);
17765
17784
  if (strictById && missingImageIds.length > 0) {
17766
- reject(new Error(`[canvas-renderer][asset-wait-timeout] Missing expected image(s): ${missingImageIds.join(", ")}`));
17767
- return;
17785
+ console.warn(
17786
+ `[canvas-renderer][asset-wait-timeout] Missing expected image(s) — continuing with partial set: ${missingImageIds.join(", ")}`
17787
+ );
17768
17788
  }
17769
17789
  settle();
17770
17790
  return;
@@ -19745,7 +19765,7 @@ async function prepareLiveCanvasSvgForPdf(rawSvg, pageWidth, pageHeight, pageKey
19745
19765
  if (options == null ? void 0 : options.stripPageBackground) stripRootPageBackgroundFromSvg(svgToDraw);
19746
19766
  sanitizeSvgTreeForPdf(svgToDraw);
19747
19767
  try {
19748
- const { bakeTextAnchorPositionsFromLiveSvg, logTextMeasurementDiagnostic } = await import("./vectorPdfExport-CuD_Ax0x.js");
19768
+ const { bakeTextAnchorPositionsFromLiveSvg, logTextMeasurementDiagnostic } = await import("./vectorPdfExport-BBQHeFKb.js");
19749
19769
  try {
19750
19770
  await logTextMeasurementDiagnostic(svgToDraw);
19751
19771
  } catch {
@@ -20145,4 +20165,4 @@ export {
20145
20165
  buildTeaserBlurFlatKeys as y,
20146
20166
  collectFontDescriptorsFromConfig as z
20147
20167
  };
20148
- //# sourceMappingURL=index-C1BrMJjh.js.map
20168
+ //# sourceMappingURL=index-KqyAyv91.js.map