djvu-rs 0.28.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/djvu_rs.d.ts ADDED
@@ -0,0 +1,321 @@
1
+ /* tslint:disable */
2
+ /* eslint-disable */
3
+
4
+ /**
5
+ * A parsed DjVu document.
6
+ *
7
+ * Created from raw bytes via [`WasmDocument::from_bytes`].
8
+ */
9
+ export class WasmDocument {
10
+ private constructor();
11
+ free(): void;
12
+ [Symbol.dispose](): void;
13
+ /**
14
+ * Parse a DjVu document from a byte buffer.
15
+ *
16
+ * The buffer is moved into a shared backing store and bundled pages
17
+ * materialize lazily on first access (#609) — the same owned-bytes path
18
+ * as the native `Document::from_bytes` (LAZY_PAGE_CONSTRUCT), instead of
19
+ * the eager parser that copied every page at open time. The JS-visible
20
+ * signature is unchanged (pass a `Uint8Array`); the JS→wasm transfer is
21
+ * the single unavoidable copy.
22
+ *
23
+ * Throws a JavaScript `Error` if the bytes are not a valid DjVu file.
24
+ */
25
+ static from_bytes(data: Uint8Array): WasmDocument;
26
+ /**
27
+ * Return a handle to page `index` (0-based).
28
+ *
29
+ * Throws if `index >= page_count()`.
30
+ */
31
+ page(index: number): WasmPage;
32
+ /**
33
+ * Total number of pages in the document.
34
+ */
35
+ page_count(): number;
36
+ /**
37
+ * Render a contiguous batch of pages at `target_dpi`, returning one
38
+ * [`WasmPixmap`] per page in input order (#610).
39
+ *
40
+ * With the opt-in `wasm-threads` build (rayon Web-Worker pool via
41
+ * `initThreadPool`), pages render concurrently as coarse one-page tasks —
42
+ * the threading shape WASM_THREADS measured as viable (fine-grained
43
+ * compositor parallelism regressed ~9× and stays disabled). Without the
44
+ * pool the batch renders sequentially with identical results.
45
+ *
46
+ * Memory is bounded by the caller-chosen batch size: `count` full-size
47
+ * pixmaps are alive at once. Failed pages yield an error for the whole
48
+ * batch (all-or-nothing keeps the ordering contract simple).
49
+ */
50
+ render_pages_batch(target_dpi: number, start: number, count: number): WasmPixmap[];
51
+ }
52
+
53
+ /**
54
+ * A single page within a [`WasmDocument`].
55
+ */
56
+ export class WasmPage {
57
+ private constructor();
58
+ free(): void;
59
+ [Symbol.dispose](): void;
60
+ /**
61
+ * Number of BG44 background chunks on this page.
62
+ *
63
+ * Determines how many refinement steps are available via
64
+ * [`render_progressive`]. Returns `0` for bilevel-only pages.
65
+ */
66
+ bg44_chunk_count(): number;
67
+ /**
68
+ * Native DPI stored in the INFO chunk.
69
+ */
70
+ dpi(): number;
71
+ /**
72
+ * Output height in pixels when rendered at `target_dpi`.
73
+ */
74
+ height_at(target_dpi: number): number;
75
+ /**
76
+ * Render the page at `target_dpi` and return raw RGBA pixels
77
+ * (`Uint8ClampedArray`, suitable for `new ImageData(pixels, w, h)`).
78
+ *
79
+ * Throws on decode error.
80
+ */
81
+ render(target_dpi: number): Uint8ClampedArray;
82
+ /**
83
+ * Fast coarse render — decodes only the first BG44 chunk (~5 ms for a
84
+ * typical color page).
85
+ *
86
+ * Returns `undefined` for bilevel-only pages (no BG44 data); use
87
+ * [`render`] for those. For color pages the result is a blurry but
88
+ * instantly visible preview; call [`render_progressive`] or [`render`]
89
+ * on a Web Worker to produce the final image.
90
+ *
91
+ * Throws on decode error.
92
+ */
93
+ render_coarse(target_dpi: number): Uint8ClampedArray | undefined;
94
+ /**
95
+ * Render into a caller-owned [`WasmPixmap`], reusing its Rust-side
96
+ * allocation (#611). No JS-side allocation, no wasm→JS copy — consume
97
+ * the pixels via [`WasmPixmap::view`].
98
+ */
99
+ render_into_pixmap(target_dpi: number, out: WasmPixmap): void;
100
+ /**
101
+ * Progressive render — decodes BG44 chunks 0..=`chunk_n` plus all
102
+ * foreground layers (JB2 mask, text).
103
+ *
104
+ * `chunk_n = 0` is equivalent to [`render_coarse`] but also composites
105
+ * the mask. Each subsequent call with `chunk_n += 1` adds one more
106
+ * wavelet refinement pass. After the last chunk the result is identical
107
+ * to [`render`].
108
+ *
109
+ * Use [`bg44_chunk_count`] to find the maximum valid `chunk_n`
110
+ * (`bg44_chunk_count() - 1`).
111
+ *
112
+ * Throws on decode error or if `chunk_n` is out of range.
113
+ */
114
+ render_progressive(target_dpi: number, chunk_n: number): Uint8ClampedArray;
115
+ /**
116
+ * Progressive render into a caller-owned [`WasmPixmap`] (#611): the same
117
+ * refinement semantics as [`render_progressive`](Self::render_progressive),
118
+ * but an N-pass progressive session reuses one buffer instead of
119
+ * allocating and copying N full frames.
120
+ */
121
+ render_progressive_into_pixmap(target_dpi: number, chunk_n: number, out: WasmPixmap): void;
122
+ /**
123
+ * Render one full-quality tile, returning a [`WasmPixmap`] whose
124
+ * `width()`/`height()` give the (possibly clipped) tile dimensions.
125
+ *
126
+ * Byte-identical to the matching rectangle of [`render`](Self::render);
127
+ * assembled from the page's composited-tile cache (cache state never
128
+ * changes bytes, only latency).
129
+ *
130
+ * Throws on decode error or a grid violation.
131
+ */
132
+ render_tile(target_dpi: number, tile_size: number, col: number, row: number): WasmPixmap;
133
+ /**
134
+ * Render one full-quality tile into a caller-owned [`WasmPixmap`]
135
+ * (#611 pattern): a pan/zoom session reuses one Rust-side allocation
136
+ * per on-screen tile slot instead of allocating per frame.
137
+ */
138
+ render_tile_into_pixmap(target_dpi: number, tile_size: number, col: number, row: number, out: WasmPixmap): void;
139
+ /**
140
+ * Render one tile at progressive quality step `chunk_n` (BG44 chunks
141
+ * `0..=chunk_n` only), byte-identical to the tile's rectangle of
142
+ * [`render_progressive`](Self::render_progressive) with the same
143
+ * `chunk_n`. Partial-quality tiles are never cached.
144
+ *
145
+ * On bilevel pages (no BG44 data) `chunk_n = 0` is the full render.
146
+ * Throws on decode error, a grid violation, or `chunk_n` out of range.
147
+ */
148
+ render_tile_progressive(target_dpi: number, tile_size: number, col: number, row: number, chunk_n: number): WasmPixmap;
149
+ /**
150
+ * Extract the plain text content of this page from the TXTz/TXTa layer.
151
+ *
152
+ * Returns `undefined` (JS `None`) if the page has no text layer.
153
+ * Throws a JavaScript `Error` on decode failure.
154
+ */
155
+ text(): string | undefined;
156
+ /**
157
+ * Return text zone data for this page, scaled to match a render at `target_dpi`.
158
+ *
159
+ * Returns a JSON string — array of `{"t":"…","x":N,"y":N,"w":N,"h":N}` objects,
160
+ * one per leaf text zone, with pixel coordinates identical to the canvas produced
161
+ * by `render(target_dpi)`. Leaf zones are the finest granularity stored in the
162
+ * text layer (word-level for richly OCR'd files, line-level otherwise).
163
+ *
164
+ * Returns `null` if the page has no text layer.
165
+ * Throws a JavaScript `Error` on decode failure.
166
+ */
167
+ text_zones_json(target_dpi: number): string | undefined;
168
+ /**
169
+ * Number of tile columns at `target_dpi` for `tile_size`-pixel tiles.
170
+ *
171
+ * Tiles live in display space: tile `(col, row)` starts at canvas pixel
172
+ * `(col * tile_size, row * tile_size)`; edge tiles are clipped, never
173
+ * padded, so blitting every tile covers the canvas exactly once.
174
+ */
175
+ tile_cols(target_dpi: number, tile_size: number): number;
176
+ /**
177
+ * Number of tile rows at `target_dpi` for `tile_size`-pixel tiles.
178
+ */
179
+ tile_rows(target_dpi: number, tile_size: number): number;
180
+ /**
181
+ * Output width in pixels when rendered at `target_dpi`.
182
+ */
183
+ width_at(target_dpi: number): number;
184
+ }
185
+
186
+ /**
187
+ * A Rust-owned RGBA pixel buffer that stays alive as long as JS holds the
188
+ * handle, so pixels can be consumed **without** the per-frame
189
+ * `Uint8ClampedArray` allocation + full-buffer copy the plain `render*`
190
+ * methods pay.
191
+ *
192
+ * Two usage modes:
193
+ * - **Zero-copy view**: [`view`](WasmPixmap::view) returns a typed-array view
194
+ * directly into wasm linear memory. Consume it immediately (e.g.
195
+ * `ctx.putImageData(new ImageData(pm.view(), pm.width(), pm.height()), 0, 0)`
196
+ * — `ImageData` copies). The view is invalidated by wasm memory growth and
197
+ * by dropping/re-rendering the pixmap; never store it.
198
+ * - **Buffer reuse**: pass the same `WasmPixmap` back to
199
+ * [`render_into_pixmap`](WasmPage::render_into_pixmap) /
200
+ * [`render_progressive_into_pixmap`](WasmPage::render_progressive_into_pixmap)
201
+ * — the Rust-side allocation is reused across frames (a progressive
202
+ * session allocates once instead of once per refinement pass).
203
+ *
204
+ * The existing copying `render*` methods are unchanged for callers that need
205
+ * independently owned JS bytes.
206
+ */
207
+ export class WasmPixmap {
208
+ free(): void;
209
+ [Symbol.dispose](): void;
210
+ /**
211
+ * RGBA byte length (`width * height * 4`).
212
+ */
213
+ byte_length(): number;
214
+ /**
215
+ * Pixel height of the last render written into this pixmap.
216
+ */
217
+ height(): number;
218
+ /**
219
+ * An empty pixmap for use with the `*_into_pixmap` methods.
220
+ */
221
+ constructor();
222
+ /**
223
+ * Copy the pixels into a fresh, independently owned
224
+ * `Uint8ClampedArray` (same guarantee as the plain `render` API).
225
+ */
226
+ to_bytes(): Uint8ClampedArray;
227
+ /**
228
+ * Zero-copy `Uint8ClampedArray` view into wasm memory.
229
+ *
230
+ * Valid only until the next wasm memory growth, the next render into
231
+ * this pixmap, or the pixmap being freed — consume it immediately and
232
+ * never store it. `new ImageData(view, w, h)` copies, so canvas
233
+ * consumption is safe.
234
+ */
235
+ view(): Uint8ClampedArray;
236
+ /**
237
+ * Pixel width of the last render written into this pixmap.
238
+ */
239
+ width(): number;
240
+ }
241
+
242
+ export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
243
+
244
+ export interface InitOutput {
245
+ readonly memory: WebAssembly.Memory;
246
+ readonly __wbg_wasmdocument_free: (a: number, b: number) => void;
247
+ readonly __wbg_wasmpage_free: (a: number, b: number) => void;
248
+ readonly __wbg_wasmpixmap_free: (a: number, b: number) => void;
249
+ readonly djvu_doc_free: (a: number) => void;
250
+ readonly djvu_doc_open: (a: number, b: number, c: number) => number;
251
+ readonly djvu_doc_page_count: (a: number) => number;
252
+ readonly djvu_error_free: (a: number) => void;
253
+ readonly djvu_page_dpi: (a: number, b: number, c: number) => number;
254
+ readonly djvu_page_height: (a: number, b: number, c: number) => number;
255
+ readonly djvu_page_render: (a: number, b: number, c: number, d: number) => number;
256
+ readonly djvu_page_text: (a: number, b: number, c: number) => number;
257
+ readonly djvu_page_width: (a: number, b: number, c: number) => number;
258
+ readonly djvu_pixmap_data: (a: number) => number;
259
+ readonly djvu_pixmap_data_len: (a: number) => number;
260
+ readonly djvu_pixmap_free: (a: number) => void;
261
+ readonly djvu_pixmap_height: (a: number) => number;
262
+ readonly djvu_pixmap_width: (a: number) => number;
263
+ readonly djvu_text_free: (a: number) => void;
264
+ readonly wasmdocument_from_bytes: (a: number, b: number) => [number, number, number];
265
+ readonly wasmdocument_page: (a: number, b: number) => [number, number, number];
266
+ readonly wasmdocument_page_count: (a: number) => number;
267
+ readonly wasmdocument_render_pages_batch: (a: number, b: number, c: number, d: number) => [number, number, number, number];
268
+ readonly wasmpage_bg44_chunk_count: (a: number) => number;
269
+ readonly wasmpage_dpi: (a: number) => number;
270
+ readonly wasmpage_height_at: (a: number, b: number) => number;
271
+ readonly wasmpage_render: (a: number, b: number) => [number, number, number];
272
+ readonly wasmpage_render_coarse: (a: number, b: number) => [number, number, number];
273
+ readonly wasmpage_render_into_pixmap: (a: number, b: number, c: number) => [number, number];
274
+ readonly wasmpage_render_progressive: (a: number, b: number, c: number) => [number, number, number];
275
+ readonly wasmpage_render_progressive_into_pixmap: (a: number, b: number, c: number, d: number) => [number, number];
276
+ readonly wasmpage_render_tile: (a: number, b: number, c: number, d: number, e: number) => [number, number, number];
277
+ readonly wasmpage_render_tile_into_pixmap: (a: number, b: number, c: number, d: number, e: number, f: number) => [number, number];
278
+ readonly wasmpage_render_tile_progressive: (a: number, b: number, c: number, d: number, e: number, f: number) => [number, number, number];
279
+ readonly wasmpage_text: (a: number) => [number, number, number, number];
280
+ readonly wasmpage_text_zones_json: (a: number, b: number) => [number, number, number, number];
281
+ readonly wasmpage_tile_cols: (a: number, b: number, c: number) => [number, number, number];
282
+ readonly wasmpage_tile_rows: (a: number, b: number, c: number) => [number, number, number];
283
+ readonly wasmpage_width_at: (a: number, b: number) => number;
284
+ readonly wasmpixmap_byte_length: (a: number) => number;
285
+ readonly wasmpixmap_height: (a: number) => number;
286
+ readonly wasmpixmap_new: () => number;
287
+ readonly wasmpixmap_to_bytes: (a: number) => any;
288
+ readonly wasmpixmap_view: (a: number) => any;
289
+ readonly wasmpixmap_width: (a: number) => number;
290
+ readonly __wbindgen_externrefs: WebAssembly.Table;
291
+ readonly __wbindgen_malloc: (a: number, b: number) => number;
292
+ readonly __externref_table_dealloc: (a: number) => void;
293
+ readonly __externref_drop_slice: (a: number, b: number) => void;
294
+ readonly __wbindgen_free: (a: number, b: number, c: number) => void;
295
+ readonly __wbindgen_start: () => void;
296
+ }
297
+
298
+ export type SyncInitInput = BufferSource | WebAssembly.Module;
299
+
300
+ /**
301
+ * Instantiates the given `module`, which can either be bytes or
302
+ * a precompiled `WebAssembly.Module`.
303
+ *
304
+ * @param {{ module: SyncInitInput }} module - Passing `SyncInitInput` directly is deprecated.
305
+ *
306
+ * @returns {InitOutput}
307
+ */
308
+ export function initSync(module: { module: SyncInitInput } | SyncInitInput): InitOutput;
309
+
310
+ /**
311
+ * If `module_or_path` is {RequestInfo} or {URL}, makes a request and
312
+ * for everything else, calls `WebAssembly.instantiate` directly.
313
+ *
314
+ * @param {{ module_or_path: InitInput | Promise<InitInput> }} module_or_path - Passing `InitInput` directly is deprecated.
315
+ *
316
+ * @returns {Promise<InitOutput>}
317
+ */
318
+ export default function __wbg_init (module_or_path?: { module_or_path: InitInput | Promise<InitInput> } | InitInput | Promise<InitInput>): Promise<InitOutput>;
319
+
320
+ export function wasmSimd128Supported(): boolean;
321
+ export function selectedWasmVariant(): "scalar" | "simd128" | undefined;
package/djvu_rs.js ADDED
@@ -0,0 +1,56 @@
1
+ import * as scalarModule from "./scalar/djvu_rs.js";
2
+ import * as simd128Module from "./simd128/djvu_rs.js";
3
+
4
+ const SIMD128_PROBE = new Uint8Array([
5
+ 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00,
6
+ 0x01, 0x05, 0x01, 0x60, 0x00, 0x01, 0x7b,
7
+ 0x03, 0x02, 0x01, 0x00,
8
+ 0x0a, 0x16, 0x01, 0x14, 0x00, 0xfd, 0x0c,
9
+ 0x00, 0x00, 0x00, 0x00,
10
+ 0x00, 0x00, 0x00, 0x00,
11
+ 0x00, 0x00, 0x00, 0x00,
12
+ 0x00, 0x00, 0x00, 0x00,
13
+ 0x0b,
14
+ ]);
15
+
16
+ let selectedModule;
17
+ let selectedVariant;
18
+
19
+ export let WasmDocument;
20
+ export let WasmPage;
21
+ export let WasmPixmap;
22
+ export let WasmLazyDocument;
23
+ export let initThreadPool;
24
+
25
+ export function wasmSimd128Supported() {
26
+ return typeof WebAssembly === "object" && WebAssembly.validate(SIMD128_PROBE);
27
+ }
28
+
29
+ export function selectedWasmVariant() {
30
+ return selectedVariant;
31
+ }
32
+
33
+ export default async function init(input) {
34
+ if (selectedModule !== undefined) {
35
+ return selectedModule;
36
+ }
37
+
38
+ const useSimd128 = wasmSimd128Supported();
39
+ selectedVariant = useSimd128 ? "simd128" : "scalar";
40
+ selectedModule = useSimd128 ? simd128Module : scalarModule;
41
+
42
+ const wasmInput = input ?? new URL(`./${selectedVariant}/djvu_rs_bg.wasm`, import.meta.url);
43
+ await selectedModule.default({ module_or_path: wasmInput });
44
+
45
+ WasmDocument = selectedModule.WasmDocument;
46
+ WasmPage = selectedModule.WasmPage;
47
+ WasmPixmap = selectedModule.WasmPixmap;
48
+ WasmLazyDocument = selectedModule.WasmLazyDocument;
49
+ initThreadPool = selectedModule.initThreadPool;
50
+
51
+ return selectedModule;
52
+ }
53
+
54
+ export function initSync() {
55
+ throw new Error("The dual wasm loader requires async init() for runtime variant selection.");
56
+ }
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "djvu-rs",
3
+ "type": "module",
4
+ "description": "Read, render, convert, and create DjVu files. Pure-Rust DjVu decoder/encoder with CLI, WebAssembly, and Python bindings. DjVu to PDF, EPUB, TIFF, PNG, and text. MIT licensed, no GPL dependencies.",
5
+ "version": "0.28.0",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/matyushkin/djvu-rs"
10
+ },
11
+ "files": [
12
+ "djvu_rs.js",
13
+ "djvu_rs.d.ts",
14
+ "README.md",
15
+ "LICENSE",
16
+ "scalar/djvu_rs.js",
17
+ "scalar/djvu_rs.d.ts",
18
+ "scalar/djvu_rs_bg.wasm",
19
+ "scalar/djvu_rs_bg.wasm.d.ts",
20
+ "simd128/djvu_rs.js",
21
+ "simd128/djvu_rs.d.ts",
22
+ "simd128/djvu_rs_bg.wasm",
23
+ "simd128/djvu_rs_bg.wasm.d.ts"
24
+ ],
25
+ "main": "djvu_rs.js",
26
+ "types": "djvu_rs.d.ts",
27
+ "sideEffects": false,
28
+ "keywords": [
29
+ "djvu",
30
+ "decoder",
31
+ "encoder",
32
+ "pdf",
33
+ "converter"
34
+ ],
35
+ "module": "djvu_rs.js",
36
+ "exports": {
37
+ ".": {
38
+ "types": "./djvu_rs.d.ts",
39
+ "import": "./djvu_rs.js",
40
+ "default": "./djvu_rs.js"
41
+ }
42
+ }
43
+ }
44
+
package/scalar/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Lev Matyushkin
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.