No matter which edition of Dynamsoft Barcode SDK you use, the underlying algorithm interfaces are all implemented in C/C++. To evaluate Dynamsoft barcode SDK precisely, you'd better get started with the C++ libraries. However, there is only a command-line sample available in the SDK package. I have been tired of the plain sample code because it is not convenient for operation. Therefore, I decide to write a fancy GUI barcode reader using Qt. This article shows how to develop a GUI barcode reader application for Windows and Linux with Qt, MinGW, CMake, and Dynamsoft C++ barcode SDK.
Prerequisites
Qt Installation
Windows
Visit Qt Downloads and download the Qt installer for Windows. The installer will automatically install Qt and its dependencies.
Qt contains MinGW development environment, whereas Visual Studio
is not auto-detected in my environment.
I am used to build C++ applications with CMake and msvc
on Windows. But it doesn't matter. I am not going to figure out the way of using msvc
for Qt project. Instead, using GCC for building Windows application is a nice try. To use the GCC compiler provided by MinGW, you need to add Qt\6.1.2\mingw81_64\bin
and Qt\Tools\mingw810_64\bin
to the PATH
environment variable.
Linux
Installing Qt on Linux is much easier than Windows:
sudo apt-get install qt5-default
CMake Configuration for Windows and Linux
We use Qt Creator
to quickly set up the skeleton of our project.
One thing to note is that MinGW supports linking .lib and .dll files. You can add link libraries as follows:
# DBRx64.lib
target_link_libraries(${PROJECT_NAME} PRIVATE Qt${QT_VERSION_MAJOR}::Widgets "DBRx64")
# Or DynamsoftBarcodeReaderx64.dll
target_link_libraries(${PROJECT_NAME} PRIVATE Qt${QT_VERSION_MAJOR}::Widgets "DynamsoftBarcodeReaderx64")
We use CMAKE_HOST_WIN32
and CMAKE_HOST_UNIX
to distinguish Windows and Linux.
if (CMAKE_HOST_WIN32)
link_directories("${PROJECT_SOURCE_DIR}/platform/windows/bin/")
elseif(CMAKE_HOST_UNIX)
link_directories("${PROJECT_SOURCE_DIR}/platform/linux/")
endif()
if (CMAKE_HOST_WIN32)
target_link_libraries(${PROJECT_NAME} PRIVATE Qt${QT_VERSION_MAJOR}::Widgets "DynamsoftBarcodeReaderx64")
elseif(CMAKE_HOST_UNIX)
target_link_libraries(${PROJECT_NAME} PRIVATE Qt${QT_VERSION_MAJOR}::Widgets "DynamsoftBarcodeReader")
endif()
To build the project, run:
mkdir build
cd build
###############################
# Windows with MinGW
cmake -G "MinGW Makefiles" ..
# Linux
cmake ..
###############################
cmake --build .
If you use C++ class CBarcodeReader
, you may meet the undefined reference
error when building the project on Windows:
Replacing the code with C API can solve the issue:
reader = DBR_CreateInstance();
Building C++ GUI Barcode Reader for Desktop
First, we use Qt Creator
to design the user interface.
Then, connect the Qt UI widgets to slot functions in MainWindow
constructor:
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
protected:
void closeEvent(QCloseEvent *);
private:
Ui::MainWindow *ui;
void *reader;
void showImage(const QImage &image, QString fileName);
void showMessageBox(QString title, QString content);
private slots:
void openFile();
void openFolder();
void listWidgetClicked(QListWidgetItem *item);
void exportTemplate();
void about();
void setLicense();
void loadTemplate();
};
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
// Dynamsoft Barcode Reader
reader = DBR_CreateInstance();
// Open a file.
connect(ui->actionOpen_File, SIGNAL(triggered()), this, SLOT(openFile()));
// Open a folder.
connect(ui->actionOpen_Folder, SIGNAL(triggered()), this, SLOT(openFolder()));
// List widget event.
connect(ui->listWidget, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(listWidgetClicked(QListWidgetItem*)));
// Export template.
connect(ui->actionExport_template, SIGNAL(triggered()), this, SLOT(exportTemplate()));
// About dialog.
connect(ui->actionAbout, SIGNAL(triggered()), this, SLOT(about()));
// Set license.
connect(ui->actionEnter_License_Key, SIGNAL(triggered()), this, SLOT(setLicense()));
// Template load button
connect(ui->pushButton_template, SIGNAL(clicked()), this, SLOT(loadTemplate()));
// Template export button
connect(ui->pushButton_export_template, SIGNAL(clicked()), this, SLOT(exportTemplate()));
}
Here are the primary implementations of the slot functions:
-
Load an image file.
QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"), "", tr("Barcode images (*)")); if (!fileName.isEmpty()) { // Add to list ui->listWidget->addItem(fileName); ui->statusbar->showMessage(fileName); // Load the image file to QImage QImage image(fileName); }
-
Open a folder and load all the image files in the folder.
QString folderName = QFileDialog::getExistingDirectory(this, tr("Open Folder"), "", QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); if (!folderName.isEmpty()) { // Get all files in the folder QStringList fileNames = QDir(folderName).entryList(QDir::Files | QDir::NoDotAndDotDot); // Add to list for (int i = 0; i < fileNames.size(); i++) { ui->listWidget->addItem(QDir::cleanPath(folderName + QDir::separator() + fileNames.at(i))); } ui->statusbar->showMessage(folderName); }
-
Trigger the click event of list widget.
void MainWindow::listWidgetClicked(QListWidgetItem *item) { ui->statusbar->showMessage(QString(item->text())); // Load the image file to QImage QImage image(item->text()); }
-
Decode a barcode image and display the result.
void MainWindow::showImage(const QImage &image, QString fileName) { ui->textEdit_results->setText(""); if (!image.isNull()) { QPixmap pm = QPixmap::fromImage(image); QPainter painter(&pm); painter.setPen(Qt::red); /************************ * Barcode detection. ************************/ // Get the template content and initialize the runtime settings. QString content = ui->textEdit_results->toPlainText(); char errorMessage[256]; DBR_InitRuntimeSettingsWithString(reader, content.toStdString().c_str(), CM_OVERWRITE, errorMessage, 256); // Set barcode types. int types = 0, types2 = 0; if (ui->checkBox_code39->isChecked()) {types |= BF_CODE_39;} if (ui->checkBox_code93->isChecked()) {types |= BF_CODE_93;} if (ui->checkBox_code128->isChecked()){ types |= BF_CODE_128;} if (ui->checkBox_codabar->isChecked()){ types |= BF_CODABAR;} if (ui->checkBox_itf->isChecked()){ types |= BF_ITF;} if (ui->checkBox_ean13->isChecked()){ types |= BF_EAN_13;} if (ui->checkBox_ean8->isChecked()){ types |= BF_EAN_8;} if (ui->checkBox_upca->isChecked()){ types |= BF_UPC_A;} if (ui->checkBox_upce->isChecked()){ types |= BF_UPC_E;} if (ui->checkBox_industrial25->isChecked()){ types |= BF_INDUSTRIAL_25;} if (ui->checkBox_qrcode->isChecked()){ types |= BF_QR_CODE;} if (ui->checkBox_pdf417->isChecked()){ types |= BF_PDF417;} if (ui->checkBox_aztec->isChecked()){ types |= BF_AZTEC;} if (ui->checkBox_maxicode->isChecked()){ types |= BF_MAXICODE;} if (ui->checkBox_datamatrix->isChecked()){ types |= BF_DATAMATRIX;} if (ui->checkBox_gs1->isChecked()){ types |= BF_GS1_COMPOSITE;} if (ui->checkBox_patchcode->isChecked()){ types |= BF_PATCHCODE;} if (ui->checkBox_dotcode->isChecked()){ types2 |= BF2_DOTCODE;} if (ui->checkBox_postalcode->isChecked()){ types2 |= BF2_POSTALCODE;} PublicRuntimeSettings settings; DBR_GetRuntimeSettings(reader, &settings); settings.barcodeFormatIds = types; settings.barcodeFormatIds_2 = types2; DBR_UpdateRuntimeSettings(reader, &settings, errorMessage, 256); int errorCode = DBR_DecodeFile(reader, fileName.toStdString().c_str(), ""); TextResultArray *handler = NULL; DBR_GetAllTextResults(reader, &handler); if (handler->resultsCount == 0) { ui->textEdit_results->setText("No barcode found.\n"); DBR_FreeTextResults(&handler); return; } QString out = ""; TextResult **results = handler->results; for (int index = 0; index < handler->resultsCount; index++) { LocalizationResult* localizationResult = results[index]->localizationResult; out += "Index: " + QString::number(index) + "\n"; out += "Barcode format: " + QString(results[index]->barcodeFormatString) + "\n"; out += "Barcode value: " + QString(results[index]->barcodeText) + "\n"; out += "Bounding box: (" + QString::number(localizationResult->x1) + ", " + QString::number(localizationResult->y1) + ") " + "(" + QString::number(localizationResult->x2) + ", " + QString::number(localizationResult->y2) + ") " + "(" + QString::number(localizationResult->x3) + ", " + QString::number(localizationResult->y3) + ") " + "(" + QString::number(localizationResult->x4) + ", " + QString::number(localizationResult->y4) + ")\n"; out += "----------------------------------------------------------------------------------------\n"; painter.drawLine(localizationResult->x1, localizationResult->y1, localizationResult->x2, localizationResult->y2); painter.drawLine(localizationResult->x2, localizationResult->y2, localizationResult->x3, localizationResult->y3); painter.drawLine(localizationResult->x3, localizationResult->y3, localizationResult->x4, localizationResult->y4); painter.drawLine(localizationResult->x4, localizationResult->y4, localizationResult->x1, localizationResult->y1); } DBR_FreeTextResults(&handler); painter.end(); ui->label->setPixmap(pm.scaled(ui->label->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation)); ui->textEdit_results->setText(out); } }
-
Load and export the template file.
void MainWindow::loadTemplate() { QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"), "", tr("Barcode Template (*.json)")); QFile file(fileName); if (file.open(QIODevice::ReadOnly)) { QTextStream stream(&file); QString content = stream.readAll(); // DBR_LoadSettingsFromStringPtr(reader, content.toStdString().c_str()); ui->textEdit_template->setText(content); } } void MainWindow::exportTemplate() { QString fileName = QFileDialog::getSaveFileName(this, tr("Save File"), "", tr("Barcode Template (*.json)")); QFile file(fileName); if (file.open(QIODevice::ReadWrite)) { QTextStream stream(&file); char* pContent = NULL; DBR_OutputSettingsToStringPtr(reader, &pContent, "currentRuntimeSettings"); stream << QString(pContent); DBR_FreeSettingsString(&pContent); } }
Here is the screenshot of running the GUI barcode reader application.
Source Code
https://github.com/yushulx/cmake-cpp-barcode-qrcode/tree/main/examples/9.x/qt