Ocean
QRCodeEncoder.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 
15 
16 #include "ocean/math/Vector2.h"
17 
18 #include <cctype>
19 
20 namespace Ocean
21 {
22 
23 namespace CV
24 {
25 
26 namespace Detector
27 {
28 
29 namespace QRCodes
30 {
31 
32 /**
33  * This class implements an encoder and decoder for QR codes.
34  * @ingroup cvdetectorqrcodes
35  */
36 class OCEAN_CV_DETECTOR_QRCODES_EXPORT QRCodeEncoder : public QRCodeEncoderBase
37 {
38  public:
39 
40  /**
41  * Enum for the mask patterns used to shuffle modules of a QR code.
42  * The values of the enum items correspond to the standard-defined bit sequences for the masks (3 bits long)
43  */
44  enum MaskingPattern : uint32_t
45  {
46  /// Masking condition: (i + j) mod 2 = 0
47  MP_PATTERN_0 = 0b000u,
48 
49  /// Masking condition: i mod 2 = 0
50  MP_PATTERN_1 = 0b001u,
51 
52  /// Masking condition: j mod 3 = 0
53  MP_PATTERN_2 = 0b010u,
54 
55  /// Masking condition: (i + j) mod 3 = 0
56  MP_PATTERN_3 = 0b011u,
57 
58  /// Masking condition: ((i div 2) + (j div 3)) mod 2 = 0
59  MP_PATTERN_4 = 0b100u,
60 
61  /// Masking condition: (i j) mod 2 + (i j) mod 3 = 0
62  MP_PATTERN_5 = 0b101u,
63 
64  /// Masking condition: ((i j) mod 2 + (i j) mod 3) mod 2 = 0
65  MP_PATTERN_6 = 0b110u,
66 
67  /// Masking condition: ((i j) mod 3 + (i+j) mod 2) mod 2 = 0
68  MP_PATTERN_7 = 0b111u,
69 
70  /// Denotes unknown masking patterns (not part of the standard)
71  MP_PATTERN_UNKNOWN = uint32_t(-1)
72  };
73 
74  /// Number of error correction codewords (rows: 0 - low, 1 - medium, 2 - quartile, 3 - high, column 0 is ignored since no version 0 exists), cf. ISO/IEC 18004:2015, Table 9, column 4
75  static const int8_t ECC_CODEWORDS_PER_BLOCK[4][41];
76 
77  /// Number of error correction blocks (rows: 0 - low, 1 - medium, 2 - quartile, 3 - high, column 0 is ignored since no version 0 exists), cf. ISO/IEC 18004:2015, Table 9, column 6
78  static const int8_t NUM_ERROR_CORRECTION_BLOCKS[4][41];
79 
80  public:
81 
82  /**
83  * Encode text and store it in a QR code, will automatically choose the most efficient encodation mode
84  * @param text The text/data to be encoded as a QR code
85  * @param errorCorrectionCapacity Specifies the level of possible error correction
86  * @param qrcode The QR code that will store the encoded data
87  * @return `SC_SUCCESS` on success, otherwise it will return a status indicating the reason for failure
88  */
89  static StatusCode encodeText(const std::string& text, const QRCode::ErrorCorrectionCapacity errorCorrectionCapacity, QRCode& qrcode);
90 
91  /**
92  * Encode binary data and store it in a QR code, will always use the byte encodation mode
93  * @param data The data to be encoded as a QR code
94  * @param errorCorrectionCapacity Specifies the level of possible error correction
95  * @param qrcode The QR code that will store the encoded data
96  * @return `SC_SUCCESS` on success, otherwise it will return a status indicating the reason for failure
97  */
98  static StatusCode encodeBinary(const std::vector<uint8_t>& data, QRCode::ErrorCorrectionCapacity errorCorrectionCapacity, QRCode& qrcode);
99 
100  /**
101  * Encodes the error correction level and the index of the masking pattern as a sequence of 15 bits with error correction ((15, 5) BCH code).
102  * @param errorCorrectionCapacity An error correction capacity that will be decoded
103  * @param maskingPattern The masking pattern that will be encoded
104  * @return The error correction level and masking pattern encoded as a sequence of 15 bits
105  */
106  static inline uint32_t encodeFormat(const QRCode::ErrorCorrectionCapacity errorCorrectionCapacity, const MaskingPattern maskingPattern);
107 
108  /**
109  * Decodes a sequence of 15 bits and extracts the encoded error correction level and index of the masking pattern
110  * Note: the format bit sequence can contain up to 3 bit error. More bit errors will cause this function to fail because the result would be ambiguous.
111  * @param formatBits A sequence of 15 bits containing the format information, range: [0, 2^15)
112  * @param errorCorrectionCapacity The error correction capacity extracted from the bit sequence
113  * @param maskingPattern The masking pattern extracted from the bit sequence
114  * @return True if the sequence was decoded successfully, otherwise false
115  */
116  static inline bool decodeFormatBits(const uint32_t formatBits, QRCode::ErrorCorrectionCapacity& errorCorrectionCapacity, MaskingPattern& maskingPattern);
117 
118  /**
119  * Encodes the version numbers as a sequences of 18 bits with error correction ((18, 6) BCH code).
120  * @param version The version number to be encoded as a 18 bit long sequence, range: [7, QRCode::MAX_VERSION] (QR code version 1-6 have no version information bit field)
121  * @return The version number encoded as a 18-bit long sequence
122  */
123  static inline uint32_t encodeVersion(const uint32_t version);
124 
125  /**
126  * Decodes a sequence of 18 bits and extracts the encoded version number
127  * Note: the version bit sequence can contain up to 4 bit error. More bit errors will cause this function to fail because the result would be ambiguous.
128  * @param versionBits The sequence of 18 bits containing the encoded version information, range: [0, 2^18)
129  * @param version The version number that was extracted from the input bit sequence
130  * @return True if the sequence was decoded successfully, otherwise false
131  */
132  static inline bool decodeVersionBits(const uint32_t versionBits, uint32_t& version);
133 
134  /**
135  * Computes the 2D locations of the alignment patterns for a specified version of a QR code
136  * @param version The version of a QR code, range: [QRCode::MIN_VERSION, QRCode::MAX_VERSION]
137  * @return The list of the locations of alignment patterns, the locations are guaranteed to be in row-wise order (left-to-right and top-to-bottom), will be empty for version 1
138  */
139  static VectorsI2 computeAlignmentPatternPositions(const unsigned int version);
140 
141  /**
142  * Encodes the format information as a sequence of 15 bits with error correction ((15, 5) BCH code).
143  * @param format The format bit sequence consisting of the concatenated error correction capacity (2 bits) and masking pattern (3 bits), range: [0, 32)
144  * @return The error correction level and masking pattern encoded as a sequence of 15 bits
145  * @sa encodeFormat(const ErrorCorrectionCapacity, const MaskingPattern)
146  */
147  static inline uint32_t encodeFormatBits(const uint32_t format);
148 
149  protected:
150 
151  /**
152  * Helper function to initialize a QR code instance
153  * @param version The version of this QR code, range: [QRCode::MIN_VERSION, QRCode::MAX_VERSION]
154  * @param errorCorrectionCapacity The error correction level that will be used to generate the error-corrected codewords stored in this QR code
155  * @param rawCodewords The encoded codewords. The size must fit exactly into the selected version of this QR code
156  * @param mask The index of the bit shuffle masked that was used to generate the modules of this QR code
157  * @param modules The resulting modules of the QR code
158  * @return `SC_SUCCESS` on success, otherwise it will return a status indicating the reason for failure
159  */
160  static StatusCode addErrorCorrectionAndCreateQRCode(const unsigned int version, const QRCode::ErrorCorrectionCapacity errorCorrectionCapacity, const Codewords& rawCodewords, MaskingPattern mask, std::vector<uint8_t>& modules);
161 
162  /**
163  * Encodes segments and writes them into a QR code
164  * @param segments The raw segements that will be encoded and written into the QR code instance, `qrcode`
165  * @param errorCorrectionCapacity The desired level of error recovery capacity. Note: if `maximizeErrorCorrectionCapacity` is true, this function will increase this level as long as it doesn't increase the size of the smallest QR code that can fit the data
166  * @param modules The resulting modules of the QR code
167  * @param version The resulting version of the QR code
168  * @param finalErrorCorrectionCapacity The resulting error correction capacity that the QR code will finally have
169  * @param minVersion The minimum version that the final QR code is supposed to have, range: [1, maxVersion]
170  * @param maxVersion The maximum version that the final QR code is supposed to have, range: [minVersion, QRCode::MAX_VERSION]. Note: if this value is chosen too small, the initialization may fail
171  * @param mask The index of the bit shuffle mask that is to be used, range: [0, 7] or (unsigned int)(-1). The latter value will cause this function to automatically select the optimal mask (cf. ISO/IEC 18004:2015, Section 7.8.3)
172  * @param maximizeErrorCorrectionCapacity If true, this function will try to maximize the error correction level as long as it doesn't increase the size of the smallest QR code that can fit the data, cf. `errorCorrectionCapacity`
173  * @return `SC_SUCCESS` on success, otherwise it will return a status indicating the reason for failure
174  */
175  static StatusCode encodeSegments(const Segments& segments, const QRCode::ErrorCorrectionCapacity errorCorrectionCapacity, std::vector<uint8_t>& modules, unsigned int& version, QRCode::ErrorCorrectionCapacity& finalErrorCorrectionCapacity, const unsigned int minVersion = 1u, const unsigned int maxVersion = QRCode::MAX_VERSION, const MaskingPattern mask = MP_PATTERN_UNKNOWN, const bool maximizeErrorCorrectionCapacity = true);
176 
177  /**
178  * Returns the number of modules that can be used to store data for a given QR code version
179  * This is the number of all modules less the number of function modules (finder pattern, timing pattern, alignment pattern, version and format information, black pixel, and separators)
180  * @param version The version of a QR code, range: [QRCode::MIN_VERSION, QRCode::MAX_VERSION]
181  * @return The number of modules that can be used to store data
182  */
183  static inline unsigned int totalNumberRawDataModules(const unsigned int version);
184 
185  /**
186  * Return the number of codewords for a specified version and error correction level
187  * @param version The version of a QR code, range: [QRCode::MIN_VERSION, QRCode::MAX_VERSION]
188  * @param errorCorrectionCapacity The error correction level of a QR code
189  * @return The total number of codewords that fit into such a QR code
190  */
191  static inline unsigned int totalNumberDataCodewords(const unsigned int version, const QRCode::ErrorCorrectionCapacity errorCorrectionCapacity);
192 
193  /**
194  * Computes the number of bits used given some data (segments) for a specified version of a QR code (this number varies depending on the version, i.e. bits per character)
195  * @param segments The segments for which the number of bits will be computed
196  * @param version The version of a QR code, range: [QRCode::MIN_VERSION, QRCode::MAX_VERSION]
197  * @param bitsUsed The total number of bits the `segments` will need in a QR code of version `version`
198  * @return True on success, otherwise false (e.g. because of an overflow)
199  */
200  static inline bool computeTotalBitsUsed(const Segments& segments, const unsigned int version, unsigned int& bitsUsed);
201 
202  /**
203  * Generates the error correction codewords and interleaves the with the raw codewords
204  * @param codewords The raw code words for which the error code will be generated, must be valid
205  * @param version The version of the designated QR code, range: [QRCode::MIN_VERSION, QRCode::MAX_VERSION]
206  * @param errorCorrectionCapacity The level of error correction to be used
207  * @return The error-corrected + interleaved codewords
208  */
209  static Codewords addErrorCorrectionAndInterleave(const Codewords& codewords, const unsigned int version, const QRCode::ErrorCorrectionCapacity errorCorrectionCapacity);
210 
211  /**
212  * Applies a data shuffle mask to the specified modules
213  * Note: Calling this function on the same data and with the same parameters a second time will undo the changes from the first time (because of the XOR used internally)
214  * @param modules The modules that will be shuffled, must be valid
215  * @param version The version of the designated QR code, range: [QRCode::MIN_VERSION, QRCode::MAX_VERSION]
216  * @param functionPatternMask The binary mask that indicates the location of function patterns (finder patern, etc.), which should not be shuffled, cf. `setFunctionPatterns()`
217  * @param mask The index of the shuffle mask, range: [0, 7]
218  * @sa setFunctionPatterns()
219  */
220  static void applyMaskPattern(std::vector<uint8_t>& modules, const unsigned int version, const std::vector<uint8_t>& functionPatternMask, const MaskingPattern mask);
221 
222  /**
223  * Computes a penalty value (fitness value) for a module configuration, cf. ISO/IEC 18004:2015, Section 7.8.3.1
224  * The result of this function is used to determine the optimal shuffle mask that is used to generate the QR code
225  * @param modules The modules of the designated QR code, must be valid
226  * @param version The version of the designated QR code, range: [QRCode::MIN_VERSION, QRCode::MAX_VERSION]
227  * @return The penalty score for this configuration of modules
228  */
229  static unsigned int computeMaskPatternPenalty(const std::vector<uint8_t>& modules, const unsigned int version);
230 
231  /**
232  * Sets (draws) the modules (bits) of all function patterns
233  * Function patterns include: finder patterns, alignment patterns, timing patterns, version and format information, separators, and the black pixel
234  *
235  * This function:
236  * 1. sets the function patterns in the modules (final bit matrix).
237  * 2. returns a binary mask denoting those bits (pixels) which are function patterns, i.e. which cannot store data and must not be overwritten.
238  *
239  * The other set*-functions use this mask in order to avoid overwriting function patterns.
240  *
241  * @param modules The modules where the codewords will be written to, must be valid and of size `QRCode::modulesPerSide(version) * QRCode::modulesPerSide(version)`
242  * @param version The version of the designated QR code, range: [QRCode::MIN_VERSION, QRCode::MAX_VERSION]
243  * @param errorCorrectionCapacity The level of error correction for the designated QR code
244  * @return A binary mask that will denote all locations of the modules with function patterns (pixel value = 255) and data modules (pixel value = 0), the size will be same as for `modules`
245  */
246  static std::vector<uint8_t> setFunctionPatterns(std::vector<uint8_t>& modules, const unsigned int version, const QRCode::ErrorCorrectionCapacity errorCorrectionCapacity);
247 
248  /**
249  * Sets (draws) the codewords (zig-zag scan)
250  * Note: the size of the codewords must match exactly the version and level of error correction
251  * @param modules The modules where the codewords will be written to, must be valid and of size `QRCode::modulesPerSide(version) * QRCode::modulesPerSide(version)`
252  * @param codewords The modules where the codewords will be written to, must be valid
253  * @param version The version of the designated QR code, range: [QRCode::MIN_VERSION, QRCode::MAX_VERSION], must match the size of `modules`
254  * @param functionPatternMask The mask that is used to identify all function patterns in the QR code (and to not overwrite them), cf. `setFunctionPatterns()`
255  * @sa setFunctionPatterns()
256  */
257  static void setCodewords(std::vector<uint8_t>& modules, const Codewords& codewords, const unsigned int version, const std::vector<uint8_t>& functionPatternMask);
258 
259  /**
260  * Sets (draws) the format information (2x5 bits) into the modules of a QR code
261  * Note: format information = `e1 e0 | m2 m1 m0`, where `ei` and `mj` are the bits for the error correction level and bit shuffle mask, respectively
262  * @param[in,out] modules The modules where the format information will be written to, must be valid and of size `QRCode::modulesPerSide(version) * QRCode::modulesPerSide(version)`
263  * @param version The version of the designated QR code, range: [QRCode::MIN_VERSION, QRCode::MAX_VERSION], must match the size of `modules`
264  * @param errorCorrectionCapacity The level of error correction used to generate this QR code
265  * @param mask The index of the bit shuffle mask used to generate this QR code, range: [0, 7]
266  * @param functionPatternMask The mask that is used to identify all function patterns in the QR code (and to not overwrite them), cf. `setFunctionPatterns()`
267  * @sa setFunctionPatterns()
268  */
269  static void setFormatInformation(std::vector<uint8_t>& modules, const unsigned int version, const QRCode::ErrorCorrectionCapacity errorCorrectionCapacity, const MaskingPattern mask, std::vector<uint8_t>& functionPatternMask);
270 
271  /**
272  * Sets (draws) the version information (2x15 bits) into the modules of a QR code
273  * @param [in,out] modules The modules where the version information will be written to, must be valid and of size `QRCode::modulesPerSide(version) * QRCode::modulesPerSide(version)`
274  * @param version The version of the designated QR code, range: [QRCode::MIN_VERSION, QRCode::MAX_VERSION], must match the size of `module`
275  * @param functionPatternMask The mask that is used to identify all function pattern in the QR code (and to not overwrite them), cf. `setFunctionPatterns()`
276  * @sa setFunctionPatterns()
277  */
278  static void setVersionInformation(std::vector<uint8_t>& modules, const unsigned int version, std::vector<uint8_t>& functionPatternMask);
279 
280  /**
281  * Returns the bit sequence identifying the encodation mode set (up to 4 bits long, cf. ISO/IEC 18004:2015, Table 2)
282  * @param mode The encodation mode
283  * @return The bit sequence of the encodation mode used
284  */
285  static inline unsigned int encodationModeIndicatorBitSequence(const QRCode::EncodingMode mode);
286 
287  /**
288  * Returns the number of bits per character for a specific version and encodation mode, cf. ISO/IEC 18004:2015, Table 3
289  * @param version Version number of a QR code, range: [QRCode::MIN_VERSION, QRCode::MAX_VERSION]
290  * @param mode The encodation mode
291  * @return The number of bits per character
292  */
293  static inline unsigned int getBitsInCharacterCountIndicator(const unsigned int version, const QRCode::EncodingMode mode);
294 };
295 
297 {
298  static_assert(int(QRCode::EM_NUMERIC) == 0 && int(QRCode::EM_ALPHANUMERIC) == 1 && int(QRCode::EM_BYTE) == 2 && int(QRCode::EM_KANJI) == 3 && int(QRCode::EM_ECI) == 4 && int(QRCode::EM_STRUCTURED_APPEND) == 5 && int(QRCode::EM_FNC1), "Unexpected order of enums");
299  ocean_assert((unsigned int)mode < 7u);
300 
301  const unsigned int encodationModeBitSequences[7] =
302  {
303  0b0001u, // QRCode::EM_NUMERIC
304  0b0010u, // QRCode::EM_ALPHANUMERIC
305  0b0100u, // QRCode::EM_BYTE
306  0b1000u, // QRCode::EM_KANJI
307  0b0111u, // QRCode::EM_ECI
308  0b0011u, // QRCode::EM_STRUCTURED_APPEND
309 
310  // Note: This mode has two different return values and requires a different solution; since this mode isn't currently supported we'll ignore this
311  0b0000u, // QRCode::EM_FNC1
312  };
313 
314  ocean_assert(encodationModeBitSequences[(unsigned int)mode] >> 4u == 0u);
315  return encodationModeBitSequences[(unsigned int)mode];
316 }
317 
318 inline unsigned int QRCodeEncoder::getBitsInCharacterCountIndicator(const unsigned int version, const QRCode::EncodingMode mode)
319 {
320  static_assert(int(QRCode::EM_NUMERIC) == 0 && int(QRCode::EM_ALPHANUMERIC) == 1 && int(QRCode::EM_BYTE) == 2 && int(QRCode::EM_KANJI) == 3 && int(QRCode::EM_ECI) == 4, "Unexpected order of enums");
321  ocean_assert(version >= QRCode::MIN_VERSION && version <= QRCode::MAX_VERSION);
322  ocean_assert((unsigned int)mode < 5u);
323 
324  const unsigned int characterCountIndicators[15] =
325  {
326  // Cf. ISO/IEC 18004:2015, Table 3
327  // Versions 1-9
328  // | Versions 10-26
329  // | | Versions 27-40
330  // | | |
331  10, 12, 14, // Numeric
332  9, 11, 13, // Alphanumeric
333  8, 16, 16, // Byte
334  8, 10, 12, // Kanji
335  0, 0, 0 // ECI
336  };
337 
338  const unsigned int column = (version + 7u) / 17u;
339  ocean_assert(column < 3u);
340 
341  return characterCountIndicators[(unsigned int)mode * 3u + column];
342 }
343 
344 inline uint32_t QRCodeEncoder::encodeFormat(const QRCode::ErrorCorrectionCapacity errorCorrectionCapacity, const MaskingPattern maskingPattern)
345 {
346  ocean_assert(errorCorrectionCapacity >> 2u == 0u && maskingPattern >> 3u == 0u);
347  return encodeFormatBits(errorCorrectionCapacity << 3u | maskingPattern);
348 }
349 
350 inline bool QRCodeEncoder::decodeFormatBits(const uint32_t formatBits, QRCode::ErrorCorrectionCapacity& errorCorrectionCapacity, MaskingPattern& maskingPattern)
351 {
352  ocean_assert(formatBits >> 15u == 0u);
353 
354  uint32_t minDistanceFormat = uint32_t(-1);
355  uint32_t minDistance = uint32_t(-1);
356  uint32_t minDistanceCounter = 0u;
357 
358  for (uint32_t referenceFormat = 0u; referenceFormat < 32u; ++referenceFormat)
359  {
360  const uint32_t referenceFormatBits = encodeFormatBits(referenceFormat);
361  const uint32_t distance = computeHammingWeight(formatBits ^ referenceFormatBits);
362 
363  if (distance < minDistance)
364  {
365  minDistance = distance;
366  minDistanceFormat = referenceFormat;
367  minDistanceCounter = 1u;
368  }
369  else if (distance == minDistance)
370  {
371  minDistanceCounter++;
372  }
373  }
374 
375  // Check if the result is unambiguous, i.e. if at least two reference formats have the same Hamming distance the input format cannot be decoded unambiguously (>= 4 bits wrong).
376 
377  if (minDistanceCounter != 1u || minDistance >= 4u)
378  {
379  return false;
380  }
381 
382  ocean_assert(minDistance != uint32_t(-1) && minDistanceFormat != uint32_t(-1));
383  ocean_assert(minDistanceFormat >> 5u == 0u);
384 
385  switch (minDistanceFormat >> 3u)
386  {
387  case 0b01u:
388  errorCorrectionCapacity = QRCode::ECC_07;
389  break;
390 
391  case 0b00u:
392  errorCorrectionCapacity = QRCode::ECC_15;
393  break;
394 
395  case 0b11u:
396  errorCorrectionCapacity = QRCode::ECC_25;
397  break;
398 
399  case 0b10u:
400  errorCorrectionCapacity = QRCode::ECC_30;
401  break;
402 
403  default:
404  ocean_assert(false && "Never be here!");
405  return false;
406  break;
407  }
408 
409  maskingPattern = MaskingPattern(minDistanceFormat & 0b00111);
410 
411  return true;
412 }
413 
414 inline uint32_t QRCodeEncoder::encodeVersion(const uint32_t version)
415 {
416  ocean_assert(version >= QRCode::MIN_VERSION && version <= QRCode::MAX_VERSION);
417  ocean_assert(version >> 6u == 0u);
418 
419  // Details in ISO/IEC 18004:2015, Annex D
420  //
421  // Compute the remainder of polynomial long division with a (18, 6) BCH code (or Golay code) using the generator
422  // polynomial G(x) = x^12 + x^11 + x^10 + x^9 + x^8 + x^5 + x^2 + 1 ~ 1111100100101.
423 
424  const uint32_t remainder = computePolynomialDivisonRemainderBCH<18u, 6u, 0b1111100100101u>(version << 12u);
425  const uint32_t versionBits = (version << 12u) ^ remainder;
426  ocean_assert(versionBits >> 18u == 0u);
427 
428  return versionBits;
429 }
430 
431 inline bool QRCodeEncoder::decodeVersionBits(const uint32_t versionBits, uint32_t& version)
432 {
433  ocean_assert(versionBits >> 18u == 0u);
434 
435  uint32_t minDistanceVersion = uint32_t(-1);
436  uint32_t minDistance = uint32_t(-1);
437  uint32_t minDistanceCounter = 0u;
438 
439  // Note: QR codes version 1-6 do not have a bit field for their version information but mathematically it's valid to decode those sequences as well
440  for (uint32_t referenceVersion = QRCode::MIN_VERSION; referenceVersion <= QRCode::MAX_VERSION; ++referenceVersion)
441  {
442  const uint32_t referenceVersionBits = encodeVersion(referenceVersion);
443  const uint32_t distance = computeHammingWeight(versionBits ^ referenceVersionBits);
444 
445  if (distance < minDistance)
446  {
447  minDistance = distance;
448  minDistanceVersion = referenceVersion;
449  minDistanceCounter = 1u;
450  }
451  else if (distance == minDistance)
452  {
453  minDistanceCounter++;
454  }
455  }
456 
457  // Check if the result is unambiguous, i.e. if at least two reference versions have the same Hamming distance the input version cannot be decoded unambiguously (>= 5 bits wrong).
458 
459  if (minDistanceCounter != 1u || minDistance >= 5u)
460  {
461  return false;
462  }
463 
464  ocean_assert(minDistance != uint32_t(-1) && minDistanceVersion != uint32_t(-1));
465  ocean_assert(minDistanceVersion >> 6u == 0u);
466 
467  version = minDistanceVersion;
468 
469  return true;
470 }
471 
472 inline uint32_t QRCodeEncoder::encodeFormatBits(const uint32_t format)
473 {
474  ocean_assert(format >> 5u == 0u);
475 
476  // Details in ISO/IEC 18004:2015, Annex C
477  //
478  // Compute the remainder of polynomial long division with a (15, 5) BCH code using the generator
479  // polynomial G(x) = x^10 + x^8 + x^5 + x^4 + x^2 + x + 1 ~ 10100110111.
480 
481  const uint32_t remainder = computePolynomialDivisonRemainderBCH<15u, 5u, 0b10100110111u>(format << 10u);
482 
483  // Append the remainder to the format and XOR it with 101010000010010
484  const uint32_t formatBitsUnmasked = (format << 10u) ^ remainder;
485  const uint32_t formatBitsMasked = formatBitsUnmasked ^ 0b101010000010010u;
486  ocean_assert(formatBitsMasked >> 15u == 0u);
487 
488  return formatBitsMasked;
489 }
490 
491 inline unsigned int QRCodeEncoder::totalNumberRawDataModules(const unsigned int version)
492 {
493  ocean_assert(version >= QRCode::MIN_VERSION && version <= QRCode::MAX_VERSION);
494 
495  // TODO Improve documentation of this calculation
496 
497  // Number of total modules (4 * version + 17)^2 minus the modules for the
498  // * finder patterns
499  // * separators
500  // * timing patterns
501  // * version information
502  unsigned int rawDataModules = (16u * version + 128u) * version + 64u;
503 
504  // Subtract the modules for the alignment patterns, if applicable
505  if (version >= 2u)
506  {
507  const unsigned int alignmentPatterns = (version / 7u) + 2u;
508 
509  ocean_assert(rawDataModules >= (25u * alignmentPatterns - 10u) * alignmentPatterns - 55u);
510  rawDataModules -= (25u * alignmentPatterns - 10u) * alignmentPatterns - 55u;
511 
512  if (version >= 7u)
513  {
514  ocean_assert(rawDataModules >= 36u);
515  rawDataModules -= 36u;
516  }
517  }
518 
519  ocean_assert(rawDataModules < QRCode::modulesPerSide(version) * QRCode::modulesPerSide(version));
520  return rawDataModules;
521 }
522 
523 inline unsigned int QRCodeEncoder::totalNumberDataCodewords(const unsigned int version, const QRCode::ErrorCorrectionCapacity errorCorrectionCapacity)
524 {
525  ocean_assert(version >= QRCode::MIN_VERSION && version <= QRCode::MAX_VERSION);
526  ocean_assert(uint32_t(errorCorrectionCapacity) < 4u);
527 
528  return (totalNumberRawDataModules(version) / 8u) - (ECC_CODEWORDS_PER_BLOCK[errorCorrectionCapacity][version] * NUM_ERROR_CORRECTION_BLOCKS[errorCorrectionCapacity][version]);
529 }
530 
531 inline bool QRCodeEncoder::computeTotalBitsUsed(const Segments& segments, const unsigned int version, unsigned int& bitsUsed)
532 {
533  ocean_assert(version >= QRCode::MIN_VERSION && version <= QRCode::MAX_VERSION);
534 
535  bitsUsed = 0u;
536 
537  for (const Segment& segment : segments)
538  {
539  // ISO/IEC 18004:2015, Table 2
540  constexpr unsigned int modeIndicatorBits = 4u;
541  const unsigned int characterCountBits = getBitsInCharacterCountIndicator(version, segment.encodationMode());
542 
543  // Make sure the segment fits into the field's bit width and the sum will not overflow.
544  if (segment.characters() >= (1u << characterCountBits)
545  || (modeIndicatorBits + characterCountBits) > (NumericT<unsigned int>::maxValue() - bitsUsed)
546  || segment.bitBuffer().size() > (NumericT<unsigned int>::maxValue() - bitsUsed))
547  {
548  return false;
549  }
550 
551  bitsUsed += modeIndicatorBits + characterCountBits;
552  bitsUsed += (unsigned int)segment.bitBuffer().size();
553  }
554 
555  return true;
556 }
557 
558 } // namespace QRCodes
559 
560 } // namespace Detector
561 
562 } // namespace CV
563 
564 } // namespace Ocean
EncodingMode
Definition of encoding modes.
Definition: QRCodeBase.h:72
@ EM_ALPHANUMERIC
Mode that supports A-Z, 0-9 and a few others, cf. ALPHANUMERIC_CHARSET
Definition: QRCodeBase.h:76
@ EM_NUMERIC
Mode that supports digits 0-9.
Definition: QRCodeBase.h:74
@ EM_ECI
Mode that allows the output data stream to have interpretations different from that of the default ch...
Definition: QRCodeBase.h:85
@ EM_BYTE
Mode that represents data as a sequence of bytes.
Definition: QRCodeBase.h:78
@ EM_KANJI
Mode that handles Kanji characters in accordance with the Shift JIS system based on JIS X 0208.
Definition: QRCodeBase.h:83
@ EM_STRUCTURED_APPEND
Structured Append mode is used to split the encodation of the data from a message over a number of QR...
Definition: QRCodeBase.h:87
@ EM_FNC1
Mode that is used for messages containing data formatted either in accordance with the UCC/EAN Applic...
Definition: QRCodeBase.h:89
ErrorCorrectionCapacity
Enumeration of the levels of error correction The value of the enums correspond to the standard-defin...
Definition: QRCodeBase.h:53
@ ECC_15
Indicates that 15% of the modules reserved error correction.
Definition: QRCodeBase.h:57
@ ECC_30
Indicates that 30% of the modules reserved error correction.
Definition: QRCodeBase.h:61
@ ECC_25
Indicates that 25% of the modules reserved error correction.
Definition: QRCodeBase.h:59
@ ECC_07
Indicates that 7% of the modules reserved error correction.
Definition: QRCodeBase.h:55
Definition of the segment class A sequence is a sequence of data encoded according to the rules of on...
Definition: QRCodeEncoderBase.h:79
This class implements basic QRCodeEncoder functionality.
Definition: QRCodeEncoderBase.h:35
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:48
StatusCode
Enum for the error codes returned by the encoding functions.
Definition: QRCodeEncoderBase.h:57
std::vector< Codeword > Codewords
Vector of codewords.
Definition: QRCodeEncoderBase.h:42
This class implements an encoder and decoder for QR codes.
Definition: QRCodeEncoder.h:37
static bool decodeVersionBits(const uint32_t versionBits, uint32_t &version)
Decodes a sequence of 18 bits and extracts the encoded version number Note: the version bit sequence ...
Definition: QRCodeEncoder.h:431
static StatusCode encodeSegments(const Segments &segments, const QRCode::ErrorCorrectionCapacity errorCorrectionCapacity, std::vector< uint8_t > &modules, unsigned int &version, QRCode::ErrorCorrectionCapacity &finalErrorCorrectionCapacity, const unsigned int minVersion=1u, const unsigned int maxVersion=QRCode::MAX_VERSION, const MaskingPattern mask=MP_PATTERN_UNKNOWN, const bool maximizeErrorCorrectionCapacity=true)
Encodes segments and writes them into a QR code.
static const int8_t ECC_CODEWORDS_PER_BLOCK[4][41]
Number of error correction codewords (rows: 0 - low, 1 - medium, 2 - quartile, 3 - high,...
Definition: QRCodeEncoder.h:75
static StatusCode addErrorCorrectionAndCreateQRCode(const unsigned int version, const QRCode::ErrorCorrectionCapacity errorCorrectionCapacity, const Codewords &rawCodewords, MaskingPattern mask, std::vector< uint8_t > &modules)
Helper function to initialize a QR code instance.
static void setVersionInformation(std::vector< uint8_t > &modules, const unsigned int version, std::vector< uint8_t > &functionPatternMask)
Sets (draws) the version information (2x15 bits) into the modules of a QR code.
static uint32_t encodeFormatBits(const uint32_t format)
Encodes the format information as a sequence of 15 bits with error correction ((15,...
Definition: QRCodeEncoder.h:472
static void applyMaskPattern(std::vector< uint8_t > &modules, const unsigned int version, const std::vector< uint8_t > &functionPatternMask, const MaskingPattern mask)
Applies a data shuffle mask to the specified modules Note: Calling this function on the same data and...
static StatusCode encodeText(const std::string &text, const QRCode::ErrorCorrectionCapacity errorCorrectionCapacity, QRCode &qrcode)
Encode text and store it in a QR code, will automatically choose the most efficient encodation mode.
static StatusCode encodeBinary(const std::vector< uint8_t > &data, QRCode::ErrorCorrectionCapacity errorCorrectionCapacity, QRCode &qrcode)
Encode binary data and store it in a QR code, will always use the byte encodation mode.
static unsigned int encodationModeIndicatorBitSequence(const QRCode::EncodingMode mode)
Returns the bit sequence identifying the encodation mode set (up to 4 bits long, cf.
Definition: QRCodeEncoder.h:296
static unsigned int totalNumberDataCodewords(const unsigned int version, const QRCode::ErrorCorrectionCapacity errorCorrectionCapacity)
Return the number of codewords for a specified version and error correction level.
Definition: QRCodeEncoder.h:523
static bool computeTotalBitsUsed(const Segments &segments, const unsigned int version, unsigned int &bitsUsed)
Computes the number of bits used given some data (segments) for a specified version of a QR code (thi...
Definition: QRCodeEncoder.h:531
static bool decodeFormatBits(const uint32_t formatBits, QRCode::ErrorCorrectionCapacity &errorCorrectionCapacity, MaskingPattern &maskingPattern)
Decodes a sequence of 15 bits and extracts the encoded error correction level and index of the maskin...
Definition: QRCodeEncoder.h:350
static unsigned int getBitsInCharacterCountIndicator(const unsigned int version, const QRCode::EncodingMode mode)
Returns the number of bits per character for a specific version and encodation mode,...
Definition: QRCodeEncoder.h:318
static uint32_t encodeFormat(const QRCode::ErrorCorrectionCapacity errorCorrectionCapacity, const MaskingPattern maskingPattern)
Encodes the error correction level and the index of the masking pattern as a sequence of 15 bits with...
Definition: QRCodeEncoder.h:344
static VectorsI2 computeAlignmentPatternPositions(const unsigned int version)
Computes the 2D locations of the alignment patterns for a specified version of a QR code.
static void setFormatInformation(std::vector< uint8_t > &modules, const unsigned int version, const QRCode::ErrorCorrectionCapacity errorCorrectionCapacity, const MaskingPattern mask, std::vector< uint8_t > &functionPatternMask)
Sets (draws) the format information (2x5 bits) into the modules of a QR code Note: format information...
static std::vector< uint8_t > setFunctionPatterns(std::vector< uint8_t > &modules, const unsigned int version, const QRCode::ErrorCorrectionCapacity errorCorrectionCapacity)
Sets (draws) the modules (bits) of all function patterns Function patterns include: finder patterns,...
static unsigned int computeMaskPatternPenalty(const std::vector< uint8_t > &modules, const unsigned int version)
Computes a penalty value (fitness value) for a module configuration, cf.
MaskingPattern
Enum for the mask patterns used to shuffle modules of a QR code.
Definition: QRCodeEncoder.h:45
static void setCodewords(std::vector< uint8_t > &modules, const Codewords &codewords, const unsigned int version, const std::vector< uint8_t > &functionPatternMask)
Sets (draws) the codewords (zig-zag scan) Note: the size of the codewords must match exactly the vers...
static unsigned int totalNumberRawDataModules(const unsigned int version)
Returns the number of modules that can be used to store data for a given QR code version This is the ...
Definition: QRCodeEncoder.h:491
static Codewords addErrorCorrectionAndInterleave(const Codewords &codewords, const unsigned int version, const QRCode::ErrorCorrectionCapacity errorCorrectionCapacity)
Generates the error correction codewords and interleaves the with the raw codewords.
static uint32_t encodeVersion(const uint32_t version)
Encodes the version numbers as a sequences of 18 bits with error correction ((18, 6) BCH code).
Definition: QRCodeEncoder.h:414
static const int8_t NUM_ERROR_CORRECTION_BLOCKS[4][41]
Number of error correction blocks (rows: 0 - low, 1 - medium, 2 - quartile, 3 - high,...
Definition: QRCodeEncoder.h:78
Definition of a QR code.
Definition: QRCode.h:35
static constexpr unsigned int MIN_VERSION
Indicates the smallest valid version number of QR codes.
Definition: QRCode.h:42
static constexpr unsigned int MAX_VERSION
Indicates the largest valid version number of QR codes.
Definition: QRCode.h:45
unsigned int modulesPerSide() const override
Returns the number of modules per side of the QR code.
Definition: QRCode.h:129
This class provides basic numeric functionalities.
Definition: Numeric.h:57
std::vector< VectorI2 > VectorsI2
Definition of a vector holding VectorI2 objects.
Definition: Vector2.h:85
std::vector< QRCode > QRCodes
Definition of a vector of QR codes.
Definition: QRCode.h:25
The namespace covering the entire Ocean framework.
Definition: Accessor.h:15