Ocean
MicroQRCodeEncoder.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 MicroQRCodeEncoder : public QRCodeEncoderBase
37 {
38  public:
39 
40  /**
41  * Enum for the mask patterns used to shuffle modules of a Micro QR code.
42  * The values of the enum items correspond to the standard-defined bit sequences for the masks (2 bits long)
43  */
44  enum MaskingPattern : uint32_t
45  {
46  /// Masking condition: i mod 2 = 0
47  MP_PATTERN_0 = 0b00u,
48 
49  /// Masking condition: ((i div 2) + (j div 3)) mod 2 = 0
50  MP_PATTERN_1 = 0b01u,
51 
52  /// Masking condition: ((i j) mod 2 + (i j) mod 3) mod 2 = 0
53  MP_PATTERN_2 = 0b10u,
54 
55  /// Masking condition: ((i j) mod 3 + (i+j) mod 2) mod 2 = 0
56  MP_PATTERN_3 = 0b11u,
57 
58  /// Denotes unknown masking patterns (not part of the standard)
59  MP_PATTERN_UNKNOWN = uint32_t(-1)
60  };
61 
62  static constexpr uint32_t INVALID_VALUE = uint32_t(-1);
63 
64  public:
65 
66  /**
67  * Encode text and store it in a QR code, will automatically choose the most efficient encodation mode
68  * @param text The text/data to be encoded as a QR code
69  * @param errorCorrectionCapacity Specifies the level of possible error correction
70  * @param qrcode The Micro QR code that will store the encoded data
71  * @return `SC_SUCCESS` on success, otherwise it will return a status indicating the reason for failure
72  */
73  static QRCodeEncoderBase::StatusCode encodeText(const std::string& text, const MicroQRCode::ErrorCorrectionCapacity errorCorrectionCapacity, MicroQRCode& qrcode);
74 
75  /**
76  * Encode binary data and store it in a QR code, will always use the byte encodation mode
77  * @param data The data to be encoded as a QR code
78  * @param errorCorrectionCapacity Specifies the level of possible error correction
79  * @param qrcode The Micro QR code that will store the encoded data
80  * @return `SC_SUCCESS` on success, otherwise it will return a status indicating the reason for failure
81  */
82  static QRCodeEncoderBase::StatusCode encodeBinary(const std::vector<uint8_t>& data, const MicroQRCode::ErrorCorrectionCapacity errorCorrectionCapacity, MicroQRCode& qrcode);
83 
84  /**
85  * 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).
86  * @param version The version of the Micro QR code that will be encoded
87  * @param errorCorrectionCapacity An error correction capacity that will be decoded
88  * @param maskingPattern The masking pattern that will be encoded
89  * @return The error correction level and masking pattern encoded as a sequence of 15 bits
90  */
91  static inline uint32_t encodeFormat(const unsigned int version, const MicroQRCode::ErrorCorrectionCapacity errorCorrectionCapacity, const MaskingPattern maskingPattern);
92 
93  /**
94  * Decodes a sequence of 15 bits and extracts the encoded error correction level and index of the masking pattern
95  * 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.
96  * @param formatBits A sequence of 15 bits containing the format information, range: [0, 2^15)
97  * @param version The version extracted from the bit sequence
98  * @param errorCorrectionCapacity The error correction capacity extracted from the bit sequence
99  * @param maskingPattern The masking pattern extracted from the bit sequence
100  * @return True if the sequence was decoded successfully, otherwise false
101  */
102  static inline bool decodeFormatBits(const uint32_t formatBits, unsigned int& version, MicroQRCode::ErrorCorrectionCapacity& errorCorrectionCapacity, MaskingPattern& maskingPattern);
103 
104  /**
105  * Encodes the format information as a sequence of 15 bits with error correction ((15, 5) BCH code).
106  * @param format The format bit sequence consisting of the concatenated error correction capacity (2 bits) and masking pattern (3 bits), range: [0, 32)
107  * @return The error correction level and masking pattern encoded as a sequence of 15 bits
108  * @sa encodeFormat(const ErrorCorrectionCapacity, const MaskingPattern)
109  */
110  static inline uint32_t encodeFormatBits(const uint32_t format);
111 
112  protected:
113 
114  /**
115  * Helper function to initialize a Micro QR code instance
116  * @param version The version of this Micro QR code, range: [MicroQRCode::MIN_VERSION, MicroQRCode::MAX_VERSION]
117  * @param errorCorrectionCapacity The error correction level that will be used to generate the error-corrected codewords stored in this Micro QR code
118  * @param rawCodewords The encoded codewords. The size must fit exactly into the selected version of this Micro QR code
119  * @param mask The index of the bit shuffle masked that was used to generate the modules of this Micro QR code
120  * @param modules The resulting modules of the Micro QR code
121  */
122  static void addErrorCorrectionAndCreateQRCode(const unsigned int version, const MicroQRCode::ErrorCorrectionCapacity errorCorrectionCapacity, const Codewords& rawCodewords, MaskingPattern mask, std::vector<uint8_t>& modules);
123 
124  /**
125  * Encodes segments and writes them into a Micro QR code
126  * @param segments The raw segements that will be encoded and written into the Micro QR code instance, `qrcode`
127  * @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 Micro QR code that can fit the data
128  * @param modules The resulting modules of the Micro QR code
129  * @param version The resulting version of the Micro QR code
130  * @param finalErrorCorrectionCapacity The resulting error correction capacity that the Micro QR code will finally have
131  * @param minVersion The minimum version that the final Micro QR code is supposed to have, range: [1, maxVersion]
132  * @param maxVersion The maximum version that the final Micro QR code is supposed to have, range: [minVersion, 4]. Note: if this value is chosen too small, the initialization may fail
133  * @param mask The index of the bit shuffle mask that is to be used, range: [0, 3] 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)
134  * @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 Micro QR code that can fit the data, cf. `errorCorrectionCapacity`
135  * @return `SC_SUCCESS` on success, otherwise it will return a status indicating the reason for failure
136  */
137  static QRCodeEncoderBase::StatusCode encodeSegments(const Segments& segments, const MicroQRCode::ErrorCorrectionCapacity errorCorrectionCapacity, std::vector<uint8_t>& modules, unsigned int& version, MicroQRCode::ErrorCorrectionCapacity& finalErrorCorrectionCapacity, unsigned int minVersion = 1u, unsigned int maxVersion = MicroQRCode::MAX_VERSION, const MaskingPattern mask = MP_PATTERN_UNKNOWN, const bool maximizeErrorCorrectionCapacity = true);
138 
139  /**
140  * Returns the number of modules that can be used to store data for a given Micro QR code version
141  * This is the number of all modules less the number of function modules (finder pattern, timing pattern, version and format information, and separators)
142  * @param version The version of a Micro QR code, range: [MicroQRCode::MIN_VERSION, MicroQRCode::MAX_VERSION]
143  * @return The number of modules that can be used to store data
144  */
145  static inline unsigned int totalNumberRawDataModules(const unsigned int version);
146 
147  /**
148  * Return the number of codeword bits for a specified version and error correction level
149  * @param version The version of a Micro QR code, range: [MicroQRCode::MIN_VERSION, MicroQRCode::MAX_VERSION]
150  * @param errorCorrectionCapacity The error correction capacity, must be valid given for the version, cf. ISO/IEC 18004:2015, Table 2
151  * @return The total number of codeword bits that fit into such a Micro QR code
152  */
153  static inline unsigned int totalNumberDataCodewordBits(const unsigned int version, const MicroQRCode::ErrorCorrectionCapacity errorCorrectionCapacity);
154 
155  /**
156  * Gets the symbol number for the version and error correction capacity
157  * @param version The version of the Micro QR code, range [MicroQRCode::MIN_VERSION, MicroQRCode::MAX_VERSION]
158  * @param errorCorrectionCapacity The error correction capacity, must be valid given for the version, cf. ISO/IEC 18004:2015, Table 2
159  * @return The symbol number corresponding to the version and error correction capacity
160  */
161  static inline uint32_t getSymbolNumber(const unsigned int version, const MicroQRCode::ErrorCorrectionCapacity errorCorrectionCapacity);
162 
163  /**
164  * Return the number of codeword bits for a specified version and error correction level
165  * @param version The version of the Micro QR code, range [MicroQRCode::MIN_VERSION, MicroQRCode::MAX_VERSION]
166  * @param errorCorrectionCapacity The error correction capacity, must be valid given for the version, cf. ISO/IEC 18004:2015, Table 2
167  * @return The total number of codewords used for error correction
168  */
169  static inline unsigned int totalNumberErrorCorrectionCodewords(const unsigned int version, const MicroQRCode::ErrorCorrectionCapacity errorCorrectionCapacity);
170 
171  /**
172  * 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)
173  * @param segments The segments for which the number of bits will be computed
174  * @param version The version of a QR code, range: [MicroQRCode::MIN_VERSION, MicroQRCode::MAX_VERSION]
175  * @param bitsUsed The total number of bits the `segments` will need in a QR code of version `version`
176  * @return True on success, otherwise false (e.g. because of an overflow)
177  */
178  static inline bool computeTotalBitsUsed(const Segments& segments, const unsigned int version, unsigned int& bitsUsed);
179 
180  /**
181  * Generates the error correction codewords appends to the raw codewords
182  * @param codewords The raw code words for which the error code will be generated, must be valid
183  * @param version The version of the designated Micro QR code, range: [MicroQRCode::MIN_VERSION, MicroQRCode::MAX_VERSION]
184  * @param errorCorrectionCapacity The level of error correction to be used
185  * @return The error-corrected codewords
186  */
187  static Codewords addErrorCorrection(const Codewords& codewords, const unsigned int version, const MicroQRCode::ErrorCorrectionCapacity errorCorrectionCapacity);
188 
189  /**
190  * Applies a data shuffle mask to the specified modules
191  * 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)
192  * @param modules The modules that will be shuffled, must be valid
193  * @param version The version of the designated Micro QR code, range: [MicroQRCode::MIN_VERSION, MicroQRCode::MAX_VERSION]
194  * @param functionPatternMask The binary mask that indicates the location of function patterns (finder patern, etc.), which should not be shuffled, cf. `setFunctionPatterns()`
195  * @param mask The index of the shuffle mask, range: [0, 3]
196  * @sa setFunctionPatterns()
197  */
198  static void applyMaskPattern(std::vector<uint8_t>& modules, const unsigned int version, const std::vector<uint8_t>& functionPatternMask, const MaskingPattern mask);
199 
200  /**
201  * Computes a score (fitness value) for a module configuration, cf. ISO/IEC 18004:2015, Section 7.8.3.2
202  * The result of this function is used to determine the optimal shuffle mask that is used to generate the Micro QR code
203  * @param modules The modules of the designated Micro QR code, must be valid
204  * @param version The version of the designated Micro QR code, range: [MicroQRCode::MIN_VERSION, MicroQRCode::MAX_VERSION]
205  * @return The score for this configuration of modules
206  */
207  static unsigned int computeMaskPatternScore(const std::vector<uint8_t>& modules, const unsigned int version);
208 
209  /**
210  * Sets (draws) the modules (bits) of all function patterns
211  * Function patterns include: finder pattern, timing patterns, version and format information, and separators
212  *
213  * This function:
214  * 1. sets the function pattern in the modules (final bit matrix).
215  * 2. returns a binary mask denoting those bits (pixels) which are function patterns, i.e. which cannot store data and must not be overwritten.
216  *
217  * The other set*-functions use this mask in order to avoid overwriting function patterns.
218  *
219  * @param modules The modules where the codewords will be written to, must be valid and of size `MicroQRCode::modulesPerSide(version) * MicroQRCode::modulesPerSide(version)`
220  * @param version The version of the designated Micro QR code, range: [MicroQRCode::MIN_VERSION, MicroQRCode::MAX_VERSION]
221  * @param errorCorrectionCapacity The level of error correction for the designated Micro QR code
222  * @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`
223  */
224  static std::vector<uint8_t> setFunctionPatterns(std::vector<uint8_t>& modules, const unsigned int version, const MicroQRCode::ErrorCorrectionCapacity errorCorrectionCapacity);
225 
226  /**
227  * Sets (draws) the codewords (zig-zag scan)
228  * Note: the size of the codewords must match exactly the version and level of error correction
229  * @param modules The modules where the codewords will be written to, must be valid and of size `MicroQRCode::modulesPerSide(version) * MicroQRCode::modulesPerSide(version)`
230  * @param codewords The modules where the codewords will be written to, must be valid
231  * @param version The version of the designated Micro QR code, range: [MicroQRCode::MIN_VERSION, MicroQRCode::MAX_VERSION], must match the size of `modules`
232  * @param errorCorrectionCapacity The level of error correction used to generate this Micro QR code
233  * @param functionPatternMask The mask that is used to identify all function patterns in the Micro QR code (and to not overwrite them), cf. `setFunctionPatterns()`
234  * @sa setFunctionPatterns()
235  */
236  static void setCodewords(std::vector<uint8_t>& modules, const Codewords& codewords, const unsigned int version, const MicroQRCode::ErrorCorrectionCapacity errorCorrectionCapacity, const std::vector<uint8_t>& functionPatternMask);
237 
238  /**
239  * Sets (draws) the format information (15 bits) into the modules of a Micro QR code
240  * Note: format information = `s2 s1 s0 | m1 m0`, where `si` are the bits for the symbol number (cf. ISO/IEC 18004:2015, Table 13) and `mj` are the bits for the bit shuffle mask
241  * @param[in,out] modules The modules where the format information will be written to, must be valid and of size `MicroQRCode::modulesPerSide(version) * MicroQRCode::modulesPerSide(version)`
242  * @param version The version of the designated Micro QR code, range: [MicroQRCode::MIN_VERSION, MicroQRCode::MAX_VERSION], must match the size of `modules`
243  * @param errorCorrectionCapacity The level of error correction used to generate this Micro QR code
244  * @param mask The index of the bit shuffle mask used to generate this Micro QR code, range: [0, 3]
245  * @param functionPatternMask The mask that is used to identify all function patterns in the Micro QR code (and to not overwrite them), cf. `setFunctionPatterns()`
246  * @sa setFunctionPatterns()
247  */
248  static void setFormatInformation(std::vector<uint8_t>& modules, const unsigned int version, const MicroQRCode::ErrorCorrectionCapacity errorCorrectionCapacity, const MaskingPattern mask, std::vector<uint8_t>& functionPatternMask);
249 
250  /**
251  * Sets (draws) the version information (2x15 bits) into the modules of a QR code
252  * @param [in,out] modules The modules where the version information will be written to, must be valid and of size `MicroQRCode::modulesPerSide(version) * MicroQRCode::modulesPerSide(version)`
253  * @param version The version of the designated QR code, range: [MicroQRCode::MIN_VERSION, MicroQRCode::MAX_VERSION], must match the size of `module`
254  * @param functionPatternMask The mask that is used to identify all function pattern in the QR code (and to not overwrite them), cf. `setFunctionPatterns()`
255  * @sa setFunctionPatterns()
256  */
257  static void setVersionInformation(std::vector<uint8_t>& modules, const unsigned int version, std::vector<uint8_t>& functionPatternMask);
258 
259  /**
260  * Returns the bit sequence identifying the encodation mode set (up to 4 bits long, cf. ISO/IEC 18004:2015, Table 2)
261  * @return The bit sequence of the encodation mode used
262  */
263  static inline unsigned int encodationModeIndicatorBitSequence(const MicroQRCode::EncodingMode mode);
264 
265  /**
266  * Returns the number of bits per character for a specific version and encodation mode, cf. ISO/IEC 18004:2015, Table 3
267  * @param version Version number of a QR code, range: [MicroQRCode::MIN_VERSION, MicroQRCode::MAX_VERSION]
268  * @param mode The encodation mode, must be valid given the version (minimum M2 for alphanumeric, minimum M3 for byte and kanji)
269  * @return The number of bits per character (zero for invalid combinations of version and mode)
270  */
271  static inline unsigned int getBitsInCharacterCountIndicator(const unsigned int version, const MicroQRCode::EncodingMode mode);
272 };
273 
275 {
276  static_assert(int(MicroQRCode::EM_NUMERIC) == 0 && int(MicroQRCode::EM_ALPHANUMERIC) == 1 && int(MicroQRCode::EM_BYTE) == 2 && int(MicroQRCode::EM_KANJI) == 3, "Unexpected order of enums");
277  ocean_assert((unsigned int)mode < 4u);
278 
279  constexpr unsigned int encodationModeBitSequences[4] =
280  {
281  0b000u, // MicroQRCode::EM_NUMERIC
282  0b001u, // MicroQRCode::EM_ALPHANUMERIC
283  0b010u, // MicroQRCode::EM_BYTE
284  0b011u, // MicroQRCode::EM_KANJI
285  };
286 
287  ocean_assert(encodationModeBitSequences[(unsigned int)mode] >> 3u == 0u);
288  return encodationModeBitSequences[(unsigned int)mode];
289 }
290 
291 inline unsigned int MicroQRCodeEncoder::getBitsInCharacterCountIndicator(const unsigned int version, const MicroQRCode::EncodingMode mode)
292 {
293  static_assert(int(MicroQRCode::EM_NUMERIC) == 0 && int(MicroQRCode::EM_ALPHANUMERIC) == 1 && int(MicroQRCode::EM_BYTE) == 2 && int(MicroQRCode::EM_KANJI) == 3, "Unexpected order of enums");
294  ocean_assert(version >= MicroQRCode::MIN_VERSION && version <= MicroQRCode::MAX_VERSION);
295  ocean_assert((unsigned int)mode < 4u);
296 
297  constexpr unsigned int characterCountIndicators[16] =
298  {
299  // Cf. ISO/IEC 18004:2015, Table 3
300  // M1
301  // | M2
302  // | | M3
303  // | | | M4
304  // | | | |
305  3u, 4u, 5u, 6u, // Numeric
306  0u, 3u, 4u, 5u, // Alphanumeric
307  0u, 0u, 4u, 5u, // Byte
308  0u, 0u, 3u, 4u // Kanji
309  };
310 
311  const unsigned int column = version - 1u;
312  ocean_assert(column < 4u);
313 
314  return characterCountIndicators[(unsigned int)mode * 4u + column];
315 }
316 
317 inline uint32_t MicroQRCodeEncoder::encodeFormat(const unsigned int version, const MicroQRCode::ErrorCorrectionCapacity errorCorrectionCapacity, const MaskingPattern maskingPattern)
318 {
319  ocean_assert(version >= MicroQRCode::MIN_VERSION && version <= MicroQRCode::MAX_VERSION);
320  ocean_assert(errorCorrectionCapacity != MicroQRCode::ECC_INVALID && errorCorrectionCapacity != MicroQRCode::ECC_30);
321  ocean_assert(maskingPattern >> 2u == 0u);
322 
323  return encodeFormatBits(getSymbolNumber(version, errorCorrectionCapacity) << 2u | maskingPattern);
324 }
325 
326 inline bool MicroQRCodeEncoder::decodeFormatBits(const uint32_t formatBits, unsigned int& version, MicroQRCode::ErrorCorrectionCapacity& errorCorrectionCapacity, MaskingPattern& maskingPattern)
327 {
328  ocean_assert(formatBits >> 15u == 0u);
329 
330  uint32_t minDistanceFormat = uint32_t(-1);
331  uint32_t minDistance = uint32_t(-1);
332  uint32_t minDistanceCounter = 0u;
333 
334  for (uint32_t referenceFormat = 0u; referenceFormat < 32u; ++referenceFormat)
335  {
336  const uint32_t referenceFormatBits = encodeFormatBits(referenceFormat);
337  const uint32_t distance = computeHammingWeight(formatBits ^ referenceFormatBits);
338 
339  if (distance < minDistance)
340  {
341  minDistance = distance;
342  minDistanceFormat = referenceFormat;
343  minDistanceCounter = 1u;
344  }
345  else if (distance == minDistance)
346  {
347  minDistanceCounter++;
348  }
349  }
350 
351  // 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).
352 
353  if (minDistanceCounter != 1u || minDistance >= 4u)
354  {
355  return false;
356  }
357 
358  ocean_assert(minDistance != uint32_t(-1) && minDistanceFormat != uint32_t(-1));
359  ocean_assert(minDistanceFormat >> 5u == 0u);
360 
361  switch (minDistanceFormat >> 2u)
362  {
363  case 0u:
364  version = 1u;
365  errorCorrectionCapacity = MicroQRCode::ECC_DETECTION_ONLY;
366  break;
367 
368  case 1u:
369  version = 2u;
370  errorCorrectionCapacity = MicroQRCode::ECC_07;
371  break;
372 
373  case 2u:
374  version = 2u;
375  errorCorrectionCapacity = MicroQRCode::ECC_15;
376  break;
377 
378  case 3u:
379  version = 3u;
380  errorCorrectionCapacity = MicroQRCode::ECC_07;
381  break;
382 
383  case 4u:
384  version = 3u;
385  errorCorrectionCapacity = MicroQRCode::ECC_15;
386  break;
387 
388  case 5u:
389  version = 4u;
390  errorCorrectionCapacity = MicroQRCode::ECC_07;
391  break;
392 
393  case 6u:
394  version = 4u;
395  errorCorrectionCapacity = MicroQRCode::ECC_15;
396  break;
397 
398  case 7u:
399  version = 4u;
400  errorCorrectionCapacity = MicroQRCode::ECC_25;
401  break;
402 
403  default:
404  ocean_assert(false && "Never be here!");
405  return false;
406  break;
407  }
408 
409  maskingPattern = MaskingPattern(minDistanceFormat & 0b00011u);
410 
411  return true;
412 }
413 
414 inline uint32_t MicroQRCodeEncoder::encodeFormatBits(const uint32_t format)
415 {
416  ocean_assert(format >> 5u == 0u);
417 
418  // Details in ISO/IEC 18004:2015, Annex C
419  //
420  // Compute the remainder of polynomial long division with a (15, 5) BCH code using the generator
421  // polynomial G(x) = x^10 + x^8 + x^5 + x^4 + x^2 + x + 1 ~ 10100110111.
422 
423  const uint32_t remainder = computePolynomialDivisonRemainderBCH<15u, 5u, 0b10100110111u>(format << 10u);
424 
425  // Append the remainder to the format and XOR it with 100010001000101
426  const uint32_t formatBitsUnmasked = (format << 10u) ^ remainder;
427  const uint32_t formatBitsMasked = formatBitsUnmasked ^ 0b100010001000101u;
428  ocean_assert(formatBitsMasked >> 15u == 0u);
429 
430  return formatBitsMasked;
431 }
432 
433 inline unsigned int MicroQRCodeEncoder::totalNumberRawDataModules(const unsigned int version)
434 {
435  ocean_assert(version >= MicroQRCode::MIN_VERSION && version <= MicroQRCode::MAX_VERSION);
436 
437  // cf. ISO/IEC 18004:2015, Table 1
438  static constexpr unsigned int rawDataModuleTable[4] = {36u, 80, 132u, 192u};
439 
440  const unsigned int rawDataModules = rawDataModuleTable[version - 1];
441 
442  ocean_assert(rawDataModules < MicroQRCode::modulesPerSide(version) * MicroQRCode::modulesPerSide(version));
443  return rawDataModules;
444 }
445 
446 inline unsigned int MicroQRCodeEncoder::totalNumberErrorCorrectionCodewords(const unsigned int version, const MicroQRCode::ErrorCorrectionCapacity errorCorrectionCapacity)
447 {
448  /// Number of error correction codewords, indexed by symbol number, cf. ISO/IEC 18004:2015, Table 2 and Table 9, column 4
449  static constexpr int8_t ECC_CODEWORDS[8] = {2, 5, 6, 6, 8, 8, 10, 14};
450 
451  return ECC_CODEWORDS[getSymbolNumber(version, errorCorrectionCapacity)];
452 }
453 
454 inline unsigned int MicroQRCodeEncoder::totalNumberDataCodewordBits(const unsigned int version, const MicroQRCode::ErrorCorrectionCapacity errorCorrectionCapacity)
455 {
456  return (totalNumberRawDataModules(version) - totalNumberErrorCorrectionCodewords(version, errorCorrectionCapacity) * 8u);
457 }
458 
459 inline bool MicroQRCodeEncoder::computeTotalBitsUsed(const Segments& segments, const unsigned int version, unsigned int& bitsUsed)
460 {
461  ocean_assert(version >= MicroQRCode::MIN_VERSION && version <= MicroQRCode::MAX_VERSION);
462 
463  bitsUsed = 0u;
464 
465  for (const Segment& segment : segments)
466  {
467  // Length of mode indicator varies by version, cf. ISO/IEC 18004:2015, Table 2
468  const unsigned int modeIndicatorBits = version - 1u;
469  const unsigned int characterCountBits = getBitsInCharacterCountIndicator(version, segment.encodationMode());
470 
471  // Make sure the segment fits into the field's bit width and the sum will not overflow.
472  if (segment.characters() >= (1u << characterCountBits)
473  || (modeIndicatorBits + characterCountBits) > (NumericT<unsigned int>::maxValue() - bitsUsed)
474  || segment.bitBuffer().size() > (NumericT<unsigned int>::maxValue() - bitsUsed))
475  {
476  return false;
477  }
478 
479  bitsUsed += modeIndicatorBits + characterCountBits;
480  bitsUsed += (unsigned int)segment.bitBuffer().size();
481  }
482 
483  return true;
484 }
485 
486 inline uint32_t MicroQRCodeEncoder::getSymbolNumber(const unsigned int version, const MicroQRCode::ErrorCorrectionCapacity errorCorrectionCapacity)
487 {
488  ocean_assert(version >= MicroQRCode::MIN_VERSION && version <= MicroQRCode::MAX_VERSION);
489 
490  switch(errorCorrectionCapacity)
491  {
493  ocean_assert(version == 1u);
494  if (version == 1u)
495  {
496  return 0u;
497  }
498  break;
499  case MicroQRCode::ECC_07:
500  ocean_assert(version >= 2u && version <= MicroQRCode::MAX_VERSION);
501  if (version >= 2u && version <= MicroQRCode::MAX_VERSION)
502  {
503  return 2u * version - 3u;
504  }
505  break;
506  case MicroQRCode::ECC_15:
507  ocean_assert(version >= 2u && version <= MicroQRCode::MAX_VERSION);
508  if (version >= 2u && version <= MicroQRCode::MAX_VERSION)
509  {
510  return 2u * version - 2u;
511  }
512  break;
513  case MicroQRCode::ECC_25:
514  ocean_assert(version == MicroQRCode::MAX_VERSION);
515  if (version == MicroQRCode::MAX_VERSION)
516  {
517  return 7u;
518  }
519  break;
520  default:
521  break;
522  }
523 
524  ocean_assert(false && "Never be here!");
525  return INVALID_VALUE;
526 }
527 
528 } // namespace QRCodes
529 
530 } // namespace Detector
531 
532 } // namespace CV
533 
534 } // namespace Ocean
This class implements an encoder and decoder for QR codes.
Definition: MicroQRCodeEncoder.h:37
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 void setFormatInformation(std::vector< uint8_t > &modules, const unsigned int version, const MicroQRCode::ErrorCorrectionCapacity errorCorrectionCapacity, const MaskingPattern mask, std::vector< uint8_t > &functionPatternMask)
Sets (draws) the format information (15 bits) into the modules of a Micro QR code Note: format inform...
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: MicroQRCodeEncoder.h:459
static unsigned int totalNumberErrorCorrectionCodewords(const unsigned int version, const MicroQRCode::ErrorCorrectionCapacity errorCorrectionCapacity)
Return the number of codeword bits for a specified version and error correction level.
Definition: MicroQRCodeEncoder.h:446
static QRCodeEncoderBase::StatusCode encodeText(const std::string &text, const MicroQRCode::ErrorCorrectionCapacity errorCorrectionCapacity, MicroQRCode &qrcode)
Encode text and store it in a QR code, will automatically choose the most efficient encodation mode.
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 void addErrorCorrectionAndCreateQRCode(const unsigned int version, const MicroQRCode::ErrorCorrectionCapacity errorCorrectionCapacity, const Codewords &rawCodewords, MaskingPattern mask, std::vector< uint8_t > &modules)
Helper function to initialize a Micro QR code instance.
static Codewords addErrorCorrection(const Codewords &codewords, const unsigned int version, const MicroQRCode::ErrorCorrectionCapacity errorCorrectionCapacity)
Generates the error correction codewords appends to the raw codewords.
MaskingPattern
Enum for the mask patterns used to shuffle modules of a Micro QR code.
Definition: MicroQRCodeEncoder.h:45
static QRCodeEncoderBase::StatusCode encodeSegments(const Segments &segments, const MicroQRCode::ErrorCorrectionCapacity errorCorrectionCapacity, std::vector< uint8_t > &modules, unsigned int &version, MicroQRCode::ErrorCorrectionCapacity &finalErrorCorrectionCapacity, unsigned int minVersion=1u, unsigned int maxVersion=MicroQRCode::MAX_VERSION, const MaskingPattern mask=MP_PATTERN_UNKNOWN, const bool maximizeErrorCorrectionCapacity=true)
Encodes segments and writes them into a Micro 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: MicroQRCodeEncoder.h:414
static std::vector< uint8_t > setFunctionPatterns(std::vector< uint8_t > &modules, const unsigned int version, const MicroQRCode::ErrorCorrectionCapacity errorCorrectionCapacity)
Sets (draws) the modules (bits) of all function patterns Function patterns include: finder pattern,...
static constexpr uint32_t INVALID_VALUE
Definition: MicroQRCodeEncoder.h:62
static uint32_t encodeFormat(const unsigned int version, const MicroQRCode::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: MicroQRCodeEncoder.h:317
static QRCodeEncoderBase::StatusCode encodeBinary(const std::vector< uint8_t > &data, const MicroQRCode::ErrorCorrectionCapacity errorCorrectionCapacity, MicroQRCode &qrcode)
Encode binary data and store it in a QR code, will always use the byte encodation mode.
static bool decodeFormatBits(const uint32_t formatBits, unsigned int &version, MicroQRCode::ErrorCorrectionCapacity &errorCorrectionCapacity, MaskingPattern &maskingPattern)
Decodes a sequence of 15 bits and extracts the encoded error correction level and index of the maskin...
Definition: MicroQRCodeEncoder.h:326
static void setCodewords(std::vector< uint8_t > &modules, const Codewords &codewords, const unsigned int version, const MicroQRCode::ErrorCorrectionCapacity errorCorrectionCapacity, 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 computeMaskPatternScore(const std::vector< uint8_t > &modules, const unsigned int version)
Computes a score (fitness value) for a module configuration, cf.
static uint32_t getSymbolNumber(const unsigned int version, const MicroQRCode::ErrorCorrectionCapacity errorCorrectionCapacity)
Gets the symbol number for the version and error correction capacity.
Definition: MicroQRCodeEncoder.h:486
static unsigned int totalNumberDataCodewordBits(const unsigned int version, const MicroQRCode::ErrorCorrectionCapacity errorCorrectionCapacity)
Return the number of codeword bits for a specified version and error correction level.
Definition: MicroQRCodeEncoder.h:454
static unsigned int getBitsInCharacterCountIndicator(const unsigned int version, const MicroQRCode::EncodingMode mode)
Returns the number of bits per character for a specific version and encodation mode,...
Definition: MicroQRCodeEncoder.h:291
static unsigned int totalNumberRawDataModules(const unsigned int version)
Returns the number of modules that can be used to store data for a given Micro QR code version This i...
Definition: MicroQRCodeEncoder.h:433
static unsigned int encodationModeIndicatorBitSequence(const MicroQRCode::EncodingMode mode)
Returns the bit sequence identifying the encodation mode set (up to 4 bits long, cf.
Definition: MicroQRCodeEncoder.h:274
Definition of a Micro QR code.
Definition: MicroQRCode.h:35
static constexpr unsigned int MIN_VERSION
Indicates the smallest valid version number of Micro QR codes.
Definition: MicroQRCode.h:42
unsigned int modulesPerSide() const override
Returns the number of modules per side of the Micro QR code.
Definition: MicroQRCode.h:176
static constexpr unsigned int MAX_VERSION
Indicates the largest valid version number of Micro QR codes.
Definition: MicroQRCode.h:45
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_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
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_INVALID
Indicator for an invalid error correction capacity.
Definition: QRCodeBase.h:65
@ ECC_07
Indicates that 7% of the modules reserved error correction.
Definition: QRCodeBase.h:55
@ ECC_DETECTION_ONLY
Indicates that the capacity is limited to error detection only (used only by Micro QR Code version M1...
Definition: QRCodeBase.h:63
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 provides basic numeric functionalities.
Definition: Numeric.h:57
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