@pixldocs/canvas-renderer 0.5.192 → 0.5.194

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const index = require("./index-UIDDdWwb.cjs");
3
+ const index = require("./index-pshD8xMc.cjs");
4
4
  exports.DEPLOYMENT_VERSION_MARKER = index.DEPLOYMENT_VERSION_MARKER;
5
5
  exports.FONT_FALLBACK_DEVANAGARI = index.FONT_FALLBACK_DEVANAGARI;
6
6
  exports.FONT_FALLBACK_MATH = index.FONT_FALLBACK_MATH;
package/dist/index.d.ts CHANGED
@@ -648,20 +648,12 @@ export declare interface RendererConfig {
648
648
  /** Verbose asset-wait diagnostics. Default: false. */
649
649
  debug?: boolean;
650
650
  /**
651
- * PDF export: when `true`, always skip the live-canvas SVG → svg2pdf fast
652
- * path and use the per-element Fabric → jsPDF `addImage` path instead.
651
+ * PDF export: advanced override. When `true`, skip the live-canvas SVG →
652
+ * svg2pdf path and use the older per-element/config-space fallback.
653
653
  *
654
- * Why: on iOS / Safari the svg2pdf path internally rasterises embedded
655
- * `data:image/*` sources through a tainted offscreen canvas roundtrip and
656
- * silently drops large user-uploaded JPEGs from camera-roll pickers. The
657
- * per-element path goes straight from the live HTMLImageElement into
658
- * jsPDF.addImage and is reliable across browsers.
659
- *
660
- * Default: `'auto'` — on by default for any config containing a
661
- * `data:image/(jpeg|png|webp)` source when running on Safari / iOS;
662
- * off everywhere else so the editor's vector fast path stays in use.
663
- * Set to `true` to force on always (e.g. BioMaker), `false` to fully
664
- * disable the auto-detect.
654
+ * Default: `'auto'`, which keeps the live SVG path. BioMaker-style hosts
655
+ * should leave this unset/`'auto'`; `true` is only a manual escape hatch and
656
+ * can drift from the live Fabric layout for auto-shrink/crop-group templates.
665
657
  */
666
658
  forcePerElementPdf?: boolean | 'auto';
667
659
  /**
@@ -670,8 +662,8 @@ export declare interface RendererConfig {
670
662
  * images are JPEG-recompressed in-browser to fit. Prevents Safari from
671
663
  * silently failing to embed multi-megapixel camera-roll JPEGs.
672
664
  *
673
- * Default: `2048` when `forcePerElementPdf` is active, otherwise `0`
674
- * (no downscaling). Set explicitly to override either way.
665
+ * Default: `0` unless explicitly set. BioMaker-style PDF hosts should pass
666
+ * `2048` so large camera/gallery photos are normalized before mount.
675
667
  */
676
668
  maxImageEdgePx?: number;
677
669
  }
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { D, F, o, q, s, P, t, u, v, w, x, y, z, B, C, E, G, H, I, J, K, L, M, b, N, O, Q, R, S, U, V, W, X, Y, Z, _, $, a0, a1, a2, a3, a4, a5 } from "./index-CqgOWYwR.js";
1
+ import { D, F, o, q, s, P, t, u, v, w, x, y, z, B, C, E, G, H, I, J, K, L, M, b, N, O, Q, R, S, U, V, W, X, Y, Z, _, $, a0, a1, a2, a3, a4, a5 } from "./index-C1BrMJjh.js";
2
2
  export {
3
3
  D as DEPLOYMENT_VERSION_MARKER,
4
4
  F as FONT_FALLBACK_DEVANAGARI,
@@ -1,7 +1,7 @@
1
1
  import { jsPDF, ShadingPattern } from "jspdf";
2
2
  import { svg2pdf } from "svg2pdf.js";
3
3
  import * as fabric from "fabric";
4
- import { g as getCanvasForPage, c as captureFabricCanvasSvgForPdf, f as findNodeById, a as getAbsoluteBounds, p as parseTextMarkdown, r as renderSmartElementToSvg, n as normalizeShapeType, h as hasEdgeFade, b as getProxiedImageUrl, d as bakeEdgeFade, i as isElement, e as isGroup, j as buildRoundedTrianglePath, A as API_URL, k as getImageProxyFetchOptions, l as getRoundedRectRadii, T as TRIANGLE_STROKE_MITER_LIMIT, m as getTrianglePoints } from "./index-CqgOWYwR.js";
4
+ import { g as getCanvasForPage, c as captureFabricCanvasSvgForPdf, f as findNodeById, a as getAbsoluteBounds, p as parseTextMarkdown, r as renderSmartElementToSvg, n as normalizeShapeType, h as hasEdgeFade, b as getProxiedImageUrl, d as bakeEdgeFade, i as isElement, e as isGroup, j as buildRoundedTrianglePath, A as API_URL, k as getImageProxyFetchOptions, l as getRoundedRectRadii, T as TRIANGLE_STROKE_MITER_LIMIT, m as getTrianglePoints } from "./index-C1BrMJjh.js";
5
5
  import { resetPdfFontRegistry, FONT_FALLBACK_SYMBOLS, FONT_FALLBACK_MATH, FONT_FALLBACK_DEVANAGARI, embedFontWithGoogleFallback, getEmbeddedVariantsList, isFontAvailable, isFamilyEmbedded, resolveBestRegisteredVariant, getEmbeddedJsPDFFontName, resolveFontWeight, doesVariantSupportChar } from "./pdfFonts-DhEaMTZl.js";
6
6
  async function embedFontsForSvg(pdf, svgStr) {
7
7
  var _a;
@@ -449,7 +449,8 @@ function buildMatrixTransformedSvgForPage(svg, matrix, localX, localY, width, he
449
449
  frame: { x: minX, y: minY, width: frameW, height: frameH }
450
450
  };
451
451
  }
452
- async function svg2pdfWithDomMount(svg, pdf, opts) {
452
+ async function svg2pdfWithDomMount(svg, pdf, opts, options) {
453
+ await preloadSvgImagesForPdf(svg, options);
453
454
  const wrap = document.createElement("div");
454
455
  wrap.style.cssText = "position:fixed;left:-9999px;top:0;width:0;height:0;overflow:hidden;pointer-events:none;opacity:0";
455
456
  wrap.appendChild(svg);
@@ -461,6 +462,51 @@ async function svg2pdfWithDomMount(svg, pdf, opts) {
461
462
  if (wrap.parentNode) document.body.removeChild(wrap);
462
463
  }
463
464
  }
465
+ function getSvgImageHref(image) {
466
+ return image.getAttribute("href") || image.getAttribute("xlink:href") || "";
467
+ }
468
+ async function preloadSvgImagesForPdf(svg, options) {
469
+ const images = Array.from(svg.querySelectorAll("image"));
470
+ if (!images.length) return;
471
+ const required = new Set((options == null ? void 0 : options.requiredImageIds) ?? []);
472
+ const failedRequired = [];
473
+ const loadOne = (href) => new Promise((resolve) => {
474
+ if (!href) return resolve(false);
475
+ const img = new Image();
476
+ if (!href.startsWith("data:") && !href.startsWith("blob:")) img.crossOrigin = "anonymous";
477
+ const done = (ok) => resolve(ok);
478
+ img.onload = async () => {
479
+ try {
480
+ if (typeof img.decode === "function") await img.decode();
481
+ } catch {
482
+ }
483
+ done(img.naturalWidth > 0 && img.naturalHeight > 0);
484
+ };
485
+ img.onerror = () => done(false);
486
+ try {
487
+ img.src = href;
488
+ } catch {
489
+ done(false);
490
+ }
491
+ });
492
+ for (const image of images) {
493
+ const href = getSvgImageHref(image);
494
+ const id = image.getAttribute("data-pixldocs-image-id") || "";
495
+ const ok = await loadOne(href);
496
+ if (id && required.has(id) && !ok) failedRequired.push(id);
497
+ }
498
+ if (required.size > 0) {
499
+ const present = new Set(images.map((image) => image.getAttribute("data-pixldocs-image-id") || "").filter(Boolean));
500
+ const missing = [...required].filter((id) => !present.has(id));
501
+ if (missing.length || failedRequired.length) {
502
+ console.warn(
503
+ `[client-pdf-export] expected image(s) not ready for SVG PDF${(options == null ? void 0 : options.context) ? ` (${options.context})` : ""}: missing=${missing.join(",") || "none"} failed=${failedRequired.join(",") || "none"}`
504
+ );
505
+ } else {
506
+ console.log("[client-pdf-export] SVG image ids ready", { context: options == null ? void 0 : options.context, count: required.size, ids: [...required] });
507
+ }
508
+ }
509
+ }
464
510
  function resetPdfColorState(pdf, label) {
465
511
  pdf.setFillColor(0, 0, 0);
466
512
  pdf.setDrawColor(0, 0, 0);
@@ -2506,7 +2552,7 @@ async function fetchSvgAsElement(imageUrl, colorMap) {
2506
2552
  async function getRecoloredSvgDataUrl(imageUrl, colorMap) {
2507
2553
  if (!colorMap || Object.keys(colorMap).length === 0) return null;
2508
2554
  try {
2509
- const { getNormalizedSvgUrl } = await import("./index-CqgOWYwR.js").then((n) => n.a6);
2555
+ const { getNormalizedSvgUrl } = await import("./index-C1BrMJjh.js").then((n) => n.a6);
2510
2556
  return await getNormalizedSvgUrl(imageUrl, colorMap);
2511
2557
  } catch {
2512
2558
  return null;
@@ -3297,7 +3343,7 @@ async function fetchImageAsBase64(imageUrl, opts = {}) {
3297
3343
  }
3298
3344
  let fetchUrl = imageUrl;
3299
3345
  if (imageUrl.startsWith("http://") || imageUrl.startsWith("https://")) {
3300
- const { isPrivateUrl } = await import("./index-CqgOWYwR.js").then((n) => n.a6);
3346
+ const { isPrivateUrl } = await import("./index-C1BrMJjh.js").then((n) => n.a6);
3301
3347
  if (isPrivateUrl(imageUrl)) return null;
3302
3348
  const proxyUrl = new URL(`${API_URL}/image-proxy`);
3303
3349
  proxyUrl.searchParams.set("url", imageUrl);
@@ -4902,6 +4948,17 @@ function preparePagesForExport(pages, canvasWidth, canvasHeight, options) {
4902
4948
  };
4903
4949
  });
4904
4950
  }
4951
+ function getExpectedRasterImageIdsForPdfPage(page) {
4952
+ const ids = [];
4953
+ const isSvgUrl = (url) => /\.svg(?:\?|#|$)/i.test(url) || /^data:image\/svg/i.test(url);
4954
+ for (const item of page.elements) {
4955
+ if (isGroupBackgroundDrawable(item) || item.type !== "image" || item.visible === false) continue;
4956
+ const src = String(item.src || item.imageUrl || "").trim();
4957
+ if (!src || item.sourceFormat === "svg" || isSvgUrl(src)) continue;
4958
+ ids.push(item.id);
4959
+ }
4960
+ return [...new Set(ids)];
4961
+ }
4905
4962
  async function exportMultiPagePdf(pages, options) {
4906
4963
  var _a, _b, _c, _d, _e;
4907
4964
  const { filename = "document.pdf", title, watermark = false, returnBlob = false, pdfTextMode = "selectable", skipLiveCanvasSvgFastPath = false } = options;
@@ -5049,6 +5106,7 @@ async function exportMultiPagePdf(pages, options) {
5049
5106
  }
5050
5107
  const liveCanvasForPage = page.pageId ? getCanvasForPage(page.pageId) : null;
5051
5108
  let allowLiveCanvasFallback = !!liveCanvasForPage && !skipLiveCanvasSvgFastPath;
5109
+ const expectedRasterImageIds = getExpectedRasterImageIdsForPdfPage(page);
5052
5110
  if (liveCanvasForPage && !skipLiveCanvasSvgFastPath) {
5053
5111
  try {
5054
5112
  const liveSvgString = captureFabricCanvasSvgForPdf(
@@ -5091,7 +5149,8 @@ async function exportMultiPagePdf(pages, options) {
5091
5149
  await svg2pdfWithDomMount(
5092
5150
  liveSvg,
5093
5151
  pdfWithColorLogging(pdf, seq, `page-${pageIndex + 1}`),
5094
- svg2pdfOpts(0, 0, page.width, page.height)
5152
+ svg2pdfOpts(0, 0, page.width, page.height),
5153
+ { requiredImageIds: expectedRasterImageIds, context: `page-${pageIndex + 1}` }
5095
5154
  );
5096
5155
  debugLog(`live canvas svg2pdf DONE #${seq} page=${pageIndex + 1}`);
5097
5156
  resetPdfColorState(pdf, `after live canvas svg2pdf page ${pageIndex + 1}`);
@@ -5293,4 +5352,4 @@ export {
5293
5352
  preparePagesForExport,
5294
5353
  rewriteSvgFontsForJsPDFWithSourceMeta
5295
5354
  };
5296
- //# sourceMappingURL=vectorPdfExport-DuVMxQSS.js.map
5355
+ //# sourceMappingURL=vectorPdfExport-CuD_Ax0x.js.map