Wie Scannt Man Barcodes in einer Qt-QML-Anwendung?

Qt QML-Entwicklung
2025-01-23
8 Minuten
Wie man Barcodes in einer Qt QML-Anwendung scannt

Viele Anwendungen benötigen unter anderem einen Barcode-Scanner. Diese Funktion existiert schon seit langer Zeit, ebenso wie fertige Implementierungen dafür.

Doch die Zeit vergeht, und alte Lösungen werden ineffizient oder gar nicht mehr kompatibel. Aus diesem Grund haben wir uns entschieden, eine Barcode-Wrapper-Lösung für Qt- und QML-Projekte zu entwickeln, die auf dem neuesten Stand ist und modernen Programmierstandards entspricht.

In diesem Beitrag erfahren Sie, wie diese Lösung funktioniert und wie Sie mithilfe unseres benutzerdefinierten Wrappers Barcodes in Ihrer QML-Anwendung scannen können.

 

Funktionen und Idee hinter SCodes

Die ZXing-Bibliothek ist eine beliebte Bibliothek zum Scannen und Generieren von Barcodes und QR-Codes, die ursprünglich in Java geschrieben wurde.

Die Funktionen dieser Bibliothek wurden auch in anderen Technologien benötigt, weshalb es viele Ports dieser Bibliothek für andere Programmiersprachen gibt.

Es gibt auch einen Qt-C++-Port, der jedoch ursprünglich um 2011 veröffentlicht wurde. Daher hatten wir das Gefühl, dass etwas Neues notwendig ist.

So entstand die Idee für SCodes. Wir haben den neuesten C++-Port der ZXing-Bibliothek als Grundlage genommen, der in modernem C++17 geschrieben wurde, um ihn an die Anforderungen heutiger Projekte anzupassen.

Diese Bibliothek ermöglicht das Dekodieren von sowohl 1D- als auch 2D-Barcodes – SCodes umschließt diese Funktionalität, um sie in Qt-Projekten nutzen zu können.

Der Hauptfokus lag darauf, sie mit einer Kamera in mobilen QML-Anwendungen zu verwenden, aber die Bibliothek wird auch auf Desktops unterstützt und kann dort ausgeführt werden.

Die Bibliothek ermöglicht auch das Generieren von Barcodes, aber dieses Thema wird in einem unserer nächsten Blogbeiträge behandelt.

Derzeit ermöglicht SCodes das Scannen von nur zwei Barcode-Typen – Code 128 und QR Code. Die Möglichkeit, den Benutzern zu erlauben, die gewünschten Barcode-Typen selbst festzulegen, steht jedoch bereits auf unserer To-Do-Liste.

Den Wrapper finden Sie auf unserem Github, zusammen mit einer einfachen Schritt-für-Schritt-Anleitung, wie Sie ihn in Ihr Projekt einbinden können.

 

Einblicke in die Entwicklung

Werfen wir einen kurzen Blick darauf, wie der Wrapper implementiert wurde. Die ursprüngliche ZXing-C++-Bibliothek enthält keinerlei Funktionen in Bezug auf QML oder Kameras.

Um Barcodes zu scannen, benötigt die Bibliothek ein Bild, das nichts anderes als ein Byte-Array ist.

Wie erhält man also ein Bild aus dem QML-Kamera-Typ? Eine der Lösungen besteht darin, einen benutzerdefinierten QAbstractVideoFilter zu schreiben, der eine direkte Bildverarbeitung in Zusammenarbeit mit dem QML-VideoOutput-Typ ermöglicht.

Das kann folgendermaßen umgesetzt werden:

class SBarcodeFilter : public QAbstractVideoFilter

 

{
    Q_OBJECT
public:
    explicit SBarcodeFilter(QObject *parent = nullptr);
    QVideoFilterRunnable * createFilterRunnable() override {
        return new SBarcodeFilterRunnable();
    }
}

Den genauen Code finden Sie auf dem GitHub-Repository von SCodes, und die hier gezeigten Codebeispiele dienen nur als Beispiele.

Wie Sie sehen können, haben wir QAbstractVideoFilter erweitert, indem wir die Methode createFilterRunnable überschrieben haben.

Diese Methode wird verwendet, um eine Instanz der entsprechenden Unterklasse von QVideoFilterRunnable zurückzugeben.

Es ist notwendig, die Bilddekodierung in einem separaten Thread durchzuführen. Werfen wir also einen Blick darauf, wie das aussehen könnte.

 

class SBarcodeFilterRunnable: public QVideoFilterRunnable
{
public:
    SBarcodeFilterRunnable() { }
    QVideoFrame run(QVideoFrame *input,
                    const QVideoSurfaceFormat &surfaceFormat,
                    QVideoFilterRunnable::RunFlags flags) override
    {
        Q_UNUSED(surfaceFormat);
        Q_UNUSED(flags);
        const QImage croppedCapturedImage = SBarcodeDecoder::videoFrameToImage(*input, _filter->captureRect().toRect());
        // you have an image now. Have fun with it.
        return *input;
    }
};

In der Unterklasse von QVideoFilterRunnable müssen wir die Methode run(…) überschreiben, um den Eingabe-Video-Frame asynchron zu verarbeiten.

Um eine QImage-Instanz aus einem QVideoFrame zu erhalten, haben wir eine benutzerdefinierte statische Methode implementiert, die QVideoFrame und QRect als Parameter benötigt.

Der zweite Parameter (QRect) könnte überflüssig sein, wenn Sie Video-Filter für andere Zwecke verwenden. In unserem Fall besteht jedoch die Möglichkeit, nur einen ausgewählten Bereich des Bildschirms zu scannen. Dafür wird das Rechteck als Parameter verwendet.

 

QImage SBarcodeDecoder::videoFrameToImage(const QVideoFrame &videoFrame, const QRect &captureRect)
{
    if (videoFrame.handleType() == QAbstractVideoBuffer::NoHandle) {
        const QImage::Format imageFormat = QVideoFrame::imageFormatFromPixelFormat(videoFrame.pixelFormat());
        QImage image(videoFrame.bits(),
                     videoFrame.width(),
                     videoFrame.height(),
                     videoFrame.bytesPerLine(),
                     imageFormat);
        if (image.isNull()) {
            return QImage();
        }
        if ( image.format() != QImage::Format_ARGB32) {
            image = image.convertToFormat(QImage::Format_ARGB32);
        }
        return image.copy(captureRect);
    }
    if (videoFrame.handleType() == QAbstractVideoBuffer::GLTextureHandle) {
        QImage image(videoFrame.width(), videoFrame.height(), QImage::Format_ARGB32);
        GLuint textureId = static_cast<GLuint>(videoFrame.handle().toInt());
        QOpenGLContext* ctx = QOpenGLContext::currentContext();
        QOpenGLFunctions* f = ctx->functions();
        GLuint fbo;
        f->glGenFramebuffers( 1, &fbo);
        GLint prevFbo;
        f->glGetIntegerv(GL_FRAMEBUFFER_BINDING, &prevFbo);
        f->glBindFramebuffer(GL_FRAMEBUFFER, fbo);
        f->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureId, 0);
        f->glReadPixels(0, 0,  videoFrame.width(),  videoFrame.height(), GL_RGBA, GL_UNSIGNED_BYTE, image.bits());
        f->glBindFramebuffer( GL_FRAMEBUFFER, static_cast<GLuint>( prevFbo ) );
        return image.rgbSwapped().copy(captureRect);
    }
    return QImage();
}

Hier haben wir das Video entsprechend dem Handle-Typ des Video-Frames angepasst. Sobald wir unser Bild haben, können wir es weiterverarbeiten. Aber wie verwenden wir unseren benutzerdefinierten Video-Filter tatsächlich in QML?

Zuerst müssen Sie Ihre Klasse für QML verfügbar machen. Dazu müssen Sie beispielsweise in Ihrer main.cpp-Datei die folgende Zeile ausführen:

 

qmlRegisterType<SBarcodeFilter>("com.scythestudio.scodes", 1, 0, "SBarcodeFilter");

Qt 5.15 bietet einen neuen Ansatz, um C++-Klassen für QML verfügbar zu machen. Alles, was Sie tun müssen, ist, dieses Makro in die Klassendeklaration einzufügen:

 

QML_ELEMENT

Gehen Sie dann zu Ihrer .pro- oder .pri-Datei und fügen Sie diese zwei Zeilen hinzu:

 

QML_IMPORT_NAME = com.scythestudio.scodes
QML_IMPORT_MAJOR_VERSION = 1

Ändern Sie den Importnamen zu einem beliebigen String Ihrer Wahl und verwenden Sie die Importanweisung am Anfang Ihrer QML-Datei.

Sobald Ihre Klasse für QML verfügbar ist, müssen Sie in Ihrer .qml-Datei die Objekte Camera, VideoOutput und SBarcodeFilter erstellen.

 

import QtQuick 2.12
import QtMultimedia 5.12
import com.scythestudio.scodes1.0
 
ApplicationWindow {
  id: root
  visible: true
  Camera {
    id: camera
    // ...
  }
  VideoOutput {
    id: videoOutput
    source: camera
    anchors.fill: parent
    autoOrientation: true
    fillMode: VideoOutput.PreserveAspectCrop
    // add barcodeFilter to videoOutput's filters to enable catching barcodes
    filters: [
      barcodeFilter
    ]
  }
  SBarcodeFilter {
    id: barcodeFilter
    // ...
  }
}

Setzen Sie die Quelle des Videoausgangs auf ein Kamera-Objekt und fügen Sie Ihren Filter in die Filterliste des Videoausgangs ein – und lassen Sie die Magie geschehen. Das Video wird im Hintergrund asynchron verarbeitet.

 

3 Tipps zur Verbesserung des Barcode-Scannens

Eine gute Kamera ist entscheidend für erfolgreiches Barcode-Scannen

Die Kamera sollte eine hohe Auflösung und eine schnelle Bildrate haben, um sicherzustellen, dass der Barcode deutlich und schnell erfasst wird. Empfehlenswert ist auch eine Kamera mit Weitwinkelobjektiv, um mehr Flexibilität bei der Positionierung des Barcodes im Sichtfeld zu ermöglichen.

 

Beleuchtung ist ein wichtiger Faktor beim Scannen von Barcodes

Der Barcode sollte gut beleuchtet sein, damit er für die Kamera gut sichtbar ist. Vermeiden Sie das Scannen in schwach beleuchteten Bereichen oder Bereichen mit starkem Gegenlicht, da dies das Lesen des Barcodes erschweren kann. Es ist empfehlenswert, den Bereich, in dem Sie den Barcode scannen, gut zu beleuchten.

 

Das Anbringen des Barcodes im Scan-Rechteck ist ein wichtiger Schritt

Das Scanrechteck ist der Bereich auf dem Bildschirm, in dem die Kamera nach dem Strichcode sucht. Dieses Rechteck sollte so positioniert werden, dass der Strichcode zentriert ist und so viel wie möglich des Rechtecks ausfüllt. Dies trägt dazu bei, dass der Barcode korrekt gelesen wird und der Scanvorgang so effizient wie möglich ist. Berücksichtigen Sie außerdem die Größe und Ausrichtung des Barcodes und passen Sie das Rechteck entsprechend an, um den Scanvorgang zu optimieren.

 

Pläne für die Entwicklung

Besuchen Sie unser Github, um einen SCodes-Wrapper zu erhalten, falls Sie das noch nicht getan haben. Derzeit erlaubt der Wrapper das Scannen von Barcodes in den Formaten Code 128 und QR Code, aber wir planen noch einige Verbesserungen wie die Unterstützung für andere Barcode-Formate oder das Äquivalent von SCodes.pri mit CMake, um eine einfache Nutzung zu ermöglichen.

 

Zusammenfassung

Entdecken Sie die Möglichkeiten der plattformübergreifenden Entwicklung mit Qt. Lassen Sie sich von Scythe Studio dabei helfen, schnelle, zuverlässige und reaktionsschnelle Software für verschiedene Plattformen zu entwickeln, einschließlich Desktop, mobile und eingebettete Umgebungen. Genießen Sie blitzschnelle Leistung mit unserem C++-basierten Kern und den integrierten Modulen und APIs. Vertrauen Sie unserem Team von Qt-Experten, die Sie durch jeden Schritt des Entwicklungsprozesses begleiten, vom ersten Entwurf bis hin zu laufendem Support und Wartung. Kontaktieren Sie uns noch heute, um zu erfahren, wie wir Sie dabei unterstützen können, Ihre Qt QML-Projekte auf die nächste Stufe zu heben.

 

FAQs

Warum werden Barcodes nicht richtig gescannt?

Barcodes können aus verschiedenen Gründen nicht richtig gescannt werden. Diese Gründe können darin liegen, dass das Gerät nicht für die Barcodes geeignet ist, der Scanner nicht richtig bedient wird oder die Barcode-Etiketten nicht für die vorgesehene Anwendung oder Umgebung geeignet sind.

 

Kann man einen QR-Code intern scannen, ohne eine App eines Drittanbieters zu verwenden?

Die neuesten Versionen von Android- und iOS-Geräten unterstützen das interne Scannen von QR-Codes mit Google Lens oder der Live-Text-Option, sodass die Verwendung einer QR-Code-Scanner-App eines Drittanbieters nicht erforderlich ist, um einen QR-Code aus der Galerie zu scannen.

 

Wie kann ich feststellen, ob ein QR-Code statisch oder dynamisch ist?

Statische QR-Codes können nicht mehr geändert werden, sobald sie erstellt und gedruckt sind. Wenn die verlinkten Informationen veraltet sind, müssen Sie den QR-Code neu drucken. Dynamische QR-Codes hingegen können in Echtzeit bearbeitet und aktualisiert werden.

 

Wie kann man zwischen einem Code 128 und einem Code 39 Barcode unterscheiden?

Der Unterschied zwischen einem Code 128- und einem Code 39-Barcode lässt sich unter anderem an der Anzahl der Zeichen erkennen, die kodiert werden können. Code 39-Barcodes können nur 39 Zeichen kodieren, während Code 128-Barcodes eine höhere Dichte aufweisen und mehr Zeichen kodieren können. Außerdem enthalten Code 39-Barcodes keine Prüfziffer, Code 128-Barcodes hingegen schon.

Scythe-Studio - Chief Executive Officer

Łukasz Kosiński Chief Executive Officer

Brauchen Sie Qt QML-Entwicklungsdienste?

service partner

Kommen wir zur Sache: Es ist eine Herausforderung, Top-Qt-QML-Entwickler zu finden. Helfen Sie sich selbst und starten Sie die Zusammenarbeit mit Scythe Studio – echten Experten im Qt C++ Framework.

Entdecken Sie unsere Fähigkeiten!

Neueste Artikel

[ 156 ]