@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.
- package/README.md +46 -1
- package/dist/attachments.d.ts +76 -0
- package/dist/attachments.d.ts.map +1 -0
- package/dist/attachments.js +65 -0
- package/dist/attachments.js.map +1 -0
- package/dist/canvas.d.ts +27 -2
- package/dist/canvas.d.ts.map +1 -1
- package/dist/canvas.js +58 -5
- package/dist/canvas.js.map +1 -1
- package/dist/document.d.ts +179 -4
- package/dist/document.d.ts.map +1 -1
- package/dist/document.js +311 -12
- package/dist/document.js.map +1 -1
- package/dist/encode.d.ts +2 -2
- package/dist/encode.d.ts.map +1 -1
- package/dist/encode.js +1 -1
- package/dist/encode.js.map +1 -1
- package/dist/encoded.d.ts +34 -5
- package/dist/encoded.d.ts.map +1 -1
- package/dist/encoded.js +28 -0
- package/dist/encoded.js.map +1 -1
- package/dist/errors.d.ts +45 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +69 -0
- package/dist/errors.js.map +1 -0
- package/dist/fingerprint.d.ts +18 -0
- package/dist/fingerprint.d.ts.map +1 -0
- package/dist/fingerprint.js +48 -0
- package/dist/fingerprint.js.map +1 -0
- package/dist/index.d.ts +14 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -2
- package/dist/index.js.map +1 -1
- package/dist/links.d.ts +53 -0
- package/dist/links.d.ts.map +1 -0
- package/dist/links.js +26 -0
- package/dist/links.js.map +1 -0
- package/dist/outline.d.ts +9 -1
- package/dist/outline.d.ts.map +1 -1
- package/dist/outline.js +9 -3
- package/dist/outline.js.map +1 -1
- package/dist/structure.d.ts +119 -0
- package/dist/structure.d.ts.map +1 -0
- package/dist/structure.js +115 -0
- package/dist/structure.js.map +1 -0
- package/dist/text.d.ts +20 -0
- package/dist/text.d.ts.map +1 -1
- package/dist/text.js +9 -0
- package/dist/text.js.map +1 -1
- package/dist/types.d.ts +75 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/viewport.d.ts +129 -0
- package/dist/viewport.d.ts.map +1 -0
- package/dist/viewport.js +163 -0
- package/dist/viewport.js.map +1 -0
- 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
|
-
/**
|
|
11
|
-
export
|
|
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
|
package/dist/canvas.d.ts.map
CHANGED
|
@@ -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;
|
|
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
|
-
/**
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
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
|
-
|
|
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
|
package/dist/canvas.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"canvas.js","sourceRoot":"","sources":["../src/canvas.ts"],"names":[],"mappings":"
|
|
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"}
|
package/dist/document.d.ts
CHANGED
|
@@ -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
|
-
/**
|
|
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
|
*
|
package/dist/document.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"document.d.ts","sourceRoot":"","sources":["../src/document.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,IAAI,cAAc,
|
|
1
|
+
{"version":3,"file":"document.d.ts","sourceRoot":"","sources":["../src/document.ts"],"names":[],"mappings":"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"}
|