1 // Copyright 2014 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6 // Original code is licensed as follows:
7 /*
8 * Copyright 2008 ZXing authors
9 *
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
13 *
14 * http://www.apache.org/licenses/LICENSE-2.0
15 *
16 * Unless required by applicable law or agreed to in writing, software
17 * distributed under the License is distributed on an "AS IS" BASIS,
18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 * See the License for the specific language governing permissions and
20 * limitations under the License.
21 */
22
23 #include "fxbarcode/qrcode/BC_QRCoderMaskUtil.h"
24
25 #include "fxbarcode/common/BC_CommonByteMatrix.h"
26 #include "fxbarcode/qrcode/BC_QRCoder.h"
27 #include "fxbarcode/qrcode/BC_QRCoderErrorCorrectionLevel.h"
28
29 namespace {
30
ApplyMaskPenaltyRule1Internal(CBC_CommonByteMatrix * matrix,bool isHorizontal)31 int32_t ApplyMaskPenaltyRule1Internal(CBC_CommonByteMatrix* matrix,
32 bool isHorizontal) {
33 int32_t penalty = 0;
34 int32_t numSameBitCells = 0;
35 int32_t prevBit = -1;
36 int32_t width = matrix->GetWidth();
37 int32_t height = matrix->GetHeight();
38 int32_t iLimit = isHorizontal ? height : width;
39 int32_t jLimit = isHorizontal ? width : height;
40 pdfium::span<const uint8_t> array = matrix->GetArray();
41 for (int32_t i = 0; i < iLimit; ++i) {
42 for (int32_t j = 0; j < jLimit; ++j) {
43 int32_t bit = isHorizontal ? array[i * width + j] : array[j * width + i];
44 if (bit == prevBit) {
45 numSameBitCells += 1;
46 if (numSameBitCells == 5) {
47 penalty += 3;
48 } else if (numSameBitCells > 5) {
49 penalty += 1;
50 }
51 } else {
52 numSameBitCells = 1;
53 prevBit = bit;
54 }
55 }
56 numSameBitCells = 0;
57 }
58 return penalty;
59 }
60
61 } // namespace
62
63 // static
ApplyMaskPenaltyRule1(CBC_CommonByteMatrix * matrix)64 int32_t CBC_QRCoderMaskUtil::ApplyMaskPenaltyRule1(
65 CBC_CommonByteMatrix* matrix) {
66 return ApplyMaskPenaltyRule1Internal(matrix, true) +
67 ApplyMaskPenaltyRule1Internal(matrix, false);
68 }
69
70 // static
ApplyMaskPenaltyRule2(CBC_CommonByteMatrix * matrix)71 int32_t CBC_QRCoderMaskUtil::ApplyMaskPenaltyRule2(
72 CBC_CommonByteMatrix* matrix) {
73 int32_t penalty = 0;
74 pdfium::span<const uint8_t> array = matrix->GetArray();
75 int32_t width = matrix->GetWidth();
76 int32_t height = matrix->GetHeight();
77 for (int32_t y = 0; y < height - 1; y++) {
78 for (int32_t x = 0; x < width - 1; x++) {
79 int32_t value = array[y * width + x];
80 if (value == array[y * width + x + 1] &&
81 value == array[(y + 1) * width + x] &&
82 value == array[(y + 1) * width + x + 1]) {
83 penalty++;
84 }
85 }
86 }
87 return 3 * penalty;
88 }
89
90 // static
ApplyMaskPenaltyRule3(CBC_CommonByteMatrix * matrix)91 int32_t CBC_QRCoderMaskUtil::ApplyMaskPenaltyRule3(
92 CBC_CommonByteMatrix* matrix) {
93 int32_t penalty = 0;
94 pdfium::span<const uint8_t> array = matrix->GetArray();
95 int32_t width = matrix->GetWidth();
96 int32_t height = matrix->GetHeight();
97 for (int32_t y = 0; y < height; ++y) {
98 for (int32_t x = 0; x < width; ++x) {
99 if (x == 0 &&
100 ((y >= 0 && y <= 6) || (y >= height - 7 && y <= height - 1))) {
101 continue;
102 }
103 if (x == width - 7 && (y >= 0 && y <= 6)) {
104 continue;
105 }
106 if (y == 0 &&
107 ((x >= 0 && x <= 6) || (x >= width - 7 && x <= width - 1))) {
108 continue;
109 }
110 if (y == height - 7 && (x >= 0 && x <= 6)) {
111 continue;
112 }
113 if (x + 6 < width && array[y * width + x] == 1 &&
114 array[y * width + x + 1] == 0 && array[y * width + x + 2] == 1 &&
115 array[y * width + x + 3] == 1 && array[y * width + x + 4] == 1 &&
116 array[y * width + x + 5] == 0 && array[y * width + x + 6] == 1 &&
117 ((x + 10 < width && array[y * width + x + 7] == 0 &&
118 array[y * width + x + 8] == 0 && array[y * width + x + 9] == 0 &&
119 array[y * width + x + 10] == 0) ||
120 (x - 4 >= 0 && array[y * width + x - 1] == 0 &&
121 array[y * width + x - 2] == 0 && array[y * width + x - 3] == 0 &&
122 array[y * width + x - 4] == 0))) {
123 penalty += 40;
124 }
125 if (y + 6 < height && array[y * width + x] == 1 &&
126 array[(y + 1) * width + x] == 0 && array[(y + 2) * width + x] == 1 &&
127 array[(y + 3) * width + x] == 1 && array[(y + 4) * width + x] == 1 &&
128 array[(y + 5) * width + x] == 0 && array[(y + 6) * width + x] == 1 &&
129 ((y + 10 < height && array[(y + 7) * width + x] == 0 &&
130 array[(y + 8) * width + x] == 0 &&
131 array[(y + 9) * width + x] == 0 &&
132 array[(y + 10) * width + x] == 0) ||
133 (y - 4 >= 0 && array[(y - 1) * width + x] == 0 &&
134 array[(y - 2) * width + x] == 0 &&
135 array[(y - 3) * width + x] == 0 &&
136 array[(y - 4) * width + x] == 0))) {
137 penalty += 40;
138 }
139 }
140 }
141 return penalty;
142 }
143
144 // static
ApplyMaskPenaltyRule4(CBC_CommonByteMatrix * matrix)145 int32_t CBC_QRCoderMaskUtil::ApplyMaskPenaltyRule4(
146 CBC_CommonByteMatrix* matrix) {
147 int32_t numDarkCells = 0;
148 pdfium::span<const uint8_t> array = matrix->GetArray();
149 int32_t width = matrix->GetWidth();
150 int32_t height = matrix->GetHeight();
151 for (int32_t y = 0; y < height; ++y) {
152 for (int32_t x = 0; x < width; ++x) {
153 if (array[y * width + x] == 1)
154 numDarkCells += 1;
155 }
156 }
157 int32_t numTotalCells = matrix->GetHeight() * matrix->GetWidth();
158 double darkRatio = static_cast<double>(numDarkCells) / numTotalCells;
159 return abs(static_cast<int32_t>(darkRatio * 100 - 50) / 5) * 5 * 10;
160 }
161
162 // static
GetDataMaskBit(int32_t maskPattern,int32_t x,int32_t y)163 bool CBC_QRCoderMaskUtil::GetDataMaskBit(int32_t maskPattern,
164 int32_t x,
165 int32_t y) {
166 ASSERT(CBC_QRCoder::IsValidMaskPattern(maskPattern));
167
168 int32_t intermediate = 0, temp = 0;
169 switch (maskPattern) {
170 case 0:
171 intermediate = (y + x) & 0x1;
172 break;
173 case 1:
174 intermediate = y & 0x1;
175 break;
176 case 2:
177 intermediate = x % 3;
178 break;
179 case 3:
180 intermediate = (y + x) % 3;
181 break;
182 case 4:
183 intermediate = ((y >> 1) + (x / 3)) & 0x1;
184 break;
185 case 5:
186 temp = y * x;
187 intermediate = (temp & 0x1) + (temp % 3);
188 break;
189 case 6:
190 temp = y * x;
191 intermediate = (((temp & 0x1) + (temp % 3)) & 0x1);
192 break;
193 case 7:
194 temp = y * x;
195 intermediate = (((temp % 3) + ((y + x) & 0x1)) & 0x1);
196 break;
197 default:
198 NOTREACHED();
199 return false;
200 }
201 return intermediate == 0;
202 }
203