@pixldocs/canvas-renderer 0.5.191 → 0.5.193

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-BJR7zaam.cjs");
3
+ const index = require("./index-uwKwubUL.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-C3kuDISv.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-CDoyeKa8.js";
2
2
  export {
3
3
  D as DEPLOYMENT_VERSION_MARKER,
4
4
  F as FONT_FALLBACK_DEVANAGARI,
@@ -3,7 +3,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const jspdf = require("jspdf");
4
4
  const svg2pdf_js = require("svg2pdf.js");
5
5
  const fabric = require("fabric");
6
- const index = require("./index-BJR7zaam.cjs");
6
+ const index = require("./index-uwKwubUL.cjs");
7
7
  const pdfFonts = require("./pdfFonts-BTj2f465.cjs");
8
8
  function _interopNamespaceDefault(e) {
9
9
  const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
@@ -468,7 +468,8 @@ function buildMatrixTransformedSvgForPage(svg, matrix, localX, localY, width, he
468
468
  frame: { x: minX, y: minY, width: frameW, height: frameH }
469
469
  };
470
470
  }
471
- async function svg2pdfWithDomMount(svg, pdf, opts) {
471
+ async function svg2pdfWithDomMount(svg, pdf, opts, options) {
472
+ await preloadSvgImagesForPdf(svg, options);
472
473
  const wrap = document.createElement("div");
473
474
  wrap.style.cssText = "position:fixed;left:-9999px;top:0;width:0;height:0;overflow:hidden;pointer-events:none;opacity:0";
474
475
  wrap.appendChild(svg);
@@ -480,6 +481,48 @@ async function svg2pdfWithDomMount(svg, pdf, opts) {
480
481
  if (wrap.parentNode) document.body.removeChild(wrap);
481
482
  }
482
483
  }
484
+ function getSvgImageHref(image) {
485
+ return image.getAttribute("href") || image.getAttribute("xlink:href") || "";
486
+ }
487
+ async function preloadSvgImagesForPdf(svg, options) {
488
+ const images = Array.from(svg.querySelectorAll("image"));
489
+ if (!images.length) return;
490
+ const required = new Set((options == null ? void 0 : options.requiredImageIds) ?? []);
491
+ const failedRequired = [];
492
+ const loadOne = (href) => new Promise((resolve) => {
493
+ if (!href) return resolve(false);
494
+ const img = new Image();
495
+ if (!href.startsWith("data:") && !href.startsWith("blob:")) img.crossOrigin = "anonymous";
496
+ const done = (ok) => resolve(ok);
497
+ img.onload = async () => {
498
+ try {
499
+ if (typeof img.decode === "function") await img.decode();
500
+ } catch {
501
+ }
502
+ done(img.naturalWidth > 0 && img.naturalHeight > 0);
503
+ };
504
+ img.onerror = () => done(false);
505
+ try {
506
+ img.src = href;
507
+ } catch {
508
+ done(false);
509
+ }
510
+ });
511
+ for (const image of images) {
512
+ const href = getSvgImageHref(image);
513
+ const id = image.getAttribute("data-pixldocs-image-id") || "";
514
+ const ok = await loadOne(href);
515
+ if (id && required.has(id) && !ok) failedRequired.push(id);
516
+ }
517
+ if (required.size > 0) {
518
+ const present = new Set(images.map((image) => image.getAttribute("data-pixldocs-image-id") || "").filter(Boolean));
519
+ const missing = [...required].filter((id) => !present.has(id));
520
+ if (missing.length || failedRequired.length) {
521
+ throw new Error(`[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"}`);
522
+ }
523
+ console.log("[client-pdf-export] SVG image ids ready", { context: options == null ? void 0 : options.context, count: required.size, ids: [...required] });
524
+ }
525
+ }
483
526
  function resetPdfColorState(pdf, label) {
484
527
  pdf.setFillColor(0, 0, 0);
485
528
  pdf.setDrawColor(0, 0, 0);
@@ -2525,7 +2568,7 @@ async function fetchSvgAsElement(imageUrl, colorMap) {
2525
2568
  async function getRecoloredSvgDataUrl(imageUrl, colorMap) {
2526
2569
  if (!colorMap || Object.keys(colorMap).length === 0) return null;
2527
2570
  try {
2528
- const { getNormalizedSvgUrl } = await Promise.resolve().then(() => require("./index-BJR7zaam.cjs")).then((n) => n.canvasImageLoader);
2571
+ const { getNormalizedSvgUrl } = await Promise.resolve().then(() => require("./index-uwKwubUL.cjs")).then((n) => n.canvasImageLoader);
2529
2572
  return await getNormalizedSvgUrl(imageUrl, colorMap);
2530
2573
  } catch {
2531
2574
  return null;
@@ -3316,7 +3359,7 @@ async function fetchImageAsBase64(imageUrl, opts = {}) {
3316
3359
  }
3317
3360
  let fetchUrl = imageUrl;
3318
3361
  if (imageUrl.startsWith("http://") || imageUrl.startsWith("https://")) {
3319
- const { isPrivateUrl } = await Promise.resolve().then(() => require("./index-BJR7zaam.cjs")).then((n) => n.canvasImageLoader);
3362
+ const { isPrivateUrl } = await Promise.resolve().then(() => require("./index-uwKwubUL.cjs")).then((n) => n.canvasImageLoader);
3320
3363
  if (isPrivateUrl(imageUrl)) return null;
3321
3364
  const proxyUrl = new URL(`${index.API_URL}/image-proxy`);
3322
3365
  proxyUrl.searchParams.set("url", imageUrl);
@@ -4921,6 +4964,17 @@ function preparePagesForExport(pages, canvasWidth, canvasHeight, options) {
4921
4964
  };
4922
4965
  });
4923
4966
  }
4967
+ function getExpectedRasterImageIdsForPdfPage(page) {
4968
+ const ids = [];
4969
+ const isSvgUrl = (url) => /\.svg(?:\?|#|$)/i.test(url) || /^data:image\/svg/i.test(url);
4970
+ for (const item of page.elements) {
4971
+ if (isGroupBackgroundDrawable(item) || item.type !== "image" || item.visible === false) continue;
4972
+ const src = String(item.src || item.imageUrl || "").trim();
4973
+ if (!src || item.sourceFormat === "svg" || isSvgUrl(src)) continue;
4974
+ ids.push(item.id);
4975
+ }
4976
+ return [...new Set(ids)];
4977
+ }
4924
4978
  async function exportMultiPagePdf(pages, options) {
4925
4979
  var _a, _b, _c, _d, _e;
4926
4980
  const { filename = "document.pdf", title, watermark = false, returnBlob = false, pdfTextMode = "selectable", skipLiveCanvasSvgFastPath = false } = options;
@@ -5068,6 +5122,7 @@ async function exportMultiPagePdf(pages, options) {
5068
5122
  }
5069
5123
  const liveCanvasForPage = page.pageId ? index.getCanvasForPage(page.pageId) : null;
5070
5124
  let allowLiveCanvasFallback = !!liveCanvasForPage && !skipLiveCanvasSvgFastPath;
5125
+ const expectedRasterImageIds = getExpectedRasterImageIdsForPdfPage(page);
5071
5126
  if (liveCanvasForPage && !skipLiveCanvasSvgFastPath) {
5072
5127
  try {
5073
5128
  const liveSvgString = index.captureFabricCanvasSvgForPdf(
@@ -5110,7 +5165,8 @@ async function exportMultiPagePdf(pages, options) {
5110
5165
  await svg2pdfWithDomMount(
5111
5166
  liveSvg,
5112
5167
  pdfWithColorLogging(pdf, seq, `page-${pageIndex + 1}`),
5113
- svg2pdfOpts(0, 0, page.width, page.height)
5168
+ svg2pdfOpts(0, 0, page.width, page.height),
5169
+ { requiredImageIds: expectedRasterImageIds, context: `page-${pageIndex + 1}` }
5114
5170
  );
5115
5171
  debugLog(`live canvas svg2pdf DONE #${seq} page=${pageIndex + 1}`);
5116
5172
  resetPdfColorState(pdf, `after live canvas svg2pdf page ${pageIndex + 1}`);
@@ -5124,6 +5180,9 @@ async function exportMultiPagePdf(pages, options) {
5124
5180
  svgLength: (liveSvgString == null ? void 0 : liveSvgString.length) ?? 0
5125
5181
  });
5126
5182
  } catch (error) {
5183
+ if (error instanceof Error && /expected image\(s\) not ready for SVG PDF/i.test(error.message)) {
5184
+ throw error;
5185
+ }
5127
5186
  allowLiveCanvasFallback = false;
5128
5187
  console.error(`[client-pdf-export] live SVG export failed for page ${pageIndex + 1}`, error);
5129
5188
  }
@@ -5310,4 +5369,4 @@ exports.exportMultiPagePdf = exportMultiPagePdf;
5310
5369
  exports.logTextMeasurementDiagnostic = logTextMeasurementDiagnostic;
5311
5370
  exports.preparePagesForExport = preparePagesForExport;
5312
5371
  exports.rewriteSvgFontsForJsPDFWithSourceMeta = rewriteSvgFontsForJsPDFWithSourceMeta;
5313
- //# sourceMappingURL=vectorPdfExport-D_2mdcwO.cjs.map
5372
+ //# sourceMappingURL=vectorPdfExport-BHKMcbVb.cjs.map