chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 12:36:49 +08:00
commit e7ae061fa2
2645 changed files with 497412 additions and 0 deletions
+230
View File
@@ -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
+79
View File
@@ -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
+210
View File
@@ -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
+195
View File
@@ -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
+21
View File
@@ -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
+60
View File
@@ -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
+59
View File
@@ -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
+91
View File
@@ -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
+10
View File
@@ -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)
+73
View File
@@ -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);
}
+120
View File
@@ -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
+53
View File
@@ -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
+148
View File
@@ -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
+118
View File
@@ -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
+164
View File
@@ -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
+177
View File
@@ -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
+113
View File
@@ -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
+33
View File
@@ -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
+179
View File
@@ -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
+10
View File
@@ -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
+19
View File
@@ -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
+17
View File
@@ -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"
+193
View File
@@ -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
+10
View File
@@ -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`.")
+30
View File
@@ -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