@ai-matrx/print 0.8.1 → 0.8.2

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.
@@ -313,10 +313,24 @@ declare const NOTO_EMOJI_URL = "https://cdn.jsdelivr.net/npm/@fontsource/noto-em
313
313
  declare const NOTO_SYMBOLS_URL = "https://cdn.jsdelivr.net/npm/@fontsource/noto-sans-math@5.3.0/files/noto-sans-math-latin-400-normal.woff";
314
314
  declare const defaultEmojiFontLoader: FontLoader;
315
315
  declare const defaultSymbolFontLoader: FontLoader;
316
+ /** Loads the CJK subset faces covering these code points. */
317
+ type CjkFontLoader = (codepoints: number[]) => Promise<Array<{
318
+ name: string;
319
+ bytes: Uint8Array;
320
+ }>>;
316
321
  interface FallbackFontLoaders {
317
322
  emoji?: FontLoader | undefined;
318
323
  symbols?: FontLoader | undefined;
319
- }
324
+ cjk?: CjkFontLoader | undefined;
325
+ }
326
+ /** Noto Sans JP (SIL OFL) from fontsource: 124 unicode-range subsets; only the needed ones load. */
327
+ declare const NOTO_CJK_BASE = "https://cdn.jsdelivr.net/npm/@fontsource/noto-sans-jp@5.3.0";
328
+ /** Parse a fontsource stylesheet: each face's file stem and its unicode ranges. */
329
+ declare function parseUnicodeRangeCss(css: string): Array<{
330
+ file: string;
331
+ ranges: Array<[number, number]>;
332
+ }>;
333
+ declare const defaultCjkFontLoader: CjkFontLoader;
320
334
  /**
321
335
  * Words pdfmake did not put on a page: a text node with no position was never
322
336
  * placed, and a node measured taller than its page (`__height`) whose lines
@@ -657,4 +671,4 @@ declare function exportDocument(source: string, format: DocumentFormat, options?
657
671
  /** Browser helper: save an export through a download link. */
658
672
  declare function downloadDocumentExport(exp: DocumentExport): void;
659
673
 
660
- export { BUNDLED_STYLE_IDS, type BibliographyEntry, type Block, CSL_STYLE_ALIASES, type Caption, CitationEngine, type CitationStyle, type CslFetcher, type CslItem, type CslName, DEFAULT_FOOTER, DOCUMENT_FORMATS, type DocSection, type DocTree, type DocumentExport, type DocumentFormat, type DocumentNotice, type DocumentSettings, type ExportDocumentOptions, type FallbackFontLoaders, type FontLoader, type ImageLoader, type ImageMap, type Inline, type ListItem, type Margins, type MathSpan, NOTO_EMOJI_URL, NOTO_SYMBOLS_URL, type Orientation, PAGE_SIZES, type PageSizeName, type ParseDocumentOptions, type PrepareDocumentOptions, type ResolvedImage, type RunningTemplate, type TocEntry, type TypesetMath, buildPdfDefinition, countUnplacedWords, cslStyleId, defaultCslFetcher, defaultEmojiFontLoader, defaultImageLoader, defaultSymbolFontLoader, documentCss, documentToDocx, documentToEpub, documentToHtml, documentToPdf, downloadDocumentExport, exportDocument, extractMath, fillTemplate, loadCslLocale, loadCslStyle, mathKey, normalizeReference, parseCitationGroup, parseDocument, parseLength, parseLocator, parseMathML, plainText, prepareDocument, renderBlocksHtml, renderPdfDefinition, resolveDocumentImages, resolveSettings, scanCitationKeys, splitFrontmatter, typesetDocumentMath };
674
+ export { BUNDLED_STYLE_IDS, type BibliographyEntry, type Block, CSL_STYLE_ALIASES, type Caption, CitationEngine, type CitationStyle, type CjkFontLoader, type CslFetcher, type CslItem, type CslName, DEFAULT_FOOTER, DOCUMENT_FORMATS, type DocSection, type DocTree, type DocumentExport, type DocumentFormat, type DocumentNotice, type DocumentSettings, type ExportDocumentOptions, type FallbackFontLoaders, type FontLoader, type ImageLoader, type ImageMap, type Inline, type ListItem, type Margins, type MathSpan, NOTO_CJK_BASE, NOTO_EMOJI_URL, NOTO_SYMBOLS_URL, type Orientation, PAGE_SIZES, type PageSizeName, type ParseDocumentOptions, type PrepareDocumentOptions, type ResolvedImage, type RunningTemplate, type TocEntry, type TypesetMath, buildPdfDefinition, countUnplacedWords, cslStyleId, defaultCjkFontLoader, defaultCslFetcher, defaultEmojiFontLoader, defaultImageLoader, defaultSymbolFontLoader, documentCss, documentToDocx, documentToEpub, documentToHtml, documentToPdf, downloadDocumentExport, exportDocument, extractMath, fillTemplate, loadCslLocale, loadCslStyle, mathKey, normalizeReference, parseCitationGroup, parseDocument, parseLength, parseLocator, parseMathML, parseUnicodeRangeCss, plainText, prepareDocument, renderBlocksHtml, renderPdfDefinition, resolveDocumentImages, resolveSettings, scanCitationKeys, splitFrontmatter, typesetDocumentMath };
@@ -313,10 +313,24 @@ declare const NOTO_EMOJI_URL = "https://cdn.jsdelivr.net/npm/@fontsource/noto-em
313
313
  declare const NOTO_SYMBOLS_URL = "https://cdn.jsdelivr.net/npm/@fontsource/noto-sans-math@5.3.0/files/noto-sans-math-latin-400-normal.woff";
314
314
  declare const defaultEmojiFontLoader: FontLoader;
315
315
  declare const defaultSymbolFontLoader: FontLoader;
316
+ /** Loads the CJK subset faces covering these code points. */
317
+ type CjkFontLoader = (codepoints: number[]) => Promise<Array<{
318
+ name: string;
319
+ bytes: Uint8Array;
320
+ }>>;
316
321
  interface FallbackFontLoaders {
317
322
  emoji?: FontLoader | undefined;
318
323
  symbols?: FontLoader | undefined;
319
- }
324
+ cjk?: CjkFontLoader | undefined;
325
+ }
326
+ /** Noto Sans JP (SIL OFL) from fontsource: 124 unicode-range subsets; only the needed ones load. */
327
+ declare const NOTO_CJK_BASE = "https://cdn.jsdelivr.net/npm/@fontsource/noto-sans-jp@5.3.0";
328
+ /** Parse a fontsource stylesheet: each face's file stem and its unicode ranges. */
329
+ declare function parseUnicodeRangeCss(css: string): Array<{
330
+ file: string;
331
+ ranges: Array<[number, number]>;
332
+ }>;
333
+ declare const defaultCjkFontLoader: CjkFontLoader;
320
334
  /**
321
335
  * Words pdfmake did not put on a page: a text node with no position was never
322
336
  * placed, and a node measured taller than its page (`__height`) whose lines
@@ -657,4 +671,4 @@ declare function exportDocument(source: string, format: DocumentFormat, options?
657
671
  /** Browser helper: save an export through a download link. */
658
672
  declare function downloadDocumentExport(exp: DocumentExport): void;
659
673
 
660
- export { BUNDLED_STYLE_IDS, type BibliographyEntry, type Block, CSL_STYLE_ALIASES, type Caption, CitationEngine, type CitationStyle, type CslFetcher, type CslItem, type CslName, DEFAULT_FOOTER, DOCUMENT_FORMATS, type DocSection, type DocTree, type DocumentExport, type DocumentFormat, type DocumentNotice, type DocumentSettings, type ExportDocumentOptions, type FallbackFontLoaders, type FontLoader, type ImageLoader, type ImageMap, type Inline, type ListItem, type Margins, type MathSpan, NOTO_EMOJI_URL, NOTO_SYMBOLS_URL, type Orientation, PAGE_SIZES, type PageSizeName, type ParseDocumentOptions, type PrepareDocumentOptions, type ResolvedImage, type RunningTemplate, type TocEntry, type TypesetMath, buildPdfDefinition, countUnplacedWords, cslStyleId, defaultCslFetcher, defaultEmojiFontLoader, defaultImageLoader, defaultSymbolFontLoader, documentCss, documentToDocx, documentToEpub, documentToHtml, documentToPdf, downloadDocumentExport, exportDocument, extractMath, fillTemplate, loadCslLocale, loadCslStyle, mathKey, normalizeReference, parseCitationGroup, parseDocument, parseLength, parseLocator, parseMathML, plainText, prepareDocument, renderBlocksHtml, renderPdfDefinition, resolveDocumentImages, resolveSettings, scanCitationKeys, splitFrontmatter, typesetDocumentMath };
674
+ export { BUNDLED_STYLE_IDS, type BibliographyEntry, type Block, CSL_STYLE_ALIASES, type Caption, CitationEngine, type CitationStyle, type CjkFontLoader, type CslFetcher, type CslItem, type CslName, DEFAULT_FOOTER, DOCUMENT_FORMATS, type DocSection, type DocTree, type DocumentExport, type DocumentFormat, type DocumentNotice, type DocumentSettings, type ExportDocumentOptions, type FallbackFontLoaders, type FontLoader, type ImageLoader, type ImageMap, type Inline, type ListItem, type Margins, type MathSpan, NOTO_CJK_BASE, NOTO_EMOJI_URL, NOTO_SYMBOLS_URL, type Orientation, PAGE_SIZES, type PageSizeName, type ParseDocumentOptions, type PrepareDocumentOptions, type ResolvedImage, type RunningTemplate, type TocEntry, type TypesetMath, buildPdfDefinition, countUnplacedWords, cslStyleId, defaultCjkFontLoader, defaultCslFetcher, defaultEmojiFontLoader, defaultImageLoader, defaultSymbolFontLoader, documentCss, documentToDocx, documentToEpub, documentToHtml, documentToPdf, downloadDocumentExport, exportDocument, extractMath, fillTemplate, loadCslLocale, loadCslStyle, mathKey, normalizeReference, parseCitationGroup, parseDocument, parseLength, parseLocator, parseMathML, parseUnicodeRangeCss, plainText, prepareDocument, renderBlocksHtml, renderPdfDefinition, resolveDocumentImages, resolveSettings, scanCitationKeys, splitFrontmatter, typesetDocumentMath };
package/dist/document.js CHANGED
@@ -4456,12 +4456,13 @@ async function loadTypography(tree, loaders = {}) {
4456
4456
  const base = await loadFaces(vfs, s.fontSize);
4457
4457
  let needEmoji = false;
4458
4458
  let needSymbols = false;
4459
+ const cjk = /* @__PURE__ */ new Set();
4459
4460
  for (const ch of documentText(tree)) {
4460
4461
  const cp = ch.codePointAt(0);
4461
4462
  if (cp < 32 || cp === 8205 || cp === 65039 || base.body(cp)) continue;
4462
4463
  if (EMOJI_CP.test(ch)) needEmoji = true;
4464
+ else if (isCjk(cp)) cjk.add(cp);
4463
4465
  else needSymbols = true;
4464
- if (needEmoji && needSymbols) break;
4465
4466
  }
4466
4467
  const fallbacks = [];
4467
4468
  if (needEmoji) {
@@ -4472,6 +4473,26 @@ async function loadTypography(tree, loaders = {}) {
4472
4473
  const b = await registerFace("NotoSymbols", "NotoSansMath.woff", loaders.symbols ?? defaultSymbolFontLoader, tree, "symbols");
4473
4474
  if (b) fallbacks.push({ font: "NotoSymbols", bytes: b });
4474
4475
  }
4476
+ if (cjk.size) {
4477
+ let subsets = [];
4478
+ try {
4479
+ subsets = await (loaders.cjk ?? defaultCjkFontLoader)([...cjk]);
4480
+ } catch {
4481
+ subsets = [];
4482
+ }
4483
+ for (const sub of subsets) {
4484
+ const font = `NotoCJK_${sub.name.replace(/[^\w]/g, "_")}`;
4485
+ const b = await registerFace(font, `${sub.name}.woff`, async () => sub.bytes, tree, "Japanese / Chinese");
4486
+ if (b) fallbacks.push({ font, bytes: b });
4487
+ }
4488
+ if (!subsets.length) {
4489
+ tree.notices.push({
4490
+ code: "glyph-substituted",
4491
+ message: "The Japanese / Chinese font could not be loaded, so those characters were left out of the PDF (Word, EPUB and HTML keep them).",
4492
+ remedy: "Check the internet connection (the font comes from cdn.jsdelivr.net) and export again."
4493
+ });
4494
+ }
4495
+ }
4475
4496
  const faces = fallbacks.length ? await loadFaces(vfs, s.fontSize, fallbacks) : base;
4476
4497
  if (!s.hyphenate) return { faces };
4477
4498
  const split = await loadHyphenator(s.lang);
@@ -4494,6 +4515,37 @@ var urlLoader = (url) => async () => {
4494
4515
  };
4495
4516
  var defaultEmojiFontLoader = urlLoader(NOTO_EMOJI_URL);
4496
4517
  var defaultSymbolFontLoader = urlLoader(NOTO_SYMBOLS_URL);
4518
+ var NOTO_CJK_BASE = "https://cdn.jsdelivr.net/npm/@fontsource/noto-sans-jp@5.3.0";
4519
+ function parseUnicodeRangeCss(css) {
4520
+ const out = [];
4521
+ for (const block3 of css.split("@font-face").slice(1)) {
4522
+ const file = /url\(\.\/files\/([\w-]+)\.woff\)/.exec(block3)?.[1];
4523
+ const range = /unicode-range:\s*([^;]+);/.exec(block3)?.[1];
4524
+ if (!file || !range) continue;
4525
+ const ranges = range.split(",").map((r) => {
4526
+ const [a, b] = r.trim().replace(/^U\+/i, "").split("-");
4527
+ const lo = parseInt(a, 16);
4528
+ return [lo, b ? parseInt(b, 16) : lo];
4529
+ });
4530
+ out.push({ file, ranges });
4531
+ }
4532
+ return out;
4533
+ }
4534
+ var defaultCjkFontLoader = async (cps) => {
4535
+ if (typeof fetch !== "function" || cps.length === 0) return [];
4536
+ const res = await fetch(`${NOTO_CJK_BASE}/400.css`);
4537
+ if (!res.ok) return [];
4538
+ const faces = parseUnicodeRangeCss(await res.text()).filter((f) => cps.some((cp) => f.ranges.some(([a, b]) => cp >= a && cp <= b)));
4539
+ const out = [];
4540
+ await Promise.all(
4541
+ faces.map(async (f) => {
4542
+ const r = await fetch(`${NOTO_CJK_BASE}/files/${f.file}.woff`);
4543
+ if (r.ok) out.push({ name: f.file, bytes: new Uint8Array(await r.arrayBuffer()) });
4544
+ })
4545
+ );
4546
+ return out;
4547
+ };
4548
+ var isCjk = (cp) => cp >= 11904 && cp <= 40959 || cp >= 44032 && cp <= 55215 || cp >= 63744 && cp <= 64255 || cp >= 65072 && cp <= 65103 || cp >= 65280 && cp <= 65519 || cp >= 131072 && cp <= 201551;
4497
4549
  var EMOJI_CP = /\p{Extended_Pictographic}|\p{Regional_Indicator}|\u20E3/u;
4498
4550
  function documentText(tree) {
4499
4551
  const s = tree.settings;
@@ -5509,12 +5561,14 @@ export {
5509
5561
  CitationEngine,
5510
5562
  DEFAULT_FOOTER,
5511
5563
  DOCUMENT_FORMATS,
5564
+ NOTO_CJK_BASE,
5512
5565
  NOTO_EMOJI_URL,
5513
5566
  NOTO_SYMBOLS_URL,
5514
5567
  PAGE_SIZES,
5515
5568
  buildPdfDefinition,
5516
5569
  countUnplacedWords,
5517
5570
  cslStyleId,
5571
+ defaultCjkFontLoader,
5518
5572
  defaultCslFetcher,
5519
5573
  defaultEmojiFontLoader,
5520
5574
  defaultImageLoader,
@@ -5537,6 +5591,7 @@ export {
5537
5591
  parseLength,
5538
5592
  parseLocator,
5539
5593
  parseMathML,
5594
+ parseUnicodeRangeCss,
5540
5595
  plainText,
5541
5596
  prepareDocument,
5542
5597
  renderBlocksHtml,