Prison

videoscannerworker.cpp
1/*
2 SPDX-FileCopyrightText: 2022 Volker Krause <vkrause@kde.org>
3 SPDX-License-Identifier: MIT
4*/
5
6#include "config-prison-scanner.h"
7#include "format_p.h"
8#include "scanresult_p.h"
9#include "videoscannerframe_p.h"
10#include "videoscannerworker_p.h"
11
12#include <QDebug>
13#include <QImage>
14#include <QTransform>
15
16#define ZX_USE_UTF8 1
17#include <ZXing/ReadBarcode.h>
18#include <ZXing/TextUtfEncoding.h>
19
20using namespace Prison;
21
22VideoScannerWorker::VideoScannerWorker(QObject *parent)
23 : QObject(parent)
24{
25 connect(this, &VideoScannerWorker::scanFrameRequest, this, &VideoScannerWorker::slotScanFrame, Qt::QueuedConnection);
26}
27
28void VideoScannerWorker::slotScanFrame(VideoScannerFrame frame)
29{
30#if ZXING_VERSION < QT_VERSION_CHECK(1, 4, 0)
31 ZXing::Result zxRes(ZXing::DecodeStatus::FormatError);
32#else
33 ZXing::Result zxRes;
34#endif
35 ZXing::DecodeHints hints;
36 hints.setFormats(frame.formats() == Format::NoFormat ? ZXing::BarcodeFormats::all() : Format::toZXing(frame.formats()));
37
38 frame.map();
39 switch (frame.pixelFormat()) {
40 case QVideoFrameFormat::Format_Invalid: // already checked before we get here
41 break;
42 // formats ZXing can consume directly
43 case QVideoFrameFormat::Format_ARGB8888:
44 case QVideoFrameFormat::Format_ARGB8888_Premultiplied:
45 case QVideoFrameFormat::Format_XRGB8888:
46 zxRes = ZXing::ReadBarcode({frame.bits(), frame.width(), frame.height(), ZXing::ImageFormat::XRGB, frame.bytesPerLine()}, hints);
47 break;
48 case QVideoFrameFormat::Format_BGRA8888:
49 case QVideoFrameFormat::Format_BGRA8888_Premultiplied:
50 case QVideoFrameFormat::Format_BGRX8888:
51 zxRes = ZXing::ReadBarcode({frame.bits(), frame.width(), frame.height(), ZXing::ImageFormat::BGRX, frame.bytesPerLine()}, hints);
52 break;
53 case QVideoFrameFormat::Format_ABGR8888:
54 case QVideoFrameFormat::Format_XBGR8888:
55 zxRes = ZXing::ReadBarcode({frame.bits(), frame.width(), frame.height(), ZXing::ImageFormat::XBGR, frame.bytesPerLine()}, hints);
56 break;
57 case QVideoFrameFormat::Format_RGBA8888:
58 case QVideoFrameFormat::Format_RGBX8888:
59 zxRes = ZXing::ReadBarcode({frame.bits(), frame.width(), frame.height(), ZXing::ImageFormat::RGBX, frame.bytesPerLine()}, hints);
60 break;
61 case QVideoFrameFormat::Format_AYUV:
62 case QVideoFrameFormat::Format_AYUV_Premultiplied:
63 zxRes = ZXing::ReadBarcode({frame.bits() + 1, frame.width(), frame.height(), ZXing::ImageFormat::Lum, frame.bytesPerLine(), 4}, hints);
64 break;
65 case QVideoFrameFormat::Format_YUV420P:
66 case QVideoFrameFormat::Format_YUV422P:
67 case QVideoFrameFormat::Format_YV12:
68 case QVideoFrameFormat::Format_NV12:
69 case QVideoFrameFormat::Format_NV21:
70 case QVideoFrameFormat::Format_IMC1:
71 case QVideoFrameFormat::Format_IMC2:
72 case QVideoFrameFormat::Format_IMC3:
73 case QVideoFrameFormat::Format_IMC4:
74 zxRes = ZXing::ReadBarcode({frame.bits(), frame.width(), frame.height(), ZXing::ImageFormat::Lum, frame.bytesPerLine()}, hints);
75 break;
76 case QVideoFrameFormat::Format_UYVY:
77 zxRes = ZXing::ReadBarcode({frame.bits() + 1, frame.width(), frame.height(), ZXing::ImageFormat::Lum, frame.bytesPerLine(), 2}, hints);
78 break;
79 case QVideoFrameFormat::Format_YUYV:
80 zxRes = ZXing::ReadBarcode({frame.bits(), frame.width(), frame.height(), ZXing::ImageFormat::Lum, frame.bytesPerLine(), 2}, hints);
81 break;
82 case QVideoFrameFormat::Format_Y8:
83 zxRes = ZXing::ReadBarcode({frame.bits(), frame.width(), frame.height(), ZXing::ImageFormat::Lum, frame.bytesPerLine()}, hints);
84 break;
85 case QVideoFrameFormat::Format_Y16:
86 zxRes = ZXing::ReadBarcode({frame.bits() + 1, frame.width(), frame.height(), ZXing::ImageFormat::Lum, frame.bytesPerLine(), 1}, hints);
87 break;
88 case QVideoFrameFormat::Format_P010:
89 case QVideoFrameFormat::Format_P016:
90 case QVideoFrameFormat::Format_YUV420P10:
91 zxRes = ZXing::ReadBarcode({frame.bits(), frame.width(), frame.height(), ZXing::ImageFormat::Lum, frame.bytesPerLine(), 1}, hints);
92 break;
93
94 // formats needing conversion before ZXing can consume them
95 case QVideoFrameFormat::Format_Jpeg:
96 case QVideoFrameFormat::Format_SamplerExternalOES:
97 case QVideoFrameFormat::Format_SamplerRect:
98 frame.convertToImage();
99 zxRes = ZXing::ReadBarcode({frame.bits(), frame.width(), frame.height(), ZXing::ImageFormat::Lum, frame.bytesPerLine()}, hints);
100 break;
101 }
102 frame.unmap();
103
104 // process scan result
105 ScanResult scanResult;
106 if (zxRes.isValid()) {
107 auto res = ScanResultPrivate::get(scanResult);
108
109#if ZXING_VERSION < QT_VERSION_CHECK(1, 4, 0)
110 // distinguish between binary and text content
111 const auto hasWideChars = std::any_of(zxRes.text().begin(), zxRes.text().end(), [](auto c) {
112 return c > 255;
113 });
114 const auto hasControlChars = std::any_of(zxRes.text().begin(), zxRes.text().end(), [](auto c) {
115 return c < 0x20 && c != 0x0a && c != 0x0d;
116 });
117 if (hasWideChars || !hasControlChars) {
118 res->content = QString::fromStdString(ZXing::TextUtfEncoding::ToUtf8(zxRes.text()));
119 } else {
120 QByteArray b;
121 b.resize(zxRes.text().size());
122 std::copy(zxRes.text().begin(), zxRes.text().end(), b.begin());
123 res->content = b;
124 }
125#else
126 if (zxRes.contentType() == ZXing::ContentType::Text) {
127 res->content = QString::fromStdString(zxRes.text());
128 } else {
129 QByteArray b;
130 b.resize(zxRes.bytes().size());
131 std::copy(zxRes.bytes().begin(), zxRes.bytes().end(), b.begin());
132 res->content = b;
133 }
134#endif
135
136 // determine the bounding rect
137 // the cooridinates we get from ZXing are a polygon, we need to determine the
138 // bounding rect manually from its coordinates
139 const auto p = zxRes.position();
140 int x1 = std::numeric_limits<int>::max();
141 int y1 = std::numeric_limits<int>::max();
142 int x2 = std::numeric_limits<int>::min();
143 int y2 = std::numeric_limits<int>::min();
144 for (int i = 0; i < 4; ++i) {
145 x1 = std::min(x1, p[i].x);
146 y1 = std::min(y1, p[i].y);
147 x2 = std::max(x2, p[i].x);
148 y2 = std::max(y2, p[i].y);
149 }
150 res->boundingRect = QRect(QPoint(x1, y1), QPoint(x2, y2));
151
152 // apply frame transformations to the bounding rect
153 if (frame.isVerticallyFlipped()) {
154 QTransform t;
155 t.scale(1, -1);
156 t.translate(0, -frame.height());
157 res->boundingRect = t.mapRect(res->boundingRect);
158 }
159
160 res->format = Format::toFormat(zxRes.format());
161 }
162
163 Q_EMIT result(scanResult);
164}
165
166void VideoScannerThread::run()
167{
168 exec();
169}
170
171#include "moc_videoscannerworker_p.cpp"
Result of a barcode scan attempt.
Definition scanresult.h:31
Provides classes and methods for generating barcodes.
Definition barcode.h:24
iterator begin()
void resize(qsizetype newSize, char c)
QString fromStdString(const std::string &str)
QueuedConnection
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
QRect mapRect(const QRect &rectangle) const const
QTransform & scale(qreal sx, qreal sy)
QTransform & translate(qreal dx, qreal dy)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:16:07 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.