Neue Funktion in scan-modes.js (Merkmal continuousCount), verdrahtet in
main.js ueber denselben Zeitgeber/dieselbe Ueberlappungssperre wie die
Barcode-Dauersuche (continuousSearchLoop ruft jetzt runCountAttempt()
zusaetzlich zu runSearchAttempt(); jeder bricht selbst ab, wenn die
Funktion nicht passt) - kein zweiter, paralleler Mechanismus. Kein "Modul
scannen"-Knopf, keine Treffer-Rueckmeldung, kein roter Dialog, keine
Stapel-Zuweisung; die grosse Zaehlanzeige (scan-view.js/styles.css) ist
reine Anzeige und speichert nichts.
buildRecognitionAdapters() liefert fuer "Zählen" zusaetzlich leere Adapter
(Absicherung gegen den seltenen Datei-Ersatzweg ohne Kamera). Die drei
bestehenden Funktionen bleiben unveraendert; einzige notwendige Anpassung an
scan-modes.test.js war die Anzahl-Pruefung (3 -> 4 Funktionen).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Neues Modul src/count-objects.js: Otsu-Schwellwert (threshold.js) teilt den
Ausschnitt in zwei Klassen, die flaechenmaessig kleinere gilt als Objekt
(funktioniert fuer helle wie dunkle Teile auf beliebigem Untergrund).
Connected-Component-Labeling ueber eine eigene Arbeitsliste statt Rekursion
(vermeidet Stapelueberlauf bei ~1 Mio. Bildpunkten), Rauschflaechen werden
verworfen, beruehrende Teile anhand des Flaechen-Medians hochgerechnet.
Test-Driven: leeres Bild, einzelne/mehrere getrennte Flaechen, verworfenes
Rauschen, Hochrechnung ohne ein nur leicht groesseres Einzelteil zu
verdoppeln, helle wie dunkle Objekte, Bild ohne Bildpunkte, diagonal statt
flaechig beruehrende Teile bleiben getrennt.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Zieht otsuThreshold()/grayscaleHistogram() aus ocr.js in src/threshold.js,
ohne das Verhalten von preprocess() zu aendern (bestehende Tests in
ocr-preprocess.test.js bleiben unveraendert gruen). Vorbereitung fuer die
neue Zaehl-Funktion, die dieselbe Schwellwertbestimmung braucht, aber nichts
mit tesseract.js (ocr.js) zu tun haben soll.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
README auf den aktuellen Stand gebracht: Zielrahmen ist jetzt auch in "Text
erkennen" wirksam (grabFrameRegion statt grabFrame), breitere Zeichen-
Whitelist samt Abwägung, additiver OCR-Rohtext (rawText) in Pipeline,
Speicherung und Anzeige, wartende statt automatisch ausblendende
Rückmeldung in "Text erkennen". Datei-Tabelle, Abschnitt
"Sitzungssicherung im Detail", "Grenzen" und die manuelle Geräte-Prüfliste
entsprechend ergänzt; Testanzahl 144 → 154.
recognize() (pipeline.js) liefert zusätzlich den ungefilterten OCR-Rohtext
(rawText) zurück - leer, wenn keine Texterkennung lief. Rein additiv: die
Stapelzuordnung (session.js/spec.js, unangetastet) stützt sich weiterhin
ausschließlich auf die daraus abgeleiteten, verstandenen Spec-Felder.
main.js hängt den Rohtext nach dem Buchen als zusätzliche Eigenschaft an den
Eintrag (analog zu den bereits vorhandenen Barcode-Inhalten je Eintrag).
storage.js sichert/prüft/stellt entry.rawText nach demselben optionalen
Muster wie entry.codes wieder her - ein gesicherter Stand ohne dieses Feld
wird nicht verworfen.
In Funktion "Text erkennen" bleibt die Treffer-Rückmeldung jetzt stehen, bis
der Nutzer sie wegtippt, und zeigt den vollen erkannten Text (lesbar über
dasselbe Scroll-Muster wie die übrigen Vollbild-Overlays); in den beiden
Barcode-Funktionen bleibt es beim automatischen Ausblenden. Das
zurückgegebene Versprechen von showResult löst in jedem Fall - Zeitgeber,
Wegtippen, verdrängende neue Rückmeldung - genau einmal ein, damit die
Bedienung nie dauerhaft gesperrt bleibt. Die Sitzungsliste zeigt den Rohtext
zusätzlich je Eintrag zum Nachlesen.
Tests (pipeline.test.js, storage.test.js): rawText nur bei tatsächlich
gelaufener Texterkennung, unterschiedlicher Rohtext beeinflusst die
Stapelzuordnung nachweislich nicht, Rohtext übersteht Sichern/Laden inkl.
Abwärtskompatibilität zu einem Stand ohne dieses Feld.
tessedit_char_whitelist ließ bisher nur Großbuchstaben, Ziffern und wenige
Sonderzeichen zu. Der Nutzer will den vollständigen Etikettentext sehen, nicht
nur die von der App verstandenen Felder - die Whitelist deckt deshalb jetzt
Groß- und Kleinbuchstaben, Ziffern sowie die auf Etiketten üblichen Satz- und
Sonderzeichen ab. Das kann die Genauigkeit bei den Codeteilen (Kapazität,
Rank, Geschwindigkeit, Teilenummer) etwas verringern - eine bewusst in Kauf
genommene Abwägung, siehe Kommentar an Ort und Stelle.
grabFrameRegion() statt grabFrame(): "Modul scannen" bekam bisher das ganze
Kamerabild, auf 1280 Pixel herunterskaliert - der Zielrahmen war dabei rein
kosmetisch, obwohl er dem Nutzer einen wirksamen Ausschnitt suggeriert. Jetzt
liest die Texterkennung genau den Rahmenausschnitt, in nativer Auflösung -
denselben, den auch die laufende Barcode-Suche längst benutzt. Die
Dateiauswahl (onPickFile) bleibt unverändert beim Vollbild, da sie keinen
Zielrahmen kennt.
The function keeps reading all 2D-code types (QR-Code, MicroQRCode, RMQRCode,
DataMatrix, Aztec, PDF417) as requested. The label is now "QR-Code" per the
client's preference for their terminology. Added clarifying comments explaining
the intentional mismatch between the name and the supported formats, since the
hardware labels use DataMatrix (not QR). Updated README and test accordingly.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Der Auftraggeber hatte Funktion 2 ausdruecklich auf QR beschraenkt, obwohl
die 2D-Codes auf seinen RAM-Etiketten DataMatrix sind. Am Geraet zeigte sich,
dass die Funktion auf seiner Ware nichts fand - er hat die Entscheidung
revidiert. Funktion 2 liest jetzt zusaetzlich zu QRCode/MicroQRCode/RMQRCode
auch DataMatrix, Aztec und PDF417 und heisst in der Oberflaeche "2D-Code"
statt "QR-Code". Die Kennung bleibt aus historischen Gruenden `qrcode`.
Veralteten Kommentar in scan-modes.js berichtigt, Test auf die neue
Codeliste/Beschriftung umgestellt (statt geloescht) und einen Test ergaenzt,
der paarweise verschiedene Kennungen/Beschriftungen der drei Funktionen
erzwingt. README-Funktionstabelle und Geraete-Checkliste entsprechend
angepasst.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Funktionsweise-Abschnitt, Technik- und Aufbau-Tabelle sowie die
Geraete-Checkliste auf die neue Funktionswahl gebracht. Haelt fest,
dass in "Text erkennen" mangels Barcode-Teilenummer allein die
technischen Angaben ueber die Stapelzuordnung entscheiden, und dass
"QR-Code" bewusst kein DataMatrix liest. Testanzahl auf 143 aktualisiert.
Neuer Vollbild-Dialog (src/ui/mode-dialog.js) mit drei grossen Flaechen,
gebaut nach dem Muster der bestehenden Dialoge. Ablauf beim Start: erst
die Fortsetzen-Frage (falls eine gesicherte Sitzung vorliegt), dann die
Funktionswahl, erst danach startet die Kamera.
Die gewaehlte Funktion steht antippbar in der Scan-Ansicht und laesst
sich dort jederzeit wechseln - der Wechsel gilt sofort: laufende Suche
startet/stoppt, "Modul scannen" erscheint nur noch in Funktion "Text
erkennen", der Zielrahmen wird beim Wechsel weg von laufender Suche
zurueckgesetzt. pipeline.js bleibt unangetastet; main.js reicht je nach
Funktion nur unterschiedliche Adapter hinein (scan-recognition.js).
decodeBarcodes(imageData, formats) bekommt die zu suchenden Codearten
uebergeben; ohne Angabe unveraendertes Verhalten (Code128 + DataMatrix).
buildRecognitionAdapters() baut daraus und aus dem echten OCR-Adapter
die an recognize() (pipeline.js, unveraendert) uebergebenen Adapter:
in Strichcode/QR-Code liefert die Texterkennung sofort leeren Text ohne
Tesseract anzustossen, in Text-erkennen liefert die Barcode-Dekodierung
sofort eine leere Liste ohne zxing-wasm anzustossen.
Kennung, deutsche Beschriftung, Codearten, laufende Suche und
Texterkennung je Funktion an einer einzigen Stelle (src/scan-modes.js),
ohne Browser-Zugriff und damit unter Node pruefbar. Funktion "QR-Code"
enthaelt bewusst kein DataMatrix.
Der rote Dialog zeigte bisher immer "Nicht eindeutig", auch wenn die
Erkennung schlicht nichts Verwertbares geliefert hat (kein Barcode, kein
brauchbarer Klartext). Das verwirrt: es klingt nach mehreren Kandidaten,
obwohl gar keine Erkennung stattfand.
askForStack() bekommt einen expliziten Parameter nothingRecognized, da
sich die beiden Lagen nicht zweifelsfrei aus spec/candidates ableiten
lassen (main.js reicht bei "nichts erkannt" als Rueckfall alle
vorhandenen Stapel als candidates durch). main.js setzt ihn anhand von
plan.kind === 'ambiguous' (echte Mehrdeutigkeit) vs. allem anderen
(nur wegen roter Konfidenz im Dialog).
Signatur, Rueckgabeform, Schaltflaechen, Klassennamen, die
Mehrfachausloese-Sperre und die inert-Handhabung bleiben unveraendert.
Solange Kamera laeuft und keine Erkennung/kein Dialog/keine
Sitzungsliste im Weg steht, sucht die App ~5x/s im Zielrahmen nach
Barcodes. Ein gefundener Code durchlaeuft denselben Weg wie der
Knopfdruck (processCapture). Sperrzeit von 2s plus Codevergleich
verhindert, dass ein laenger vor die Kamera gehaltenes Modul mehrfach
gebucht wird, ohne einen zuegigen Modulwechsel auszubremsen.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
scan-view.js setzt die Rahmenlage jetzt aus camera.js' FRAME_INSET
statt aus einem im Stilblatt duplizierten Wert. Neue Methode
setFrameDetected() faerbt den Rahmen gruen, sobald die Dauersuche
einen Barcode im Ausschnitt findet - schlichte Farbaenderung, keine
Animation.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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>
Ohne gueltiges Passwort gibt der Server weder Seite noch Skript heraus.
Das Passwort kommt aus APP_PASSWORD; fehlt die Variable, startet der Server
absichtlich nicht. /healthz bleibt passwortfrei, damit die Ueberwachung den
geschuetzten Dienst nicht faelschlich fuer ausgefallen haelt.