@pixldocs/canvas-renderer 0.5.112 → 0.5.114
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 +101 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +101 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -259,7 +259,7 @@ export declare function normalizeFontFamily(fontStack: string): string;
|
|
|
259
259
|
* Package version banner. Bump alongside package.json so we can confirm
|
|
260
260
|
* (via browser:log) that the deployed bundle matches the expected build.
|
|
261
261
|
*/
|
|
262
|
-
export declare const PACKAGE_VERSION = "0.5.
|
|
262
|
+
export declare const PACKAGE_VERSION = "0.5.114";
|
|
263
263
|
|
|
264
264
|
export declare interface PageSettings {
|
|
265
265
|
backgroundColor?: string;
|
|
@@ -305,7 +305,7 @@ export declare interface PdfFromFormOptions {
|
|
|
305
305
|
title?: string;
|
|
306
306
|
/** Base URL for TTF font files for PDF font embedding */
|
|
307
307
|
fontBaseUrl?: string;
|
|
308
|
-
/** PDF text rendering mode. Default:
|
|
308
|
+
/** PDF text rendering mode. Default: selectable text for client vector-PDF parity. */
|
|
309
309
|
textMode?: 'auto' | 'selectable' | 'pixel-perfect';
|
|
310
310
|
}
|
|
311
311
|
|
package/dist/index.js
CHANGED
|
@@ -13998,7 +13998,7 @@ function PixldocsPreview(props) {
|
|
|
13998
13998
|
!canvasSettled && /* @__PURE__ */ jsx("div", { style: { position: "absolute", inset: 0, display: "flex", alignItems: "center", justifyContent: "center", minHeight: 200 }, children: /* @__PURE__ */ jsx("div", { style: { color: "#888", fontSize: 14 }, children: "Loading preview..." }) })
|
|
13999
13999
|
] });
|
|
14000
14000
|
}
|
|
14001
|
-
const PACKAGE_VERSION = "0.5.
|
|
14001
|
+
const PACKAGE_VERSION = "0.5.114";
|
|
14002
14002
|
const roundParityValue = (value) => {
|
|
14003
14003
|
if (typeof value !== "number") return value;
|
|
14004
14004
|
return Number.isFinite(value) ? Number(value.toFixed(3)) : value;
|
|
@@ -14285,7 +14285,7 @@ class PixldocsRenderer {
|
|
|
14285
14285
|
async renderPdf(templateConfig, options) {
|
|
14286
14286
|
const svgs = await this.renderAllPageSvgs(templateConfig);
|
|
14287
14287
|
const { assemblePdfFromSvgs: assemblePdfFromSvgs2 } = await Promise.resolve().then(() => pdfExport);
|
|
14288
|
-
return assemblePdfFromSvgs2(svgs, { title: options == null ? void 0 : options.title, fontBaseUrl: options == null ? void 0 : options.fontBaseUrl, textMode: (options == null ? void 0 : options.textMode) ?? "
|
|
14288
|
+
return assemblePdfFromSvgs2(svgs, { title: options == null ? void 0 : options.title, fontBaseUrl: options == null ? void 0 : options.fontBaseUrl, textMode: (options == null ? void 0 : options.textMode) ?? "selectable" });
|
|
14289
14289
|
}
|
|
14290
14290
|
/**
|
|
14291
14291
|
* Resolve from V2 sectionState and render a vector PDF.
|
|
@@ -14310,7 +14310,7 @@ class PixldocsRenderer {
|
|
|
14310
14310
|
}
|
|
14311
14311
|
const svgs = await this.renderAllPageSvgs(configToRender);
|
|
14312
14312
|
const { assemblePdfFromSvgs: assemblePdfFromSvgs2 } = await Promise.resolve().then(() => pdfExport);
|
|
14313
|
-
return assemblePdfFromSvgs2(svgs, { title: title ?? resolved.config.name, fontBaseUrl, textMode: options.textMode ?? "
|
|
14313
|
+
return assemblePdfFromSvgs2(svgs, { title: title ?? resolved.config.name, fontBaseUrl, textMode: options.textMode ?? "selectable" });
|
|
14314
14314
|
}
|
|
14315
14315
|
async renderById(templateId, formData, options) {
|
|
14316
14316
|
const resolved = await resolveTemplateData({
|
|
@@ -15716,6 +15716,9 @@ const remoteVariantKey = (family, weight, isItalic) => `${family}|${resolveFontW
|
|
|
15716
15716
|
const registeredVariants = /* @__PURE__ */ new Set();
|
|
15717
15717
|
const registeredVariantCoverage = /* @__PURE__ */ new Map();
|
|
15718
15718
|
const variantKey = (family, weight, italic) => `${family}|${resolveFontWeight(weight)}|${italic ? "i" : "n"}`;
|
|
15719
|
+
function isVariantEmbedded(family, weight, italic) {
|
|
15720
|
+
return registeredVariants.has(variantKey(family, weight, italic));
|
|
15721
|
+
}
|
|
15719
15722
|
const resolveBestRegisteredVariant = (family, weight, italic) => {
|
|
15720
15723
|
const want = resolveFontWeight(weight);
|
|
15721
15724
|
const weights = [300, 400, 500, 600, 700];
|
|
@@ -16203,6 +16206,88 @@ function extractFontFamiliesFromSvgs(svgs) {
|
|
|
16203
16206
|
}
|
|
16204
16207
|
return families;
|
|
16205
16208
|
}
|
|
16209
|
+
async function embedFontVariantsFromSvg(pdf, svgStr, fontBaseUrl) {
|
|
16210
|
+
var _a;
|
|
16211
|
+
const parser = new DOMParser();
|
|
16212
|
+
const doc = parser.parseFromString(svgStr, "image/svg+xml");
|
|
16213
|
+
const textEls = Array.from(doc.querySelectorAll("text, tspan, textPath"));
|
|
16214
|
+
const readStyleToken = (style, prop) => {
|
|
16215
|
+
var _a2;
|
|
16216
|
+
const m = style.match(new RegExp(`${prop}\\s*:\\s*([^;]+)`, "i"));
|
|
16217
|
+
return ((_a2 = m == null ? void 0 : m[1]) == null ? void 0 : _a2.trim()) || null;
|
|
16218
|
+
};
|
|
16219
|
+
const resolveInherited = (el, attr, styleProp = attr) => {
|
|
16220
|
+
var _a2;
|
|
16221
|
+
let cur = el;
|
|
16222
|
+
while (cur) {
|
|
16223
|
+
const a = (_a2 = cur.getAttribute(attr)) == null ? void 0 : _a2.trim();
|
|
16224
|
+
if (a) return a;
|
|
16225
|
+
const s = readStyleToken(cur.getAttribute("style") || "", styleProp);
|
|
16226
|
+
if (s) return s;
|
|
16227
|
+
cur = cur.parentElement;
|
|
16228
|
+
}
|
|
16229
|
+
return null;
|
|
16230
|
+
};
|
|
16231
|
+
const parseWeight = (raw) => {
|
|
16232
|
+
const n = Number.parseInt(raw, 10);
|
|
16233
|
+
if (Number.isFinite(n)) return n;
|
|
16234
|
+
const s = raw.toLowerCase();
|
|
16235
|
+
if (/bold/.test(s)) return 700;
|
|
16236
|
+
if (/semi|demi/.test(s)) return 600;
|
|
16237
|
+
if (/medium/.test(s)) return 500;
|
|
16238
|
+
if (/light|thin/.test(s)) return 300;
|
|
16239
|
+
return 400;
|
|
16240
|
+
};
|
|
16241
|
+
const needed = /* @__PURE__ */ new Map();
|
|
16242
|
+
for (const el of textEls) {
|
|
16243
|
+
const rawFf = resolveInherited(el, "font-family");
|
|
16244
|
+
if (!rawFf) continue;
|
|
16245
|
+
const family = (_a = rawFf.split(",")[0]) == null ? void 0 : _a.replace(/['"]/g, "").trim();
|
|
16246
|
+
if (!family) continue;
|
|
16247
|
+
const weight = resolveFontWeight(parseWeight(resolveInherited(el, "font-weight") || "400"));
|
|
16248
|
+
const italic = /italic|oblique/i.test(resolveInherited(el, "font-style") || "normal");
|
|
16249
|
+
const key = `${family}${weight}${italic ? "i" : "n"}`;
|
|
16250
|
+
if (!needed.has(key)) needed.set(key, { family, weight, italic });
|
|
16251
|
+
}
|
|
16252
|
+
let embedded = 0;
|
|
16253
|
+
for (const { family, weight, italic } of needed.values()) {
|
|
16254
|
+
if (isVariantEmbedded(family, weight, italic)) continue;
|
|
16255
|
+
await embedFontWithGoogleFallback(pdf, family, weight, fontBaseUrl, italic);
|
|
16256
|
+
if (isVariantEmbedded(family, weight, italic)) embedded++;
|
|
16257
|
+
}
|
|
16258
|
+
const fallbacks = [
|
|
16259
|
+
{ family: FONT_FALLBACK_SYMBOLS, weight: 400 },
|
|
16260
|
+
{ family: FONT_FALLBACK_MATH, weight: 400 }
|
|
16261
|
+
];
|
|
16262
|
+
for (const w of [300, 400, 500, 600, 700]) {
|
|
16263
|
+
fallbacks.push({ family: FONT_FALLBACK_DEVANAGARI, weight: w });
|
|
16264
|
+
}
|
|
16265
|
+
for (const { family, weight } of fallbacks) {
|
|
16266
|
+
if (isVariantEmbedded(family, weight, false)) continue;
|
|
16267
|
+
await embedFontWithGoogleFallback(pdf, family, weight, fontBaseUrl, false);
|
|
16268
|
+
if (isVariantEmbedded(family, weight, false)) embedded++;
|
|
16269
|
+
}
|
|
16270
|
+
for (const { family, weight, italic } of needed.values()) {
|
|
16271
|
+
if (!italic) continue;
|
|
16272
|
+
if (!isVariantEmbedded(family, weight, false)) {
|
|
16273
|
+
await embedFontWithGoogleFallback(pdf, family, weight, fontBaseUrl, false);
|
|
16274
|
+
if (isVariantEmbedded(family, weight, false)) embedded++;
|
|
16275
|
+
}
|
|
16276
|
+
if (!isVariantEmbedded(family, 400, false)) {
|
|
16277
|
+
await embedFontWithGoogleFallback(pdf, family, 400, fontBaseUrl, false);
|
|
16278
|
+
if (isVariantEmbedded(family, 400, false)) embedded++;
|
|
16279
|
+
}
|
|
16280
|
+
if (weight <= 400) continue;
|
|
16281
|
+
if (isVariantEmbedded(family, 400, true)) continue;
|
|
16282
|
+
await embedFontWithGoogleFallback(pdf, family, 400, fontBaseUrl, true);
|
|
16283
|
+
if (isVariantEmbedded(family, 400, true)) embedded++;
|
|
16284
|
+
}
|
|
16285
|
+
console.log("[pdf-fonts] embedFontVariantsFromSvg", {
|
|
16286
|
+
requested: needed.size,
|
|
16287
|
+
newlyEmbedded: embedded
|
|
16288
|
+
});
|
|
16289
|
+
return embedded;
|
|
16290
|
+
}
|
|
16206
16291
|
async function embedFontsInPdf(pdf, fontFamilies, fontBaseUrl) {
|
|
16207
16292
|
const embedded = /* @__PURE__ */ new Set();
|
|
16208
16293
|
const weights = [300, 400, 500, 600, 700];
|
|
@@ -16254,6 +16339,7 @@ const pdfFonts = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProp
|
|
|
16254
16339
|
FONT_FILES,
|
|
16255
16340
|
FONT_WEIGHT_LABELS,
|
|
16256
16341
|
embedFont,
|
|
16342
|
+
embedFontVariantsFromSvg,
|
|
16257
16343
|
embedFontWithGoogleFallback,
|
|
16258
16344
|
embedFontsForConfig,
|
|
16259
16345
|
embedFontsInPdf,
|
|
@@ -16261,6 +16347,7 @@ const pdfFonts = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProp
|
|
|
16261
16347
|
getEmbeddedJsPDFFontName,
|
|
16262
16348
|
getFontPathForWeight,
|
|
16263
16349
|
isFontAvailable,
|
|
16350
|
+
isVariantEmbedded,
|
|
16264
16351
|
resolveBestRegisteredVariant,
|
|
16265
16352
|
resolveFontWeight,
|
|
16266
16353
|
rewriteSvgFontsForJsPDF
|
|
@@ -17767,7 +17854,17 @@ async function assemblePdfFromSvgs(svgResults, options = {}) {
|
|
|
17767
17854
|
} catch {
|
|
17768
17855
|
}
|
|
17769
17856
|
await convertTextDecorationsToLines(processedSvg);
|
|
17770
|
-
const
|
|
17857
|
+
const liveSvgStr = new XMLSerializer().serializeToString(processedSvg);
|
|
17858
|
+
try {
|
|
17859
|
+
const { embedFontVariantsFromSvg: embedFontVariantsFromSvg2 } = await Promise.resolve().then(() => pdfFonts);
|
|
17860
|
+
await embedFontVariantsFromSvg2(pdf, liveSvgStr, fontBaseUrl);
|
|
17861
|
+
} catch (embedErr) {
|
|
17862
|
+
console.warn(
|
|
17863
|
+
"[canvas-renderer][pdf] embedFontVariantsFromSvg failed (page " + (i + 1) + "):",
|
|
17864
|
+
embedErr
|
|
17865
|
+
);
|
|
17866
|
+
}
|
|
17867
|
+
const rewrittenSvg = rewriteSvgFontsForJsPDF(liveSvgStr);
|
|
17771
17868
|
const reParser = new DOMParser();
|
|
17772
17869
|
const reDoc = reParser.parseFromString(rewrittenSvg, "image/svg+xml");
|
|
17773
17870
|
processedSvg = reDoc.documentElement;
|