chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,230 @@
|
||||
/*
|
||||
* Copyright 2016 Nu-book Inc.
|
||||
* Copyright 2016 ZXing authors
|
||||
* Copyright 2020 Axel Waggershauser
|
||||
*/
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BarcodeFormat.h"
|
||||
#include "ByteArray.h"
|
||||
#include "Content.h"
|
||||
#include "ReaderOptions.h"
|
||||
#include "Error.h"
|
||||
#include "ImageView.h"
|
||||
#include "Quadrilateral.h"
|
||||
#include "StructuredAppend.h"
|
||||
|
||||
#ifdef ZXING_EXPERIMENTAL_API
|
||||
#include <memory>
|
||||
namespace ZXing {
|
||||
class BitMatrix;
|
||||
|
||||
namespace BarcodeExtra {
|
||||
#define ZX_EXTRA(NAME) static constexpr auto NAME = #NAME
|
||||
ZX_EXTRA(DataMask); // QRCodes
|
||||
ZX_EXTRA(Version);
|
||||
ZX_EXTRA(EanAddOn); // EAN/UPC
|
||||
ZX_EXTRA(UPCE);
|
||||
#undef ZX_EXTRA
|
||||
} // namespace BarcodeExtra
|
||||
|
||||
} // namespace ZXing
|
||||
|
||||
extern "C" struct zint_symbol;
|
||||
struct zint_symbol_deleter
|
||||
{
|
||||
void operator()(zint_symbol* p) const noexcept;
|
||||
};
|
||||
using unique_zint_symbol = std::unique_ptr<zint_symbol, zint_symbol_deleter>;
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace ZXing {
|
||||
|
||||
class DecoderResult;
|
||||
class DetectorResult;
|
||||
class WriterOptions;
|
||||
class Result; // TODO: 3.0 replace deprected symbol name
|
||||
|
||||
using Position = QuadrilateralI;
|
||||
using Barcode = Result;
|
||||
using Barcodes = std::vector<Barcode>;
|
||||
using Results = std::vector<Result>;
|
||||
|
||||
/**
|
||||
* @brief The Barcode class encapsulates the result of decoding a barcode within an image.
|
||||
*/
|
||||
class Result
|
||||
{
|
||||
void setIsInverted(bool v) { _isInverted = v; }
|
||||
Result& setReaderOptions(const ReaderOptions& opts);
|
||||
|
||||
friend Barcode MergeStructuredAppendSequence(const Barcodes&);
|
||||
friend Barcodes ReadBarcodes(const ImageView&, const ReaderOptions&);
|
||||
friend Image WriteBarcodeToImage(const Barcode&, const WriterOptions&);
|
||||
friend void IncrementLineCount(Barcode&);
|
||||
|
||||
public:
|
||||
Result() = default;
|
||||
|
||||
// linear symbology convenience constructor
|
||||
Result(const std::string& text, int y, int xStart, int xStop, BarcodeFormat format, SymbologyIdentifier si, Error error = {},
|
||||
bool readerInit = false);
|
||||
|
||||
Result(DecoderResult&& decodeResult, DetectorResult&& detectorResult, BarcodeFormat format);
|
||||
|
||||
[[deprecated]] Result(DecoderResult&& decodeResult, Position&& position, BarcodeFormat format);
|
||||
|
||||
bool isValid() const;
|
||||
|
||||
const Error& error() const { return _error; }
|
||||
|
||||
BarcodeFormat format() const { return _format; }
|
||||
|
||||
/**
|
||||
* @brief bytes is the raw / standard content without any modifications like character set conversions
|
||||
*/
|
||||
const ByteArray& bytes() const; // TODO 3.0: replace ByteArray with std::vector<uint8_t>
|
||||
|
||||
/**
|
||||
* @brief bytesECI is the raw / standard content following the ECI protocol
|
||||
*/
|
||||
ByteArray bytesECI() const;
|
||||
|
||||
/**
|
||||
* @brief text returns the bytes() content rendered to unicode/utf8 text accoring to specified TextMode
|
||||
*/
|
||||
std::string text(TextMode mode) const;
|
||||
|
||||
/**
|
||||
* @brief text returns the bytes() content rendered to unicode/utf8 text accoring to the TextMode set in the ReaderOptions
|
||||
*/
|
||||
std::string text() const;
|
||||
|
||||
/**
|
||||
* @brief ecLevel returns the error correction level of the symbol (empty string if not applicable)
|
||||
*/
|
||||
std::string ecLevel() const;
|
||||
|
||||
/**
|
||||
* @brief contentType gives a hint to the type of content found (Text/Binary/GS1/etc.)
|
||||
*/
|
||||
ContentType contentType() const;
|
||||
|
||||
/**
|
||||
* @brief hasECI specifies wheter or not an ECI tag was found
|
||||
*/
|
||||
bool hasECI() const;
|
||||
|
||||
const Position& position() const { return _position; }
|
||||
void setPosition(Position pos) { _position = pos; }
|
||||
|
||||
/**
|
||||
* @brief orientation of barcode in degree, see also Position::orientation()
|
||||
*/
|
||||
int orientation() const;
|
||||
|
||||
/**
|
||||
* @brief isMirrored is the symbol mirrored (currently only supported by QRCode and DataMatrix)
|
||||
*/
|
||||
bool isMirrored() const { return _isMirrored; }
|
||||
|
||||
/**
|
||||
* @brief isInverted is the symbol inverted / has reveresed reflectance (see ReaderOptions::tryInvert)
|
||||
*/
|
||||
bool isInverted() const { return _isInverted; }
|
||||
|
||||
/**
|
||||
* @brief symbologyIdentifier Symbology identifier "]cm" where "c" is symbology code character, "m" the modifier.
|
||||
*/
|
||||
std::string symbologyIdentifier() const;
|
||||
|
||||
/**
|
||||
* @brief sequenceSize number of symbols in a structured append sequence.
|
||||
*
|
||||
* If this is not part of a structured append sequence, the returned value is -1.
|
||||
* If it is a structured append symbol but the total number of symbols is unknown, the
|
||||
* returned value is 0 (see PDF417 if optional "Segment Count" not given).
|
||||
*/
|
||||
int sequenceSize() const;
|
||||
|
||||
/**
|
||||
* @brief sequenceIndex the 0-based index of this symbol in a structured append sequence.
|
||||
*/
|
||||
int sequenceIndex() const;
|
||||
|
||||
/**
|
||||
* @brief sequenceId id to check if a set of symbols belongs to the same structured append sequence.
|
||||
*
|
||||
* If the symbology does not support this feature, the returned value is empty (see MaxiCode).
|
||||
* For QR Code, this is the parity integer converted to a string.
|
||||
* For PDF417 and DataMatrix, this is the "fileId".
|
||||
*/
|
||||
std::string sequenceId() const;
|
||||
|
||||
bool isLastInSequence() const { return sequenceSize() == sequenceIndex() + 1; }
|
||||
bool isPartOfSequence() const { return sequenceSize() > -1 && sequenceIndex() > -1; }
|
||||
|
||||
/**
|
||||
* @brief readerInit Set if Reader Initialisation/Programming symbol.
|
||||
*/
|
||||
bool readerInit() const { return _readerInit; }
|
||||
|
||||
/**
|
||||
* @brief lineCount How many lines have been detected with this code (applies only to linear symbologies)
|
||||
*/
|
||||
int lineCount() const { return _lineCount; }
|
||||
|
||||
/**
|
||||
* @brief version QRCode / DataMatrix / Aztec version or size.
|
||||
*/
|
||||
std::string version() const;
|
||||
|
||||
#ifdef ZXING_EXPERIMENTAL_API
|
||||
void symbol(BitMatrix&& bits);
|
||||
ImageView symbol() const;
|
||||
void zint(unique_zint_symbol&& z);
|
||||
zint_symbol* zint() const { return _zint.get(); }
|
||||
Result&& addExtra(std::string&& json) { _json += std::move(json); return std::move(*this); }
|
||||
// template<typename T>
|
||||
// Result&& addExtra(std::string_view key, T val, T ignore = {}) { _json += JsonProp(key, val, ignore); return std::move(*this); }
|
||||
std::string extra(std::string_view key = "") const;
|
||||
#endif
|
||||
|
||||
bool operator==(const Result& o) const;
|
||||
|
||||
private:
|
||||
Content _content;
|
||||
Error _error;
|
||||
Position _position;
|
||||
ReaderOptions _readerOpts; // TODO: 3.0 switch order to prevent 4 padding bytes
|
||||
StructuredAppendInfo _sai;
|
||||
BarcodeFormat _format = BarcodeFormat::None;
|
||||
char _ecLevel[4] = {};
|
||||
char _version[4] = {};
|
||||
int _lineCount = 0;
|
||||
bool _isMirrored = false;
|
||||
bool _isInverted = false;
|
||||
bool _readerInit = false;
|
||||
#ifdef ZXING_EXPERIMENTAL_API
|
||||
std::shared_ptr<BitMatrix> _symbol;
|
||||
std::shared_ptr<zint_symbol> _zint;
|
||||
std::string _json;
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Merge a list of Barcodes from one Structured Append sequence to a single barcode
|
||||
*/
|
||||
Barcode MergeStructuredAppendSequence(const Barcodes& results);
|
||||
|
||||
/**
|
||||
* @brief Automatically merge all Structured Append sequences found in the given list of barcodes
|
||||
*/
|
||||
Barcodes MergeStructuredAppendSequences(const Barcodes& barcodes);
|
||||
|
||||
} // ZXing
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright 2016 Nu-book Inc.
|
||||
* Copyright 2016 ZXing authors
|
||||
*/
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Flags.h"
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
namespace ZXing {
|
||||
|
||||
/**
|
||||
* Enumerates barcode formats known to this package.
|
||||
*/
|
||||
enum class BarcodeFormat
|
||||
{
|
||||
// The values are an implementation detail. The c++ use-case (ZXing::Flags) could have been designed such that it
|
||||
// would not have been necessary to explicitly set the values to single bit constants. This has been done to ease
|
||||
// the interoperability with C-like interfaces, the python and the Qt wrapper.
|
||||
None = 0, ///< Used as a return value if no valid barcode has been detected
|
||||
Aztec = (1 << 0), ///< Aztec
|
||||
Codabar = (1 << 1), ///< Codabar
|
||||
Code39 = (1 << 2), ///< Code39
|
||||
Code93 = (1 << 3), ///< Code93
|
||||
Code128 = (1 << 4), ///< Code128
|
||||
DataBar = (1 << 5), ///< GS1 DataBar, formerly known as RSS 14
|
||||
DataBarExpanded = (1 << 6), ///< GS1 DataBar Expanded, formerly known as RSS EXPANDED
|
||||
DataMatrix = (1 << 7), ///< DataMatrix
|
||||
EAN8 = (1 << 8), ///< EAN-8
|
||||
EAN13 = (1 << 9), ///< EAN-13
|
||||
ITF = (1 << 10), ///< ITF (Interleaved Two of Five)
|
||||
MaxiCode = (1 << 11), ///< MaxiCode
|
||||
PDF417 = (1 << 12), ///< PDF417
|
||||
QRCode = (1 << 13), ///< QR Code
|
||||
UPCA = (1 << 14), ///< UPC-A
|
||||
UPCE = (1 << 15), ///< UPC-E
|
||||
MicroQRCode = (1 << 16), ///< Micro QR Code
|
||||
RMQRCode = (1 << 17), ///< Rectangular Micro QR Code
|
||||
DXFilmEdge = (1 << 18), ///< DX Film Edge Barcode
|
||||
DataBarLimited = (1 << 19), ///< GS1 DataBar Limited
|
||||
|
||||
LinearCodes = Codabar | Code39 | Code93 | Code128 | EAN8 | EAN13 | ITF | DataBar | DataBarExpanded | DataBarLimited
|
||||
| DXFilmEdge | UPCA | UPCE,
|
||||
MatrixCodes = Aztec | DataMatrix | MaxiCode | PDF417 | QRCode | MicroQRCode | RMQRCode,
|
||||
Any = LinearCodes | MatrixCodes,
|
||||
|
||||
_max = DataBarLimited, ///> implementation detail, don't use
|
||||
};
|
||||
|
||||
ZX_DECLARE_FLAGS(BarcodeFormats, BarcodeFormat)
|
||||
|
||||
inline constexpr bool IsLinearBarcode(BarcodeFormat format)
|
||||
{
|
||||
return BarcodeFormats(BarcodeFormat::LinearCodes).testFlag(format);
|
||||
}
|
||||
|
||||
std::string ToString(BarcodeFormat format);
|
||||
std::string ToString(BarcodeFormats formats);
|
||||
|
||||
/**
|
||||
* @brief Parse a string into a BarcodeFormat. '-' and '_' are optional.
|
||||
* @return None if str can not be parsed as a valid enum value
|
||||
*/
|
||||
BarcodeFormat BarcodeFormatFromString(std::string_view str);
|
||||
|
||||
/**
|
||||
* @brief Parse a string into a set of BarcodeFormats.
|
||||
* Separators can be (any combination of) '|', ',' or ' '.
|
||||
* Underscores are optional and input can be lower case.
|
||||
* e.g. "EAN-8 qrcode, Itf" would be parsed into [EAN8, QRCode, ITF].
|
||||
* @throws std::invalid_parameter if the string can not be fully parsed.
|
||||
*/
|
||||
BarcodeFormats BarcodeFormatsFromString(std::string_view str);
|
||||
|
||||
} // ZXing
|
||||
@@ -0,0 +1,210 @@
|
||||
/*
|
||||
* Copyright 2016 Huy Cuong Nguyen
|
||||
* Copyright 2017 Axel Waggershauser
|
||||
*/
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
|
||||
// MSVC has the <bit> header but then warns about including it.
|
||||
// We check for _MSVC_LANG here as well, so client code is depending on /Zc:__cplusplus
|
||||
#if __has_include(<bit>) && (__cplusplus > 201703L || (defined(_MSVC_LANG) && _MSVC_LANG > 201703L))
|
||||
#include <bit>
|
||||
#if __cplusplus > 201703L && defined(__ANDROID__) // NDK 25.1.8937393 has the implementation but fails to advertise it
|
||||
#define __cpp_lib_bitops 201907L
|
||||
#endif
|
||||
#elif defined(_MSC_VER)
|
||||
// accoring to #863 MSVC defines __cpp_lib_bitops even when <bit> it not included and bitops are not available
|
||||
#undef __cpp_lib_bitops
|
||||
#endif
|
||||
|
||||
#if defined(__clang__) || defined(__GNUC__)
|
||||
#define ZX_HAS_GCC_BUILTINS
|
||||
#elif defined(_MSC_VER) && !defined(_M_ARM) && !defined(_M_ARM64)
|
||||
#include <intrin.h>
|
||||
#define ZX_HAS_MSC_BUILTINS
|
||||
#endif
|
||||
|
||||
namespace ZXing::BitHacks {
|
||||
|
||||
/**
|
||||
* The code below is taken from https://graphics.stanford.edu/~seander/bithacks.html
|
||||
* All credits go to Sean Eron Anderson and other authors mentioned in that page.
|
||||
*/
|
||||
|
||||
/// <summary>
|
||||
/// Compute the number of zero bits on the left.
|
||||
/// </summary>
|
||||
template<typename T, typename = std::enable_if_t<std::is_integral_v<T>>>
|
||||
inline int NumberOfLeadingZeros(T x)
|
||||
{
|
||||
#ifdef __cpp_lib_bitops
|
||||
return std::countl_zero(static_cast<std::make_unsigned_t<T>>(x));
|
||||
#else
|
||||
if constexpr (sizeof(x) <= 4) {
|
||||
static_assert(sizeof(x) == 4, "NumberOfLeadingZeros not implemented for 8 and 16 bit ints.");
|
||||
if (x == 0)
|
||||
return 32;
|
||||
#ifdef ZX_HAS_GCC_BUILTINS
|
||||
return __builtin_clz(x);
|
||||
#elif defined(ZX_HAS_MSC_BUILTINS)
|
||||
unsigned long where;
|
||||
if (_BitScanReverse(&where, x))
|
||||
return 31 - static_cast<int>(where);
|
||||
return 32;
|
||||
#else
|
||||
int n = 0;
|
||||
if ((x & 0xFFFF0000) == 0) { n = n + 16; x = x << 16; }
|
||||
if ((x & 0xFF000000) == 0) { n = n + 8; x = x << 8; }
|
||||
if ((x & 0xF0000000) == 0) { n = n + 4; x = x << 4; }
|
||||
if ((x & 0xC0000000) == 0) { n = n + 2; x = x << 2; }
|
||||
if ((x & 0x80000000) == 0) { n = n + 1; }
|
||||
return n;
|
||||
#endif
|
||||
} else {
|
||||
if (x == 0)
|
||||
return 64;
|
||||
#ifdef ZX_HAS_GCC_BUILTINS
|
||||
return __builtin_clzll(x);
|
||||
#else // including ZX_HAS_MSC_BUILTINS
|
||||
int n = NumberOfLeadingZeros(static_cast<uint32_t>(x >> 32));
|
||||
if (n == 32)
|
||||
n += NumberOfLeadingZeros(static_cast<uint32_t>(x));
|
||||
return n;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compute the number of zero bits on the right.
|
||||
/// </summary>
|
||||
template<typename T, typename = std::enable_if_t<std::is_integral_v<T>>>
|
||||
inline int NumberOfTrailingZeros(T v)
|
||||
{
|
||||
#ifdef __cpp_lib_bitops
|
||||
return std::countr_zero(static_cast<std::make_unsigned_t<T>>(v));
|
||||
#else
|
||||
if constexpr (sizeof(v) <= 4) {
|
||||
static_assert(sizeof(v) == 4, "NumberOfTrailingZeros not implemented for 8 and 16 bit ints.");
|
||||
#ifdef ZX_HAS_GCC_BUILTINS
|
||||
return v == 0 ? 32 : __builtin_ctz(v);
|
||||
#elif defined(ZX_HAS_MSC_BUILTINS)
|
||||
unsigned long where;
|
||||
if (_BitScanForward(&where, v))
|
||||
return static_cast<int>(where);
|
||||
return 32;
|
||||
#else
|
||||
int c = 32;
|
||||
v &= -int32_t(v);
|
||||
if (v) c--;
|
||||
if (v & 0x0000FFFF) c -= 16;
|
||||
if (v & 0x00FF00FF) c -= 8;
|
||||
if (v & 0x0F0F0F0F) c -= 4;
|
||||
if (v & 0x33333333) c -= 2;
|
||||
if (v & 0x55555555) c -= 1;
|
||||
return c;
|
||||
#endif
|
||||
} else {
|
||||
#ifdef ZX_HAS_GCC_BUILTINS
|
||||
return v == 0 ? 64 : __builtin_ctzll(v);
|
||||
#else // including ZX_HAS_MSC_BUILTINS
|
||||
int n = NumberOfTrailingZeros(static_cast<uint32_t>(v));
|
||||
if (n == 32)
|
||||
n += NumberOfTrailingZeros(static_cast<uint32_t>(v >> 32));
|
||||
return n;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
inline uint32_t Reverse(uint32_t v)
|
||||
{
|
||||
#if 0
|
||||
return __builtin_bitreverse32(v);
|
||||
#else
|
||||
v = ((v >> 1) & 0x55555555) | ((v & 0x55555555) << 1);
|
||||
// swap consecutive pairs
|
||||
v = ((v >> 2) & 0x33333333) | ((v & 0x33333333) << 2);
|
||||
// swap nibbles ...
|
||||
v = ((v >> 4) & 0x0F0F0F0F) | ((v & 0x0F0F0F0F) << 4);
|
||||
// swap bytes
|
||||
v = ((v >> 8) & 0x00FF00FF) | ((v & 0x00FF00FF) << 8);
|
||||
// swap 2-byte long pairs
|
||||
v = (v >> 16) | (v << 16);
|
||||
return v;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline int CountBitsSet(uint32_t v)
|
||||
{
|
||||
#ifdef __cpp_lib_bitops
|
||||
return std::popcount(v);
|
||||
#elif defined(ZX_HAS_GCC_BUILTINS)
|
||||
return __builtin_popcount(v);
|
||||
#else
|
||||
v = v - ((v >> 1) & 0x55555555); // reuse input as temporary
|
||||
v = (v & 0x33333333) + ((v >> 2) & 0x33333333); // temp
|
||||
return (((v + (v >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24; // count
|
||||
#endif
|
||||
}
|
||||
|
||||
// this is the same as log base 2 of v
|
||||
inline int HighestBitSet(uint32_t v)
|
||||
{
|
||||
return 31 - NumberOfLeadingZeros(v);
|
||||
}
|
||||
|
||||
// shift a whole array of bits by offset bits to the right (thinking of the array as a contiguous stream of bits
|
||||
// starting with the LSB of the first int and ending with the MSB of the last int, this is actually a left shift)
|
||||
template <typename T>
|
||||
void ShiftRight(std::vector<T>& bits, std::size_t offset)
|
||||
{
|
||||
assert(offset < sizeof(T) * 8);
|
||||
|
||||
if (offset == 0 || bits.empty())
|
||||
return;
|
||||
|
||||
std::size_t leftOffset = sizeof(T) * 8 - offset;
|
||||
for (std::size_t i = 0; i < bits.size() - 1; ++i) {
|
||||
bits[i] = (bits[i] >> offset) | (bits[i + 1] << leftOffset);
|
||||
}
|
||||
bits.back() >>= offset;
|
||||
}
|
||||
|
||||
// reverse a whole array of bits. padding is the number of 'dummy' bits at the end of the array
|
||||
template <typename T>
|
||||
void Reverse(std::vector<T>& bits, std::size_t padding)
|
||||
{
|
||||
static_assert(sizeof(T) == sizeof(uint32_t), "Reverse only implemented for 32 bit types");
|
||||
|
||||
// reverse all int's first (reversing the ints in the array and the bits in the ints at the same time)
|
||||
auto first = bits.begin(), last = bits.end();
|
||||
for (; first < --last; ++first) {
|
||||
auto t = *first;
|
||||
*first = BitHacks::Reverse(*last);
|
||||
*last = BitHacks::Reverse(t);
|
||||
}
|
||||
if (first == last)
|
||||
*last = BitHacks::Reverse(*last);
|
||||
|
||||
// now correct the int's if the bit size isn't a multiple of 32
|
||||
ShiftRight(bits, padding);
|
||||
}
|
||||
|
||||
// use to avoid "load of misaligned address" when using a simple type cast
|
||||
template <typename T>
|
||||
T LoadU(const void* ptr)
|
||||
{
|
||||
static_assert(std::is_integral<T>::value, "T must be an integer");
|
||||
T res;
|
||||
memcpy(&res, ptr, sizeof(T));
|
||||
return res;
|
||||
}
|
||||
|
||||
} // namespace ZXing::BitHacks
|
||||
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* Copyright 2016 Nu-book Inc.
|
||||
* Copyright 2016 ZXing authors
|
||||
* Copyright 2022 Axel Waggershauser
|
||||
*/
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Matrix.h"
|
||||
#include "Point.h"
|
||||
#include "Range.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
|
||||
namespace ZXing {
|
||||
|
||||
class BitArray;
|
||||
class ByteMatrix;
|
||||
|
||||
/**
|
||||
* @brief A simple, fast 2D array of bits.
|
||||
*/
|
||||
class BitMatrix
|
||||
{
|
||||
int _width = 0;
|
||||
int _height = 0;
|
||||
using data_t = uint8_t;
|
||||
|
||||
std::vector<data_t> _bits;
|
||||
// There is nothing wrong to support this but disable to make it explicit since we may copy something very big here.
|
||||
// Use copy() below.
|
||||
BitMatrix(const BitMatrix&) = default;
|
||||
BitMatrix& operator=(const BitMatrix&) = delete;
|
||||
|
||||
const data_t& get(int i) const
|
||||
{
|
||||
#if 1
|
||||
return _bits.at(i);
|
||||
#else
|
||||
return _bits[i];
|
||||
#endif
|
||||
}
|
||||
|
||||
data_t& get(int i) { return const_cast<data_t&>(static_cast<const BitMatrix*>(this)->get(i)); }
|
||||
|
||||
bool getTopLeftOnBit(int &left, int& top) const;
|
||||
bool getBottomRightOnBit(int &right, int& bottom) const;
|
||||
|
||||
public:
|
||||
static constexpr data_t SET_V = 0xff; // allows playing with SIMD binarization
|
||||
static constexpr data_t UNSET_V = 0;
|
||||
static_assert(bool(SET_V) && !bool(UNSET_V), "SET_V needs to evaluate to true, UNSET_V to false, see iterator usage");
|
||||
|
||||
BitMatrix() = default;
|
||||
|
||||
#if defined(__llvm__) || (defined(__GNUC__) && (__GNUC__ > 7))
|
||||
__attribute__((no_sanitize("signed-integer-overflow")))
|
||||
#endif
|
||||
BitMatrix(int width, int height) : _width(width), _height(height), _bits(width * height, UNSET_V)
|
||||
{
|
||||
if (width != 0 && Size(_bits) / width != height)
|
||||
throw std::invalid_argument("Invalid size: width * height is too big");
|
||||
}
|
||||
|
||||
explicit BitMatrix(int dimension) : BitMatrix(dimension, dimension) {} // Construct a square matrix.
|
||||
|
||||
BitMatrix(BitMatrix&& other) noexcept = default;
|
||||
BitMatrix& operator=(BitMatrix&& other) noexcept = default;
|
||||
|
||||
BitMatrix copy() const { return *this; }
|
||||
|
||||
Range<data_t*> row(int y) { return {_bits.data() + y * _width, _bits.data() + (y + 1) * _width}; }
|
||||
Range<const data_t*> row(int y) const { return {_bits.data() + y * _width, _bits.data() + (y + 1) * _width}; }
|
||||
|
||||
Range<StrideIter<const data_t*>> col(int x) const
|
||||
{
|
||||
return {{_bits.data() + x + (_height - 1) * _width, -_width}, {_bits.data() + x - _width, -_width}};
|
||||
}
|
||||
|
||||
bool get(int x, int y) const { return get(y * _width + x); }
|
||||
void set(int x, int y, bool val = true) { get(y * _width + x) = val * SET_V; }
|
||||
|
||||
/**
|
||||
* <p>Flips the given bit.</p>
|
||||
*
|
||||
* @param x The horizontal component (i.e. which column)
|
||||
* @param y The vertical component (i.e. which row)
|
||||
*/
|
||||
void flip(int x, int y)
|
||||
{
|
||||
auto& v = get(y * _width + x);
|
||||
v = !v;
|
||||
}
|
||||
|
||||
void flipAll()
|
||||
{
|
||||
for (auto& i : _bits)
|
||||
i = !i * SET_V;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Sets a square region of the bit matrix to true.</p>
|
||||
*
|
||||
* @param left The horizontal position to begin at (inclusive)
|
||||
* @param top The vertical position to begin at (inclusive)
|
||||
* @param width The width of the region
|
||||
* @param height The height of the region
|
||||
*/
|
||||
void setRegion(int left, int top, int width, int height);
|
||||
|
||||
void rotate90();
|
||||
|
||||
void rotate180();
|
||||
|
||||
void mirror();
|
||||
|
||||
/**
|
||||
* Find the rectangle that contains all non-white pixels. Useful for detection of 'pure' barcodes.
|
||||
*
|
||||
* @return True iff this rectangle is at least minWidth x minHeight pixels big
|
||||
*/
|
||||
bool findBoundingBox(int &left, int& top, int& width, int& height, int minSize = 1) const;
|
||||
|
||||
int width() const { return _width; }
|
||||
|
||||
int height() const { return _height; }
|
||||
|
||||
bool empty() const { return _bits.empty(); }
|
||||
|
||||
friend bool operator==(const BitMatrix& a, const BitMatrix& b)
|
||||
{
|
||||
return a._width == b._width && a._height == b._height && a._bits == b._bits;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool isIn(PointT<T> p, int b = 0) const noexcept
|
||||
{
|
||||
return b <= p.x && p.x < width() - b && b <= p.y && p.y < height() - b;
|
||||
}
|
||||
|
||||
bool get(PointI p) const { return get(p.x, p.y); }
|
||||
bool get(PointF p) const { return get(PointI(p)); }
|
||||
void set(PointI p, bool v = true) { set(p.x, p.y, v); }
|
||||
void set(PointF p, bool v = true) { set(PointI(p), v); }
|
||||
};
|
||||
|
||||
void GetPatternRow(const BitMatrix& matrix, int r, std::vector<uint16_t>& pr, bool transpose);
|
||||
|
||||
/**
|
||||
* @brief Inflate scales a BitMatrix up and adds a quiet Zone plus padding
|
||||
* @param input matrix to be expanded
|
||||
* @param width new width in bits (pixel)
|
||||
* @param height new height in bits (pixel)
|
||||
* @param quietZone size of quiet zone to add in modules
|
||||
* @return expanded BitMatrix, maybe move(input) if size did not change
|
||||
*/
|
||||
BitMatrix Inflate(BitMatrix&& input, int width, int height, int quietZone);
|
||||
|
||||
/**
|
||||
* @brief Deflate (crop + subsample) a bit matrix
|
||||
* @param input matrix to be shrinked
|
||||
* @param width new width
|
||||
* @param height new height
|
||||
* @param top cropping starts at top row
|
||||
* @param left cropping starts at left col
|
||||
* @param subSampling typically the module size
|
||||
* @return deflated input
|
||||
*/
|
||||
BitMatrix Deflate(const BitMatrix& input, int width, int height, float top, float left, float subSampling);
|
||||
|
||||
template<typename T>
|
||||
BitMatrix ToBitMatrix(const Matrix<T>& in, T trueValue = {true})
|
||||
{
|
||||
BitMatrix out(in.width(), in.height());
|
||||
for (int y = 0; y < in.height(); ++y)
|
||||
for (int x = 0; x < in.width(); ++x)
|
||||
if (in.get(x, y) == trueValue)
|
||||
out.set(x, y);
|
||||
return out;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Matrix<T> ToMatrix(const BitMatrix& in, T black = 0, T white = ~0)
|
||||
{
|
||||
Matrix<T> res(in.width(), in.height());
|
||||
for (int y = 0; y < in.height(); ++y)
|
||||
for (int x = 0; x < in.width(); ++x)
|
||||
res.set(x, y, in.get(x, y) ? black : white);
|
||||
return res;
|
||||
}
|
||||
|
||||
} // ZXing
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright 2017 Huy Cuong Nguyen
|
||||
* Copyright 2017 Axel Waggershauser
|
||||
*/
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "BitMatrix.h"
|
||||
|
||||
namespace ZXing {
|
||||
|
||||
std::string ToString(const BitMatrix& matrix, bool inverted = false);
|
||||
std::string ToString(const BitMatrix& matrix, char one, char zero = ' ', bool addSpace = true, bool printAsCString = false);
|
||||
std::string ToSVG(const BitMatrix& matrix);
|
||||
BitMatrix ParseBitMatrix(const std::string& str, char one = 'X', bool expectSpace = true);
|
||||
void SaveAsPBM(const BitMatrix& matrix, const std::string filename, int quietZone = 0);
|
||||
|
||||
} // ZXing
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2016 Nu-book Inc.
|
||||
* Copyright 2022 Axel Waggershauser
|
||||
*/
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Range.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
namespace ZXing {
|
||||
|
||||
/**
|
||||
ByteArray is an extension of std::vector<uint8_t>.
|
||||
*/
|
||||
class ByteArray : public std::vector<uint8_t>
|
||||
{
|
||||
public:
|
||||
ByteArray() = default;
|
||||
ByteArray(std::initializer_list<uint8_t> list) : std::vector<uint8_t>(list) {}
|
||||
explicit ByteArray(int len) : std::vector<uint8_t>(len, 0) {}
|
||||
explicit ByteArray(const std::string& str) : std::vector<uint8_t>(str.begin(), str.end()) {}
|
||||
|
||||
void append(ByteView other) { insert(end(), other.begin(), other.end()); }
|
||||
void append(std::string_view other) { insert(end(), other.begin(), other.end()); }
|
||||
|
||||
std::string_view asString(size_t pos = 0, size_t len = std::string_view::npos) const
|
||||
{
|
||||
return std::string_view(reinterpret_cast<const char*>(data()), size()).substr(pos, len);
|
||||
}
|
||||
|
||||
ByteView asView(size_t pos = 0, size_t len = size_t(-1)) const
|
||||
{
|
||||
return ByteView(*this).subview(pos, len);
|
||||
}
|
||||
};
|
||||
|
||||
inline std::string ToHex(ByteView bytes)
|
||||
{
|
||||
std::string res(bytes.size() * 3, ' ');
|
||||
|
||||
for (size_t i = 0; i < bytes.size(); ++i)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
sprintf_s(&res[i * 3], 4, "%02X ", bytes[i]);
|
||||
#else
|
||||
snprintf(&res[i * 3], 4, "%02X ", bytes[i]);
|
||||
#endif
|
||||
}
|
||||
|
||||
return res.substr(0, res.size()-1);
|
||||
}
|
||||
|
||||
} // ZXing
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2016 Nu-book Inc.
|
||||
*/
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
namespace ZXing {
|
||||
|
||||
enum class CharacterSet : unsigned char
|
||||
{
|
||||
Unknown,
|
||||
ASCII,
|
||||
ISO8859_1,
|
||||
ISO8859_2,
|
||||
ISO8859_3,
|
||||
ISO8859_4,
|
||||
ISO8859_5,
|
||||
ISO8859_6,
|
||||
ISO8859_7,
|
||||
ISO8859_8,
|
||||
ISO8859_9,
|
||||
ISO8859_10,
|
||||
ISO8859_11,
|
||||
ISO8859_13,
|
||||
ISO8859_14,
|
||||
ISO8859_15,
|
||||
ISO8859_16,
|
||||
Cp437,
|
||||
Cp1250,
|
||||
Cp1251,
|
||||
Cp1252,
|
||||
Cp1256,
|
||||
|
||||
Shift_JIS,
|
||||
Big5,
|
||||
GB2312,
|
||||
GB18030,
|
||||
EUC_JP,
|
||||
EUC_KR,
|
||||
UTF16BE,
|
||||
UnicodeBig [[deprecated]] = UTF16BE,
|
||||
UTF8,
|
||||
UTF16LE,
|
||||
UTF32BE,
|
||||
UTF32LE,
|
||||
|
||||
BINARY,
|
||||
|
||||
CharsetCount
|
||||
};
|
||||
|
||||
CharacterSet CharacterSetFromString(std::string_view name);
|
||||
std::string ToString(CharacterSet cs);
|
||||
|
||||
} // ZXing
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright 2022 Axel Waggershauser
|
||||
*/
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ByteArray.h"
|
||||
#include "CharacterSet.h"
|
||||
#include "ReaderOptions.h"
|
||||
#include "ZXAlgorithms.h"
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
namespace ZXing {
|
||||
|
||||
enum class ECI : int;
|
||||
|
||||
enum class ContentType { Text, Binary, Mixed, GS1, ISO15434, UnknownECI };
|
||||
enum class AIFlag : char { None, GS1, AIM };
|
||||
|
||||
std::string ToString(ContentType type);
|
||||
|
||||
struct SymbologyIdentifier
|
||||
{
|
||||
char code = 0, modifier = 0, eciModifierOffset = 0;
|
||||
AIFlag aiFlag = AIFlag::None;
|
||||
|
||||
std::string toString(bool hasECI = false) const
|
||||
{
|
||||
int modVal = (modifier >= 'A' ? modifier - 'A' + 10 : modifier - '0') + eciModifierOffset * hasECI;
|
||||
return code ? StrCat(']', code, static_cast<char>((modVal >= 10 ? 'A' - 10 : '0') + modVal)) : std::string();
|
||||
}
|
||||
};
|
||||
|
||||
class Content
|
||||
{
|
||||
template <typename FUNC>
|
||||
void ForEachECIBlock(FUNC f) const;
|
||||
|
||||
void switchEncoding(ECI eci, bool isECI);
|
||||
std::string render(bool withECI) const;
|
||||
|
||||
public:
|
||||
struct Encoding
|
||||
{
|
||||
ECI eci;
|
||||
int pos;
|
||||
};
|
||||
|
||||
ByteArray bytes;
|
||||
std::vector<Encoding> encodings;
|
||||
#if !defined(ZXING_READERS) && defined(ZXING_EXPERIMENTAL_API) && defined(ZXING_USE_ZINT)
|
||||
std::vector<std::string> utf8Cache;
|
||||
#endif
|
||||
SymbologyIdentifier symbology;
|
||||
CharacterSet defaultCharset = CharacterSet::Unknown;
|
||||
bool hasECI = false;
|
||||
|
||||
Content();
|
||||
Content(ByteArray&& bytes, SymbologyIdentifier si);
|
||||
|
||||
void switchEncoding(ECI eci) { switchEncoding(eci, true); }
|
||||
void switchEncoding(CharacterSet cs);
|
||||
|
||||
void reserve(int count) { bytes.reserve(bytes.size() + count); }
|
||||
|
||||
void push_back(uint8_t val) { bytes.push_back(val); }
|
||||
void push_back(int val) { bytes.push_back(narrow_cast<uint8_t>(val)); }
|
||||
void append(std::string_view str) { bytes.insert(bytes.end(), str.begin(), str.end()); }
|
||||
void append(ByteView bv) { bytes.insert(bytes.end(), bv.begin(), bv.end()); }
|
||||
void append(const Content& other);
|
||||
|
||||
void erase(int pos, int n);
|
||||
void insert(int pos, std::string_view str);
|
||||
|
||||
bool empty() const { return bytes.empty(); }
|
||||
bool canProcess() const;
|
||||
|
||||
std::string text(TextMode mode) const;
|
||||
std::wstring utfW() const; // utf16 or utf32 depending on the platform, i.e. on size_of(wchar_t)
|
||||
std::string utf8() const { return render(false); }
|
||||
|
||||
ByteArray bytesECI() const;
|
||||
CharacterSet guessEncoding() const;
|
||||
ContentType type() const;
|
||||
};
|
||||
|
||||
} // ZXing
|
||||
@@ -0,0 +1,10 @@
|
||||
/*
|
||||
* Copyright 2023 Axel Waggershauser
|
||||
*/
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ReaderOptions.h"
|
||||
|
||||
// TODO: remove this backward compatibility header once the deprecated name DecodeHints has been removed (3.0)
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2022 Axel Waggershauser
|
||||
*/
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
|
||||
namespace ZXing {
|
||||
|
||||
/**
|
||||
* @brief The Error class is a value type for the error() member of @Barcode
|
||||
*
|
||||
* The use-case of this class is to communicate whether or not a particular Barcode
|
||||
* symbol is in error. It is (primarily) not meant to be thrown as an exception and
|
||||
* therefore not derived from std::exception. The library code may throw (and catch!)
|
||||
* objects of this class as a convenient means of flow control (c++23's std::expected
|
||||
* will allow to replace those use-cases with something similarly convenient). In
|
||||
* those situations, the author is advised to make sure any thrown Error object is
|
||||
* caught before leaking into user/wrapper code, i.e. the functions of the public
|
||||
* API should be considered `noexcept` with respect to this class.
|
||||
*
|
||||
* Looking at the implementation of std::runtime_exception, it might actually be of
|
||||
* interest to replace the std::string msg member with a std::runtime_exception base
|
||||
* class, thereby reducing sizeof(Error) by 16 bytes. This would be a breaking ABI
|
||||
* change and would therefore have to wait for release 3.0. (TODO)
|
||||
*/
|
||||
|
||||
class Error
|
||||
{
|
||||
public:
|
||||
enum class Type : uint8_t { None, Format, Checksum, Unsupported };
|
||||
Type type() const noexcept { return _type; }
|
||||
const std::string& msg() const noexcept { return _msg; }
|
||||
explicit operator bool() const noexcept { return _type != Type::None; }
|
||||
|
||||
std::string location() const;
|
||||
|
||||
Error() = default;
|
||||
Error(Type type, std::string msg = {}) : _msg(std::move(msg)), _type(type) {}
|
||||
Error(const char* file, short line, Type type, std::string msg = {}) : _msg(std::move(msg)), _file(file), _line(line), _type(type) {}
|
||||
|
||||
static constexpr auto Format = Type::Format;
|
||||
static constexpr auto Checksum = Type::Checksum;
|
||||
static constexpr auto Unsupported = Type::Unsupported;
|
||||
|
||||
inline bool operator==(const Error& o) const noexcept
|
||||
{
|
||||
return _type == o._type && _msg == o._msg && _file == o._file && _line == o._line;
|
||||
}
|
||||
inline bool operator!=(const Error& o) const noexcept { return !(*this == o); }
|
||||
|
||||
protected:
|
||||
std::string _msg;
|
||||
const char* _file = nullptr;
|
||||
short _line = -1;
|
||||
Type _type = Type::None;
|
||||
};
|
||||
|
||||
inline bool operator==(const Error& e, Error::Type t) noexcept { return e.type() == t; }
|
||||
inline bool operator!=(const Error& e, Error::Type t) noexcept { return !(e == t); }
|
||||
inline bool operator==(Error::Type t, const Error& e) noexcept { return e.type() == t; }
|
||||
inline bool operator!=(Error::Type t, const Error& e) noexcept { return !(t == e); }
|
||||
|
||||
#define FormatError(...) Error(__FILE__, __LINE__, Error::Format, std::string(__VA_ARGS__))
|
||||
#define ChecksumError(...) Error(__FILE__, __LINE__, Error::Checksum, std::string(__VA_ARGS__))
|
||||
#define UnsupportedError(...) Error(__FILE__, __LINE__, Error::Unsupported, std::string(__VA_ARGS__))
|
||||
|
||||
std::string ToString(const Error& e);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright 2020 Axel Waggershauser
|
||||
*/
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BitHacks.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
|
||||
namespace ZXing {
|
||||
|
||||
template<typename Enum>
|
||||
class Flags
|
||||
{
|
||||
static_assert(std::is_enum<Enum>::value, "Flags is only usable on enumeration types.");
|
||||
|
||||
using Int = typename std::underlying_type<Enum>::type;
|
||||
Int i = 0;
|
||||
|
||||
constexpr inline Flags(Int other) : i(other) {}
|
||||
constexpr static inline unsigned highestBitSet(Int x) noexcept { return x < 2 ? x : 1 + highestBitSet(x >> 1); }
|
||||
|
||||
public:
|
||||
using enum_type = Enum;
|
||||
|
||||
constexpr inline Flags() noexcept = default;
|
||||
constexpr inline Flags(Enum flag) noexcept : i(Int(flag)) {}
|
||||
|
||||
// constexpr inline Flags(std::initializer_list<Enum> flags) noexcept
|
||||
// : i(initializer_list_helper(flags.begin(), flags.end()))
|
||||
// {}
|
||||
|
||||
class iterator
|
||||
{
|
||||
friend class Flags;
|
||||
const Int _flags = 0;
|
||||
int _pos = 0;
|
||||
iterator(Int i, int p) : _flags(i), _pos(p) {}
|
||||
public:
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
using value_type = Enum;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = Enum*;
|
||||
using reference = Enum&;
|
||||
|
||||
Enum operator*() const noexcept { return Enum(1 << _pos); }
|
||||
|
||||
iterator& operator++() noexcept
|
||||
{
|
||||
while (++_pos < BitHacks::HighestBitSet(_flags) && !((1 << _pos) & _flags))
|
||||
;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const iterator& rhs) const noexcept { return _pos == rhs._pos; }
|
||||
bool operator!=(const iterator& rhs) const noexcept { return !(*this == rhs); }
|
||||
};
|
||||
|
||||
iterator begin() const noexcept { return {i, BitHacks::NumberOfTrailingZeros(i)}; }
|
||||
iterator end() const noexcept { return {i, BitHacks::HighestBitSet(i) + 1}; }
|
||||
|
||||
bool empty() const noexcept { return i == 0; }
|
||||
int count() const noexcept { return BitHacks::CountBitsSet(i); }
|
||||
|
||||
constexpr inline bool operator==(Flags other) const noexcept { return i == other.i; }
|
||||
|
||||
inline Flags& operator&=(Flags mask) noexcept { return i &= mask.i, *this; }
|
||||
inline Flags& operator&=(Enum mask) noexcept { return i &= Int(mask), *this; }
|
||||
inline Flags& operator|=(Flags other) noexcept { return i |= other.i, *this; }
|
||||
inline Flags& operator|=(Enum other) noexcept { return i |= Int(other), *this; }
|
||||
// inline Flags &operator^=(Flags other) noexcept { return i ^= other.i, *this; }
|
||||
// inline Flags &operator^=(Enum other) noexcept { return i ^= Int(other), *this; }
|
||||
|
||||
constexpr inline Flags operator&(Flags other) const noexcept { return i & other.i; }
|
||||
constexpr inline Flags operator&(Enum other) const noexcept { return i & Int(other); }
|
||||
constexpr inline Flags operator|(Flags other) const noexcept { return i | other.i; }
|
||||
constexpr inline Flags operator|(Enum other) const noexcept { return i | Int(other); }
|
||||
// constexpr inline Flags operator^(Flags other) const noexcept { return i ^ other.i; }
|
||||
// constexpr inline Flags operator^(Enum other) const noexcept { return i ^ Int(other); }
|
||||
// constexpr inline Flags operator~() const noexcept { return ~i; }
|
||||
|
||||
// constexpr inline operator Int() const noexcept { return i; }
|
||||
// constexpr inline bool operator!() const noexcept { return !i; }
|
||||
// constexpr inline Int asInt() const noexcept { return i; }
|
||||
|
||||
constexpr inline bool testFlag(Enum flag) const noexcept
|
||||
{
|
||||
return (i & Int(flag)) == Int(flag) && (Int(flag) != 0 || i == Int(flag));
|
||||
}
|
||||
constexpr inline bool testFlags(Flags mask) const noexcept { return i & mask.i; }
|
||||
inline Flags& setFlag(Enum flag, bool on = true) noexcept
|
||||
{
|
||||
return on ? (*this |= flag) : (*this &= ~Int(flag));
|
||||
}
|
||||
inline void clear() noexcept { i = 0; }
|
||||
|
||||
constexpr static Flags all() noexcept { return ~(unsigned(~0) << highestBitSet(Int(Enum::_max))); }
|
||||
|
||||
private:
|
||||
// constexpr static inline Int
|
||||
// initializer_list_helper(typename std::initializer_list<Enum>::const_iterator it,
|
||||
// typename std::initializer_list<Enum>::const_iterator end) noexcept
|
||||
// {
|
||||
// return (it == end ? Int(0) : (Int(*it) | initializer_list_helper(it + 1, end)));
|
||||
// }
|
||||
};
|
||||
|
||||
#define ZX_DECLARE_FLAGS(FLAGS, ENUM) \
|
||||
using FLAGS = Flags<ENUM>; \
|
||||
constexpr inline FLAGS operator|(FLAGS::enum_type e1, FLAGS::enum_type e2) noexcept { return FLAGS(e1) | e2; } \
|
||||
constexpr inline FLAGS operator|(FLAGS::enum_type e, FLAGS f) noexcept { return f | e; } \
|
||||
constexpr inline bool operator==(FLAGS::enum_type e, FLAGS f) noexcept { return FLAGS(e) == f; } \
|
||||
constexpr inline bool operator==(FLAGS f, FLAGS::enum_type e) noexcept { return FLAGS(e) == f; }
|
||||
|
||||
} // ZXing
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2016 Nu-book Inc.
|
||||
* Copyright 2016 ZXing authors
|
||||
* Copyright 2020 Axel Waggershauser
|
||||
*/
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Barcode.h"
|
||||
#include "BarcodeFormat.h"
|
||||
#include "ZXAlgorithms.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace ZXing::GTIN {
|
||||
|
||||
template <typename T>
|
||||
T ComputeCheckDigit(const std::basic_string<T>& digits, bool skipTail = false)
|
||||
{
|
||||
int sum = 0, N = Size(digits) - skipTail;
|
||||
for (int i = N - 1; i >= 0; i -= 2)
|
||||
sum += digits[i] - '0';
|
||||
sum *= 3;
|
||||
for (int i = N - 2; i >= 0; i -= 2)
|
||||
sum += digits[i] - '0';
|
||||
return ToDigit<T>((10 - (sum % 10)) % 10);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool IsCheckDigitValid(const std::basic_string<T>& s)
|
||||
{
|
||||
return ComputeCheckDigit(s, true) == s.back();
|
||||
}
|
||||
|
||||
//TODO: use std::string_view in 3.0
|
||||
/**
|
||||
* Evaluate the prefix of the GTIN to estimate the country of origin. See
|
||||
* <a href="https://www.gs1.org/standards/id-keys/company-prefix">
|
||||
* https://www.gs1.org/standards/id-keys/company-prefix</a> and
|
||||
* <a href="https://en.wikipedia.org/wiki/List_of_GS1_country_codes">
|
||||
* https://en.wikipedia.org/wiki/List_of_GS1_country_codes</a>.
|
||||
*
|
||||
* `format` required for EAN-8 (UPC-E assumed if not given)
|
||||
*/
|
||||
std::string LookupCountryIdentifier(const std::string& GTIN, const BarcodeFormat format = BarcodeFormat::None);
|
||||
|
||||
std::string EanAddOn(const Barcode& barcode);
|
||||
|
||||
std::string IssueNr(const std::string& ean2AddOn);
|
||||
std::string Price(const std::string& ean5AddOn);
|
||||
|
||||
} // namespace ZXing::GTIN
|
||||
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Copyright 2019 Axel Waggershauser
|
||||
*/
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace ZXing {
|
||||
|
||||
enum class ImageFormat : uint32_t
|
||||
{
|
||||
None = 0,
|
||||
Lum = 0x01000000,
|
||||
LumA = 0x02000000,
|
||||
RGB = 0x03000102,
|
||||
BGR = 0x03020100,
|
||||
RGBA = 0x04000102,
|
||||
ARGB = 0x04010203,
|
||||
BGRA = 0x04020100,
|
||||
ABGR = 0x04030201,
|
||||
RGBX [[deprecated("use RGBA")]] = RGBA,
|
||||
XRGB [[deprecated("use ARGB")]] = ARGB,
|
||||
BGRX [[deprecated("use BGRA")]] = BGRA,
|
||||
XBGR [[deprecated("use ABGR")]] = ABGR,
|
||||
};
|
||||
|
||||
constexpr inline int PixStride(ImageFormat format) { return (static_cast<uint32_t>(format) >> 3*8) & 0xFF; }
|
||||
constexpr inline int RedIndex(ImageFormat format) { return (static_cast<uint32_t>(format) >> 2*8) & 0xFF; }
|
||||
constexpr inline int GreenIndex(ImageFormat format) { return (static_cast<uint32_t>(format) >> 1*8) & 0xFF; }
|
||||
constexpr inline int BlueIndex(ImageFormat format) { return (static_cast<uint32_t>(format) >> 0*8) & 0xFF; }
|
||||
|
||||
constexpr inline uint8_t RGBToLum(unsigned r, unsigned g, unsigned b)
|
||||
{
|
||||
// .299R + 0.587G + 0.114B (YUV/YIQ for PAL and NTSC),
|
||||
// (306*R) >> 10 is approximately equal to R*0.299, and so on.
|
||||
// 0x200 >> 10 is 0.5, it implements rounding.
|
||||
return static_cast<uint8_t>((306 * r + 601 * g + 117 * b + 0x200) >> 10);
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple class that stores a non-owning const pointer to image data plus layout and format information.
|
||||
*/
|
||||
class ImageView
|
||||
{
|
||||
protected:
|
||||
const uint8_t* _data = nullptr;
|
||||
ImageFormat _format = ImageFormat::None;
|
||||
int _width = 0, _height = 0, _pixStride = 0, _rowStride = 0;
|
||||
|
||||
public:
|
||||
/** ImageView default constructor creates a 'null' image view
|
||||
*/
|
||||
ImageView() = default;
|
||||
|
||||
/**
|
||||
* ImageView constructor
|
||||
*
|
||||
* @param data pointer to image buffer
|
||||
* @param width image width in pixels
|
||||
* @param height image height in pixels
|
||||
* @param format image/pixel format
|
||||
* @param rowStride optional row stride in bytes, default is width * pixStride
|
||||
* @param pixStride optional pixel stride in bytes, default is calculated from format
|
||||
*/
|
||||
ImageView(const uint8_t* data, int width, int height, ImageFormat format, int rowStride = 0, int pixStride = 0)
|
||||
: _data(data),
|
||||
_format(format),
|
||||
_width(width),
|
||||
_height(height),
|
||||
_pixStride(pixStride ? pixStride : PixStride(format)),
|
||||
_rowStride(rowStride ? rowStride : width * _pixStride)
|
||||
{
|
||||
// TODO: [[deprecated]] this check is to prevent exising code from suddenly throwing, remove in 3.0
|
||||
if (_data == nullptr && _width == 0 && _height == 0 && rowStride == 0 && pixStride == 0) {
|
||||
fprintf(stderr, "zxing-cpp deprecation warning: ImageView(nullptr, ...) will throw in the future, use ImageView()\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (_data == nullptr)
|
||||
throw std::invalid_argument("Can not construct an ImageView from a NULL pointer");
|
||||
|
||||
if (_width <= 0 || _height <= 0)
|
||||
throw std::invalid_argument("Neither width nor height of ImageView can be less or equal to 0");
|
||||
}
|
||||
|
||||
/**
|
||||
* ImageView constructor with bounds checking
|
||||
*/
|
||||
ImageView(const uint8_t* data, int size, int width, int height, ImageFormat format, int rowStride = 0, int pixStride = 0)
|
||||
: ImageView(data, width, height, format, rowStride, pixStride)
|
||||
{
|
||||
if (_rowStride < 0 || _pixStride < 0 || size < _height * _rowStride)
|
||||
throw std::invalid_argument("ImageView parameters are inconsistent (out of bounds)");
|
||||
}
|
||||
|
||||
int width() const { return _width; }
|
||||
int height() const { return _height; }
|
||||
int pixStride() const { return _pixStride; }
|
||||
int rowStride() const { return _rowStride; }
|
||||
ImageFormat format() const { return _format; }
|
||||
|
||||
const uint8_t* data() const { return _data; }
|
||||
const uint8_t* data(int x, int y) const { return _data + y * _rowStride + x * _pixStride; }
|
||||
|
||||
ImageView cropped(int left, int top, int width, int height) const
|
||||
{
|
||||
left = std::clamp(left, 0, _width - 1);
|
||||
top = std::clamp(top, 0, _height - 1);
|
||||
width = width <= 0 ? (_width - left) : std::min(_width - left, width);
|
||||
height = height <= 0 ? (_height - top) : std::min(_height - top, height);
|
||||
return {data(left, top), width, height, _format, _rowStride, _pixStride};
|
||||
}
|
||||
|
||||
ImageView rotated(int degree) const
|
||||
{
|
||||
switch ((degree + 360) % 360) {
|
||||
case 90: return {data(0, _height - 1), _height, _width, _format, _pixStride, -_rowStride};
|
||||
case 180: return {data(_width - 1, _height - 1), _width, _height, _format, -_rowStride, -_pixStride};
|
||||
case 270: return {data(_width - 1, 0), _height, _width, _format, -_pixStride, _rowStride};
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
ImageView subsampled(int scale) const
|
||||
{
|
||||
return {_data, _width / scale, _height / scale, _format, _rowStride * scale, _pixStride * scale};
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class Image : public ImageView
|
||||
{
|
||||
std::unique_ptr<uint8_t[]> _memory;
|
||||
Image(std::unique_ptr<uint8_t[]>&& data, int w, int h, ImageFormat f) : ImageView(data.get(), w, h, f), _memory(std::move(data)) {}
|
||||
|
||||
public:
|
||||
Image() = default;
|
||||
Image(int w, int h, ImageFormat f = ImageFormat::Lum) : Image(std::make_unique<uint8_t[]>(w * h * PixStride(f)), w, h, f) {}
|
||||
};
|
||||
|
||||
} // ZXing
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright 2016 Huy Cuong Nguyen
|
||||
* Copyright 2016 ZXing authors
|
||||
*/
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Point.h"
|
||||
#include "ZXAlgorithms.h"
|
||||
|
||||
#include <stdexcept>
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <vector>
|
||||
|
||||
namespace ZXing {
|
||||
|
||||
template <class T>
|
||||
class Matrix
|
||||
{
|
||||
public:
|
||||
using value_t = T;
|
||||
|
||||
private:
|
||||
int _width = 0;
|
||||
int _height = 0;
|
||||
std::vector<value_t> _data;
|
||||
|
||||
// Nothing wrong to support it, just to make it explicit, instead of by mistake.
|
||||
// Use copy() below.
|
||||
Matrix(const Matrix &) = default;
|
||||
Matrix& operator=(const Matrix &) = delete;
|
||||
|
||||
public:
|
||||
Matrix() = default;
|
||||
|
||||
#if defined(__llvm__) || (defined(__GNUC__) && (__GNUC__ > 7))
|
||||
__attribute__((no_sanitize("signed-integer-overflow")))
|
||||
#endif
|
||||
Matrix(int width, int height, value_t val = {}) : _width(width), _height(height), _data(_width * _height, val) {
|
||||
if (width != 0 && Size(_data) / width != height)
|
||||
throw std::invalid_argument("Invalid size: width * height is too big");
|
||||
}
|
||||
|
||||
Matrix(Matrix&&) noexcept = default;
|
||||
Matrix& operator=(Matrix&&) noexcept = default;
|
||||
|
||||
Matrix copy() const {
|
||||
return *this;
|
||||
}
|
||||
|
||||
int height() const {
|
||||
return _height;
|
||||
}
|
||||
|
||||
int width() const {
|
||||
return _width;
|
||||
}
|
||||
|
||||
int size() const {
|
||||
return Size(_data);
|
||||
}
|
||||
|
||||
value_t& operator()(int x, int y)
|
||||
{
|
||||
assert(x >= 0 && x < _width && y >= 0 && y < _height);
|
||||
return _data[y * _width + x];
|
||||
}
|
||||
|
||||
const T& operator()(int x, int y) const
|
||||
{
|
||||
assert(x >= 0 && x < _width && y >= 0 && y < _height);
|
||||
return _data[y * _width + x];
|
||||
}
|
||||
|
||||
const value_t& get(int x, int y) const {
|
||||
return operator()(x, y);
|
||||
}
|
||||
|
||||
value_t& set(int x, int y, value_t value) {
|
||||
return operator()(x, y) = value;
|
||||
}
|
||||
|
||||
const value_t& get(PointI p) const {
|
||||
return operator()(p.x, p.y);
|
||||
}
|
||||
|
||||
value_t& set(PointI p, value_t value) {
|
||||
return operator()(p.x, p.y) = value;
|
||||
}
|
||||
|
||||
const value_t* data() const {
|
||||
return _data.data();
|
||||
}
|
||||
|
||||
const value_t* begin() const {
|
||||
return _data.data();
|
||||
}
|
||||
|
||||
const value_t* end() const {
|
||||
return _data.data() + _width * _height;
|
||||
}
|
||||
|
||||
value_t* begin() {
|
||||
return _data.data();
|
||||
}
|
||||
|
||||
value_t* end() {
|
||||
return _data.data() + _width * _height;
|
||||
}
|
||||
|
||||
void clear(value_t value = {}) {
|
||||
std::fill(_data.begin(), _data.end(), value);
|
||||
}
|
||||
};
|
||||
|
||||
} // ZXing
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2017 Huy Cuong Nguyen
|
||||
*/
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BarcodeFormat.h"
|
||||
#include "CharacterSet.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace ZXing {
|
||||
|
||||
class BitMatrix;
|
||||
|
||||
/**
|
||||
* This class is here just for convenience as it offers single-point service
|
||||
* to generate barcodes for all supported formats. As a result, this class
|
||||
* offer very limited customization compared to what are available in each
|
||||
* individual encoder.
|
||||
*/
|
||||
class MultiFormatWriter
|
||||
{
|
||||
public:
|
||||
explicit MultiFormatWriter(BarcodeFormat format) : _format(format) {}
|
||||
|
||||
/**
|
||||
* Used for Aztec, PDF417, and QRCode only.
|
||||
*/
|
||||
MultiFormatWriter& setEncoding(CharacterSet encoding) {
|
||||
_encoding = encoding;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used for Aztec, PDF417, and QRCode only, [0-8].
|
||||
*/
|
||||
MultiFormatWriter& setEccLevel(int level) {
|
||||
_eccLevel = level;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used for all formats, sets the minimum number of quiet zone pixels.
|
||||
*/
|
||||
MultiFormatWriter& setMargin(int margin) {
|
||||
_margin = margin;
|
||||
return *this;
|
||||
}
|
||||
|
||||
BitMatrix encode(const std::wstring& contents, int width, int height) const;
|
||||
BitMatrix encode(const std::string& contents, int width, int height) const;
|
||||
|
||||
private:
|
||||
BarcodeFormat _format;
|
||||
CharacterSet _encoding = CharacterSet::Unknown;
|
||||
int _margin = -1;
|
||||
int _eccLevel = -1;
|
||||
};
|
||||
|
||||
} // ZXing
|
||||
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* Copyright 2020 Axel Waggershauser
|
||||
*/
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <string>
|
||||
|
||||
namespace ZXing {
|
||||
|
||||
template <typename T>
|
||||
struct PointT
|
||||
{
|
||||
using value_t = T;
|
||||
T x = 0, y = 0;
|
||||
|
||||
constexpr PointT() = default;
|
||||
constexpr PointT(T x, T y) : x(x), y(y) {}
|
||||
|
||||
template <typename U>
|
||||
constexpr explicit PointT(const PointT<U>& p) : x(static_cast<T>(p.x)), y(static_cast<T>(p.y))
|
||||
{}
|
||||
|
||||
template <typename U>
|
||||
PointT& operator+=(const PointT<U>& b)
|
||||
{
|
||||
x += b.x;
|
||||
y += b.y;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
bool operator==(const PointT<T>& a, const PointT<T>& b)
|
||||
{
|
||||
return a.x == b.x && a.y == b.y;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool operator!=(const PointT<T>& a, const PointT<T>& b)
|
||||
{
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
auto operator-(const PointT<T>& a) -> PointT<T>
|
||||
{
|
||||
return {-a.x, -a.y};
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
auto operator+(const PointT<T>& a, const PointT<U>& b) -> PointT<decltype(a.x + b.x)>
|
||||
{
|
||||
return {a.x + b.x, a.y + b.y};
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
auto operator-(const PointT<T>& a, const PointT<U>& b) -> PointT<decltype(a.x - b.x)>
|
||||
{
|
||||
return {a.x - b.x, a.y - b.y};
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
auto operator*(const PointT<T>& a, const PointT<U>& b) -> PointT<decltype(a.x * b.x)>
|
||||
{
|
||||
return {a.x * b.x, a.y * b.y};
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
PointT<T> operator*(U s, const PointT<T>& a)
|
||||
{
|
||||
return {s * a.x, s * a.y};
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
PointT<T> operator/(const PointT<T>& a, U d)
|
||||
{
|
||||
return {a.x / d, a.y / d};
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
auto dot(const PointT<T>& a, const PointT<U>& b) -> decltype (a.x * b.x)
|
||||
{
|
||||
return a.x * b.x + a.y * b.y;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
auto cross(PointT<T> a, PointT<T> b) -> decltype(a.x * b.x)
|
||||
{
|
||||
return a.x * b.y - b.x * a.y;
|
||||
}
|
||||
|
||||
/// L1 norm
|
||||
template <typename T>
|
||||
T sumAbsComponent(PointT<T> p)
|
||||
{
|
||||
return std::abs(p.x) + std::abs(p.y);
|
||||
}
|
||||
|
||||
/// L2 norm
|
||||
template <typename T>
|
||||
auto length(PointT<T> p) -> decltype(std::sqrt(dot(p, p)))
|
||||
{
|
||||
return std::sqrt(dot(p, p));
|
||||
}
|
||||
|
||||
/// L-inf norm
|
||||
template <typename T>
|
||||
T maxAbsComponent(PointT<T> p)
|
||||
{
|
||||
return std::max(std::abs(p.x), std::abs(p.y));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
auto distance(PointT<T> a, PointT<T> b) -> decltype(length(a - b))
|
||||
{
|
||||
return length(a - b);
|
||||
}
|
||||
|
||||
using PointI = PointT<int>;
|
||||
using PointF = PointT<double>;
|
||||
|
||||
/// Calculate a floating point pixel coordinate representing the 'center' of the pixel.
|
||||
/// This is sort of the inverse operation of the PointI(PointF) conversion constructor.
|
||||
/// See also the documentation of the GridSampler API.
|
||||
inline PointF centered(PointI p)
|
||||
{
|
||||
return p + PointF(0.5f, 0.5f);
|
||||
}
|
||||
|
||||
inline PointF centered(PointF p)
|
||||
{
|
||||
return {std::floor(p.x) + 0.5f, std::floor(p.y) + 0.5f};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
PointF normalized(PointT<T> d)
|
||||
{
|
||||
return PointF(d) / length(PointF(d));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
PointT<T> bresenhamDirection(PointT<T> d)
|
||||
{
|
||||
return d / maxAbsComponent(d);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
PointT<T> mainDirection(PointT<T> d)
|
||||
{
|
||||
return std::abs(d.x) > std::abs(d.y) ? PointT<T>(d.x, 0) : PointT<T>(0, d.y);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::string ToString(const PointT<T>& p, bool swap = false, char delim = 'x')
|
||||
{
|
||||
return std::to_string(swap ? p.y : p.x) + delim + std::to_string(swap ? p.x : p.y);
|
||||
}
|
||||
|
||||
} // ZXing
|
||||
|
||||
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* Copyright 2020 Axel Waggershauser
|
||||
*/
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Point.h"
|
||||
#include "ZXAlgorithms.h"
|
||||
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
#include <string>
|
||||
|
||||
namespace ZXing {
|
||||
|
||||
template <typename T>
|
||||
class Quadrilateral : public std::array<T, 4>
|
||||
{
|
||||
using Base = std::array<T, 4>;
|
||||
using Base::at;
|
||||
public:
|
||||
using Point = T;
|
||||
|
||||
Quadrilateral() = default;
|
||||
Quadrilateral(T tl, T tr, T br, T bl) : Base{tl, tr, br, bl} {}
|
||||
template <typename U>
|
||||
Quadrilateral(PointT<U> tl, PointT<U> tr, PointT<U> br, PointT<U> bl)
|
||||
: Quadrilateral(Point(tl), Point(tr), Point(br), Point(bl))
|
||||
{}
|
||||
|
||||
constexpr Point topLeft() const noexcept { return at(0); }
|
||||
constexpr Point topRight() const noexcept { return at(1); }
|
||||
constexpr Point bottomRight() const noexcept { return at(2); }
|
||||
constexpr Point bottomLeft() const noexcept { return at(3); }
|
||||
|
||||
double orientation() const
|
||||
{
|
||||
auto centerLine = (topRight() + bottomRight()) - (topLeft() + bottomLeft());
|
||||
if (centerLine == Point{})
|
||||
return 0.;
|
||||
auto centerLineF = normalized(centerLine);
|
||||
return std::atan2(centerLineF.y, centerLineF.x);
|
||||
}
|
||||
};
|
||||
|
||||
using QuadrilateralF = Quadrilateral<PointF>;
|
||||
using QuadrilateralI = Quadrilateral<PointI>;
|
||||
|
||||
template <typename PointT = PointF>
|
||||
Quadrilateral<PointT> Rectangle(int width, int height, typename PointT::value_t margin = 0)
|
||||
{
|
||||
return {
|
||||
PointT{margin, margin}, {width - margin, margin}, {width - margin, height - margin}, {margin, height - margin}};
|
||||
}
|
||||
|
||||
template <typename PointT = PointF>
|
||||
Quadrilateral<PointT> CenteredSquare(int size)
|
||||
{
|
||||
return Scale(Quadrilateral(PointT{-1, -1}, {1, -1}, {1, 1}, {-1, 1}), size / 2);
|
||||
}
|
||||
|
||||
template <typename PointT = PointI>
|
||||
Quadrilateral<PointT> Line(int y, int xStart, int xStop)
|
||||
{
|
||||
return {PointT{xStart, y}, {xStop, y}, {xStop, y}, {xStart, y}};
|
||||
}
|
||||
|
||||
template <typename PointT>
|
||||
bool IsConvex(const Quadrilateral<PointT>& poly)
|
||||
{
|
||||
const int N = Size(poly);
|
||||
bool sign = false;
|
||||
|
||||
typename PointT::value_t m = INFINITY, M = 0;
|
||||
|
||||
for(int i = 0; i < N; i++)
|
||||
{
|
||||
auto d1 = poly[(i + 2) % N] - poly[(i + 1) % N];
|
||||
auto d2 = poly[i] - poly[(i + 1) % N];
|
||||
auto cp = cross(d1, d2);
|
||||
|
||||
// TODO: see if the isInside check for all boundary points in GridSampler is still required after fixing the wrong fabs()
|
||||
// application in the following line
|
||||
UpdateMinMax(m, M, std::fabs(cp));
|
||||
|
||||
if (i == 0)
|
||||
sign = cp > 0;
|
||||
else if (sign != (cp > 0))
|
||||
return false;
|
||||
}
|
||||
|
||||
// It turns out being convex is not enough to prevent a "numerical instability"
|
||||
// that can cause the corners being projected inside the image boundaries but
|
||||
// some points near the corners being projected outside. This has been observed
|
||||
// where one corner is almost in line with two others. The M/m ratio is below 2
|
||||
// for the complete existing sample set. For very "skewed" QRCodes a value of
|
||||
// around 3 is realistic. A value of 14 has been observed to trigger the
|
||||
// instability.
|
||||
return M / m < 4.0;
|
||||
}
|
||||
|
||||
template <typename PointT>
|
||||
Quadrilateral<PointT> Scale(const Quadrilateral<PointT>& q, int factor)
|
||||
{
|
||||
return {factor * q[0], factor * q[1], factor * q[2], factor * q[3]};
|
||||
}
|
||||
|
||||
template <typename PointT>
|
||||
PointT Center(const Quadrilateral<PointT>& q)
|
||||
{
|
||||
return Reduce(q) / Size(q);
|
||||
}
|
||||
|
||||
template <typename PointT>
|
||||
Quadrilateral<PointT> RotatedCorners(const Quadrilateral<PointT>& q, int n = 1, bool mirror = false)
|
||||
{
|
||||
Quadrilateral<PointT> res;
|
||||
std::rotate_copy(q.begin(), q.begin() + ((n + 4) % 4), q.end(), res.begin());
|
||||
if (mirror)
|
||||
std::swap(res[1], res[3]);
|
||||
return res;
|
||||
}
|
||||
|
||||
template <typename PointT>
|
||||
bool IsInside(const PointT& p, const Quadrilateral<PointT>& q)
|
||||
{
|
||||
// Test if p is on the same side (right or left) of all polygon segments
|
||||
int pos = 0, neg = 0;
|
||||
for (int i = 0; i < Size(q); ++i)
|
||||
(cross(p - q[i], q[(i + 1) % Size(q)] - q[i]) < 0 ? neg : pos)++;
|
||||
return pos == 0 || neg == 0;
|
||||
}
|
||||
|
||||
template <typename PointT>
|
||||
Quadrilateral<PointT> BoundingBox(const Quadrilateral<PointT>& q)
|
||||
{
|
||||
auto [minX, maxX] = std::minmax({q[0].x, q[1].x, q[2].x, q[3].x});
|
||||
auto [minY, maxY] = std::minmax({q[0].y, q[1].y, q[2].y, q[3].y});
|
||||
return {PointT{minX, minY}, {maxX, minY}, {maxX, maxY}, {minX, maxY}};
|
||||
}
|
||||
|
||||
template <typename PointT>
|
||||
bool HaveIntersectingBoundingBoxes(const Quadrilateral<PointT>& a, const Quadrilateral<PointT>& b)
|
||||
{
|
||||
auto bba = BoundingBox(a), bbb = BoundingBox(b);
|
||||
|
||||
bool x = bbb.topRight().x < bba.topLeft().x || bbb.topLeft().x > bba.topRight().x;
|
||||
bool y = bbb.bottomLeft().y < bba.topLeft().y || bbb.topLeft().y > bba.bottomLeft().y;
|
||||
return !(x || y);
|
||||
}
|
||||
|
||||
template <typename PointT>
|
||||
Quadrilateral<PointT> Blend(const Quadrilateral<PointT>& a, const Quadrilateral<PointT>& b)
|
||||
{
|
||||
auto dist2First = [r = a[0]](auto s, auto t) { return distance(s, r) < distance(t, r); };
|
||||
// rotate points such that the the two topLeft points are closest to each other
|
||||
auto offset = std::min_element(b.begin(), b.end(), dist2First) - b.begin();
|
||||
|
||||
Quadrilateral<PointT> res;
|
||||
for (int i = 0; i < 4; ++i)
|
||||
res[i] = (a[i] + b[(i + offset) % 4]) / 2;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::string ToString(const Quadrilateral<PointT<T>>& points)
|
||||
{
|
||||
std::string res;
|
||||
for (const auto& p : points)
|
||||
res += std::to_string(p.x) + "x" + std::to_string(p.y) + (&p == &points.back() ? "" : " ");
|
||||
return res;
|
||||
}
|
||||
|
||||
} // ZXing
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright 2022 Axel Waggershauser
|
||||
*/
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ZXAlgorithms.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <iterator>
|
||||
|
||||
namespace ZXing {
|
||||
|
||||
template <typename Iterator>
|
||||
struct StrideIter
|
||||
{
|
||||
Iterator pos;
|
||||
int stride;
|
||||
|
||||
using iterator_category = std::random_access_iterator_tag;
|
||||
using difference_type = typename std::iterator_traits<Iterator>::difference_type;
|
||||
using value_type = typename std::iterator_traits<Iterator>::value_type;
|
||||
using pointer = Iterator;
|
||||
using reference = typename std::iterator_traits<Iterator>::reference;
|
||||
|
||||
auto operator*() const { return *pos; }
|
||||
auto operator[](int i) const { return *(pos + i * stride); }
|
||||
StrideIter<Iterator>& operator++() { return pos += stride, *this; }
|
||||
StrideIter<Iterator> operator++(int) { auto temp = *this; ++*this; return temp; }
|
||||
bool operator==(const StrideIter<Iterator>& rhs) const { return pos == rhs.pos; }
|
||||
bool operator!=(const StrideIter<Iterator>& rhs) const { return pos != rhs.pos; }
|
||||
StrideIter<Iterator> operator+(int i) const { return {pos + i * stride, stride}; }
|
||||
StrideIter<Iterator> operator-(int i) const { return {pos - i * stride, stride}; }
|
||||
int operator-(const StrideIter<Iterator>& rhs) const { return narrow_cast<int>((pos - rhs.pos) / stride); }
|
||||
};
|
||||
|
||||
template <typename Iterator>
|
||||
StrideIter(const Iterator&, int) -> StrideIter<Iterator>;
|
||||
|
||||
|
||||
template <typename Iterator>
|
||||
struct Range
|
||||
{
|
||||
Iterator _begin, _end;
|
||||
|
||||
Range(Iterator b, Iterator e) : _begin(b), _end(e) {}
|
||||
|
||||
template <typename C>
|
||||
Range(const C& c) : _begin(std::begin(c)), _end(std::end(c)) {}
|
||||
|
||||
Iterator begin() const noexcept { return _begin; }
|
||||
Iterator end() const noexcept { return _end; }
|
||||
explicit operator bool() const { return begin() < end(); }
|
||||
int size() const { return narrow_cast<int>(end() - begin()); }
|
||||
};
|
||||
|
||||
template <typename C>
|
||||
Range(const C&) -> Range<typename C::const_iterator>;
|
||||
|
||||
/**
|
||||
* ArrayView is a lightweight, non-owning, non-mutable view over a contiguous sequence of elements.
|
||||
* Similar to std::span<const T>. See also Range template for general iterator use case.
|
||||
*/
|
||||
template <typename T>
|
||||
class ArrayView
|
||||
{
|
||||
const T* _data = nullptr;
|
||||
std::size_t _size = 0;
|
||||
|
||||
public:
|
||||
using value_type = T;
|
||||
using pointer = const value_type*;
|
||||
using const_pointer = const value_type*;
|
||||
using reference = const value_type&;
|
||||
using const_reference = const value_type&;
|
||||
using size_type = std::size_t;
|
||||
|
||||
constexpr ArrayView() noexcept = default;
|
||||
|
||||
constexpr ArrayView(pointer data, size_type size) noexcept : _data(data), _size(size) {}
|
||||
|
||||
template <typename P, typename U = T,
|
||||
typename = std::enable_if_t<
|
||||
sizeof(U) == 1 && std::is_same_v<void, std::remove_cv_t<std::remove_reference_t<std::remove_pointer_t<P>>>>>>
|
||||
constexpr ArrayView(P data, size_type size) noexcept : _data(reinterpret_cast<pointer>(data)), _size(size)
|
||||
{}
|
||||
|
||||
template <typename Container,
|
||||
typename = std::enable_if_t<std::is_convertible_v<decltype(std::data(std::declval<Container&>())), const_pointer>>>
|
||||
constexpr ArrayView(const Container& c) noexcept : _data(std::data(c)), _size(std::size(c))
|
||||
{}
|
||||
|
||||
constexpr pointer data() const noexcept { return _data; }
|
||||
constexpr size_type size() const noexcept { return _size; }
|
||||
constexpr bool empty() const noexcept { return _size == 0; }
|
||||
|
||||
constexpr const_reference operator[](size_type index) const noexcept { return _data[index]; }
|
||||
|
||||
constexpr pointer begin() const noexcept { return _data; }
|
||||
constexpr pointer end() const noexcept { return _data + _size; }
|
||||
|
||||
constexpr ArrayView<T> subview(size_type pos, size_type len = size_type(-1)) const noexcept
|
||||
{
|
||||
if (pos > _size)
|
||||
return {};
|
||||
return {_data + pos, std::min(len, _size - pos)};
|
||||
}
|
||||
};
|
||||
|
||||
using ByteView = ArrayView<uint8_t>;
|
||||
|
||||
} // namespace ZXing
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2019 Axel Waggershauser
|
||||
*/
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ReaderOptions.h"
|
||||
#include "ImageView.h"
|
||||
#include "Barcode.h"
|
||||
|
||||
namespace ZXing {
|
||||
|
||||
/**
|
||||
* Read barcode from an ImageView
|
||||
*
|
||||
* @param image view of the image data including layout and format
|
||||
* @param options optional ReaderOptions to parameterize / speed up detection
|
||||
* @return #Barcode structure
|
||||
*/
|
||||
Barcode ReadBarcode(const ImageView& image, const ReaderOptions& options = {});
|
||||
|
||||
/**
|
||||
* Read barcodes from an ImageView
|
||||
*
|
||||
* @param image view of the image data including layout and format
|
||||
* @param options optional ReaderOptions to parameterize / speed up detection
|
||||
* @return #Barcodes list of barcodes found, may be empty
|
||||
*/
|
||||
Barcodes ReadBarcodes(const ImageView& image, const ReaderOptions& options = {});
|
||||
|
||||
} // ZXing
|
||||
|
||||
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
* Copyright 2016 Nu-book Inc.
|
||||
* Copyright 2016 ZXing authors
|
||||
* Copyright 2020 Axel Waggershauser
|
||||
*/
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BarcodeFormat.h"
|
||||
#include "CharacterSet.h"
|
||||
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
|
||||
namespace ZXing {
|
||||
|
||||
/**
|
||||
* @brief The Binarizer enum
|
||||
*
|
||||
* Specify which algorithm to use for the grayscale to binary transformation.
|
||||
* The difference is how to get to a threshold value T which results in a bit
|
||||
* value R = L <= T.
|
||||
*/
|
||||
enum class Binarizer : unsigned char // needs to be unsigned for the bitfield below to work, uint8_t fails as well
|
||||
{
|
||||
LocalAverage, ///< T = average of neighboring pixels for matrix and GlobalHistogram for linear (HybridBinarizer)
|
||||
GlobalHistogram, ///< T = valley between the 2 largest peaks in the histogram (per line in linear case)
|
||||
FixedThreshold, ///< T = 127
|
||||
BoolCast, ///< T = 0, fastest possible
|
||||
};
|
||||
|
||||
enum class EanAddOnSymbol : unsigned char // see above
|
||||
{
|
||||
Ignore, ///< Ignore any Add-On symbol during read/scan
|
||||
Read, ///< Read EAN-2/EAN-5 Add-On symbol if found
|
||||
Require, ///< Require EAN-2/EAN-5 Add-On symbol to be present
|
||||
};
|
||||
|
||||
enum class TextMode : unsigned char // see above
|
||||
{
|
||||
Plain, ///< bytes() transcoded to unicode based on ECI info or guessed charset (the default mode prior to 2.0)
|
||||
ECI, ///< standard content following the ECI protocol with every character set ECI segment transcoded to unicode
|
||||
HRI, ///< Human Readable Interpretation (dependent on the ContentType)
|
||||
Hex, ///< bytes() transcoded to ASCII string of HEX values
|
||||
Escaped, ///< Use the EscapeNonGraphical() function (e.g. ASCII 29 will be transcoded to "<GS>")
|
||||
};
|
||||
|
||||
class ReaderOptions
|
||||
{
|
||||
bool _tryHarder : 1;
|
||||
bool _tryRotate : 1;
|
||||
bool _tryInvert : 1;
|
||||
bool _tryDownscale : 1;
|
||||
bool _isPure : 1;
|
||||
bool _tryCode39ExtendedMode : 1;
|
||||
bool _validateCode39CheckSum : 1;
|
||||
bool _validateITFCheckSum : 1;
|
||||
bool _returnCodabarStartEnd : 1;
|
||||
bool _returnErrors : 1;
|
||||
uint8_t _downscaleFactor : 3;
|
||||
EanAddOnSymbol _eanAddOnSymbol : 2;
|
||||
Binarizer _binarizer : 2;
|
||||
TextMode _textMode : 3;
|
||||
CharacterSet _characterSet : 6;
|
||||
#ifdef ZXING_EXPERIMENTAL_API
|
||||
bool _tryDenoise : 1;
|
||||
#endif
|
||||
|
||||
uint8_t _minLineCount = 2;
|
||||
uint8_t _maxNumberOfSymbols = 0xff;
|
||||
uint16_t _downscaleThreshold = 500;
|
||||
BarcodeFormats _formats = BarcodeFormat::None;
|
||||
|
||||
public:
|
||||
// bitfields don't get default initialized to 0 before c++20
|
||||
ReaderOptions()
|
||||
: _tryHarder(1),
|
||||
_tryRotate(1),
|
||||
_tryInvert(1),
|
||||
_tryDownscale(1),
|
||||
_isPure(0),
|
||||
_tryCode39ExtendedMode(1),
|
||||
_validateCode39CheckSum(0),
|
||||
_validateITFCheckSum(0),
|
||||
_returnCodabarStartEnd(1),
|
||||
_returnErrors(0),
|
||||
_downscaleFactor(3),
|
||||
_eanAddOnSymbol(EanAddOnSymbol::Ignore),
|
||||
_binarizer(Binarizer::LocalAverage),
|
||||
_textMode(TextMode::HRI),
|
||||
_characterSet(CharacterSet::Unknown)
|
||||
#ifdef ZXING_EXPERIMENTAL_API
|
||||
,
|
||||
_tryDenoise(0)
|
||||
#endif
|
||||
{}
|
||||
|
||||
#define ZX_PROPERTY(TYPE, GETTER, SETTER, ...) \
|
||||
TYPE GETTER() const noexcept { return _##GETTER; } \
|
||||
__VA_ARGS__ ReaderOptions& SETTER(TYPE v)& { return (void)(_##GETTER = std::move(v)), *this; } \
|
||||
__VA_ARGS__ ReaderOptions&& SETTER(TYPE v)&& { return (void)(_##GETTER = std::move(v)), std::move(*this); }
|
||||
|
||||
/// Specify a set of BarcodeFormats that should be searched for, the default is all supported formats.
|
||||
ZX_PROPERTY(BarcodeFormats, formats, setFormats)
|
||||
|
||||
/// Spend more time to try to find a barcode; optimize for accuracy, not speed.
|
||||
ZX_PROPERTY(bool, tryHarder, setTryHarder)
|
||||
|
||||
/// Also try detecting code in 90, 180 and 270 degree rotated images.
|
||||
ZX_PROPERTY(bool, tryRotate, setTryRotate)
|
||||
|
||||
/// Also try detecting inverted ("reversed reflectance") codes if the format allows for those.
|
||||
ZX_PROPERTY(bool, tryInvert, setTryInvert)
|
||||
|
||||
/// Also try detecting code in downscaled images (depending on image size).
|
||||
ZX_PROPERTY(bool, tryDownscale, setTryDownscale)
|
||||
|
||||
#ifdef ZXING_EXPERIMENTAL_API
|
||||
/// Also try detecting code after denoising (currently morphological closing filter for 2D symbologies only).
|
||||
ZX_PROPERTY(bool, tryDenoise, setTryDenoise)
|
||||
#endif
|
||||
|
||||
/// Binarizer to use internally when using the ReadBarcode function
|
||||
ZX_PROPERTY(Binarizer, binarizer, setBinarizer)
|
||||
|
||||
/// Set to true if the input contains nothing but a single perfectly aligned barcode (generated image)
|
||||
ZX_PROPERTY(bool, isPure, setIsPure)
|
||||
|
||||
/// Image size ( min(width, height) ) threshold at which to start downscaled scanning
|
||||
// WARNING: this API is experimental and may change/disappear
|
||||
ZX_PROPERTY(uint16_t, downscaleThreshold, setDownscaleThreshold)
|
||||
|
||||
/// Scale factor used during downscaling, meaningful values are 2, 3 and 4
|
||||
// WARNING: this API is experimental and may change/disappear
|
||||
ZX_PROPERTY(uint8_t, downscaleFactor, setDownscaleFactor)
|
||||
|
||||
/// The number of scan lines in a linear barcode that have to be equal to accept the result, default is 2
|
||||
ZX_PROPERTY(uint8_t, minLineCount, setMinLineCount)
|
||||
|
||||
/// The maximum number of symbols (barcodes) to detect / look for in the image with ReadBarcodes
|
||||
ZX_PROPERTY(uint8_t, maxNumberOfSymbols, setMaxNumberOfSymbols)
|
||||
|
||||
/// Enable the heuristic to detect and decode "full ASCII"/extended Code39 symbols
|
||||
ZX_PROPERTY(bool, tryCode39ExtendedMode, setTryCode39ExtendedMode)
|
||||
|
||||
/// Deprecated / does nothing. The Code39 symbol has a valid checksum iff symbologyIdentifier()[2] is an odd digit
|
||||
ZX_PROPERTY(bool, validateCode39CheckSum, setValidateCode39CheckSum, [[deprecated]])
|
||||
|
||||
/// Deprecated / does nothing. The ITF symbol has a valid checksum iff symbologyIdentifier()[2] == '1'.
|
||||
ZX_PROPERTY(bool, validateITFCheckSum, setValidateITFCheckSum, [[deprecated]])
|
||||
|
||||
/// Deprecated / does nothing. Codabar start/stop characters are always returned.
|
||||
ZX_PROPERTY(bool, returnCodabarStartEnd, setReturnCodabarStartEnd, [[deprecated]])
|
||||
|
||||
/// If true, return the barcodes with errors as well (e.g. checksum errors, see @Barcode::error())
|
||||
ZX_PROPERTY(bool, returnErrors, setReturnErrors)
|
||||
|
||||
/// Specify whether to ignore, read or require EAN-2/5 add-on symbols while scanning EAN/UPC codes
|
||||
ZX_PROPERTY(EanAddOnSymbol, eanAddOnSymbol, setEanAddOnSymbol)
|
||||
|
||||
/// Specifies the TextMode that controls the return of the Barcode::text() function
|
||||
ZX_PROPERTY(TextMode, textMode, setTextMode)
|
||||
|
||||
/// Specifies fallback character set to use instead of auto-detecting it (when applicable)
|
||||
ZX_PROPERTY(CharacterSet, characterSet, setCharacterSet)
|
||||
ReaderOptions& setCharacterSet(std::string_view v)& { return (void)(_characterSet = CharacterSetFromString(v)), *this; }
|
||||
ReaderOptions&& setCharacterSet(std::string_view v) && { return (void)(_characterSet = CharacterSetFromString(v)), std::move(*this); }
|
||||
|
||||
#undef ZX_PROPERTY
|
||||
|
||||
bool hasFormat(BarcodeFormats f) const noexcept { return _formats.testFlags(f) || _formats.empty(); }
|
||||
};
|
||||
|
||||
#ifndef HIDE_DECODE_HINTS_ALIAS
|
||||
using DecodeHints [[deprecated]] = ReaderOptions;
|
||||
#endif
|
||||
|
||||
} // ZXing
|
||||
@@ -0,0 +1,10 @@
|
||||
/*
|
||||
* Copyright 2024 Axel Waggershauser
|
||||
*/
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Barcode.h"
|
||||
|
||||
#pragma message("Header `Result.h` is deprecated, please include `Barcode.h` and use the new name `Barcode`.")
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright 2021 Axel Waggershauser
|
||||
*/
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace ZXing {
|
||||
|
||||
struct StructuredAppendInfo
|
||||
{
|
||||
int index = -1;
|
||||
int count = -1;
|
||||
std::string id;
|
||||
};
|
||||
|
||||
} // ZXing
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright 2016 Nu-book Inc.
|
||||
*/
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
namespace ZXing::TextUtfEncoding {
|
||||
|
||||
// The following functions are not required anymore after Barcode::text() now returns utf8 natively and the encoders accept utf8 as well.
|
||||
|
||||
[[deprecated]] std::string ToUtf8(std::wstring_view str);
|
||||
[[deprecated]] std::string ToUtf8(std::wstring_view str, const bool angleEscape);
|
||||
[[deprecated]] std::wstring FromUtf8(std::string_view utf8);
|
||||
|
||||
} // namespace ZXing::TextUtfEncoding
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright 2019 Nu-book Inc.
|
||||
* Copyright 2023 Axel Waggershauser
|
||||
*/
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#define ZXING_READERS
|
||||
#define ZXING_WRITERS
|
||||
|
||||
// Version numbering
|
||||
#define ZXING_VERSION_MAJOR 2
|
||||
#define ZXING_VERSION_MINOR 3
|
||||
#define ZXING_VERSION_PATCH 0
|
||||
|
||||
#define ZXING_VERSION_STR "2.3.0"
|
||||
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
* Copyright 2017 Axel Waggershauser
|
||||
*/
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Error.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <charconv>
|
||||
#include <cstring>
|
||||
#include <initializer_list>
|
||||
#include <iterator>
|
||||
#include <numeric>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
|
||||
namespace ZXing {
|
||||
|
||||
template <class T, class U>
|
||||
constexpr T narrow_cast(U&& u) noexcept {
|
||||
return static_cast<T>(std::forward<U>(u));
|
||||
}
|
||||
|
||||
template <typename Container, typename Value>
|
||||
auto Find(Container& c, const Value& v) -> decltype(std::begin(c)) {
|
||||
return std::find(std::begin(c), std::end(c), v);
|
||||
}
|
||||
|
||||
template <typename Container, typename Predicate>
|
||||
auto FindIf(Container& c, Predicate p) -> decltype(std::begin(c)) {
|
||||
return std::find_if(std::begin(c), std::end(c), p);
|
||||
}
|
||||
|
||||
template <typename Container, typename Value>
|
||||
auto Contains(const Container& c, const Value& v) -> decltype(std::begin(c), bool()){
|
||||
return Find(c, v) != std::end(c);
|
||||
}
|
||||
|
||||
template <typename ListType, typename Value>
|
||||
auto Contains(const std::initializer_list<ListType>& c, const Value& v) -> decltype(std::begin(c), bool()){
|
||||
return Find(c, v) != std::end(c);
|
||||
}
|
||||
|
||||
inline bool Contains(const char* str, char c) {
|
||||
return strchr(str, c) != nullptr;
|
||||
}
|
||||
|
||||
inline bool Contains(std::string_view str, std::string_view substr) {
|
||||
return str.find(substr) != std::string_view::npos;
|
||||
}
|
||||
|
||||
template <template <typename...> typename C, typename... Ts>
|
||||
auto FirstOrDefault(C<Ts...>&& container)
|
||||
{
|
||||
return container.empty() ? typename C<Ts...>::value_type() : std::move(container.front());
|
||||
}
|
||||
|
||||
template <typename Iterator, typename Value = typename std::iterator_traits<Iterator>::value_type, typename Op = std::plus<Value>>
|
||||
Value Reduce(Iterator b, Iterator e, Value v = Value{}, Op op = {}) {
|
||||
// std::reduce() first sounded like a better implementation because it is not implemented as a strict left-fold
|
||||
// operation, meaning the order of the op-application is not specified. This sounded like an optimization opportunity
|
||||
// but it turns out that for this use case it actually does not make a difference (falsepositives runtime). And
|
||||
// when tested with a large std::vector<uint16_t> and proper autovectorization (e.g. clang++ -O2) it turns out that
|
||||
// std::accumulate can be twice as fast as std::reduce.
|
||||
return std::accumulate(b, e, v, op);
|
||||
}
|
||||
|
||||
template <typename Container, typename Value = typename Container::value_type, typename Op = std::plus<Value>>
|
||||
Value Reduce(const Container& c, Value v = Value{}, Op op = {}) {
|
||||
return Reduce(std::begin(c), std::end(c), v, op);
|
||||
}
|
||||
|
||||
// see C++20 ssize
|
||||
template <class Container>
|
||||
constexpr auto Size(const Container& c) -> decltype(c.size(), int()) {
|
||||
return narrow_cast<int>(c.size());
|
||||
}
|
||||
|
||||
template <class T, std::size_t N>
|
||||
constexpr int Size(T const (&)[N]) noexcept {
|
||||
return narrow_cast<int>(N);
|
||||
}
|
||||
|
||||
inline constexpr int Size(const char* s) noexcept {
|
||||
return narrow_cast<int>(std::char_traits<char>::length(s));
|
||||
}
|
||||
|
||||
inline constexpr int Size(char) noexcept { return 1; }
|
||||
|
||||
template <typename... Args>
|
||||
std::string StrCat(Args&&... args)
|
||||
{
|
||||
std::string res;
|
||||
res.reserve((Size(args) + ...));
|
||||
(res += ... += args);
|
||||
return res;
|
||||
}
|
||||
|
||||
template <typename Container, typename Value>
|
||||
int IndexOf(const Container& c, const Value& v) {
|
||||
auto i = Find(c, v);
|
||||
return i == std::end(c) ? -1 : narrow_cast<int>(std::distance(std::begin(c), i));
|
||||
}
|
||||
|
||||
inline int IndexOf(const char* str, char c) {
|
||||
auto s = strchr(str, c);
|
||||
return s != nullptr ? narrow_cast<int>(s - str) : -1;
|
||||
}
|
||||
|
||||
template <typename Container, typename Value, class UnaryOp>
|
||||
Value TransformReduce(const Container& c, Value s, UnaryOp op) {
|
||||
for (const auto& v : c)
|
||||
s += op(v);
|
||||
return s;
|
||||
}
|
||||
|
||||
template <typename T = char>
|
||||
T ToDigit(int i)
|
||||
{
|
||||
if (i < 0 || i > 9)
|
||||
throw FormatError("Invalid digit value");
|
||||
return static_cast<T>('0' + i);
|
||||
}
|
||||
|
||||
template<typename T, typename = std::enable_if_t<std::is_integral_v<T>>>
|
||||
std::string ToString(T val, int len)
|
||||
{
|
||||
std::string result(len--, '0');
|
||||
if (val < 0)
|
||||
throw FormatError("Invalid value");
|
||||
for (; len >= 0 && val != 0; --len, val /= 10)
|
||||
result[len] = '0' + val % 10;
|
||||
if (val)
|
||||
throw FormatError("Invalid value");
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
constexpr std::string_view TypeName()
|
||||
{
|
||||
#ifdef __clang__
|
||||
std::string_view p = __PRETTY_FUNCTION__;
|
||||
return p.substr(40, p.size() - 40 - 1);
|
||||
#elif defined(__GNUC__)
|
||||
std::string_view p = __PRETTY_FUNCTION__;
|
||||
return p.substr(55, p.find(';', 55) - 55);
|
||||
#elif defined(_MSC_VER)
|
||||
std::string_view p = __FUNCSIG__;
|
||||
return p.substr(90, p.size() - 90 - 7);
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename T, typename = std::enable_if_t<std::is_arithmetic_v<T>>>
|
||||
inline T FromString(std::string_view sv)
|
||||
{
|
||||
T val = {};
|
||||
auto [ptr, ec] = std::from_chars(sv.data(), sv.data() + sv.size(), val);
|
||||
if (ec != std::errc() || ptr != sv.data() + sv.size())
|
||||
throw std::invalid_argument(StrCat("failed to parse '", TypeName<T>(), "' from '", sv, "'"));
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void UpdateMin(T& min, T val)
|
||||
{
|
||||
min = std::min(min, val);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void UpdateMax(T& max, T val)
|
||||
{
|
||||
max = std::max(max, val);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void UpdateMinMax(T& min, T& max, T val)
|
||||
{
|
||||
min = std::min(min, val);
|
||||
max = std::max(max, val);
|
||||
|
||||
// Note: the above code is not equivalent to
|
||||
// if (val < min) min = val;
|
||||
// else if (val > max) max = val;
|
||||
// It is basically the same but without the 'else'. For the 'else'-variant to work,
|
||||
// both min and max have to be initialized with a value that is part of the sequence.
|
||||
// Also it turns out clang and gcc can vectorize the code above but not the code below.
|
||||
}
|
||||
|
||||
} // ZXing
|
||||
@@ -0,0 +1,10 @@
|
||||
/*
|
||||
* Copyright 2024 Axel Waggershauser
|
||||
*/
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Version.h"
|
||||
|
||||
#pragma message("Header `ZXVersion.h` is deprecated, please include `Version.h`.")
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2024 Axel Waggershauser
|
||||
*/
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BarcodeFormat.h"
|
||||
#include "ReadBarcode.h"
|
||||
#include "WriteBarcode.h"
|
||||
|
||||
namespace ZXing {
|
||||
|
||||
const std::string& Version();
|
||||
|
||||
#ifdef ZXING_EXPERIMENTAL_API
|
||||
|
||||
enum class Operation
|
||||
{
|
||||
Create,
|
||||
Read,
|
||||
CreateAndRead,
|
||||
CreateOrRead,
|
||||
};
|
||||
|
||||
BarcodeFormats SupportedBarcodeFormats(Operation op = Operation::CreateOrRead);
|
||||
|
||||
#endif // ZXING_EXPERIMENTAL_API
|
||||
|
||||
} // namespace ZXing
|
||||
Reference in New Issue
Block a user