@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
@@ -0,0 +1,45 @@
1
+ /**
2
+ * A document that could not be opened because of its password.
3
+ *
4
+ * The base of both password failures, because a viewer handles them in one place: a
5
+ * dialog that either asks for the first time or says the last answer was wrong.
6
+ *
7
+ * @example
8
+ * ```ts
9
+ * try {
10
+ * doc = await open(file, { password });
11
+ * } catch (e) {
12
+ * if (e instanceof PasswordError) showPasswordDialog({ retry: e.retry });
13
+ * else throw e;
14
+ * }
15
+ * ```
16
+ */
17
+ export declare class PasswordError extends Error {
18
+ /**
19
+ * A password was already tried and rejected.
20
+ *
21
+ * `false` the first time, so a dialog can open without an error on it.
22
+ */
23
+ readonly retry: boolean;
24
+ }
25
+ /** The document is encrypted and {@link OpenOptions.password} was not supplied. */
26
+ export declare class PasswordRequiredError extends PasswordError {
27
+ /** Always `'PasswordRequiredError'`. */
28
+ readonly name = "PasswordRequiredError";
29
+ readonly retry = false;
30
+ constructor(message?: string);
31
+ }
32
+ /** A password was supplied and it did not open the document. */
33
+ export declare class IncorrectPasswordError extends PasswordError {
34
+ /** Always `'IncorrectPasswordError'`. */
35
+ readonly name = "IncorrectPasswordError";
36
+ readonly retry = true;
37
+ constructor(message?: string);
38
+ }
39
+ /**
40
+ * Rethrow a load failure as itself, or as the typed error it was tagged as.
41
+ *
42
+ * @internal
43
+ */
44
+ export declare function rethrowLoadError(error: unknown): never;
45
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAeA;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,aAAc,SAAQ,KAAK;IACtC;;;;OAIG;IACH,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAS;CACjC;AAED,mFAAmF;AACnF,qBAAa,qBAAsB,SAAQ,aAAa;IACtD,wCAAwC;IACxC,SAAkB,IAAI,2BAA2B;IACjD,SAAkB,KAAK,SAAS;IAChC,YAAY,OAAO,SAAmC,EAErD;CACF;AAED,gEAAgE;AAChE,qBAAa,sBAAuB,SAAQ,aAAa;IACvD,yCAAyC;IACzC,SAAkB,IAAI,4BAA4B;IAClD,SAAkB,KAAK,QAAQ;IAC/B,YAAY,OAAO,SAAuC,EAEzD;CACF;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,CAQtD"}
package/dist/errors.js ADDED
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Tags the bindings put in front of a load failure's message.
3
+ *
4
+ * napi-rs gives every error it throws the same `code`, so the message is the only
5
+ * channel a typed failure can travel through. These are stripped before the error
6
+ * reaches a caller — keep them in step with `TAG_PASSWORD_REQUIRED` and
7
+ * `TAG_INCORRECT_PASSWORD` in `packages/bindings/src/lib.rs`.
8
+ */
9
+ const TAGS = {
10
+ 'papyra/password-required': (message) => new PasswordRequiredError(message),
11
+ 'papyra/incorrect-password': (message) => new IncorrectPasswordError(message),
12
+ };
13
+ /**
14
+ * A document that could not be opened because of its password.
15
+ *
16
+ * The base of both password failures, because a viewer handles them in one place: a
17
+ * dialog that either asks for the first time or says the last answer was wrong.
18
+ *
19
+ * @example
20
+ * ```ts
21
+ * try {
22
+ * doc = await open(file, { password });
23
+ * } catch (e) {
24
+ * if (e instanceof PasswordError) showPasswordDialog({ retry: e.retry });
25
+ * else throw e;
26
+ * }
27
+ * ```
28
+ */
29
+ export class PasswordError extends Error {
30
+ /**
31
+ * A password was already tried and rejected.
32
+ *
33
+ * `false` the first time, so a dialog can open without an error on it.
34
+ */
35
+ retry = false;
36
+ }
37
+ /** The document is encrypted and {@link OpenOptions.password} was not supplied. */
38
+ export class PasswordRequiredError extends PasswordError {
39
+ /** Always `'PasswordRequiredError'`. */
40
+ name = 'PasswordRequiredError';
41
+ retry = false;
42
+ constructor(message = 'this PDF is password-protected') {
43
+ super(message);
44
+ }
45
+ }
46
+ /** A password was supplied and it did not open the document. */
47
+ export class IncorrectPasswordError extends PasswordError {
48
+ /** Always `'IncorrectPasswordError'`. */
49
+ name = 'IncorrectPasswordError';
50
+ retry = true;
51
+ constructor(message = 'the supplied password is incorrect') {
52
+ super(message);
53
+ }
54
+ }
55
+ /**
56
+ * Rethrow a load failure as itself, or as the typed error it was tagged as.
57
+ *
58
+ * @internal
59
+ */
60
+ export function rethrowLoadError(error) {
61
+ const message = error instanceof Error ? error.message : String(error);
62
+ for (const [tag, build] of Object.entries(TAGS)) {
63
+ if (message.startsWith(tag)) {
64
+ throw build(message.slice(tag.length).trim());
65
+ }
66
+ }
67
+ throw error;
68
+ }
69
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,IAAI,GAAG;IACX,0BAA0B,EAAE,CAAC,OAAe,EAAE,EAAE,CAC9C,IAAI,qBAAqB,CAAC,OAAO,CAAC;IACpC,2BAA2B,EAAE,CAAC,OAAe,EAAE,EAAE,CAC/C,IAAI,sBAAsB,CAAC,OAAO,CAAC;CAC7B,CAAC;AAEX;;;;;;;;;;;;;;;GAeG;AACH,MAAM,OAAO,aAAc,SAAQ,KAAK;IACtC;;;;OAIG;IACM,KAAK,GAAY,KAAK,CAAC;CACjC;AAED,mFAAmF;AACnF,MAAM,OAAO,qBAAsB,SAAQ,aAAa;IACtD,wCAAwC;IACtB,IAAI,GAAG,uBAAuB,CAAC;IAC/B,KAAK,GAAG,KAAK,CAAC;IAChC,YAAY,OAAO,GAAG,gCAAgC;QACpD,KAAK,CAAC,OAAO,CAAC,CAAC;IACjB,CAAC;CACF;AAED,gEAAgE;AAChE,MAAM,OAAO,sBAAuB,SAAQ,aAAa;IACvD,yCAAyC;IACvB,IAAI,GAAG,wBAAwB,CAAC;IAChC,KAAK,GAAG,IAAI,CAAC;IAC/B,YAAY,OAAO,GAAG,oCAAoC;QACxD,KAAK,CAAC,OAAO,CAAC,CAAC;IACjB,CAAC;CACF;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAc;IAC7C,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACvE,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QAChD,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YAC5B,MAAM,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;QAChD,CAAC;IACH,CAAC;IACD,MAAM,KAAK,CAAC;AACd,CAAC"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * A stable identifier for a document's bytes.
3
+ *
4
+ * Sixteen hex characters, derived from the head, the tail and the length of the file.
5
+ * Meant as a key for whatever a viewer remembers per document — the page it was left
6
+ * on, the zoom, a set of highlights.
7
+ *
8
+ * **This is a content hash, not the PDF's `/ID`.** hayro exposes no trailer accessor,
9
+ * so the identifier the spec defines is out of reach; the practical difference is
10
+ * that a document saved with an incremental update keeps its `/ID` and gets a new
11
+ * fingerprint here. For "is this the same file I had open", which is what the value
12
+ * is for, hashing the bytes is the stronger answer anyway — it also distinguishes two
13
+ * documents that were copied from one another and kept the same `/ID`.
14
+ *
15
+ * @internal
16
+ */
17
+ export declare function fingerprint(bytes: Uint8Array): string;
18
+ //# sourceMappingURL=fingerprint.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fingerprint.d.ts","sourceRoot":"","sources":["../src/fingerprint.ts"],"names":[],"mappings":"AAqBA;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAarD"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * How many bytes to read from each end of the file.
3
+ *
4
+ * The tail is the load-bearing half: it holds the cross-reference table and the
5
+ * trailer, and the trailer is where `/ID` lives. So although this never parses the
6
+ * document, a file that carries an `/ID` still contributes it to the hash.
7
+ */
8
+ const SAMPLE = 4096;
9
+ /** FNV-1a, 32-bit. Two runs at different offsets give the 64 bits below. */
10
+ function fnv1a(bytes, seed) {
11
+ let hash = seed;
12
+ for (const byte of bytes) {
13
+ hash ^= byte;
14
+ // The FNV prime, 16777619, as shifts — `Math.imul` keeps this in 32 bits where
15
+ // `*` would silently go through a double and lose the low bits.
16
+ hash = Math.imul(hash, 0x01000193);
17
+ }
18
+ return hash >>> 0;
19
+ }
20
+ /**
21
+ * A stable identifier for a document's bytes.
22
+ *
23
+ * Sixteen hex characters, derived from the head, the tail and the length of the file.
24
+ * Meant as a key for whatever a viewer remembers per document — the page it was left
25
+ * on, the zoom, a set of highlights.
26
+ *
27
+ * **This is a content hash, not the PDF's `/ID`.** hayro exposes no trailer accessor,
28
+ * so the identifier the spec defines is out of reach; the practical difference is
29
+ * that a document saved with an incremental update keeps its `/ID` and gets a new
30
+ * fingerprint here. For "is this the same file I had open", which is what the value
31
+ * is for, hashing the bytes is the stronger answer anyway — it also distinguishes two
32
+ * documents that were copied from one another and kept the same `/ID`.
33
+ *
34
+ * @internal
35
+ */
36
+ export function fingerprint(bytes) {
37
+ const head = bytes.subarray(0, SAMPLE);
38
+ // `subarray` clamps, so a file shorter than one sample simply hashes twice rather
39
+ // than needing a branch.
40
+ const tail = bytes.subarray(Math.max(0, bytes.length - SAMPLE));
41
+ const low = fnv1a(tail, fnv1a(head, 0x811c9dc5));
42
+ // A second pass from a different seed, so the two halves of the output are not the
43
+ // same 32 bits twice. Length goes in as well: it separates a file from its own
44
+ // prefix, which the samples alone would not.
45
+ const high = fnv1a(tail, fnv1a(head, bytes.length >>> 0));
46
+ return high.toString(16).padStart(8, '0') + low.toString(16).padStart(8, '0');
47
+ }
48
+ //# sourceMappingURL=fingerprint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fingerprint.js","sourceRoot":"","sources":["../src/fingerprint.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,MAAM,GAAG,IAAI,CAAC;AAEpB,4EAA4E;AAC5E,SAAS,KAAK,CAAC,KAAiB,EAAE,IAAY;IAC5C,IAAI,IAAI,GAAG,IAAI,CAAC;IAChB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,IAAI,CAAC;QACb,+EAA+E;QAC/E,gEAAgE;QAChE,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;IACrC,CAAC;IACD,OAAO,IAAI,KAAK,CAAC,CAAC;AACpB,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,WAAW,CAAC,KAAiB;IAC3C,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IACvC,kFAAkF;IAClF,yBAAyB;IACzB,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC;IAEhE,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC;IACjD,mFAAmF;IACnF,+EAA+E;IAC/E,6CAA6C;IAC7C,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC;IAE1D,OAAO,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AAChF,CAAC"}
package/dist/index.d.ts CHANGED
@@ -13,12 +13,17 @@
13
13
  * onScroll(() => job.setPriority(0));
14
14
  * ```
15
15
  */
16
+ export type { Attachment } from './attachments.js';
17
+ export { attachmentMediaType, isInvoiceAttachment, } from './attachments.js';
16
18
  export type { CacheStats } from './cache.js';
19
+ export type { PaintOptions } from './canvas.js';
17
20
  export { paintToCanvas, toImageData } from './canvas.js';
18
- export type { ImageHandle, RenderHandle } from './document.js';
21
+ export type { ImageHandle, RenderHandle, SvgHandle } from './document.js';
19
22
  export { Document, open } from './document.js';
20
- export type { EncodedFormat, EncodedImage, EncodeOptions, } from './encode.js';
21
- export { encode, encodedImage, mimeType, PageImage } from './encode.js';
23
+ export type { EncodedFormat, EncodedImage, EncodeOptions, RasterFormat, SvgPage, } from './encode.js';
24
+ export { encode, encodedImage, mimeType, PageImage, svgPage, } from './encode.js';
25
+ export { IncorrectPasswordError, PasswordError, PasswordRequiredError, } from './errors.js';
26
+ export type { LinkTarget, PageLink } from './links.js';
22
27
  export type { DestinationKind, OutlineDestination, OutlineNode, } from './outline.js';
23
28
  export { buildOutlineTree, walkOutline } from './outline.js';
24
29
  export type { Runtime } from './runtime.js';
@@ -27,7 +32,11 @@ export type { JobHandle, JobTiming } from './scheduler.js';
27
32
  export { AbortError, DEFAULT_PRIORITY } from './scheduler.js';
28
33
  export type { MatchOptions, SearchMatch } from './search.js';
29
34
  export { findRanges, searchPageText } from './search.js';
35
+ export type { MarkedContent, OrderedLine, StructNode, } from './structure.js';
36
+ export { buildStructTree, readingOrder, structuredPageString, walkStructTree, } from './structure.js';
30
37
  export type { PageText, Quad, Rect, TextLine } from './text.js';
31
- export { lineQuad, pageString, quadBounds, scaleQuad, } from './text.js';
32
- export type { OpenOptions, PageSize, PdfSource, RenderedPage, RenderOptions, SearchOptions, StreamedPage, StreamOptions, } from './types.js';
38
+ export { lineQuad, pageString, quadBounds, scaleQuad, scaleRect, } from './text.js';
39
+ export type { DocumentMetadata, OpenOptions, PageSize, PdfSource, RenderedPage, RenderOptions, SearchOptions, StreamedPage, StreamOptions, SvgOptions, } from './types.js';
40
+ export type { Rotation, Viewport, ViewportOptions } from './viewport.js';
41
+ export { rotatePage, rotateSize, viewport, viewportQuad, viewportRect, } from './viewport.js';
33
42
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AACzD,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC/D,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAC/C,YAAY,EACV,aAAa,EACb,YAAY,EACZ,aAAa,GACd,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxE,YAAY,EACV,eAAe,EACf,kBAAkB,EAClB,WAAW,GACZ,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC7D,YAAY,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EACL,OAAO,EACP,cAAc,EACd,mBAAmB,EACnB,IAAI,GACL,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3D,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAC9D,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AACzD,YAAY,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAChE,OAAO,EACL,QAAQ,EACR,UAAU,EACV,UAAU,EACV,SAAS,GACV,MAAM,WAAW,CAAC;AACnB,YAAY,EACV,WAAW,EACX,QAAQ,EACR,SAAS,EACT,YAAY,EACZ,aAAa,EACb,aAAa,EACb,YAAY,EACZ,aAAa,GACd,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,YAAY,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EACL,mBAAmB,EACnB,mBAAmB,GACpB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AACzD,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1E,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAC/C,YAAY,EACV,aAAa,EACb,YAAY,EACZ,aAAa,EACb,YAAY,EACZ,OAAO,GACR,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,MAAM,EACN,YAAY,EACZ,QAAQ,EACR,SAAS,EACT,OAAO,GACR,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,sBAAsB,EACtB,aAAa,EACb,qBAAqB,GACtB,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACvD,YAAY,EACV,eAAe,EACf,kBAAkB,EAClB,WAAW,GACZ,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC7D,YAAY,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EACL,OAAO,EACP,cAAc,EACd,mBAAmB,EACnB,IAAI,GACL,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3D,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAC9D,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AACzD,YAAY,EACV,aAAa,EACb,WAAW,EACX,UAAU,GACX,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,eAAe,EACf,YAAY,EACZ,oBAAoB,EACpB,cAAc,GACf,MAAM,gBAAgB,CAAC;AACxB,YAAY,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAChE,OAAO,EACL,QAAQ,EACR,UAAU,EACV,UAAU,EACV,SAAS,EACT,SAAS,GACV,MAAM,WAAW,CAAC;AACnB,YAAY,EACV,gBAAgB,EAChB,WAAW,EACX,QAAQ,EACR,SAAS,EACT,YAAY,EACZ,aAAa,EACb,aAAa,EACb,YAAY,EACZ,aAAa,EACb,UAAU,GACX,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,QAAQ,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACzE,OAAO,EACL,UAAU,EACV,UAAU,EACV,QAAQ,EACR,YAAY,EACZ,YAAY,GACb,MAAM,eAAe,CAAC"}
package/dist/index.js CHANGED
@@ -13,12 +13,16 @@
13
13
  * onScroll(() => job.setPriority(0));
14
14
  * ```
15
15
  */
16
+ export { attachmentMediaType, isInvoiceAttachment, } from './attachments.js';
16
17
  export { paintToCanvas, toImageData } from './canvas.js';
17
18
  export { Document, open } from './document.js';
18
- export { encode, encodedImage, mimeType, PageImage } from './encode.js';
19
+ export { encode, encodedImage, mimeType, PageImage, svgPage, } from './encode.js';
20
+ export { IncorrectPasswordError, PasswordError, PasswordRequiredError, } from './errors.js';
19
21
  export { buildOutlineTree, walkOutline } from './outline.js';
20
22
  export { backend, currentRuntime, hardwareConcurrency, init, } from './runtime.js';
21
23
  export { AbortError, DEFAULT_PRIORITY } from './scheduler.js';
22
24
  export { findRanges, searchPageText } from './search.js';
23
- export { lineQuad, pageString, quadBounds, scaleQuad, } from './text.js';
25
+ export { buildStructTree, readingOrder, structuredPageString, walkStructTree, } from './structure.js';
26
+ export { lineQuad, pageString, quadBounds, scaleQuad, scaleRect, } from './text.js';
27
+ export { rotatePage, rotateSize, viewport, viewportQuad, viewportRect, } from './viewport.js';
24
28
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAEzD,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAM/C,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAMxE,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE7D,OAAO,EACL,OAAO,EACP,cAAc,EACd,mBAAmB,EACnB,IAAI,GACL,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAE9D,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAEzD,OAAO,EACL,QAAQ,EACR,UAAU,EACV,UAAU,EACV,SAAS,GACV,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,EACL,mBAAmB,EACnB,mBAAmB,GACpB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAEzD,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAQ/C,OAAO,EACL,MAAM,EACN,YAAY,EACZ,QAAQ,EACR,SAAS,EACT,OAAO,GACR,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,sBAAsB,EACtB,aAAa,EACb,qBAAqB,GACtB,MAAM,aAAa,CAAC;AAOrB,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE7D,OAAO,EACL,OAAO,EACP,cAAc,EACd,mBAAmB,EACnB,IAAI,GACL,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAE9D,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAMzD,OAAO,EACL,eAAe,EACf,YAAY,EACZ,oBAAoB,EACpB,cAAc,GACf,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,QAAQ,EACR,UAAU,EACV,UAAU,EACV,SAAS,EACT,SAAS,GACV,MAAM,WAAW,CAAC;AAcnB,OAAO,EACL,UAAU,EACV,UAAU,EACV,QAAQ,EACR,YAAY,EACZ,YAAY,GACb,MAAM,eAAe,CAAC"}
@@ -0,0 +1,53 @@
1
+ import type { PageLink as NativePageLink } from '@build-qube/papyra-native';
2
+ import { type OutlineDestination } from './outline.js';
3
+ import type { Rect } from './text.js';
4
+ /**
5
+ * Where a link goes.
6
+ *
7
+ * A discriminated union rather than two nullable fields, so narrowing on `kind` gives
8
+ * you the payload without a non-null assertion:
9
+ *
10
+ * ```ts
11
+ * if (link.target.kind === 'uri') window.open(link.target.uri);
12
+ * else void doc.render(link.target.dest.page, { fitWidth: 1600 });
13
+ * ```
14
+ */
15
+ export type LinkTarget = {
16
+ /** The link points somewhere in this document. */
17
+ readonly kind: 'internal';
18
+ /** The page and the view, in the same shape an outline entry uses. */
19
+ readonly dest: OutlineDestination;
20
+ } | {
21
+ /**
22
+ * The link points out of this document.
23
+ *
24
+ * Not necessarily `http`: `mailto:` and `file:` are both common, and papyra
25
+ * does not validate the string. Decide for yourself what you are willing to
26
+ * follow before handing it to a browser.
27
+ */
28
+ readonly kind: 'uri';
29
+ /** The URI, exactly as the document wrote it. */
30
+ readonly uri: string;
31
+ };
32
+ /**
33
+ * One link on a page: a clickable region, and what it does.
34
+ *
35
+ * Only links that resolve to something actionable are reported — a `/Link` pointing
36
+ * at a page the document does not contain, or carrying an action papyra does not act
37
+ * on, is dropped rather than handed over as a region that would swallow clicks.
38
+ */
39
+ export interface PageLink {
40
+ /**
41
+ * The clickable region, in the same 72-DPI top-left space as {@link PageText} and
42
+ * {@link PageSize}. Multiply by `rendered.width / pageSize.width` to place it over
43
+ * a render — {@link scaleRect} does exactly that.
44
+ */
45
+ readonly rect: Rect;
46
+ /** Where activating the link goes. Narrow on `target.kind`. */
47
+ readonly target: LinkTarget;
48
+ /** The annotation's tooltip, when it has one. */
49
+ readonly alt: string | null;
50
+ }
51
+ /** @internal */
52
+ export declare function toPageLink(native: NativePageLink): PageLink | null;
53
+ //# sourceMappingURL=links.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"links.d.ts","sourceRoot":"","sources":["../src/links.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,IAAI,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC5E,OAAO,EAAE,KAAK,kBAAkB,EAAiB,MAAM,cAAc,CAAC;AACtE,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEtC;;;;;;;;;;GAUG;AACH,MAAM,MAAM,UAAU,GAClB;IACE,kDAAkD;IAClD,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,sEAAsE;IACtE,QAAQ,CAAC,IAAI,EAAE,kBAAkB,CAAC;CACnC,GACD;IACE;;;;;;OAMG;IACH,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;IACrB,iDAAiD;IACjD,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB,CAAC;AAEN;;;;;;GAMG;AACH,MAAM,WAAW,QAAQ;IACvB;;;;OAIG;IACH,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB,+DAA+D;IAC/D,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B,iDAAiD;IACjD,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,gBAAgB;AAChB,wBAAgB,UAAU,CAAC,MAAM,EAAE,cAAc,GAAG,QAAQ,GAAG,IAAI,CAelE"}
package/dist/links.js ADDED
@@ -0,0 +1,26 @@
1
+ import { toDestination } from './outline.js';
2
+ /** @internal */
3
+ export function toPageLink(native) {
4
+ const target = linkTarget(native);
5
+ // The bindings only emit a link with one target or the other, so this is
6
+ // unreachable in practice; dropping it beats widening the type with a null target.
7
+ if (!target)
8
+ return null;
9
+ return {
10
+ rect: {
11
+ x: native.x0,
12
+ y: native.y0,
13
+ width: native.x1 - native.x0,
14
+ height: native.y1 - native.y0,
15
+ },
16
+ target,
17
+ alt: native.alt ?? null,
18
+ };
19
+ }
20
+ function linkTarget(native) {
21
+ if (native.uri !== undefined)
22
+ return { kind: 'uri', uri: native.uri };
23
+ const dest = toDestination(native.dest);
24
+ return dest ? { kind: 'internal', dest } : null;
25
+ }
26
+ //# sourceMappingURL=links.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"links.js","sourceRoot":"","sources":["../src/links.ts"],"names":[],"mappings":"AACA,OAAO,EAA2B,aAAa,EAAE,MAAM,cAAc,CAAC;AAsDtE,gBAAgB;AAChB,MAAM,UAAU,UAAU,CAAC,MAAsB;IAC/C,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;IAClC,yEAAyE;IACzE,mFAAmF;IACnF,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IACzB,OAAO;QACL,IAAI,EAAE;YACJ,CAAC,EAAE,MAAM,CAAC,EAAE;YACZ,CAAC,EAAE,MAAM,CAAC,EAAE;YACZ,KAAK,EAAE,MAAM,CAAC,EAAE,GAAG,MAAM,CAAC,EAAE;YAC5B,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,MAAM,CAAC,EAAE;SAC9B;QACD,MAAM;QACN,GAAG,EAAE,MAAM,CAAC,GAAG,IAAI,IAAI;KACxB,CAAC;AACJ,CAAC;AAED,SAAS,UAAU,CAAC,MAAsB;IACxC,IAAI,MAAM,CAAC,GAAG,KAAK,SAAS;QAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,CAAC;IACtE,MAAM,IAAI,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACxC,OAAO,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AAClD,CAAC"}
package/dist/outline.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { OutlineEntry as NativeEntry } from '@build-qube/papyra-native';
1
+ import type { OutlineDestination as NativeDestination, OutlineEntry as NativeEntry } from '@build-qube/papyra-native';
2
2
  /** How a destination positions the page in the window (PDF 32000-1, 12.3.2.2). */
3
3
  export type DestinationKind = 'XYZ' | 'Fit' | 'FitH' | 'FitV' | 'FitR' | 'FitB' | 'FitBH' | 'FitBV';
4
4
  /**
@@ -45,6 +45,14 @@ export interface OutlineNode {
45
45
  /** Nested entries, empty for a leaf. */
46
46
  readonly children: OutlineNode[];
47
47
  }
48
+ /**
49
+ * napi omits absent numbers rather than nulling them; normalise to one shape.
50
+ *
51
+ * Shared with the link reader, whose targets resolve to the same destinations.
52
+ *
53
+ * @internal
54
+ */
55
+ export declare function toDestination(dest: NativeDestination | undefined): OutlineDestination | null;
48
56
  /**
49
57
  * Rebuild the tree from the flat pre-order list the bindings return.
50
58
  *
@@ -1 +1 @@
1
- {"version":3,"file":"outline.d.ts","sourceRoot":"","sources":["../src/outline.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,YAAY,IAAI,WAAW,EAC5B,MAAM,2BAA2B,CAAC;AAEnC,kFAAkF;AAClF,MAAM,MAAM,eAAe,GACvB,KAAK,GACL,KAAK,GACL,MAAM,GACN,MAAM,GACN,MAAM,GACN,MAAM,GACN,OAAO,GACP,OAAO,CAAC;AAEZ;;;;;;;GAOG;AACH,MAAM,WAAW,kBAAkB;IACjC,0BAA0B;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,iEAAiE;IACjE,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAC;IAC/B,gEAAgE;IAChE,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,+DAA+D;IAC/D,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,8CAA8C;IAC9C,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,+CAA+C;IAC/C,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,oFAAoF;IACpF,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAED,sCAAsC;AACtC,MAAM,WAAW,WAAW;IAC1B,+EAA+E;IAC/E,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,QAAQ,CAAC,IAAI,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACzC,+DAA+D;IAC/D,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,yDAAyD;IACzD,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,2DAA2D;IAC3D,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,yDAAyD;IACzD,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,wCAAwC;IACxC,QAAQ,CAAC,QAAQ,EAAE,WAAW,EAAE,CAAC;CAClC;AA+BD;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,SAAS,WAAW,EAAE,GAC9B,WAAW,EAAE,CAyBf;AAED,sEAAsE;AACtE,wBAAiB,WAAW,CAC1B,KAAK,EAAE,SAAS,WAAW,EAAE,EAC7B,KAAK,SAAI,GACR,SAAS,CAAC;IACX,iBAAiB;IACjB,IAAI,EAAE,WAAW,CAAC;IAClB,2DAA2D;IAC3D,KAAK,EAAE,MAAM,CAAC;CACf,CAAC,CAKD"}
1
+ {"version":3,"file":"outline.d.ts","sourceRoot":"","sources":["../src/outline.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,kBAAkB,IAAI,iBAAiB,EACvC,YAAY,IAAI,WAAW,EAC5B,MAAM,2BAA2B,CAAC;AAEnC,kFAAkF;AAClF,MAAM,MAAM,eAAe,GACvB,KAAK,GACL,KAAK,GACL,MAAM,GACN,MAAM,GACN,MAAM,GACN,MAAM,GACN,OAAO,GACP,OAAO,CAAC;AAEZ;;;;;;;GAOG;AACH,MAAM,WAAW,kBAAkB;IACjC,0BAA0B;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,iEAAiE;IACjE,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAC;IAC/B,gEAAgE;IAChE,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,+DAA+D;IAC/D,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,8CAA8C;IAC9C,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,+CAA+C;IAC/C,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,oFAAoF;IACpF,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAED,sCAAsC;AACtC,MAAM,WAAW,WAAW;IAC1B,+EAA+E;IAC/E,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,QAAQ,CAAC,IAAI,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACzC,+DAA+D;IAC/D,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,yDAAyD;IACzD,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,2DAA2D;IAC3D,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,yDAAyD;IACzD,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,wCAAwC;IACxC,QAAQ,CAAC,QAAQ,EAAE,WAAW,EAAE,CAAC;CAClC;AAaD;;;;;;GAMG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,iBAAiB,GAAG,SAAS,GAClC,kBAAkB,GAAG,IAAI,CAa3B;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,SAAS,WAAW,EAAE,GAC9B,WAAW,EAAE,CAyBf;AAED,sEAAsE;AACtE,wBAAiB,WAAW,CAC1B,KAAK,EAAE,SAAS,WAAW,EAAE,EAC7B,KAAK,SAAI,GACR,SAAS,CAAC;IACX,iBAAiB;IACjB,IAAI,EAAE,WAAW,CAAC;IAClB,2DAA2D;IAC3D,KAAK,EAAE,MAAM,CAAC;CACf,CAAC,CAKD"}
package/dist/outline.js CHANGED
@@ -8,8 +8,14 @@ const KINDS = new Set([
8
8
  'FitBH',
9
9
  'FitBV',
10
10
  ]);
11
- /** napi omits absent numbers rather than nulling them; normalise to one shape. */
12
- function destination(dest) {
11
+ /**
12
+ * napi omits absent numbers rather than nulling them; normalise to one shape.
13
+ *
14
+ * Shared with the link reader, whose targets resolve to the same destinations.
15
+ *
16
+ * @internal
17
+ */
18
+ export function toDestination(dest) {
13
19
  if (!dest)
14
20
  return null;
15
21
  return {
@@ -36,7 +42,7 @@ export function buildOutlineTree(entries) {
36
42
  const roots = [];
37
43
  const stack = [];
38
44
  for (const entry of entries) {
39
- const dest = destination(entry.dest);
45
+ const dest = toDestination(entry.dest);
40
46
  const node = {
41
47
  title: entry.title,
42
48
  dest,
@@ -1 +1 @@
1
- {"version":3,"file":"outline.js","sourceRoot":"","sources":["../src/outline.ts"],"names":[],"mappings":"AA8DA,MAAM,KAAK,GAAG,IAAI,GAAG,CAAS;IAC5B,KAAK;IACL,KAAK;IACL,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,OAAO;IACP,OAAO;CACR,CAAC,CAAC;AAEH,kFAAkF;AAClF,SAAS,WAAW,CAClB,IAAmC;IAEnC,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IACvB,OAAO;QACL,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,8EAA8E;QAC9E,iDAAiD;QACjD,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAoB;QACnE,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,IAAI;QACvB,GAAG,EAAE,IAAI,CAAC,GAAG,IAAI,IAAI;QACrB,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,IAAI;QACzB,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,IAAI;QAC3B,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,IAAI;KACxB,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,gBAAgB,CAC9B,OAA+B;IAE/B,MAAM,KAAK,GAAkB,EAAE,CAAC;IAChC,MAAM,KAAK,GAAkB,EAAE,CAAC;IAEhC,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,MAAM,IAAI,GAAG,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACrC,MAAM,IAAI,GAAgB;YACxB,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,IAAI;YACJ,IAAI,EAAE,IAAI,EAAE,IAAI,IAAI,IAAI;YACxB,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,QAAQ,EAAE,EAAE;SACb,CAAC;QAEF,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;QAClD,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC;QACrB,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;QAChC,IAAI,MAAM;YAAE,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;;YAClC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACtB,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACnB,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,sEAAsE;AACtE,MAAM,SAAS,CAAC,CAAC,WAAW,CAC1B,KAA6B,EAC7B,KAAK,GAAG,CAAC;IAOT,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;QACtB,KAAK,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;IAC/C,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"outline.js","sourceRoot":"","sources":["../src/outline.ts"],"names":[],"mappings":"AA8DA,MAAM,KAAK,GAAG,IAAI,GAAG,CAAS;IAC5B,KAAK;IACL,KAAK;IACL,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,OAAO;IACP,OAAO;CACR,CAAC,CAAC;AAEH;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAC3B,IAAmC;IAEnC,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IACvB,OAAO;QACL,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,8EAA8E;QAC9E,iDAAiD;QACjD,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAoB;QACnE,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,IAAI;QACvB,GAAG,EAAE,IAAI,CAAC,GAAG,IAAI,IAAI;QACrB,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,IAAI;QACzB,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,IAAI;QAC3B,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,IAAI;KACxB,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,gBAAgB,CAC9B,OAA+B;IAE/B,MAAM,KAAK,GAAkB,EAAE,CAAC;IAChC,MAAM,KAAK,GAAkB,EAAE,CAAC;IAEhC,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,MAAM,IAAI,GAAG,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACvC,MAAM,IAAI,GAAgB;YACxB,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,IAAI;YACJ,IAAI,EAAE,IAAI,EAAE,IAAI,IAAI,IAAI;YACxB,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,QAAQ,EAAE,EAAE;SACb,CAAC;QAEF,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;QAClD,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC;QACrB,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;QAChC,IAAI,MAAM;YAAE,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;;YAClC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACtB,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACnB,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,sEAAsE;AACtE,MAAM,SAAS,CAAC,CAAC,WAAW,CAC1B,KAA6B,EAC7B,KAAK,GAAG,CAAC;IAOT,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;QACtB,KAAK,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;IAC/C,CAAC;AACH,CAAC"}
@@ -0,0 +1,119 @@
1
+ import type { StructEntry as NativeEntry } from '@build-qube/papyra-native';
2
+ import type { PageText, TextLine } from './text.js';
3
+ /**
4
+ * One run of page content owned by a {@link StructNode}.
5
+ *
6
+ * The pair is what makes the join work: a marked-content id is only unique within a
7
+ * single page's content stream, so an id on its own addresses nothing.
8
+ */
9
+ export interface MarkedContent {
10
+ /** 0-based page index. */
11
+ readonly page: number;
12
+ /** Matches {@link TextLine.mcid} on that page. */
13
+ readonly mcid: number;
14
+ }
15
+ /**
16
+ * A node in the document structure tree.
17
+ *
18
+ * A tagged PDF states what its content *means* — which runs are a heading, which are
19
+ * a table cell — and, more usefully than either, what order it is meant to be read
20
+ * in. Nothing else in a PDF carries that: {@link PageText.lines} is content-stream
21
+ * order, which interleaves the columns of a two-column page.
22
+ */
23
+ export interface StructNode {
24
+ /**
25
+ * Standard structure type: `'Document'`, `'H1'`, `'P'`, `'Table'`, `'TD'`,
26
+ * `'Figure'`, and the rest of ISO 32000-1's set.
27
+ *
28
+ * Already resolved through the document's `/RoleMap`, so a file that tags its
29
+ * headings `Heading1` and maps that onto `H1` reports `'H1'` here. Word and
30
+ * InDesign both emit such files, so matching on {@link StructNode.rawRole} instead
31
+ * misses a large share of real tagged documents.
32
+ */
33
+ readonly role: string;
34
+ /**
35
+ * The document's own tag, before `/RoleMap`. Equal to {@link StructNode.role}
36
+ * unless the document remapped it.
37
+ */
38
+ readonly rawRole: string;
39
+ /**
40
+ * Content this element owns directly, in the order the tree declares it.
41
+ *
42
+ * Empty for a pure container — a `Sect` whose text all belongs to the `P`s beneath
43
+ * it — which is most interior nodes.
44
+ */
45
+ readonly content: readonly MarkedContent[];
46
+ /** `/Alt`: replacement text for a figure, and the only text an image has. */
47
+ readonly alt: string | null;
48
+ /**
49
+ * `/ActualText`: text that replaces the content rather than describing it, which is
50
+ * how a document spells out a ligature or a decorative glyph.
51
+ */
52
+ readonly actualText: string | null;
53
+ /** `/Lang`: a BCP 47 tag overriding the document language for this subtree. */
54
+ readonly lang: string | null;
55
+ /** `/T`: a human-readable title for the element, such as a table's caption. */
56
+ readonly title: string | null;
57
+ /** Nested elements, empty for a leaf. */
58
+ readonly children: StructNode[];
59
+ }
60
+ /**
61
+ * Rebuild the tree from the flat pre-order list the bindings return.
62
+ *
63
+ * The same stack-by-level pass {@link buildOutlineTree} uses, and correct for the same
64
+ * reason: pre-order guarantees a node's parent is the most recent node one level
65
+ * shallower. A level that skips a step cannot come from our own walker, and is clamped
66
+ * rather than trusted — a malformed document should flatten, not crash.
67
+ */
68
+ export declare function buildStructTree(entries: readonly NativeEntry[]): StructNode[];
69
+ /** Walk a structure tree depth-first, yielding each node with its depth. */
70
+ export declare function walkStructTree(nodes: readonly StructNode[], depth?: number): Generator<{
71
+ /** The element. */
72
+ node: StructNode;
73
+ /** How deep it sits, 0 for a root. */
74
+ depth: number;
75
+ }>;
76
+ /** One line of a page, with the structure element that claims it. */
77
+ export interface OrderedLine {
78
+ /** The line, exactly as {@link PageText} reported it. */
79
+ readonly line: TextLine;
80
+ /**
81
+ * The element whose content the line's first glyph sits in, or `null` for a line
82
+ * the structure tree does not account for.
83
+ */
84
+ readonly node: StructNode | null;
85
+ }
86
+ /**
87
+ * Put a page's lines into the reading order the document declares.
88
+ *
89
+ * This is the payoff of a tagged PDF and the one thing geometry cannot recover: on a
90
+ * two-column page the content stream may draw both columns interleaved, and no line
91
+ * grouping fixes that, because the drawing order genuinely is what it is. The
92
+ * structure tree states the intended order outright.
93
+ *
94
+ * Lines are keyed by their first glyph's {@link TextLine.mcid}, so a line is placed by
95
+ * the element that *starts* it. Ties — several lines inside one `P`, which is the
96
+ * normal case for a wrapped paragraph — keep their original relative order, so within
97
+ * an element the result is still the content stream's sequence. That is what makes
98
+ * this safe on a document whose tagging is partial.
99
+ *
100
+ * Lines with no structure element go **last**, rather than being dropped: untagged
101
+ * content is usually a running head or a page number, and losing it silently would be
102
+ * worse than putting it at the end. Pass `includeUntagged: false` to drop them.
103
+ *
104
+ * Returns the lines in content-stream order, unchanged, when the page has no tagged
105
+ * content at all — an untagged document is the common case and should not come back
106
+ * empty or reshuffled.
107
+ */
108
+ export declare function readingOrder(text: PageText, tree: readonly StructNode[], options?: {
109
+ /** Keep lines no element claims, at the end. Defaults to `true`. */
110
+ readonly includeUntagged?: boolean;
111
+ }): OrderedLine[];
112
+ /**
113
+ * Every character of a page in declared reading order, one line per entry.
114
+ *
115
+ * The structure-aware counterpart to {@link pageString}; identical to it on an
116
+ * untagged page.
117
+ */
118
+ export declare function structuredPageString(text: PageText, tree: readonly StructNode[]): string;
119
+ //# sourceMappingURL=structure.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"structure.d.ts","sourceRoot":"","sources":["../src/structure.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,WAAW,IAAI,WAAW,EAE3B,MAAM,2BAA2B,CAAC;AACnC,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAEpD;;;;;GAKG;AACH,MAAM,WAAW,aAAa;IAC5B,0BAA0B;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,kDAAkD;IAClD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,UAAU;IACzB;;;;;;;;OAQG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB;;;;;OAKG;IACH,QAAQ,CAAC,OAAO,EAAE,SAAS,aAAa,EAAE,CAAC;IAC3C,6EAA6E;IAC7E,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B;;;OAGG;IACH,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,+EAA+E;IAC/E,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,+EAA+E;IAC/E,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,yCAAyC;IACzC,QAAQ,CAAC,QAAQ,EAAE,UAAU,EAAE,CAAC;CACjC;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,SAAS,WAAW,EAAE,GAAG,UAAU,EAAE,CAyB7E;AAED,4EAA4E;AAC5E,wBAAiB,cAAc,CAC7B,KAAK,EAAE,SAAS,UAAU,EAAE,EAC5B,KAAK,SAAI,GACR,SAAS,CAAC;IACX,mBAAmB;IACnB,IAAI,EAAE,UAAU,CAAC;IACjB,sCAAsC;IACtC,KAAK,EAAE,MAAM,CAAC;CACf,CAAC,CAKD;AAED,qEAAqE;AACrE,MAAM,WAAW,WAAW;IAC1B,yDAAyD;IACzD,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB;;;OAGG;IACH,QAAQ,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,CAAC;CAClC;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,QAAQ,EACd,IAAI,EAAE,SAAS,UAAU,EAAE,EAC3B,OAAO,GAAE;IACP,oEAAoE;IACpE,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,CAAC;CAC/B,GACL,WAAW,EAAE,CA4Cf;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,QAAQ,EACd,IAAI,EAAE,SAAS,UAAU,EAAE,GAC1B,MAAM,CAIR"}