@pixldocs/canvas-renderer 0.5.81 → 0.5.82

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.d.ts CHANGED
@@ -276,6 +276,14 @@ export declare interface PdfAssemblyOptions {
276
276
  fontBaseUrl?: string;
277
277
  /** Convert SVG text to paths before svg2pdf. Default: false — keep live Fabric SVG text for preview/PDF metric parity. */
278
278
  outlineText?: boolean;
279
+ /**
280
+ * Per-template text rendering mode.
281
+ * - 'auto' : outline only complex scripts (Indic/Arabic/CJK/emoji); Latin stays selectable.
282
+ * - 'selectable' : never outline; all text remains real selectable text in the PDF.
283
+ * - 'pixel-perfect' : outline every <text> for 100% font parity.
284
+ * When omitted, falls back to `outlineText` (legacy boolean) for backwards compatibility.
285
+ */
286
+ textMode?: 'auto' | 'selectable' | 'pixel-perfect';
279
287
  }
280
288
 
281
289
  /** Options for PDF rendering */
@@ -294,6 +302,8 @@ export declare interface PdfFromFormOptions {
294
302
  title?: string;
295
303
  /** Base URL for TTF font files for PDF font embedding */
296
304
  fontBaseUrl?: string;
305
+ /** PDF text rendering mode. Default: selectable real text. */
306
+ textMode?: 'auto' | 'selectable' | 'pixel-perfect';
297
307
  }
298
308
 
299
309
  export declare interface PdfRenderResult {
@@ -403,6 +413,7 @@ export declare class PixldocsRenderer {
403
413
  renderPdf(templateConfig: TemplateConfig, options?: {
404
414
  title?: string;
405
415
  fontBaseUrl?: string;
416
+ textMode?: 'auto' | 'selectable' | 'pixel-perfect';
406
417
  }): Promise<PdfRenderResult>;
407
418
  /**
408
419
  * Resolve from V2 sectionState and render a vector PDF.
@@ -669,6 +680,8 @@ export declare interface TemplateConfig {
669
680
  dynamicFields?: DynamicField[];
670
681
  fieldGroups?: any[];
671
682
  themeConfig?: ThemeConfig;
683
+ /** PDF text rendering mode. Default: selectable real text. */
684
+ pdfTextMode?: 'auto' | 'selectable' | 'pixel-perfect';
672
685
  formBindingMode?: string;
673
686
  boundFormDefId?: string;
674
687
  boundFormDefName?: string;
package/dist/index.js CHANGED
@@ -12865,7 +12865,7 @@ class PixldocsRenderer {
12865
12865
  async renderPdf(templateConfig, options) {
12866
12866
  const svgs = await this.renderAllPageSvgs(templateConfig);
12867
12867
  const { assemblePdfFromSvgs: assemblePdfFromSvgs2 } = await Promise.resolve().then(() => pdfExport);
12868
- return assemblePdfFromSvgs2(svgs, { title: options == null ? void 0 : options.title, fontBaseUrl: options == null ? void 0 : options.fontBaseUrl });
12868
+ return assemblePdfFromSvgs2(svgs, { title: options == null ? void 0 : options.title, fontBaseUrl: options == null ? void 0 : options.fontBaseUrl, textMode: (options == null ? void 0 : options.textMode) ?? templateConfig.pdfTextMode ?? "selectable" });
12869
12869
  }
12870
12870
  /**
12871
12871
  * Resolve from V2 sectionState and render a vector PDF.
@@ -12890,7 +12890,7 @@ class PixldocsRenderer {
12890
12890
  }
12891
12891
  const svgs = await this.renderAllPageSvgs(configToRender);
12892
12892
  const { assemblePdfFromSvgs: assemblePdfFromSvgs2 } = await Promise.resolve().then(() => pdfExport);
12893
- return assemblePdfFromSvgs2(svgs, { title: title ?? resolved.config.name, fontBaseUrl });
12893
+ return assemblePdfFromSvgs2(svgs, { title: title ?? resolved.config.name, fontBaseUrl, textMode: options.textMode ?? configToRender.pdfTextMode ?? "selectable" });
12894
12894
  }
12895
12895
  async renderById(templateId, formData, options) {
12896
12896
  const resolved = await resolveTemplateData({
@@ -14140,10 +14140,22 @@ async function embedFont(pdf, fontName, weight, fontBaseUrl, isItalic = false) {
14140
14140
  async function embedFontsForConfig(pdf, config, fontBaseUrl) {
14141
14141
  const fontKeys = /* @__PURE__ */ new Set();
14142
14142
  const SEP = "";
14143
+ const normalizeWeight = (raw) => {
14144
+ if (raw == null) return 400;
14145
+ if (typeof raw === "number" && Number.isFinite(raw)) return resolveFontWeight(raw);
14146
+ const str = String(raw).trim().toLowerCase();
14147
+ const parsed = Number.parseInt(str, 10);
14148
+ if (Number.isFinite(parsed)) return resolveFontWeight(parsed);
14149
+ if (str === "bold" || str === "bolder") return 700;
14150
+ if (str === "semibold" || str === "demibold") return 600;
14151
+ if (str === "medium") return 500;
14152
+ if (str === "light" || str === "lighter" || str === "thin") return 300;
14153
+ return 400;
14154
+ };
14143
14155
  const walkElements = (elements) => {
14144
14156
  for (const el of elements) {
14145
14157
  if (el.fontFamily) {
14146
- const w = resolveFontWeight(el.fontWeight ?? 400);
14158
+ const w = normalizeWeight(el.fontWeight);
14147
14159
  fontKeys.add(`${el.fontFamily}${SEP}${w}`);
14148
14160
  }
14149
14161
  if (el.styles && typeof el.styles === "object") {
@@ -14153,7 +14165,7 @@ async function embedFontsForConfig(pdf, config, fontBaseUrl) {
14153
14165
  for (const charKey of Object.keys(lineStyles)) {
14154
14166
  const s = lineStyles[charKey];
14155
14167
  if (s == null ? void 0 : s.fontFamily) {
14156
- const w = resolveFontWeight(s.fontWeight ?? 400);
14168
+ const w = normalizeWeight(s.fontWeight);
14157
14169
  fontKeys.add(`${s.fontFamily}${SEP}${w}`);
14158
14170
  }
14159
14171
  }
@@ -15788,7 +15800,9 @@ async function assemblePdfFromSvgs(svgResults, options = {}) {
15788
15800
  const hasGradient = !!((_b = (_a = page.backgroundGradient) == null ? void 0 : _a.stops) == null ? void 0 : _b.length);
15789
15801
  drawPageBackground(pdf, i, page.width, page.height, page.backgroundColor, page.backgroundGradient);
15790
15802
  const shouldStripBg = stripPageBackground ?? hasGradient;
15791
- const shouldOutlineText = options.outlineText !== false;
15803
+ const textMode = options.textMode ?? (options.outlineText ? "pixel-perfect" : "selectable");
15804
+ const shouldOutlineText = textMode === "pixel-perfect" || textMode === "auto";
15805
+ const outlineSubMode = textMode === "auto" ? "complex-only" : "all";
15792
15806
  let pageSvg = page.svg;
15793
15807
  try {
15794
15808
  pageSvg = await convertSvgTextDecorationsToLinesString(pageSvg);
@@ -15800,8 +15814,8 @@ async function assemblePdfFromSvgs(svgResults, options = {}) {
15800
15814
  }
15801
15815
  if (shouldOutlineText) {
15802
15816
  try {
15803
- const { convertAllTextToPath } = await import("./svgTextToPath-BP0Kppla.js");
15804
- pageSvg = await convertAllTextToPath(pageSvg, fontBaseUrl);
15817
+ const { convertAllTextToPath } = await import("./svgTextToPath-B5sT7sre.js");
15818
+ pageSvg = await convertAllTextToPath(pageSvg, fontBaseUrl, { mode: outlineSubMode });
15805
15819
  try {
15806
15820
  dumpSvgTextDiagnostics(pageSvg, i, PARITY_TAG, "STAGE-1b-after-text-to-path-raw");
15807
15821
  } catch {