8
9
10
11
12
13
14
15
16
17
18
19
20
21
23#include "fxbarcode/qrcode/BC_QRCoderMatrixUtil.h"
28#include "core/fxcrt/check.h"
29#include "core/fxcrt/check_op.h"
30#include "fxbarcode/common/BC_CommonByteMatrix.h"
31#include "fxbarcode/qrcode/BC_QRCoder.h"
32#include "fxbarcode/qrcode/BC_QRCoderBitVector.h"
33#include "fxbarcode/qrcode/BC_QRCoderErrorCorrectionLevel.h"
34#include "fxbarcode/qrcode/BC_QRCoderMaskUtil.h"
38using PositionDetectionPatternRow =
std::array<uint8_t, 7>;
39constexpr std::array<
const PositionDetectionPatternRow, 7>
40 kPositionDetectionPatternTable = {{{{1, 1, 1, 1, 1, 1, 1}},
41 {{1, 0, 0, 0, 0, 0, 1}},
42 {{1, 0, 1, 1, 1, 0, 1}},
43 {{1, 0, 1, 1, 1, 0, 1}},
44 {{1, 0, 1, 1, 1, 0, 1}},
45 {{1, 0, 0, 0, 0, 0, 1}},
46 {{1, 1, 1, 1, 1, 1, 1}}}};
48using PositionAdjustmentPatternRow =
std::array<uint8_t, 5>;
49constexpr std::array<
const PositionAdjustmentPatternRow, 5>
50 kPositionAdjustmentPatternTable = {{{{1, 1, 1, 1, 1}},
56constexpr size_t kNumCoordinate = 7;
57using PositionCoordinatePatternRow = std::array<uint8_t, kNumCoordinate>;
58constexpr std::array<
const PositionCoordinatePatternRow, 39>
59 kPositionCoordinatePatternTable = {{
60 {{6, 18, 0, 0, 0, 0, 0}}, {{6, 22, 0, 0, 0, 0, 0}},
61 {{6, 26, 0, 0, 0, 0, 0}}, {{6, 30, 0, 0, 0, 0, 0}},
62 {{6, 34, 0, 0, 0, 0, 0}}, {{6, 22, 38, 0, 0, 0, 0}},
63 {{6, 24, 42, 0, 0, 0, 0}}, {{6, 26, 46, 0, 0, 0, 0}},
64 {{6, 28, 50, 0, 0, 0, 0}}, {{6, 30, 54, 0, 0, 0, 0}},
65 {{6, 32, 58, 0, 0, 0, 0}}, {{6, 34, 62, 0, 0, 0, 0}},
66 {{6, 26, 46, 66, 0, 0, 0}}, {{6, 26, 48, 70, 0, 0, 0}},
67 {{6, 26, 50, 74, 0, 0, 0}}, {{6, 30, 54, 78, 0, 0, 0}},
68 {{6, 30, 56, 82, 0, 0, 0}}, {{6, 30, 58, 86, 0, 0, 0}},
69 {{6, 34, 62, 90, 0, 0, 0}}, {{6, 28, 50, 72, 94, 0, 0}},
70 {{6, 26, 50, 74, 98, 0, 0}}, {{6, 30, 54, 78, 102, 0, 0}},
71 {{6, 28, 54, 80, 106, 0, 0}}, {{6, 32, 58, 84, 110, 0, 0}},
72 {{6, 30, 58, 86, 114, 0, 0}}, {{6, 34, 62, 90, 118, 0, 0}},
73 {{6, 26, 50, 74, 98, 122, 0}}, {{6, 30, 54, 78, 102, 126, 0}},
74 {{6, 26, 52, 78, 104, 130, 0}}, {{6, 30, 56, 82, 108, 134, 0}},
75 {{6, 34, 60, 86, 112, 138, 0}}, {{6, 30, 58, 86, 114, 142, 0}},
76 {{6, 34, 62, 90, 118, 146, 0}}, {{6, 30, 54, 78, 102, 126, 150}},
77 {{6, 24, 50, 76, 102, 128, 154}}, {{6, 28, 54, 80, 106, 132, 158}},
78 {{6, 32, 58, 84, 110, 136, 162}}, {{6, 26, 54, 82, 110, 138, 166}},
79 {{6, 30, 58, 86, 114, 142, 170}},
82struct TypeInfoCoordinate {
87const std::array<
const TypeInfoCoordinate, 15> kTypeInfoCoordinates = {{
105constexpr int32_t VERSION_INFO_POLY = 0x1f25;
106constexpr int32_t TYPE_INFO_POLY = 0x0537;
107constexpr int32_t TYPE_INFO_MASK_PATTERN = 0x5412;
109bool IsEmpty(int32_t value) {
110 return (uint8_t)value == 0xff;
113bool IsValidValue(int32_t value) {
114 return ((uint8_t)value == 0xff || (uint8_t)value == 0x00 ||
115 (uint8_t)value == 0x01);
118int32_t FindMSBSet(int32_t value) {
119 int32_t numDigits = 0;
129 CBC_CommonByteMatrix* matrix) {
130 size_t szBitIndex = 0;
131 int32_t direction = -1;
132 int32_t x = matrix->GetWidth() - 1;
133 int32_t y = matrix->GetHeight() - 1;
138 while (y >= 0 && y <
static_cast<int32_t>(matrix->GetHeight())) {
143 for (int32_t i = 0; i < 2; i++) {
145 if (!IsEmpty(matrix->Get(xx, y))) {
149 if (szBitIndex < dataBits->Size()) {
150 bit = dataBits->At(szBitIndex);
155 DCHECK(CBC_QRCoder::IsValidMaskPattern(maskPattern));
158 matrix->Set(xx, y, bit);
162 direction = -direction;
166 return szBitIndex == dataBits->Size();
169int32_t CalculateBCHCode(int32_t value, int32_t poly) {
170 int32_t msbSetInPoly = FindMSBSet(poly);
171 value <<= msbSetInPoly - 1;
172 while (FindMSBSet(value) >= msbSetInPoly) {
173 value ^= poly << (FindMSBSet(value) - msbSetInPoly);
184 int32_t typeInfo = (ecLevel
->GetBits() << 3) | maskPattern;
186 int32_t bchCode = CalculateBCHCode(typeInfo, TYPE_INFO_POLY);
199 int32_t bchCode = CalculateBCHCode(version, VERSION_INFO_POLY);
206 CBC_CommonByteMatrix* matrix) {
208 if (!MakeTypeInfoBits(ecLevel, maskPattern, &typeInfoBits))
211 for (size_t i = 0; i < typeInfoBits.Size(); i++) {
212 int32_t bit = typeInfoBits.At(typeInfoBits.Size() - 1 - i);
213 int32_t x1 = kTypeInfoCoordinates[i].x;
214 int32_t y1 = kTypeInfoCoordinates[i].y;
215 matrix->Set(x1, y1, bit);
217 int32_t x2 = matrix->GetWidth() - i - 1;
219 matrix->Set(x2, y2, bit);
222 int32_t y2 = matrix->GetHeight() - 7 + (i - 8);
223 matrix->Set(x2, y2, bit);
229void MaybeEmbedVersionInfo(int32_t version, CBC_CommonByteMatrix* matrix) {
234 MakeVersionInfoBits(version, &versionInfoBits);
235 int32_t bitIndex = 6 * 3 - 1;
236 for (int32_t i = 0; i < 6; i++) {
237 for (int32_t j = 0; j < 3; j++) {
238 int32_t bit = versionInfoBits.At(bitIndex);
240 matrix->Set(i, matrix->GetHeight() - 11 + j, bit);
241 matrix->Set(matrix->GetHeight() - 11 + j, i, bit);
246bool EmbedTimingPatterns(CBC_CommonByteMatrix* matrix) {
247 for (size_t i = 8; i + 8 < matrix->GetWidth(); i++) {
248 const uint8_t bit =
static_cast<uint8_t>((i + 1) % 2);
249 if (!IsValidValue(matrix->Get(i, 6)))
252 if (IsEmpty(matrix->Get(i, 6)))
253 matrix->Set(i, 6, bit);
255 if (!IsValidValue(matrix->Get(6, i)))
258 if (IsEmpty(matrix->Get(6, i)))
259 matrix->Set(6, i, bit);
264bool EmbedDarkDotAtLeftBottomCorner(CBC_CommonByteMatrix* matrix) {
265 if (matrix->Get(8, matrix->GetHeight() - 8) == 0)
268 matrix->Set(8, matrix->GetHeight() - 8, 1);
272bool EmbedHorizontalSeparationPattern(int32_t xStart,
274 CBC_CommonByteMatrix* matrix) {
275 for (int32_t x = 0; x < 8; x++) {
276 if (!IsEmpty(matrix->Get(xStart + x, yStart)))
279 matrix->Set(xStart + x, yStart, 0);
284bool EmbedVerticalSeparationPattern(int32_t xStart,
286 CBC_CommonByteMatrix* matrix) {
287 for (int32_t y = 0; y < 7; y++) {
288 if (!IsEmpty(matrix->Get(xStart, yStart + y)))
291 matrix->Set(xStart, yStart + y, 0);
296bool EmbedPositionAdjustmentPattern(int32_t xStart,
298 CBC_CommonByteMatrix* matrix) {
299 for (int32_t y = 0; y < 5; y++) {
300 for (int32_t x = 0; x < 5; x++) {
301 if (!IsEmpty(matrix->Get(xStart + x, y + yStart))) {
304 matrix->Set(xStart + x, yStart + y,
305 kPositionAdjustmentPatternTable[y][x]);
311bool EmbedPositionDetectionPattern(int32_t xStart,
313 CBC_CommonByteMatrix* matrix) {
314 for (int32_t y = 0; y < 7; y++) {
315 for (int32_t x = 0; x < 7; x++) {
316 if (!IsEmpty(matrix->Get(xStart + x, yStart + y)))
319 matrix->Set(xStart + x, yStart + y, kPositionDetectionPatternTable[y][x]);
325bool EmbedPositionDetectionPatternsAndSeparators(CBC_CommonByteMatrix* matrix) {
326 constexpr int32_t pdpWidth = 7;
327 if (!EmbedPositionDetectionPattern(0, 0, matrix))
329 if (!EmbedPositionDetectionPattern(matrix->GetWidth() - pdpWidth, 0, matrix))
331 if (!EmbedPositionDetectionPattern(0, matrix->GetWidth() - pdpWidth, matrix))
334 constexpr int32_t hspWidth = 8;
335 if (!EmbedHorizontalSeparationPattern(0, hspWidth - 1, matrix))
337 if (!EmbedHorizontalSeparationPattern(matrix->GetWidth() - hspWidth,
338 hspWidth - 1, matrix)) {
341 if (!EmbedHorizontalSeparationPattern(0, matrix->GetWidth() - hspWidth,
346 constexpr int32_t vspSize = 7;
347 if (!EmbedVerticalSeparationPattern(vspSize, 0, matrix))
349 if (!EmbedVerticalSeparationPattern(matrix->GetHeight() - vspSize - 1, 0,
353 if (!EmbedVerticalSeparationPattern(vspSize, matrix->GetHeight() - vspSize,
360bool MaybeEmbedPositionAdjustmentPatterns(int32_t version,
361 CBC_CommonByteMatrix* matrix) {
365 const size_t index = version - 2;
366 if (index >=
std::size(kPositionCoordinatePatternTable)) {
370 const auto& coordinates = kPositionCoordinatePatternTable[index];
371 for (size_t i = 0; i < kNumCoordinate; i++) {
372 const int32_t y = coordinates[i];
375 for (size_t j = 0; j < kNumCoordinate; j++) {
376 const int32_t x = coordinates[j];
380 if (IsEmpty(matrix->Get(x, y))) {
381 if (!EmbedPositionAdjustmentPattern(x - 2, y - 2, matrix))
389bool EmbedBasicPatterns(int32_t version, CBC_CommonByteMatrix* matrix) {
390 if (!EmbedPositionDetectionPatternsAndSeparators(matrix))
392 if (!EmbedDarkDotAtLeftBottomCorner(matrix))
394 if (!MaybeEmbedPositionAdjustmentPatterns(version, matrix))
396 if (!EmbedTimingPatterns(matrix))
408 CBC_CommonByteMatrix* matrix) {
409 if (!dataBits || !matrix)
414 if (!EmbedBasicPatterns(version, matrix))
416 if (!EmbedTypeInfo(ecLevel, maskPattern, matrix))
419 MaybeEmbedVersionInfo(version, matrix);
420 return EmbedDataBits(dataBits, maskPattern, matrix);
void AppendBits(int32_t value, int32_t numBits)
bool XOR(const CBC_QRCoderBitVector *other)
static bool GetDataMaskBit(int32_t maskPattern, int32_t x, int32_t y)
static bool BuildMatrix(CBC_QRCoderBitVector *dataBits, const CBC_QRCoderErrorCorrectionLevel *ecLevel, int32_t version, int32_t maskPattern, CBC_CommonByteMatrix *matrix)
static bool IsValidMaskPattern(int32_t maskPattern)