diff --git a/frontend/src/lib/document/viewer/usePdfRenderer.svelte.test.ts b/frontend/src/lib/document/viewer/usePdfRenderer.svelte.test.ts index 6b48c3f8..c9e07a51 100644 --- a/frontend/src/lib/document/viewer/usePdfRenderer.svelte.test.ts +++ b/frontend/src/lib/document/viewer/usePdfRenderer.svelte.test.ts @@ -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: '' }, diff --git a/frontend/src/lib/document/viewer/usePdfRenderer.svelte.ts b/frontend/src/lib/document/viewer/usePdfRenderer.svelte.ts index 13315f8e..c21ad2dd 100644 --- a/frontend/src/lib/document/viewer/usePdfRenderer.svelte.ts +++ b/frontend/src/lib/document/viewer/usePdfRenderer.svelte.ts @@ -5,6 +5,12 @@ export type LibLoader = () => Promise 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;