1
1
using System ;
2
+ using System . Collections ;
2
3
using System . Collections . Generic ;
3
4
4
5
namespace QRCoder
@@ -7,63 +8,109 @@ public partial class QRCodeGenerator
7
8
{
8
9
private static partial class ModulePlacer
9
10
{
11
+ /// <summary>
12
+ /// Provides static methods and properties to handle mask patterns used in QR code generation.
13
+ /// Mask patterns are applied to QR codes to break up patterns in the data matrix that might confuse scanners.
14
+ /// </summary>
10
15
private static class MaskPattern
11
16
{
17
+ /// <summary>
18
+ /// A dictionary mapping each mask pattern index to its corresponding function that calculates whether a given pixel should be masked.
19
+ /// </summary>
12
20
public static readonly Dictionary < int , Func < int , int , bool > > Patterns =
13
21
new Dictionary < int , Func < int , int , bool > > ( 8 ) {
14
22
{ 1 , MaskPattern . Pattern1 } , { 2 , MaskPattern . Pattern2 } , { 3 , MaskPattern . Pattern3 } , { 4 , MaskPattern . Pattern4 } ,
15
23
{ 5 , MaskPattern . Pattern5 } , { 6 , MaskPattern . Pattern6 } , { 7 , MaskPattern . Pattern7 } , { 8 , MaskPattern . Pattern8 }
16
24
} ;
17
25
26
+ /// <summary>
27
+ /// Mask pattern 1: (x + y) % 2 == 0
28
+ /// Applies a checkerboard mask on the QR code.
29
+ /// </summary>
18
30
public static bool Pattern1 ( int x , int y )
19
31
{
20
32
return ( x + y ) % 2 == 0 ;
21
33
}
22
34
35
+ /// <summary>
36
+ /// Mask pattern 2: y % 2 == 0
37
+ /// Applies a horizontal striping mask on the QR code.
38
+ /// </summary>
23
39
public static bool Pattern2 ( int x , int y )
24
40
{
25
41
return y % 2 == 0 ;
26
42
}
27
43
44
+ /// <summary>
45
+ /// Mask pattern 3: x % 3 == 0
46
+ /// Applies a vertical striping mask on the QR code.
47
+ /// </summary>
28
48
public static bool Pattern3 ( int x , int y )
29
49
{
30
50
return x % 3 == 0 ;
31
51
}
32
52
53
+ /// <summary>
54
+ /// Mask pattern 4: (x + y) % 3 == 0
55
+ /// Applies a diagonal striping mask on the QR code.
56
+ /// </summary>
33
57
public static bool Pattern4 ( int x , int y )
34
58
{
35
59
return ( x + y ) % 3 == 0 ;
36
60
}
37
61
62
+ /// <summary>
63
+ /// Mask pattern 5: ((y / 2) + (x / 3)) % 2 == 0
64
+ /// Applies a complex pattern mask on the QR code, mixing horizontal and vertical rules.
65
+ /// </summary>
38
66
public static bool Pattern5 ( int x , int y )
39
67
{
40
68
return ( ( int ) ( Math . Floor ( y / 2d ) + Math . Floor ( x / 3d ) ) % 2 ) == 0 ;
41
69
}
42
70
71
+ /// <summary>
72
+ /// Mask pattern 6: ((x * y) % 2 + (x * y) % 3) == 0
73
+ /// Applies a mask based on the product of x and y coordinates modulo 2 and 3.
74
+ /// </summary>
43
75
public static bool Pattern6 ( int x , int y )
44
76
{
45
77
return ( ( x * y ) % 2 ) + ( ( x * y ) % 3 ) == 0 ;
46
78
}
47
79
80
+ /// <summary>
81
+ /// Mask pattern 7: (((x * y) % 2 + (x * y) % 3) % 2) == 0
82
+ /// Applies a mask based on a more complex function involving the product of x and y coordinates.
83
+ /// </summary>
48
84
public static bool Pattern7 ( int x , int y )
49
85
{
50
86
return ( ( ( x * y ) % 2 ) + ( ( x * y ) % 3 ) ) % 2 == 0 ;
51
87
}
52
88
89
+ /// <summary>
90
+ /// Mask pattern 8: (((x + y) % 2) + ((x * y) % 3) % 2) == 0
91
+ /// Combines rules of checkers and complex multiplicative masks.
92
+ /// </summary>
53
93
public static bool Pattern8 ( int x , int y )
54
94
{
55
95
return ( ( ( x + y ) % 2 ) + ( ( x * y ) % 3 ) ) % 2 == 0 ;
56
96
}
57
97
98
+ /// <summary>
99
+ /// Calculates a penalty score for a QR code to evaluate the effectiveness of a mask pattern.
100
+ /// A lower score indicates a QR code that is easier for decoders to read accurately.
101
+ /// The score is the sum of four penalty rules applied to the QR code.
102
+ /// </summary>
103
+ /// <param name="qrCode">The QR code data structure to be evaluated.</param>
104
+ /// <returns>The total penalty score of the QR code.</returns>
58
105
public static int Score ( QRCodeData qrCode )
59
106
{
60
- int score1 = 0 ,
61
- score2 = 0 ,
62
- score3 = 0 ,
63
- score4 = 0 ;
107
+ int score1 = 0 , // Penalty for groups of five or more same-color modules in a row (or column)
108
+ score2 = 0 , // Penalty for blocks of modules in the same color
109
+ score3 = 0 , // Penalty for specific patterns found within the QR code
110
+ score4 = 0 ; // Penalty for having more than 50% black modules or more than 50% white modules
64
111
var size = qrCode . ModuleMatrix . Count ;
65
112
66
- //Penalty 1
113
+ //Penalty 1: Checking for consecutive modules of the same color in rows and columns
67
114
for ( var y = 0 ; y < size ; y ++ )
68
115
{
69
116
var modInRow = 0 ;
@@ -72,6 +119,7 @@ public static int Score(QRCodeData qrCode)
72
119
var lastValColumn = qrCode . ModuleMatrix [ 0 ] [ y ] ;
73
120
for ( var x = 0 ; x < size ; x ++ )
74
121
{
122
+ // Check rows for consecutive modules
75
123
if ( qrCode . ModuleMatrix [ y ] [ x ] == lastValRow )
76
124
modInRow ++ ;
77
125
else
@@ -82,7 +130,7 @@ public static int Score(QRCodeData qrCode)
82
130
score1 ++ ;
83
131
lastValRow = qrCode . ModuleMatrix [ y ] [ x ] ;
84
132
85
-
133
+ // Check columns for consecutive modules
86
134
if ( qrCode . ModuleMatrix [ x ] [ y ] == lastValColumn )
87
135
modInColumn ++ ;
88
136
else
@@ -95,79 +143,35 @@ public static int Score(QRCodeData qrCode)
95
143
}
96
144
}
97
145
98
-
99
- //Penalty 2
146
+ //Penalty 2: Checking for blocks of modules in the same color
100
147
for ( var y = 0 ; y < size - 1 ; y ++ )
101
148
{
102
149
for ( var x = 0 ; x < size - 1 ; x ++ )
103
150
{
104
151
if ( qrCode . ModuleMatrix [ y ] [ x ] == qrCode . ModuleMatrix [ y ] [ x + 1 ] &&
105
152
qrCode . ModuleMatrix [ y ] [ x ] == qrCode . ModuleMatrix [ y + 1 ] [ x ] &&
106
153
qrCode . ModuleMatrix [ y ] [ x ] == qrCode . ModuleMatrix [ y + 1 ] [ x + 1 ] )
154
+ {
107
155
score2 += 3 ;
156
+ }
108
157
}
109
158
}
110
159
111
- //Penalty 3
160
+ //Penalty 3: Checking for specific patterns within the QR code (patterns that should be avoided)
112
161
for ( var y = 0 ; y < size ; y ++ )
113
162
{
114
163
for ( var x = 0 ; x < size - 10 ; x ++ )
115
164
{
116
- if ( ( qrCode . ModuleMatrix [ y ] [ x ] &&
117
- ! qrCode . ModuleMatrix [ y ] [ x + 1 ] &&
118
- qrCode . ModuleMatrix [ y ] [ x + 2 ] &&
119
- qrCode . ModuleMatrix [ y ] [ x + 3 ] &&
120
- qrCode . ModuleMatrix [ y ] [ x + 4 ] &&
121
- ! qrCode . ModuleMatrix [ y ] [ x + 5 ] &&
122
- qrCode . ModuleMatrix [ y ] [ x + 6 ] &&
123
- ! qrCode . ModuleMatrix [ y ] [ x + 7 ] &&
124
- ! qrCode . ModuleMatrix [ y ] [ x + 8 ] &&
125
- ! qrCode . ModuleMatrix [ y ] [ x + 9 ] &&
126
- ! qrCode . ModuleMatrix [ y ] [ x + 10 ] ) ||
127
- ( ! qrCode . ModuleMatrix [ y ] [ x ] &&
128
- ! qrCode . ModuleMatrix [ y ] [ x + 1 ] &&
129
- ! qrCode . ModuleMatrix [ y ] [ x + 2 ] &&
130
- ! qrCode . ModuleMatrix [ y ] [ x + 3 ] &&
131
- qrCode . ModuleMatrix [ y ] [ x + 4 ] &&
132
- ! qrCode . ModuleMatrix [ y ] [ x + 5 ] &&
133
- qrCode . ModuleMatrix [ y ] [ x + 6 ] &&
134
- qrCode . ModuleMatrix [ y ] [ x + 7 ] &&
135
- qrCode . ModuleMatrix [ y ] [ x + 8 ] &&
136
- ! qrCode . ModuleMatrix [ y ] [ x + 9 ] &&
137
- qrCode . ModuleMatrix [ y ] [ x + 10 ] ) )
138
- {
165
+ // Horizontal pattern matching
166
+ if ( MatchesPattern1 ( qrCode . ModuleMatrix , x , y ) )
139
167
score3 += 40 ;
140
- }
141
-
142
- if ( ( qrCode . ModuleMatrix [ x ] [ y ] &&
143
- ! qrCode . ModuleMatrix [ x + 1 ] [ y ] &&
144
- qrCode . ModuleMatrix [ x + 2 ] [ y ] &&
145
- qrCode . ModuleMatrix [ x + 3 ] [ y ] &&
146
- qrCode . ModuleMatrix [ x + 4 ] [ y ] &&
147
- ! qrCode . ModuleMatrix [ x + 5 ] [ y ] &&
148
- qrCode . ModuleMatrix [ x + 6 ] [ y ] &&
149
- ! qrCode . ModuleMatrix [ x + 7 ] [ y ] &&
150
- ! qrCode . ModuleMatrix [ x + 8 ] [ y ] &&
151
- ! qrCode . ModuleMatrix [ x + 9 ] [ y ] &&
152
- ! qrCode . ModuleMatrix [ x + 10 ] [ y ] ) ||
153
- ( ! qrCode . ModuleMatrix [ x ] [ y ] &&
154
- ! qrCode . ModuleMatrix [ x + 1 ] [ y ] &&
155
- ! qrCode . ModuleMatrix [ x + 2 ] [ y ] &&
156
- ! qrCode . ModuleMatrix [ x + 3 ] [ y ] &&
157
- qrCode . ModuleMatrix [ x + 4 ] [ y ] &&
158
- ! qrCode . ModuleMatrix [ x + 5 ] [ y ] &&
159
- qrCode . ModuleMatrix [ x + 6 ] [ y ] &&
160
- qrCode . ModuleMatrix [ x + 7 ] [ y ] &&
161
- qrCode . ModuleMatrix [ x + 8 ] [ y ] &&
162
- ! qrCode . ModuleMatrix [ x + 9 ] [ y ] &&
163
- qrCode . ModuleMatrix [ x + 10 ] [ y ] ) )
164
- {
168
+ // Vertical pattern matching
169
+ if ( MatchesPattern1 ( qrCode . ModuleMatrix , y , x ) )
165
170
score3 += 40 ;
166
- }
167
171
}
168
172
}
169
173
170
- //Penalty 4
174
+ //Penalty 4: Proportions of dark and light modules
171
175
int blackModules = 0 ;
172
176
foreach ( var bitArray in qrCode . ModuleMatrix )
173
177
for ( var x = 0 ; x < size ; x ++ )
@@ -179,8 +183,38 @@ public static int Score(QRCodeData qrCode)
179
183
var nextMultipleOf5 = Math . Abs ( percentDiv5 - 9 ) ;
180
184
score4 = Math . Min ( prevMultipleOf5 , nextMultipleOf5 ) * 10 ;
181
185
186
+ // Return the sum of all four penalties
182
187
return ( score1 + score2 ) + ( score3 + score4 ) ;
183
188
}
189
+
190
+ /// <summary>
191
+ /// Matches the specified pattern in QR code evaluation rules (1:1:3:1:1 ratio).
192
+ /// </summary>
193
+ private static bool MatchesPattern1 ( List < BitArray > matrix , int x , int y )
194
+ {
195
+ return ( matrix [ y ] [ x ] &&
196
+ ! matrix [ y ] [ x + 1 ] &&
197
+ matrix [ y ] [ x + 2 ] &&
198
+ matrix [ y ] [ x + 3 ] &&
199
+ matrix [ y ] [ x + 4 ] &&
200
+ ! matrix [ y ] [ x + 5 ] &&
201
+ matrix [ y ] [ x + 6 ] &&
202
+ ! matrix [ y ] [ x + 7 ] &&
203
+ ! matrix [ y ] [ x + 8 ] &&
204
+ ! matrix [ y ] [ x + 9 ] &&
205
+ ! matrix [ y ] [ x + 10 ] ) ||
206
+ ( ! matrix [ y ] [ x ] &&
207
+ ! matrix [ y ] [ x + 1 ] &&
208
+ ! matrix [ y ] [ x + 2 ] &&
209
+ ! matrix [ y ] [ x + 3 ] &&
210
+ matrix [ y ] [ x + 4 ] &&
211
+ ! matrix [ y ] [ x + 5 ] &&
212
+ matrix [ y ] [ x + 6 ] &&
213
+ matrix [ y ] [ x + 7 ] &&
214
+ matrix [ y ] [ x + 8 ] &&
215
+ ! matrix [ y ] [ x + 9 ] &&
216
+ matrix [ y ] [ x + 10 ] ) ;
217
+ }
184
218
}
185
219
}
186
220
}
0 commit comments