
Qt 및 C/C++를 사용하여 데스크탑용 GUI 바코드 리더를 개발하는 방법
어떤 에디션Dynamsoft Barcode SDK을 사용하든 기본 알고리즘 인터페이스는 모두 C/C++로 구현됩니다. Dynamsoft 바코드 SDK를 정확하게 평가하려면 C++ 라이브러리를 시작하는 것이 좋습니다. 그러나 SDK 패키지에는 명령줄 샘플만 있습니다. 평범한 샘플 코드는 조작이 편하지 않아서 지겹다. 따라서 Qt를 사용하여 멋진 GUI 바코드 리더기를 작성하기로 결정했습니다. 이 기사에서는 Qt, MinGW, CMake 및 Dynamsoft C++ 바코드 SDK를 사용하여 Windows 및 Linux용 GUI 바코드 리더 애플리케이션을 개발하는 방법을 보여줍니다.
Dynamsoft C++ SDK v8.6
창
Qt Downloads를 방문하여 Windows용 Qt 설치 프로그램을 다운로드하십시오. 설치 프로그램은 Qt와 그 종속성을 자동으로 설치합니다.
Qt에는 MinGW 개발 환경이 포함되어 있지만

저는 Windows에서 CMake 및
리눅스
Linux에 Qt를 설치하는 것은 Windows보다 훨씬 쉽습니다.
템플릿

빌드 시스템으로

한 가지 주의할 점은 MinGW가 .lib 및 .dll 파일 연결을 지원한다는 것입니다. 다음과 같이 링크 라이브러리를 추가할 수 있습니다.
프로젝트를 빌드하려면 다음을 실행합니다.
C++ 클래스

코드를 C API로 교체하면 문제를 해결할 수 있습니다.
먼저

그런 다음 Qt UI 위젯을
다음은 슬롯 기능의 기본 구현입니다.
이미지 파일을 로드합니다.
폴더를 열고 폴더에 있는 모든 이미지 파일을 로드합니다.
목록 위젯의 클릭 이벤트를 트리거합니다.
바코드 이미지를 디코딩하여 결과를 표시합니다.
템플릿 파일을 로드하고 내보냅니다.
다음은 GUI 바코드 리더 애플리케이션을 실행하는 스크린샷입니다.

https://github.com/yushulx/Qt-desktop-barcode-reader
바코드 SDK 다운로드
Dynamsoft C++ SDK v8.6
Qt 설치
창
Qt Downloads를 방문하여 Windows용 Qt 설치 프로그램을 다운로드하십시오. 설치 프로그램은 Qt와 그 종속성을 자동으로 설치합니다.
Qt에는 MinGW 개발 환경이 포함되어 있지만
Visual Studio
는 내 환경에서 자동 감지되지 않습니다.
저는 Windows에서 CMake 및
msvc
를 사용하여 C++ 응용 프로그램을 빌드하는 데 익숙합니다. 하지만 그것은 중요하지 않습니다. Qt 프로젝트에 msvc
를 사용하는 방법을 알아내지 않겠습니다. 대신 Windows 응용 프로그램을 빌드하기 위해 GCC를 사용하는 것이 좋습니다. MinGW에서 제공하는 GCC 컴파일러를 사용하려면 Qt\6.1.2\mingw81_64\bin
환경 변수에 Qt\Tools\mingw810_64\bin
, PATH
를 추가해야 합니다.리눅스
Linux에 Qt를 설치하는 것은 Windows보다 훨씬 쉽습니다.
sudo apt-get install qt5-default
Windows 및 Linux용 CMake 구성
Qt Creator
를 사용하여 프로젝트의 골격을 빠르게 설정합니다.템플릿
Qt Widgets Application
을 선택합니다.
빌드 시스템으로
CMake
를 선택하십시오.
한 가지 주의할 점은 MinGW가 .lib 및 .dll 파일 연결을 지원한다는 것입니다. 다음과 같이 링크 라이브러리를 추가할 수 있습니다.
# 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")
CMAKE_HOST_WIN32
와 CMAKE_HOST_UNIX
를 사용하여 Windows와 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()
프로젝트를 빌드하려면 다음을 실행합니다.
mkdir build
cd build
###############################
# Windows with MinGW
cmake -G "MinGW Makefiles" ..
# Linux
cmake ..
###############################
cmake --build .
C++ 클래스
CBarcodeReader
를 사용하는 경우 Windows에서 프로젝트를 빌드할 때 undefined reference
오류가 발생할 수 있습니다.
코드를 C API로 교체하면 문제를 해결할 수 있습니다.
reader = DBR_CreateInstance();
데스크탑용 C++ GUI 바코드 리더 빌드
먼저
Qt Creator
를 사용하여 사용자 인터페이스를 디자인합니다.
그런 다음 Qt UI 위젯을
MainWindow
생성자의 슬롯 기능에 연결합니다.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()));
}
다음은 슬롯 기능의 기본 구현입니다.
이미지 파일을 로드합니다.
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);
}
폴더를 열고 폴더에 있는 모든 이미지 파일을 로드합니다.
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);
}
목록 위젯의 클릭 이벤트를 트리거합니다.
void MainWindow::listWidgetClicked(QListWidgetItem *item)
{
ui->statusbar->showMessage(QString(item->text()));
// Load the image file to QImage
QImage image(item->text());
}
바코드 이미지를 디코딩하여 결과를 표시합니다.
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);
}
}
템플릿 파일을 로드하고 내보냅니다.
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);
}
}
다음은 GUI 바코드 리더 애플리케이션을 실행하는 스크린샷입니다.

소스 코드
https://github.com/yushulx/Qt-desktop-barcode-reader