@build-qube/papyra 0.2.0 → 0.4.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 +18 -0
- 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/cells.d.ts +148 -0
- package/dist/cells.d.ts.map +1 -0
- package/dist/cells.js +144 -0
- package/dist/cells.js.map +1 -0
- package/dist/document.d.ts +61 -0
- package/dist/document.d.ts.map +1 -1
- package/dist/document.js +105 -7
- package/dist/document.js.map +1 -1
- package/dist/errors.d.ts +12 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +17 -1
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +18 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -2
- package/dist/index.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/styles.d.ts +96 -0
- package/dist/styles.d.ts.map +1 -0
- package/dist/styles.js +69 -0
- package/dist/styles.js.map +1 -0
- package/dist/text.d.ts +18 -0
- package/dist/text.d.ts.map +1 -1
- package/dist/text.js.map +1 -1
- package/dist/tiff.d.ts +95 -0
- package/dist/tiff.d.ts.map +1 -0
- package/dist/tiff.js +78 -0
- package/dist/tiff.js.map +1 -0
- package/dist/types.d.ts +25 -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/dist/workbook.d.ts +152 -0
- package/dist/workbook.d.ts.map +1 -0
- package/dist/workbook.js +158 -0
- package/dist/workbook.js.map +1 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -104,6 +104,24 @@ Encrypted files throw `PasswordRequiredError` or `IncorrectPasswordError`, both
|
|
|
104
104
|
extending `PasswordError` with a `retry` flag, so one dialog handles the cold ask and
|
|
105
105
|
the wrong answer.
|
|
106
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.
|
|
124
|
+
|
|
107
125
|
## Two things that will bite you
|
|
108
126
|
|
|
109
127
|
**Size with `fitWidth`, not `dpi`.** Page areas vary by two orders of magnitude. At a
|
|
@@ -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/cells.d.ts
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import type { CellWindow as NativeCellWindow } from '@build-qube/papyra-native';
|
|
2
|
+
/** What a cell holds. A formula cell reports the result Excel last computed. */
|
|
3
|
+
export type CellKind = 'empty' | 'number' | 'text' | 'bool' | 'date' | 'duration' | 'error';
|
|
4
|
+
/** A cell with nothing in it, or outside the sheet's used range. */
|
|
5
|
+
export interface EmptyCell {
|
|
6
|
+
/** Always `'empty'`. */
|
|
7
|
+
kind: 'empty';
|
|
8
|
+
/** Always `''`. */
|
|
9
|
+
text: '';
|
|
10
|
+
}
|
|
11
|
+
/** A number, or in CSV a field that is unambiguously one. */
|
|
12
|
+
export interface NumberCell {
|
|
13
|
+
/** Always `'number'`. */
|
|
14
|
+
kind: 'number';
|
|
15
|
+
/** The value. */
|
|
16
|
+
value: number;
|
|
17
|
+
/**
|
|
18
|
+
* Excel's General rendering for a workbook. For CSV, the field exactly as
|
|
19
|
+
* written: `2.50` stays `2.50`.
|
|
20
|
+
*/
|
|
21
|
+
text: string;
|
|
22
|
+
}
|
|
23
|
+
/** A string. Every CSV field that is not a plain number is one. */
|
|
24
|
+
export interface TextCell {
|
|
25
|
+
/** Always `'text'`. */
|
|
26
|
+
kind: 'text';
|
|
27
|
+
/** The string. */
|
|
28
|
+
text: string;
|
|
29
|
+
}
|
|
30
|
+
/** A boolean. */
|
|
31
|
+
export interface BoolCell {
|
|
32
|
+
/** Always `'bool'`. */
|
|
33
|
+
kind: 'bool';
|
|
34
|
+
/** The value. */
|
|
35
|
+
value: boolean;
|
|
36
|
+
/** Excel's spelling, which is also what a CSV export of the cell contains. */
|
|
37
|
+
text: 'TRUE' | 'FALSE';
|
|
38
|
+
}
|
|
39
|
+
/** A date, a time, or both. */
|
|
40
|
+
export interface DateCell {
|
|
41
|
+
/** Always `'date'`. */
|
|
42
|
+
kind: 'date';
|
|
43
|
+
/**
|
|
44
|
+
* The Excel date serial: days since 1899-12-30, time as the fraction. NaN for
|
|
45
|
+
* OpenDocument, which stores only the ISO form.
|
|
46
|
+
*/
|
|
47
|
+
serial: number;
|
|
48
|
+
/** `2024-03-15`, `2024-03-15T13:30:00`, or `13:30:00` for a time alone. */
|
|
49
|
+
text: string;
|
|
50
|
+
}
|
|
51
|
+
/** A length of time. */
|
|
52
|
+
export interface DurationCell {
|
|
53
|
+
/** Always `'duration'`. */
|
|
54
|
+
kind: 'duration';
|
|
55
|
+
/** Length in days. NaN for OpenDocument, which stores only the text form. */
|
|
56
|
+
days: number;
|
|
57
|
+
/** `[h]:mm:ss` — hours do not wrap at 24. */
|
|
58
|
+
text: string;
|
|
59
|
+
}
|
|
60
|
+
/** An error a formula evaluated to. */
|
|
61
|
+
export interface ErrorCell {
|
|
62
|
+
/** Always `'error'`. */
|
|
63
|
+
kind: 'error';
|
|
64
|
+
/** Excel's code for it, e.g. `#DIV/0!`. */
|
|
65
|
+
text: string;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* One cell's value, discriminated on `kind`.
|
|
69
|
+
*
|
|
70
|
+
* `text` is always what to display. Number formats are not applied yet, so a
|
|
71
|
+
* currency cell reads `1234.5` rather than `$1,234.50` and a date reads as ISO 8601
|
|
72
|
+
* — the raw value is beside it for anything that needs to compute.
|
|
73
|
+
*/
|
|
74
|
+
export type Cell = EmptyCell | NumberCell | TextCell | BoolCell | DateCell | DurationCell | ErrorCell;
|
|
75
|
+
/**
|
|
76
|
+
* Cells merged into one, as a sheet reports them. Inclusive at both ends, like the
|
|
77
|
+
* `A4:B4` Excel would write — hence `lastRow` rather than an exclusive `rowEnd`.
|
|
78
|
+
*/
|
|
79
|
+
export interface MergedRange {
|
|
80
|
+
/** 0-based row of the top-left cell, which holds the value. */
|
|
81
|
+
row: number;
|
|
82
|
+
/** 0-based column of the top-left cell. */
|
|
83
|
+
col: number;
|
|
84
|
+
/** Last row covered, inclusive. */
|
|
85
|
+
lastRow: number;
|
|
86
|
+
/** Last column covered, inclusive. */
|
|
87
|
+
lastCol: number;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* A rectangle of a sheet, read in one call and decoded on access.
|
|
91
|
+
*
|
|
92
|
+
* Cells cross from Rust as four flat buffers rather than an object each, because
|
|
93
|
+
* building thousands of objects costs more than parsing them did. Nothing is
|
|
94
|
+
* decoded until asked for, so a grid that only draws text never builds a {@link Cell}.
|
|
95
|
+
*
|
|
96
|
+
* Coordinates are the sheet's, not the window's: `text(10, 2)` is row 10 of the
|
|
97
|
+
* sheet whichever row the window starts on. Anything outside the window is empty.
|
|
98
|
+
*/
|
|
99
|
+
export declare class CellWindow {
|
|
100
|
+
#private;
|
|
101
|
+
/** First row held. */
|
|
102
|
+
readonly rowStart: number;
|
|
103
|
+
/** First column held. */
|
|
104
|
+
readonly colStart: number;
|
|
105
|
+
/** Rows held, which may be fewer than asked for at the sheet's edge. */
|
|
106
|
+
readonly rows: number;
|
|
107
|
+
/** Columns held. */
|
|
108
|
+
readonly cols: number;
|
|
109
|
+
/** @internal Use `Sheet.window`. */
|
|
110
|
+
constructor(native: NativeCellWindow);
|
|
111
|
+
/** One past the last row held. */
|
|
112
|
+
get rowEnd(): number;
|
|
113
|
+
/** One past the last column held. */
|
|
114
|
+
get colEnd(): number;
|
|
115
|
+
/** What the cell at `(row, col)` holds. Cheaper than {@link cell}. */
|
|
116
|
+
kind(row: number, col: number): CellKind;
|
|
117
|
+
/** The display text at `(row, col)` — all a plain grid needs. */
|
|
118
|
+
text(row: number, col: number): string;
|
|
119
|
+
/**
|
|
120
|
+
* The numeric value at `(row, col)`: a number, a bool as 0 or 1, a date's serial,
|
|
121
|
+
* a duration in days. NaN for anything else.
|
|
122
|
+
*/
|
|
123
|
+
number(row: number, col: number): number;
|
|
124
|
+
/**
|
|
125
|
+
* The index of the cell's style in `Sheet.styles`. 0, the default, for a cell
|
|
126
|
+
* with none — and for every cell of a format that carries no styles.
|
|
127
|
+
*/
|
|
128
|
+
style(row: number, col: number): number;
|
|
129
|
+
/**
|
|
130
|
+
* The colour the cell's number format chose, as `0xRRGGBB` — the `[Red]` in
|
|
131
|
+
* `#,##0;[Red](#,##0)`. It overrides the style's text colour, as in Excel.
|
|
132
|
+
*/
|
|
133
|
+
color(row: number, col: number): number | undefined;
|
|
134
|
+
/** The cell at `(row, col)`, fully decoded. */
|
|
135
|
+
cell(row: number, col: number): Cell;
|
|
136
|
+
}
|
|
137
|
+
/** Unpack the bindings' flat merge quads. @internal */
|
|
138
|
+
export declare function toMergedRanges(quads: Uint32Array): MergedRange[];
|
|
139
|
+
/**
|
|
140
|
+
* The letters Excel heads a column with: 0 is `A`, 25 is `Z`, 26 is `AA`.
|
|
141
|
+
*
|
|
142
|
+
* @example
|
|
143
|
+
* ```ts
|
|
144
|
+
* columnName(27); // 'AB'
|
|
145
|
+
* ```
|
|
146
|
+
*/
|
|
147
|
+
export declare function columnName(index: number): string;
|
|
148
|
+
//# sourceMappingURL=cells.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cells.d.ts","sourceRoot":"","sources":["../src/cells.ts"],"names":[],"mappings":"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"}
|
package/dist/cells.js
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/** Indexed by the tag byte the bindings write. Keep in step with `CellKind` in Rust. */
|
|
2
|
+
const KINDS = [
|
|
3
|
+
'empty',
|
|
4
|
+
'number',
|
|
5
|
+
'text',
|
|
6
|
+
'bool',
|
|
7
|
+
'date',
|
|
8
|
+
'duration',
|
|
9
|
+
'error',
|
|
10
|
+
];
|
|
11
|
+
/**
|
|
12
|
+
* A rectangle of a sheet, read in one call and decoded on access.
|
|
13
|
+
*
|
|
14
|
+
* Cells cross from Rust as four flat buffers rather than an object each, because
|
|
15
|
+
* building thousands of objects costs more than parsing them did. Nothing is
|
|
16
|
+
* decoded until asked for, so a grid that only draws text never builds a {@link Cell}.
|
|
17
|
+
*
|
|
18
|
+
* Coordinates are the sheet's, not the window's: `text(10, 2)` is row 10 of the
|
|
19
|
+
* sheet whichever row the window starts on. Anything outside the window is empty.
|
|
20
|
+
*/
|
|
21
|
+
export class CellWindow {
|
|
22
|
+
/** First row held. */
|
|
23
|
+
rowStart;
|
|
24
|
+
/** First column held. */
|
|
25
|
+
colStart;
|
|
26
|
+
/** Rows held, which may be fewer than asked for at the sheet's edge. */
|
|
27
|
+
rows;
|
|
28
|
+
/** Columns held. */
|
|
29
|
+
cols;
|
|
30
|
+
#native;
|
|
31
|
+
/** @internal Use `Sheet.window`. */
|
|
32
|
+
constructor(native) {
|
|
33
|
+
this.#native = native;
|
|
34
|
+
this.rowStart = native.rowStart;
|
|
35
|
+
this.colStart = native.colStart;
|
|
36
|
+
this.rows = native.rows;
|
|
37
|
+
this.cols = native.cols;
|
|
38
|
+
}
|
|
39
|
+
/** One past the last row held. */
|
|
40
|
+
get rowEnd() {
|
|
41
|
+
return this.rowStart + this.rows;
|
|
42
|
+
}
|
|
43
|
+
/** One past the last column held. */
|
|
44
|
+
get colEnd() {
|
|
45
|
+
return this.colStart + this.cols;
|
|
46
|
+
}
|
|
47
|
+
#index(row, col) {
|
|
48
|
+
const r = row - this.rowStart;
|
|
49
|
+
const c = col - this.colStart;
|
|
50
|
+
if (r < 0 || c < 0 || r >= this.rows || c >= this.cols)
|
|
51
|
+
return -1;
|
|
52
|
+
return r * this.cols + c;
|
|
53
|
+
}
|
|
54
|
+
/** What the cell at `(row, col)` holds. Cheaper than {@link cell}. */
|
|
55
|
+
kind(row, col) {
|
|
56
|
+
const i = this.#index(row, col);
|
|
57
|
+
return i < 0 ? 'empty' : (KINDS[this.#native.kinds[i] ?? 0] ?? 'empty');
|
|
58
|
+
}
|
|
59
|
+
/** The display text at `(row, col)` — all a plain grid needs. */
|
|
60
|
+
text(row, col) {
|
|
61
|
+
const i = this.#index(row, col);
|
|
62
|
+
if (i < 0)
|
|
63
|
+
return '';
|
|
64
|
+
const { offsets, text } = this.#native;
|
|
65
|
+
return text.slice(offsets[i], offsets[i + 1]);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* The numeric value at `(row, col)`: a number, a bool as 0 or 1, a date's serial,
|
|
69
|
+
* a duration in days. NaN for anything else.
|
|
70
|
+
*/
|
|
71
|
+
number(row, col) {
|
|
72
|
+
const i = this.#index(row, col);
|
|
73
|
+
return i < 0 ? Number.NaN : (this.#native.numbers[i] ?? Number.NaN);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* The index of the cell's style in `Sheet.styles`. 0, the default, for a cell
|
|
77
|
+
* with none — and for every cell of a format that carries no styles.
|
|
78
|
+
*/
|
|
79
|
+
style(row, col) {
|
|
80
|
+
const i = this.#index(row, col);
|
|
81
|
+
return i < 0 ? 0 : (this.#native.styles[i] ?? 0);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* The colour the cell's number format chose, as `0xRRGGBB` — the `[Red]` in
|
|
85
|
+
* `#,##0;[Red](#,##0)`. It overrides the style's text colour, as in Excel.
|
|
86
|
+
*/
|
|
87
|
+
color(row, col) {
|
|
88
|
+
const i = this.#index(row, col);
|
|
89
|
+
const c = i < 0 ? 0 : (this.#native.colors[i] ?? 0);
|
|
90
|
+
return c === 0 ? undefined : c & 0xffffff;
|
|
91
|
+
}
|
|
92
|
+
/** The cell at `(row, col)`, fully decoded. */
|
|
93
|
+
cell(row, col) {
|
|
94
|
+
const kind = this.kind(row, col);
|
|
95
|
+
const text = this.text(row, col);
|
|
96
|
+
const n = this.number(row, col);
|
|
97
|
+
switch (kind) {
|
|
98
|
+
case 'empty':
|
|
99
|
+
return { kind, text: '' };
|
|
100
|
+
case 'number':
|
|
101
|
+
return { kind, value: n, text };
|
|
102
|
+
case 'bool':
|
|
103
|
+
return n === 1
|
|
104
|
+
? { kind, value: true, text: 'TRUE' }
|
|
105
|
+
: { kind, value: false, text: 'FALSE' };
|
|
106
|
+
case 'date':
|
|
107
|
+
return { kind, serial: n, text };
|
|
108
|
+
case 'duration':
|
|
109
|
+
return { kind, days: n, text };
|
|
110
|
+
case 'text':
|
|
111
|
+
case 'error':
|
|
112
|
+
return { kind, text };
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
/** Unpack the bindings' flat merge quads. @internal */
|
|
117
|
+
export function toMergedRanges(quads) {
|
|
118
|
+
const out = [];
|
|
119
|
+
for (let i = 0; i + 3 < quads.length; i += 4) {
|
|
120
|
+
out.push({
|
|
121
|
+
row: quads[i] ?? 0,
|
|
122
|
+
col: quads[i + 1] ?? 0,
|
|
123
|
+
lastRow: quads[i + 2] ?? 0,
|
|
124
|
+
lastCol: quads[i + 3] ?? 0,
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
return out;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* The letters Excel heads a column with: 0 is `A`, 25 is `Z`, 26 is `AA`.
|
|
131
|
+
*
|
|
132
|
+
* @example
|
|
133
|
+
* ```ts
|
|
134
|
+
* columnName(27); // 'AB'
|
|
135
|
+
* ```
|
|
136
|
+
*/
|
|
137
|
+
export function columnName(index) {
|
|
138
|
+
let name = '';
|
|
139
|
+
for (let n = Math.floor(index) + 1; n > 0; n = Math.floor((n - 1) / 26)) {
|
|
140
|
+
name = String.fromCharCode(65 + ((n - 1) % 26)) + name;
|
|
141
|
+
}
|
|
142
|
+
return name;
|
|
143
|
+
}
|
|
144
|
+
//# sourceMappingURL=cells.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cells.js","sourceRoot":"","sources":["../src/cells.ts"],"names":[],"mappings":"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"}
|