postext-pdf 1.56.0 → 1.57.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.
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=moduleTextOver.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"moduleTextOver.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/moduleTextOver.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,75 @@
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/index.js';
7
+ import { parseFontString } from '../fontString.js';
8
+ // #1189: a text of a module template is painted after the module's frames
9
+ // (a label on its picture shows), left to right and through the mirrored
10
+ // flow of a right-to-left page. With `over: false` it is painted with the
11
+ // decoration, before the picture.
12
+ const fontBytes = fs.readFileSync(new URL('../../../../apps/web/public/fonts/Lora-Regular.ttf', import.meta.url));
13
+ const face = fontkit.create(fontBytes);
14
+ const fontProvider = async () => new Uint8Array(fontBytes);
15
+ class StubCtx {
16
+ font = '';
17
+ measureText(s) {
18
+ const sizePx = parseFontString(this.font)?.sizePx ?? 16;
19
+ return { width: (face.layout(s).advanceWidth / face.unitsPerEm) * sizePx };
20
+ }
21
+ }
22
+ globalThis.OffscreenCanvas = class {
23
+ getContext() {
24
+ return new StubCtx();
25
+ }
26
+ };
27
+ const PNG = Uint8Array.from(Buffer.from('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg==', 'base64'));
28
+ const mm = (value) => ({ value, unit: 'mm' });
29
+ const PLAN = {
30
+ id: 'plan', typeId: 'figure', kind: 'bitmap', altText: 'A plan of a garden', caption: '', createdAt: 0, updatedAt: 0,
31
+ bitmap: { fileId: 'plan.png', format: 'png', width: 400, height: 300 },
32
+ };
33
+ const config = (direction, over) => ({
34
+ locale: 'en-us',
35
+ direction,
36
+ header: { elements: [] },
37
+ footer: { elements: [] },
38
+ pageTemplates: [
39
+ { id: 'shell', groups: [{ name: 'body', modules: true, placement: { anchor: { to: 'container', edge: 'top-left' }, size: { width: 'fill', height: 'fill' } } }] },
40
+ {
41
+ id: 'card',
42
+ role: 'module',
43
+ frames: [{ name: 'picture', width: mm(90), height: mm(70), placement: { anchor: { to: 'container', edge: 'top-left' } } }],
44
+ decoration: { elements: [{
45
+ kind: 'text', id: 'label', content: '{attr.label}', fontSize: { value: 10, unit: 'pt' }, color: { hex: '#c0392b', model: 'hex' },
46
+ placement: { anchor: { to: '#picture', edge: 'top-left' }, offset: { x: mm(3), y: mm(3) } }, ...(over === undefined ? {} : { over }),
47
+ }] },
48
+ },
49
+ ],
50
+ });
51
+ const markdown = '::::page{template="shell"}\n:::module{template="card" label="Pond"}\n:::frame{slot="picture"}\n:::figure{resource="plan"}\n:::\n:::\n:::\n::::\n';
52
+ async function pageOps(direction, over) {
53
+ const doc = buildDocument({ markdown, resources: [PLAN] }, config(direction, over));
54
+ const pdf = await PDFDocument.load(await renderToPdf(doc, { fontProvider, resourceBytes: (id) => (id === 'plan.png' ? PNG : undefined) }));
55
+ const contents = pdf.getPage(0).node.Contents();
56
+ const streams = contents instanceof PDFArray ? contents.asArray().map((r) => pdf.context.lookup(r)) : [contents];
57
+ return streams.map((s) => (s instanceof PDFRawStream ? Buffer.from(decodePDFRawStream(s).decode()).toString('latin1') : '')).join('\n').split(/\s+/);
58
+ }
59
+ /** The first filling colour op of the label's red (#c0392b). */
60
+ const red = (ops) => ops.findIndex((op, i) => op === 'rg' && Math.abs(Number(ops[i - 3]) - 0xc0 / 255) < 0.002 && Math.abs(Number(ops[i - 2]) - 0x39 / 255) < 0.002);
61
+ /** The picture's paint (`/ImN Do`). */
62
+ const image = (ops) => ops.findIndex((op, i) => op === 'Do' && /^\/Im|^\/I\d|^\/X/.test(ops[i - 1] ?? ''));
63
+ describe('a module text in the PDF (#1189)', () => {
64
+ for (const direction of ['ltr', 'rtl']) {
65
+ it(`${direction}: filled after the module's picture by default, before it with over: false`, async () => {
66
+ const ops = await pageOps(direction);
67
+ expect(image(ops)).toBeGreaterThan(0);
68
+ expect(red(ops)).toBeGreaterThan(image(ops));
69
+ const under = await pageOps(direction, false);
70
+ expect(red(under)).toBeGreaterThan(-1);
71
+ expect(red(under)).toBeLessThan(image(under));
72
+ }, 60_000);
73
+ }
74
+ });
75
+ //# sourceMappingURL=moduleTextOver.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"moduleTextOver.test.js","sourceRoot":"","sources":["../../src/__tests__/moduleTextOver.test.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "postext-pdf",
3
- "version": "1.56.0",
3
+ "version": "1.57.0",
4
4
  "description": "Browser-native PDF renderer for Postext documents. Consumes the same VDT as the canvas/HTML backends and produces a physical PDF with faithful glyph positioning, justification, crop marks, and baseline grid.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -40,7 +40,7 @@
40
40
  "./package.json": "./package.json"
41
41
  },
42
42
  "peerDependencies": {
43
- "postext": "^1.56.0"
43
+ "postext": "^1.57.0"
44
44
  },
45
45
  "dependencies": {
46
46
  "@pdf-lib/fontkit": "^1.1.1",
@@ -53,7 +53,7 @@
53
53
  "@types/node": "^26.5.0",
54
54
  "eslint": "^9.39.4",
55
55
  "harfbuzzjs": "1.6.2",
56
- "postext": "1.56.0",
56
+ "postext": "1.57.0",
57
57
  "typescript": "^6.0.3",
58
58
  "typescript-eslint": "^8.70.0",
59
59
  "vitest": "^5.0.0",