postext-pdf 1.4.2 → 1.5.1
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 +3 -3
- package/dist/__tests__/accessibility.test.js +66 -0
- package/dist/__tests__/accessibility.test.js.map +1 -1
- package/dist/__tests__/alpha.test.d.ts +2 -0
- package/dist/__tests__/alpha.test.d.ts.map +1 -0
- package/dist/__tests__/alpha.test.js +164 -0
- package/dist/__tests__/alpha.test.js.map +1 -0
- package/dist/__tests__/bleedClip.test.d.ts +2 -0
- package/dist/__tests__/bleedClip.test.d.ts.map +1 -0
- package/dist/__tests__/bleedClip.test.js +83 -0
- package/dist/__tests__/bleedClip.test.js.map +1 -0
- package/dist/__tests__/boxBorderInside.test.d.ts +2 -0
- package/dist/__tests__/boxBorderInside.test.d.ts.map +1 -0
- package/dist/__tests__/boxBorderInside.test.js +63 -0
- package/dist/__tests__/boxBorderInside.test.js.map +1 -0
- package/dist/__tests__/calloutRuntTracking.test.d.ts +2 -0
- package/dist/__tests__/calloutRuntTracking.test.d.ts.map +1 -0
- package/dist/__tests__/calloutRuntTracking.test.js +72 -0
- package/dist/__tests__/calloutRuntTracking.test.js.map +1 -0
- package/dist/__tests__/calloutStripeRadius.test.d.ts +2 -0
- package/dist/__tests__/calloutStripeRadius.test.d.ts.map +1 -0
- package/dist/__tests__/calloutStripeRadius.test.js +90 -0
- package/dist/__tests__/calloutStripeRadius.test.js.map +1 -0
- package/dist/__tests__/chipVerticalPadding.test.d.ts +2 -0
- package/dist/__tests__/chipVerticalPadding.test.d.ts.map +1 -0
- package/dist/__tests__/chipVerticalPadding.test.js +71 -0
- package/dist/__tests__/chipVerticalPadding.test.js.map +1 -0
- package/dist/__tests__/chips.test.js +20 -3
- package/dist/__tests__/chips.test.js.map +1 -1
- package/dist/__tests__/documentLanguage.test.d.ts +2 -0
- package/dist/__tests__/documentLanguage.test.d.ts.map +1 -0
- package/dist/__tests__/documentLanguage.test.js +44 -0
- package/dist/__tests__/documentLanguage.test.js.map +1 -0
- package/dist/__tests__/fallbackSpaces.test.d.ts +2 -0
- package/dist/__tests__/fallbackSpaces.test.d.ts.map +1 -0
- package/dist/__tests__/fallbackSpaces.test.js +156 -0
- package/dist/__tests__/fallbackSpaces.test.js.map +1 -0
- package/dist/__tests__/floatReadingOrder.test.d.ts +2 -0
- package/dist/__tests__/floatReadingOrder.test.d.ts.map +1 -0
- package/dist/__tests__/floatReadingOrder.test.js +208 -0
- package/dist/__tests__/floatReadingOrder.test.js.map +1 -0
- package/dist/__tests__/fontEmbedding.test.d.ts +2 -0
- package/dist/__tests__/fontEmbedding.test.d.ts.map +1 -0
- package/dist/__tests__/fontEmbedding.test.js +118 -0
- package/dist/__tests__/fontEmbedding.test.js.map +1 -0
- package/dist/__tests__/fontFaces.test.d.ts +2 -0
- package/dist/__tests__/fontFaces.test.d.ts.map +1 -0
- package/dist/__tests__/fontFaces.test.js +193 -0
- package/dist/__tests__/fontFaces.test.js.map +1 -0
- package/dist/__tests__/fontStack.test.d.ts +2 -0
- package/dist/__tests__/fontStack.test.d.ts.map +1 -0
- package/dist/__tests__/fontStack.test.js +48 -0
- package/dist/__tests__/fontStack.test.js.map +1 -0
- package/dist/__tests__/headerFooter.test.js +83 -1
- package/dist/__tests__/headerFooter.test.js.map +1 -1
- package/dist/__tests__/headingAlign.test.d.ts +2 -0
- package/dist/__tests__/headingAlign.test.d.ts.map +1 -0
- package/dist/__tests__/headingAlign.test.js +66 -0
- package/dist/__tests__/headingAlign.test.js.map +1 -0
- package/dist/__tests__/hiddenHeadings.test.d.ts +2 -0
- package/dist/__tests__/hiddenHeadings.test.d.ts.map +1 -0
- package/dist/__tests__/hiddenHeadings.test.js +96 -0
- package/dist/__tests__/hiddenHeadings.test.js.map +1 -0
- package/dist/__tests__/lineTracking.test.d.ts +2 -0
- package/dist/__tests__/lineTracking.test.d.ts.map +1 -0
- package/dist/__tests__/lineTracking.test.js +80 -0
- package/dist/__tests__/lineTracking.test.js.map +1 -0
- package/dist/__tests__/measuredLines.test.d.ts +2 -0
- package/dist/__tests__/measuredLines.test.d.ts.map +1 -0
- package/dist/__tests__/measuredLines.test.js +255 -0
- package/dist/__tests__/measuredLines.test.js.map +1 -0
- package/dist/__tests__/metadata.test.d.ts +2 -0
- package/dist/__tests__/metadata.test.d.ts.map +1 -0
- package/dist/__tests__/metadata.test.js +51 -0
- package/dist/__tests__/metadata.test.js.map +1 -0
- package/dist/__tests__/outlineTitles.test.d.ts +2 -0
- package/dist/__tests__/outlineTitles.test.d.ts.map +1 -0
- package/dist/__tests__/outlineTitles.test.js +59 -0
- package/dist/__tests__/outlineTitles.test.js.map +1 -0
- package/dist/__tests__/pdfGenerationConfig.test.d.ts +2 -0
- package/dist/__tests__/pdfGenerationConfig.test.d.ts.map +1 -0
- package/dist/__tests__/pdfGenerationConfig.test.js +76 -0
- package/dist/__tests__/pdfGenerationConfig.test.js.map +1 -0
- package/dist/__tests__/pdfWorker.test.d.ts +2 -0
- package/dist/__tests__/pdfWorker.test.d.ts.map +1 -0
- package/dist/__tests__/pdfWorker.test.js +123 -0
- package/dist/__tests__/pdfWorker.test.js.map +1 -0
- package/dist/__tests__/printMarks.test.d.ts +2 -0
- package/dist/__tests__/printMarks.test.d.ts.map +1 -0
- package/dist/__tests__/printMarks.test.js +170 -0
- package/dist/__tests__/printMarks.test.js.map +1 -0
- package/dist/__tests__/printMaster.test.d.ts +2 -0
- package/dist/__tests__/printMaster.test.d.ts.map +1 -0
- package/dist/__tests__/printMaster.test.js +161 -0
- package/dist/__tests__/printMaster.test.js.map +1 -0
- package/dist/__tests__/renderWarnings.test.d.ts +2 -0
- package/dist/__tests__/renderWarnings.test.d.ts.map +1 -0
- package/dist/__tests__/renderWarnings.test.js +89 -0
- package/dist/__tests__/renderWarnings.test.js.map +1 -0
- package/dist/__tests__/repeatedHyphen.test.d.ts +2 -0
- package/dist/__tests__/repeatedHyphen.test.d.ts.map +1 -0
- package/dist/__tests__/repeatedHyphen.test.js +125 -0
- package/dist/__tests__/repeatedHyphen.test.js.map +1 -0
- package/dist/__tests__/scriptStacking.test.d.ts +2 -0
- package/dist/__tests__/scriptStacking.test.d.ts.map +1 -0
- package/dist/__tests__/scriptStacking.test.js +66 -0
- package/dist/__tests__/scriptStacking.test.js.map +1 -0
- package/dist/__tests__/sectionColumnRule.test.d.ts +2 -0
- package/dist/__tests__/sectionColumnRule.test.d.ts.map +1 -0
- package/dist/__tests__/sectionColumnRule.test.js +144 -0
- package/dist/__tests__/sectionColumnRule.test.js.map +1 -0
- package/dist/__tests__/svgFormReuse.test.d.ts +2 -0
- package/dist/__tests__/svgFormReuse.test.d.ts.map +1 -0
- package/dist/__tests__/svgFormReuse.test.js +102 -0
- package/dist/__tests__/svgFormReuse.test.js.map +1 -0
- package/dist/__tests__/svgVector.test.js +85 -11
- package/dist/__tests__/svgVector.test.js.map +1 -1
- package/dist/__tests__/tableFillSeams.test.d.ts +2 -0
- package/dist/__tests__/tableFillSeams.test.d.ts.map +1 -0
- package/dist/__tests__/tableFillSeams.test.js +72 -0
- package/dist/__tests__/tableFillSeams.test.js.map +1 -0
- package/dist/__tests__/tocLeaderKerning.test.d.ts +2 -0
- package/dist/__tests__/tocLeaderKerning.test.d.ts.map +1 -0
- package/dist/__tests__/tocLeaderKerning.test.js +84 -0
- package/dist/__tests__/tocLeaderKerning.test.js.map +1 -0
- package/dist/__tests__/tocNumberBaseline.test.d.ts +2 -0
- package/dist/__tests__/tocNumberBaseline.test.d.ts.map +1 -0
- package/dist/__tests__/tocNumberBaseline.test.js +72 -0
- package/dist/__tests__/tocNumberBaseline.test.js.map +1 -0
- package/dist/__tests__/tocTagging.test.d.ts +2 -0
- package/dist/__tests__/tocTagging.test.d.ts.map +1 -0
- package/dist/__tests__/tocTagging.test.js +120 -0
- package/dist/__tests__/tocTagging.test.js.map +1 -0
- package/dist/__tests__/trackedLineAlign.test.d.ts +2 -0
- package/dist/__tests__/trackedLineAlign.test.d.ts.map +1 -0
- package/dist/__tests__/trackedLineAlign.test.js +73 -0
- package/dist/__tests__/trackedLineAlign.test.js.map +1 -0
- package/dist/__tests__/uriLinks.test.d.ts +2 -0
- package/dist/__tests__/uriLinks.test.d.ts.map +1 -0
- package/dist/__tests__/uriLinks.test.js +103 -0
- package/dist/__tests__/uriLinks.test.js.map +1 -0
- package/dist/colors.d.ts +18 -3
- package/dist/colors.d.ts.map +1 -1
- package/dist/colors.js +77 -25
- package/dist/colors.js.map +1 -1
- package/dist/fontCache.d.ts +67 -4
- package/dist/fontCache.d.ts.map +1 -1
- package/dist/fontCache.js +200 -23
- package/dist/fontCache.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/pdf-backend/blockRender.d.ts.map +1 -1
- package/dist/pdf-backend/blockRender.js +127 -28
- package/dist/pdf-backend/blockRender.js.map +1 -1
- package/dist/pdf-backend/fallbackSpaces.d.ts +37 -0
- package/dist/pdf-backend/fallbackSpaces.d.ts.map +1 -0
- package/dist/pdf-backend/fallbackSpaces.js +119 -0
- package/dist/pdf-backend/fallbackSpaces.js.map +1 -0
- package/dist/pdf-backend/fontHelpers.d.ts +10 -1
- package/dist/pdf-backend/fontHelpers.d.ts.map +1 -1
- package/dist/pdf-backend/fontHelpers.js +111 -65
- package/dist/pdf-backend/fontHelpers.js.map +1 -1
- package/dist/pdf-backend/headerFooter.d.ts +4 -2
- package/dist/pdf-backend/headerFooter.d.ts.map +1 -1
- package/dist/pdf-backend/headerFooter.js +105 -48
- package/dist/pdf-backend/headerFooter.js.map +1 -1
- package/dist/pdf-backend/index.d.ts +55 -6
- package/dist/pdf-backend/index.d.ts.map +1 -1
- package/dist/pdf-backend/index.js +135 -35
- package/dist/pdf-backend/index.js.map +1 -1
- package/dist/pdf-backend/links.d.ts +82 -1
- package/dist/pdf-backend/links.d.ts.map +1 -1
- package/dist/pdf-backend/links.js +141 -3
- package/dist/pdf-backend/links.js.map +1 -1
- package/dist/pdf-backend/outlines.d.ts.map +1 -1
- package/dist/pdf-backend/outlines.js +7 -0
- package/dist/pdf-backend/outlines.js.map +1 -1
- package/dist/pdf-backend/pageDecorations.d.ts.map +1 -1
- package/dist/pdf-backend/pageDecorations.js +42 -26
- package/dist/pdf-backend/pageDecorations.js.map +1 -1
- package/dist/pdf-backend/primitives.d.ts +61 -1
- package/dist/pdf-backend/primitives.d.ts.map +1 -1
- package/dist/pdf-backend/primitives.js +318 -18
- package/dist/pdf-backend/primitives.js.map +1 -1
- package/dist/pdf-backend/renderResourceBlock.d.ts +3 -1
- package/dist/pdf-backend/renderResourceBlock.d.ts.map +1 -1
- package/dist/pdf-backend/renderResourceBlock.js +97 -19
- package/dist/pdf-backend/renderResourceBlock.js.map +1 -1
- package/dist/pdf-backend/structureFlow.d.ts +70 -3
- package/dist/pdf-backend/structureFlow.d.ts.map +1 -1
- package/dist/pdf-backend/structureFlow.js +209 -27
- package/dist/pdf-backend/structureFlow.js.map +1 -1
- package/dist/pdf-backend/svgVector.d.ts +7 -2
- package/dist/pdf-backend/svgVector.d.ts.map +1 -1
- package/dist/pdf-backend/svgVector.js +157 -72
- package/dist/pdf-backend/svgVector.js.map +1 -1
- package/dist/pdf-backend/tagging.d.ts +1 -1
- package/dist/pdf-backend/tagging.d.ts.map +1 -1
- package/dist/pdf-backend/tagging.js.map +1 -1
- package/dist/worker/client.d.ts +1 -1
- package/dist/worker/client.d.ts.map +1 -1
- package/dist/worker/client.js +8 -0
- package/dist/worker/client.js.map +1 -1
- package/dist/worker/pdf.worker.js +1 -0
- package/dist/worker/pdf.worker.js.map +1 -1
- package/dist/worker/protocol.d.ts +8 -1
- package/dist/worker/protocol.d.ts.map +1 -1
- package/package.json +3 -3
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { describe, it, expect, beforeAll, vi } from 'vitest';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import fontkit from '@pdf-lib/fontkit';
|
|
4
|
+
import { buildDocument } from 'postext';
|
|
5
|
+
import { parseFontString } from '../fontString';
|
|
6
|
+
// EF-52: `postext-pdf/worker` end to end, with the worker run in-process
|
|
7
|
+
// behind a message channel that clones every message the way a real
|
|
8
|
+
// worker boundary does. The host answers the worker's font questions and
|
|
9
|
+
// receives its progress and warnings.
|
|
10
|
+
const fontBytes = fs.readFileSync(new URL('../../../../apps/web/public/fonts/Lora-Regular.ttf', import.meta.url));
|
|
11
|
+
const face = fontkit.create(fontBytes);
|
|
12
|
+
class StubCtx {
|
|
13
|
+
font = '';
|
|
14
|
+
measureText(s) {
|
|
15
|
+
const sizePx = parseFontString(this.font)?.sizePx ?? 16;
|
|
16
|
+
return { width: (face.layout(s).advanceWidth / face.unitsPerEm) * sizePx };
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
globalThis.OffscreenCanvas = class {
|
|
20
|
+
getContext() {
|
|
21
|
+
return new StubCtx();
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
/** One end of a message channel: messages posted here reach the other end
|
|
25
|
+
* on a later task, structured-cloned. */
|
|
26
|
+
class Port {
|
|
27
|
+
other;
|
|
28
|
+
listeners = [];
|
|
29
|
+
addEventListener(type, fn) {
|
|
30
|
+
if (type === 'message')
|
|
31
|
+
this.listeners.push(fn);
|
|
32
|
+
}
|
|
33
|
+
postMessage(data) {
|
|
34
|
+
const copy = structuredClone(data);
|
|
35
|
+
setTimeout(() => {
|
|
36
|
+
for (const fn of this.other.listeners)
|
|
37
|
+
fn({ data: copy });
|
|
38
|
+
}, 0);
|
|
39
|
+
}
|
|
40
|
+
terminate() { }
|
|
41
|
+
close() { }
|
|
42
|
+
}
|
|
43
|
+
/** One handle for the one in-process worker (a handle listens to every
|
|
44
|
+
* message of its worker, so two on one channel would both answer). */
|
|
45
|
+
let pdf;
|
|
46
|
+
beforeAll(async () => {
|
|
47
|
+
const host = new Port();
|
|
48
|
+
const scope = new Port();
|
|
49
|
+
host.other = scope;
|
|
50
|
+
scope.other = host;
|
|
51
|
+
// The worker module binds `self` when it loads.
|
|
52
|
+
globalThis.self = scope;
|
|
53
|
+
await import('../worker/pdf.worker');
|
|
54
|
+
const { createPdfWorker } = await import('../worker/client');
|
|
55
|
+
pdf = createPdfWorker({ worker: host });
|
|
56
|
+
});
|
|
57
|
+
const pt = (value) => ({ value, unit: 'pt' });
|
|
58
|
+
const config = {
|
|
59
|
+
page: { width: pt(300), height: pt(300), margins: { top: pt(20), bottom: pt(20), left: pt(20), right: pt(20) } },
|
|
60
|
+
bodyText: { fontFamily: 'Lora' },
|
|
61
|
+
headings: { fontFamily: 'Lora', levels: [{ level: 1, breakBefore: { enabled: false } }] },
|
|
62
|
+
};
|
|
63
|
+
describe('createPdfWorker (EF-52)', () => {
|
|
64
|
+
it('renders on the worker, asking the host for fonts and reporting progress', async () => {
|
|
65
|
+
const doc = buildDocument({ markdown: '# Title\n\nBody text.' }, config);
|
|
66
|
+
const asked = [];
|
|
67
|
+
const progress = [];
|
|
68
|
+
const bytes = await pdf.render(doc, {
|
|
69
|
+
fontProvider: async (family, weight, style) => {
|
|
70
|
+
asked.push(`${family}|${weight}|${style}`);
|
|
71
|
+
return new Uint8Array(fontBytes);
|
|
72
|
+
},
|
|
73
|
+
onProgress: (p) => progress.push(p.phase),
|
|
74
|
+
});
|
|
75
|
+
expect(new TextDecoder().decode(bytes.slice(0, 5))).toBe('%PDF-');
|
|
76
|
+
expect(asked).toContain('Lora|400|normal');
|
|
77
|
+
expect(progress).toEqual(expect.arrayContaining(['prepare', 'pages', 'save']));
|
|
78
|
+
});
|
|
79
|
+
it('forwards font fallback warnings to the host', async () => {
|
|
80
|
+
const doc = buildDocument({ markdown: 'Some *italic* words.' }, config);
|
|
81
|
+
const warnings = [];
|
|
82
|
+
const bytes = await pdf.render(doc, {
|
|
83
|
+
fontProvider: async (_family, _weight, style) => {
|
|
84
|
+
if (style === 'italic')
|
|
85
|
+
throw new Error('no italic cut');
|
|
86
|
+
return new Uint8Array(fontBytes);
|
|
87
|
+
},
|
|
88
|
+
onWarning: (w) => { if (w.kind === 'fontFallback')
|
|
89
|
+
warnings.push(w); },
|
|
90
|
+
});
|
|
91
|
+
expect(bytes.byteLength).toBeGreaterThan(0);
|
|
92
|
+
expect(warnings).toHaveLength(1);
|
|
93
|
+
expect(warnings[0]).toMatchObject({ kind: 'fontFallback', family: 'Lora', style: 'italic', fallback: { style: 'normal' } });
|
|
94
|
+
expect(warnings[0].reason).toContain('no italic cut');
|
|
95
|
+
});
|
|
96
|
+
it('forwards a missing image to the host, and logs only font fallbacks without a handler', async () => {
|
|
97
|
+
const photo = {
|
|
98
|
+
id: 'photo', typeId: 'figure', kind: 'bitmap', caption: 'A photo.', createdAt: 0, updatedAt: 0,
|
|
99
|
+
bitmap: { fileId: 'file-photo', format: 'png', width: 400, height: 300 }, placement: { position: 'here' },
|
|
100
|
+
};
|
|
101
|
+
const doc = buildDocument({ markdown: 'Text.\n\n::resource{id="photo"}\n', resources: [photo] }, config);
|
|
102
|
+
const fontProvider = async () => new Uint8Array(fontBytes);
|
|
103
|
+
const warnings = [];
|
|
104
|
+
await pdf.render(doc, { fontProvider, onWarning: (w) => warnings.push(w) });
|
|
105
|
+
expect(warnings).toEqual([{ kind: 'missingImage', fileId: 'file-photo', resourceId: 'photo', pageIndex: 0, documentIndex: 0 }]);
|
|
106
|
+
const warn = vi.spyOn(console, 'warn').mockImplementation(() => { });
|
|
107
|
+
try {
|
|
108
|
+
await pdf.render(doc, { fontProvider });
|
|
109
|
+
expect(warn).not.toHaveBeenCalled();
|
|
110
|
+
}
|
|
111
|
+
finally {
|
|
112
|
+
warn.mockRestore();
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
it('rejects when a family cannot be had at all', async () => {
|
|
116
|
+
const doc = buildDocument({ markdown: 'Body.' }, config);
|
|
117
|
+
await expect(pdf.render(doc, {
|
|
118
|
+
fontProvider: async () => { throw new Error('offline'); },
|
|
119
|
+
onWarning: () => undefined,
|
|
120
|
+
})).rejects.toThrow(/failed to load font\(s\): Lora 400/);
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
//# sourceMappingURL=pdfWorker.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pdfWorker.test.js","sourceRoot":"","sources":["../../src/__tests__/pdfWorker.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"printMarks.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/printMarks.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import { PDFArray, PDFDict, PDFDocument, PDFName, PDFRawStream, decodePDFRawStream } from 'pdf-lib';
|
|
4
|
+
import fontkit from '@pdf-lib/fontkit';
|
|
5
|
+
import { buildDocument, dimensionToPx } from 'postext';
|
|
6
|
+
import { renderToPdf } from '../pdf-backend';
|
|
7
|
+
import { parseFontString } from '../fontString';
|
|
8
|
+
const fontBytes = fs.readFileSync(new URL('../../../../apps/web/public/fonts/Lora-Regular.ttf', import.meta.url));
|
|
9
|
+
const fontProvider = async () => new Uint8Array(fontBytes);
|
|
10
|
+
const face = fontkit.create(fontBytes);
|
|
11
|
+
class StubCtx {
|
|
12
|
+
font = '';
|
|
13
|
+
measureText(s) {
|
|
14
|
+
const sizePx = parseFontString(this.font)?.sizePx ?? 16;
|
|
15
|
+
return { width: (face.layout(s).advanceWidth / face.unitsPerEm) * sizePx };
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
globalThis.OffscreenCanvas = class {
|
|
19
|
+
getContext() {
|
|
20
|
+
return new StubCtx();
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
const mm = (value) => ({ value, unit: 'mm' });
|
|
24
|
+
const MM = 72 / 25.4;
|
|
25
|
+
/** A 170 × 227 mm page (the EF-120 report), no running heads. */
|
|
26
|
+
function config(cutLines) {
|
|
27
|
+
return {
|
|
28
|
+
page: { sizePreset: 'custom', width: mm(170), height: mm(227), dpi: 150, ...(cutLines ? { cutLines } : {}) },
|
|
29
|
+
header: { elements: [] },
|
|
30
|
+
footer: { elements: [] },
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
async function render(cutLines, colorSpace) {
|
|
34
|
+
const doc = buildDocument({ markdown: 'A paragraph of text.' }, config(cutLines));
|
|
35
|
+
const bytes = await renderToPdf(doc, { fontProvider, ...(colorSpace ? { colorSpace } : {}) });
|
|
36
|
+
const pdf = await PDFDocument.load(bytes);
|
|
37
|
+
const page = pdf.getPage(0);
|
|
38
|
+
const contents = page.node.Contents();
|
|
39
|
+
const streams = contents instanceof PDFArray ? contents.asArray().map((r) => pdf.context.lookup(r)) : [contents];
|
|
40
|
+
const content = streams
|
|
41
|
+
.map((s) => (s instanceof PDFRawStream ? Buffer.from(decodePDFRawStream(s).decode()).toString('latin1') : ''))
|
|
42
|
+
.join('\n');
|
|
43
|
+
const box = (name) => {
|
|
44
|
+
const arr = page.node.lookupMaybe(PDFName.of(name), PDFArray);
|
|
45
|
+
return arr?.asArray().map((n) => n.asNumber());
|
|
46
|
+
};
|
|
47
|
+
return { pdf, page, content, box, doc };
|
|
48
|
+
}
|
|
49
|
+
/** Every `x1 y1 m x2 y2 l S` line of a content stream, in points. */
|
|
50
|
+
function strokedLines(content) {
|
|
51
|
+
const num = '(-?[\\d.]+)';
|
|
52
|
+
const re = new RegExp(`((?:[^\\n]*\\n){0,4}?)${num} ${num} m\\s+${num} ${num} l\\s+S`, 'g');
|
|
53
|
+
return [...content.matchAll(re)].map((m) => ({ ops: m[1], x1: +m[2], y1: +m[3], x2: +m[4], y2: +m[5] }));
|
|
54
|
+
}
|
|
55
|
+
const close = (a, b) => {
|
|
56
|
+
expect(a).toBeDefined();
|
|
57
|
+
expect(a.length).toBe(4);
|
|
58
|
+
a.forEach((v, i) => expect(v).toBeCloseTo(b[i], 3));
|
|
59
|
+
};
|
|
60
|
+
// EF-125. With cut lines on, the MediaBox is the whole sheet, marks
|
|
61
|
+
// included; a print workflow needs the trimmed page (TrimBox) and the art
|
|
62
|
+
// that runs past it (BleedBox) on every page.
|
|
63
|
+
describe('print boxes (EF-125)', () => {
|
|
64
|
+
it('sets TrimBox to the trimmed page and BleedBox to the trim plus the bleed', async () => {
|
|
65
|
+
const { pdf, box } = await render({ enabled: true, bleed: mm(5) });
|
|
66
|
+
// Sheet: 170 + 2 × (5 + 3 + 5) mm = 196 mm wide, 253 mm tall.
|
|
67
|
+
const [, , w, h] = box('MediaBox');
|
|
68
|
+
expect(w / MM).toBeCloseTo(196, 3);
|
|
69
|
+
expect(h / MM).toBeCloseTo(253, 3);
|
|
70
|
+
close(box('TrimBox'), [13 * MM, 13 * MM, 183 * MM, 240 * MM]);
|
|
71
|
+
close(box('BleedBox'), [8 * MM, 8 * MM, 188 * MM, 245 * MM]);
|
|
72
|
+
for (const page of pdf.getPages()) {
|
|
73
|
+
expect(page.getTrimBox().width / MM).toBeCloseTo(170, 3);
|
|
74
|
+
expect(page.getBleedBox().width / MM).toBeCloseTo(180, 3);
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
it('adds no boxes when cut lines are off (the page is the trim)', async () => {
|
|
78
|
+
const { box } = await render(undefined);
|
|
79
|
+
expect(box('TrimBox')).toBeUndefined();
|
|
80
|
+
expect(box('BleedBox')).toBeUndefined();
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
// EF-120. The marks started markOffset outside the trim even when the bleed
|
|
84
|
+
// was wider, so their inner ends lay over art running into the bleed.
|
|
85
|
+
describe('crop marks in the PDF (EF-120)', () => {
|
|
86
|
+
it('keeps every mark outside the BleedBox', async () => {
|
|
87
|
+
const { content } = await render({ enabled: true, bleed: mm(5) });
|
|
88
|
+
// The trim plus 5 mm of bleed, 8 mm inside the 196 × 253 mm sheet.
|
|
89
|
+
const [bx0, by0, bx1, by1] = [8 * MM, 8 * MM, 188 * MM, 245 * MM];
|
|
90
|
+
const lines = strokedLines(content);
|
|
91
|
+
expect(lines).toHaveLength(8);
|
|
92
|
+
const eps = 1e-3;
|
|
93
|
+
for (const l of lines) {
|
|
94
|
+
for (const [x, y] of [[l.x1, l.y1], [l.x2, l.y2]]) {
|
|
95
|
+
const inside = x > bx0 + eps && x < bx1 - eps && y > by0 + eps && y < by1 - eps;
|
|
96
|
+
expect(inside).toBe(false);
|
|
97
|
+
}
|
|
98
|
+
// 5 mm long, from the bleed edge outwards.
|
|
99
|
+
expect(Math.hypot(l.x2 - l.x1, l.y2 - l.y1) / MM).toBeCloseTo(5, 3);
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
it('draws the marks 3 to 8 mm outside the trim with the defaults, as before', async () => {
|
|
103
|
+
const { content, doc } = await render({ enabled: true });
|
|
104
|
+
const trim = (doc.trimOffset * 72) / 150 / MM;
|
|
105
|
+
expect(trim).toBeCloseTo(dimensionToPx(mm(11), 150) * 72 / 150 / MM, 6);
|
|
106
|
+
const lines = strokedLines(content);
|
|
107
|
+
expect(lines).toHaveLength(8);
|
|
108
|
+
// The top-left horizontal mark runs from 8 mm to 3 mm off the sheet's left edge.
|
|
109
|
+
const xs = lines.flatMap((l) => (Math.abs(l.y1 - l.y2) < 1e-6 ? [l.x1, l.x2] : [])).map((v) => v / MM).sort((a, b) => a - b);
|
|
110
|
+
expect(xs[0]).toBeCloseTo(trim - 8, 3);
|
|
111
|
+
expect(xs[1]).toBeCloseTo(trim - 8, 3);
|
|
112
|
+
expect(xs[2]).toBeCloseTo(trim - 3, 3);
|
|
113
|
+
});
|
|
114
|
+
it('sets the marks round the TrimBox it writes, both read from doc.trimOffset', async () => {
|
|
115
|
+
const built = buildDocument({ markdown: 'A paragraph of text.' }, config({ enabled: true }));
|
|
116
|
+
// A trim offset the cut-line settings alone would not give.
|
|
117
|
+
const doc = { ...built, trimOffset: built.trimOffset + dimensionToPx(mm(4), 150) };
|
|
118
|
+
const pdf = await PDFDocument.load(await renderToPdf(doc, { fontProvider }));
|
|
119
|
+
const page = pdf.getPage(0);
|
|
120
|
+
const contents = page.node.Contents();
|
|
121
|
+
const streams = contents instanceof PDFArray ? contents.asArray().map((r) => pdf.context.lookup(r)) : [contents];
|
|
122
|
+
const content = streams
|
|
123
|
+
.map((s) => (s instanceof PDFRawStream ? Buffer.from(decodePDFRawStream(s).decode()).toString('latin1') : ''))
|
|
124
|
+
.join('\n');
|
|
125
|
+
const trimLeft = page.getTrimBox().x / MM;
|
|
126
|
+
expect(trimLeft).toBeCloseTo(15, 3);
|
|
127
|
+
const xs = strokedLines(content)
|
|
128
|
+
.flatMap((l) => (Math.abs(l.y1 - l.y2) < 1e-6 ? [l.x1, l.x2] : []))
|
|
129
|
+
.map((v) => v / MM)
|
|
130
|
+
.sort((a, b) => a - b);
|
|
131
|
+
// The left marks run 3 to 8 mm outside the TrimBox.
|
|
132
|
+
expect(xs[0]).toBeCloseTo(trimLeft - 8, 3);
|
|
133
|
+
expect(xs[2]).toBeCloseTo(trimLeft - 3, 3);
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
// EF-125. A CMYK file printed the marks '0 0 0 1 K', on the black plate
|
|
137
|
+
// alone; crop marks belong on every plate, in registration colour.
|
|
138
|
+
describe('crop mark colour (EF-125)', () => {
|
|
139
|
+
it('paints the marks in the /All separation in CMYK output', async () => {
|
|
140
|
+
const { content, page, pdf } = await render({ enabled: true, bleed: mm(5) }, 'cmyk');
|
|
141
|
+
const lines = strokedLines(content);
|
|
142
|
+
expect(lines).toHaveLength(8);
|
|
143
|
+
for (const l of lines) {
|
|
144
|
+
expect(l.ops).toMatch(/\/(\S+) CS\s+1 SCN/);
|
|
145
|
+
expect(l.ops).not.toMatch(/\bK\b/);
|
|
146
|
+
}
|
|
147
|
+
const name = /\/(\S+) CS\s+1 SCN/.exec(lines[0].ops)[1];
|
|
148
|
+
const resources = page.node.Resources();
|
|
149
|
+
const spaces = resources.lookup(PDFName.of('ColorSpace'), PDFDict);
|
|
150
|
+
const space = spaces.lookup(PDFName.of(name), PDFArray);
|
|
151
|
+
const [family, colorant, alternate, fn] = space.asArray().map((o) => pdf.context.lookup(o));
|
|
152
|
+
expect(String(family)).toBe('/Separation');
|
|
153
|
+
expect(String(colorant)).toBe('/All');
|
|
154
|
+
expect(String(alternate)).toBe('/DeviceCMYK');
|
|
155
|
+
const c1 = fn.lookup(PDFName.of('C1'), PDFArray).asArray().map((n) => n.asNumber());
|
|
156
|
+
expect(c1).toEqual([1, 1, 1, 1]);
|
|
157
|
+
});
|
|
158
|
+
it('keeps the configured colour in RGB and grayscale output', async () => {
|
|
159
|
+
for (const [space, ink] of [['rgb', /0 0 0 RG/], ['grayscale', /0 G/]]) {
|
|
160
|
+
const { content } = await render({ enabled: true, color: { hex: '#000000', model: 'hex' } }, space);
|
|
161
|
+
const lines = strokedLines(content);
|
|
162
|
+
expect(lines).toHaveLength(8);
|
|
163
|
+
for (const l of lines) {
|
|
164
|
+
expect(l.ops).toMatch(ink);
|
|
165
|
+
expect(l.ops).not.toMatch(/SCN/);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
//# sourceMappingURL=printMarks.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"printMarks.test.js","sourceRoot":"","sources":["../../src/__tests__/printMarks.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"printMaster.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/printMaster.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { PDFArray, PDFDocument, PDFRawStream, decodePDFRawStream } from 'pdf-lib';
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import fontkit from '@pdf-lib/fontkit';
|
|
5
|
+
import { buildDocument } from 'postext';
|
|
6
|
+
import { renderToPdf } from '../pdf-backend';
|
|
7
|
+
import { preloadResourceImages } from '../pdf-backend/renderResourceBlock';
|
|
8
|
+
import { parseFontString } from '../fontString';
|
|
9
|
+
// EF-06: a figure's vector print master (`svg.pdfFileId`) is what
|
|
10
|
+
// `renderToPdf` embeds — the host hands over bytes by id, it does not have
|
|
11
|
+
// to swap the master in for the SVG's own id (only the bundle adapter did).
|
|
12
|
+
const fontBytes = fs.readFileSync(new URL('../../../../apps/web/public/fonts/Lora-Regular.ttf', import.meta.url));
|
|
13
|
+
const face = fontkit.create(fontBytes);
|
|
14
|
+
class StubCtx {
|
|
15
|
+
font = '';
|
|
16
|
+
measureText(s) {
|
|
17
|
+
const sizePx = parseFontString(this.font)?.sizePx ?? 16;
|
|
18
|
+
return { width: (face.layout(s).advanceWidth / face.unitsPerEm) * sizePx };
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
globalThis.OffscreenCanvas = class {
|
|
22
|
+
getContext() {
|
|
23
|
+
return new StubCtx();
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
const SVG = new TextEncoder().encode('<svg xmlns="http://www.w3.org/2000/svg" width="200" height="100" viewBox="0 0 200 100"><rect width="200" height="100" fill="#000000"/></svg>');
|
|
27
|
+
async function masterPdf() {
|
|
28
|
+
const master = await PDFDocument.create();
|
|
29
|
+
master.addPage([200, 100]).drawRectangle({ x: 0, y: 0, width: 200, height: 100 });
|
|
30
|
+
return master.save();
|
|
31
|
+
}
|
|
32
|
+
function vdt(resource, singleInk = false) {
|
|
33
|
+
return {
|
|
34
|
+
config: { page: { dpi: 72 }, diagramStyle: { singleInk, inkColor: { hex: '#295aa3' } } },
|
|
35
|
+
blocks: [{
|
|
36
|
+
bbox: { x: 0, y: 0, width: 100, height: 80 },
|
|
37
|
+
resourceBlock: {
|
|
38
|
+
kind: 'svg',
|
|
39
|
+
fileId: 'fig.svg',
|
|
40
|
+
resource: { id: 'fig', kind: 'svg', ...resource },
|
|
41
|
+
bodyRect: { x: 0, y: 0, width: 100, height: 50 },
|
|
42
|
+
},
|
|
43
|
+
}],
|
|
44
|
+
pages: [],
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
describe('preloadResourceImages — print masters (EF-06)', () => {
|
|
48
|
+
it('asks for the master by its own id and embeds it in place of the SVG', async () => {
|
|
49
|
+
const master = await masterPdf();
|
|
50
|
+
const asked = [];
|
|
51
|
+
const bytes = (id) => {
|
|
52
|
+
asked.push(id);
|
|
53
|
+
return id === 'fig.pdf' ? master : id === 'fig.svg' ? SVG : undefined;
|
|
54
|
+
};
|
|
55
|
+
const pdfDoc = await PDFDocument.create();
|
|
56
|
+
const images = await preloadResourceImages(pdfDoc, vdt({ svg: { fileId: 'fig.svg', pdfFileId: 'fig.pdf' } }), bytes);
|
|
57
|
+
expect(asked[0]).toBe('fig.pdf');
|
|
58
|
+
expect(images.get('fig.svg')?.kind).toBe('page');
|
|
59
|
+
});
|
|
60
|
+
it('falls back to the SVG when the master is missing or does not decode', async () => {
|
|
61
|
+
const pdfDoc = await PDFDocument.create();
|
|
62
|
+
const missing = await preloadResourceImages(pdfDoc, vdt({ svg: { fileId: 'fig.svg', pdfFileId: 'fig.pdf' } }), (id) => (id === 'fig.svg' ? SVG : undefined));
|
|
63
|
+
expect(missing.get('fig.svg')?.kind).toBe('vector');
|
|
64
|
+
const broken = await preloadResourceImages(pdfDoc, vdt({ svg: { fileId: 'fig.svg', pdfFileId: 'fig.pdf' } }), (id) => (id === 'fig.pdf' ? new TextEncoder().encode('%PDF-1.7 truncated') : id === 'fig.svg' ? SVG : undefined));
|
|
65
|
+
expect(broken.get('fig.svg')?.kind).toBe('vector');
|
|
66
|
+
});
|
|
67
|
+
it('ignores the master in single-ink mode, which recolours SVG markup only', async () => {
|
|
68
|
+
const master = await masterPdf();
|
|
69
|
+
const asked = [];
|
|
70
|
+
const pdfDoc = await PDFDocument.create();
|
|
71
|
+
const images = await preloadResourceImages(pdfDoc, vdt({ svg: { fileId: 'fig.svg', pdfFileId: 'fig.pdf' } }, true), (id) => {
|
|
72
|
+
asked.push(id);
|
|
73
|
+
return id === 'fig.pdf' ? master : SVG;
|
|
74
|
+
});
|
|
75
|
+
expect(asked).not.toContain('fig.pdf');
|
|
76
|
+
expect(images.get('fig.svg')?.kind).toBe('vector');
|
|
77
|
+
});
|
|
78
|
+
it('still takes a master a host swapped in under the SVG id (bundleResourceBytes)', async () => {
|
|
79
|
+
const master = await masterPdf();
|
|
80
|
+
const pdfDoc = await PDFDocument.create();
|
|
81
|
+
const images = await preloadResourceImages(pdfDoc, vdt({ svg: { fileId: 'fig.svg', pdfFileId: 'fig.pdf' } }), (id) => (id === 'fig.svg' ? master : undefined));
|
|
82
|
+
expect(images.get('fig.svg')?.kind).toBe('page');
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
describe('renderToPdf — print masters (EF-06)', () => {
|
|
86
|
+
const pt = (value) => ({ value, unit: 'pt' });
|
|
87
|
+
const config = {
|
|
88
|
+
page: { width: pt(300), height: pt(300), margins: { top: pt(20), bottom: pt(20), left: pt(20), right: pt(20) } },
|
|
89
|
+
headings: { levels: [{ level: 1, breakBefore: { enabled: false } }] },
|
|
90
|
+
};
|
|
91
|
+
const resources = [{
|
|
92
|
+
id: 'fig',
|
|
93
|
+
typeId: 'figure',
|
|
94
|
+
kind: 'svg',
|
|
95
|
+
createdAt: 0,
|
|
96
|
+
updatedAt: 0,
|
|
97
|
+
svg: { fileId: 'fig.svg', width: 200, height: 100, pdfFileId: 'fig.pdf' },
|
|
98
|
+
placement: { position: 'here' },
|
|
99
|
+
}];
|
|
100
|
+
it('embeds the master page as a form XObject from plain resourceBytes', async () => {
|
|
101
|
+
const master = await masterPdf();
|
|
102
|
+
const doc = buildDocument({ markdown: 'Text.\n\n::resource{id="fig"}', resources }, config);
|
|
103
|
+
const bytes = await renderToPdf(doc, {
|
|
104
|
+
fontProvider: async () => new Uint8Array(fontBytes),
|
|
105
|
+
resourceBytes: (id) => (id === 'fig.pdf' ? master : id === 'fig.svg' ? SVG : undefined),
|
|
106
|
+
});
|
|
107
|
+
const pdf = await PDFDocument.load(bytes);
|
|
108
|
+
const contents = pdf.getPage(0).node.Contents();
|
|
109
|
+
const refs = contents instanceof PDFArray ? contents.asArray() : [contents];
|
|
110
|
+
const content = refs
|
|
111
|
+
.map((ref) => {
|
|
112
|
+
const s = pdf.context.lookup(ref);
|
|
113
|
+
return s instanceof PDFRawStream ? new TextDecoder('latin1').decode(decodePDFRawStream(s).decode()) : '';
|
|
114
|
+
})
|
|
115
|
+
.join('\n');
|
|
116
|
+
expect(content).toMatch(/\/EmbeddedPdfPage[^\s]* Do/);
|
|
117
|
+
});
|
|
118
|
+
it('embeds the master wherever the SVG is drawn: a table cell, a design image, a box icon', async () => {
|
|
119
|
+
const master = await masterPdf();
|
|
120
|
+
const table = {
|
|
121
|
+
id: 'tab', typeId: 'table', kind: 'table', createdAt: 0, updatedAt: 0,
|
|
122
|
+
table: { model: { rows: [[{ content: 'Cell', image: { resourceId: 'fig' } }]] } },
|
|
123
|
+
placement: { position: 'here' },
|
|
124
|
+
};
|
|
125
|
+
const uses = [
|
|
126
|
+
['cell', config, 'Text.\n\n::resource{id="tab"}'],
|
|
127
|
+
['design image', {
|
|
128
|
+
...config,
|
|
129
|
+
header: { elements: [{ kind: 'image', id: 'logo', resourceId: 'fig', placement: { anchor: { to: 'container', edge: 'top-left' }, size: { width: pt(40) } } }] },
|
|
130
|
+
}, 'Text.'],
|
|
131
|
+
['box icon', { ...config, calloutStyles: [{ id: 'note', icon: { kind: 'resource', resourceId: 'fig' } }] }, ':::callout{type="note"}\nBoxed.\n:::'],
|
|
132
|
+
];
|
|
133
|
+
for (const [use, cfg, markdown] of uses) {
|
|
134
|
+
const doc = buildDocument({ markdown, resources: [...resources, table] }, cfg);
|
|
135
|
+
const asked = [];
|
|
136
|
+
const pdfDoc = await PDFDocument.create();
|
|
137
|
+
const images = await preloadResourceImages(pdfDoc, doc, (id) => {
|
|
138
|
+
asked.push(id);
|
|
139
|
+
return id === 'fig.pdf' ? master : id === 'fig.svg' ? SVG : undefined;
|
|
140
|
+
});
|
|
141
|
+
expect(asked[0], use).toBe('fig.pdf');
|
|
142
|
+
expect(images.get('fig.svg')?.kind, use).toBe('page');
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
it('gives every chapter of a book the master, whichever chapter draws the SVG first', async () => {
|
|
146
|
+
const master = await masterPdf();
|
|
147
|
+
const table = {
|
|
148
|
+
id: 'tab', typeId: 'table', kind: 'table', createdAt: 0, updatedAt: 0,
|
|
149
|
+
table: { model: { rows: [[{ content: 'Cell', image: { resourceId: 'fig' } }]] } },
|
|
150
|
+
placement: { position: 'here' },
|
|
151
|
+
};
|
|
152
|
+
const chapter1 = buildDocument({ markdown: 'One.\n\n::resource{id="tab"}', resources: [...resources, table] }, config);
|
|
153
|
+
const chapter2 = buildDocument({ markdown: 'Two.\n\n::resource{id="fig"}', resources: [...resources, table] }, config);
|
|
154
|
+
const pdfDoc = await PDFDocument.create();
|
|
155
|
+
const bytes = (id) => (id === 'fig.pdf' ? master : id === 'fig.svg' ? SVG : undefined);
|
|
156
|
+
const shared = await preloadResourceImages(pdfDoc, chapter1, bytes);
|
|
157
|
+
await preloadResourceImages(pdfDoc, chapter2, bytes, undefined, undefined, shared);
|
|
158
|
+
expect(shared.get('fig.svg')?.kind).toBe('page');
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
//# sourceMappingURL=printMaster.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"printMaster.test.js","sourceRoot":"","sources":["../../src/__tests__/printMaster.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAClF,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,OAAO,MAAM,kBAAkB,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAExC,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAC;AAC3E,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAEhD,kEAAkE;AAClE,2EAA2E;AAC3E,4EAA4E;AAE5E,MAAM,SAAS,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,GAAG,CAAC,oDAAoD,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAClH,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;AAEvC,MAAM,OAAO;IACX,IAAI,GAAG,EAAE,CAAC;IACV,WAAW,CAAC,CAAS;QACnB,MAAM,MAAM,GAAG,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,MAAM,IAAI,EAAE,CAAC;QACxD,OAAO,EAAE,KAAK,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,YAAY,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,MAAM,EAAE,CAAC;IAC7E,CAAC;CACF;AACA,UAAsD,CAAC,eAAe,GAAG;IACxE,UAAU;QACR,OAAO,IAAI,OAAO,EAAE,CAAC;IACvB,CAAC;CACF,CAAC;AAEF,MAAM,GAAG,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAClC,8IAA8I,CAC/I,CAAC;AAEF,KAAK,UAAU,SAAS;IACtB,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,MAAM,EAAE,CAAC;IAC1C,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,aAAa,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;IAClF,OAAO,MAAM,CAAC,IAAI,EAAE,CAAC;AACvB,CAAC;AAED,SAAS,GAAG,CAAC,QAA2B,EAAE,SAAS,GAAG,KAAK;IACzD,OAAO;QACL,MAAM,EAAE,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,YAAY,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,EAAE,EAAE;QACxF,MAAM,EAAE,CAAC;gBACP,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE;gBAC5C,aAAa,EAAE;oBACb,IAAI,EAAE,KAAK;oBACX,MAAM,EAAE,SAAS;oBACjB,QAAQ,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,QAAQ,EAAE;oBACjD,QAAQ,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE;iBACjD;aACF,CAAC;QACF,KAAK,EAAE,EAAE;KACgB,CAAC;AAC9B,CAAC;AAED,QAAQ,CAAC,+CAA+C,EAAE,GAAG,EAAE;IAC7D,EAAE,CAAC,qEAAqE,EAAE,KAAK,IAAI,EAAE;QACnF,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAC;QACjC,MAAM,KAAK,GAAa,EAAE,CAAC;QAC3B,MAAM,KAAK,GAAG,CAAC,EAAU,EAAE,EAAE;YAC3B,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACf,OAAO,EAAE,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC;QACxE,CAAC,CAAC;QACF,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,MAAM,EAAE,CAAC;QAC1C,MAAM,MAAM,GAAG,MAAM,qBAAqB,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,GAAG,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC;QACrH,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACjC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACnD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qEAAqE,EAAE,KAAK,IAAI,EAAE;QACnF,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,MAAM,EAAE,CAAC;QAC1C,MAAM,OAAO,GAAG,MAAM,qBAAqB,CACzC,MAAM,EACN,GAAG,CAAC,EAAE,GAAG,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,EAAE,CAAC,EACzD,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAC7C,CAAC;QACF,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACpD,MAAM,MAAM,GAAG,MAAM,qBAAqB,CACxC,MAAM,EACN,GAAG,CAAC,EAAE,GAAG,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,EAAE,CAAC,EACzD,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CACjH,CAAC;QACF,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wEAAwE,EAAE,KAAK,IAAI,EAAE;QACtF,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAC;QACjC,MAAM,KAAK,GAAa,EAAE,CAAC;QAC3B,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,MAAM,EAAE,CAAC;QAC1C,MAAM,MAAM,GAAG,MAAM,qBAAqB,CACxC,MAAM,EACN,GAAG,CAAC,EAAE,GAAG,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,EAAE,EAAE,IAAI,CAAC,EAC/D,CAAC,EAAE,EAAE,EAAE;YACL,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACf,OAAO,EAAE,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC;QACzC,CAAC,CACF,CAAC;QACF,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;QACvC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+EAA+E,EAAE,KAAK,IAAI,EAAE;QAC7F,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAC;QACjC,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,MAAM,EAAE,CAAC;QAC1C,MAAM,MAAM,GAAG,MAAM,qBAAqB,CACxC,MAAM,EACN,GAAG,CAAC,EAAE,GAAG,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,EAAE,CAAC,EACzD,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAChD,CAAC;QACF,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACnD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,qCAAqC,EAAE,GAAG,EAAE;IACnD,MAAM,EAAE,GAAG,CAAC,KAAa,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,IAAa,EAAE,CAAC,CAAC;IAC/D,MAAM,MAAM,GAAkB;QAC5B,IAAI,EAAE,EAAE,KAAK,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE;QAChH,QAAQ,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,WAAW,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,CAAC,EAAE;KACtE,CAAC;IACF,MAAM,SAAS,GAAe,CAAC;YAC7B,EAAE,EAAE,KAAK;YACT,MAAM,EAAE,QAAQ;YAChB,IAAI,EAAE,KAAK;YACX,SAAS,EAAE,CAAC;YACZ,SAAS,EAAE,CAAC;YACZ,GAAG,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,SAAS,EAAE,SAAS,EAAE;YACzE,SAAS,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE;SAChC,CAAC,CAAC;IAEH,EAAE,CAAC,mEAAmE,EAAE,KAAK,IAAI,EAAE;QACjF,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAC;QACjC,MAAM,GAAG,GAAG,aAAa,CAAC,EAAE,QAAQ,EAAE,+BAA+B,EAAE,SAAS,EAAE,EAAE,MAAM,CAAC,CAAC;QAC5F,MAAM,KAAK,GAAG,MAAM,WAAW,CAAC,GAAG,EAAE;YACnC,YAAY,EAAE,KAAK,IAAI,EAAE,CAAC,IAAI,UAAU,CAAC,SAAS,CAAC;YACnD,aAAa,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC;SACxF,CAAC,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC1C,MAAM,QAAQ,GAAG,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;QAChD,MAAM,IAAI,GAAG,QAAQ,YAAY,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;QAC5E,MAAM,OAAO,GAAG,IAAI;aACjB,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;YACX,MAAM,CAAC,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAClC,OAAO,CAAC,YAAY,YAAY,CAAC,CAAC,CAAC,IAAI,WAAW,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3G,CAAC,CAAC;aACD,IAAI,CAAC,IAAI,CAAC,CAAC;QACd,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,4BAA4B,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uFAAuF,EAAE,KAAK,IAAI,EAAE;QACrG,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAC;QACjC,MAAM,KAAK,GAAa;YACtB,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC;YACrE,KAAK,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE;YACjF,SAAS,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE;SAChC,CAAC;QACF,MAAM,IAAI,GAA2C;YACnD,CAAC,MAAM,EAAE,MAAM,EAAE,+BAA+B,CAAC;YACjD,CAAC,cAAc,EAAE;oBACf,GAAG,MAAM;oBACT,MAAM,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE;iBAChK,EAAE,OAAO,CAAC;YACX,CAAC,UAAU,EAAE,EAAE,GAAG,MAAM,EAAE,aAAa,EAAE,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,KAAK,EAAE,EAAE,CAAC,EAAE,EAAE,sCAAsC,CAAC;SACpJ,CAAC;QACF,KAAK,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,QAAQ,CAAC,IAAI,IAAI,EAAE,CAAC;YACxC,MAAM,GAAG,GAAG,aAAa,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,GAAG,SAAS,EAAE,KAAK,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;YAC/E,MAAM,KAAK,GAAa,EAAE,CAAC;YAC3B,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,MAAM,EAAE,CAAC;YAC1C,MAAM,MAAM,GAAG,MAAM,qBAAqB,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,EAAE,EAAE,EAAE;gBAC7D,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBACf,OAAO,EAAE,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC;YACxE,CAAC,CAAC,CAAC;YACH,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACtC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACxD,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iFAAiF,EAAE,KAAK,IAAI,EAAE;QAC/F,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAC;QACjC,MAAM,KAAK,GAAa;YACtB,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC;YACrE,KAAK,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE;YACjF,SAAS,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE;SAChC,CAAC;QACF,MAAM,QAAQ,GAAG,aAAa,CAAC,EAAE,QAAQ,EAAE,8BAA8B,EAAE,SAAS,EAAE,CAAC,GAAG,SAAS,EAAE,KAAK,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;QACvH,MAAM,QAAQ,GAAG,aAAa,CAAC,EAAE,QAAQ,EAAE,8BAA8B,EAAE,SAAS,EAAE,CAAC,GAAG,SAAS,EAAE,KAAK,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;QACvH,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,MAAM,EAAE,CAAC;QAC1C,MAAM,KAAK,GAAG,CAAC,EAAU,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;QAC/F,MAAM,MAAM,GAAG,MAAM,qBAAqB,CAAC,MAAM,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;QACpE,MAAM,qBAAqB,CAAC,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;QACnF,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACnD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"renderWarnings.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/renderWarnings.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import { PDFArray, PDFDocument, PDFRawStream, decodePDFRawStream } from 'pdf-lib';
|
|
4
|
+
import fontkit from '@pdf-lib/fontkit';
|
|
5
|
+
import { buildDocument } from 'postext';
|
|
6
|
+
import { renderToPdf } from '../pdf-backend';
|
|
7
|
+
import { parseFontString } from '../fontString';
|
|
8
|
+
const fontBytes = fs.readFileSync(new URL('../../../../apps/web/public/fonts/Lora-Regular.ttf', import.meta.url));
|
|
9
|
+
const fontProvider = async () => new Uint8Array(fontBytes);
|
|
10
|
+
const face = fontkit.create(fontBytes);
|
|
11
|
+
class StubCtx {
|
|
12
|
+
font = '';
|
|
13
|
+
measureText(s) {
|
|
14
|
+
const sizePx = parseFontString(this.font)?.sizePx ?? 16;
|
|
15
|
+
const run = face.layout(s);
|
|
16
|
+
return { width: (run.advanceWidth / face.unitsPerEm) * sizePx };
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
globalThis.OffscreenCanvas = class {
|
|
20
|
+
getContext() {
|
|
21
|
+
return new StubCtx();
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
const pt = (value) => ({ value, unit: 'pt' });
|
|
25
|
+
const hex = (h) => ({ hex: h, model: 'hex' });
|
|
26
|
+
const cell = (content, extra = {}) => ({ content, ...extra });
|
|
27
|
+
const PAGE = {
|
|
28
|
+
page: { width: pt(400), height: pt(500), margins: { top: pt(20), bottom: pt(20), left: pt(20), right: pt(20) } },
|
|
29
|
+
headings: { balancing: { enabled: false }, levels: [{ level: 1, breakBefore: { enabled: false } }] },
|
|
30
|
+
};
|
|
31
|
+
const table = {
|
|
32
|
+
id: 'parts',
|
|
33
|
+
typeId: 'table',
|
|
34
|
+
kind: 'table',
|
|
35
|
+
caption: 'Parts.',
|
|
36
|
+
createdAt: 0,
|
|
37
|
+
updatedAt: 0,
|
|
38
|
+
table: {
|
|
39
|
+
model: {
|
|
40
|
+
headerRowCount: 1,
|
|
41
|
+
rows: [
|
|
42
|
+
[cell('Part', { isHeader: true }), cell('Qty', { isHeader: true })],
|
|
43
|
+
...Array.from({ length: 4 }, (_, i) => [cell(`Part ${i + 1}`), cell(String(i + 2))]),
|
|
44
|
+
],
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
placement: { position: 'here' },
|
|
48
|
+
};
|
|
49
|
+
const photo = {
|
|
50
|
+
id: 'photo',
|
|
51
|
+
typeId: 'figure',
|
|
52
|
+
kind: 'bitmap',
|
|
53
|
+
caption: 'A photo.',
|
|
54
|
+
createdAt: 0,
|
|
55
|
+
updatedAt: 0,
|
|
56
|
+
bitmap: { fileId: 'file-photo', format: 'png', width: 400, height: 300 },
|
|
57
|
+
placement: { position: 'here' },
|
|
58
|
+
};
|
|
59
|
+
async function pageText(bytes, index = 0) {
|
|
60
|
+
const pdf = await PDFDocument.load(bytes);
|
|
61
|
+
const contents = pdf.getPage(index).node.Contents();
|
|
62
|
+
const streams = contents instanceof PDFArray ? contents.asArray().map((r) => pdf.context.lookup(r)) : [contents];
|
|
63
|
+
return streams
|
|
64
|
+
.map((s) => (s instanceof PDFRawStream ? Buffer.from(decodePDFRawStream(s).decode()).toString('latin1') : ''))
|
|
65
|
+
.join('\n');
|
|
66
|
+
}
|
|
67
|
+
/** Non-stroking RGB fills set on a page (`r g b rg`). */
|
|
68
|
+
const fills = (text) => [...text.matchAll(/([\d.]+) ([\d.]+) ([\d.]+) rg/g)].map((m) => m.slice(1, 4).map((v) => Number(v).toFixed(3)).join(' '));
|
|
69
|
+
describe('zebra rows in the PDF', () => {
|
|
70
|
+
it('fills the alternate body rows, and only when enabled', async () => {
|
|
71
|
+
const md = '::resource{id="parts"}\n';
|
|
72
|
+
const zebra = { ...PAGE, tableStyle: { bodyAlternateBackgroundEnabled: true, bodyAlternateBackground: hex('#eef3fa') } };
|
|
73
|
+
const stripe = [0xee, 0xf3, 0xfa].map((v) => (v / 255).toFixed(3)).join(' ');
|
|
74
|
+
const on = fills(await pageText(await renderToPdf(buildDocument({ markdown: md, resources: [table] }, zebra), { fontProvider })));
|
|
75
|
+
const off = fills(await pageText(await renderToPdf(buildDocument({ markdown: md, resources: [table] }, PAGE), { fontProvider })));
|
|
76
|
+
// Body rows 2 and 4 × two columns.
|
|
77
|
+
expect(on.filter((f) => f === stripe)).toHaveLength(4);
|
|
78
|
+
expect(off).not.toContain(stripe);
|
|
79
|
+
}, 60_000);
|
|
80
|
+
});
|
|
81
|
+
describe('render warnings in the PDF', () => {
|
|
82
|
+
it('reports an image with no bytes once, with its document and page', async () => {
|
|
83
|
+
const doc = buildDocument({ markdown: 'Text.\n\n::resource{id="photo"}\n\nMore :ref{id="photo"}.\n', resources: [photo] }, PAGE);
|
|
84
|
+
const warnings = [];
|
|
85
|
+
await renderToPdf([doc, doc], { fontProvider, onWarning: (w) => warnings.push(w) });
|
|
86
|
+
expect(warnings).toEqual([{ kind: 'missingImage', fileId: 'file-photo', resourceId: 'photo', pageIndex: 0, documentIndex: 0 }]);
|
|
87
|
+
}, 60_000);
|
|
88
|
+
});
|
|
89
|
+
//# sourceMappingURL=renderWarnings.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"renderWarnings.test.js","sourceRoot":"","sources":["../../src/__tests__/renderWarnings.test.ts"],"names":[],"mappings":"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"}
|