@docx-editor.dev/docx-to-pdf 2.22.0 → 2.23.0
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/README.md +10 -1
- package/THIRD_PARTY_NOTICES.md +0 -1
- package/assets/sources.json +0 -9
- package/dist/index.cjs +630 -135
- package/dist/index.js +612 -127
- package/docs/fonts.md +60 -2
- package/docs/integrations.md +2 -1
- package/package.json +11 -4
- package/assets/NotoSansCJKjp-Regular.otf +0 -0
- package/licenses/NotoSansCJK-OFL.txt +0 -92
package/dist/index.cjs
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __export = (target, all) => {
|
|
7
9
|
for (var name in all)
|
|
@@ -15,12 +17,20 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
17
|
}
|
|
16
18
|
return to;
|
|
17
19
|
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
18
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
29
|
|
|
20
30
|
// src/index.ts
|
|
21
31
|
var index_exports = {};
|
|
22
32
|
__export(index_exports, {
|
|
23
|
-
ExportResourceError: () =>
|
|
33
|
+
ExportResourceError: () => import_export6.ExportResourceError,
|
|
24
34
|
PdfDocumentOpenError: () => PdfDocumentOpenError,
|
|
25
35
|
PdfEncodingError: () => PdfEncodingError,
|
|
26
36
|
PdfFidelityError: () => PdfFidelityError,
|
|
@@ -37,7 +47,7 @@ module.exports = __toCommonJS(index_exports);
|
|
|
37
47
|
|
|
38
48
|
// src/export-pdf.ts
|
|
39
49
|
var import_pdf_lib6 = require("pdf-lib");
|
|
40
|
-
var
|
|
50
|
+
var import_export5 = require("@docx-editor.dev/core/export");
|
|
41
51
|
|
|
42
52
|
// src/context.ts
|
|
43
53
|
var import_export = require("@docx-editor.dev/core/export");
|
|
@@ -243,11 +253,11 @@ var latinSubstitute = (family, prefix) => [
|
|
|
243
253
|
weight,
|
|
244
254
|
style
|
|
245
255
|
]);
|
|
256
|
+
var CJK_FAMILY = "Noto Sans CJK JP";
|
|
246
257
|
var supplemental = [
|
|
247
258
|
["Noto Sans Symbols 2", new import_node_url.URL("NotoSansSymbols2-Regular.ttf", assetRoot), 400, "normal"],
|
|
248
259
|
["Noto Sans Math", new import_node_url.URL("NotoSansMath-Regular.ttf", assetRoot), 400, "normal"],
|
|
249
260
|
["Noto Sans Arabic", new import_node_url.URL("NotoSansArabic-Regular.ttf", assetRoot), 400, "normal"],
|
|
250
|
-
["Noto Sans CJK JP", new import_node_url.URL("NotoSansCJKjp-Regular.otf", assetRoot), 400, "normal"],
|
|
251
261
|
["Twemoji Mozilla", new import_node_url.URL("TwemojiMozilla.ttf", assetRoot), 400, "normal"],
|
|
252
262
|
["Noto Emoji", new import_node_url.URL("NotoEmoji-Regular.ttf", assetRoot), 400, "normal"],
|
|
253
263
|
...latinSubstitute("Liberation Sans", "LiberationSans"),
|
|
@@ -261,10 +271,16 @@ var PDF_GLYPH_FALLBACKS = [
|
|
|
261
271
|
"Noto Sans Symbols 2",
|
|
262
272
|
"Noto Sans Math",
|
|
263
273
|
"Noto Sans Arabic",
|
|
264
|
-
//
|
|
274
|
+
// Hebrew, and Latin, Greek or Cyrillic letters the faces above lack. A missing glyph falls
|
|
275
|
+
// back to Times New Roman in the reference renderer. A host without it resolves the packaged
|
|
276
|
+
// Liberation Serif, whose Latin letters share its widths but whose Hebrew runs about 12%
|
|
277
|
+
// wider, so Hebrew in that face can wrap earlier.
|
|
278
|
+
"Times New Roman",
|
|
279
|
+
// Prefer available Word CJK faces; Noto Sans CJK JP from `@docx-editor.dev/fonts-cjk` is
|
|
280
|
+
// the portable fallback when that package is installed.
|
|
265
281
|
"SimSun",
|
|
266
282
|
"Batang",
|
|
267
|
-
|
|
283
|
+
CJK_FAMILY,
|
|
268
284
|
// Color first: a COLR face paints its layers in the writer. The monochrome face stays
|
|
269
285
|
// behind it for the few symbols the color set leaves out.
|
|
270
286
|
"Twemoji Mozilla",
|
|
@@ -300,7 +316,7 @@ var substitutes = {
|
|
|
300
316
|
"Gulim",
|
|
301
317
|
"Dotum",
|
|
302
318
|
"Malgun Gothic"
|
|
303
|
-
].map((family) => [family,
|
|
319
|
+
].map((family) => [family, CJK_FAMILY])
|
|
304
320
|
)
|
|
305
321
|
};
|
|
306
322
|
var localizedFamilies = {
|
|
@@ -369,6 +385,7 @@ var substituteFor = (family) => {
|
|
|
369
385
|
function genericSubstituteFor(family) {
|
|
370
386
|
const name = canonicalFamily(family).family;
|
|
371
387
|
if (/mono|courier|consol|menlo|typewriter|\bcode\b|fixed/i.test(name)) return "Liberation Mono";
|
|
388
|
+
if (/symbol/i.test(name)) return "Noto Sans Symbols 2";
|
|
372
389
|
if (/sans/i.test(name)) return "Liberation Sans";
|
|
373
390
|
if (/serif|roman|garamond|georgia|times|book|baskerville|cambria|minion|palatino|century|didot|caslon|constantia|sagona|lora|merriweather|playfair|charter|bodoni|perpetua|rockwell|goudy|bembo|sabon|antiqua/i.test(
|
|
374
391
|
name
|
|
@@ -378,6 +395,7 @@ function genericSubstituteFor(family) {
|
|
|
378
395
|
}
|
|
379
396
|
var knownFamilies = /* @__PURE__ */ new Set([
|
|
380
397
|
...supplemental.map(([family]) => family),
|
|
398
|
+
CJK_FAMILY,
|
|
381
399
|
...Object.keys(substitutes),
|
|
382
400
|
...Object.keys(packagedSubstitutes),
|
|
383
401
|
...Object.values(packagedSubstitutes),
|
|
@@ -388,89 +406,184 @@ var knownFamilies = /* @__PURE__ */ new Set([
|
|
|
388
406
|
"Webdings",
|
|
389
407
|
"MT Extra"
|
|
390
408
|
]);
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
var
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
|
|
409
|
+
var cjkWordFamilies = /* @__PURE__ */ new Set([
|
|
410
|
+
CJK_FAMILY,
|
|
411
|
+
...Object.keys(substitutes).filter((family) => substitutes[family] === CJK_FAMILY)
|
|
412
|
+
]);
|
|
413
|
+
var CJK_PACKAGE = "@docx-editor.dev/fonts-cjk";
|
|
414
|
+
function isPackageNotFound(error, specifier) {
|
|
415
|
+
if (typeof error !== "object" || error === null) return false;
|
|
416
|
+
const { code, message } = error;
|
|
417
|
+
if (code !== "ERR_MODULE_NOT_FOUND" && code !== "MODULE_NOT_FOUND") return false;
|
|
418
|
+
if (typeof message !== "string") return false;
|
|
419
|
+
return [`Cannot find package '${specifier}'`, `Cannot find module '${specifier}'`].some(
|
|
420
|
+
(prefix) => message.startsWith(prefix)
|
|
421
|
+
);
|
|
422
|
+
}
|
|
423
|
+
async function importCjkFace() {
|
|
424
|
+
let module2;
|
|
425
|
+
try {
|
|
426
|
+
module2 = await import(
|
|
427
|
+
/* webpackIgnore: true */
|
|
428
|
+
"@docx-editor.dev/fonts-cjk"
|
|
429
|
+
);
|
|
430
|
+
} catch (error) {
|
|
431
|
+
if (isPackageNotFound(error, CJK_PACKAGE)) return null;
|
|
432
|
+
throw error;
|
|
433
|
+
}
|
|
434
|
+
const file = module2.NOTO_SANS_CJK_JP_URL;
|
|
435
|
+
if (typeof file?.href !== "string")
|
|
436
|
+
throw new TypeError(`${CJK_PACKAGE} does not export NOTO_SANS_CJK_JP_URL`);
|
|
437
|
+
return new import_node_url.URL(file.href);
|
|
438
|
+
}
|
|
439
|
+
var CJK_TEXT = /[\u1100-\u11ff\u2e80-\u2fdf\u3000-\u9fff\ua960-\ua97f\uac00-\ud7ff\uf900-\ufaff\ufe30-\ufe4f\uff00-\uffef]|[\u{20000}-\u{3ffff}]/u;
|
|
440
|
+
var substitutionsTo = (family, target) => {
|
|
441
|
+
const { bold, italic } = canonicalFamily(family);
|
|
442
|
+
return [400, 700].flatMap(
|
|
443
|
+
(weight) => ["normal", "italic"].map((style) => ({
|
|
444
|
+
from: face(family, weight, style),
|
|
445
|
+
// The packaged CJK, symbol and mathematics faces come in one weight and one style.
|
|
446
|
+
to: target.startsWith("Noto") ? face(target) : face(
|
|
447
|
+
target,
|
|
448
|
+
bold || weight === 700 ? 700 : 400,
|
|
449
|
+
italic || style === "italic" ? "italic" : "normal"
|
|
450
|
+
)
|
|
451
|
+
}))
|
|
452
|
+
);
|
|
453
|
+
};
|
|
454
|
+
function packagedFontResolvers(locateCjkFace = importCjkFace) {
|
|
455
|
+
let located;
|
|
456
|
+
let cjkMissing = false;
|
|
457
|
+
const cjkFace = () => located ??= locateCjkFace().then(
|
|
458
|
+
(file) => {
|
|
459
|
+
cjkMissing = file === null;
|
|
460
|
+
return file;
|
|
461
|
+
},
|
|
462
|
+
(error) => {
|
|
463
|
+
cjkMissing = true;
|
|
464
|
+
throw error;
|
|
465
|
+
}
|
|
466
|
+
);
|
|
467
|
+
const readFaces = (faces, signal) => Promise.all(
|
|
468
|
+
faces.map(async ([family, file, weight, style]) => {
|
|
404
469
|
const bytes = new Uint8Array(await readFontFile(file, signal));
|
|
405
470
|
const result = (0, import_editor.createFontSource)(bytes, face(family, weight, style));
|
|
406
|
-
if ("failure" in result) throw new Error(`Invalid packaged PDF font: ${file
|
|
471
|
+
if ("failure" in result) throw new Error(`Invalid packaged PDF font: ${String(file)}`);
|
|
407
472
|
return result.source;
|
|
408
473
|
})
|
|
409
474
|
);
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
475
|
+
const supplementalFonts2 = (0, import_editor.defineFontResolver)(async ({ families, signal }) => {
|
|
476
|
+
const wanted = /* @__PURE__ */ new Set();
|
|
477
|
+
for (const family of families) {
|
|
478
|
+
wanted.add(family);
|
|
413
479
|
const target = substituteFor(family);
|
|
414
|
-
if (
|
|
480
|
+
if (target) wanted.add(target);
|
|
481
|
+
}
|
|
482
|
+
const sources = await readFaces(
|
|
483
|
+
supplemental.filter(([family]) => wanted.has(family)),
|
|
484
|
+
signal
|
|
485
|
+
);
|
|
486
|
+
return {
|
|
487
|
+
sources,
|
|
488
|
+
substitutions: families.flatMap((family) => {
|
|
489
|
+
const target = substituteFor(family);
|
|
490
|
+
return target && target !== CJK_FAMILY ? substitutionsTo(family, target) : [];
|
|
491
|
+
})
|
|
492
|
+
};
|
|
493
|
+
});
|
|
494
|
+
const cjkFonts2 = (0, import_editor.defineFontResolver)(async ({ families, signal }) => {
|
|
495
|
+
const planned = families.filter((family) => substituteFor(family) === CJK_FAMILY);
|
|
496
|
+
if (!families.includes(CJK_FAMILY) && planned.length === 0) return { sources: [] };
|
|
497
|
+
let sources;
|
|
498
|
+
try {
|
|
499
|
+
const file = await cjkFace();
|
|
500
|
+
if (!file) return { sources: [] };
|
|
501
|
+
sources = await readFaces([[CJK_FAMILY, file, 400, "normal"]], signal);
|
|
502
|
+
} catch (error) {
|
|
503
|
+
if (signal?.aborted) throw error;
|
|
504
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
505
|
+
throw new Error(`${CJK_PACKAGE} could not supply its face: ${detail}`, { cause: error });
|
|
506
|
+
}
|
|
507
|
+
return {
|
|
508
|
+
sources,
|
|
509
|
+
substitutions: planned.flatMap((family) => substitutionsTo(family, CJK_FAMILY))
|
|
510
|
+
};
|
|
511
|
+
});
|
|
512
|
+
const standInFonts2 = (0, import_editor.defineFontResolver)(async ({ families, signal, resolvedFaces }) => {
|
|
513
|
+
const covered = new Set(
|
|
514
|
+
(resolvedFaces ?? []).map(
|
|
515
|
+
(face2) => `${face2.family.toLowerCase()}/${face2.weight}/${face2.style}`
|
|
516
|
+
)
|
|
517
|
+
);
|
|
518
|
+
const has = (family, weight, style) => covered.has(`${family.toLowerCase()}/${weight}/${style}`);
|
|
519
|
+
const faces = [
|
|
520
|
+
[400, "normal"],
|
|
521
|
+
[700, "normal"],
|
|
522
|
+
[400, "italic"],
|
|
523
|
+
[700, "italic"]
|
|
524
|
+
];
|
|
525
|
+
const substitutions = [];
|
|
526
|
+
const wanted = /* @__PURE__ */ new Set();
|
|
527
|
+
for (const family of families) {
|
|
528
|
+
if (has(family, 400, "normal")) {
|
|
529
|
+
for (const [weight, style] of faces)
|
|
530
|
+
if (!has(family, weight, style))
|
|
531
|
+
substitutions.push({ from: face(family, weight, style), to: face(family) });
|
|
532
|
+
continue;
|
|
533
|
+
}
|
|
534
|
+
const canonical = canonicalFamily(family).family;
|
|
535
|
+
if (knownFamilies.has(canonical) && !cjkWordFamilies.has(canonical)) continue;
|
|
536
|
+
const target = genericSubstituteFor(family);
|
|
537
|
+
wanted.add(target);
|
|
415
538
|
const { bold, italic } = canonicalFamily(family);
|
|
416
|
-
|
|
417
|
-
|
|
539
|
+
for (const [weight, style] of faces)
|
|
540
|
+
substitutions.push({
|
|
418
541
|
from: face(family, weight, style),
|
|
419
|
-
|
|
420
|
-
to: target.startsWith("Noto") ? face(target) : face(
|
|
542
|
+
to: face(
|
|
421
543
|
target,
|
|
422
544
|
bold || weight === 700 ? 700 : 400,
|
|
423
545
|
italic || style === "italic" ? "italic" : "normal"
|
|
424
546
|
)
|
|
425
|
-
})
|
|
426
|
-
);
|
|
427
|
-
})
|
|
428
|
-
};
|
|
429
|
-
});
|
|
430
|
-
var standInFonts = (0, import_editor.defineFontResolver)(async ({ families, signal, resolvedFaces }) => {
|
|
431
|
-
const covered = new Set(
|
|
432
|
-
(resolvedFaces ?? []).map((face2) => `${face2.family.toLowerCase()}/${face2.weight}/${face2.style}`)
|
|
433
|
-
);
|
|
434
|
-
const has = (family, weight, style) => covered.has(`${family.toLowerCase()}/${weight}/${style}`);
|
|
435
|
-
const faces = [
|
|
436
|
-
[400, "normal"],
|
|
437
|
-
[700, "normal"],
|
|
438
|
-
[400, "italic"],
|
|
439
|
-
[700, "italic"]
|
|
440
|
-
];
|
|
441
|
-
const substitutions = [];
|
|
442
|
-
const wanted = /* @__PURE__ */ new Set();
|
|
443
|
-
for (const family of families) {
|
|
444
|
-
if (has(family, 400, "normal")) {
|
|
445
|
-
for (const [weight, style] of faces)
|
|
446
|
-
if (!has(family, weight, style))
|
|
447
|
-
substitutions.push({ from: face(family, weight, style), to: face(family) });
|
|
448
|
-
continue;
|
|
547
|
+
});
|
|
449
548
|
}
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
return
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
549
|
+
const sources = await readFaces(
|
|
550
|
+
supplemental.filter(([family]) => wanted.has(family)),
|
|
551
|
+
signal
|
|
552
|
+
);
|
|
553
|
+
return { sources, substitutions };
|
|
554
|
+
});
|
|
555
|
+
return {
|
|
556
|
+
supplementalFonts: supplementalFonts2,
|
|
557
|
+
cjkFonts: cjkFonts2,
|
|
558
|
+
standInFonts: standInFonts2,
|
|
559
|
+
/**
|
|
560
|
+
* Whether a face resolved through the generic stand-in rather than a metric-compatible
|
|
561
|
+
* plan: a substitution whose family this package does not answer for, or a Word CJK
|
|
562
|
+
* family in its stand-in rather than the CJK face. The writer reports these, since the
|
|
563
|
+
* page carries the text in another font's metrics.
|
|
564
|
+
*/
|
|
565
|
+
isGenericSubstitution(family, sourceFamily) {
|
|
566
|
+
if (family === sourceFamily) return false;
|
|
567
|
+
const canonical = canonicalFamily(family).family;
|
|
568
|
+
if (cjkWordFamilies.has(canonical)) return sourceFamily === genericSubstituteFor(family);
|
|
569
|
+
return !knownFamilies.has(canonical);
|
|
570
|
+
},
|
|
571
|
+
/**
|
|
572
|
+
* What a missing-glyph report adds for `text`: the package to install, when the text is
|
|
573
|
+
* CJK and the lookup found no usable package. Empty otherwise.
|
|
574
|
+
*/
|
|
575
|
+
missingGlyphHint(text) {
|
|
576
|
+
return cjkMissing && CJK_TEXT.test(text) ? `; install ${CJK_PACKAGE} for Chinese, Japanese, and Korean text` : "";
|
|
577
|
+
}
|
|
578
|
+
};
|
|
579
|
+
}
|
|
580
|
+
var {
|
|
581
|
+
supplementalFonts,
|
|
582
|
+
cjkFonts,
|
|
583
|
+
standInFonts,
|
|
584
|
+
isGenericSubstitution,
|
|
585
|
+
missingGlyphHint
|
|
586
|
+
} = packagedFontResolvers();
|
|
474
587
|
var wordFontRoots = process.platform === "darwin" ? [
|
|
475
588
|
"/System/Library/Fonts/Supplemental",
|
|
476
589
|
"/Library/Fonts",
|
|
@@ -638,7 +751,8 @@ function openExportSession(source, options, signal) {
|
|
|
638
751
|
...useSystemFonts ? [installedWordFonts] : [],
|
|
639
752
|
bundledFonts,
|
|
640
753
|
...fallbackFonts ? Array.isArray(fallbackFonts) ? fallbackFonts : [fallbackFonts] : [],
|
|
641
|
-
supplementalFonts
|
|
754
|
+
supplementalFonts,
|
|
755
|
+
cjkFonts
|
|
642
756
|
];
|
|
643
757
|
return (0, import_export2.openFontBackedDocumentForExport)(source, {
|
|
644
758
|
...core,
|
|
@@ -694,7 +808,7 @@ function reportFontDiagnostics(resolution, work) {
|
|
|
694
808
|
}
|
|
695
809
|
|
|
696
810
|
// src/paint.ts
|
|
697
|
-
var
|
|
811
|
+
var import_layout6 = require("@docx-editor.dev/core/layout");
|
|
698
812
|
|
|
699
813
|
// src/text.ts
|
|
700
814
|
var import_pdf_lib2 = require("pdf-lib");
|
|
@@ -975,9 +1089,17 @@ var EmbeddedFace = class {
|
|
|
975
1089
|
throw new Error("Variable fonts require an exact static instance");
|
|
976
1090
|
this.font = font;
|
|
977
1091
|
this.colorLayers = Boolean(font.COLR && font.CPAL);
|
|
1092
|
+
const tables = font;
|
|
1093
|
+
const os2 = tables["OS/2"];
|
|
1094
|
+
const macStyle = tables.head?.macStyle;
|
|
1095
|
+
this.bold = (os2?.usWeightClass ?? 400) >= 600 || Boolean(os2?.fsSelection?.bold || macStyle?.bold);
|
|
1096
|
+
this.slanted = Boolean(os2?.fsSelection?.italic || os2?.fsSelection?.oblique || macStyle?.italic) || Number.isFinite(font.italicAngle) && font.italicAngle !== 0;
|
|
978
1097
|
this.family = admitted.request.family;
|
|
979
1098
|
this.strike = strikeMetrics(admitted);
|
|
980
1099
|
this.subset = font.createSubset();
|
|
1100
|
+
this.trueType = Boolean(
|
|
1101
|
+
font.directory?.tables?.glyf
|
|
1102
|
+
);
|
|
981
1103
|
this.ref = doc.context.nextRef();
|
|
982
1104
|
this.name = `F${index}`;
|
|
983
1105
|
}
|
|
@@ -992,9 +1114,18 @@ var EmbeddedFace = class {
|
|
|
992
1114
|
* glyph, and the page carries the text in its line's `ActualText` instead.
|
|
993
1115
|
*/
|
|
994
1116
|
colorLayers;
|
|
1117
|
+
/**
|
|
1118
|
+
* Whether the face's own outlines are bold or slanted. A bold or italic run drawn in a
|
|
1119
|
+
* face that is not (a single-weight face, or a substituted regular) gets Word's synthetic
|
|
1120
|
+
* style at paint; a real bold or italic face draws as it is.
|
|
1121
|
+
*/
|
|
1122
|
+
bold;
|
|
1123
|
+
slanted;
|
|
995
1124
|
/** The family this face was admitted under, for legacy symbol-encoding extraction. */
|
|
996
1125
|
family;
|
|
997
1126
|
subset;
|
|
1127
|
+
/** A `glyf` face, whose subset has a `loca` table; see {@link encodeSubset}. */
|
|
1128
|
+
trueType;
|
|
998
1129
|
codes = /* @__PURE__ */ new Map();
|
|
999
1130
|
rows = [];
|
|
1000
1131
|
widths = /* @__PURE__ */ new Map();
|
|
@@ -1016,7 +1147,7 @@ var EmbeddedFace = class {
|
|
|
1016
1147
|
let code = this.codes.get(key);
|
|
1017
1148
|
if (code === void 0) {
|
|
1018
1149
|
if (this.rows.length >= 65534) throw new Error("Font character code limit exceeded");
|
|
1019
|
-
const cid = this.
|
|
1150
|
+
const cid = this.cidFor(glyph, text);
|
|
1020
1151
|
if (!Number.isInteger(cid) || cid < 0 || cid > 65535)
|
|
1021
1152
|
throw new Error("Invalid subset glyph identifier");
|
|
1022
1153
|
code = this.rows.length + 1;
|
|
@@ -1026,6 +1157,60 @@ var EmbeddedFace = class {
|
|
|
1026
1157
|
}
|
|
1027
1158
|
return hex(code);
|
|
1028
1159
|
}
|
|
1160
|
+
/** The text each subset glyph first extracted as; see {@link cidFor}. */
|
|
1161
|
+
cidText = /* @__PURE__ */ new Map();
|
|
1162
|
+
/**
|
|
1163
|
+
* The subset glyph for one (glyph, text) pair.
|
|
1164
|
+
*
|
|
1165
|
+
* An Arabic face draws BEH, TEH, NOON and YEH on one dotless base glyph and adds the dots
|
|
1166
|
+
* as separate glyphs, so one glyph extracts as several letters. Codes already differ per
|
|
1167
|
+
* letter, but MuPDF resolves `ToUnicode` per CID, so one shared CID read every such letter
|
|
1168
|
+
* as the last one mapped. The subset takes the glyph again under a new CID, the way
|
|
1169
|
+
* LibreOffice's writer does. Both fontkit subsets write one entry per listed glyph: a
|
|
1170
|
+
* TrueType subset one `glyf` record, a CFF subset one charstring under a single charset
|
|
1171
|
+
* range, so the CID is the subset index either way.
|
|
1172
|
+
*
|
|
1173
|
+
* Bounded: no copy once the copies and every glyph composites could still pull in could
|
|
1174
|
+
* reach 65535, where the glyph count and component ids wrap. A TrueType subset with copies
|
|
1175
|
+
* is written with long `loca` offsets (see `encodeSubset`).
|
|
1176
|
+
*/
|
|
1177
|
+
cidFor(glyph, text) {
|
|
1178
|
+
const known = this.subset.mapping[glyph];
|
|
1179
|
+
if (known === void 0) {
|
|
1180
|
+
const cid2 = this.subset.includeGlyph(glyph);
|
|
1181
|
+
this.cidText.set(cid2, text);
|
|
1182
|
+
return cid2;
|
|
1183
|
+
}
|
|
1184
|
+
const glyphs = this.subset.glyphs;
|
|
1185
|
+
if (this.cidText.get(known) === text || !Array.isArray(glyphs)) return known;
|
|
1186
|
+
if (glyphs.length + this.font.numGlyphs >= 65535) return known;
|
|
1187
|
+
glyphs.push(glyph);
|
|
1188
|
+
this.copies += 1;
|
|
1189
|
+
const cid = glyphs.length - 1;
|
|
1190
|
+
this.cidText.set(cid, text);
|
|
1191
|
+
return cid;
|
|
1192
|
+
}
|
|
1193
|
+
/** Glyphs the subset lists more than once; see {@link cidFor}. */
|
|
1194
|
+
copies = 0;
|
|
1195
|
+
/**
|
|
1196
|
+
* Encode the subset. A TrueType face with short `loca` offsets can address 131070 bytes of
|
|
1197
|
+
* `glyf`, and fontkit copies the face's format into the subset; copies can pass that, and
|
|
1198
|
+
* the offsets then wrap and later glyphs draw other glyphs' outlines. fontkit reads the
|
|
1199
|
+
* format from the face's parsed `loca` (whose offsets are already decoded, so the format
|
|
1200
|
+
* no longer affects reads), so it says long while the subset encodes.
|
|
1201
|
+
*/
|
|
1202
|
+
encodeSubset() {
|
|
1203
|
+
const loca = this.font.loca;
|
|
1204
|
+
if (!this.trueType || this.copies === 0 || !loca || loca.version !== 0) {
|
|
1205
|
+
return this.subset.encode();
|
|
1206
|
+
}
|
|
1207
|
+
loca.version = 1;
|
|
1208
|
+
try {
|
|
1209
|
+
return this.subset.encode();
|
|
1210
|
+
} finally {
|
|
1211
|
+
loca.version = 0;
|
|
1212
|
+
}
|
|
1213
|
+
}
|
|
1029
1214
|
/**
|
|
1030
1215
|
* A code that draws this face's space and extracts as `text`: the carrier for characters
|
|
1031
1216
|
* painted some other way, such as the palette layers of a color emoji. Drawn invisibly, it
|
|
@@ -1052,7 +1237,7 @@ var EmbeddedFace = class {
|
|
|
1052
1237
|
async finish(work) {
|
|
1053
1238
|
if (this.colorLayers) return;
|
|
1054
1239
|
await work.yield();
|
|
1055
|
-
const bytes = this.
|
|
1240
|
+
const bytes = this.encodeSubset();
|
|
1056
1241
|
work.check();
|
|
1057
1242
|
const cff = bytes[0] === 1 && bytes[1] === 0;
|
|
1058
1243
|
const ctx = this.doc.context;
|
|
@@ -1131,8 +1316,54 @@ var EmbeddedFace = class {
|
|
|
1131
1316
|
};
|
|
1132
1317
|
|
|
1133
1318
|
// src/color-glyphs.ts
|
|
1319
|
+
var import_export3 = require("@docx-editor.dev/core/export");
|
|
1134
1320
|
var MAX_LAYERS = 256;
|
|
1135
1321
|
var MAX_COMMANDS = 8192;
|
|
1322
|
+
var MAX_COMPOSITE_DEPTH = 8;
|
|
1323
|
+
var MAX_EXPANDED_POINTS = MAX_COMMANDS;
|
|
1324
|
+
var pathSafety = /* @__PURE__ */ new WeakMap();
|
|
1325
|
+
function pathIsSafe(font, glyph) {
|
|
1326
|
+
const cached = pathSafety.get(glyph);
|
|
1327
|
+
if (cached !== void 0) return cached;
|
|
1328
|
+
let safe;
|
|
1329
|
+
try {
|
|
1330
|
+
const { points, height } = expanded(font, glyph, 0, /* @__PURE__ */ new Map(), /* @__PURE__ */ new Set());
|
|
1331
|
+
safe = points <= MAX_EXPANDED_POINTS && height <= MAX_COMPOSITE_DEPTH;
|
|
1332
|
+
} catch {
|
|
1333
|
+
safe = false;
|
|
1334
|
+
}
|
|
1335
|
+
pathSafety.set(glyph, safe);
|
|
1336
|
+
return safe;
|
|
1337
|
+
}
|
|
1338
|
+
function expanded(font, glyph, depth, memo, open) {
|
|
1339
|
+
const cached = memo.get(glyph);
|
|
1340
|
+
if (cached) return cached;
|
|
1341
|
+
if (depth > MAX_COMPOSITE_DEPTH || open.has(glyph)) return { points: Infinity, height: Infinity };
|
|
1342
|
+
const decode = glyph._decode;
|
|
1343
|
+
if (typeof decode !== "function") return { points: 0, height: 0 };
|
|
1344
|
+
const decoded = decode.call(glyph);
|
|
1345
|
+
let points = (decoded?.points?.length ?? 0) + 1;
|
|
1346
|
+
let height = 0;
|
|
1347
|
+
open.add(glyph);
|
|
1348
|
+
for (const component of decoded?.components ?? []) {
|
|
1349
|
+
const child = expanded(font, font.getGlyph(component.glyphID), depth + 1, memo, open);
|
|
1350
|
+
points += child.points;
|
|
1351
|
+
height = Math.max(height, child.height + 1);
|
|
1352
|
+
if (points > MAX_EXPANDED_POINTS || height > MAX_COMPOSITE_DEPTH) break;
|
|
1353
|
+
}
|
|
1354
|
+
open.delete(glyph);
|
|
1355
|
+
const result = { points, height };
|
|
1356
|
+
memo.set(glyph, result);
|
|
1357
|
+
return result;
|
|
1358
|
+
}
|
|
1359
|
+
function boundedPathCommands(font, glyph) {
|
|
1360
|
+
if (!pathIsSafe(font, glyph)) return null;
|
|
1361
|
+
try {
|
|
1362
|
+
return glyph.path.commands;
|
|
1363
|
+
} catch {
|
|
1364
|
+
return null;
|
|
1365
|
+
}
|
|
1366
|
+
}
|
|
1136
1367
|
var cache = /* @__PURE__ */ new WeakMap();
|
|
1137
1368
|
function colorGlyph(font, glyphId, work) {
|
|
1138
1369
|
let byGlyph = cache.get(font);
|
|
@@ -1142,21 +1373,30 @@ function colorGlyph(font, glyphId, work) {
|
|
|
1142
1373
|
}
|
|
1143
1374
|
const known = byGlyph.get(glyphId);
|
|
1144
1375
|
if (known) return known;
|
|
1145
|
-
|
|
1376
|
+
let result;
|
|
1377
|
+
try {
|
|
1378
|
+
result = readColorGlyph(font, glyphId, work);
|
|
1379
|
+
} catch (error) {
|
|
1380
|
+
if (error instanceof PdfWorkLimitError || error instanceof import_export3.ExportResourceError) throw error;
|
|
1381
|
+
result = { kind: "refused", reason: "the color glyph could not be read" };
|
|
1382
|
+
}
|
|
1146
1383
|
byGlyph.set(glyphId, result);
|
|
1147
1384
|
return result;
|
|
1148
1385
|
}
|
|
1149
1386
|
function readColorGlyph(font, glyphId, work) {
|
|
1150
1387
|
const glyph = font.getGlyph(glyphId);
|
|
1151
1388
|
const layers = glyph.layers;
|
|
1152
|
-
if (!layers || layers.length === 0)
|
|
1153
|
-
|
|
1389
|
+
if (!layers || layers.length === 0) {
|
|
1390
|
+
const commands = boundedPathCommands(font, glyph);
|
|
1391
|
+
return { kind: "none", outlined: commands === null || commands.length > 0 };
|
|
1392
|
+
}
|
|
1154
1393
|
if (layers.length > MAX_LAYERS)
|
|
1155
1394
|
return { kind: "refused", reason: `${layers.length} layers exceed the ${MAX_LAYERS} allowed` };
|
|
1156
1395
|
const out = [];
|
|
1157
1396
|
for (const layer of layers) {
|
|
1158
1397
|
work.tick();
|
|
1159
|
-
const
|
|
1398
|
+
const commands = boundedPathCommands(font, layer.glyph);
|
|
1399
|
+
const path = commands && pathOperators(commands, work);
|
|
1160
1400
|
if (path === null)
|
|
1161
1401
|
return { kind: "refused", reason: "a layer outline is malformed or too long" };
|
|
1162
1402
|
if (!path) continue;
|
|
@@ -1169,6 +1409,19 @@ function readColorGlyph(font, glyphId, work) {
|
|
|
1169
1409
|
}
|
|
1170
1410
|
return { kind: "layers", layers: out };
|
|
1171
1411
|
}
|
|
1412
|
+
var outlines = /* @__PURE__ */ new WeakMap();
|
|
1413
|
+
function glyphOutline(font, glyphId, work) {
|
|
1414
|
+
let byGlyph = outlines.get(font);
|
|
1415
|
+
if (!byGlyph) {
|
|
1416
|
+
byGlyph = /* @__PURE__ */ new Map();
|
|
1417
|
+
outlines.set(font, byGlyph);
|
|
1418
|
+
}
|
|
1419
|
+
if (byGlyph.has(glyphId)) return byGlyph.get(glyphId);
|
|
1420
|
+
const commands = boundedPathCommands(font, font.getGlyph(glyphId));
|
|
1421
|
+
const path = commands && pathOperators(commands, work);
|
|
1422
|
+
byGlyph.set(glyphId, path);
|
|
1423
|
+
return path;
|
|
1424
|
+
}
|
|
1172
1425
|
function clampByte(value) {
|
|
1173
1426
|
return Number.isFinite(value) ? Math.min(255, Math.max(0, Math.round(value))) : 0;
|
|
1174
1427
|
}
|
|
@@ -1216,6 +1469,35 @@ function pathOperators(commands, work) {
|
|
|
1216
1469
|
return out.join(" ");
|
|
1217
1470
|
}
|
|
1218
1471
|
|
|
1472
|
+
// src/outline-placement.ts
|
|
1473
|
+
var MAX_OUTLINE_MOVE = 1e5;
|
|
1474
|
+
var movable = (value) => Number.isFinite(value) && Math.abs(value) <= MAX_OUTLINE_MOVE;
|
|
1475
|
+
function outlineOperators(placements) {
|
|
1476
|
+
const out = [];
|
|
1477
|
+
let group = null;
|
|
1478
|
+
let [ra, rc, rd, px, py] = [1, 0, 1, 0, 0];
|
|
1479
|
+
for (const placement of placements) {
|
|
1480
|
+
const same = group !== null && group.state === placement.state && group.a === placement.a && group.c === placement.c && group.d === placement.d;
|
|
1481
|
+
const rawV = same && rd !== 0 ? (placement.y - py) / rd : NaN;
|
|
1482
|
+
const v = movable(rawV) ? Number(number(rawV)) : NaN;
|
|
1483
|
+
const rawU = movable(v) && ra !== 0 ? (placement.x - px - rc * v) / ra : NaN;
|
|
1484
|
+
const u = movable(rawU) ? Number(number(rawU)) : NaN;
|
|
1485
|
+
if (movable(u) && movable(v)) {
|
|
1486
|
+
out.push(`1 0 0 1 ${number(u)} ${number(v)} cm /${placement.form} Do`);
|
|
1487
|
+
px += ra * u + rc * v;
|
|
1488
|
+
py += rd * v;
|
|
1489
|
+
continue;
|
|
1490
|
+
}
|
|
1491
|
+
if (group) out.push("Q");
|
|
1492
|
+
group = placement;
|
|
1493
|
+
const { a, c, d, x, y } = placement;
|
|
1494
|
+
out.push(`q ${placement.state}${[a, 0, c, d, x, y].map(number).join(" ")} cm /${placement.form} Do`);
|
|
1495
|
+
[ra, rc, rd, px, py] = [a, c, d, x, y].map((value) => Number(number(value)));
|
|
1496
|
+
}
|
|
1497
|
+
if (group) out.push("Q");
|
|
1498
|
+
return out.join("\n");
|
|
1499
|
+
}
|
|
1500
|
+
|
|
1219
1501
|
// src/text.ts
|
|
1220
1502
|
var PDF_PAINT_GRID_PT2 = 0.24;
|
|
1221
1503
|
function reducedHalfPoints(fontSizePt, factor) {
|
|
@@ -1236,6 +1518,20 @@ function griddedBaselineInLine(line, face2, paragraph) {
|
|
|
1236
1518
|
return units(line.baseline) * PDF_PAINT_GRID_PT2;
|
|
1237
1519
|
return (units(naturalBox) - units(descent)) * PDF_PAINT_GRID_PT2;
|
|
1238
1520
|
}
|
|
1521
|
+
var SYNTHETIC_ITALIC_SKEW = 87 / 256;
|
|
1522
|
+
var SYNTHETIC_BOLD_VERTICAL = 1 / 1.02;
|
|
1523
|
+
var syntheticBoldStrokePt = (size) => size / 50 + 0.12;
|
|
1524
|
+
var rightToLeftLines = /* @__PURE__ */ new WeakMap();
|
|
1525
|
+
function rightToLeftOnly(line) {
|
|
1526
|
+
let known = rightToLeftLines.get(line);
|
|
1527
|
+
if (known === void 0) {
|
|
1528
|
+
known = line.spans.every(
|
|
1529
|
+
(span) => !/\S/u.test(span.text) || (span.style.shaping?.level ?? 0) % 2 === 1
|
|
1530
|
+
);
|
|
1531
|
+
rightToLeftLines.set(line, known);
|
|
1532
|
+
}
|
|
1533
|
+
return known;
|
|
1534
|
+
}
|
|
1239
1535
|
var MAX_TJ_ADJUSTMENT = 1e6;
|
|
1240
1536
|
function penOrigins(run) {
|
|
1241
1537
|
const advances = run.exactAdvancesX;
|
|
@@ -1255,15 +1551,28 @@ function createGlyphBatch(out, horizontal) {
|
|
|
1255
1551
|
let startX = 0;
|
|
1256
1552
|
let penX = 0;
|
|
1257
1553
|
let parts = [];
|
|
1554
|
+
let skew = 0;
|
|
1555
|
+
let vertical = 1;
|
|
1556
|
+
let rise = 0;
|
|
1258
1557
|
const flush = () => {
|
|
1259
1558
|
if (parts.length === 0) return;
|
|
1260
1559
|
const show = parts.length === 1 && parts[0].startsWith("<") ? `${parts[0]} Tj` : `[${parts.join("")}] TJ`;
|
|
1261
|
-
out.push(
|
|
1560
|
+
out.push(
|
|
1561
|
+
`${number(horizontal)} 0 ${number(skew * vertical)} ${number(vertical)} ${number(startX)} ${number(baselineY + rise)} Tm ${show}`
|
|
1562
|
+
);
|
|
1262
1563
|
parts = [];
|
|
1263
1564
|
face2 = null;
|
|
1264
1565
|
};
|
|
1265
1566
|
return {
|
|
1266
1567
|
flush,
|
|
1568
|
+
/** Change the synthetic matrix; the next glyph starts a new batch when it changes. */
|
|
1569
|
+
matrix(nextSkew, nextVertical, nextRise) {
|
|
1570
|
+
if (nextSkew === skew && nextVertical === vertical && nextRise === rise) return;
|
|
1571
|
+
flush();
|
|
1572
|
+
skew = nextSkew;
|
|
1573
|
+
vertical = nextVertical;
|
|
1574
|
+
rise = nextRise;
|
|
1575
|
+
},
|
|
1267
1576
|
add(nextFace, nextSize, gx, gy, code) {
|
|
1268
1577
|
const unit = nextSize * horizontal;
|
|
1269
1578
|
const continues = face2 === nextFace && size === nextSize && baselineY === gy && unit !== 0;
|
|
@@ -1297,6 +1606,14 @@ var TextWriter = class {
|
|
|
1297
1606
|
work;
|
|
1298
1607
|
showRevisionMarkup;
|
|
1299
1608
|
faces = /* @__PURE__ */ new Map();
|
|
1609
|
+
/** Outline glyphs of the current line, for {@link takeOutlines}. */
|
|
1610
|
+
pendingOutlines = [];
|
|
1611
|
+
/** The outline glyphs painted since the last call; the caller places them after a line. */
|
|
1612
|
+
takeOutlines() {
|
|
1613
|
+
const taken = this.pendingOutlines.length > 0 ? outlineOperators(this.pendingOutlines) : "";
|
|
1614
|
+
this.pendingOutlines = [];
|
|
1615
|
+
return taken;
|
|
1616
|
+
}
|
|
1300
1617
|
refused = /* @__PURE__ */ new Map();
|
|
1301
1618
|
paint(visit, page) {
|
|
1302
1619
|
const { span, line, storyOrigin, absoluteBox } = visit;
|
|
@@ -1318,7 +1635,10 @@ var TextWriter = class {
|
|
|
1318
1635
|
`Core could not provide exact shaping for a visible span in ${family}`
|
|
1319
1636
|
);
|
|
1320
1637
|
if (shaped.run.glyphs.some((g) => g.id === 0))
|
|
1321
|
-
return report(
|
|
1638
|
+
return report(
|
|
1639
|
+
"missing-glyph",
|
|
1640
|
+
`A visible span in ${family} contains missing glyphs${missingGlyphHint(span.text)}`
|
|
1641
|
+
);
|
|
1322
1642
|
const face2 = this.embeddedFace(shaped.font, visit, page);
|
|
1323
1643
|
if (!face2) return "";
|
|
1324
1644
|
const style = (0, import_layout4.styleForFontSlot)(span.style, span.fontSlot);
|
|
@@ -1348,7 +1668,11 @@ var TextWriter = class {
|
|
|
1348
1668
|
const origins = penOrigins(shaped.run);
|
|
1349
1669
|
const batch = createGlyphBatch(out, horizontal);
|
|
1350
1670
|
const colorGlyphs = [];
|
|
1671
|
+
const outlineGlyphs = [];
|
|
1672
|
+
const rightToLeft = (style.shaping?.level ?? 0) % 2 === 1;
|
|
1351
1673
|
let extra = 0;
|
|
1674
|
+
let strokeWidth = 0;
|
|
1675
|
+
let stroked = false;
|
|
1352
1676
|
let activeSize = size;
|
|
1353
1677
|
let activeFace = face2;
|
|
1354
1678
|
let activeIdentity = shaped.font.identity;
|
|
@@ -1363,6 +1687,9 @@ var TextWriter = class {
|
|
|
1363
1687
|
if (!activeFace.colorLayers) out.push(`/${activeFace.name} ${number(activeSize)} Tf`);
|
|
1364
1688
|
}
|
|
1365
1689
|
const text = shaped.run.text.slice(cluster.textStart, cluster.textEnd);
|
|
1690
|
+
let textGlyph = cluster.glyphStart;
|
|
1691
|
+
for (let i = cluster.glyphStart + 1; i < cluster.glyphEnd; i++)
|
|
1692
|
+
if (shaped.run.glyphs[i].advanceX > shaped.run.glyphs[textGlyph].advanceX) textGlyph = i;
|
|
1366
1693
|
for (let i = cluster.glyphStart; i < cluster.glyphEnd; i++) {
|
|
1367
1694
|
this.work.tick();
|
|
1368
1695
|
const glyph = shaped.run.glyphs[i];
|
|
@@ -1405,17 +1732,92 @@ var TextWriter = class {
|
|
|
1405
1732
|
batch.add(host, activeSize, gx, gy, carrier);
|
|
1406
1733
|
batch.flush();
|
|
1407
1734
|
out.push("0 Tr 100 Tz");
|
|
1735
|
+
strokeWidth = 0;
|
|
1408
1736
|
}
|
|
1409
1737
|
continue;
|
|
1410
1738
|
}
|
|
1411
|
-
const
|
|
1412
|
-
|
|
1739
|
+
const synthesizeBold = style.bold && !style.textOutline && !activeFace.bold;
|
|
1740
|
+
const width = synthesizeBold ? syntheticBoldStrokePt(activeSize) : 0;
|
|
1741
|
+
if (width !== strokeWidth) {
|
|
1742
|
+
batch.flush();
|
|
1743
|
+
if (width > 0 && !stroked) out.push(`${color(foreground)} RG`);
|
|
1744
|
+
stroked ||= width > 0;
|
|
1745
|
+
out.push(width > 0 ? `${number(width)} w 2 Tr` : "0 Tr");
|
|
1746
|
+
strokeWidth = width;
|
|
1747
|
+
}
|
|
1748
|
+
batch.matrix(
|
|
1749
|
+
style.italic && !activeFace.slanted ? SYNTHETIC_ITALIC_SKEW : 0,
|
|
1750
|
+
width > 0 ? SYNTHETIC_BOLD_VERTICAL : 1,
|
|
1751
|
+
width > 0 ? width / 2 * SYNTHETIC_BOLD_VERTICAL : 0
|
|
1752
|
+
);
|
|
1753
|
+
if (rightToLeft && /^ +$/.test(text) && rightToLeftOnly(line)) continue;
|
|
1754
|
+
if (i === textGlyph) {
|
|
1755
|
+
batch.add(activeFace, activeSize, gx, gy, activeFace.encode(glyph.id, text));
|
|
1756
|
+
continue;
|
|
1757
|
+
}
|
|
1758
|
+
const outline = glyphOutline(activeFace.font, glyph.id, this.work);
|
|
1759
|
+
if (outline === null) {
|
|
1760
|
+
this.work.report(
|
|
1761
|
+
"glyph-outline",
|
|
1762
|
+
`A glyph outline in ${family} is malformed or too long`,
|
|
1763
|
+
visit.page.index
|
|
1764
|
+
);
|
|
1765
|
+
continue;
|
|
1766
|
+
}
|
|
1767
|
+
if (outline) {
|
|
1768
|
+
outlineGlyphs.push({
|
|
1769
|
+
face: activeFace,
|
|
1770
|
+
id: glyph.id,
|
|
1771
|
+
path: outline,
|
|
1772
|
+
x: gx,
|
|
1773
|
+
y: gy + (width > 0 ? width / 2 * SYNTHETIC_BOLD_VERTICAL : 0),
|
|
1774
|
+
scale: glyphSize / activeFace.font.unitsPerEm,
|
|
1775
|
+
skew: style.italic && !activeFace.slanted ? SYNTHETIC_ITALIC_SKEW : 0,
|
|
1776
|
+
vertical: width > 0 ? SYNTHETIC_BOLD_VERTICAL : 1,
|
|
1777
|
+
strokeWidth: width
|
|
1778
|
+
});
|
|
1779
|
+
}
|
|
1413
1780
|
}
|
|
1414
1781
|
extra += text.length * style.characterSpacingPt + (text.match(/ /g)?.length ?? 0) * (style.shaping?.wordSpacingPt ?? 0);
|
|
1415
1782
|
}
|
|
1416
1783
|
batch.flush();
|
|
1784
|
+
if (strokeWidth > 0) out.push("0 Tr");
|
|
1417
1785
|
out.push("ET");
|
|
1418
1786
|
if (style.textOutline) out.push("Q");
|
|
1787
|
+
const placements = [];
|
|
1788
|
+
for (const glyph of outlineGlyphs) {
|
|
1789
|
+
const matrix = [
|
|
1790
|
+
glyph.scale * horizontal,
|
|
1791
|
+
0,
|
|
1792
|
+
glyph.skew * glyph.scale * glyph.vertical,
|
|
1793
|
+
glyph.scale * glyph.vertical,
|
|
1794
|
+
glyph.x,
|
|
1795
|
+
glyph.y
|
|
1796
|
+
];
|
|
1797
|
+
const outlineStroke = style.textOutline ? { color: style.textOutline.color, width: style.textOutline.widthPt } : glyph.strokeWidth > 0 ? { color: foreground, width: glyph.strokeWidth } : null;
|
|
1798
|
+
const stroke = outlineStroke ? `${color(outlineStroke.color)} RG ${number(outlineStroke.width / (glyph.scale * glyph.vertical))} w ` : "";
|
|
1799
|
+
const form = this.outlineForm(
|
|
1800
|
+
glyph.face,
|
|
1801
|
+
glyph.id,
|
|
1802
|
+
glyph.path,
|
|
1803
|
+
outlineStroke ? "B" : "f",
|
|
1804
|
+
page
|
|
1805
|
+
);
|
|
1806
|
+
placements.push({
|
|
1807
|
+
state: `${color(foreground)} rg ${stroke}`,
|
|
1808
|
+
a: matrix[0],
|
|
1809
|
+
c: matrix[2],
|
|
1810
|
+
d: matrix[3],
|
|
1811
|
+
x: glyph.x,
|
|
1812
|
+
y: glyph.y,
|
|
1813
|
+
form
|
|
1814
|
+
});
|
|
1815
|
+
}
|
|
1816
|
+
if (visit.paragraph.clipToBox) {
|
|
1817
|
+
if (placements.length > 0) out.push(outlineOperators(placements));
|
|
1818
|
+
} else {
|
|
1819
|
+
for (const placement of placements) this.pendingOutlines.push(placement);
|
|
1820
|
+
}
|
|
1419
1821
|
for (const { layers, x: gx, y: gy, scale: glyphScale } of colorGlyphs) {
|
|
1420
1822
|
out.push(`q ${number(glyphScale * horizontal)} 0 0 ${number(glyphScale)} ${number(gx)} ${number(gy)} cm`);
|
|
1421
1823
|
for (const layer of layers) {
|
|
@@ -1566,6 +1968,36 @@ var TextWriter = class {
|
|
|
1566
1968
|
const top = line.box.y + line.baseline - faceBaseline - (0, import_layout4.baselineShiftPtOf)((0, import_layout4.styleForFontSlot)(span.style, span.fontSlot));
|
|
1567
1969
|
return { ...absoluteBox, y: absoluteBox.y + (top - span.box.y) };
|
|
1568
1970
|
}
|
|
1971
|
+
outlineForms = /* @__PURE__ */ new Map();
|
|
1972
|
+
/**
|
|
1973
|
+
* A form XObject that paints one glyph outline in font units, registered on the page.
|
|
1974
|
+
*
|
|
1975
|
+
* The same few dot and mark glyphs repeat across a page, so each outline is written once
|
|
1976
|
+
* per face and paint operator and placed with `Do`. The form sets no colour or width, so
|
|
1977
|
+
* the caller's fill, stroke and line width apply.
|
|
1978
|
+
*/
|
|
1979
|
+
outlineForm(face2, glyphId, path, operator, page) {
|
|
1980
|
+
let forms = this.outlineForms.get(face2);
|
|
1981
|
+
if (!forms) this.outlineForms.set(face2, forms = /* @__PURE__ */ new Map());
|
|
1982
|
+
const key = `${glyphId}:${operator}`;
|
|
1983
|
+
let form = forms.get(key);
|
|
1984
|
+
if (!form) {
|
|
1985
|
+
this.work.reserveContent(path.length + 2);
|
|
1986
|
+
const margin = face2.font.unitsPerEm / 4;
|
|
1987
|
+
const bbox = face2.font.bbox;
|
|
1988
|
+
const ref = this.doc.context.register(
|
|
1989
|
+
flateStream(this.doc.context, `${path} ${operator}`, {
|
|
1990
|
+
Type: "XObject",
|
|
1991
|
+
Subtype: "Form",
|
|
1992
|
+
BBox: [bbox.minX - margin, bbox.minY - margin, bbox.maxX + margin, bbox.maxY + margin]
|
|
1993
|
+
})
|
|
1994
|
+
);
|
|
1995
|
+
form = { name: `${face2.name}G${forms.size + 1}`, ref };
|
|
1996
|
+
forms.set(key, form);
|
|
1997
|
+
}
|
|
1998
|
+
page.node.setXObject(import_pdf_lib2.PDFName.of(form.name), form.ref);
|
|
1999
|
+
return form.name;
|
|
2000
|
+
}
|
|
1569
2001
|
alphaStates = /* @__PURE__ */ new Map();
|
|
1570
2002
|
/** A registered constant-alpha graphics state, shared across layers of the same alpha. */
|
|
1571
2003
|
alphaState(page, alpha) {
|
|
@@ -1808,17 +2240,20 @@ var import_pdf_lib5 = require("pdf-lib");
|
|
|
1808
2240
|
|
|
1809
2241
|
// src/vector-shapes.ts
|
|
1810
2242
|
var import_pdf_lib4 = require("pdf-lib");
|
|
2243
|
+
var import_layout5 = require("@docx-editor.dev/core/layout");
|
|
1811
2244
|
function paintVectorShape(doc, page, visit, work) {
|
|
1812
2245
|
const d = visit.drawing;
|
|
1813
2246
|
const shape = d.vectorShape;
|
|
1814
|
-
const
|
|
2247
|
+
const painted = visit.absolutePaintBounds;
|
|
2248
|
+
const bounds = (0, import_layout5.vectorShapeInkClip)(d, painted);
|
|
1815
2249
|
if (bounds.width <= 0 || bounds.height <= 0 || d.accessibility.hidden) return "";
|
|
1816
2250
|
const content = d.geometry.contentBounds;
|
|
1817
2251
|
const x = visit.drawingOrigin.x - d.x - visit.page.box.x;
|
|
1818
2252
|
const y = visit.drawingOrigin.y - d.y - visit.page.box.y;
|
|
1819
2253
|
const unit = 12700;
|
|
1820
|
-
const
|
|
1821
|
-
const
|
|
2254
|
+
const { cx, cy } = shape.extentEmu;
|
|
2255
|
+
const sx = cx > 0 ? content.width / (cx / unit) : content.height / (cy / unit);
|
|
2256
|
+
const sy = cy > 0 ? content.height / (cy / unit) : sx;
|
|
1822
2257
|
const out = new Commands(work);
|
|
1823
2258
|
out.push(
|
|
1824
2259
|
`q ${rect(bounds, -visit.page.box.x, -visit.page.box.y, pageHeight(page))} W n`,
|
|
@@ -1846,16 +2281,20 @@ function paintVectorShape(doc, page, visit, work) {
|
|
|
1846
2281
|
const stateName = `ShapeAlpha${state.objectNumber}`;
|
|
1847
2282
|
page.node.setExtGState(import_pdf_lib4.PDFName.of(stateName), state);
|
|
1848
2283
|
out.push(`q /${stateName} gs`);
|
|
2284
|
+
const inset = component.strokeInset === true && component.strokeHex !== null;
|
|
2285
|
+
const width = Math.max(1, component.strokeWidthEmu) * (inset ? 2 : 1);
|
|
1849
2286
|
if (component.fillHex !== null) out.push(`${color(component.fillHex)} rg`);
|
|
1850
2287
|
if (component.strokeHex !== null)
|
|
2288
|
+
out.push(`${color(component.strokeHex)} RG ${number(width / unit)} w`);
|
|
2289
|
+
const geometry = component.subpathsEmu.map((points, index) => path(points, component.subpathsClosed?.[index] !== false)).join("\n");
|
|
2290
|
+
if (inset) {
|
|
2291
|
+
out.push(`q ${geometry} W* n`, geometry, component.fillHex !== null ? "B* Q" : "S Q");
|
|
2292
|
+
} else {
|
|
2293
|
+
out.push(geometry);
|
|
1851
2294
|
out.push(
|
|
1852
|
-
|
|
2295
|
+
component.fillHex !== null ? component.strokeHex !== null ? "B*" : "f*" : component.strokeHex !== null ? "S" : "n"
|
|
1853
2296
|
);
|
|
1854
|
-
|
|
1855
|
-
out.push(path(points, component.subpathsClosed?.[index] !== false));
|
|
1856
|
-
out.push(
|
|
1857
|
-
component.fillHex !== null ? component.strokeHex !== null ? "B*" : "f*" : component.strokeHex !== null ? "S" : "n"
|
|
1858
|
-
);
|
|
2297
|
+
}
|
|
1859
2298
|
if (component.strokeHex !== null && component.arrowheadsEmu?.length) {
|
|
1860
2299
|
const arrowState = doc.context.register(
|
|
1861
2300
|
doc.context.obj({
|
|
@@ -1873,14 +2312,15 @@ function paintVectorShape(doc, page, visit, work) {
|
|
|
1873
2312
|
out.push("Q");
|
|
1874
2313
|
const uri = d.hyperlinkHref && /^(https?:|mailto:|tel:|ftp:)/i.test(d.hyperlinkHref) ? pdfLiteralUri(d.hyperlinkHref) : null;
|
|
1875
2314
|
if (uri !== null) {
|
|
1876
|
-
const
|
|
1877
|
-
const
|
|
2315
|
+
const target = painted.width > 0 && painted.height > 0 ? painted : bounds;
|
|
2316
|
+
const left = target.x - visit.page.box.x;
|
|
2317
|
+
const bottom = pageHeight(page) - target.y + visit.page.box.y - target.height;
|
|
1878
2318
|
page.node.addAnnot(
|
|
1879
2319
|
doc.context.register(
|
|
1880
2320
|
doc.context.obj({
|
|
1881
2321
|
Type: "Annot",
|
|
1882
2322
|
Subtype: "Link",
|
|
1883
|
-
Rect: [left, bottom, left +
|
|
2323
|
+
Rect: [left, bottom, left + target.width, bottom + target.height],
|
|
1884
2324
|
Border: [0, 0, 0],
|
|
1885
2325
|
A: { S: "URI", URI: import_pdf_lib4.PDFString.of(uri) }
|
|
1886
2326
|
})
|
|
@@ -2015,14 +2455,51 @@ var ImageWriter = class {
|
|
|
2015
2455
|
async paint(visit, page) {
|
|
2016
2456
|
await this.work.yield();
|
|
2017
2457
|
const d = visit.drawing;
|
|
2458
|
+
if (d.accessibility.hidden) return "";
|
|
2018
2459
|
const report = (message) => {
|
|
2019
2460
|
this.work.report("drawing", message, visit.page.index);
|
|
2020
2461
|
return "";
|
|
2021
2462
|
};
|
|
2463
|
+
if (d.groupPicture) return this.paintGroupPicture(visit, page, report);
|
|
2022
2464
|
if (d.vectorShape) return paintVectorShape(this.doc, page, visit, this.work);
|
|
2023
2465
|
if (d.kind === "anchoredDrawing" && d.textboxStory)
|
|
2024
2466
|
return report("Textbox story not routed through paintTextbox");
|
|
2025
2467
|
if (d.placeholderGraphicKind) return report(`Unsupported drawing: ${d.placeholderGraphicKind}`);
|
|
2468
|
+
return this.paintPicture(visit, page, report);
|
|
2469
|
+
}
|
|
2470
|
+
/**
|
|
2471
|
+
* A shape group with a picture member: the picture, then the group's vector members over it.
|
|
2472
|
+
*
|
|
2473
|
+
* The group paints whole or not at all, as it does on screen. Layout already drops an
|
|
2474
|
+
* `mc:AlternateContent` group whose picture resource fails, following the rule for MC
|
|
2475
|
+
* payloads the engine cannot draw. A ready picture in a format this writer cannot embed
|
|
2476
|
+
* gets the same rule here: the MC group is left out and reported at `information`, because
|
|
2477
|
+
* the editor draws it and only this output cannot. A bare group reports every refusal as
|
|
2478
|
+
* `unsupported`, as it reports an unsupported group.
|
|
2479
|
+
*/
|
|
2480
|
+
async paintGroupPicture(visit, page, report) {
|
|
2481
|
+
const d = visit.drawing;
|
|
2482
|
+
const { resource } = d;
|
|
2483
|
+
if (d.groupPicture?.alternateContent && resource.kind === "ready" && !EMBEDDABLE_MIMES.has(resource.mime)) {
|
|
2484
|
+
this.work.report(
|
|
2485
|
+
"drawing",
|
|
2486
|
+
`Shape group left out: picture format not embeddable: ${resource.mime}`,
|
|
2487
|
+
visit.page.index,
|
|
2488
|
+
"information"
|
|
2489
|
+
);
|
|
2490
|
+
return "";
|
|
2491
|
+
}
|
|
2492
|
+
let refused = false;
|
|
2493
|
+
const picture = await this.paintPicture(visit, page, (message) => {
|
|
2494
|
+
refused = true;
|
|
2495
|
+
return report(message);
|
|
2496
|
+
});
|
|
2497
|
+
if (refused) return "";
|
|
2498
|
+
const vector = d.vectorShape ? paintVectorShape(this.doc, page, visit, this.work) : "";
|
|
2499
|
+
return [picture, vector].filter((commands) => commands !== "").join("\n");
|
|
2500
|
+
}
|
|
2501
|
+
async paintPicture(visit, page, report) {
|
|
2502
|
+
const d = visit.drawing;
|
|
2026
2503
|
const bytes = this.session.validatedImageBytes(d);
|
|
2027
2504
|
if (!bytes || d.resource.kind !== "ready") return report("Image has no validated raster bytes");
|
|
2028
2505
|
const mime = d.resource.mime;
|
|
@@ -2320,6 +2797,12 @@ async function paint(doc, session, layout, work, includeComments) {
|
|
|
2320
2797
|
`0 0 0 rg ${rect(separator, record.contentBox.x - record.box.x, record.contentBox.y - record.box.y, height, true)} f`
|
|
2321
2798
|
);
|
|
2322
2799
|
for (const area of [record.footnotes, record.endnotes]) {
|
|
2800
|
+
if (area?.fallbackReason === "note-continuation-notice-height-cap")
|
|
2801
|
+
work.report(
|
|
2802
|
+
area.fallbackReason,
|
|
2803
|
+
"Continuation notice exceeds the available page height",
|
|
2804
|
+
record.index
|
|
2805
|
+
);
|
|
2323
2806
|
const sep = area?.separator;
|
|
2324
2807
|
if (!sep || !(sep.ruleStyle || sep.synthetic)) continue;
|
|
2325
2808
|
for (const offset of sep.ruleStyle === "double" ? [0, 2] : [0])
|
|
@@ -2332,15 +2815,15 @@ async function paint(doc, session, layout, work, includeComments) {
|
|
|
2332
2815
|
const drawings = [];
|
|
2333
2816
|
for (const warning of layout.contentWarnings ?? [])
|
|
2334
2817
|
work.report(`core-${warning.code}`, warning.code);
|
|
2335
|
-
(0,
|
|
2818
|
+
(0, import_layout6.forEachSemanticSpan)(layout, (visit) => {
|
|
2336
2819
|
work.tick();
|
|
2337
2820
|
spans.push(visit);
|
|
2338
2821
|
});
|
|
2339
|
-
(0,
|
|
2822
|
+
(0, import_layout6.forEachSemanticDrawing)(layout, (visit) => {
|
|
2340
2823
|
work.tick();
|
|
2341
2824
|
drawings.push(visit);
|
|
2342
2825
|
});
|
|
2343
|
-
(0,
|
|
2826
|
+
(0, import_layout6.forEachSemanticStory)(layout, (root) => {
|
|
2344
2827
|
streams[root.page.index].push(
|
|
2345
2828
|
...decorations(
|
|
2346
2829
|
root.host.fragments,
|
|
@@ -2369,7 +2852,7 @@ async function paint(doc, session, layout, work, includeComments) {
|
|
|
2369
2852
|
markRotated(inner.blocks, cell ?? (inner.textDirection ? inner : void 0));
|
|
2370
2853
|
}
|
|
2371
2854
|
};
|
|
2372
|
-
(0,
|
|
2855
|
+
(0, import_layout6.forEachSemanticStory)(layout, (root) => markRotated(root.host.fragments));
|
|
2373
2856
|
const rotatedBuffers = /* @__PURE__ */ new Map();
|
|
2374
2857
|
const outFor = (visit) => {
|
|
2375
2858
|
const cell = visit.paragraph && rotatedCellOf.get(visit.paragraph);
|
|
@@ -2423,19 +2906,29 @@ async function paint(doc, session, layout, work, includeComments) {
|
|
|
2423
2906
|
const first = group[0];
|
|
2424
2907
|
const markerText = first.paragraph.lines[0] === first.line ? first.paragraph.marker?.text : void 0;
|
|
2425
2908
|
const logical = (markerText ? markerText + " " : "") + group.map((v) => v.span.equation?.fallbackText ?? v.span.text).join("");
|
|
2909
|
+
const rightToLeft = group.some((v) => (v.span.style.shaping?.level ?? 0) % 2 === 1);
|
|
2426
2910
|
group.sort((a, b) => a.absoluteBox.x - b.absoluteBox.x);
|
|
2427
|
-
lineStarts.set(group[0], logical);
|
|
2911
|
+
lineStarts.set(group[0], rightToLeft ? null : logical);
|
|
2428
2912
|
for (const visit of group) spans.push(visit);
|
|
2429
2913
|
}
|
|
2430
2914
|
let activeOut;
|
|
2915
|
+
let lineOut;
|
|
2916
|
+
const placeOutlines = () => {
|
|
2917
|
+
const outlines2 = text.takeOutlines();
|
|
2918
|
+
if (outlines2 && lineOut) lineOut.push(outlines2);
|
|
2919
|
+
};
|
|
2431
2920
|
const markersByPage = /* @__PURE__ */ new Map();
|
|
2432
2921
|
for (let i = 0; i < spans.length; i++) {
|
|
2433
2922
|
if (i % 128 === 0) await work.yield();
|
|
2434
2923
|
const visit = spans[i], page = pages[visit.page.index], out = outFor(visit);
|
|
2435
2924
|
if (lineStarts.has(visit)) {
|
|
2925
|
+
placeOutlines();
|
|
2926
|
+
lineOut = out;
|
|
2436
2927
|
if (activeOut) activeOut.push("EMC");
|
|
2437
|
-
|
|
2438
|
-
|
|
2928
|
+
const logical = lineStarts.get(visit);
|
|
2929
|
+
activeOut = logical === null ? void 0 : out;
|
|
2930
|
+
if (logical !== null)
|
|
2931
|
+
out.push(`/Span << /ActualText <FEFF${unicodeHex(logical ?? "")}> >> BDC`);
|
|
2439
2932
|
}
|
|
2440
2933
|
let markers = markersByPage.get(visit.page.index);
|
|
2441
2934
|
if (!markers) {
|
|
@@ -2457,27 +2950,28 @@ async function paint(doc, session, layout, work, includeComments) {
|
|
|
2457
2950
|
) : "";
|
|
2458
2951
|
if (picture) out.push(picture);
|
|
2459
2952
|
else
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2953
|
+
for (const piece of marker.pieces ?? [marker])
|
|
2954
|
+
out.push(
|
|
2955
|
+
text.paint(
|
|
2956
|
+
{
|
|
2957
|
+
...visit,
|
|
2958
|
+
span: {
|
|
2959
|
+
...visit.span,
|
|
2960
|
+
text: piece.text,
|
|
2961
|
+
style: piece.style,
|
|
2962
|
+
box: piece.box,
|
|
2963
|
+
link: void 0,
|
|
2964
|
+
revisions: void 0
|
|
2965
|
+
},
|
|
2966
|
+
absoluteBox: {
|
|
2967
|
+
...piece.box,
|
|
2968
|
+
x: piece.box.x + visit.storyOrigin.x,
|
|
2969
|
+
y: piece.box.y + visit.storyOrigin.y
|
|
2970
|
+
}
|
|
2471
2971
|
},
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
y: marker.box.y + visit.storyOrigin.y
|
|
2476
|
-
}
|
|
2477
|
-
},
|
|
2478
|
-
page
|
|
2479
|
-
)
|
|
2480
|
-
);
|
|
2972
|
+
page
|
|
2973
|
+
)
|
|
2974
|
+
);
|
|
2481
2975
|
}
|
|
2482
2976
|
const fill = HIGHLIGHTS[visit.span.style.highlight ?? ""] ?? visit.span.style.shading;
|
|
2483
2977
|
if (fill)
|
|
@@ -2495,11 +2989,12 @@ async function paint(doc, session, layout, work, includeComments) {
|
|
|
2495
2989
|
if (clipping) out.push("Q");
|
|
2496
2990
|
linkAnnotation(doc, page, visit, names);
|
|
2497
2991
|
}
|
|
2992
|
+
placeOutlines();
|
|
2498
2993
|
if (activeOut) activeOut.push("EMC");
|
|
2499
2994
|
for (const lines of pageGroups.values()) {
|
|
2500
2995
|
for (const group of lines.values()) {
|
|
2501
2996
|
const visit = group[0];
|
|
2502
|
-
const strokes = (0,
|
|
2997
|
+
const strokes = (0, import_layout6.runBorderStrokesForLine)(visit.line);
|
|
2503
2998
|
if (strokes.length === 0) continue;
|
|
2504
2999
|
work.tick();
|
|
2505
3000
|
const out = outFor(visit);
|
|
@@ -2574,7 +3069,7 @@ async function paint(doc, session, layout, work, includeComments) {
|
|
|
2574
3069
|
}
|
|
2575
3070
|
|
|
2576
3071
|
// src/pdf-work.ts
|
|
2577
|
-
var
|
|
3072
|
+
var import_export4 = require("@docx-editor.dev/core/export");
|
|
2578
3073
|
|
|
2579
3074
|
// src/types.ts
|
|
2580
3075
|
var PdfFidelityError = class extends Error {
|
|
@@ -2633,12 +3128,12 @@ async function withPdfWork(options, run) {
|
|
|
2633
3128
|
const controller = new AbortController();
|
|
2634
3129
|
const signal = options.signal;
|
|
2635
3130
|
const abort = () => controller.abort(
|
|
2636
|
-
new
|
|
3131
|
+
new import_export4.ExportResourceError("aborted", "PDF conversion aborted", { cause: signal?.reason })
|
|
2637
3132
|
);
|
|
2638
3133
|
if (signal?.aborted) abort();
|
|
2639
3134
|
signal?.addEventListener("abort", abort, { once: true });
|
|
2640
3135
|
const timer = setTimeout(
|
|
2641
|
-
() => controller.abort(new
|
|
3136
|
+
() => controller.abort(new import_export4.ExportResourceError("timedOut", "PDF conversion timed out")),
|
|
2642
3137
|
timeoutMs
|
|
2643
3138
|
);
|
|
2644
3139
|
const work = new Work(controller.signal, Date.now() + timeoutMs);
|
|
@@ -2647,9 +3142,9 @@ async function withPdfWork(options, run) {
|
|
|
2647
3142
|
work.check();
|
|
2648
3143
|
return await run(work, () => Math.round(performance.now() - started));
|
|
2649
3144
|
} catch (error) {
|
|
2650
|
-
if (error instanceof PdfDocumentOpenError && error.reason === "aborted" || error instanceof
|
|
3145
|
+
if (error instanceof PdfDocumentOpenError && error.reason === "aborted" || error instanceof import_export4.ExportResourceError && error.code === "aborted")
|
|
2651
3146
|
work.check();
|
|
2652
|
-
if (error instanceof PdfFidelityError || error instanceof PdfDocumentOpenError || error instanceof
|
|
3147
|
+
if (error instanceof PdfFidelityError || error instanceof PdfDocumentOpenError || error instanceof import_export4.ExportResourceError || error instanceof RangeError || error instanceof PdfEncodingError || error instanceof PdfWorkLimitError)
|
|
2653
3148
|
throw error;
|
|
2654
3149
|
work.check();
|
|
2655
3150
|
throw new PdfEncodingError("PDF encoding failed", { cause: error });
|
|
@@ -2722,7 +3217,7 @@ async function exportPdfFrom(session, options = {}) {
|
|
|
2722
3217
|
].includes(key))
|
|
2723
3218
|
throw new TypeError(`${key} must be configured when opening the PDF session`);
|
|
2724
3219
|
}
|
|
2725
|
-
if (!session || typeof session !== "object" || !(0,
|
|
3220
|
+
if (!session || typeof session !== "object" || !(0, import_export5.hasFontBackedExportCapabilities)(session) || typeof session.layout !== "function" || typeof session.layoutFor !== "function" || !session.fontResolution)
|
|
2726
3221
|
throw new TypeError("exportPdfFrom requires a font-backed export session");
|
|
2727
3222
|
return withPdfWork(options, (work, phase) => renderSession(session, options, work, phase, 0));
|
|
2728
3223
|
}
|
|
@@ -2786,7 +3281,7 @@ async function openDocumentForExport(source, options = {}) {
|
|
|
2786
3281
|
|
|
2787
3282
|
// src/index.ts
|
|
2788
3283
|
var import_editor2 = require("@docx-editor.dev/core/editor");
|
|
2789
|
-
var
|
|
3284
|
+
var import_export6 = require("@docx-editor.dev/core/export");
|
|
2790
3285
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2791
3286
|
0 && (module.exports = {
|
|
2792
3287
|
ExportResourceError,
|