@pixldocs/canvas-renderer 0.5.113 → 0.5.115

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
@@ -14017,7 +14017,7 @@ function PixldocsPreview(props) {
14017
14017
  !canvasSettled && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { position: "absolute", inset: 0, display: "flex", alignItems: "center", justifyContent: "center", minHeight: 200 }, children: /* @__PURE__ */ jsxRuntime.jsx("div", { style: { color: "#888", fontSize: 14 }, children: "Loading preview..." }) })
14018
14018
  ] });
14019
14019
  }
14020
- const PACKAGE_VERSION = "0.5.113";
14020
+ const PACKAGE_VERSION = "0.5.115";
14021
14021
  const roundParityValue = (value) => {
14022
14022
  if (typeof value !== "number") return value;
14023
14023
  return Number.isFinite(value) ? Number(value.toFixed(3)) : value;
@@ -15735,6 +15735,9 @@ const remoteVariantKey = (family, weight, isItalic) => `${family}|${resolveFontW
15735
15735
  const registeredVariants = /* @__PURE__ */ new Set();
15736
15736
  const registeredVariantCoverage = /* @__PURE__ */ new Map();
15737
15737
  const variantKey = (family, weight, italic) => `${family}|${resolveFontWeight(weight)}|${italic ? "i" : "n"}`;
15738
+ function isVariantEmbedded(family, weight, italic) {
15739
+ return registeredVariants.has(variantKey(family, weight, italic));
15740
+ }
15738
15741
  const resolveBestRegisteredVariant = (family, weight, italic) => {
15739
15742
  const want = resolveFontWeight(weight);
15740
15743
  const weights = [300, 400, 500, 600, 700];
@@ -16222,6 +16225,88 @@ function extractFontFamiliesFromSvgs(svgs) {
16222
16225
  }
16223
16226
  return families;
16224
16227
  }
16228
+ async function embedFontVariantsFromSvg(pdf, svgStr, fontBaseUrl) {
16229
+ var _a;
16230
+ const parser = new DOMParser();
16231
+ const doc = parser.parseFromString(svgStr, "image/svg+xml");
16232
+ const textEls = Array.from(doc.querySelectorAll("text, tspan, textPath"));
16233
+ const readStyleToken = (style, prop) => {
16234
+ var _a2;
16235
+ const m = style.match(new RegExp(`${prop}\\s*:\\s*([^;]+)`, "i"));
16236
+ return ((_a2 = m == null ? void 0 : m[1]) == null ? void 0 : _a2.trim()) || null;
16237
+ };
16238
+ const resolveInherited = (el, attr, styleProp = attr) => {
16239
+ var _a2;
16240
+ let cur = el;
16241
+ while (cur) {
16242
+ const a = (_a2 = cur.getAttribute(attr)) == null ? void 0 : _a2.trim();
16243
+ if (a) return a;
16244
+ const s = readStyleToken(cur.getAttribute("style") || "", styleProp);
16245
+ if (s) return s;
16246
+ cur = cur.parentElement;
16247
+ }
16248
+ return null;
16249
+ };
16250
+ const parseWeight = (raw) => {
16251
+ const n = Number.parseInt(raw, 10);
16252
+ if (Number.isFinite(n)) return n;
16253
+ const s = raw.toLowerCase();
16254
+ if (/bold/.test(s)) return 700;
16255
+ if (/semi|demi/.test(s)) return 600;
16256
+ if (/medium/.test(s)) return 500;
16257
+ if (/light|thin/.test(s)) return 300;
16258
+ return 400;
16259
+ };
16260
+ const needed = /* @__PURE__ */ new Map();
16261
+ for (const el of textEls) {
16262
+ const rawFf = resolveInherited(el, "font-family");
16263
+ if (!rawFf) continue;
16264
+ const family = (_a = rawFf.split(",")[0]) == null ? void 0 : _a.replace(/['"]/g, "").trim();
16265
+ if (!family) continue;
16266
+ const weight = resolveFontWeight(parseWeight(resolveInherited(el, "font-weight") || "400"));
16267
+ const italic = /italic|oblique/i.test(resolveInherited(el, "font-style") || "normal");
16268
+ const key = `${family}${weight}${italic ? "i" : "n"}`;
16269
+ if (!needed.has(key)) needed.set(key, { family, weight, italic });
16270
+ }
16271
+ let embedded = 0;
16272
+ for (const { family, weight, italic } of needed.values()) {
16273
+ if (isVariantEmbedded(family, weight, italic)) continue;
16274
+ await embedFontWithGoogleFallback(pdf, family, weight, fontBaseUrl, italic);
16275
+ if (isVariantEmbedded(family, weight, italic)) embedded++;
16276
+ }
16277
+ const fallbacks = [
16278
+ { family: FONT_FALLBACK_SYMBOLS, weight: 400 },
16279
+ { family: FONT_FALLBACK_MATH, weight: 400 }
16280
+ ];
16281
+ for (const w of [300, 400, 500, 600, 700]) {
16282
+ fallbacks.push({ family: FONT_FALLBACK_DEVANAGARI, weight: w });
16283
+ }
16284
+ for (const { family, weight } of fallbacks) {
16285
+ if (isVariantEmbedded(family, weight, false)) continue;
16286
+ await embedFontWithGoogleFallback(pdf, family, weight, fontBaseUrl, false);
16287
+ if (isVariantEmbedded(family, weight, false)) embedded++;
16288
+ }
16289
+ for (const { family, weight, italic } of needed.values()) {
16290
+ if (!italic) continue;
16291
+ if (!isVariantEmbedded(family, weight, false)) {
16292
+ await embedFontWithGoogleFallback(pdf, family, weight, fontBaseUrl, false);
16293
+ if (isVariantEmbedded(family, weight, false)) embedded++;
16294
+ }
16295
+ if (!isVariantEmbedded(family, 400, false)) {
16296
+ await embedFontWithGoogleFallback(pdf, family, 400, fontBaseUrl, false);
16297
+ if (isVariantEmbedded(family, 400, false)) embedded++;
16298
+ }
16299
+ if (weight <= 400) continue;
16300
+ if (isVariantEmbedded(family, 400, true)) continue;
16301
+ await embedFontWithGoogleFallback(pdf, family, 400, fontBaseUrl, true);
16302
+ if (isVariantEmbedded(family, 400, true)) embedded++;
16303
+ }
16304
+ console.log("[pdf-fonts] embedFontVariantsFromSvg", {
16305
+ requested: needed.size,
16306
+ newlyEmbedded: embedded
16307
+ });
16308
+ return embedded;
16309
+ }
16225
16310
  async function embedFontsInPdf(pdf, fontFamilies, fontBaseUrl) {
16226
16311
  const embedded = /* @__PURE__ */ new Set();
16227
16312
  const weights = [300, 400, 500, 600, 700];
@@ -16273,6 +16358,7 @@ const pdfFonts = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProp
16273
16358
  FONT_FILES,
16274
16359
  FONT_WEIGHT_LABELS,
16275
16360
  embedFont,
16361
+ embedFontVariantsFromSvg,
16276
16362
  embedFontWithGoogleFallback,
16277
16363
  embedFontsForConfig,
16278
16364
  embedFontsInPdf,
@@ -16280,6 +16366,7 @@ const pdfFonts = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProp
16280
16366
  getEmbeddedJsPDFFontName,
16281
16367
  getFontPathForWeight,
16282
16368
  isFontAvailable,
16369
+ isVariantEmbedded,
16283
16370
  resolveBestRegisteredVariant,
16284
16371
  resolveFontWeight,
16285
16372
  rewriteSvgFontsForJsPDF
@@ -17786,7 +17873,17 @@ async function assemblePdfFromSvgs(svgResults, options = {}) {
17786
17873
  } catch {
17787
17874
  }
17788
17875
  await convertTextDecorationsToLines(processedSvg);
17789
- const rewrittenSvg = rewriteSvgFontsForJsPDF(new XMLSerializer().serializeToString(processedSvg));
17876
+ const liveSvgStr = new XMLSerializer().serializeToString(processedSvg);
17877
+ try {
17878
+ const { embedFontVariantsFromSvg: embedFontVariantsFromSvg2 } = await Promise.resolve().then(() => pdfFonts);
17879
+ await embedFontVariantsFromSvg2(pdf, liveSvgStr, fontBaseUrl);
17880
+ } catch (embedErr) {
17881
+ console.warn(
17882
+ "[canvas-renderer][pdf] embedFontVariantsFromSvg failed (page " + (i + 1) + "):",
17883
+ embedErr
17884
+ );
17885
+ }
17886
+ const rewrittenSvg = rewriteSvgFontsForJsPDF(liveSvgStr);
17790
17887
  const reParser = new DOMParser();
17791
17888
  const reDoc = reParser.parseFromString(rewrittenSvg, "image/svg+xml");
17792
17889
  processedSvg = reDoc.documentElement;