Mobile oder Web-App? Barcodes scannen mit Vue.js

von Andreas Scheidmeir
Barcodes Scannen in Vue.js

Bei einem unserer Kunden kam der Wunsch auf, mittels der integrierten Kamera von Tablets Barcodes zu scannen, um einen vorhandenen Workflow zu beschleunigen. Der Kunde erwartete eine Mobile App, die auf den internen Tablets ausgerollt werden kann. Das so etwas möglich ist, haben wir im Blogpost Barcodes Scannen mit Google Flutter demonstriert. Doch nur weil etwas möglich ist, ist es noch lange nicht der effizienteste Weg.

Da wir in diesem Fall nicht auf der grünen Wiese entwickeln, sondern bereits eine Web-Applikation in Form eines Java Backends mit Vue.js Oberfläche vorliegt, könnte das nicht einfacher, schneller und vor allem billiger gelöst werden? Nur um den Zugriff auf die Kamera zu gewähren ist keine Mobile-App von Nöten. Dank moderner HTML5 APIs ist der Zugriff auf gerätespezifische Hardware wie der Kamera über den Browser möglich. Wie das im Fall von Vue.js umgesetzt werden kann, möchte ich in diesem Blogpost beispielhaft beschreiben.

Voraussetzungen für das Barcode-Scannen in Vue.js

Da in der vorliegenden Implementierung für das Styling vue-bootstrap zum Einsatz kommt, baut auch das Beispiel auf dem Framework auf und macht sich dessen Styling und Elemente zu Nutze. Eine entsprechende Vue.js App mit Bootstrap wird also als gegeben vorausgesetzt und nicht weiter im Blogpost erklärt.

Für das eigentliche Scannen der Barcodes setzen wir auf das Plugin vue-barcode-reader, welches ein Wrapper für die JS-Bibliothek ZXing ist. Diese erlaubt das Scannen von diversen Formaten, sowohl 1D als auch 2D. Eine genaue Auflistung der unterstützen Formate findet sich auf der GitHub Seite des Projekts.

Installation des Plugins

Um Vue Barcode Reader zu installieren, muss lediglich der folgende Befehl im Projektverzeichnis ausgeführt werden:

npm install vue-barcode-reader --save

Hinweis: Im Fall einer Vue2 App, muss auf den Stand vue-barcode-reader@0.0.3 zurückgegriffen werden.

Einbindung des Scanners in Vue.js

Für die Nutzung stellt das Plugin zwei Komponenten zur Verfügung: Zum einen den StreamBarcodeReader, der das Scannen über die aktive Kamera ermöglicht, zum anderen ImageBarcodeReader, der mittels eines vorhandenen Bildes versucht, Barcodes zu decodieren. Beide Komponenten bieten die Callbacks loaded und decode an. Wie die Namen vermuten lassen, gibt loaded Aufschluss darüber, wenn der Scanner einsatzbereit ist und decode liefert im Erfolgsfall das Resultat zurück.

In unserem Beispiel nutzen wir die Videokamera mittels StreamBarcodeReader. Dafür binden wir die Komponente in ein Bootstrap-Modal ein, das über einen Button geöffnet werden kann.

<b-input-group>
  <b-form-input size="lg" v-model="code" placeholder="" />
  <b-input-group-append>
    <b-button v-b-modal.scanner-modal variant="primary">Scan</b-button>
  </b-input-group-append>
</b-input-group><b-modal id="scanner-modal" centered hide-footer title="Scanner">
  <StreamBarcodeReader @decode="onDecode" @loaded="onLoaded" />
</b-modal>
…
import { StreamBarcodeReader } from 'vue-barcode-reader'
…
components: { StreamBarcodeReader },
…

Beim Klick oder Tab auf den Button öffnet sich das Modal und der Nutzer bekommt automatisch Nachfrage, ob die aktuelle Seite auf die Kamera zugreifen darf. Sofern der Nutzer der Kameranutzung zustimmt, wird der Live-Stream angezeigt und kontinuierlich nach Barcodes durchsucht. Bei einem Treffer wird das Ergebnis als Text zurückgegeben und in der onDecode-Metode entgegengenommen, in das Model geschrieben und das Modal geschlossen. Damit endet der Stream und Kamerazugriff.

data() {
  return {
    code: "",
  };
},
methods: {
  onLoaded() {
    console.log("scanner ready");
  },
  onDecode(result) {
    this.code = result;
    this.$bvModal.hide("scanner-modal");
  },
},

Die beiden Callback-Methoden fallen in unserem Beispiel recht minimalistisch aus. Die erste onLoaded dient nur dem Logging, dass die Komponente korrekt initialisiert wurde. In onDecode wird das Ergebnis des Scanners entgegengenommen, in das Model geschrieben und das Modal wieder ausgeblendet, um die Kameranutzung zu beenden. Zusätzlich könnte hier noch eine Fehlerbehandlung für den Misserfolg implementiert werden.

Wichtig: Die Api steht nur in einem Secure-Context (https und localhost) zur Verfügung!
Um einen Vue.js Dev-Server mit https zu starten, gibt es je nach Tooling verschiedene Konfigurationsmöglichkeiten.

Die möglichen Konfigurationen sind in der Dokumentation beschrieben:

Damit ist das gesetzte Ziel erreicht und das Scannen von Barcodes mittels der Geräte-eigenen Kamera ist möglich. Diese Lösung funktioniert auf allen Geräten mit Video-Input, auf denen ein moderner Browser läuft, sei es ein Smartphone, Tablet oder Laptop. Was aber, wenn das Gerät mehrere Kameras besitzt und wir Kontrolle über die Auswahl erlangen möchten, zum Beispiel, um gezielt eine angeschlossene Webcam zu nutzen? Eine Erweiterung hierfür wird im nächsten Abschnitt beschrieben.

Erweiterung: Kamera-Auswahl

Im Folgenden analysieren wir die Fähigkeiten des Plugins etwas genauer und lernen, wie man gezielt Kameras wählen kann.

Wie bereits beschrieben nutzt das Plugin im Hintergrund die Bibliothek ZXing für das Detektieren und Decodieren der Codes. Um das Beispiel zu erweitern, nutzen wir den Wrapper von vue-barcode-reader heran und ergänzen diesen, um mittels der sogenannten DeviceId bestimmen zu können, welche Kamera genutzt wird (z.B. Front und Rear-Cam). Der Code des Plugins kann hier eingesehen werden.

Für unser Beispiel erweitern wir den StreamBarcodeReader-Wrapper um die Kamera-Auswahl.

Original

methods: {
   start() {
     this.codeReader.decodeFromVideoDevice(undefined, this.$refs.scanner, (result, err) => {
       if (result) {
         this.$emit("decode", result.text);
         this.$emit("result", result);
       }
     });
   },
 },

Angepasst

methods: {
  async start(deviceId) {
    this.codeReader.decodeFromVideoDevice(
      deviceId,
      this.$refs.scanner,
      (result) => {
        if (result) {
          this.$emit("decode", result.text);
          this.$emit("result", result);
        }
      }
    );
  },
},

Der Unterschied liegt in der Übergabe der deviceId, welche dem CodeReader vorgibt, welche Kamera genutzt werden soll. Wird hier undefined übergeben, wird versucht, die Standard-Kamera zu nutzen (z.B. hintere Kamera am Handy). Damit können wir die Methode initial mit undefined aufrufen, bevor der Nutzer eine Auswahl getroffen hat, und direkt einen Stream präsentieren.

Original

mounted() {
  if (!this.isMediaStreamAPISupported) {
    throw new Exception("Media Stream API is not supported");
    return;
  }
  this.start();
  this.$refs.scanner.oncanplay = (event) => {
    this.isLoading = false;
    this.$emit("loaded");
  };
},

Angepasst

mounted() {
  if (!this.isMediaStreamAPISupported) {
    throw new Exception("Media Stream API is not supported");
    return;
  }
  this.start();
  this.$refs.scanner.oncanplay = () => {
    this.isLoading = false;
    this.$emit("loaded");
    console.log("VideoDevices:");
    this.codeReader.listVideoInputDevices().then((videoInputDevices) => {
      if (videoInputDevices.length >= 1) {
        videoInputDevices.forEach((element) => {
          console.log(element);
          const index = this.options.findIndex(
            (object) => object.value === element.deviceId
          );
          if (index === -1) {
            this.options.push({
              value: element.deviceId,
              text: element.label,
            });
          }
        });
      }
    });
  };
},

Für die Abfrage der verfügbaren Eingabegeräte stellt XZing die Methode listVideoInputDevices zur Verfügung. Dies ist aber erst möglich, nachdem die Erlaubnis zur Nutzung durch den Benutzer erteilt wurde. Ohne die Freigabe wird lediglich eine leere Liste durch den Browser zurückgegeben.

Daher starten wir zuerst den Scanner, was die initiale Abfrage auslöst, und sobald dieser geladen ist, werden weitere verfügbare Inputs gelistet und in die Optionen eines Select-Inputs geschrieben.

<b-form-select v-model="selected" :options="options"></b-form-select>

Beim Wechsel der Input-Kamera wird der Reader resettet und über die gewählte DevideId neu gestartet.

watch: {
  selected: function (deviceId) {
    this.isLoading = true;
    this.codeReader.reset();
    this.start(deviceId);
  },
},

Damit ist die Wahl der Kamera durch den Nutzer möglich.

Fazit zur Umsetzung in Vue.js

Dank moderner Browser Apis ist der Zugriff auf die Kameras von beliebigen Endgeräten möglich. Durch Open-Source-Lösungen für das Decodieren von Barcodes ist dies auch in Vue.js einfach umsetzbar und erlaubt auch die gezielte Wahl der Kameras, falls der Einsatzzweck einen Mehrwert daraus zieht.

Damit konnten wir nach Analyse der eigentlichen Problemstellung die Implementierung beschleunigen und eine erhebliche Kosteneinsparung für unseren Kunden erreichen.

Zurück

© 2006-2024 exensio GmbH
Einstellungen gespeichert
Datenschutzeinstellungen

Wir nutzen Cookies auf unserer Website. Einige von ihnen sind essenziell, während andere uns helfen, diese Website und Ihre Erfahrung zu verbessern.

Sie können Ihre Einwilligung jederzeit ändern oder widerrufen, indem Sie auf den Link in der Datenschutzerklärung klicken.

Zu den gesetzlichen Rechenschaftspflichten gehört die Einwilligung (Opt-In) zu protokollieren und archivieren. Aus diesem Grund wird Ihre Opt-In Entscheidung in eine LOG-Datei geschrieben. In dieser Datei werden folgende Daten gespeichert:

 

  • IP-Adresse des Besuchers
  • Vom Besucher gewählte Datenschutzeinstellung (Privacy Level)
  • Datum und Zeit des Speicherns
  • Domain
You are using an outdated browser. The website may not be displayed correctly. Close