@build-qube/papyra 0.1.0 → 0.3.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.
Files changed (56) hide show
  1. package/README.md +46 -1
  2. package/dist/attachments.d.ts +76 -0
  3. package/dist/attachments.d.ts.map +1 -0
  4. package/dist/attachments.js +65 -0
  5. package/dist/attachments.js.map +1 -0
  6. package/dist/canvas.d.ts +27 -2
  7. package/dist/canvas.d.ts.map +1 -1
  8. package/dist/canvas.js +58 -5
  9. package/dist/canvas.js.map +1 -1
  10. package/dist/document.d.ts +179 -4
  11. package/dist/document.d.ts.map +1 -1
  12. package/dist/document.js +311 -12
  13. package/dist/document.js.map +1 -1
  14. package/dist/encode.d.ts +2 -2
  15. package/dist/encode.d.ts.map +1 -1
  16. package/dist/encode.js +1 -1
  17. package/dist/encode.js.map +1 -1
  18. package/dist/encoded.d.ts +34 -5
  19. package/dist/encoded.d.ts.map +1 -1
  20. package/dist/encoded.js +28 -0
  21. package/dist/encoded.js.map +1 -1
  22. package/dist/errors.d.ts +45 -0
  23. package/dist/errors.d.ts.map +1 -0
  24. package/dist/errors.js +69 -0
  25. package/dist/errors.js.map +1 -0
  26. package/dist/fingerprint.d.ts +18 -0
  27. package/dist/fingerprint.d.ts.map +1 -0
  28. package/dist/fingerprint.js +48 -0
  29. package/dist/fingerprint.js.map +1 -0
  30. package/dist/index.d.ts +14 -5
  31. package/dist/index.d.ts.map +1 -1
  32. package/dist/index.js +6 -2
  33. package/dist/index.js.map +1 -1
  34. package/dist/links.d.ts +53 -0
  35. package/dist/links.d.ts.map +1 -0
  36. package/dist/links.js +26 -0
  37. package/dist/links.js.map +1 -0
  38. package/dist/outline.d.ts +9 -1
  39. package/dist/outline.d.ts.map +1 -1
  40. package/dist/outline.js +9 -3
  41. package/dist/outline.js.map +1 -1
  42. package/dist/structure.d.ts +119 -0
  43. package/dist/structure.d.ts.map +1 -0
  44. package/dist/structure.js +115 -0
  45. package/dist/structure.js.map +1 -0
  46. package/dist/text.d.ts +20 -0
  47. package/dist/text.d.ts.map +1 -1
  48. package/dist/text.js +9 -0
  49. package/dist/text.js.map +1 -1
  50. package/dist/types.d.ts +75 -0
  51. package/dist/types.d.ts.map +1 -1
  52. package/dist/viewport.d.ts +129 -0
  53. package/dist/viewport.d.ts.map +1 -0
  54. package/dist/viewport.js +163 -0
  55. package/dist/viewport.js.map +1 -0
  56. package/package.json +2 -2
package/README.md CHANGED
@@ -75,7 +75,52 @@ for (const node of await doc.outline()) {
75
75
  ```
76
76
 
77
77
  `renderImage` keeps the pixels in Rust and encodes on demand, so nothing but the
78
- finished file crosses into JS.
78
+ finished file crosses into JS. For output that has to survive being scaled there is
79
+ `doc.renderSvg(0)`, which returns vector markup instead of pixels and so takes no
80
+ size and no quality.
81
+
82
+ ## Links, labels, and what the file says about itself
83
+
84
+ ```ts
85
+ const scale = rendered.width / doc.pageSize(index).width;
86
+ for (const link of await doc.links(index)) {
87
+ const box = scaleRect(link.rect, scale);
88
+ if (link.target.kind === 'uri') openExternally(link.target.uri);
89
+ else goTo(link.target.dest.page);
90
+ }
91
+
92
+ const labels = await doc.pageLabels();
93
+ const shown = labels[index] || String(index + 1); // "iv", not "4"
94
+
95
+ doc.metadata.title; // null when the document never said
96
+ doc.fingerprint; // stable key for per-document state
97
+ ```
98
+
99
+ Link rectangles are in the same space as extracted text — 72 DPI from the top-left,
100
+ rotation applied — so one multiply places them over any render. `pageLabels()` is empty
101
+ when the document defines no labels, which is your signal to number by index.
102
+
103
+ Encrypted files throw `PasswordRequiredError` or `IncorrectPasswordError`, both
104
+ extending `PasswordError` with a `retry` flag, so one dialog handles the cold ask and
105
+ the wrong answer.
106
+
107
+ ## Rotate the view
108
+
109
+ ```ts
110
+ const vp = viewport(doc.pageSize(index), { fitWidth: 1600, rotation: 90 });
111
+
112
+ paintToCanvas(await doc.renderPage(index, { dpi: vp.dpi }), canvas, {
113
+ rotation: vp.rotation,
114
+ });
115
+ const box = viewportRect(link.rect, vp); // the link layer, turned to match
116
+ ```
117
+
118
+ Pages render unrotated and the canvas does the turning, so a rotate button costs no
119
+ render. Size through the viewport rather than with `fitWidth` directly: turned, the
120
+ width on screen is the page's height, and `vp.dpi` carries the answer back.
121
+
122
+ Renders draw annotations by default. Pass `{ annotations: false }` when you are drawing
123
+ your own link or highlight layer, or they appear twice.
79
124
 
80
125
  ## Two things that will bite you
81
126
 
@@ -0,0 +1,76 @@
1
+ import type { Attachment as NativeAttachment } from '@build-qube/papyra-native';
2
+ /**
3
+ * A file embedded in the document.
4
+ *
5
+ * Metadata only. The bytes come from {@link Document.attachmentData}, because listing
6
+ * what a document carries is a different question from opening one of the things it
7
+ * carries, and an embedded file is as large as it is.
8
+ */
9
+ export interface Attachment {
10
+ /** Position in {@link Document.attachments}, and what identifies it for a fetch. */
11
+ readonly index: number;
12
+ /**
13
+ * The name to save the file under.
14
+ *
15
+ * `/UF` where the document provides it — the Unicode spelling, and the one the spec
16
+ * tells a reader to prefer — falling back to `/F`, then to the name the file was
17
+ * filed under. Never empty.
18
+ */
19
+ readonly name: string;
20
+ /** The document's own description of what the file is for. */
21
+ readonly description: string | null;
22
+ /**
23
+ * The declared media type, e.g. `'application/xml'`.
24
+ *
25
+ * Absent more often than not, so fall back to the extension on {@link name} rather
26
+ * than treating this as the answer. {@link attachmentMediaType} does exactly that.
27
+ */
28
+ readonly mediaType: string | null;
29
+ /**
30
+ * Length in bytes, uncompressed, **as the document claims it**.
31
+ *
32
+ * Not a measurement: reading the true length means decompressing the stream, which
33
+ * is the work this type exists to defer. Fine for a size column; not something to
34
+ * allocate against.
35
+ */
36
+ readonly size: number | null;
37
+ /** Creation date, ISO 8601. */
38
+ readonly created: string | null;
39
+ /** Modification date, ISO 8601. */
40
+ readonly modified: string | null;
41
+ /**
42
+ * What the file is to the document: `'Source'`, `'Data'`, `'Alternative'`,
43
+ * `'Supplement'`, `'EncryptedPayload'` or `'Unspecified'`.
44
+ *
45
+ * This is what identifies a hybrid invoice. A ZUGFeRD or Factur-X PDF carries its
46
+ * XML with a relationship of `Alternative` or `Data`, and that is the difference
47
+ * between a machine-readable invoice and a PDF with a file stapled to it — see
48
+ * {@link isInvoiceAttachment}.
49
+ */
50
+ readonly relationship: string | null;
51
+ }
52
+ /** @internal */
53
+ export declare function toAttachment(native: NativeAttachment, index: number): Attachment;
54
+ /**
55
+ * The attachment's media type, falling back to its extension.
56
+ *
57
+ * `'application/octet-stream'` when neither answers, which is the honest default for
58
+ * bytes nothing describes — and the one a download will not misrender.
59
+ */
60
+ export declare function attachmentMediaType(file: Attachment): string;
61
+ /**
62
+ * Whether this attachment is the machine-readable half of a hybrid invoice.
63
+ *
64
+ * ZUGFeRD, Factur-X, Order-X and XRechnung all work the same way: the PDF is what a
65
+ * person reads, and an embedded XML file is what an accounting system reads. Both
66
+ * halves are the same invoice, and a consumer that ignores the XML is retyping data
67
+ * the document already carries.
68
+ *
69
+ * Matched on the standardised filename rather than on
70
+ * {@link Attachment.relationship} alone. The relationship narrows it — the standards
71
+ * require `Alternative` or `Data` — but producers get it wrong often enough that
72
+ * requiring it would miss real invoices, while the filenames are fixed by the
73
+ * specifications and are what every other implementation keys on.
74
+ */
75
+ export declare function isInvoiceAttachment(file: Attachment): boolean;
76
+ //# sourceMappingURL=attachments.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attachments.d.ts","sourceRoot":"","sources":["../src/attachments.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,IAAI,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAEhF;;;;;;GAMG;AACH,MAAM,WAAW,UAAU;IACzB,oFAAoF;IACpF,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB;;;;;;OAMG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,8DAA8D;IAC9D,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC;;;;;OAKG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC;;;;;;OAMG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,+BAA+B;IAC/B,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,mCAAmC;IACnC,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC;;;;;;;;OAQG;IACH,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CACtC;AAED,gBAAgB;AAChB,wBAAgB,YAAY,CAC1B,MAAM,EAAE,gBAAgB,EACxB,KAAK,EAAE,MAAM,GACZ,UAAU,CAWZ;AAiBD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAK5D;AAUD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAE7D"}
@@ -0,0 +1,65 @@
1
+ /** @internal */
2
+ export function toAttachment(native, index) {
3
+ return {
4
+ index,
5
+ name: native.name,
6
+ description: native.description ?? null,
7
+ mediaType: native.mediaType ?? null,
8
+ size: native.size ?? null,
9
+ created: native.created ?? null,
10
+ modified: native.modified ?? null,
11
+ relationship: native.relationship ?? null,
12
+ };
13
+ }
14
+ /** Extension to media type, for the majority of files that declare none. */
15
+ const BY_EXTENSION = {
16
+ csv: 'text/csv',
17
+ html: 'text/html',
18
+ json: 'application/json',
19
+ pdf: 'application/pdf',
20
+ png: 'image/png',
21
+ jpg: 'image/jpeg',
22
+ jpeg: 'image/jpeg',
23
+ svg: 'image/svg+xml',
24
+ txt: 'text/plain',
25
+ xml: 'application/xml',
26
+ zip: 'application/zip',
27
+ };
28
+ /**
29
+ * The attachment's media type, falling back to its extension.
30
+ *
31
+ * `'application/octet-stream'` when neither answers, which is the honest default for
32
+ * bytes nothing describes — and the one a download will not misrender.
33
+ */
34
+ export function attachmentMediaType(file) {
35
+ if (file.mediaType)
36
+ return file.mediaType;
37
+ const dot = file.name.lastIndexOf('.');
38
+ const extension = dot < 0 ? '' : file.name.slice(dot + 1).toLowerCase();
39
+ return BY_EXTENSION[extension] ?? 'application/octet-stream';
40
+ }
41
+ /** The filenames the hybrid-invoice standards define, lowercased. */
42
+ const INVOICE_NAMES = new Set([
43
+ 'factur-x.xml',
44
+ 'zugferd-invoice.xml',
45
+ 'xrechnung.xml',
46
+ 'order-x.xml',
47
+ ]);
48
+ /**
49
+ * Whether this attachment is the machine-readable half of a hybrid invoice.
50
+ *
51
+ * ZUGFeRD, Factur-X, Order-X and XRechnung all work the same way: the PDF is what a
52
+ * person reads, and an embedded XML file is what an accounting system reads. Both
53
+ * halves are the same invoice, and a consumer that ignores the XML is retyping data
54
+ * the document already carries.
55
+ *
56
+ * Matched on the standardised filename rather than on
57
+ * {@link Attachment.relationship} alone. The relationship narrows it — the standards
58
+ * require `Alternative` or `Data` — but producers get it wrong often enough that
59
+ * requiring it would miss real invoices, while the filenames are fixed by the
60
+ * specifications and are what every other implementation keys on.
61
+ */
62
+ export function isInvoiceAttachment(file) {
63
+ return INVOICE_NAMES.has(file.name.toLowerCase());
64
+ }
65
+ //# sourceMappingURL=attachments.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attachments.js","sourceRoot":"","sources":["../src/attachments.ts"],"names":[],"mappings":"AAqDA,gBAAgB;AAChB,MAAM,UAAU,YAAY,CAC1B,MAAwB,EACxB,KAAa;IAEb,OAAO;QACL,KAAK;QACL,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,WAAW,EAAE,MAAM,CAAC,WAAW,IAAI,IAAI;QACvC,SAAS,EAAE,MAAM,CAAC,SAAS,IAAI,IAAI;QACnC,IAAI,EAAE,MAAM,CAAC,IAAI,IAAI,IAAI;QACzB,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,IAAI;QAC/B,QAAQ,EAAE,MAAM,CAAC,QAAQ,IAAI,IAAI;QACjC,YAAY,EAAE,MAAM,CAAC,YAAY,IAAI,IAAI;KAC1C,CAAC;AACJ,CAAC;AAED,4EAA4E;AAC5E,MAAM,YAAY,GAA2B;IAC3C,GAAG,EAAE,UAAU;IACf,IAAI,EAAE,WAAW;IACjB,IAAI,EAAE,kBAAkB;IACxB,GAAG,EAAE,iBAAiB;IACtB,GAAG,EAAE,WAAW;IAChB,GAAG,EAAE,YAAY;IACjB,IAAI,EAAE,YAAY;IAClB,GAAG,EAAE,eAAe;IACpB,GAAG,EAAE,YAAY;IACjB,GAAG,EAAE,iBAAiB;IACtB,GAAG,EAAE,iBAAiB;CACvB,CAAC;AAEF;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAAgB;IAClD,IAAI,IAAI,CAAC,SAAS;QAAE,OAAO,IAAI,CAAC,SAAS,CAAC;IAC1C,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IACvC,MAAM,SAAS,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;IACxE,OAAO,YAAY,CAAC,SAAS,CAAC,IAAI,0BAA0B,CAAC;AAC/D,CAAC;AAED,qEAAqE;AACrE,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC;IAC5B,cAAc;IACd,qBAAqB;IACrB,eAAe;IACf,aAAa;CACd,CAAC,CAAC;AAEH;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAAgB;IAClD,OAAO,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;AACpD,CAAC"}
package/dist/canvas.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import type { RenderedPage } from './types.js';
2
+ import type { Rotation } from './viewport.js';
2
3
  /**
3
4
  * Wrap a rendered page as `ImageData`, ready for `putImageData`.
4
5
  *
@@ -7,6 +8,30 @@ import type { RenderedPage } from './types.js';
7
8
  * unconditionally keeps both runtimes on the same path.
8
9
  */
9
10
  export declare function toImageData(page: RenderedPage): ImageData;
10
- /** Paint a rendered page onto a canvas, resizing the canvas to match. */
11
- export declare function paintToCanvas(page: RenderedPage, canvas: HTMLCanvasElement | OffscreenCanvas): void;
11
+ /** How to paint. */
12
+ export interface PaintOptions {
13
+ /**
14
+ * Quarter turns clockwise to apply while drawing. Defaults to none.
15
+ *
16
+ * Free in the sense that matters: the pixels are not copied twice and no rotated
17
+ * bitmap is retained. Pair it with a {@link Viewport} of the same rotation so that
18
+ * link regions and text highlights land on the same page the pixels do.
19
+ */
20
+ rotation?: Rotation;
21
+ }
22
+ /**
23
+ * Paint a rendered page onto a canvas, resizing the canvas to match.
24
+ *
25
+ * With a `rotation` the canvas takes the turned dimensions — a 90° view of a portrait
26
+ * page is a landscape canvas.
27
+ *
28
+ * @example
29
+ * ```ts
30
+ * const vp = viewport(doc.pageSize(0), { fitWidth: 1600, rotation: 90 });
31
+ * paintToCanvas(await doc.renderPage(0, { dpi: vp.dpi }), canvas, {
32
+ * rotation: vp.rotation,
33
+ * });
34
+ * ```
35
+ */
36
+ export declare function paintToCanvas(page: RenderedPage, canvas: HTMLCanvasElement | OffscreenCanvas, options?: PaintOptions): void;
12
37
  //# sourceMappingURL=canvas.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"canvas.d.ts","sourceRoot":"","sources":["../src/canvas.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,YAAY,GAAG,SAAS,CAMzD;AAED,yEAAyE;AACzE,wBAAgB,aAAa,CAC3B,IAAI,EAAE,YAAY,EAClB,MAAM,EAAE,iBAAiB,GAAG,eAAe,GAC1C,IAAI,CASN"}
1
+ {"version":3,"file":"canvas.d.ts","sourceRoot":"","sources":["../src/canvas.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAU9C;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,YAAY,GAAG,SAAS,CAMzD;AAED,oBAAoB;AACpB,MAAM,WAAW,YAAY;IAC3B;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,YAAY,EAClB,MAAM,EAAE,iBAAiB,GAAG,eAAe,EAC3C,OAAO,GAAE,YAAiB,GACzB,IAAI,CA+BN"}
package/dist/canvas.js CHANGED
@@ -8,13 +8,66 @@
8
8
  export function toImageData(page) {
9
9
  return new ImageData(Uint8ClampedArray.from(page.data), page.width, page.height);
10
10
  }
11
- /** Paint a rendered page onto a canvas, resizing the canvas to match. */
12
- export function paintToCanvas(page, canvas) {
13
- canvas.width = page.width;
14
- canvas.height = page.height;
11
+ /**
12
+ * Paint a rendered page onto a canvas, resizing the canvas to match.
13
+ *
14
+ * With a `rotation` the canvas takes the turned dimensions — a 90° view of a portrait
15
+ * page is a landscape canvas.
16
+ *
17
+ * @example
18
+ * ```ts
19
+ * const vp = viewport(doc.pageSize(0), { fitWidth: 1600, rotation: 90 });
20
+ * paintToCanvas(await doc.renderPage(0, { dpi: vp.dpi }), canvas, {
21
+ * rotation: vp.rotation,
22
+ * });
23
+ * ```
24
+ */
25
+ export function paintToCanvas(page, canvas, options = {}) {
26
+ const rotation = options.rotation ?? 0;
27
+ const turned = rotation === 90 || rotation === 270;
28
+ canvas.width = turned ? page.height : page.width;
29
+ canvas.height = turned ? page.width : page.height;
15
30
  const ctx = canvas.getContext('2d');
16
31
  if (!ctx)
17
32
  throw new Error('papyra: could not get a 2d canvas context');
18
- ctx.putImageData(toImageData(page), 0, 0);
33
+ if (rotation === 0) {
34
+ ctx.putImageData(toImageData(page), 0, 0);
35
+ return;
36
+ }
37
+ // `putImageData` writes straight to the backing store and ignores the transform, so
38
+ // a rotation cannot go through it. The pixels land on a scratch surface first and
39
+ // are then blitted under a transform, which is one extra copy — against rotating
40
+ // the buffer ourselves, which is a copy plus a per-pixel loop in JS.
41
+ const scratch = scratchCanvas(page.width, page.height);
42
+ const scratchCtx = scratch.getContext('2d');
43
+ if (!scratchCtx)
44
+ throw new Error('papyra: could not get a 2d canvas context');
45
+ scratchCtx.putImageData(toImageData(page), 0, 0);
46
+ // Each pair puts the rotated page's origin back at the canvas corner: at 90° the
47
+ // page's top-left corner ends up top-right, so the axes move there first.
48
+ if (rotation === 90)
49
+ ctx.translate(canvas.width, 0);
50
+ else if (rotation === 180)
51
+ ctx.translate(canvas.width, canvas.height);
52
+ else
53
+ ctx.translate(0, canvas.height);
54
+ ctx.rotate((rotation * Math.PI) / 180);
55
+ ctx.drawImage(scratch, 0, 0);
56
+ ctx.setTransform(1, 0, 0, 1, 0, 0);
57
+ }
58
+ /**
59
+ * A surface to hold the unrotated pixels.
60
+ *
61
+ * `OffscreenCanvas` when there is one — it is the only option inside a worker, where
62
+ * there is no `document` to create an element from.
63
+ */
64
+ function scratchCanvas(width, height) {
65
+ if (typeof OffscreenCanvas !== 'undefined') {
66
+ return new OffscreenCanvas(width, height);
67
+ }
68
+ const el = document.createElement('canvas');
69
+ el.width = width;
70
+ el.height = height;
71
+ return el;
19
72
  }
20
73
  //# sourceMappingURL=canvas.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"canvas.js","sourceRoot":"","sources":["../src/canvas.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CAAC,IAAkB;IAC5C,OAAO,IAAI,SAAS,CAClB,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EACjC,IAAI,CAAC,KAAK,EACV,IAAI,CAAC,MAAM,CACZ,CAAC;AACJ,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,aAAa,CAC3B,IAAkB,EAClB,MAA2C;IAE3C,MAAM,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;IAC1B,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;IAC5B,MAAM,GAAG,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,CAG1B,CAAC;IACT,IAAI,CAAC,GAAG;QAAE,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;IACvE,GAAG,CAAC,YAAY,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;AAC5C,CAAC"}
1
+ {"version":3,"file":"canvas.js","sourceRoot":"","sources":["../src/canvas.ts"],"names":[],"mappings":"AAWA;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CAAC,IAAkB;IAC5C,OAAO,IAAI,SAAS,CAClB,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EACjC,IAAI,CAAC,KAAK,EACV,IAAI,CAAC,MAAM,CACZ,CAAC;AACJ,CAAC;AAcD;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,aAAa,CAC3B,IAAkB,EAClB,MAA2C,EAC3C,OAAO,GAAiB,EAAE;IAE1B,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,CAAC,CAAC;IACvC,MAAM,MAAM,GAAG,QAAQ,KAAK,EAAE,IAAI,QAAQ,KAAK,GAAG,CAAC;IACnD,MAAM,CAAC,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC;IACjD,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC;IAElD,MAAM,GAAG,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,CAAsB,CAAC;IACzD,IAAI,CAAC,GAAG;QAAE,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;IAEvE,IAAI,QAAQ,KAAK,CAAC,EAAE,CAAC;QACnB,GAAG,CAAC,YAAY,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QAC1C,OAAO;IACT,CAAC;IAED,oFAAoF;IACpF,kFAAkF;IAClF,iFAAiF;IACjF,qEAAqE;IACrE,MAAM,OAAO,GAAG,aAAa,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IACvD,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,IAAI,CAAsB,CAAC;IACjE,IAAI,CAAC,UAAU;QAAE,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;IAC9E,UAAU,CAAC,YAAY,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IAEjD,iFAAiF;IACjF,0EAA0E;IAC1E,IAAI,QAAQ,KAAK,EAAE;QAAE,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;SAC/C,IAAI,QAAQ,KAAK,GAAG;QAAE,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;;QACjE,GAAG,CAAC,SAAS,CAAC,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IACrC,GAAG,CAAC,MAAM,CAAC,CAAC,QAAQ,GAAG,IAAI,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC;IACvC,GAAG,CAAC,SAAS,CAAC,OAA4B,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IAClD,GAAG,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;AACrC,CAAC;AAED;;;;;GAKG;AACH,SAAS,aAAa,CAAC,KAAa,EAAE,MAAc;IAClD,IAAI,OAAO,eAAe,KAAK,WAAW,EAAE,CAAC;QAC3C,OAAO,IAAI,eAAe,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IAC5C,CAAC;IACD,MAAM,EAAE,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;IAC5C,EAAE,CAAC,KAAK,GAAG,KAAK,CAAC;IACjB,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC;IACnB,OAAO,EAAE,CAAC;AACZ,CAAC"}
@@ -1,11 +1,14 @@
1
1
  import { PdfDocument as NativeDocument } from '@build-qube/papyra-native';
2
+ import { type Attachment } from './attachments.js';
2
3
  import { type CacheStats } from './cache.js';
3
- import { PageImage } from './encode.js';
4
+ import { PageImage, type SvgPage } from './encode.js';
5
+ import { type PageLink } from './links.js';
4
6
  import { type OutlineNode } from './outline.js';
5
7
  import { type JobHandle } from './scheduler.js';
6
8
  import { type SearchMatch } from './search.js';
9
+ import { type StructNode } from './structure.js';
7
10
  import { type PageText } from './text.js';
8
- import type { OpenOptions, PageSize, PdfSource, RenderedPage, RenderOptions, SearchOptions, StreamedPage, StreamOptions } from './types.js';
11
+ import type { DocumentMetadata, OpenOptions, PageSize, PdfSource, RenderedPage, RenderOptions, SearchOptions, StreamedPage, StreamOptions, SvgOptions } from './types.js';
9
12
  /** A queued render, plus whether it was served from cache without rendering at all. */
10
13
  export interface RenderHandle extends JobHandle<RenderedPage> {
11
14
  /**
@@ -21,7 +24,19 @@ export interface RenderHandle extends JobHandle<RenderedPage> {
21
24
  * never comes from the cache, which is keyed by page and size with no format dimension.
22
25
  */
23
26
  export type ImageHandle = JobHandle<PageImage>;
24
- /** Open a PDF from bytes, an `ArrayBuffer`, a `Blob`, or a `File`. */
27
+ /**
28
+ * A queued SVG conversion. Uncached for the same reason as {@link ImageHandle}, and
29
+ * unsized: an SVG has no DPI to key on.
30
+ */
31
+ export type SvgHandle = JobHandle<SvgPage>;
32
+ /**
33
+ * Open a PDF from bytes, an `ArrayBuffer`, a `Blob`, or a `File`.
34
+ *
35
+ * Throws {@link PasswordRequiredError} when the document is encrypted and no
36
+ * {@link OpenOptions.password} was given, and {@link IncorrectPasswordError} when one
37
+ * was given and rejected. Both extend {@link PasswordError}, so a viewer that shows
38
+ * one dialog for both can catch the base.
39
+ */
25
40
  export declare function open(source: PdfSource, options?: OpenOptions): Promise<Document>;
26
41
  /**
27
42
  * An open PDF, and the queue and caches that serve it.
@@ -32,8 +47,20 @@ export declare function open(source: PdfSource, options?: OpenOptions): Promise<
32
47
  */
33
48
  export declare class Document {
34
49
  #private;
50
+ /**
51
+ * A stable identifier for this document's bytes.
52
+ *
53
+ * Sixteen hex characters, for keying whatever you remember per document — the page
54
+ * it was left on, a zoom level, a set of highlights. Two `open` calls on the same
55
+ * file always agree.
56
+ *
57
+ * It is a hash of the file, **not** the PDF's own `/ID`: the engine exposes no
58
+ * trailer accessor, so that identifier is out of reach. The practical difference is
59
+ * that saving an incremental update changes this while `/ID` would have survived.
60
+ */
61
+ readonly fingerprint: string;
35
62
  /** @internal — construct via {@link open}. */
36
- constructor(inner: NativeDocument, options?: OpenOptions);
63
+ constructor(inner: NativeDocument, fingerprintOfBytes: string, options?: OpenOptions);
37
64
  /** Rendered pages held for reuse, and how often that has paid off. */
38
65
  get cache(): CacheStats;
39
66
  /** Drop every cached page. */
@@ -54,6 +81,18 @@ export declare class Document {
54
81
  };
55
82
  /** How many pages the document has. Page indices are 0-based throughout. */
56
83
  get pageCount(): number;
84
+ /**
85
+ * The PDF specification version the file declares, e.g. `'1.7'`.
86
+ *
87
+ * Deliberately not part of {@link Document.metadata}: that is what the producer
88
+ * chose to say about the document, while this is a structural property read from
89
+ * the file's header — and from the catalog, which overrides it for 1.4 and later,
90
+ * so an incrementally saved file reports the version it was last written as.
91
+ *
92
+ * `'1.0'` is worth treating with suspicion. Genuine PDF 1.0 files are close to
93
+ * extinct, and it is also what a file with an unreadable header reports.
94
+ */
95
+ get pdfVersion(): string | null;
57
96
  /**
58
97
  * The document outline — bookmarks, the table of contents — as a tree.
59
98
  *
@@ -73,6 +112,117 @@ export declare class Document {
73
112
  * ```
74
113
  */
75
114
  outline(): Promise<OutlineNode[]>;
115
+ /**
116
+ * What the document says about itself: title, author, dates, the tool that wrote it.
117
+ *
118
+ * Synchronous — the engine reads the information dictionary while loading, so this
119
+ * only decodes strings. Every field is independently `null`, and none of it is
120
+ * verified; `title` in particular is often a filename or missing entirely.
121
+ */
122
+ get metadata(): DocumentMetadata;
123
+ /**
124
+ * The label printed on each page, one entry per page.
125
+ *
126
+ * Resolves to an **empty array** when the document defines no page labels, which is
127
+ * the common case — that is the signal to number pages by index yourself. A
128
+ * document that defines labels but says nothing about a particular page gives that
129
+ * page an empty string, which is a different answer.
130
+ *
131
+ * Worth honouring wherever a page number is shown: a document with front matter
132
+ * numbers its first pages i, ii, iii, and a viewer that says "page 4 of 300" when
133
+ * the sheet reads "A101" is describing a document nobody else can see.
134
+ *
135
+ * The walk runs off the event loop and the result is memoised.
136
+ *
137
+ * @example
138
+ * ```ts
139
+ * const labels = await doc.pageLabels();
140
+ * const shown = labels[index] || String(index + 1);
141
+ * ```
142
+ */
143
+ pageLabels(): Promise<readonly string[]>;
144
+ /**
145
+ * The document structure tree, if the document is tagged.
146
+ *
147
+ * Resolves to an **empty array** for an untagged document, which is the common
148
+ * case — most PDFs carry no `/StructTreeRoot` at all. That emptiness is the signal
149
+ * to fall back to {@link Document.pageText} on its own.
150
+ *
151
+ * What it buys, when it is there, is the thing extraction otherwise cannot get:
152
+ * the reading order the author declared. {@link Document.pageText} reports lines in
153
+ * content-stream order, and a two-column page is free to draw its columns
154
+ * interleaved. Pass both to {@link readingOrder} to resolve it.
155
+ *
156
+ * The walk runs off the event loop and the result is memoised — it is one walk for
157
+ * the whole document, not one per page.
158
+ *
159
+ * @example
160
+ * ```ts
161
+ * const [text, tree] = await Promise.all([
162
+ * doc.pageText(0),
163
+ * doc.structTree(),
164
+ * ]);
165
+ * for (const { line, node } of readingOrder(text, tree)) {
166
+ * console.log(node?.role ?? '-', line.text);
167
+ * }
168
+ * ```
169
+ */
170
+ structTree(): Promise<StructNode[]>;
171
+ /**
172
+ * The files embedded in the document, in the order it files them.
173
+ *
174
+ * Resolves to an **empty array** when there are none, which is the common case.
175
+ * Metadata only — {@link Document.attachmentData} fetches the bytes, so listing a
176
+ * document's attachments never decompresses one.
177
+ *
178
+ * Worth honouring even in a viewer that has no use for the files themselves: a
179
+ * ZUGFeRD or Factur-X invoice keeps its machine-readable half here, and a reader
180
+ * that never mentions it leaves the user retyping data the document is carrying.
181
+ * See {@link isInvoiceAttachment}.
182
+ *
183
+ * The walk runs off the event loop and the result is memoised.
184
+ *
185
+ * @example
186
+ * ```ts
187
+ * for (const file of await doc.attachments()) {
188
+ * const bytes = await doc.attachmentData(file.index);
189
+ * await write(file.name, bytes);
190
+ * }
191
+ * ```
192
+ */
193
+ attachments(): Promise<readonly Attachment[]>;
194
+ /**
195
+ * Decompress one embedded file, by its {@link Attachment.index}.
196
+ *
197
+ * Not cached: the bytes are the caller's to keep or drop, and holding every
198
+ * attachment a document was ever asked for is the cost {@link Document.attachments}
199
+ * is shaped to avoid. Rejects if the index names no attachment, or if the stream
200
+ * cannot be decoded.
201
+ */
202
+ attachmentData(index: number): Promise<Uint8Array>;
203
+ /**
204
+ * The links on one page — where they are, and where they go.
205
+ *
206
+ * Rectangles are in the same 72-DPI top-left space as {@link Document.pageText} and
207
+ * {@link Document.pageSize}, so placing them over a render is one multiply; see
208
+ * {@link scaleRect}. Only links that resolve to something actionable are reported.
209
+ *
210
+ * Unlike text extraction this never interprets a content stream — it is an
211
+ * object-graph read, roughly a thousandth the cost of rendering the page — so it
212
+ * does **not** go through the priority queue. Making a link layer wait behind
213
+ * renders would add latency a viewer can feel, for work that costs nothing.
214
+ * Results are cached, and two calls for the same page share one read.
215
+ *
216
+ * @example
217
+ * ```ts
218
+ * const scale = rendered.width / doc.pageSize(index).width;
219
+ * for (const link of await doc.links(index)) {
220
+ * const { x, y, width, height } = scaleRect(link.rect, scale);
221
+ * // ...position an anchor over the canvas
222
+ * }
223
+ * ```
224
+ */
225
+ links(index: number): Promise<readonly PageLink[]>;
76
226
  /** Page dimensions in PDF points (1/72 inch). */
77
227
  pageSize(index: number): PageSize;
78
228
  /** Render a single page. Never blocks the event loop. */
@@ -107,6 +257,31 @@ export declare class Document {
107
257
  * render time, which end-to-end timing around the promise cannot.
108
258
  */
109
259
  imageHandle(index: number, options?: RenderOptions): ImageHandle;
260
+ /**
261
+ * Convert a page to SVG — vector output, not pixels.
262
+ *
263
+ * Paths stay paths and text stays glyph outlines, so the result scales to any size
264
+ * and can be edited downstream. That is the trade: an SVG of a dense drawing is
265
+ * larger than a WebP of the same page at screen size and slower for a browser to
266
+ * paint, but it is the only output that survives being scaled up.
267
+ *
268
+ * Conversion is content-stream interpretation without rasterisation — roughly the
269
+ * non-preemptible portion of a render — so it shares the scheduler with everything
270
+ * else and honours {@link SvgOptions.priority}. **Not cached**, for the same reason
271
+ * {@link renderImage} is not.
272
+ *
273
+ * @example
274
+ * ```ts
275
+ * const page = await doc.renderSvg(0, { background: 'transparent' });
276
+ * await writeFile('page-0.svg', page.markup);
277
+ * ```
278
+ */
279
+ renderSvg(index: number, options?: SvgOptions): Promise<SvgPage>;
280
+ /**
281
+ * As {@link renderSvg}, but returns the handle so the job can be reprioritised,
282
+ * cancelled, or timed — the same relationship `imageHandle` has to `renderImage`.
283
+ */
284
+ svgHandle(index: number, options?: SvgOptions): SvgHandle;
110
285
  /**
111
286
  * Render a page, returning a handle you can reprioritise or drop.
112
287
  *
@@ -1 +1 @@
1
- {"version":3,"file":"document.d.ts","sourceRoot":"","sources":["../src/document.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"document.d.ts","sourceRoot":"","sources":["../src/document.ts"],"names":[],"mappings":"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"}