Small style stuff
[zxing.git] / core / src / com / google / zxing / qrcode / encoder / MaskUtil.java
1 /*
2  * Copyright 2008 ZXing authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package com.google.zxing.qrcode.encoder;
18
19 /**
20  * @author satorux@google.com (Satoru Takabayashi) - creator
21  * @author dswitkin@google.com (Daniel Switkin) - ported from C++
22  */
23 public final class MaskUtil {
24
25   private MaskUtil() {
26     // do nothing
27   }
28
29   // Apply mask penalty rule 1 and return the penalty. Find repetitive cells with the same color and
30   // give penalty to them. Example: 00000 or 11111.
31   public static int applyMaskPenaltyRule1(ByteMatrix matrix) {
32     return applyMaskPenaltyRule1Internal(matrix, true) + applyMaskPenaltyRule1Internal(matrix, false);
33   }
34
35   // Apply mask penalty rule 2 and return the penalty. Find 2x2 blocks with the same color and give
36   // penalty to them.
37   public static int applyMaskPenaltyRule2(ByteMatrix matrix) {
38     int penalty = 0;
39     byte[][] array = matrix.getArray();
40     int width = matrix.getWidth();
41     int height = matrix.getHeight();
42     for (int y = 0; y < height - 1; ++y) {
43       for (int x = 0; x < width - 1; ++x) {
44         int value = array[y][x];
45         if (value == array[y][x + 1] && value == array[y + 1][x] && value == array[y + 1][x + 1]) {
46           penalty += 3;
47         }
48       }
49     }
50     return penalty;
51   }
52
53   // Apply mask penalty rule 3 and return the penalty. Find consecutive cells of 00001011101 or
54   // 10111010000, and give penalty to them.  If we find patterns like 000010111010000, we give
55   // penalties twice (i.e. 40 * 2).
56   public static int applyMaskPenaltyRule3(ByteMatrix matrix) {
57     int penalty = 0;
58     byte[][] array = matrix.getArray();
59     int width = matrix.getWidth();
60     int height = matrix.getHeight();
61     for (int y = 0; y < height; ++y) {
62       for (int x = 0; x < width; ++x) {
63         // Tried to simplify following conditions but failed.
64         if (x + 6 < width &&
65             array[y][x] == 1 &&
66             array[y][x +  1] == 0 &&
67             array[y][x +  2] == 1 &&
68             array[y][x +  3] == 1 &&
69             array[y][x +  4] == 1 &&
70             array[y][x +  5] == 0 &&
71             array[y][x +  6] == 1 &&
72             ((x + 10 < width &&
73                 array[y][x +  7] == 0 &&
74                 array[y][x +  8] == 0 &&
75                 array[y][x +  9] == 0 &&
76                 array[y][x + 10] == 0) ||
77                 (x - 4 >= 0 &&
78                     array[y][x -  1] == 0 &&
79                     array[y][x -  2] == 0 &&
80                     array[y][x -  3] == 0 &&
81                     array[y][x -  4] == 0))) {
82           penalty += 40;
83         }
84         if (y + 6 < height &&
85             array[y][x] == 1  &&
86             array[y +  1][x] == 0  &&
87             array[y +  2][x] == 1  &&
88             array[y +  3][x] == 1  &&
89             array[y +  4][x] == 1  &&
90             array[y +  5][x] == 0  &&
91             array[y +  6][x] == 1 &&
92             ((y + 10 < height &&
93                 array[y +  7][x] == 0 &&
94                 array[y +  8][x] == 0 &&
95                 array[y +  9][x] == 0 &&
96                 array[y + 10][x] == 0) ||
97                 (y - 4 >= 0 &&
98                     array[y -  1][x] == 0 &&
99                     array[y -  2][x] == 0 &&
100                     array[y -  3][x] == 0 &&
101                     array[y -  4][x] == 0))) {
102           penalty += 40;
103         }
104       }
105     }
106     return penalty;
107   }
108
109   // Apply mask penalty rule 4 and return the penalty. Calculate the ratio of dark cells and give
110   // penalty if the ratio is far from 50%. It gives 10 penalty for 5% distance. Examples:
111   // -   0% => 100
112   // -  40% =>  20
113   // -  45% =>  10
114   // -  50% =>   0
115   // -  55% =>  10
116   // -  55% =>  20
117   // - 100% => 100
118   public static int applyMaskPenaltyRule4(ByteMatrix matrix) {
119     int numDarkCells = 0;
120     byte[][] array = matrix.getArray();
121     int width = matrix.getWidth();
122     int height = matrix.getHeight();
123     for (int y = 0; y < height; ++y) {
124       for (int x = 0; x < width; ++x) {
125         if (array[y][x] == 1) {
126           numDarkCells += 1;
127         }
128       }
129     }
130     int numTotalCells = matrix.getHeight() * matrix.getWidth();
131     double darkRatio = (double) numDarkCells / numTotalCells;
132     return Math.abs((int) (darkRatio * 100 - 50)) / 5 * 10;
133   }
134
135   // Return the mask bit for "getMaskPattern" at "x" and "y". See 8.8 of JISX0510:2004 for mask
136   // pattern conditions.
137   public static boolean getDataMaskBit(int maskPattern, int x, int y) {
138     if (!QRCode.isValidMaskPattern(maskPattern)) {
139       throw new IllegalArgumentException("Invalid mask pattern");
140     }
141     int intermediate, temp;
142     switch (maskPattern) {
143       case 0:
144         intermediate = (y + x) & 0x1;
145         break;
146       case 1:
147         intermediate = y & 0x1;
148         break;
149       case 2:
150         intermediate = x % 3;
151         break;
152       case 3:
153         intermediate = (y + x) % 3;
154         break;
155       case 4:
156         intermediate = ((y >>> 1) + (x / 3)) & 0x1;
157         break;
158       case 5:
159         temp = y * x;
160         intermediate = (temp & 0x1) + (temp % 3);
161         break;
162       case 6:
163         temp = y * x;
164         intermediate = (((temp & 0x1) + (temp % 3)) & 0x1);
165         break;
166       case 7:
167         temp = y * x;
168         intermediate = (((temp % 3) + ((y + x) & 0x1)) & 0x1);
169         break;
170       default:
171         throw new IllegalArgumentException("Invalid mask pattern: " + maskPattern);
172     }
173     return intermediate == 0;
174   }
175
176   // Helper function for applyMaskPenaltyRule1. We need this for doing this calculation in both
177   // vertical and horizontal orders respectively.
178   private static int applyMaskPenaltyRule1Internal(ByteMatrix matrix, boolean isHorizontal) {
179     int penalty = 0;
180     int numSameBitCells = 0;
181     int prevBit = -1;
182     // Horizontal mode:
183     //   for (int i = 0; i < matrix.height(); ++i) {
184     //     for (int j = 0; j < matrix.width(); ++j) {
185     //       int bit = matrix.get(i, j);
186     // Vertical mode:
187     //   for (int i = 0; i < matrix.width(); ++i) {
188     //     for (int j = 0; j < matrix.height(); ++j) {
189     //       int bit = matrix.get(j, i);
190     int iLimit = isHorizontal ? matrix.getHeight() : matrix.getWidth();
191     int jLimit = isHorizontal ? matrix.getWidth() : matrix.getHeight();
192     byte[][] array = matrix.getArray();
193     for (int i = 0; i < iLimit; ++i) {
194       for (int j = 0; j < jLimit; ++j) {
195         int bit = isHorizontal ? array[i][j] : array[j][i];
196         if (bit == prevBit) {
197           numSameBitCells += 1;
198           // Found five repetitive cells with the same color (bit).
199           // We'll give penalty of 3.
200           if (numSameBitCells == 5) {
201             penalty += 3;
202           } else if (numSameBitCells > 5) {
203             // After five repetitive cells, we'll add the penalty one
204             // by one.
205             penalty += 1;
206           }
207         } else {
208           numSameBitCells = 1;  // Include the cell itself.
209           prevBit = bit;
210         }
211       }
212       numSameBitCells = 0;  // Clear at each row/column.
213     }
214     return penalty;
215   }
216
217 }