react-pdf-viewer-wasm 0.1.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.
@@ -0,0 +1,31 @@
1
+ import { ReactNode } from 'react';
2
+ interface DocContextValue {
3
+ docHandle: number;
4
+ scale: number;
5
+ rotate: number;
6
+ }
7
+ export declare function useDocContext(): DocContextValue;
8
+ type FileInput = string | File | Uint8Array;
9
+ interface DocumentProps {
10
+ file: FileInput;
11
+ className?: string | string[];
12
+ scale?: number;
13
+ rotate?: number;
14
+ error?: ReactNode | (() => ReactNode);
15
+ loading?: ReactNode | (() => ReactNode);
16
+ noData?: ReactNode | (() => ReactNode);
17
+ children?: ReactNode;
18
+ onLoadSuccess?: (info: {
19
+ numPages: number;
20
+ }) => void;
21
+ onLoadError?: (error: Error) => void;
22
+ onLoadProgress?: (info: {
23
+ loaded: number;
24
+ total: number;
25
+ }) => void;
26
+ onSourceSuccess?: () => void;
27
+ onSourceError?: (error: Error) => void;
28
+ onPassword?: (callback: (password: string) => void) => void;
29
+ }
30
+ export declare const Document: import('react').ForwardRefExoticComponent<DocumentProps & import('react').RefAttributes<HTMLDivElement>>;
31
+ export {};
@@ -0,0 +1,8 @@
1
+ interface PageProps {
2
+ pageIndex: number;
3
+ scale?: number;
4
+ rotate?: number;
5
+ textSelectable?: boolean;
6
+ }
7
+ export declare function Page({ pageIndex, scale, rotate, textSelectable }: PageProps): import("react").JSX.Element;
8
+ export {};
@@ -0,0 +1,9 @@
1
+ interface TextLayerProps {
2
+ docHandle: number;
3
+ pageIndex: number;
4
+ scale: number;
5
+ pageWidthPts: number;
6
+ pageHeightPts: number;
7
+ }
8
+ export declare function TextLayer({ docHandle, pageIndex, scale, pageWidthPts, pageHeightPts }: TextLayerProps): import("react").JSX.Element;
9
+ export {};
@@ -0,0 +1,3 @@
1
+ export { Document } from './components/Document';
2
+ export { Page } from './components/Page';
3
+ export { setPdfiumSource } from './pdf-core/loadPdfEngine';
package/dist/index.mjs ADDED
@@ -0,0 +1,662 @@
1
+ import { createContext as e, forwardRef as t, useContext as n, useEffect as r, useImperativeHandle as i, useRef as a, useState as o } from "react";
2
+ import { jsx as s, jsxs as c } from "react/jsx-runtime";
3
+ //#region \0rolldown/runtime.js
4
+ var l = Object.defineProperty, u = /* @__PURE__ */ ((e, t) => {
5
+ let n = {};
6
+ for (var r in e) l(n, r, {
7
+ get: e[r],
8
+ enumerable: !0
9
+ });
10
+ return t || l(n, Symbol.toStringTag, { value: "Module" }), n;
11
+ })({
12
+ close_document: () => d,
13
+ default: () => J,
14
+ extract_text: () => f,
15
+ get_page_count: () => p,
16
+ get_page_dimensions: () => m,
17
+ get_text_chars: () => h,
18
+ initSync: () => re,
19
+ initialize: () => g,
20
+ initialize_pdfium_render: () => _,
21
+ open_document: () => v,
22
+ read_block_from_callback_wasm: () => y,
23
+ render_page: () => b,
24
+ start: () => x,
25
+ write_block_from_callback_wasm: () => S
26
+ });
27
+ function d(e) {
28
+ let t = G.close_document(e);
29
+ if (t[1]) throw R(t[0]);
30
+ }
31
+ function f(e, t) {
32
+ let n = G.extract_text(e, t);
33
+ if (n[3]) throw R(n[2]);
34
+ var r = D(n[0], n[1]);
35
+ return n[0] !== 0 && G.__wbindgen_free(n[0], n[1], 1), r;
36
+ }
37
+ function p(e) {
38
+ let t = G.get_page_count(e);
39
+ if (t[2]) throw R(t[1]);
40
+ return t[0] >>> 0;
41
+ }
42
+ function m(e, t) {
43
+ let n = G.get_page_dimensions(e, t);
44
+ if (n[3]) throw R(n[2]);
45
+ var r = ee(n[0], n[1]).slice();
46
+ return G.__wbindgen_free(n[0], n[1] * 4, 4), r;
47
+ }
48
+ function h(e, t) {
49
+ let n = G.get_text_chars(e, t);
50
+ if (n[3]) throw R(n[2]);
51
+ var r = D(n[0], n[1]);
52
+ return n[0] !== 0 && G.__wbindgen_free(n[0], n[1], 1), r;
53
+ }
54
+ function g() {
55
+ let e = G.initialize();
56
+ if (e[1]) throw R(e[0]);
57
+ }
58
+ function _(e, t, n) {
59
+ return G.initialize_pdfium_render(e, t, n) !== 0;
60
+ }
61
+ function v(e, t) {
62
+ let n = I(e, G.__wbindgen_malloc), r = W;
63
+ var i = F(t) ? 0 : L(t, G.__wbindgen_malloc, G.__wbindgen_realloc), a = W;
64
+ let o = G.open_document(n, r, i, a);
65
+ if (o[2]) throw R(o[1]);
66
+ return o[0] >>> 0;
67
+ }
68
+ function y(e, t, n, r) {
69
+ return G.read_block_from_callback_wasm(e, t, n, r);
70
+ }
71
+ function b(e, t, n, r) {
72
+ let i = G.render_page(e, t, n, r);
73
+ if (i[2]) throw R(i[1]);
74
+ return R(i[0]);
75
+ }
76
+ function x() {
77
+ G.start();
78
+ }
79
+ function S(e, t, n) {
80
+ return G.write_block_from_callback_wasm(e, t, n);
81
+ }
82
+ function C() {
83
+ return {
84
+ __proto__: null,
85
+ "./pdf_core_bg.js": {
86
+ __proto__: null,
87
+ __wbg___wbindgen_debug_string_0e68cf47c9cbd9b0: function(e, t) {
88
+ let n = L(T(t), G.__wbindgen_malloc, G.__wbindgen_realloc), r = W;
89
+ k().setInt32(e + 4, r, !0), k().setInt32(e + 0, n, !0);
90
+ },
91
+ __wbg___wbindgen_is_object_edb6b15aa3afe12e: function(e) {
92
+ let t = e;
93
+ return typeof t == "object" && !!t;
94
+ },
95
+ __wbg___wbindgen_is_undefined_8c687d0b90d5b524: function(e) {
96
+ return e === void 0;
97
+ },
98
+ __wbg___wbindgen_jsval_eq_9fdcd3c0a860dd3b: function(e, t) {
99
+ return e === t;
100
+ },
101
+ __wbg___wbindgen_number_get_1dc732b810cb937c: function(e, t) {
102
+ let n = t, r = typeof n == "number" ? n : void 0;
103
+ k().setFloat64(e + 8, F(r) ? 0 : r, !0), k().setInt32(e + 0, !F(r), !0);
104
+ },
105
+ __wbg___wbindgen_string_get_92ab86bb19cbc12f: function(e, t) {
106
+ let n = t, r = typeof n == "string" ? n : void 0;
107
+ var i = F(r) ? 0 : L(r, G.__wbindgen_malloc, G.__wbindgen_realloc), a = W;
108
+ k().setInt32(e + 4, a, !0), k().setInt32(e + 0, i, !0);
109
+ },
110
+ __wbg___wbindgen_throw_5d9e815e6fdf150f: function(e, t) {
111
+ var n = D(e, t);
112
+ throw Error(n);
113
+ },
114
+ __wbg_apply_5d9aa7604c2490a8: function() {
115
+ return P(function(e, t, n) {
116
+ return e.apply(t, n);
117
+ }, arguments);
118
+ },
119
+ __wbg_call_6bcf8d3e20937e46: function() {
120
+ return P(function(e, t, n) {
121
+ return e.call(t, n);
122
+ }, arguments);
123
+ },
124
+ __wbg_debug_eb092a10b3338acb: function(e) {
125
+ console.debug(e);
126
+ },
127
+ __wbg_decode_ec8279b49e2f79cf: function() {
128
+ return P(function(e, t, n, r) {
129
+ let i = L(t.decode(E(n, r)), G.__wbindgen_malloc, G.__wbindgen_realloc), a = W;
130
+ k().setInt32(e + 4, a, !0), k().setInt32(e + 0, i, !0);
131
+ }, arguments);
132
+ },
133
+ __wbg_error_756c5934221e6fee: function(e) {
134
+ console.error(e);
135
+ },
136
+ __wbg_error_757e9472f8410341: function(e, t) {
137
+ var n = D(e, t);
138
+ e !== 0 && G.__wbindgen_free(e, t, 1), console.error(n);
139
+ },
140
+ __wbg_from_a39669ce566077da: function(e) {
141
+ return Array.from(e);
142
+ },
143
+ __wbg_getTime_65922ba0b59d55a7: function(e) {
144
+ return e.getTime();
145
+ },
146
+ __wbg_get_97dc2df9d87d0f6a: function() {
147
+ return P(function(e, t) {
148
+ return e.get(t >>> 0);
149
+ }, arguments);
150
+ },
151
+ __wbg_get_989d0a1309644f2b: function() {
152
+ return P(function(e, t) {
153
+ return Reflect.get(e, t);
154
+ }, arguments);
155
+ },
156
+ __wbg_get_index_a916f0ff97f6772a: function(e, t) {
157
+ return e[t >>> 0];
158
+ },
159
+ __wbg_get_unchecked_363572bdd397d473: function(e, t) {
160
+ return e[t >>> 0];
161
+ },
162
+ __wbg_info_f25c01bee103395d: function(e) {
163
+ console.info(e);
164
+ },
165
+ __wbg_isArray_5674713bb7b79043: function(e) {
166
+ return Array.isArray(e);
167
+ },
168
+ __wbg_length_31bdaf014f5fbde2: function(e) {
169
+ return e.length;
170
+ },
171
+ __wbg_length_4e1adc0d42e23620: function(e) {
172
+ return e.length;
173
+ },
174
+ __wbg_length_e1c40798f58a4170: function(e) {
175
+ return e.length;
176
+ },
177
+ __wbg_length_e87c15f832faddc2: function(e) {
178
+ return e.length;
179
+ },
180
+ __wbg_log_363d83b9114c8831: function(e) {
181
+ console.log(e);
182
+ },
183
+ __wbg_new_0_35540e542ba689d2: function() {
184
+ return /* @__PURE__ */ new Date();
185
+ },
186
+ __wbg_new_227d7c05414eb861: function() {
187
+ return /* @__PURE__ */ Error();
188
+ },
189
+ __wbg_new_ffa92086ea89f79c: function() {
190
+ return [];
191
+ },
192
+ __wbg_new_from_slice_4ee02165f9de919e: function(e, t) {
193
+ return new Uint8Array(E(e, t));
194
+ },
195
+ __wbg_new_with_label_aad02dde1eb03f9b: function() {
196
+ return P(function(e, t) {
197
+ var n = D(e, t);
198
+ return new TextDecoder(n);
199
+ }, arguments);
200
+ },
201
+ __wbg_new_with_length_6a9fc3631737ef8c: function(e) {
202
+ return Array(e >>> 0);
203
+ },
204
+ __wbg_of_04ed67a73000e0bd: function(e, t, n, r) {
205
+ return [
206
+ e,
207
+ t,
208
+ n,
209
+ r
210
+ ];
211
+ },
212
+ __wbg_of_1a3f47170341cefe: function(e) {
213
+ return [e];
214
+ },
215
+ __wbg_of_1c173c2ad96e2f7e: function(e, t) {
216
+ return [e, t];
217
+ },
218
+ __wbg_of_8211d46fcab1ec90: function(e, t, n, r, i) {
219
+ return [
220
+ e,
221
+ t,
222
+ n,
223
+ r,
224
+ i
225
+ ];
226
+ },
227
+ __wbg_of_d9a05aa72bb023a2: function(e, t, n) {
228
+ return [
229
+ e,
230
+ t,
231
+ n
232
+ ];
233
+ },
234
+ __wbg_prototypesetcall_ae9f5e7459250748: function(e, t, n) {
235
+ Uint8Array.prototype.set.call(E(e, t), n);
236
+ },
237
+ __wbg_push_bfdf956ba476f65b: function(e, t) {
238
+ return e.push(t);
239
+ },
240
+ __wbg_set_13d25b81ab403f5e: function(e, t, n) {
241
+ e[t >>> 0] = n;
242
+ },
243
+ __wbg_set_361ed22a3b8802e9: function() {
244
+ return P(function(e, t, n) {
245
+ e.set(t >>> 0, n);
246
+ }, arguments);
247
+ },
248
+ __wbg_set_9cfc0f17d60ff0af: function(e, t, n) {
249
+ e.set(t, n >>> 0);
250
+ },
251
+ __wbg_slice_ec88db741786524b: function(e, t, n) {
252
+ return e.slice(t >>> 0, n >>> 0);
253
+ },
254
+ __wbg_stack_3b0d974bbf31e44f: function(e, t) {
255
+ let n = t.stack, r = L(n, G.__wbindgen_malloc, G.__wbindgen_realloc), i = W;
256
+ k().setInt32(e + 4, i, !0), k().setInt32(e + 0, r, !0);
257
+ },
258
+ __wbg_static_accessor_GLOBAL_8eb4cd83130a11a0: function() {
259
+ let e = typeof global > "u" ? null : global;
260
+ return F(e) ? 0 : w(e);
261
+ },
262
+ __wbg_static_accessor_GLOBAL_THIS_1e7044f654e934db: function() {
263
+ let e = typeof globalThis > "u" ? null : globalThis;
264
+ return F(e) ? 0 : w(e);
265
+ },
266
+ __wbg_static_accessor_SELF_d8b50611246a6d92: function() {
267
+ let e = typeof self > "u" ? null : self;
268
+ return F(e) ? 0 : w(e);
269
+ },
270
+ __wbg_static_accessor_WINDOW_fd0bc376bf0f8b42: function() {
271
+ let e = typeof window > "u" ? null : window;
272
+ return F(e) ? 0 : w(e);
273
+ },
274
+ __wbg_subarray_1daff70dde20c145: function(e, t, n) {
275
+ return e.subarray(t >>> 0, n >>> 0);
276
+ },
277
+ __wbg_warn_d3544c7814fab534: function(e) {
278
+ console.warn(e);
279
+ },
280
+ __wbindgen_generic_0000000000000001: function(e) {
281
+ return e;
282
+ },
283
+ __wbindgen_generic_0000000000000002: function(e, t) {
284
+ return D(e, t);
285
+ },
286
+ __wbindgen_generic_0000000000000003: function(e, t) {
287
+ return E(e, t);
288
+ },
289
+ __wbindgen_init_externref_table: function() {
290
+ let e = G.__wbindgen_externrefs, t = e.grow(4);
291
+ e.set(0, void 0), e.set(t + 0, void 0), e.set(t + 1, null), e.set(t + 2, !0), e.set(t + 3, !1);
292
+ }
293
+ }
294
+ };
295
+ }
296
+ function w(e) {
297
+ let t = G.__externref_table_alloc();
298
+ return G.__wbindgen_externrefs.set(t, e), t;
299
+ }
300
+ function T(e) {
301
+ let t = typeof e;
302
+ if (t == "number" || t == "boolean" || e == null) return `${e}`;
303
+ if (t == "string") return `"${e}"`;
304
+ if (t == "symbol") {
305
+ let t = e.description;
306
+ return t == null ? "Symbol" : `Symbol(${t})`;
307
+ }
308
+ if (t == "function") {
309
+ let t = e.name;
310
+ return typeof t == "string" && t.length > 0 ? `Function(${t})` : "Function";
311
+ }
312
+ if (Array.isArray(e)) {
313
+ let t = e.length, n = "[";
314
+ t > 0 && (n += T(e[0]));
315
+ for (let r = 1; r < t; r++) n += ", " + T(e[r]);
316
+ return n += "]", n;
317
+ }
318
+ let n = /\[object ([^\]]+)\]/.exec(toString.call(e)), r;
319
+ if (n && n.length > 1) r = n[1];
320
+ else return toString.call(e);
321
+ if (r == "Object") try {
322
+ return "Object(" + JSON.stringify(e) + ")";
323
+ } catch {
324
+ return "Object";
325
+ }
326
+ return e instanceof Error ? `${e.name}: ${e.message}\n${e.stack}` : r;
327
+ }
328
+ function ee(e, t) {
329
+ return e >>>= 0, j().subarray(e / 4, e / 4 + t);
330
+ }
331
+ function E(e, t) {
332
+ return e >>>= 0, N().subarray(e / 1, e / 1 + t);
333
+ }
334
+ function D(e, t) {
335
+ return e === 0 ? te(t) : ne(e, t);
336
+ }
337
+ var O = null;
338
+ function k() {
339
+ return (O === null || O.buffer.detached === !0 || O.buffer.detached === void 0 && O.buffer !== G.memory.buffer) && (O = new DataView(G.memory.buffer)), O;
340
+ }
341
+ var A = null;
342
+ function j() {
343
+ return (A === null || A.byteLength === 0) && (A = new Float32Array(G.memory.buffer)), A;
344
+ }
345
+ function te(e) {
346
+ return G.__wbindgen_externrefs.get(e);
347
+ }
348
+ function ne(e, t) {
349
+ return H(e >>> 0, t);
350
+ }
351
+ var M = null;
352
+ function N() {
353
+ return (M === null || M.byteLength === 0) && (M = new Uint8Array(G.memory.buffer)), M;
354
+ }
355
+ function P(e, t) {
356
+ try {
357
+ return e.apply(this, t);
358
+ } catch (e) {
359
+ let t = w(e);
360
+ G.__wbindgen_exn_store(t);
361
+ }
362
+ }
363
+ function F(e) {
364
+ return e == null;
365
+ }
366
+ function I(e, t) {
367
+ let n = t(e.length * 1, 1) >>> 0;
368
+ return N().set(e, n / 1), W = e.length, n;
369
+ }
370
+ function L(e, t, n) {
371
+ if (n === void 0) {
372
+ let n = U.encode(e), r = t(n.length, 1) >>> 0;
373
+ return N().subarray(r, r + n.length).set(n), W = n.length, r;
374
+ }
375
+ let r = e.length, i = t(r, 1) >>> 0, a = N(), o = 0;
376
+ for (; o < r; o++) {
377
+ let t = e.charCodeAt(o);
378
+ if (t > 127) break;
379
+ a[i + o] = t;
380
+ }
381
+ if (o !== r) {
382
+ o !== 0 && (e = e.slice(o)), i = n(i, r, r = o + e.length * 3, 1) >>> 0;
383
+ let t = N().subarray(i + o, i + r), a = U.encodeInto(e, t);
384
+ o += a.written, i = n(i, r, o, 1) >>> 0;
385
+ }
386
+ return W = o, i;
387
+ }
388
+ function R(e) {
389
+ let t = G.__wbindgen_externrefs.get(e);
390
+ return G.__externref_table_dealloc(e), t;
391
+ }
392
+ var z = new TextDecoder("utf-8", {
393
+ ignoreBOM: !0,
394
+ fatal: !0
395
+ });
396
+ z.decode();
397
+ var B = 2146435072, V = 0;
398
+ function H(e, t) {
399
+ return V += t, V >= B && (z = new TextDecoder("utf-8", {
400
+ ignoreBOM: !0,
401
+ fatal: !0
402
+ }), z.decode(), V = t), z.decode(N().subarray(e, e + t));
403
+ }
404
+ var U = new TextEncoder();
405
+ "encodeInto" in U || (U.encodeInto = function(e, t) {
406
+ let n = U.encode(e);
407
+ return t.set(n), {
408
+ read: e.length,
409
+ written: n.length
410
+ };
411
+ });
412
+ var W = 0, G;
413
+ function K(e, t) {
414
+ return G = e.exports, O = null, A = null, M = null, G.__wbindgen_start(), G;
415
+ }
416
+ async function q(e, t) {
417
+ if (typeof Response == "function" && e instanceof Response) {
418
+ if (!e.ok) throw Error(`failed to fetch Wasm: ${e.status} ${e.statusText} fetching '${e.url}'`);
419
+ if (typeof WebAssembly.instantiateStreaming == "function") try {
420
+ return await WebAssembly.instantiateStreaming(e, t);
421
+ } catch (t) {
422
+ if (n(e.type) && e.headers.get("Content-Type") !== "application/wasm") console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve Wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n", t);
423
+ else throw t;
424
+ }
425
+ let r = await e.arrayBuffer();
426
+ return await WebAssembly.instantiate(r, t);
427
+ }
428
+ {
429
+ let n = await WebAssembly.instantiate(e, t);
430
+ return n instanceof WebAssembly.Instance ? {
431
+ instance: n,
432
+ module: e
433
+ } : n;
434
+ }
435
+ function n(e) {
436
+ switch (e) {
437
+ case "basic":
438
+ case "cors":
439
+ case "default": return !0;
440
+ }
441
+ return !1;
442
+ }
443
+ }
444
+ function re(e) {
445
+ if (G !== void 0) return G;
446
+ e !== void 0 && (Object.getPrototypeOf(e) === Object.prototype ? {module: e} = e : console.warn("using deprecated parameters for `initSync()`; pass a single object instead"));
447
+ let t = C();
448
+ return e instanceof WebAssembly.Module || (e = new WebAssembly.Module(e)), K(new WebAssembly.Instance(e, t), e);
449
+ }
450
+ async function J(e) {
451
+ if (G !== void 0) return G;
452
+ e !== void 0 && (Object.getPrototypeOf(e) === Object.prototype ? {module_or_path: e} = e : console.warn("using deprecated parameters for the initialization function; pass a single object instead")), e === void 0 && (e = new URL("/pdf_core_bg.wasm", "" + import.meta.url));
453
+ let t = C();
454
+ (typeof e == "string" || typeof Request == "function" && e instanceof Request || typeof URL == "function" && e instanceof URL) && (e = fetch(e));
455
+ let { instance: n, module: r } = await q(await e, t);
456
+ return K(n, r);
457
+ }
458
+ //#endregion
459
+ //#region src/pdf-core/loadPdfEngine.ts
460
+ var ie = "https://cdn.jsdelivr.net/npm/pdf-viewer-assets@1.0.0/pdfium.js", ae = "https://cdn.jsdelivr.net/npm/pdf-viewer-assets@1.0.0/pdfium.wasm", Y = ie, X = ae, Z = null;
461
+ function oe(e) {
462
+ if (Z) throw Error("setPdfiumSource() must be called before the first <Document> is rendered. The pdfium engine has already started loading.");
463
+ Y = e.jsUrl, X = e.wasmUrl;
464
+ }
465
+ function se(e) {
466
+ return new Promise((t, n) => {
467
+ if (document.querySelector(`script[src="${e}"]`)) {
468
+ t();
469
+ return;
470
+ }
471
+ let r = document.createElement("script");
472
+ r.src = e, r.onload = () => t(), r.onerror = () => n(/* @__PURE__ */ Error(`Failed to load script: ${e}`)), document.head.appendChild(r);
473
+ });
474
+ }
475
+ function Q() {
476
+ return Z || (Z = (async () => {
477
+ await se(Y);
478
+ let e = await window.PDFiumModule({ locateFile: () => X });
479
+ if (await J(), !_(e, u, !1)) throw Error("Failed to initialize pdfium-render");
480
+ return g(), u;
481
+ })(), Z);
482
+ }
483
+ //#endregion
484
+ //#region src/components/Document.tsx
485
+ var $ = e(null);
486
+ function ce() {
487
+ let e = n($);
488
+ if (!e) throw Error("Page must be used inside a Document");
489
+ return e;
490
+ }
491
+ async function le(e, t) {
492
+ if (e instanceof Uint8Array) return e;
493
+ if (e instanceof File) return new Uint8Array(await e.arrayBuffer());
494
+ let n = await fetch(e);
495
+ if (!n.ok) throw Error(`Failed to fetch PDF: ${n.status}`);
496
+ let r = Number(n.headers.get("content-length")) || 0;
497
+ if (!n.body || !r) return new Uint8Array(await n.arrayBuffer());
498
+ let i = n.body.getReader(), a = [], o = 0;
499
+ for (;;) {
500
+ let { done: e, value: n } = await i.read();
501
+ if (e) break;
502
+ a.push(n), o += n.length, t?.(o, r);
503
+ }
504
+ let s = new Uint8Array(o), c = 0;
505
+ for (let e of a) s.set(e, c), c += e.length;
506
+ return s;
507
+ }
508
+ var ue = t(function({ file: e, className: t, scale: n = 1, rotate: c = 0, error: l = "Failed to load PDF file.", loading: u = "Loading PDF…", noData: d = "No PDF file specified.", children: f, onLoadSuccess: p, onLoadError: m, onLoadProgress: h, onSourceSuccess: g, onSourceError: _, onPassword: v }, y) {
509
+ let [b, x] = o(null), [S, C] = o("loading"), w = a(null);
510
+ i(y, () => w.current), r(() => {
511
+ if (!e) {
512
+ C("idle");
513
+ return;
514
+ }
515
+ let t = !1;
516
+ return C("loading"), (async () => {
517
+ try {
518
+ let n = await Q(), r = await le(e, (e, t) => {
519
+ h?.({
520
+ loaded: e,
521
+ total: t
522
+ });
523
+ });
524
+ if (t) return;
525
+ g?.();
526
+ let i;
527
+ try {
528
+ i = n.open_document(r, void 0);
529
+ } catch (e) {
530
+ let t = String(e);
531
+ if (t.includes("Password") || t.includes("password")) {
532
+ if (!v) throw Error("Password-protected PDF, but no onPassword handler provided.");
533
+ i = await new Promise((e, t) => {
534
+ v((i) => {
535
+ try {
536
+ e(n.open_document(r, i));
537
+ } catch (e) {
538
+ t(e);
539
+ }
540
+ });
541
+ });
542
+ } else throw e;
543
+ }
544
+ if (t) return;
545
+ x(i), C("idle"), p?.({ numPages: n.get_page_count(i) });
546
+ } catch (e) {
547
+ if (t) return;
548
+ C("error");
549
+ let n = e instanceof Error ? e : Error(String(e));
550
+ m?.(n), _?.(n);
551
+ }
552
+ })(), () => {
553
+ t = !0;
554
+ };
555
+ }, [e]);
556
+ let T = ["react-pdf-viewer-wasm__Document", Array.isArray(t) ? t.join(" ") : t].filter(Boolean).join(" ");
557
+ return e ? S === "loading" ? /* @__PURE__ */ s("div", {
558
+ className: T,
559
+ ref: w,
560
+ children: typeof u == "function" ? u() : u
561
+ }) : S === "error" || b === null ? /* @__PURE__ */ s("div", {
562
+ className: T,
563
+ ref: w,
564
+ children: typeof l == "function" ? l() : l
565
+ }) : /* @__PURE__ */ s("div", {
566
+ className: T,
567
+ ref: w,
568
+ children: /* @__PURE__ */ s($.Provider, {
569
+ value: {
570
+ docHandle: b,
571
+ scale: n,
572
+ rotate: c
573
+ },
574
+ children: f
575
+ })
576
+ }) : /* @__PURE__ */ s("div", {
577
+ className: T,
578
+ ref: w,
579
+ children: typeof d == "function" ? d() : d
580
+ });
581
+ });
582
+ //#endregion
583
+ //#region src/components/TextLayer.tsx
584
+ function de({ docHandle: e, pageIndex: t, scale: n, pageWidthPts: i, pageHeightPts: a }) {
585
+ let [c, l] = o([]);
586
+ return r(() => {
587
+ let n = !1;
588
+ return (async () => {
589
+ let r = (await Q()).get_text_chars(e, t);
590
+ n || l(JSON.parse(r));
591
+ })(), () => {
592
+ n = !0;
593
+ };
594
+ }, [e, t]), /* @__PURE__ */ s("div", {
595
+ "data-pdf-textlayer": "true",
596
+ style: {
597
+ position: "absolute",
598
+ top: 0,
599
+ left: 0,
600
+ width: i * n,
601
+ height: a * n,
602
+ pointerEvents: "none"
603
+ },
604
+ children: c.map((e, t) => /* @__PURE__ */ s("span", {
605
+ style: {
606
+ position: "absolute",
607
+ left: e.left * n,
608
+ top: e.top * n,
609
+ width: e.width * n,
610
+ height: e.height * n,
611
+ fontSize: e.height * n,
612
+ lineHeight: 1,
613
+ color: "transparent",
614
+ whiteSpace: "pre",
615
+ userSelect: "text",
616
+ pointerEvents: "auto"
617
+ },
618
+ children: e.ch
619
+ }, t))
620
+ });
621
+ }
622
+ //#endregion
623
+ //#region src/components/Page.tsx
624
+ function fe({ pageIndex: e, scale: t, rotate: n, textSelectable: i = !0 }) {
625
+ let l = ce(), u = t ?? l.scale, d = n ?? l.rotate, f = a(null), [p, m] = o(null);
626
+ return r(() => {
627
+ let t = !1;
628
+ return (async () => {
629
+ let n = await Q(), [r, i] = n.get_page_dimensions(l.docHandle, e), a = d === 90 || d === 270, o = a ? i : r, s = a ? r : i, c = Math.round(o * u), p = Math.round(s * u), h = n.render_page(l.docHandle, e, u, d);
630
+ if (t || !f.current) return;
631
+ let g = f.current;
632
+ g.width = c, g.height = p, g.getContext("2d").putImageData(new ImageData(new Uint8ClampedArray(h), c, p), 0, 0), m({
633
+ w: o,
634
+ h: s
635
+ });
636
+ })(), () => {
637
+ t = !0;
638
+ };
639
+ }, [
640
+ l.docHandle,
641
+ e,
642
+ u,
643
+ d
644
+ ]), /* @__PURE__ */ c("div", {
645
+ style: {
646
+ position: "relative",
647
+ display: "inline-block"
648
+ },
649
+ children: [/* @__PURE__ */ s("canvas", {
650
+ ref: f,
651
+ style: { display: "block" }
652
+ }), i && p && /* @__PURE__ */ s(de, {
653
+ docHandle: l.docHandle,
654
+ pageIndex: e,
655
+ scale: u,
656
+ pageWidthPts: p.w,
657
+ pageHeightPts: p.h
658
+ })]
659
+ });
660
+ }
661
+ //#endregion
662
+ export { ue as Document, fe as Page, oe as setPdfiumSource };
@@ -0,0 +1,18 @@
1
+ import * as PdfCore from './pdf_core.js';
2
+ /**
3
+ * Override where the pdfium engine (pdfium.js / pdfium.wasm) is loaded from.
4
+ * Call this BEFORE rendering any <Document>, if you need to self-host these
5
+ * files instead of using the default CDN (e.g. for corporate networks that
6
+ * block external CDNs, offline/airgapped apps, or strict CSP policies).
7
+ *
8
+ * Example:
9
+ * setPdfiumSource({
10
+ * jsUrl: '/vendor/pdfium.js',
11
+ * wasmUrl: '/vendor/pdfium.wasm',
12
+ * });
13
+ */
14
+ export declare function setPdfiumSource(options: {
15
+ jsUrl: string;
16
+ wasmUrl: string;
17
+ }): void;
18
+ export declare function loadPdfEngine(): Promise<typeof PdfCore>;
@@ -0,0 +1,166 @@
1
+ /* tslint:disable */
2
+ /* eslint-disable */
3
+
4
+ /**
5
+ * Free a document from memory.
6
+ *
7
+ * Drops both the raw bytes and the cached metadata.
8
+ * After this call, using the handle in any other function returns an error.
9
+ */
10
+ export function close_document(doc_handle: number): void;
11
+
12
+ /**
13
+ * Extract all text from a specific page.
14
+ *
15
+ * Returns an empty string if the page contains no selectable text
16
+ * (e.g., scanned images without OCR).
17
+ *
18
+ * KNOWN LIMITATION: re-parses the PDF from bytes on every call.
19
+ * Same root cause as `render_page`; see that function's doc comment for
20
+ * the planned fix (`ouroboros` / `self_cell` self-referential struct).
21
+ */
22
+ export function extract_text(doc_handle: number, page_index: number): string;
23
+
24
+ /**
25
+ * Returns the total number of pages in the document.
26
+ *
27
+ * O(1) — served from the metadata cache built at `open_document` time.
28
+ * Does **not** re-parse the PDF.
29
+ */
30
+ export function get_page_count(doc_handle: number): number;
31
+
32
+ /**
33
+ * Returns `[width_pts, height_pts]` for the given page.
34
+ *
35
+ * Dimensions are in **PDF points** (72 points = 1 inch).
36
+ * Multiply by your `scale` factor to get pixel dimensions.
37
+ *
38
+ * O(1) — served from the metadata cache built at `open_document` time.
39
+ * Does **not** re-parse the PDF.
40
+ */
41
+ export function get_page_dimensions(doc_handle: number, page_index: number): Float32Array;
42
+
43
+ /**
44
+ * Returns per-character position data for a page, as a JSON string.
45
+ * Coordinates are in PDF points, with origin at TOP-LEFT (converted from
46
+ * pdfium's native bottom-left origin) so they map directly onto a
47
+ * top-left-origin HTML/CSS layer once multiplied by your zoom scale.
48
+ */
49
+ export function get_text_chars(doc_handle: number, page_index: number): string;
50
+
51
+ /**
52
+ * Initialize the pdfium binding.
53
+ *
54
+ * **Must be called once before any other function.**
55
+ * Calling it multiple times is safe — subsequent calls are no-ops.
56
+ *
57
+ * On native (cargo test): links against the system pdfium shared library.
58
+ * On WASM: connects to the pdfium.wasm module loaded by the JS host.
59
+ */
60
+ export function initialize(): void;
61
+
62
+ /**
63
+ * Establishes a binding between an external Pdfium WASM module and `pdfium-render`'s WASM module.
64
+ * This function should be called from Javascript once the external Pdfium WASM module has been loaded
65
+ * into the browser. It is essential that this function is called _before_ initializing
66
+ * `pdfium-render` from within Rust code. For an example, see:
67
+ * <https://github.com/ajrcarey/pdfium-render/blob/master/examples/index.html>
68
+ */
69
+ export function initialize_pdfium_render(pdfium_wasm_module: any, local_wasm_module: any, debug: boolean): boolean;
70
+
71
+ /**
72
+ * Load a PDF from raw bytes.
73
+ *
74
+ * Returns a **document handle** (u32) that identifies this document in all
75
+ * subsequent calls. Call `close_document()` when done to free memory.
76
+ *
77
+ * This is the **only** time the full PDF is parsed to extract metadata.
78
+ * Page count and page dimensions are cached here so subsequent calls to
79
+ * `get_page_count` and `get_page_dimensions` are O(1) and never re-parse.
80
+ *
81
+ * Errors if the bytes are not a valid PDF.
82
+ */
83
+ export function open_document(bytes: Uint8Array, password?: string | null): number;
84
+
85
+ /**
86
+ * A callback function that can be invoked by Pdfium's `FPDF_LoadCustomDocument()` function,
87
+ * wrapping around `crate::utils::files::read_block_from_callback()` to shuffle data buffers
88
+ * from our WASM memory heap to Pdfium's WASM memory heap as they are loaded.
89
+ */
90
+ export function read_block_from_callback_wasm(param: number, position: number, pBuf: number, size: number): number;
91
+
92
+ /**
93
+ * Render a single page to raw **RGBA pixel data**.
94
+ *
95
+ * - `scale = 1.0` → 72 DPI (native PDF point resolution)
96
+ * - `scale = 1.5` → 108 DPI
97
+ * - `scale = 2.0` → 144 DPI (retina-quality)
98
+ *
99
+ * Returns a flat `Uint8Array` of `[R, G, B, A, R, G, B, A, …]` bytes.
100
+ * The output pixel dimensions are `round(width_pts * scale) × round(height_pts * scale)`.
101
+ *
102
+ * Call `get_page_dimensions()` beforehand to know the canvas size (O(1), no re-parse).
103
+ *
104
+ * KNOWN LIMITATION: re-parses the PDF from bytes on every call.
105
+ * For a user scrolling through a 200-page document this means 200 re-parses.
106
+ * Future fix: use `ouroboros` or `self_cell` to store a parsed `PdfDocument`
107
+ * alongside the bytes it borrows from, eliminating the re-parse entirely.
108
+ */
109
+ export function render_page(doc_handle: number, page_index: number, scale: number, rotation_degrees: number): Uint8Array;
110
+
111
+ export function start(): void;
112
+
113
+ /**
114
+ * A callback function that can be invoked by Pdfium's `FPDF_SaveAsCopy()` and `FPDF_SaveWithVersion()`
115
+ * functions, wrapping around `crate::utils::files::write_block_from_callback()` to shuffle data buffers
116
+ * from Pdfium's WASM memory heap to our WASM memory heap as they are written.
117
+ */
118
+ export function write_block_from_callback_wasm(param: number, buf: number, size: number): number;
119
+
120
+ export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
121
+
122
+ export interface InitOutput {
123
+ readonly memory: WebAssembly.Memory;
124
+ readonly close_document: (a: number) => [number, number];
125
+ readonly extract_text: (a: number, b: number) => [number, number, number, number];
126
+ readonly get_page_count: (a: number) => [number, number, number];
127
+ readonly get_page_dimensions: (a: number, b: number) => [number, number, number, number];
128
+ readonly get_text_chars: (a: number, b: number) => [number, number, number, number];
129
+ readonly initialize: () => [number, number];
130
+ readonly initialize_pdfium_render: (a: any, b: any, c: number) => number;
131
+ readonly open_document: (a: number, b: number, c: number, d: number) => [number, number, number];
132
+ readonly read_block_from_callback_wasm: (a: number, b: number, c: number, d: number) => number;
133
+ readonly render_page: (a: number, b: number, c: number, d: number) => [number, number, number];
134
+ readonly start: () => void;
135
+ readonly write_block_from_callback_wasm: (a: number, b: number, c: number) => number;
136
+ readonly __wbindgen_malloc: (a: number, b: number) => number;
137
+ readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
138
+ readonly __wbindgen_externrefs: WebAssembly.Table;
139
+ readonly __wbindgen_exn_store: (a: number) => void;
140
+ readonly __externref_table_alloc: () => number;
141
+ readonly __wbindgen_free: (a: number, b: number, c: number) => void;
142
+ readonly __externref_table_dealloc: (a: number) => void;
143
+ readonly __wbindgen_start: () => void;
144
+ }
145
+
146
+ export type SyncInitInput = BufferSource | WebAssembly.Module;
147
+
148
+ /**
149
+ * Instantiates the given `module`, which can either be bytes or
150
+ * a precompiled `WebAssembly.Module`.
151
+ *
152
+ * @param {{ module: SyncInitInput }} module - Passing `SyncInitInput` directly is deprecated.
153
+ *
154
+ * @returns {InitOutput}
155
+ */
156
+ export function initSync(module: { module: SyncInitInput } | SyncInitInput): InitOutput;
157
+
158
+ /**
159
+ * If `module_or_path` is {RequestInfo} or {URL}, makes a request and
160
+ * for everything else, calls `WebAssembly.instantiate` directly.
161
+ *
162
+ * @param {{ module_or_path: InitInput | Promise<InitInput> }} module_or_path - Passing `InitInput` directly is deprecated.
163
+ *
164
+ * @returns {Promise<InitOutput>}
165
+ */
166
+ export default function __wbg_init (module_or_path?: { module_or_path: InitInput | Promise<InitInput> } | InitInput | Promise<InitInput>): Promise<InitOutput>;
Binary file
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "react-pdf-viewer-wasm",
3
+ "version": "0.1.0",
4
+ "description": "A React PDF viewer powered by Rust + WebAssembly, using pdfium as the rendering backend.",
5
+ "type": "module",
6
+ "main": "./dist/index.mjs",
7
+ "module": "./dist/index.mjs",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "import": "./dist/index.mjs",
12
+ "types": "./dist/index.d.ts"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist"
17
+ ],
18
+ "peerDependencies": {
19
+ "react": ">=18.0.0",
20
+ "react-dom": ">=18.0.0"
21
+ },
22
+ "scripts": {
23
+ "build": "vite build"
24
+ },
25
+ "license": "MIT",
26
+ "author": "Rohit Kumar <shan.rohitkumar12@gmail.com>",
27
+ "keywords": [
28
+ "pdf",
29
+ "react",
30
+ "wasm",
31
+ "rust",
32
+ "pdfium",
33
+ "viewer",
34
+ "render-pdf"
35
+ ],
36
+ "devDependencies": {
37
+ "@types/react": "^19.3.0",
38
+ "@types/react-dom": "^19.3.0",
39
+ "@typescript/typescript6": "^6.0.2",
40
+ "@vitejs/plugin-react": "^6.1.1",
41
+ "react": "^19.3.0",
42
+ "react-dom": "^19.3.0",
43
+ "typescript": "^7.0.2",
44
+ "vite": "^8.3.0",
45
+ "vite-plugin-dts": "^5.1.0"
46
+ }
47
+ }
package/readme.md ADDED
@@ -0,0 +1,256 @@
1
+ # react-pdf-viewer-wasm
2
+
3
+ Show PDF files in your React app — powered by **Rust + WebAssembly** instead of the usual `pdf.js`.
4
+
5
+ This library uses **pdfium**, the same PDF engine built into Google Chrome, to draw PDF pages onto the screen. It works a lot like the popular `react-pdf` package, but under the hood it's a completely different engine.
6
+
7
+ > **Status:** early release (v0.1.x). The basics — viewing pages, zooming, rotating, selecting text, password-protected files — all work. Some more advanced features (clickable links, bookmarks, forms) aren't built yet. See [What's not supported yet](#whats-not-supported-yet).
8
+
9
+ ---
10
+
11
+ ## What you get
12
+
13
+ - 📄 Render any PDF page onto the screen
14
+ - 🔍 Zoom in and out
15
+ - 🔄 Rotate pages
16
+ - ✍️ Select and copy text from the PDF (just like a real document)
17
+ - 🔒 Support for password-protected PDFs
18
+ - ⚡ No setup needed — the PDF engine loads automatically from the internet the first time it's used
19
+
20
+ ---
21
+
22
+ ## Installing it
23
+
24
+ ```bash
25
+ npm install react-pdf-viewer-wasm
26
+ ```
27
+
28
+ That's it. You don't need to download or configure anything else — this library automatically fetches the small "PDF engine" file it needs from the internet the first time your app shows a PDF.
29
+
30
+ *(If your company's network blocks outside websites, see [Using it without the internet](#using-it-without-the-internet) below.)*
31
+
32
+ ---
33
+
34
+ ## Showing your first PDF
35
+
36
+ ```tsx
37
+ import { Document, Page } from 'react-pdf-viewer-wasm';
38
+
39
+ function App() {
40
+ return (
41
+ <Document file="/my-file.pdf">
42
+ <Page pageIndex={0} />
43
+ </Document>
44
+ );
45
+ }
46
+ ```
47
+
48
+ That's the whole thing. `pageIndex={0}` means "show the first page" (pages are counted starting from 0, not 1).
49
+
50
+ Put your PDF file in your app's `public` folder so `"/my-file.pdf"` can find it. You can also use a full web address instead, like `"https://example.com/my-file.pdf"`.
51
+
52
+ ---
53
+
54
+ ## Showing every page in the PDF
55
+
56
+ ```tsx
57
+ import { useState } from 'react';
58
+ import { Document, Page } from 'react-pdf-viewer-wasm';
59
+
60
+ function App() {
61
+ const [numPages, setNumPages] = useState(0);
62
+
63
+ return (
64
+ <Document
65
+ file="/my-file.pdf"
66
+ onLoadSuccess={({ numPages }) => setNumPages(numPages)}
67
+ >
68
+ {Array.from({ length: numPages }, (_, i) => (
69
+ <Page key={i} pageIndex={i} />
70
+ ))}
71
+ </Document>
72
+ );
73
+ }
74
+ ```
75
+
76
+ `onLoadSuccess` tells you how many pages the PDF has, once it's finished loading. We use that number to draw one `<Page>` for every page in the file.
77
+
78
+ ---
79
+
80
+ ## Zooming in and out
81
+
82
+ ```tsx
83
+ <Document file="/my-file.pdf" scale={1.5}>
84
+ <Page pageIndex={0} />
85
+ </Document>
86
+ ```
87
+
88
+ `scale={1}` is the normal size. `scale={1.5}` makes it 50% bigger. `scale={0.5}` makes it half size.
89
+
90
+ You can also zoom just one page differently from the rest:
91
+
92
+ ```tsx
93
+ <Page pageIndex={0} scale={2} />
94
+ ```
95
+
96
+ ---
97
+
98
+ ## Rotating pages
99
+
100
+ ```tsx
101
+ <Document file="/my-file.pdf" rotate={90}>
102
+ <Page pageIndex={0} />
103
+ </Document>
104
+ ```
105
+
106
+ Use `90`, `180`, or `270` degrees. Just like `scale`, you can also rotate a single page differently:
107
+
108
+ ```tsx
109
+ <Page pageIndex={0} rotate={180} />
110
+ ```
111
+
112
+ ---
113
+
114
+ ## Turning text selection on or off
115
+
116
+ By default, users can click and drag to select text on the page, then copy it — just like a real document.
117
+
118
+ If you don't want this (for example, showing small page thumbnails), turn it off:
119
+
120
+ ```tsx
121
+ <Page pageIndex={0} textSelectable={false} />
122
+ ```
123
+
124
+ ---
125
+
126
+ ## Opening password-protected PDFs
127
+
128
+ ```tsx
129
+ <Document
130
+ file="/protected-file.pdf"
131
+ onPassword={(submitPassword) => {
132
+ const password = window.prompt('This PDF needs a password:');
133
+ submitPassword(password ?? '');
134
+ }}
135
+ >
136
+ <Page pageIndex={0} />
137
+ </Document>
138
+ ```
139
+
140
+ When the library discovers the PDF needs a password, it calls your `onPassword` function. You ask the user for the password (however you like — a prompt box, a form, anything), and then call `submitPassword(theirAnswer)` to try opening it.
141
+
142
+ ---
143
+
144
+ ## Showing loading and error messages
145
+
146
+ ```tsx
147
+ <Document
148
+ file="/my-file.pdf"
149
+ loading="Loading your document..."
150
+ error="Sorry, we couldn't open this PDF."
151
+ >
152
+ <Page pageIndex={0} />
153
+ </Document>
154
+ ```
155
+
156
+ You can use plain text, or your own custom design:
157
+
158
+ ```tsx
159
+ <Document
160
+ file="/my-file.pdf"
161
+ loading={<MySpinner />}
162
+ error={<MyErrorMessage />}
163
+ >
164
+ <Page pageIndex={0} />
165
+ </Document>
166
+ ```
167
+
168
+ ---
169
+
170
+ ## All the settings you can use
171
+
172
+ ### `<Document>` settings
173
+
174
+ | Setting | What it does | Default |
175
+ |---|---|---|
176
+ | `file` | The PDF to show — a web address, an uploaded file, or raw file data. | *(required)* |
177
+ | `scale` | How zoomed in the pages are. | `1` |
178
+ | `rotate` | How many degrees to rotate the pages (`0`, `90`, `180`, `270`). | `0` |
179
+ | `loading` | What to show while the PDF is loading. | `"Loading PDF…"` |
180
+ | `error` | What to show if something goes wrong. | `"Failed to load PDF file."` |
181
+ | `noData` | What to show if no file was given. | `"No PDF file specified."` |
182
+ | `onLoadSuccess` | Runs when the PDF has finished loading. Tells you `numPages`. | — |
183
+ | `onLoadError` | Runs if the PDF fails to load. | — |
184
+ | `onLoadProgress` | Runs while the file is downloading, so you can show a progress bar. | — |
185
+ | `onPassword` | Runs when a password-protected PDF needs unlocking. | — |
186
+ | `className` | Add your own CSS class name(s) to the wrapper. | — |
187
+
188
+ ### `<Page>` settings
189
+
190
+ | Setting | What it does | Default |
191
+ |---|---|---|
192
+ | `pageIndex` | Which page to show (starting at `0` for the first page). | *(required)* |
193
+ | `scale` | Zoom for this page only (overrides the Document's setting). | inherited |
194
+ | `rotate` | Rotation for this page only (overrides the Document's setting). | inherited |
195
+ | `textSelectable` | Whether people can select and copy text on this page. | `true` |
196
+
197
+ ---
198
+
199
+ ## Using it without the internet
200
+
201
+ By default, this library downloads a small "PDF engine" file from a free content-delivery service the first time it's needed. For most people, this just works with zero setup.
202
+
203
+ If you're building something for a company network that blocks outside websites, or an app that needs to work completely offline, you can host these files yourself instead:
204
+
205
+ **1. Download the two engine files:**
206
+
207
+ - [`pdfium.js`](https://cdn.jsdelivr.net/npm/pdf-viewer-assets@1.0.0/pdfium.js)
208
+ - [`pdfium.wasm`](https://cdn.jsdelivr.net/npm/pdf-viewer-assets@1.0.0/pdfium.wasm)
209
+
210
+ **2. Put both files in your app's `public` folder.**
211
+
212
+ **3. Tell the library to use your own copies, before showing any PDF:**
213
+
214
+ ```tsx
215
+ import { setPdfiumSource } from 'react-pdf-viewer-wasm';
216
+
217
+ setPdfiumSource({
218
+ jsUrl: '/pdfium.js',
219
+ wasmUrl: '/pdfium.wasm',
220
+ });
221
+ ```
222
+
223
+ Do this once, near the very start of your app (for example, in your main entry file), before any `<Document>` is shown.
224
+
225
+ ---
226
+
227
+ ## What's not supported yet
228
+
229
+ This is a young library, and being upfront about its current limits:
230
+
231
+ - **No clickable links or bookmarks inside PDFs yet.**
232
+ - **No PDF forms yet** (fillable fields, checkboxes, etc.).
233
+ - **Large PDFs may feel a little slow** — page rendering currently happens on the main part of your browser's engine, so very big or complex PDFs might cause a brief pause while rendering. Improving this is planned.
234
+
235
+ If any of these matter for what you're building, keep that in mind before relying on this library for a big project just yet.
236
+
237
+ ---
238
+
239
+ ## Requirements
240
+
241
+ - React 18 or newer
242
+ - Any modern web browser (Chrome, Firefox, Safari, Edge — all support what this library needs)
243
+
244
+ ---
245
+
246
+ ## License
247
+
248
+ MIT
249
+
250
+ ---
251
+
252
+ ## Credits
253
+
254
+ - [pdfium](https://pdfium.googlesource.com/pdfium/) — the actual PDF engine, made by Google.
255
+ - [pdfium-render](https://github.com/ajrcarey/pdfium-render) — the Rust tool this library is built on top of.
256
+ - [pdfium-lib](https://github.com/paulocoutinhox/pdfium-lib) — provides the ready-to-use engine files.