Ocean
Loading...
Searching...
No Matches
QRCodeEncoderBase.h
Go to the documentation of this file.
1/*
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
8#pragma once
9
11
13
14#include "ocean/math/Vector2.h"
15
16#include <cctype>
17
18namespace Ocean
19{
20
21namespace CV
22{
23
24namespace Detector
25{
26
27namespace QRCodes
28{
29
30/**
31 * This class implements basic QRCodeEncoder functionality
32 * @ingroup cvdetectorqrcodes
33 */
34class OCEAN_CV_DETECTOR_QRCODES_EXPORT QRCodeEncoderBase
35{
36 public:
37
38 /// Codeword: sequence of 8 bits
39 typedef uint8_t Codeword;
40
41 /// Vector of codewords
42 typedef std::vector<Codeword> Codewords;
43
44 /// Typedef for a bit buffer
45 typedef std::vector<uint8_t> BitBuffer;
46
47 /// Forward declaration of the segment class
48 class Segment;
49
50 /// Typedef for a vector of segments
51 typedef std::vector<Segment> Segments;
52
53 /**
54 * Enum for the error codes returned by the encoding functions
55 */
56 enum StatusCode : uint32_t
57 {
58 /// The encoding was successful
59 SC_SUCCESS = 0u,
60
61 /// The data given exceeds the maximum capacity of the QR code
63
64 /// The data given is not valid
66
67 // The error correction level is not valid
69
70 /// The encoding failed due to an unknown reason
71 SC_UNKNOWN_ERROR
72 };
73
74 /**
75 * Definition of the segment class
76 * A sequence is a sequence of data encoded according to the rules of one ECI or encodation mode
77 */
78 class OCEAN_CV_DETECTOR_QRCODES_EXPORT Segment
79 {
80 public:
81 /**
82 * Constructor for segments
83 * @param mode The data encodation mode of this segment
84 * @param characters The number of characters stored in this segment, range: [0, infinity)
85 * @param bitBuffer The bit sequence representing the data stored in this segment, must be valid
86 */
87 inline Segment(const QRCode::EncodingMode mode, const unsigned int characters, BitBuffer& bitBuffer);
88
89 /**
90 * Returns the encodation mode set for this segment
91 * @return The encodation mode
92 */
93 inline QRCode::EncodingMode encodationMode() const;
94
95 /**
96 * Returns the number of characters stored in this segment
97 * @return The number of characters stored in this segment
98 */
99 inline unsigned int characters() const;
100
101 /**
102 * Returns the encoded bits stored in this segment
103 * @return The encoded bits
104 */
105 inline const BitBuffer& bitBuffer() const;
106
107 /**
108 * Encode a sequence of digits (0-9) and store it in a segment
109 * @param data The data that will be encoded, must be a sequence of digits, i.e., `isNumeric(data) == true`
110 * @param segments The segment storing the encoded data will be appended to this vector, memory will be initialized internally
111 * @return True if the data was successfully encoded, otherwise false
112 */
113 static StatusCode generateSegmentNumeric(const std::string& data, Segments& segments);
114
115 /**
116 * Encode a sequence of alphanumeric characters (cf. ISO/IEC 18004:2015, Table 5) and store it in a segment
117 * @param data The data that will be encoded, must be a sequence of alphanumeric characters, i.e., `isAlphanumeric(data) == true`
118 * @param segments The segment storing the encoded data will be appended to this vector, memory will be initialized internally
119 * @return True if the data was successfully encoded, otherwise false
120 */
121 static StatusCode generateSegmentAlphanumeric(const std::string& data, Segments& segments);
122
123 /**
124 * Encode a sequence of bytes and store it in a segment
125 * @param data The data that will be encoded
126 * @param segments The segment storing the encoded data will be appended to this vector, memory will be initialized internally
127 * @return True if the data was successfully encoded, otherwise false
128 */
129 static StatusCode generateSegmentsBytes(const std::vector<uint8_t>& data, Segments& segments);
130
131 /**
132 * Helper function to append a certain number of bits of a number to a bit buffer
133 * @param value The value of which the first `N` bits will be appended to the bit buffer
134 * @param bits The number of bits to append, range: [0, sizeof(unsigned int) * 8]
135 * @param bitBuffer The bit buffer to which the `N` bits will be appended
136 */
137 static inline void bitBufferAppend(const unsigned int value, size_t bits, BitBuffer& bitBuffer);
138
139 /**
140 * Test to check if data is numeric (consisting of only digits)
141 * @param data The data to be tested
142 * @return True if the data consists of only digits, otherwise false
143 */
144 static inline bool isNumericData(const std::string& data);
145
146 /**
147 * Test to check if data contains only alphanumeric characters
148 * @param data The data to be tested
149 * @return True if the data consists of alphanumeric characters, otherwise false
150 * @sa getAlphanumericCharset()
151 */
152 static inline bool isAlphanumericData(const std::string& data);
153
154 /**
155 * Returns the character set for the alphanumeric data mode
156 * The character set for the alphanumeric data mode, cf. ISO/IEC 18004:2015, Table 5. The index
157 * of each character in the string corresponds to the value assigned to them in the alphanumeric
158 * encoding/decoding table.
159 * @return The character set for the alphanumeric data mode.
160 */
161 static inline const std::string& getAlphanumericCharset();
162
163 protected:
164
165 /// The mode used to encode the data of this segment
167
168 /// The number of characters stored in this segment
169 unsigned int characters_;
170
171 /// The actual encoded data (sequence of bits)
173 };
174
175 /**
176 * Definition of the ReedSolomon class
177 */
179 {
180 public:
181
182 /// Coefficients of the divisor polynomial, stored from highest to lower power (excluding the leading term which is always 1). Example x^3 + 255x^2 + 8x + 93 is stored as {255, 8, 93}.
183 typedef std::vector<uint8_t> Coefficients;
184
185 public:
186
187 /**
188 * Generates the Reed-Solomon coefficients for a divisor polynomial of degree `N`.
189 * @param degree The degree of the divisor polynomial, range: [1, infinity)
190 * @return The coeffiencts of the divisor polynomial (will have `N = degree` elements)
191 */
192 static Coefficients generateCoefficients(const unsigned int degree);
193
194 /**
195 * Computes the Reed-Solomon error correction codewords for a sequence of data codewords
196 * @param codewords The input codewords for which the error correction will be computed
197 * @param coefficients The coefficients of the Reed-Solomon divisor polynomial of degree `N`
198 * @return The error correction codewords
199 */
200 static Codewords computeRemainders(const Codewords& codewords, const Coefficients& coefficients);
201
202 protected:
203
204 /**
205 * Return the product of two fields modulo GF(2^8/0x11D)
206 */
207 static uint8_t multiply(const uint8_t a, const uint8_t b);
208 };
209
210 /**
211 * Computes the remainder of a polynomial long division for (n, k) BCH codes
212 * Notation:
213 * n : block length in bits
214 * k : number of information/data bits
215 * @param data The data used as the nominator in this division
216 * @return The remainder of the polynomial division
217 * @tparam tBlockLength The length, n, of the BCH code in bits, range: (tDataLength, infinity)
218 * @tparam tDataLength The number the information/data bits, k, range: [1, tBlockLength)
219 * @tparam tGeneratorPolynomial The generator polynomial used by this code for the polynomial division. This is specificied as an integer (or binary number). Range: (0, 2^n - 1) (Important: make sure this value is correct according to the Galois field theory behind it, there are no additional sanity checks)
220 */
221 template <uint32_t tBlockLength, uint32_t tDataLength, uint32_t tGeneratorPolynomial>
222 static inline uint32_t computePolynomialDivisonRemainderBCH(const uint32_t data);
223
224 /**
225 * Determines the number of 1-bits in an integer value (Hamming weight)
226 * @param value The value of which the 1-bits will be counted
227 * @return The number of 1-bits in the input value
228 */
229 static inline uint32_t computeHammingWeight(uint32_t value);
230
231 /**
232 * Translates the given status code into a human readable string
233 */
234 static inline std::string translateStatusCode(const StatusCode statusCode);
235};
236
237inline QRCodeEncoderBase::Segment::Segment(const QRCode::EncodingMode mode, const unsigned int characters, BitBuffer& bitBuffer) :
238 encodationMode_(mode),
239 characters_(characters),
240 bitBuffer_(bitBuffer)
241{
242 // Nothing else to do.
243}
244
246{
247 return encodationMode_;
248}
249
250inline unsigned int QRCodeEncoderBase::Segment::characters() const
251{
252 return characters_;
253}
254
256{
257 return bitBuffer_;
258}
259
260inline bool QRCodeEncoderBase::Segment::isNumericData(const std::string& data)
261{
262 for (size_t i = 0; i < data.size(); ++i)
263 {
264 if (std::isdigit((unsigned char)data[i]) == false)
265 {
266 return false;
267 }
268 }
269
270 return data.size() != 0;
271}
272
273inline bool QRCodeEncoderBase::Segment::isAlphanumericData(const std::string& data)
274{
275 if (data.empty())
276 {
277 return false;
278 }
279
280 const std::string& alphanumericCharset = getAlphanumericCharset();
281
282 for (const char character : data)
283 {
284 if (alphanumericCharset.find(character) == std::string::npos)
285 {
286 return false;
287 }
288 }
289
290 return true;
291}
292
294{
295 const static std::string alphanumericCharset = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:";
296 ocean_assert(alphanumericCharset.size() == 45);
297
298 return alphanumericCharset;
299}
300
301inline void QRCodeEncoderBase::Segment::bitBufferAppend(const unsigned int value, size_t bits, BitBuffer& bitBuffer)
302{
303 ocean_assert(bits <= sizeof(unsigned int) * 8);
304
305 if (bits == 0u)
306 {
307 return;
308 }
309
310 for (size_t i = bits - 1; i < bits; --i)
311 {
312 bitBuffer.push_back((value >> i) & 1);
313 }
314}
315
316template <uint32_t tBlockLength, uint32_t tDataLength, uint32_t tGeneratorPolynomial>
318{
319 static_assert(tBlockLength != 0u && tDataLength != 0u && tBlockLength > tDataLength, "The block length must be larger than the number of data bits and both must be nonzero.");
320 static_assert(tGeneratorPolynomial != 0u && tGeneratorPolynomial >> tBlockLength == 0u, "The generator polynomial cannot be zero and must fit into the block length");
321 ocean_assert(data >> tBlockLength == 0u);
322
323 // Example for a (15, 5) BCH code:
324 //
325 // * block length: 15
326 // * data length: 5
327 // * generator polynomial = 10100110111 ~ G(x) = x^10 + x^8 + x^5 + x^4 + x^2 + x + 1
328 // * data = 000111101011001, i.e. 00011|1101011001
329 // data | error correction
330 //
331 // remainder0 = 000111101011001
332 // ^ 10100110111 skip step - left-most bit of the remainder is zero
333 // -----------------
334 // remainder1 = 000111101011001
335 // ^ 10100110111 skip step - left-most bit of the remainder is zero
336 // -----------------
337 // remainder2 = 000111101011001
338 // ^ 10100110111 skip step - left-most bit of the remainder is zero
339 // -----------------
340 // remainder3 = 000111101011001
341 // ^ 10100110111
342 // -----------------
343 // remainder4 = 000010100110111
344 // ^ 10100110111
345 // -----------------
346 // remainder = 000000000000000
347
348 constexpr uint32_t errorCorrectionBits = tBlockLength - tDataLength;
349
350 uint32_t remainder = data;
351
352 for (uint32_t i = 0u; i < tDataLength; ++i)
353 {
354 ocean_assert(tDataLength >= i + 1u);
355 const uint32_t shift = tDataLength - i - 1u;
356
357 if (remainder & (1u << (shift + errorCorrectionBits)))
358 {
359 remainder ^= tGeneratorPolynomial << shift;
360 }
361 }
362
363 ocean_assert(tGeneratorPolynomial > remainder);
364 return remainder;
365}
366
367inline uint32_t QRCodeEncoderBase::computeHammingWeight(uint32_t value)
368{
369 uint32_t weight = 0u;
370
371 while (value > 0u)
372 {
373 value = value & (value - 1u);
374 weight += 1u;
375 }
376
377 return weight;
378}
379
381{
382 switch (statusCode)
383 {
384 case SC_SUCCESS:
385 return "SUCCESS";
387 return "CODE_CAPACITY_EXCEEDED";
388 case SC_INVALID_DATA:
389 return "INVALID_DATA";
391 return "INVALID_ERROR_CORRECTION_CAPACITY";
392 case SC_UNKNOWN_ERROR:
393 return "UNKNOWN_ERROR";
394 }
395
396 ocean_assert(false && "Never be here!");
397 return "UNKOWN";
398}
399
400} // namespace QRCodes
401
402} // namespace Detector
403
404} // namespace CV
405
406} // namespace Ocean
EncodingMode
Definition of encoding modes.
Definition QRCodeBase.h:72
Definition of the ReedSolomon class.
Definition QRCodeEncoderBase.h:179
std::vector< uint8_t > Coefficients
Coefficients of the divisor polynomial, stored from highest to lower power (excluding the leading ter...
Definition QRCodeEncoderBase.h:183
static Coefficients generateCoefficients(const unsigned int degree)
Generates the Reed-Solomon coefficients for a divisor polynomial of degree N.
static Codewords computeRemainders(const Codewords &codewords, const Coefficients &coefficients)
Computes the Reed-Solomon error correction codewords for a sequence of data codewords.
static uint8_t multiply(const uint8_t a, const uint8_t b)
Return the product of two fields modulo GF(2^8/0x11D)
Definition of the segment class A sequence is a sequence of data encoded according to the rules of on...
Definition QRCodeEncoderBase.h:79
static bool isAlphanumericData(const std::string &data)
Test to check if data contains only alphanumeric characters.
Definition QRCodeEncoderBase.h:273
static StatusCode generateSegmentNumeric(const std::string &data, Segments &segments)
Encode a sequence of digits (0-9) and store it in a segment.
static StatusCode generateSegmentsBytes(const std::vector< uint8_t > &data, Segments &segments)
Encode a sequence of bytes and store it in a segment.
QRCode::EncodingMode encodationMode() const
Returns the encodation mode set for this segment.
Definition QRCodeEncoderBase.h:245
static bool isNumericData(const std::string &data)
Test to check if data is numeric (consisting of only digits)
Definition QRCodeEncoderBase.h:260
unsigned int characters_
The number of characters stored in this segment.
Definition QRCodeEncoderBase.h:169
QRCode::EncodingMode encodationMode_
The mode used to encode the data of this segment.
Definition QRCodeEncoderBase.h:166
static void bitBufferAppend(const unsigned int value, size_t bits, BitBuffer &bitBuffer)
Helper function to append a certain number of bits of a number to a bit buffer.
Definition QRCodeEncoderBase.h:301
BitBuffer bitBuffer_
The actual encoded data (sequence of bits)
Definition QRCodeEncoderBase.h:172
unsigned int characters() const
Returns the number of characters stored in this segment.
Definition QRCodeEncoderBase.h:250
Segment(const QRCode::EncodingMode mode, const unsigned int characters, BitBuffer &bitBuffer)
Constructor for segments.
Definition QRCodeEncoderBase.h:237
const BitBuffer & bitBuffer() const
Returns the encoded bits stored in this segment.
Definition QRCodeEncoderBase.h:255
static const std::string & getAlphanumericCharset()
Returns the character set for the alphanumeric data mode The character set for the alphanumeric data ...
Definition QRCodeEncoderBase.h:293
static StatusCode generateSegmentAlphanumeric(const std::string &data, Segments &segments)
Encode a sequence of alphanumeric characters (cf.
This class implements basic QRCodeEncoder functionality.
Definition QRCodeEncoderBase.h:35
static uint32_t computePolynomialDivisonRemainderBCH(const uint32_t data)
Computes the remainder of a polynomial long division for (n, k) BCH codes Notation: n : block length ...
Definition QRCodeEncoderBase.h:317
std::vector< uint8_t > BitBuffer
Typedef for a bit buffer.
Definition QRCodeEncoderBase.h:45
static std::string translateStatusCode(const StatusCode statusCode)
Translates the given status code into a human readable string.
Definition QRCodeEncoderBase.h:380
static uint32_t computeHammingWeight(uint32_t value)
Determines the number of 1-bits in an integer value (Hamming weight)
Definition QRCodeEncoderBase.h:367
std::vector< Segment > Segments
Typedef for a vector of segments.
Definition QRCodeEncoderBase.h:51
uint8_t Codeword
Codeword: sequence of 8 bits.
Definition QRCodeEncoderBase.h:39
StatusCode
Enum for the error codes returned by the encoding functions.
Definition QRCodeEncoderBase.h:57
@ SC_INVALID_ERROR_CORRECTION_CAPACITY
Definition QRCodeEncoderBase.h:68
@ SC_CODE_CAPACITY_EXCEEDED
The data given exceeds the maximum capacity of the QR code.
Definition QRCodeEncoderBase.h:62
@ SC_UNKNOWN_ERROR
The encoding failed due to an unknown reason.
Definition QRCodeEncoderBase.h:71
@ SC_INVALID_DATA
The data given is not valid.
Definition QRCodeEncoderBase.h:65
@ SC_SUCCESS
The encoding was successful.
Definition QRCodeEncoderBase.h:59
std::vector< Codeword > Codewords
Vector of codewords.
Definition QRCodeEncoderBase.h:42
std::vector< QRCode > QRCodes
Definition of a vector of QR codes.
Definition QRCode.h:28
The namespace covering the entire Ocean framework.
Definition Accessor.h:15