forked from zxing-cpp/zxing-cpp
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathBarcode.cpp
More file actions
269 lines (220 loc) · 7.43 KB
/
Copy pathBarcode.cpp
File metadata and controls
269 lines (220 loc) · 7.43 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
/*
* Copyright 2016 Nu-book Inc.
* Copyright 2016 ZXing authors
*/
// SPDX-License-Identifier: Apache-2.0
#include "Barcode.h"
#include "DecoderResult.h"
#include "DetectorResult.h"
#include "JSON.h"
#include "ZXAlgorithms.h"
#ifdef ZXING_EXPERIMENTAL_API
#include "BitMatrix.h"
#ifdef ZXING_USE_ZINT
#include <zint.h>
void zint_symbol_deleter::operator()(zint_symbol* p) const noexcept
{
ZBarcode_Delete(p);
}
#else
struct zint_symbol {};
void zint_symbol_deleter::operator()(zint_symbol*) const noexcept {}
#endif
#endif
#include <cmath>
#include <list>
#include <map>
#include <utility>
namespace ZXing {
Result::Result(const std::string& text, int y, int xStart, int xStop, BarcodeFormat format, SymbologyIdentifier si, Error error, bool readerInit)
: _content({ByteArray(text)}, si),
_error(error),
_position(Line(y, xStart, xStop)),
_format(format),
_readerInit(readerInit)
{}
Result::Result(DecoderResult&& decodeResult, DetectorResult&& detectorResult, BarcodeFormat format)
: _content(std::move(decodeResult).content()),
_error(std::move(decodeResult).error()),
_position(std::move(detectorResult).position()),
_sai(decodeResult.structuredAppend()),
_format(format),
_lineCount(decodeResult.lineCount()),
_isMirrored(decodeResult.isMirrored()),
_readerInit(decodeResult.readerInit())
#ifdef ZXING_EXPERIMENTAL_API
, _symbol(std::make_shared<BitMatrix>(std::move(detectorResult).bits()))
, _json(std::move(decodeResult).json())
#endif
{
if (decodeResult.versionNumber())
snprintf(_version, 4, "%d", decodeResult.versionNumber());
snprintf(_ecLevel, 4, "%s", decodeResult.ecLevel().data());
// TODO: add type opaque and code specific 'extra data'? (see DecoderResult::extra())
}
Result::Result(DecoderResult&& decodeResult, Position&& position, BarcodeFormat format)
: Result(std::move(decodeResult), {{}, std::move(position)}, format)
{}
bool Result::isValid() const
{
return format() != BarcodeFormat::None && !_content.bytes.empty() && !error();
}
const ByteArray& Result::bytes() const
{
return _content.bytes;
}
ByteArray Result::bytesECI() const
{
return _content.bytesECI();
}
std::string Result::text(TextMode mode) const
{
return _content.text(mode);
}
std::string Result::text() const
{
return text(_readerOpts.textMode());
}
std::string Result::ecLevel() const
{
return _ecLevel;
}
ContentType Result::contentType() const
{
return _content.type();
}
bool Result::hasECI() const
{
return _content.hasECI;
}
int Result::orientation() const
{
constexpr auto std_numbers_pi_v = 3.14159265358979323846; // TODO: c++20 <numbers>
return narrow_cast<int>(std::lround(_position.orientation() * 180 / std_numbers_pi_v));
}
std::string Result::symbologyIdentifier() const
{
return _content.symbology.toString();
}
int Result::sequenceSize() const
{
return _sai.count;
}
int Result::sequenceIndex() const
{
return _sai.index;
}
std::string Result::sequenceId() const
{
return _sai.id;
}
std::string Result::version() const
{
return _version;
}
Result& Result::setReaderOptions(const ReaderOptions& opts)
{
if (opts.characterSet() != CharacterSet::Unknown)
_content.defaultCharset = opts.characterSet();
_readerOpts = opts;
return *this;
}
#ifdef ZXING_EXPERIMENTAL_API
void Result::symbol(BitMatrix&& bits)
{
bits.flipAll();
_symbol = std::make_shared<BitMatrix>(std::move(bits));
}
ImageView Result::symbol() const
{
return _symbol && !_symbol->empty() ? ImageView{_symbol->row(0).begin(), _symbol->width(), _symbol->height(), ImageFormat::Lum}
: ImageView{};
}
void Result::zint(unique_zint_symbol&& z)
{
_zint = std::shared_ptr(std::move(z));
}
std::string Result::extra(std::string_view key) const
{
if (key == "ALL") {
if (format() == BarcodeFormat::None)
return {};
auto res =
StrCat("{", JsonProp("Text", text(TextMode::Plain)), JsonProp("HRI", text(TextMode::HRI)),
JsonProp("TextECI", text(TextMode::ECI)), JsonProp("Bytes", text(TextMode::Hex)),
JsonProp("Identifier", symbologyIdentifier()), JsonProp("Format", ToString(format())),
JsonProp("ContentType", isValid() ? ToString(contentType()) : ""), JsonProp("Position", ToString(position())),
JsonProp("HasECI", hasECI()), JsonProp("IsMirrored", isMirrored()), JsonProp("IsInverted", isInverted()), _json,
JsonProp("Error", ToString(error())));
res.back() = '}';
return res;
}
return _json.empty() ? "" : key.empty() ? StrCat("{", _json.substr(0, _json.size() - 1), "}") : std::string(JsonGetStr(_json, key));
}
#endif
bool Result::operator==(const Result& o) const
{
if (format() != o.format())
return false;
// handle MatrixCodes first
if (!IsLinearBarcode(format())) {
if (bytes() != o.bytes() && isValid() && o.isValid())
return false;
// check for equal position if both are valid with equal bytes or at least one is in error
return IsInside(Center(o.position()), position());
}
if (bytes() != o.bytes() || error() != o.error() || orientation() != o.orientation())
return false;
if (lineCount() > 1 && o.lineCount() > 1)
return HaveIntersectingBoundingBoxes(o.position(), position());
// the following code is only meant for this or other lineCount == 1
assert(lineCount() == 1 || o.lineCount() == 1);
// sl == single line, ml = multi line
const auto& sl = lineCount() == 1 ? *this : o;
const auto& ml = lineCount() == 1 ? o : *this;
// If one line is less than half the length of the other away from the
// latter, we consider it to belong to the same symbol.
// Additionally, both need to have roughly the same length (see #367).
auto dTop = maxAbsComponent(ml.position().topLeft() - sl.position().topLeft());
auto dBot = maxAbsComponent(ml.position().bottomLeft() - sl.position().topLeft());
auto slLength = maxAbsComponent(sl.position().topLeft() - sl.position().bottomRight());
bool isHorizontal = sl.position().topLeft().y == sl.position().bottomRight().y;
// Measure the multi line length in the same direction as the single line one (not diagonaly)
// to make sure overly tall symbols don't get segmented (see #769).
auto mlLength = isHorizontal ? std::abs(ml.position().topLeft().x - ml.position().bottomRight().x)
: std::abs(ml.position().topLeft().y - ml.position().bottomRight().y);
return std::min(dTop, dBot) < slLength / 2 && std::abs(slLength - mlLength) < slLength / 5;
}
Barcode MergeStructuredAppendSequence(const Barcodes& barcodes)
{
if (barcodes.empty())
return {};
std::list<Barcode> allBarcodes(barcodes.begin(), barcodes.end());
allBarcodes.sort([](const Barcode& r1, const Barcode& r2) { return r1.sequenceIndex() < r2.sequenceIndex(); });
Barcode res = allBarcodes.front();
for (auto i = std::next(allBarcodes.begin()); i != allBarcodes.end(); ++i)
res._content.append(i->_content);
res._position = {};
res._sai.index = -1;
if (allBarcodes.back().sequenceSize() != Size(allBarcodes) ||
!std::all_of(allBarcodes.begin(), allBarcodes.end(),
[&](Barcode& it) { return it.sequenceId() == allBarcodes.front().sequenceId(); }))
res._error = FormatError("sequenceIDs not matching during structured append sequence merging");
return res;
}
Barcodes MergeStructuredAppendSequences(const Barcodes& barcodes)
{
std::map<std::string, Barcodes> sas;
for (auto& barcode : barcodes) {
if (barcode.isPartOfSequence())
sas[barcode.sequenceId()].push_back(barcode);
}
Barcodes res;
for (auto& [id, seq] : sas) {
auto barcode = MergeStructuredAppendSequence(seq);
if (barcode.isValid())
res.push_back(std::move(barcode));
}
return res;
}
} // namespace ZXing