@2018kguo/recto 0.1.0 → 0.5.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/dist/assets.d.ts +11 -6
- package/dist/assets.js +123 -42
- package/dist/document.d.ts +144 -2
- package/dist/document.js +163 -14
- package/dist/engine.d.ts +24 -9
- package/dist/engine.js +236 -49
- package/dist/errors.d.ts +4 -2
- package/dist/errors.js +4 -1
- package/dist/index.d.ts +12 -1
- package/dist/index.js +13 -0
- package/dist/pool-worker.d.ts +15 -0
- package/dist/pool-worker.js +65 -0
- package/dist/pool.d.ts +42 -0
- package/dist/pool.js +295 -0
- package/dist/ranged.d.ts +44 -9
- package/dist/ranged.js +571 -86
- package/package.json +2 -1
- package/wasm/FoxitDingbats.pfb +0 -0
- package/wasm/FoxitFixed.pfb +0 -0
- package/wasm/FoxitFixedBold.pfb +0 -0
- package/wasm/FoxitFixedBoldItalic.pfb +0 -0
- package/wasm/FoxitFixedItalic.pfb +0 -0
- package/wasm/FoxitSans.pfb +0 -0
- package/wasm/FoxitSansBold.pfb +0 -0
- package/wasm/FoxitSansBoldItalic.pfb +0 -0
- package/wasm/FoxitSansItalic.pfb +0 -0
- package/wasm/FoxitSerif.pfb +0 -0
- package/wasm/FoxitSerifBold.pfb +0 -0
- package/wasm/FoxitSerifBoldItalic.pfb +0 -0
- package/wasm/FoxitSerifItalic.pfb +0 -0
- package/wasm/FoxitSymbol.pfb +0 -0
- package/wasm/THIRD_PARTY_NOTICES +2 -158
- package/wasm/cmaps.deflate +0 -0
- package/wasm/pins.d.mts +1 -1
- package/wasm/pins.mjs +19 -3
- package/wasm/recto-more.wasm +0 -0
- package/wasm/recto-rare.wasm +0 -0
- package/wasm/recto-render.wasm +0 -0
- package/wasm/recto.gen.d.mts +2 -1
- package/wasm/recto.gen.mjs +213 -19
- package/wasm/recto.types.d.mts +83 -4
- package/wasm/recto.wasm +0 -0
- package/wasm/cmaps.brotli +0 -0
- package/wasm/fonts.bin +0 -0
package/dist/assets.d.ts
CHANGED
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
import { PINS } from "../wasm/pins.mjs";
|
|
2
2
|
export type AssetName = keyof typeof PINS;
|
|
3
|
+
export type WasmName = "recto.wasm" | "recto-render.wasm" | "recto-more.wasm" | "recto-rare.wasm";
|
|
4
|
+
/** The standard fonts, in the order the wasm asks for them (`font_index` in crates/recto/src/assets.rs). */
|
|
5
|
+
export declare const STANDARD_FONTS: readonly ["FoxitFixed.pfb", "FoxitFixedBold.pfb", "FoxitFixedBoldItalic.pfb", "FoxitFixedItalic.pfb", "FoxitSans.pfb", "FoxitSansBold.pfb", "FoxitSansBoldItalic.pfb", "FoxitSansItalic.pfb", "FoxitSerif.pfb", "FoxitSerifBold.pfb", "FoxitSerifBoldItalic.pfb", "FoxitSerifItalic.pfb", "FoxitSymbol.pfb", "FoxitDingbats.pfb"];
|
|
3
6
|
/** Whether an asset can be read at the moment the engine asks for it. */
|
|
4
7
|
export declare function canReadSync(): boolean;
|
|
5
8
|
/** `assetBase` as a directory URL, or null for the package's own files. */
|
|
6
9
|
export declare function assetBaseUrl(base: string | URL | undefined): URL | null;
|
|
7
|
-
/**
|
|
8
|
-
export
|
|
9
|
-
/**
|
|
10
|
+
/** A hash to use where there is no native one to call synchronously. A live instance's is quicker than this file's. */
|
|
11
|
+
export type SyncHash = (bytes: Uint8Array) => string | null;
|
|
12
|
+
/** The wasm, verified and then compiled. */
|
|
13
|
+
export declare function compileWasm(name: WasmName, base: URL | null): Promise<WebAssembly.Module>;
|
|
14
|
+
/** Fetches and verifies assets ahead of time; a thread that can't read them when needed has to. */
|
|
10
15
|
export declare function preloadAssets(base: URL | null, names: AssetName[]): Promise<void>;
|
|
11
16
|
/** An asset, read synchronously. Throws a PdfError rather than returning nothing. */
|
|
12
|
-
export declare function loadAssetSync(name: AssetName, base: URL | null): Uint8Array;
|
|
13
|
-
/**
|
|
14
|
-
export declare function
|
|
17
|
+
export declare function loadAssetSync(name: AssetName, base: URL | null, hash?: SyncHash): Uint8Array;
|
|
18
|
+
/** A file, read now and hashed before it's returned, and not kept: a part is compiled once. */
|
|
19
|
+
export declare function readCheckedSync(name: AssetName, base: URL | null, hash?: SyncHash): Uint8Array;
|
package/dist/assets.js
CHANGED
|
@@ -8,21 +8,72 @@
|
|
|
8
8
|
// are written out as `new URL("literal", import.meta.url)` because that is the form
|
|
9
9
|
// bundlers recognise and rewrite, emitting the file.
|
|
10
10
|
//
|
|
11
|
-
// Each file is pinned by SHA-256
|
|
12
|
-
// HTML fallback page must not read as a font.
|
|
11
|
+
// Each file is pinned by SHA-256 and hashed here, every byte, before it's used: the engine reads
|
|
12
|
+
// its tables as trusted, and a dev server's HTML fallback page must not read as a font. Nothing is
|
|
13
|
+
// left to `fetch`'s `integrity`, which a wrapper around `fetch` can drop, and which buffers the
|
|
14
|
+
// body anyway. pins.mjs is written by the build.
|
|
13
15
|
import { PINS } from "../wasm/pins.mjs";
|
|
14
16
|
import { PdfError } from "./errors.js";
|
|
15
17
|
import { sha256Hex } from "./sha256.js";
|
|
18
|
+
/** The standard fonts, in the order the wasm asks for them (`font_index` in crates/recto/src/assets.rs). */
|
|
19
|
+
export const STANDARD_FONTS = [
|
|
20
|
+
"FoxitFixed.pfb",
|
|
21
|
+
"FoxitFixedBold.pfb",
|
|
22
|
+
"FoxitFixedBoldItalic.pfb",
|
|
23
|
+
"FoxitFixedItalic.pfb",
|
|
24
|
+
"FoxitSans.pfb",
|
|
25
|
+
"FoxitSansBold.pfb",
|
|
26
|
+
"FoxitSansBoldItalic.pfb",
|
|
27
|
+
"FoxitSansItalic.pfb",
|
|
28
|
+
"FoxitSerif.pfb",
|
|
29
|
+
"FoxitSerifBold.pfb",
|
|
30
|
+
"FoxitSerifBoldItalic.pfb",
|
|
31
|
+
"FoxitSerifItalic.pfb",
|
|
32
|
+
"FoxitSymbol.pfb",
|
|
33
|
+
"FoxitDingbats.pfb",
|
|
34
|
+
];
|
|
16
35
|
function packagedUrl(name) {
|
|
17
36
|
switch (name) {
|
|
18
37
|
case "recto.wasm":
|
|
19
38
|
return new URL("../wasm/recto.wasm", import.meta.url);
|
|
20
|
-
case "
|
|
21
|
-
return new URL("../wasm/
|
|
39
|
+
case "recto-render.wasm":
|
|
40
|
+
return new URL("../wasm/recto-render.wasm", import.meta.url);
|
|
41
|
+
case "recto-more.wasm":
|
|
42
|
+
return new URL("../wasm/recto-more.wasm", import.meta.url);
|
|
43
|
+
case "recto-rare.wasm":
|
|
44
|
+
return new URL("../wasm/recto-rare.wasm", import.meta.url);
|
|
45
|
+
case "FoxitFixed.pfb":
|
|
46
|
+
return new URL("../wasm/FoxitFixed.pfb", import.meta.url);
|
|
47
|
+
case "FoxitFixedBold.pfb":
|
|
48
|
+
return new URL("../wasm/FoxitFixedBold.pfb", import.meta.url);
|
|
49
|
+
case "FoxitFixedBoldItalic.pfb":
|
|
50
|
+
return new URL("../wasm/FoxitFixedBoldItalic.pfb", import.meta.url);
|
|
51
|
+
case "FoxitFixedItalic.pfb":
|
|
52
|
+
return new URL("../wasm/FoxitFixedItalic.pfb", import.meta.url);
|
|
53
|
+
case "FoxitSans.pfb":
|
|
54
|
+
return new URL("../wasm/FoxitSans.pfb", import.meta.url);
|
|
55
|
+
case "FoxitSansBold.pfb":
|
|
56
|
+
return new URL("../wasm/FoxitSansBold.pfb", import.meta.url);
|
|
57
|
+
case "FoxitSansBoldItalic.pfb":
|
|
58
|
+
return new URL("../wasm/FoxitSansBoldItalic.pfb", import.meta.url);
|
|
59
|
+
case "FoxitSansItalic.pfb":
|
|
60
|
+
return new URL("../wasm/FoxitSansItalic.pfb", import.meta.url);
|
|
61
|
+
case "FoxitSerif.pfb":
|
|
62
|
+
return new URL("../wasm/FoxitSerif.pfb", import.meta.url);
|
|
63
|
+
case "FoxitSerifBold.pfb":
|
|
64
|
+
return new URL("../wasm/FoxitSerifBold.pfb", import.meta.url);
|
|
65
|
+
case "FoxitSerifBoldItalic.pfb":
|
|
66
|
+
return new URL("../wasm/FoxitSerifBoldItalic.pfb", import.meta.url);
|
|
67
|
+
case "FoxitSerifItalic.pfb":
|
|
68
|
+
return new URL("../wasm/FoxitSerifItalic.pfb", import.meta.url);
|
|
69
|
+
case "FoxitSymbol.pfb":
|
|
70
|
+
return new URL("../wasm/FoxitSymbol.pfb", import.meta.url);
|
|
71
|
+
case "FoxitDingbats.pfb":
|
|
72
|
+
return new URL("../wasm/FoxitDingbats.pfb", import.meta.url);
|
|
22
73
|
case "cjk-fallback.ttf":
|
|
23
74
|
return new URL("../wasm/cjk-fallback.ttf", import.meta.url);
|
|
24
|
-
case "cmaps.
|
|
25
|
-
return new URL("../wasm/cmaps.
|
|
75
|
+
case "cmaps.deflate":
|
|
76
|
+
return new URL("../wasm/cmaps.deflate", import.meta.url);
|
|
26
77
|
}
|
|
27
78
|
}
|
|
28
79
|
/** A stalled server must not block the thread for ever; the largest asset is 5 MB. */
|
|
@@ -71,11 +122,16 @@ function loadFailure(name, url, reason, cause) {
|
|
|
71
122
|
return new PdfError("missing-asset", `recto could not load ${name}${url ? ` from ${url.href}` : ""}: ${reason}. It ships in the package's wasm/ ` +
|
|
72
123
|
"directory. If a bundler or dev server moved the package without its files, copy them " +
|
|
73
124
|
"somewhere it serves and pass that directory as `assetBase` (with Vite's dev server, add " +
|
|
74
|
-
'optimizeDeps: { exclude: ["@2018kguo/recto"] } instead).', cause);
|
|
125
|
+
'optimizeDeps: { exclude: ["@2018kguo/recto"] } instead; a server bundle should keep the package external).', cause);
|
|
75
126
|
}
|
|
76
|
-
function
|
|
77
|
-
|
|
78
|
-
|
|
127
|
+
function notThisBuild(name, url, bytes) {
|
|
128
|
+
return loadFailure(name, url, `the ${bytes.byteLength} bytes there are not this build's file (a server's fallback page, or a different version of the package)`);
|
|
129
|
+
}
|
|
130
|
+
function checked(name, url, bytes, hash) {
|
|
131
|
+
const crypto = globalThis.process?.getBuiltinModule?.("node:crypto");
|
|
132
|
+
const hex = crypto ? crypto.createHash("sha256").update(bytes).digest("hex") : (hash?.(bytes) ?? sha256Hex(bytes));
|
|
133
|
+
if (hex !== PINS[name]) {
|
|
134
|
+
throw notThisBuild(name, url, bytes);
|
|
79
135
|
}
|
|
80
136
|
return bytes;
|
|
81
137
|
}
|
|
@@ -93,32 +149,52 @@ function readSync(url) {
|
|
|
93
149
|
}
|
|
94
150
|
return new Uint8Array(xhr.response);
|
|
95
151
|
}
|
|
96
|
-
/**
|
|
97
|
-
|
|
152
|
+
/** `crypto.subtle` is only there in a secure context; a plain-http page hashes here. */
|
|
153
|
+
async function hashOf(bytes) {
|
|
154
|
+
const subtle = globalThis.crypto?.subtle;
|
|
155
|
+
if (!subtle) {
|
|
156
|
+
return sha256Hex(bytes);
|
|
157
|
+
}
|
|
158
|
+
const digest = new Uint8Array(await subtle.digest("SHA-256", bytes));
|
|
159
|
+
return Array.from(digest, (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
160
|
+
}
|
|
161
|
+
/** The only way bytes get here from a network without blocking: whole, and hashed before they're used. */
|
|
162
|
+
async function fetchBytes(name, url) {
|
|
163
|
+
const response = await fetch(url);
|
|
164
|
+
if (!response.ok) {
|
|
165
|
+
throw new Error(`HTTP ${response.status}`);
|
|
166
|
+
}
|
|
167
|
+
const bytes = new Uint8Array(await response.arrayBuffer());
|
|
168
|
+
if ((await hashOf(bytes)) !== PINS[name]) {
|
|
169
|
+
throw notThisBuild(name, url, bytes);
|
|
170
|
+
}
|
|
171
|
+
return bytes;
|
|
172
|
+
}
|
|
173
|
+
/** The wasm, verified and then compiled. */
|
|
174
|
+
export async function compileWasm(name, base) {
|
|
98
175
|
let url = null;
|
|
99
176
|
let bytes;
|
|
100
177
|
try {
|
|
101
178
|
// Inside the try: under a blob: worker `import.meta.url` is no base for a URL.
|
|
102
|
-
url = assetUrl(
|
|
103
|
-
|
|
104
|
-
bytes = readFromDisk(url);
|
|
105
|
-
}
|
|
106
|
-
else {
|
|
107
|
-
const response = await fetch(url);
|
|
108
|
-
if (!response.ok) {
|
|
109
|
-
throw new Error(`HTTP ${response.status}`);
|
|
110
|
-
}
|
|
111
|
-
bytes = new Uint8Array(await response.arrayBuffer());
|
|
112
|
-
}
|
|
179
|
+
url = assetUrl(name, base);
|
|
180
|
+
bytes = (nodeFs() ? checked(name, url, readFromDisk(url)) : await fetchBytes(name, url));
|
|
113
181
|
}
|
|
114
182
|
catch (error) {
|
|
115
|
-
|
|
183
|
+
if (error instanceof PdfError) {
|
|
184
|
+
throw error;
|
|
185
|
+
}
|
|
186
|
+
throw loadFailure(name, url, error instanceof Error ? error.message : String(error), error);
|
|
116
187
|
}
|
|
117
|
-
return
|
|
188
|
+
return await compiling(name, WebAssembly.compile(bytes));
|
|
189
|
+
}
|
|
190
|
+
function compiling(name, module) {
|
|
191
|
+
return module.catch((error) => {
|
|
192
|
+
throw new PdfError("missing-asset", `recto could not compile ${name}: ${String(error)}. A Content-Security-Policy must allow 'wasm-unsafe-eval'.`, error);
|
|
193
|
+
});
|
|
118
194
|
}
|
|
119
195
|
/** Verified assets by URL: hash and read each once per thread. */
|
|
120
196
|
const loaded = new Map();
|
|
121
|
-
/** Fetches assets ahead of time
|
|
197
|
+
/** Fetches and verifies assets ahead of time; a thread that can't read them when needed has to. */
|
|
122
198
|
export async function preloadAssets(base, names) {
|
|
123
199
|
await Promise.all(names.map(async (name) => {
|
|
124
200
|
let url = null;
|
|
@@ -128,28 +204,40 @@ export async function preloadAssets(base, names) {
|
|
|
128
204
|
if (loaded.has(url.href)) {
|
|
129
205
|
return;
|
|
130
206
|
}
|
|
131
|
-
|
|
132
|
-
if (!response.ok) {
|
|
133
|
-
throw new Error(`HTTP ${response.status}`);
|
|
134
|
-
}
|
|
135
|
-
bytes = new Uint8Array(await response.arrayBuffer());
|
|
207
|
+
bytes = nodeFs() ? checked(name, url, readFromDisk(url)) : await fetchBytes(name, url);
|
|
136
208
|
}
|
|
137
209
|
catch (error) {
|
|
210
|
+
if (error instanceof PdfError) {
|
|
211
|
+
throw error;
|
|
212
|
+
}
|
|
138
213
|
throw loadFailure(name, url, error instanceof Error ? error.message : String(error), error);
|
|
139
214
|
}
|
|
140
|
-
loaded.set(url.href,
|
|
215
|
+
loaded.set(url.href, bytes);
|
|
141
216
|
}));
|
|
142
217
|
}
|
|
143
218
|
/** An asset, read synchronously. Throws a PdfError rather than returning nothing. */
|
|
144
|
-
export function loadAssetSync(name, base) {
|
|
219
|
+
export function loadAssetSync(name, base, hash) {
|
|
145
220
|
let url = null;
|
|
146
|
-
let bytes;
|
|
147
221
|
try {
|
|
148
222
|
url = assetUrl(name, base);
|
|
149
223
|
const cached = loaded.get(url.href);
|
|
150
224
|
if (cached) {
|
|
151
225
|
return cached;
|
|
152
226
|
}
|
|
227
|
+
}
|
|
228
|
+
catch (error) {
|
|
229
|
+
throw loadFailure(name, url, error instanceof Error ? error.message : String(error), error);
|
|
230
|
+
}
|
|
231
|
+
const bytes = readCheckedSync(name, base, hash);
|
|
232
|
+
loaded.set(url.href, bytes);
|
|
233
|
+
return bytes;
|
|
234
|
+
}
|
|
235
|
+
/** A file, read now and hashed before it's returned, and not kept: a part is compiled once. */
|
|
236
|
+
export function readCheckedSync(name, base, hash) {
|
|
237
|
+
let url = null;
|
|
238
|
+
let bytes;
|
|
239
|
+
try {
|
|
240
|
+
url = assetUrl(name, base);
|
|
153
241
|
if (!canReadSync()) {
|
|
154
242
|
throw new Error("this thread can only use assets fetched up front, and it was left out of preloadAssets");
|
|
155
243
|
}
|
|
@@ -158,12 +246,5 @@ export function loadAssetSync(name, base) {
|
|
|
158
246
|
catch (error) {
|
|
159
247
|
throw loadFailure(name, url, error instanceof Error ? error.message : String(error), error);
|
|
160
248
|
}
|
|
161
|
-
|
|
162
|
-
return bytes;
|
|
163
|
-
}
|
|
164
|
-
/** Entry `index` of fonts.bin: u32 count, u32 offsets[count + 1], bytes (little-endian). */
|
|
165
|
-
export function fontFromBundle(bundle, index) {
|
|
166
|
-
const view = new DataView(bundle.buffer, bundle.byteOffset, bundle.byteLength);
|
|
167
|
-
const base = 4 + (view.getUint32(0, true) + 1) * 4;
|
|
168
|
-
return bundle.subarray(base + view.getUint32(4 + index * 4, true), base + view.getUint32(8 + index * 4, true));
|
|
249
|
+
return checked(name, url, bytes, hash);
|
|
169
250
|
}
|
package/dist/document.d.ts
CHANGED
|
@@ -170,6 +170,29 @@ export type PdfRenderOptions = {
|
|
|
170
170
|
width: number;
|
|
171
171
|
/** Default 4096. May be Infinity, to fit the width alone. A render is capped at 16,384 px a side and 64 Mpx. */
|
|
172
172
|
maxHeight?: number;
|
|
173
|
+
/**
|
|
174
|
+
* Draws only this part of the page: x, y, width, height in points in the viewer frame, as text and
|
|
175
|
+
* annotation boxes are (top-left origin, `/Rotate` and the crop box applied). The bitmap holds the
|
|
176
|
+
* pixels of the whole page's bitmap at the scale `width` and `maxHeight` give that this covers,
|
|
177
|
+
* grown out to whole pixels and cut to the page, and says where they are. With a region the limits
|
|
178
|
+
* are on the region's bitmap, not the page's, and `width` may be up to 262,144.
|
|
179
|
+
*/
|
|
180
|
+
region?: PdfBox;
|
|
181
|
+
};
|
|
182
|
+
/** A render of a region: where its pixels are in the whole page's bitmap at that scale. */
|
|
183
|
+
export type PdfRegionBitmap = PdfBitmap & {
|
|
184
|
+
/** The bitmap's top-left pixel, in the whole page's bitmap. */
|
|
185
|
+
x: number;
|
|
186
|
+
y: number;
|
|
187
|
+
/** The whole page's bitmap's size at this scale: what `render` without a region and its limits would give. */
|
|
188
|
+
pageWidth: number;
|
|
189
|
+
pageHeight: number;
|
|
190
|
+
};
|
|
191
|
+
export type PdfRenderAsyncOptions = PdfRenderOptions & {
|
|
192
|
+
/** Stops the render at the next pause: `aborted`, with the document still usable. */
|
|
193
|
+
signal?: AbortSignal;
|
|
194
|
+
/** About how long it runs before giving the thread back. Default 8. */
|
|
195
|
+
sliceMs?: number;
|
|
173
196
|
};
|
|
174
197
|
export type PdfBitmap = {
|
|
175
198
|
width: number;
|
|
@@ -182,6 +205,67 @@ export type PdfBitmap = {
|
|
|
182
205
|
*/
|
|
183
206
|
truncated: boolean;
|
|
184
207
|
};
|
|
208
|
+
/** Where a link in this file goes: a page, and the place on it in that page's viewer frame. */
|
|
209
|
+
export type PdfDestination = {
|
|
210
|
+
/** The page's index, or -1 if it goes nowhere in this file. */
|
|
211
|
+
page: number;
|
|
212
|
+
/**
|
|
213
|
+
* How to show the page, as the file names it: "XYZ", "Fit", "FitH", "FitV", "FitR", "FitB", "FitBH",
|
|
214
|
+
* "FitBV"; null if it names none.
|
|
215
|
+
*/
|
|
216
|
+
view: string | null;
|
|
217
|
+
/**
|
|
218
|
+
* The point to bring to the window's top-left, in points in the target page's viewer frame
|
|
219
|
+
* (top-left origin, its `/Rotate` and crop box applied). null for a coordinate the destination leaves
|
|
220
|
+
* as it was; under a quarter turn, the page's `left` is the viewer's `y`.
|
|
221
|
+
*/
|
|
222
|
+
x: number | null;
|
|
223
|
+
y: number | null;
|
|
224
|
+
/** "XYZ"'s zoom, 1 for 100%; null to leave it as it was. */
|
|
225
|
+
zoom: number | null;
|
|
226
|
+
/** "FitR"'s rectangle, in the target page's viewer frame; null for any other view. */
|
|
227
|
+
box: PdfBox | null;
|
|
228
|
+
};
|
|
229
|
+
/** What a link does. Another file or a program is reported, never followed. */
|
|
230
|
+
export type PdfLinkTarget = {
|
|
231
|
+
kind: "uri";
|
|
232
|
+
uri: string;
|
|
233
|
+
}
|
|
234
|
+
/** A `GoTo` action or the link's `/Dest`, named destinations resolved. */
|
|
235
|
+
| {
|
|
236
|
+
kind: "page";
|
|
237
|
+
destination: PdfDestination;
|
|
238
|
+
}
|
|
239
|
+
/** `GoToR`: a destination in another file, by name or by page number there. */
|
|
240
|
+
| {
|
|
241
|
+
kind: "remote";
|
|
242
|
+
file: string;
|
|
243
|
+
name: string | null;
|
|
244
|
+
page: number | null;
|
|
245
|
+
}
|
|
246
|
+
/** `Launch`: a file or program. */
|
|
247
|
+
| {
|
|
248
|
+
kind: "launch";
|
|
249
|
+
file: string;
|
|
250
|
+
}
|
|
251
|
+
/** Any other action by its `/S` ("JavaScript", "SubmitForm", ...); a `Named` action's `/N` ("NextPage", ...) is `name`. */
|
|
252
|
+
| {
|
|
253
|
+
kind: "action";
|
|
254
|
+
action: string;
|
|
255
|
+
name: string | null;
|
|
256
|
+
}
|
|
257
|
+
/** No action and no destination. */
|
|
258
|
+
| {
|
|
259
|
+
kind: "none";
|
|
260
|
+
};
|
|
261
|
+
/** A `/Link` annotation and where it goes. */
|
|
262
|
+
export type PdfLink = {
|
|
263
|
+
/** Its index in what `annotations` returns for the page. */
|
|
264
|
+
annotation: number;
|
|
265
|
+
/** Its `/Rect` in the viewer frame, as its annotation's `box`. */
|
|
266
|
+
box: PdfBox;
|
|
267
|
+
target: PdfLinkTarget;
|
|
268
|
+
};
|
|
185
269
|
export declare const ANNOT_SUBTYPE: {
|
|
186
270
|
readonly text: 1;
|
|
187
271
|
readonly link: 2;
|
|
@@ -204,6 +288,18 @@ export interface PdfDocument {
|
|
|
204
288
|
readonly pageCount: number;
|
|
205
289
|
/** The document's bookmarks; empty if it has none. */
|
|
206
290
|
outline(): PdfOutlineItem[];
|
|
291
|
+
/** What each page is called, one string per page ("iv", "A-5"), or null if the file doesn't say. */
|
|
292
|
+
pageLabels(): string[] | null;
|
|
293
|
+
/**
|
|
294
|
+
* Which of the document's trees were cut short: `pages` means `pageCount` may be short, by a limit or
|
|
295
|
+
* because a damaged tree left no pages (an honestly empty document says false). `pageLabels` and `outline`
|
|
296
|
+
* mean those passed a limit, and may be wrong or incomplete. A page's own limits are `truncated` on its results.
|
|
297
|
+
*/
|
|
298
|
+
structureTruncated(): {
|
|
299
|
+
pages: boolean;
|
|
300
|
+
pageLabels: boolean;
|
|
301
|
+
outline: boolean;
|
|
302
|
+
};
|
|
207
303
|
pageInfo(index: number): PdfPageInfo;
|
|
208
304
|
text(index: number): PdfPageText;
|
|
209
305
|
/** `text`, `objects` and `annotations` from one interpretation of the page. */
|
|
@@ -219,17 +315,46 @@ export interface PdfDocument {
|
|
|
219
315
|
};
|
|
220
316
|
objects(index: number): PdfPageObjects;
|
|
221
317
|
annotations(index: number): PdfAnnotation[];
|
|
318
|
+
/**
|
|
319
|
+
* The page's links, in the order `annotations` lists them, and where each goes. Loads drawing's
|
|
320
|
+
* part of the wasm, as `objects` does.
|
|
321
|
+
*/
|
|
322
|
+
links(index: number): PdfLink[];
|
|
323
|
+
render(index: number, options: PdfRenderOptions & {
|
|
324
|
+
region: PdfBox;
|
|
325
|
+
}): PdfRegionBitmap;
|
|
222
326
|
render(index: number, options: PdfRenderOptions): PdfBitmap;
|
|
327
|
+
/**
|
|
328
|
+
* The same pixels as `render`, giving the thread back between slices, and stoppable with a
|
|
329
|
+
* signal. The last step, rasterizing, is one piece: about a third of a heavy page's time.
|
|
330
|
+
*/
|
|
331
|
+
renderAsync(index: number, options: PdfRenderAsyncOptions & {
|
|
332
|
+
region: PdfBox;
|
|
333
|
+
}): Promise<PdfRegionBitmap>;
|
|
334
|
+
renderAsync(index: number, options: PdfRenderAsyncOptions): Promise<PdfBitmap>;
|
|
223
335
|
close(): void;
|
|
224
336
|
[Symbol.dispose](): void;
|
|
225
337
|
}
|
|
226
338
|
export type Instance = {
|
|
227
339
|
glue: ReturnType<typeof createGlue>;
|
|
340
|
+
/** Loads a part of the wasm, hashed first, or throws `missing-asset` having changed nothing. */
|
|
341
|
+
loadPart(name: "recto-render.wasm" | "recto-more.wasm" | "recto-rare.wasm"): void;
|
|
228
342
|
memory: WebAssembly.Memory;
|
|
343
|
+
/** Its memory when it was made: past this, something used it, and dropping it gives memory back. */
|
|
344
|
+
startBytes: number;
|
|
229
345
|
generation: number;
|
|
230
346
|
openDocuments: number;
|
|
231
|
-
/**
|
|
347
|
+
/** The engine's count of documents open, on any of its instances. */
|
|
348
|
+
documents: {
|
|
349
|
+
open: number;
|
|
350
|
+
};
|
|
351
|
+
/** Set once the instance trapped; nothing may call it again. */
|
|
232
352
|
dead: boolean;
|
|
353
|
+
/**
|
|
354
|
+
* Set once a part or asset failed to load inside a call. Nothing more runs on it, but a document's
|
|
355
|
+
* file is still whole there, so it reopens on another instance at its next call.
|
|
356
|
+
*/
|
|
357
|
+
abandoned: boolean;
|
|
233
358
|
/** An asset's load failure, rethrown by the call that needed the asset. */
|
|
234
359
|
failure: PdfError | undefined;
|
|
235
360
|
/** Called when a document on this instance closes. */
|
|
@@ -240,12 +365,22 @@ export declare function engineFailure(instance: Instance, error: unknown): unkno
|
|
|
240
365
|
export declare class RectoDocument implements PdfDocument {
|
|
241
366
|
#private;
|
|
242
367
|
readonly pageCount: number;
|
|
243
|
-
constructor(instance: Instance, doc: Glue.Document,
|
|
368
|
+
constructor(instance: Instance, doc: Glue.Document, reopen: (doc: Glue.Document, instance: Instance) => {
|
|
369
|
+
instance: Instance;
|
|
370
|
+
doc: Glue.Document;
|
|
371
|
+
}, fetchFailure?: () => PdfError | null);
|
|
244
372
|
pageInfo(index: number): PdfPageInfo;
|
|
245
373
|
text(index: number): PdfPageText;
|
|
246
374
|
objects(index: number): PdfPageObjects;
|
|
375
|
+
pageLabels(): string[] | null;
|
|
376
|
+
structureTruncated(): {
|
|
377
|
+
pages: boolean;
|
|
378
|
+
pageLabels: boolean;
|
|
379
|
+
outline: boolean;
|
|
380
|
+
};
|
|
247
381
|
outline(): PdfOutlineItem[];
|
|
248
382
|
annotations(index: number): PdfAnnotation[];
|
|
383
|
+
links(index: number): PdfLink[];
|
|
249
384
|
scan(index: number): {
|
|
250
385
|
text: PdfPageText;
|
|
251
386
|
objects: PdfPageObjects;
|
|
@@ -255,7 +390,14 @@ export declare class RectoDocument implements PdfDocument {
|
|
|
255
390
|
text: PdfPageText;
|
|
256
391
|
annotations: PdfAnnotation[];
|
|
257
392
|
};
|
|
393
|
+
render(index: number, options: PdfRenderOptions & {
|
|
394
|
+
region: PdfBox;
|
|
395
|
+
}): PdfRegionBitmap;
|
|
258
396
|
render(index: number, options: PdfRenderOptions): PdfBitmap;
|
|
397
|
+
renderAsync(index: number, options: PdfRenderAsyncOptions & {
|
|
398
|
+
region: PdfBox;
|
|
399
|
+
}): Promise<PdfRegionBitmap>;
|
|
400
|
+
renderAsync(index: number, options: PdfRenderAsyncOptions): Promise<PdfBitmap>;
|
|
259
401
|
close(): void;
|
|
260
402
|
[Symbol.dispose](): void;
|
|
261
403
|
}
|