PluginProbe ʕ •ᴥ•ʔ
Booking for Appointments and Events Calendar – Amelia / 2.4.4
Booking for Appointments and Events Calendar – Amelia v2.4.4
2.4.4 2.4.3 2.4.2 2.4.1 2.4 trunk 1.2.1 1.2.10 1.2.11 1.2.12 1.2.13 1.2.14 1.2.15 1.2.16 1.2.17 1.2.18 1.2.19 1.2.2 1.2.20 1.2.21 1.2.22 1.2.23 1.2.24 1.2.25 1.2.26 1.2.27 1.2.28 1.2.29 1.2.3 1.2.30 1.2.31 1.2.32 1.2.33 1.2.34 1.2.35 1.2.36 1.2.37 1.2.38 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 2.0 2.0.1 2.0.2 2.1 2.1.1 2.1.2 2.1.3 2.2 2.2.1 2.3
ameliabooking / vendor / bacon / bacon-qr-code / src / Encoder / MaskUtil.php
ameliabooking / vendor / bacon / bacon-qr-code / src / Encoder Last commit date
BlockPair.php 8 months ago ByteMatrix.php 8 months ago Encoder.php 8 months ago MaskUtil.php 8 months ago MatrixUtil.php 8 months ago QrCode.php 8 months ago
MaskUtil.php
272 lines
1 <?php
2 declare(strict_types = 1);
3
4 namespace BaconQrCode\Encoder;
5
6 use BaconQrCode\Common\BitUtils;
7 use BaconQrCode\Exception\InvalidArgumentException;
8
9 /**
10 * Mask utility.
11 */
12 final class MaskUtil
13 {
14 /**#@+
15 * Penalty weights from section 6.8.2.1
16 */
17 const N1 = 3;
18 const N2 = 3;
19 const N3 = 40;
20 const N4 = 10;
21 /**#@-*/
22
23 private function __construct()
24 {
25 }
26
27 /**
28 * Applies mask penalty rule 1 and returns the penalty.
29 *
30 * Finds repetitive cells with the same color and gives penalty to them.
31 * Example: 00000 or 11111.
32 */
33 public static function applyMaskPenaltyRule1(ByteMatrix $matrix) : int
34 {
35 return (
36 self::applyMaskPenaltyRule1Internal($matrix, true)
37 + self::applyMaskPenaltyRule1Internal($matrix, false)
38 );
39 }
40
41 /**
42 * Applies mask penalty rule 2 and returns the penalty.
43 *
44 * Finds 2x2 blocks with the same color and gives penalty to them. This is
45 * actually equivalent to the spec's rule, which is to find MxN blocks and
46 * give a penalty proportional to (M-1)x(N-1), because this is the number of
47 * 2x2 blocks inside such a block.
48 */
49 public static function applyMaskPenaltyRule2(ByteMatrix $matrix) : int
50 {
51 $penalty = 0;
52 $array = $matrix->getArray();
53 $width = $matrix->getWidth();
54 $height = $matrix->getHeight();
55
56 for ($y = 0; $y < $height - 1; ++$y) {
57 for ($x = 0; $x < $width - 1; ++$x) {
58 $value = $array[$y][$x];
59
60 if ($value === $array[$y][$x + 1]
61 && $value === $array[$y + 1][$x]
62 && $value === $array[$y + 1][$x + 1]
63 ) {
64 ++$penalty;
65 }
66 }
67 }
68
69 return self::N2 * $penalty;
70 }
71
72 /**
73 * Applies mask penalty rule 3 and returns the penalty.
74 *
75 * Finds consecutive cells of 00001011101 or 10111010000, and gives penalty
76 * to them. If we find patterns like 000010111010000, we give penalties
77 * twice (i.e. 40 * 2).
78 */
79 public static function applyMaskPenaltyRule3(ByteMatrix $matrix) : int
80 {
81 $penalty = 0;
82 $array = $matrix->getArray();
83 $width = $matrix->getWidth();
84 $height = $matrix->getHeight();
85
86 for ($y = 0; $y < $height; ++$y) {
87 for ($x = 0; $x < $width; ++$x) {
88 if ($x + 6 < $width
89 && 1 === $array[$y][$x]
90 && 0 === $array[$y][$x + 1]
91 && 1 === $array[$y][$x + 2]
92 && 1 === $array[$y][$x + 3]
93 && 1 === $array[$y][$x + 4]
94 && 0 === $array[$y][$x + 5]
95 && 1 === $array[$y][$x + 6]
96 && (
97 (
98 $x + 10 < $width
99 && 0 === $array[$y][$x + 7]
100 && 0 === $array[$y][$x + 8]
101 && 0 === $array[$y][$x + 9]
102 && 0 === $array[$y][$x + 10]
103 )
104 || (
105 $x - 4 >= 0
106 && 0 === $array[$y][$x - 1]
107 && 0 === $array[$y][$x - 2]
108 && 0 === $array[$y][$x - 3]
109 && 0 === $array[$y][$x - 4]
110 )
111 )
112 ) {
113 $penalty += self::N3;
114 }
115
116 if ($y + 6 < $height
117 && 1 === $array[$y][$x]
118 && 0 === $array[$y + 1][$x]
119 && 1 === $array[$y + 2][$x]
120 && 1 === $array[$y + 3][$x]
121 && 1 === $array[$y + 4][$x]
122 && 0 === $array[$y + 5][$x]
123 && 1 === $array[$y + 6][$x]
124 && (
125 (
126 $y + 10 < $height
127 && 0 === $array[$y + 7][$x]
128 && 0 === $array[$y + 8][$x]
129 && 0 === $array[$y + 9][$x]
130 && 0 === $array[$y + 10][$x]
131 )
132 || (
133 $y - 4 >= 0
134 && 0 === $array[$y - 1][$x]
135 && 0 === $array[$y - 2][$x]
136 && 0 === $array[$y - 3][$x]
137 && 0 === $array[$y - 4][$x]
138 )
139 )
140 ) {
141 $penalty += self::N3;
142 }
143 }
144 }
145
146 return $penalty;
147 }
148
149 /**
150 * Applies mask penalty rule 4 and returns the penalty.
151 *
152 * Calculates the ratio of dark cells and gives penalty if the ratio is far
153 * from 50%. It gives 10 penalty for 5% distance.
154 */
155 public static function applyMaskPenaltyRule4(ByteMatrix $matrix) : int
156 {
157 $numDarkCells = 0;
158
159 $array = $matrix->getArray();
160 $width = $matrix->getWidth();
161 $height = $matrix->getHeight();
162
163 for ($y = 0; $y < $height; ++$y) {
164 $arrayY = $array[$y];
165
166 for ($x = 0; $x < $width; ++$x) {
167 if (1 === $arrayY[$x]) {
168 ++$numDarkCells;
169 }
170 }
171 }
172
173 $numTotalCells = $height * $width;
174 $darkRatio = $numDarkCells / $numTotalCells;
175 $fixedPercentVariances = (int) (abs($darkRatio - 0.5) * 20);
176
177 return $fixedPercentVariances * self::N4;
178 }
179
180 /**
181 * Returns the mask bit for "getMaskPattern" at "x" and "y".
182 *
183 * See 8.8 of JISX0510:2004 for mask pattern conditions.
184 *
185 * @throws InvalidArgumentException if an invalid mask pattern was supplied
186 */
187 public static function getDataMaskBit(int $maskPattern, int $x, int $y) : bool
188 {
189 switch ($maskPattern) {
190 case 0:
191 $intermediate = ($y + $x) & 0x1;
192 break;
193
194 case 1:
195 $intermediate = $y & 0x1;
196 break;
197
198 case 2:
199 $intermediate = $x % 3;
200 break;
201
202 case 3:
203 $intermediate = ($y + $x) % 3;
204 break;
205
206 case 4:
207 $intermediate = (BitUtils::unsignedRightShift($y, 1) + (int) ($x / 3)) & 0x1;
208 break;
209
210 case 5:
211 $temp = $y * $x;
212 $intermediate = ($temp & 0x1) + ($temp % 3);
213 break;
214
215 case 6:
216 $temp = $y * $x;
217 $intermediate = (($temp & 0x1) + ($temp % 3)) & 0x1;
218 break;
219
220 case 7:
221 $temp = $y * $x;
222 $intermediate = (($temp % 3) + (($y + $x) & 0x1)) & 0x1;
223 break;
224
225 default:
226 throw new InvalidArgumentException('Invalid mask pattern: ' . $maskPattern);
227 }
228
229 return 0 == $intermediate;
230 }
231
232 /**
233 * Helper function for applyMaskPenaltyRule1.
234 *
235 * We need this for doing this calculation in both vertical and horizontal
236 * orders respectively.
237 */
238 private static function applyMaskPenaltyRule1Internal(ByteMatrix $matrix, bool $isHorizontal) : int
239 {
240 $penalty = 0;
241 $iLimit = $isHorizontal ? $matrix->getHeight() : $matrix->getWidth();
242 $jLimit = $isHorizontal ? $matrix->getWidth() : $matrix->getHeight();
243 $array = $matrix->getArray();
244
245 for ($i = 0; $i < $iLimit; ++$i) {
246 $numSameBitCells = 0;
247 $prevBit = -1;
248
249 for ($j = 0; $j < $jLimit; $j++) {
250 $bit = $isHorizontal ? $array[$i][$j] : $array[$j][$i];
251
252 if ($bit === $prevBit) {
253 ++$numSameBitCells;
254 } else {
255 if ($numSameBitCells >= 5) {
256 $penalty += self::N1 + ($numSameBitCells - 5);
257 }
258
259 $numSameBitCells = 1;
260 $prevBit = $bit;
261 }
262 }
263
264 if ($numSameBitCells >= 5) {
265 $penalty += self::N1 + ($numSameBitCells - 5);
266 }
267 }
268
269 return $penalty;
270 }
271 }
272