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