fix(document): pass wasmUrl to pdf.js getDocument so wasm decoders load

getDocument was called with a bare src string, so pdf.js 5.x had no
`wasmUrl` and could not initialise the JBIG2/CCITTFax wasm decoder —
CCITT (G4 fax) scans painted a blank canvas. Pass
{ url, wasmUrl: '/pdfjs-wasm/' }; the directory URL (trailing slash
required) is the single source of truth next to the worker config.

Refs #708

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-06-01 20:07:35 +02:00
parent 8d2ef97fe2
commit be42e1f01f
2 changed files with 33 additions and 1 deletions

View File

@@ -205,6 +205,32 @@ describe('createPdfRenderer', () => {
expect(fakeLoader).toHaveBeenCalledOnce();
});
it('passes a non-null wasmUrl directory (ending in /) to getDocument, not a bare src string', async () => {
const getDocument = vi.fn().mockReturnValue({
promise: Promise.resolve({ numPages: 1, getPage: vi.fn() })
});
const lib = {
GlobalWorkerOptions: { workerSrc: '' },
getDocument,
TextLayer: class {
render() {
return Promise.resolve();
}
cancel() {}
}
} as unknown as typeof import('pdfjs-dist');
const r = createPdfRenderer(vi.fn().mockResolvedValue([lib, { default: '' }] as const));
await r.init();
await r.loadDocument('/api/documents/abc/file');
expect(getDocument).toHaveBeenCalledTimes(1);
const arg = getDocument.mock.calls[0][0] as { url?: string; wasmUrl?: string };
expect(arg.url).toBe('/api/documents/abc/file');
expect(typeof arg.wasmUrl).toBe('string');
expect(arg.wasmUrl).not.toBe('');
expect(arg.wasmUrl?.endsWith('/')).toBe(true);
});
it('loadDocument sets error and loading=false when getDocument().promise rejects', async () => {
const failingLib = {
GlobalWorkerOptions: { workerSrc: '' },

View File

@@ -5,6 +5,12 @@ export type LibLoader = () => Promise<readonly [typeof import('pdfjs-dist'), { d
const defaultLibLoader: LibLoader = () =>
Promise.all([import('pdfjs-dist'), import('pdfjs-dist/build/pdf.worker.min.mjs?url')]);
// pdf.js 5.x decodes JBIG2 / CCITTFax / JPEG2000 images via WebAssembly and
// needs to know where the .wasm modules are served. Must be a directory URL
// with a trailing slash — pdf.js appends `jbig2.wasm` etc. Served from our own
// origin by vite-plugin-static-copy (see vite.config.ts). See issue #708.
const WASM_URL = '/pdfjs-wasm/';
export function createPdfRenderer(libLoader: LibLoader = defaultLibLoader) {
// Reactive state — exposed via getters
let currentPage = $state(1);
@@ -44,7 +50,7 @@ export function createPdfRenderer(libLoader: LibLoader = defaultLibLoader) {
totalPages = 0;
try {
const loadingTask = pdfjsLib.getDocument(src);
const loadingTask = pdfjsLib.getDocument({ url: src, wasmUrl: WASM_URL });
const doc = await loadingTask.promise;
pdfDoc = doc;
totalPages = doc.numPages;