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