648aec24307c4eb875653866eef693f723d8a73b
[toast/barcode2cash.git] / qtapp / barcode2cash / mainwindow.cpp
1 #include <cstddef>
2 #include <zbar.h>
3 #include "mainwindow.h"
4 #include "ui_mainwindow.h"
5 #include <QDir>
6
7
8 /// converts a string like "123,45" (comma as decimal point) to 12345.
9 bool cashstr_to_currencycent(QString cash, CurrencyCent& cent) {
10     bool ok;
11     cent = cash.replace(",", "").toInt(&ok);
12     return ok;
13 }
14
15
16 /// returns true if the decoding was successful
17 bool decode_rksv(const QString& rksv_string, RksvParts& rksv_parts) {
18     // https://github.com/a-sit-plus/at-registrierkassen-mustercode/releases/download/1.2-DOK/2016-09-05-Detailfragen-RKSV-V1.2.pdf
19     auto parts = rksv_string.split("_");
20     if (parts.size() != 14) return false; // QR code found but not RKSV
21     if (!parts.takeFirst().isEmpty()) return false;
22     rksv_parts.rlat = parts.takeFirst();
23     if (!rksv_parts.rlat.startsWith("R1-")) return false; // e.g. "R1-AT1"
24     rksv_parts.device_id = parts.takeFirst(); // e.g. "603002101"
25     rksv_parts.receipt_id = parts.takeFirst(); // e.g. "1/603002101/691/10340"
26     rksv_parts.date_time = QDateTime::fromString(parts.takeFirst(), "yyyy-MM-ddThh:mm:ss");
27     if (!rksv_parts.date_time.isValid()) return false;
28     for (int i = 0; i != RksvParts::cash_count; ++i) {
29         if (!cashstr_to_currencycent(parts.takeFirst(), rksv_parts.cash[i])) return false;
30     }
31     rksv_parts.counter = parts.takeFirst(); // e.g. "9IY7hV1mTqhVd4bii4gIhw=="
32     rksv_parts.cert_serial = parts.takeFirst();  // e.g. "5660C34F"
33     rksv_parts.sig_prev = parts.takeFirst(); // e.g. "I8/Wa2TZWgw="
34     rksv_parts.sig = parts.takeFirst(); // e.g."eSmlrKimgzbtYBJXq0MzwmgI3fBDL+NfSjzfFCCdcZuoHC+LET8BGvmVGWAwmNSZnDD2tCewJ7AooQc0Bt0HcQ=="
35     return true;
36 }
37
38
39 bool checkCameraAvailability()
40 {
41     if (QCameraInfo::availableCameras().count() > 0)
42         return true;
43     else
44         return false;
45 }
46
47 MainWindow::MainWindow(QWidget *parent) :
48     QMainWindow(parent),
49     ui(new Ui::MainWindow)
50 {
51     ui->setupUi(this);
52
53     QCameraInfo info = QCameraInfo::defaultCamera();
54     if (!info.isNull()) {
55         camera = new QCamera(info);
56         camera->setCaptureMode(QCamera::CaptureStillImage);
57         camera->setViewfinder(ui->viewFinder);
58         imageCapture = new QCameraImageCapture(camera);
59         connect(imageCapture, SIGNAL(readyForCaptureChanged(bool)), SLOT(updateCameraInfo()));
60         connect(imageCapture, SIGNAL(imageSaved(int,QString)), SLOT(showCaptureSuccess(int,QString)));
61         connect(imageCapture, SIGNAL(error(int,QCameraImageCapture::Error,QString)), SLOT(showCaptureError(int,QCameraImageCapture::Error,QString)));
62         updateCameraInfo();
63         connect(ui->pbCapture, SIGNAL(clicked()), SLOT(capture()));
64         QImageEncoderSettings imageSettings;
65         imageSettings.setCodec("image/jpeg");
66         imageCapture->setEncodingSettings(imageSettings);
67         camera->start();
68     }
69
70
71     ui->statusBar->showMessage(tr("There are %1 cameras").arg(checkCameraAvailability()));
72
73 }
74
75 MainWindow::~MainWindow() {
76     delete imageCapture;
77     delete camera;
78     delete ui;
79 }
80
81
82 void MainWindow::updateRksv(const RksvParts& rksv) {
83     ui->le_rlat->setText(rksv.rlat);
84     ui->le_device_id->setText(rksv.device_id);
85     ui->le_receipt_id->setText(rksv.receipt_id);
86     ui->dte_date_time->setDateTime(rksv.date_time);
87     ui->le_counter->setText(rksv.counter);
88     ui->le_cert_serial->setText(rksv.cert_serial);
89     ui->le_sig_prev->setText(rksv.sig_prev);
90     ui->le_sig->setText(rksv.sig);
91     for (int i = 0; i != RksvParts::cash_count; ++i) {
92         QString text = tr("%1").arg(double(rksv.cash[i]) / 100);
93         QTableWidgetItem* item = new QTableWidgetItem(text);
94         ui->twCash->setItem(i, 0, item);
95     }
96 }
97
98
99 void MainWindow::updateCameraInfo() {
100     ui->labCameraReady->setText(imageCapture->isReadyForCapture() ? "ready" : "not ready");
101 }
102
103
104 void MainWindow::capture() {
105     camera->searchAndLock();
106     imageCapture->capture(QDir::homePath() + "/test.jpg"); // default: saves to $HOME under Linux, to %USERPROFILE%\Pictures under Windows, so let's unify
107     camera->unlock();
108 }
109
110
111 void MainWindow::showCaptureSuccess(int, QString fileName) {
112     ui->statusBar->showMessage(tr("Image captured and saved as '%1'.").arg(fileName));
113 }
114
115
116 void MainWindow::showCaptureError(int, QCameraImageCapture::Error error, QString errorString) {
117     ui->statusBar->showMessage(tr("Error when capturing image (error id %2): %1.").arg(errorString).arg(error));
118 }
119
120
121 void MainWindow::analyze() {
122     QImage qimage(QDir::homePath() + "/test.jpg"); // default: read from $HOME under Linux, from whereever under Windows, so let's be explicit
123     if (qimage.isNull()) {
124         ui->labAnalyzeImage->setText("Can't read image");
125         return;
126     }
127     qimage = qimage.convertToFormat(QImage::Format_Grayscale8);
128     auto zbimage = zbar::Image(qimage.width(), qimage.height(), "GREY", qimage.constBits(), qimage.byteCount());
129     auto scanner = zbar::ImageScanner();
130     auto scan_results = scanner.scan(zbimage);
131     if (scan_results > 0) {
132         auto results = scanner.get_results();
133         for (auto resit = results.symbol_begin(); resit != results.symbol_end(); ++ resit) {
134             if (resit->get_type() == zbar::ZBAR_QRCODE) {
135                 QString qrcode_data = QString::fromStdString(resit->get_data());
136                 RksvParts rksv_parts;
137                 if (decode_rksv(qrcode_data, rksv_parts)) {
138                     updateRksv(rksv_parts);
139                     break;
140                 }
141             }
142         }
143     }
144
145     if (qimage.width() > 500) qimage = qimage.scaledToWidth(500);
146     ui->labAnalyzeImage->setPixmap(QPixmap::fromImage(qimage));
147 }