Ausschnitt in nativer Aufloesung fuer Barcode-Erkennung
FRAME_INSET und frameRect() legen die Rahmenmasse einmalig fest, statt sie nur im Stilblatt zu duplizieren. grabFrameRegion() liefert den Zielrahmen unskaliert aus dem Kamerabild - grabFrame() (fuer OCR) bleibt unveraendert. Ein Code-128 auf kleinem Etikett braucht die volle Aufloesung, sonst verschmieren die Striche unlesbar. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -32,6 +32,39 @@ export async function startCamera(videoElement) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Rahmenmasse als Anteil der Bildkanten - einzige Quelle fuer die Lage des
|
||||
* Zielrahmens. scan-view.js uebernimmt daraus den sichtbaren Rahmen,
|
||||
* grabFrameRegion() weiter unten den nativen Ausschnitt - beide koennen so
|
||||
* nicht mehr auseinanderlaufen (frueher stand das, unabhaengig davon, nur
|
||||
* im Stilblatt).
|
||||
*/
|
||||
export const FRAME_INSET = { top: 0.2, right: 0.08, bottom: 0.2, left: 0.08 };
|
||||
|
||||
/**
|
||||
* Rechnet die Rahmenmasse (Anteile der Kantenlaenge) in Bildpunkte um.
|
||||
* Reine Funktion ohne Bezug zu einem konkreten Bild oder einer Browser-API -
|
||||
* damit auch ohne DOM testbar.
|
||||
*
|
||||
* Breite und Hoehe werden als Differenz aus der Gesamtkante und den beiden
|
||||
* gerundeten Raendern gebildet, nicht unabhaengig aus dem Anteil selbst
|
||||
* gerundet - so bleibt der Ausschnitt bei krummen Bildgroessen garantiert
|
||||
* innerhalb des Bildes, auch wenn die Anteile keine ganzzahligen Ergebnisse
|
||||
* liefern.
|
||||
*/
|
||||
export function frameRect(width, height, inset = FRAME_INSET) {
|
||||
const left = Math.round(width * inset.left);
|
||||
const right = Math.round(width * inset.right);
|
||||
const top = Math.round(height * inset.top);
|
||||
const bottom = Math.round(height * inset.bottom);
|
||||
return {
|
||||
x: left,
|
||||
y: top,
|
||||
width: Math.max(0, width - left - right),
|
||||
height: Math.max(0, height - top - bottom),
|
||||
};
|
||||
}
|
||||
|
||||
function drawScaled(source, sourceWidth, sourceHeight, maxEdge) {
|
||||
const scale = Math.min(1, maxEdge / Math.max(sourceWidth, sourceHeight));
|
||||
const width = Math.round(sourceWidth * scale);
|
||||
@@ -64,6 +97,30 @@ export function grabFrame(videoElement, maxEdge = 1280) {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Schneidet den Zielrahmen (siehe FRAME_INSET) aus dem laufenden Kamerabild -
|
||||
* in unveraenderter Aufloesung, ohne jede Verkleinerung. Anders als
|
||||
* grabFrame(): fuer die Texterkennung genuegt ein herunterskaliertes
|
||||
* Vollbild, aber ein Code-128 auf einem kleinen Etikett braucht seine
|
||||
* feinen Striche in voller Schaerfe - beim Skalieren auf die fuer OCR
|
||||
* ausreichende Kantenlaenge verschmieren sie unlesbar.
|
||||
*/
|
||||
export function grabFrameRegion(videoElement, inset = FRAME_INSET) {
|
||||
assertHasSize(videoElement.videoWidth, videoElement.videoHeight);
|
||||
const rect = frameRect(videoElement.videoWidth, videoElement.videoHeight, inset);
|
||||
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = rect.width;
|
||||
canvas.height = rect.height;
|
||||
const context = canvas.getContext('2d', { willReadFrequently: true });
|
||||
context.drawImage(
|
||||
videoElement,
|
||||
rect.x, rect.y, rect.width, rect.height,
|
||||
0, 0, rect.width, rect.height,
|
||||
);
|
||||
return context.getImageData(0, 0, rect.width, rect.height);
|
||||
}
|
||||
|
||||
/** Ersatzweg ohne Kamera: Bilddatei auswaehlen (z. B. am Rechner). */
|
||||
export async function imageDataFromFile(file, maxEdge = 1280) {
|
||||
const bitmap = await createImageBitmap(file);
|
||||
|
||||
Reference in New Issue
Block a user