diff 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
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mupdf-source/thirdparty/zxing-cpp/core/src/Barcode.cpp	Mon Sep 15 11:43:07 2025 +0200
@@ -0,0 +1,248 @@
+/*
+* 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 "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()))
+#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->row(0).begin(), _symbol->width(), _symbol->height(), ImageFormat::Lum};
+}
+
+void Result::zint(unique_zint_symbol&& z)
+{
+	_zint = std::shared_ptr(std::move(z));
+}
+#endif
+
+bool Result::operator==(const Result& o) const
+{
+	// handle case where both are MatrixCodes first
+	if (!BarcodeFormats(BarcodeFormat::LinearCodes).testFlags(format() | o.format())) {
+		if (format() != o.format() || (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 (format() != o.format() || bytes() != o.bytes() || error() != o.error())
+		return false;
+
+	if (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