Merge pull request 'Скан PDF с JBIG2 не рисовался: wasmUrl для pdf.js и копирование wasm (#32, AURORA-1635)' (#33) from feat/32-pdfjs-jbig2 into test

This commit is contained in:
aep 2026-10-16 12:34:33 +03:00
commit 025233f3c2
4 changed files with 36 additions and 1 deletions

View File

@ -12,6 +12,8 @@ export default defineConfig({
}, },
}, },
output: { output: {
// wasm-декодеры pdf.js (JBIG2, JPEG2000, ICC): без них скан не рисуется (AURORA-1635). Путь = PDFJS_WASM_DIR
copy: [{ from: 'node_modules/pdfjs-dist/wasm', to: 'static/pdfjs/wasm' }],
filename: { filename: {
js: '[name]_script.[contenthash:8].js', js: '[name]_script.[contenthash:8].js',
css: '[name]_style.[contenthash:8].css', css: '[name]_style.[contenthash:8].css',

View File

@ -1,6 +1,8 @@
import type { PDFDocumentProxy, RenderTask } from 'pdfjs-dist'; import type { PDFDocumentProxy, RenderTask } from 'pdfjs-dist';
import { useCallback, useEffect, useRef, useState } from 'react'; import { useCallback, useEffect, useRef, useState } from 'react';
import { Config } from '../../conf/config';
import { pdfjsLib } from './pdfjs'; import { pdfjsLib } from './pdfjs';
import { pdfjsWasmUrl } from './pdfjsOptions';
export const MIN_ZOOM = 0.5; export const MIN_ZOOM = 0.5;
export const MAX_ZOOM = 3; export const MAX_ZOOM = 3;
@ -22,7 +24,7 @@ export default function PdfPages({ data, zoom }: { data: ArrayBuffer; zoom: numb
let cancelled = false; let cancelled = false;
async function load() { async function load() {
// pdf.js забирает переданный буфер себе, поэтому отдаём копию (эффект может выполниться повторно) // pdf.js забирает переданный буфер себе, поэтому отдаём копию (эффект может выполниться повторно)
pdf = await pdfjsLib.getDocument({ data: data.slice(0) }).promise; pdf = await pdfjsLib.getDocument({ data: data.slice(0), wasmUrl: pdfjsWasmUrl(Config.APP_ADDRESS) }).promise;
if (cancelled) { if (cancelled) {
pdf.destroy(); pdf.destroy();
return; return;

View File

@ -0,0 +1,17 @@
import { describe, expect, it } from 'vitest';
import { PDFJS_WASM_DIR, pdfjsWasmUrl } from './pdfjsOptions';
describe('pdfjsWasmUrl', () => {
it('кладёт wasm под префикс приложения и заканчивается слэшем (pdf.js дописывает к нему имя файла)', () => {
expect(pdfjsWasmUrl('/aurora/apps/fastapi-dkb-armka')).toBe(`/aurora/apps/fastapi-dkb-armka/${PDFJS_WASM_DIR}/`);
});
it('не удваивает слэши, если префикс уже заканчивается слэшем', () => {
expect(pdfjsWasmUrl('/aurora/apps/fastapi-dkb-armka/')).toBe(`/aurora/apps/fastapi-dkb-armka/${PDFJS_WASM_DIR}/`);
});
it('при корневом префиксе даёт путь от корня', () => {
expect(pdfjsWasmUrl('/')).toBe(`/${PDFJS_WASM_DIR}/`);
expect(pdfjsWasmUrl('')).toBe(`/${PDFJS_WASM_DIR}/`);
});
});

View File

@ -0,0 +1,14 @@
// Опции pdf.js для getDocument. Чистый модуль (без импорта pdfjs-dist), чтобы его можно было тестировать.
//
// pdf.js 5.x декодирует сканы JBIG2 и JPEG2000 и цветовые профили ICC через wasm-файлы (jbig2.wasm, openjpeg.wasm,
// qcms_bg.wasm). Без опции wasmUrl он их не находит: «JBig2 failed to initialize», «Unable to decode image», страница
// остаётся пустой (AURORA-1635). Файлы копирует в сборку rsbuild.config.ts (output.copy) в каталог PDFJS_WASM_DIR.
/** Каталог wasm-файлов pdf.js в собранном приложении (относительно корня приложения). Тот же путь — в rsbuild.config.ts. */
export const PDFJS_WASM_DIR = 'static/pdfjs/wasm';
/** Адрес каталога wasm: с учётом префикса приложения (ROOT_PATH) и обязательным слэшем в конце — pdf.js дописывает к нему имя файла. */
export function pdfjsWasmUrl(appAddress: string): string {
const base = appAddress.replace(/\/+$/, '');
return `${base}/${PDFJS_WASM_DIR}/`;
}