@ai-matrx/print 0.8.0 → 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.
- package/CHANGELOG.md +19 -0
- package/dist/document.cjs +71 -2
- package/dist/document.cjs.map +1 -1
- package/dist/document.d.cts +17 -3
- package/dist/document.d.ts +17 -3
- package/dist/document.js +71 -2
- package/dist/document.js.map +1 -1
- package/dist/react.d.cts +1 -1
- package/dist/react.d.ts +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.8.2
|
|
4
|
+
|
|
5
|
+
- **PDF font fallback covers Japanese / Chinese / Korean.** Characters the
|
|
6
|
+
body, emoji and symbol faces cannot draw now fall back to Noto Sans JP
|
|
7
|
+
(SIL OFL, fontsource) — loading only the unicode-range subsets the document
|
|
8
|
+
uses (`fonts.cjk` loader; default jsDelivr). Found on a real conversation
|
|
9
|
+
whose citations carried Japanese source titles. A glyph is announced only
|
|
10
|
+
when no face in the chain can draw it.
|
|
11
|
+
- Consumer action: none — refresh to latest.
|
|
12
|
+
|
|
13
|
+
## 0.8.1
|
|
14
|
+
|
|
15
|
+
- **Fixed (Word):** exporting DOCX laid out a whole PDF to number the table of
|
|
16
|
+
contents even when the document has no table of contents; now only with a
|
|
17
|
+
TOC, and a failed measuring pass never fails the export — the TOC lists every
|
|
18
|
+
heading and Word fills in the page numbers on open (`toc-pages-deferred`
|
|
19
|
+
notice).
|
|
20
|
+
- Consumer action: none — refresh to latest.
|
|
21
|
+
|
|
3
22
|
## 0.8.0
|
|
4
23
|
|
|
5
24
|
- **Citations through a real CSL processor.** citeproc-js (the engine Zotero
|
package/dist/document.cjs
CHANGED
|
@@ -35,12 +35,14 @@ __export(document_exports, {
|
|
|
35
35
|
CitationEngine: () => CitationEngine,
|
|
36
36
|
DEFAULT_FOOTER: () => DEFAULT_FOOTER,
|
|
37
37
|
DOCUMENT_FORMATS: () => DOCUMENT_FORMATS,
|
|
38
|
+
NOTO_CJK_BASE: () => NOTO_CJK_BASE,
|
|
38
39
|
NOTO_EMOJI_URL: () => NOTO_EMOJI_URL,
|
|
39
40
|
NOTO_SYMBOLS_URL: () => NOTO_SYMBOLS_URL,
|
|
40
41
|
PAGE_SIZES: () => PAGE_SIZES,
|
|
41
42
|
buildPdfDefinition: () => buildPdfDefinition,
|
|
42
43
|
countUnplacedWords: () => countUnplacedWords,
|
|
43
44
|
cslStyleId: () => cslStyleId,
|
|
45
|
+
defaultCjkFontLoader: () => defaultCjkFontLoader,
|
|
44
46
|
defaultCslFetcher: () => defaultCslFetcher,
|
|
45
47
|
defaultEmojiFontLoader: () => defaultEmojiFontLoader,
|
|
46
48
|
defaultImageLoader: () => defaultImageLoader,
|
|
@@ -63,6 +65,7 @@ __export(document_exports, {
|
|
|
63
65
|
parseLength: () => parseLength,
|
|
64
66
|
parseLocator: () => parseLocator,
|
|
65
67
|
parseMathML: () => parseMathML,
|
|
68
|
+
parseUnicodeRangeCss: () => parseUnicodeRangeCss,
|
|
66
69
|
plainText: () => plainText,
|
|
67
70
|
prepareDocument: () => prepareDocument,
|
|
68
71
|
renderBlocksHtml: () => renderBlocksHtml,
|
|
@@ -4533,12 +4536,13 @@ async function loadTypography(tree, loaders = {}) {
|
|
|
4533
4536
|
const base = await loadFaces(vfs, s.fontSize);
|
|
4534
4537
|
let needEmoji = false;
|
|
4535
4538
|
let needSymbols = false;
|
|
4539
|
+
const cjk = /* @__PURE__ */ new Set();
|
|
4536
4540
|
for (const ch of documentText(tree)) {
|
|
4537
4541
|
const cp = ch.codePointAt(0);
|
|
4538
4542
|
if (cp < 32 || cp === 8205 || cp === 65039 || base.body(cp)) continue;
|
|
4539
4543
|
if (EMOJI_CP.test(ch)) needEmoji = true;
|
|
4544
|
+
else if (isCjk(cp)) cjk.add(cp);
|
|
4540
4545
|
else needSymbols = true;
|
|
4541
|
-
if (needEmoji && needSymbols) break;
|
|
4542
4546
|
}
|
|
4543
4547
|
const fallbacks = [];
|
|
4544
4548
|
if (needEmoji) {
|
|
@@ -4549,6 +4553,26 @@ async function loadTypography(tree, loaders = {}) {
|
|
|
4549
4553
|
const b = await registerFace("NotoSymbols", "NotoSansMath.woff", loaders.symbols ?? defaultSymbolFontLoader, tree, "symbols");
|
|
4550
4554
|
if (b) fallbacks.push({ font: "NotoSymbols", bytes: b });
|
|
4551
4555
|
}
|
|
4556
|
+
if (cjk.size) {
|
|
4557
|
+
let subsets = [];
|
|
4558
|
+
try {
|
|
4559
|
+
subsets = await (loaders.cjk ?? defaultCjkFontLoader)([...cjk]);
|
|
4560
|
+
} catch {
|
|
4561
|
+
subsets = [];
|
|
4562
|
+
}
|
|
4563
|
+
for (const sub of subsets) {
|
|
4564
|
+
const font = `NotoCJK_${sub.name.replace(/[^\w]/g, "_")}`;
|
|
4565
|
+
const b = await registerFace(font, `${sub.name}.woff`, async () => sub.bytes, tree, "Japanese / Chinese");
|
|
4566
|
+
if (b) fallbacks.push({ font, bytes: b });
|
|
4567
|
+
}
|
|
4568
|
+
if (!subsets.length) {
|
|
4569
|
+
tree.notices.push({
|
|
4570
|
+
code: "glyph-substituted",
|
|
4571
|
+
message: "The Japanese / Chinese font could not be loaded, so those characters were left out of the PDF (Word, EPUB and HTML keep them).",
|
|
4572
|
+
remedy: "Check the internet connection (the font comes from cdn.jsdelivr.net) and export again."
|
|
4573
|
+
});
|
|
4574
|
+
}
|
|
4575
|
+
}
|
|
4552
4576
|
const faces = fallbacks.length ? await loadFaces(vfs, s.fontSize, fallbacks) : base;
|
|
4553
4577
|
if (!s.hyphenate) return { faces };
|
|
4554
4578
|
const split = await loadHyphenator(s.lang);
|
|
@@ -4571,6 +4595,37 @@ var urlLoader = (url) => async () => {
|
|
|
4571
4595
|
};
|
|
4572
4596
|
var defaultEmojiFontLoader = urlLoader(NOTO_EMOJI_URL);
|
|
4573
4597
|
var defaultSymbolFontLoader = urlLoader(NOTO_SYMBOLS_URL);
|
|
4598
|
+
var NOTO_CJK_BASE = "https://cdn.jsdelivr.net/npm/@fontsource/noto-sans-jp@5.3.0";
|
|
4599
|
+
function parseUnicodeRangeCss(css) {
|
|
4600
|
+
const out = [];
|
|
4601
|
+
for (const block3 of css.split("@font-face").slice(1)) {
|
|
4602
|
+
const file = /url\(\.\/files\/([\w-]+)\.woff\)/.exec(block3)?.[1];
|
|
4603
|
+
const range = /unicode-range:\s*([^;]+);/.exec(block3)?.[1];
|
|
4604
|
+
if (!file || !range) continue;
|
|
4605
|
+
const ranges = range.split(",").map((r) => {
|
|
4606
|
+
const [a, b] = r.trim().replace(/^U\+/i, "").split("-");
|
|
4607
|
+
const lo = parseInt(a, 16);
|
|
4608
|
+
return [lo, b ? parseInt(b, 16) : lo];
|
|
4609
|
+
});
|
|
4610
|
+
out.push({ file, ranges });
|
|
4611
|
+
}
|
|
4612
|
+
return out;
|
|
4613
|
+
}
|
|
4614
|
+
var defaultCjkFontLoader = async (cps) => {
|
|
4615
|
+
if (typeof fetch !== "function" || cps.length === 0) return [];
|
|
4616
|
+
const res = await fetch(`${NOTO_CJK_BASE}/400.css`);
|
|
4617
|
+
if (!res.ok) return [];
|
|
4618
|
+
const faces = parseUnicodeRangeCss(await res.text()).filter((f) => cps.some((cp) => f.ranges.some(([a, b]) => cp >= a && cp <= b)));
|
|
4619
|
+
const out = [];
|
|
4620
|
+
await Promise.all(
|
|
4621
|
+
faces.map(async (f) => {
|
|
4622
|
+
const r = await fetch(`${NOTO_CJK_BASE}/files/${f.file}.woff`);
|
|
4623
|
+
if (r.ok) out.push({ name: f.file, bytes: new Uint8Array(await r.arrayBuffer()) });
|
|
4624
|
+
})
|
|
4625
|
+
);
|
|
4626
|
+
return out;
|
|
4627
|
+
};
|
|
4628
|
+
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;
|
|
4574
4629
|
var EMOJI_CP = /\p{Extended_Pictographic}|\p{Regional_Indicator}|\u20E3/u;
|
|
4575
4630
|
function documentText(tree) {
|
|
4576
4631
|
const s = tree.settings;
|
|
@@ -5548,7 +5603,21 @@ async function exportDocument(source, format, options = {}) {
|
|
|
5548
5603
|
bytes = r.bytes;
|
|
5549
5604
|
pageCount = r.pageCount;
|
|
5550
5605
|
} else if (format === "docx") {
|
|
5551
|
-
const
|
|
5606
|
+
const hasToc = tree.sections.some((sec) => sec.blocks.some((blk) => blk.type === "toc"));
|
|
5607
|
+
let pages;
|
|
5608
|
+
if (hasToc) {
|
|
5609
|
+
try {
|
|
5610
|
+
pages = await headingPages(tree, images, options.fonts);
|
|
5611
|
+
} catch (err) {
|
|
5612
|
+
const n = {
|
|
5613
|
+
code: "toc-pages-deferred",
|
|
5614
|
+
message: `The Word file's table of contents lists every heading; its page numbers fill in when the file is opened (they could not be measured here: ${err.message}).`,
|
|
5615
|
+
remedy: "Open the file in Word (or update fields) to show the page numbers."
|
|
5616
|
+
};
|
|
5617
|
+
tree.notices.push(n);
|
|
5618
|
+
options.onNotice?.(n);
|
|
5619
|
+
}
|
|
5620
|
+
}
|
|
5552
5621
|
bytes = await documentToDocx(tree, { images, headingPages: pages });
|
|
5553
5622
|
} else bytes = await documentToEpub(tree, { images });
|
|
5554
5623
|
}
|