57 lines
1.7 KiB
TypeScript
57 lines
1.7 KiB
TypeScript
import { PDFDocument } from 'pdf-lib';
|
|
import { PDFParse } from 'pdf-parse';
|
|
|
|
/** Kennzahlen eines Belegs; `null` = nicht ermittelbar. */
|
|
export interface Kennzahlen {
|
|
seiten: number | null;
|
|
woerter: number | null;
|
|
}
|
|
|
|
/** Kennzahlen des vorhandenen (Paperless) und des neuen Belegs. */
|
|
export interface VergleichKennzahlen {
|
|
vorhanden: Kennzahlen;
|
|
neu: Kennzahlen;
|
|
}
|
|
|
|
/**
|
|
* Zählt Wörter: Tokens zwischen Leerraum, die mindestens einen Buchstaben oder
|
|
* eine Ziffer enthalten. Seitenmarker von pdf-parse („-- 1 of 2 --“) zählen
|
|
* nicht. Kein Wort → `null` (z. B. Scan ohne Textebene).
|
|
*/
|
|
export function zaehleWoerter(text: string | null | undefined): number | null {
|
|
if (!text) return null;
|
|
const ohneMarker = text.replace(/-- \d+ of \d+ --/g, ' ');
|
|
const anzahl = ohneMarker
|
|
.split(/\s+/)
|
|
.filter((token) => /[\p{L}\p{N}]/u.test(token)).length;
|
|
return anzahl > 0 ? anzahl : null;
|
|
}
|
|
|
|
async function seitenzahl(pdf: Buffer): Promise<number | null> {
|
|
try {
|
|
const doc = await PDFDocument.load(pdf, { ignoreEncryption: true });
|
|
return doc.getPageCount();
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
async function wortzahl(pdf: Buffer): Promise<number | null> {
|
|
// pdf.js übernimmt den Puffer, deshalb eine Kopie übergeben
|
|
const parser = new PDFParse({ data: new Uint8Array(pdf) });
|
|
try {
|
|
const { text } = await parser.getText();
|
|
return zaehleWoerter(text);
|
|
} catch {
|
|
return null;
|
|
} finally {
|
|
await parser.destroy().catch(() => undefined);
|
|
}
|
|
}
|
|
|
|
/** Seiten- und Wortzahl eines PDFs; Lesefehler ergeben `null`. */
|
|
export async function kennzahlenAusPdf(pdf: Buffer): Promise<Kennzahlen> {
|
|
const [seiten, woerter] = await Promise.all([seitenzahl(pdf), wortzahl(pdf)]);
|
|
return { seiten, woerter };
|
|
}
|