Ocean
Loading...
Searching...
No Matches
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
20namespace Ocean
21{
22
23namespace CV
24{
25
26namespace Detector
27{
28
29namespace QRCodes
30{
31
32/**
33 * This class implements an encoder and decoder for QR codes.
34 * @ingroup cvdetectorqrcodes
35 */
36class 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
318inline 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
344inline 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
350inline 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
414inline 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
431inline 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
472inline 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
491inline 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
523inline 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
531inline 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:51
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 unsigned int computeMaskPatternPenalty(const std::vector< uint8_t > &modules, const unsigned int version)
Computes a penalty value (fitness value) for a module configuration, cf.
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,...
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:28
The namespace covering the entire Ocean framework.
Definition Accessor.h:15