feat: implement region-based QR code scanning for inbox documents
Build and Push Multi-Platform Images / build-and-push (push) Successful in 33s
Build and Push Multi-Platform Images / build-and-push (push) Successful in 33s
This commit is contained in:
@@ -2,6 +2,7 @@ import { Injectable, Logger, OnApplicationBootstrap } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
import * as fs from 'fs/promises';
|
||||
import sharp = require('sharp');
|
||||
import { PdfService } from '../preprocessing/pdf.service';
|
||||
import { QrCodeService } from '../preprocessing/qr-code.service';
|
||||
import {
|
||||
@@ -76,6 +77,7 @@ export class BarcodeScannerService implements OnApplicationBootstrap {
|
||||
|
||||
doc.QrCodes = qrCodes;
|
||||
doc.PageCount = pageCount;
|
||||
doc.IsScanned = true;
|
||||
try {
|
||||
await this.documentRepo.save(doc);
|
||||
} catch (err: any) {
|
||||
@@ -174,6 +176,61 @@ export class BarcodeScannerService implements OnApplicationBootstrap {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Rendert eine einzelne Seite bei hoher DPI, beschneidet den angegebenen
|
||||
* Bereich (normalisierte Koordinaten 0..1) und scannt ihn nach QR-Codes.
|
||||
* Neu gefundene QR-Codes werden in der DB persistiert.
|
||||
*/
|
||||
async scanRegion(
|
||||
doc: InboxDocument,
|
||||
pdfPath: string,
|
||||
page: number,
|
||||
x: number,
|
||||
y: number,
|
||||
w: number,
|
||||
h: number,
|
||||
): Promise<{ found: string[] }> {
|
||||
let imagePath: string | null = null;
|
||||
try {
|
||||
imagePath = await this.pdfService.pdfPageToImage(pdfPath, page, 400);
|
||||
|
||||
const image = sharp(imagePath);
|
||||
const { width: imgW, height: imgH } = await image.metadata();
|
||||
if (!imgW || !imgH) return { found: [] };
|
||||
|
||||
const left = Math.round(Math.max(0, x * imgW));
|
||||
const top = Math.round(Math.max(0, y * imgH));
|
||||
const width = Math.round(Math.min(imgW - left, w * imgW));
|
||||
const height = Math.round(Math.min(imgH - top, h * imgH));
|
||||
if (width <= 0 || height <= 0) return { found: [] };
|
||||
|
||||
const cropped = await image.extract({ left, top, width, height }).png().toBuffer();
|
||||
const qrResults = await this.qrCodeService.extractFromImage(cropped);
|
||||
if (qrResults.length === 0) return { found: [] };
|
||||
|
||||
const existingKeys = new Set((doc.QrCodes ?? []).map((qr) => `${qr.page}:${qr.value}`));
|
||||
const found: string[] = [];
|
||||
let changed = false;
|
||||
|
||||
for (const qr of qrResults) {
|
||||
found.push(qr.data);
|
||||
const key = `${page}:${qr.data}`;
|
||||
if (!existingKeys.has(key)) {
|
||||
doc.QrCodes = [...(doc.QrCodes ?? []), { page, value: qr.data }];
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
await this.documentRepo.save(doc);
|
||||
}
|
||||
|
||||
return { found };
|
||||
} finally {
|
||||
if (imagePath) await this.pdfService.cleanup([imagePath]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Rescannt alle Inbox-Dokumente — wird nach Änderungen an Eingangsdokumentarten aufgerufen.
|
||||
* Läuft sequenziell, um PDF-Rendering nicht zu überlasten. Fire-and-forget vom Caller.
|
||||
|
||||
Reference in New Issue
Block a user