Added rendering fix from beyonddeath
[zxing.git] / csharp / qrcode / encoder / MatrixUtil.cs
1 /*\r
2 * Copyright 2007 ZXing authors\r
3 *\r
4 * Licensed under the Apache License, Version 2.0 (the "License");\r
5 * you may not use this file except in compliance with the License.\r
6 * You may obtain a copy of the License at\r
7 *\r
8 *      http://www.apache.org/licenses/LICENSE-2.0\r
9 *\r
10 * Unless required by applicable law or agreed to in writing, software\r
11 * distributed under the License is distributed on an "AS IS" BASIS,\r
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
13 * See the License for the specific language governing permissions and\r
14 * limitations under the License.\r
15 */\r
16 using System;\r
17 using System.Text;\r
18 using com.google.zxing;\r
19 using com.google.zxing.common;\r
20 using com.google.zxing.qrcode.decoder;\r
21 using com.google.zxing.qrcode;\r
22 \r
23 namespace com.google.zxing.qrcode.encoder\r
24 {\r
25     public sealed class MatrixUtil \r
26     { \r
27           private MatrixUtil() {\r
28             // do nothing\r
29           }\r
30 \r
31          private static int[][] POSITION_DETECTION_PATTERN =  new int[][]{\r
32               new int[]{1, 1, 1, 1, 1, 1, 1},\r
33               new int[]{1, 0, 0, 0, 0, 0, 1},\r
34               new int[]{1, 0, 1, 1, 1, 0, 1},\r
35               new int[]{1, 0, 1, 1, 1, 0, 1},\r
36               new int[]{1, 0, 1, 1, 1, 0, 1},\r
37               new int[]{1, 0, 0, 0, 0, 0, 1},\r
38               new int[]{1, 1, 1, 1, 1, 1, 1},\r
39           };\r
40 \r
41           private static  int[][] HORIZONTAL_SEPARATION_PATTERN = new int[][]{\r
42               new int[]{0, 0, 0, 0, 0, 0, 0, 0},\r
43           };\r
44 \r
45           private static int[][] VERTICAL_SEPARATION_PATTERN = new int[][]{\r
46               new int[]{0}, new int[]{0}, new int[]{0}, new int[]{0}, new int[]{0}, new int[]{0}, new int[]{0},\r
47           };\r
48 \r
49           private static int[][] POSITION_ADJUSTMENT_PATTERN = new int[][]{\r
50               new int[]{1, 1, 1, 1, 1},\r
51               new int[]{1, 0, 0, 0, 1},\r
52               new int[]{1, 0, 1, 0, 1},\r
53               new int[]{1, 0, 0, 0, 1},\r
54               new int[]{1, 1, 1, 1, 1},\r
55           };\r
56 \r
57           // From Appendix E. Table 1, JIS0510X:2004 (p 71). The table was double-checked by komatsu.\r
58           private static int[][] POSITION_ADJUSTMENT_PATTERN_COORDINATE_TABLE = new int[][]{\r
59               new int[]{-1, -1, -1, -1,  -1,  -1,  -1},  // Version 1\r
60               new int[]{ 6, 18, -1, -1,  -1,  -1,  -1},  // Version 2\r
61               new int[]{ 6, 22, -1, -1,  -1,  -1,  -1},  // Version 3\r
62               new int[]{ 6, 26, -1, -1,  -1,  -1,  -1},  // Version 4\r
63               new int[]{ 6, 30, -1, -1,  -1,  -1,  -1},  // Version 5\r
64               new int[]{ 6, 34, -1, -1,  -1,  -1,  -1},  // Version 6\r
65               new int[]{ 6, 22, 38, -1,  -1,  -1,  -1},  // Version 7\r
66               new int[]{ 6, 24, 42, -1,  -1,  -1,  -1},  // Version 8\r
67               new int[]{ 6, 26, 46, -1,  -1,  -1,  -1},  // Version 9\r
68               new int[]{ 6, 28, 50, -1,  -1,  -1,  -1},  // Version 10\r
69               new int[]{ 6, 30, 54, -1,  -1,  -1,  -1},  // Version 11\r
70               new int[]{ 6, 32, 58, -1,  -1,  -1,  -1},  // Version 12\r
71               new int[]{ 6, 34, 62, -1,  -1,  -1,  -1},  // Version 13\r
72               new int[]{ 6, 26, 46, 66,  -1,  -1,  -1},  // Version 14\r
73               new int[]{ 6, 26, 48, 70,  -1,  -1,  -1},  // Version 15\r
74               new int[]{ 6, 26, 50, 74,  -1,  -1,  -1},  // Version 16\r
75               new int[]{ 6, 30, 54, 78,  -1,  -1,  -1},  // Version 17\r
76               new int[]{ 6, 30, 56, 82,  -1,  -1,  -1},  // Version 18\r
77               new int[]{ 6, 30, 58, 86,  -1,  -1,  -1},  // Version 19\r
78               new int[]{ 6, 34, 62, 90,  -1,  -1,  -1},  // Version 20\r
79               new int[]{ 6, 28, 50, 72,  94,  -1,  -1},  // Version 21\r
80               new int[]{ 6, 26, 50, 74,  98,  -1,  -1},  // Version 22\r
81               new int[]{ 6, 30, 54, 78, 102,  -1,  -1},  // Version 23\r
82               new int[]{ 6, 28, 54, 80, 106,  -1,  -1},  // Version 24\r
83               new int[]{ 6, 32, 58, 84, 110,  -1,  -1},  // Version 25\r
84               new int[]{ 6, 30, 58, 86, 114,  -1,  -1},  // Version 26\r
85               new int[]{ 6, 34, 62, 90, 118,  -1,  -1},  // Version 27\r
86               new int[]{ 6, 26, 50, 74,  98, 122,  -1},  // Version 28\r
87               new int[]{ 6, 30, 54, 78, 102, 126,  -1},  // Version 29\r
88               new int[]{ 6, 26, 52, 78, 104, 130,  -1},  // Version 30\r
89               new int[]{ 6, 30, 56, 82, 108, 134,  -1},  // Version 31\r
90               new int[]{ 6, 34, 60, 86, 112, 138,  -1},  // Version 32\r
91               new int[]{ 6, 30, 58, 86, 114, 142,  -1},  // Version 33\r
92               new int[]{ 6, 34, 62, 90, 118, 146,  -1},  // Version 34\r
93               new int[]{ 6, 30, 54, 78, 102, 126, 150},  // Version 35\r
94               new int[]{ 6, 24, 50, 76, 102, 128, 154},  // Version 36\r
95               new int[]{ 6, 28, 54, 80, 106, 132, 158},  // Version 37\r
96               new int[]{ 6, 32, 58, 84, 110, 136, 162},  // Version 38\r
97               new int[]{ 6, 26, 54, 82, 110, 138, 166},  // Version 39\r
98               new int[]{ 6, 30, 58, 86, 114, 142, 170},  // Version 40\r
99           };\r
100 \r
101           // Type info cells at the left top corner.\r
102           private static int[][] TYPE_INFO_COORDINATES = new int[][]{\r
103               new int[]{8, 0},\r
104               new int[]{8, 1},\r
105               new int[]{8, 2},\r
106               new int[]{8, 3},\r
107               new int[]{8, 4},\r
108               new int[]{8, 5},\r
109               new int[]{8, 7},\r
110               new int[]{8, 8},\r
111               new int[]{7, 8},\r
112               new int[]{5, 8},\r
113               new int[]{4, 8},\r
114               new int[]{3, 8},\r
115               new int[]{2, 8},\r
116               new int[]{1, 8},\r
117               new int[]{0, 8},\r
118           };\r
119 \r
120           // From Appendix D in JISX0510:2004 (p. 67)\r
121           private static  int VERSION_INFO_POLY = 0x1f25;  // 1 1111 0010 0101\r
122 \r
123           // From Appendix C in JISX0510:2004 (p.65).\r
124           private static  int TYPE_INFO_POLY = 0x537;\r
125           private static  int TYPE_INFO_MASK_PATTERN = 0x5412;\r
126 \r
127           // Set all cells to -1.  -1 means that the cell is empty (not set yet).\r
128           //\r
129           // JAVAPORT: We shouldn't need to do this at all. The code should be rewritten to begin encoding\r
130           // with the ByteMatrix initialized all to zero.\r
131           public static void clearMatrix(ByteMatrix matrix) {\r
132               matrix.clear((sbyte)(-1));\r
133           }\r
134 \r
135           // Build 2D matrix of QR Code from "dataBits" with "ecLevel", "version" and "getMaskPattern". On\r
136           // success, store the result in "matrix" and return true.\r
137           public static void buildMatrix(BitVector dataBits, ErrorCorrectionLevel ecLevel, int version,int maskPattern, ByteMatrix matrix) {\r
138                try{\r
139                     clearMatrix(matrix);\r
140                     embedBasicPatterns(version, matrix);\r
141                     // Type information appear with any version.\r
142                     embedTypeInfo(ecLevel, maskPattern, matrix);\r
143                     // Version info appear if version >= 7.\r
144                     maybeEmbedVersionInfo(version, matrix);\r
145                     // Data should be embedded at end.\r
146                     embedDataBits(dataBits, maskPattern, matrix);\r
147                }catch(Exception e){\r
148                     throw  new WriterException(e.Message);\r
149                }\r
150               \r
151           }\r
152 \r
153           // Embed basic patterns. On success, modify the matrix and return true.\r
154           // The basic patterns are:\r
155           // - Position detection patterns\r
156           // - Timing patterns\r
157           // - Dark dot at the left bottom corner\r
158           // - Position adjustment patterns, if need be\r
159           public static void embedBasicPatterns(int version, ByteMatrix matrix){\r
160               try\r
161               {\r
162                     // Let's get started with embedding big squares at corners.\r
163                     embedPositionDetectionPatternsAndSeparators(matrix);\r
164                     // Then, embed the dark dot at the left bottom corner.\r
165                     embedDarkDotAtLeftBottomCorner(matrix);\r
166 \r
167                     // Position adjustment patterns appear if version >= 2.\r
168                     maybeEmbedPositionAdjustmentPatterns(version, matrix);\r
169                     // Timing patterns should be embedded after position adj. patterns.\r
170                     embedTimingPatterns(matrix);\r
171               }catch(Exception e){\r
172                 throw new WriterException (e.Message);\r
173               }\r
174           }\r
175 \r
176           // Embed type information. On success, modify the matrix.\r
177           public static void embedTypeInfo(ErrorCorrectionLevel ecLevel, int maskPattern, ByteMatrix matrix)\r
178           {\r
179             BitVector typeInfoBits = new BitVector();\r
180             makeTypeInfoBits(ecLevel, maskPattern, typeInfoBits);\r
181 \r
182             for (int i = 0; i < typeInfoBits.size(); ++i) {\r
183               // Place bits in LSB to MSB order.  LSB (least significant bit) is the last value in\r
184               // "typeInfoBits".\r
185               int bit = typeInfoBits.at(typeInfoBits.size() - 1 - i);\r
186 \r
187               // Type info bits at the left top corner. See 8.9 of JISX0510:2004 (p.46).\r
188               int x1 = TYPE_INFO_COORDINATES[i][0];\r
189               int y1 = TYPE_INFO_COORDINATES[i][1];\r
190               matrix.set(y1, x1, bit);\r
191 \r
192               if (i < 8) {\r
193                 // Right top corner.\r
194                 int x2 = matrix.width() - i - 1;\r
195                 int y2 = 8;\r
196                 matrix.set(y2, x2, bit);\r
197               } else {\r
198                 // Left bottom corner.\r
199                 int x2 = 8;\r
200                 int y2 = matrix.height() - 7 + (i - 8);\r
201                 matrix.set(y2, x2, bit);\r
202               }\r
203             }\r
204           }\r
205 \r
206           // Embed version information if need be. On success, modify the matrix and return true.\r
207           // See 8.10 of JISX0510:2004 (p.47) for how to embed version information.\r
208           public static void maybeEmbedVersionInfo(int version, ByteMatrix matrix){\r
209             if (version < 7) {  // Version info is necessary if version >= 7.\r
210               return;  // Don't need version info.\r
211             }\r
212             BitVector versionInfoBits = new BitVector();\r
213             makeVersionInfoBits(version, versionInfoBits);\r
214 \r
215             int bitIndex = 6 * 3 - 1;  // It will decrease from 17 to 0.\r
216             for (int i = 0; i < 6; ++i) {\r
217               for (int j = 0; j < 3; ++j) {\r
218                 // Place bits in LSB (least significant bit) to MSB order.\r
219                 int bit = versionInfoBits.at(bitIndex);\r
220                 bitIndex--;\r
221                 // Left bottom corner.\r
222                 matrix.set(matrix.height() - 11 + j, i, bit);\r
223                 // Right bottom corner.\r
224                 matrix.set(i, matrix.height() - 11 + j, bit);\r
225               }\r
226             }\r
227           }\r
228 \r
229           // Embed "dataBits" using "getMaskPattern". On success, modify the matrix and return true.\r
230           // For debugging purposes, it skips masking process if "getMaskPattern" is -1.\r
231           // See 8.7 of JISX0510:2004 (p.38) for how to embed data bits.\r
232           public static void embedDataBits(BitVector dataBits, int maskPattern, ByteMatrix matrix)\r
233           {\r
234             int bitIndex = 0;\r
235             int direction = -1;\r
236             // Start from the right bottom cell.\r
237             int x = matrix.width() - 1;\r
238             int y = matrix.height() - 1;\r
239             while (x > 0) {\r
240               // Skip the vertical timing pattern.\r
241               if (x == 6) {\r
242                 x -= 1;\r
243               }\r
244               while (y >= 0 && y < matrix.height()) {\r
245                 for (int i = 0; i < 2; ++i) {\r
246                   int xx = x - i;\r
247                   // Skip the cell if it's not empty.\r
248                   if (!isEmpty(matrix.get(y, xx))) {\r
249                     continue;\r
250                   }\r
251                   int bit;\r
252                   if (bitIndex < dataBits.size()) {\r
253                     bit = dataBits.at(bitIndex);\r
254                     ++bitIndex;\r
255                   } else {\r
256                     // Padding bit. If there is no bit left, we'll fill the left cells with 0, as described\r
257                     // in 8.4.9 of JISX0510:2004 (p. 24).\r
258                     bit = 0;\r
259                   }\r
260 \r
261                   // Skip masking if mask_pattern is -1.\r
262                   if (maskPattern != -1) {\r
263                     int mask = MaskUtil.getDataMaskBit(maskPattern, xx, y);\r
264                     bit ^= mask;\r
265                   }\r
266                   matrix.set(y, xx, bit);\r
267                 }\r
268                 y += direction;\r
269               }\r
270               direction = -direction;  // Reverse the direction.\r
271               y += direction;\r
272               x -= 2;  // Move to the left.\r
273             }\r
274             // All bits should be consumed.\r
275             if (bitIndex != dataBits.size()) {\r
276               throw new WriterException("Not all bits consumed: " + bitIndex + '/' + dataBits.size());\r
277             }\r
278           }\r
279 \r
280           // Return the position of the most significant bit set (to one) in the "value". The most\r
281           // significant bit is position 32. If there is no bit set, return 0. Examples:\r
282           // - findMSBSet(0) => 0\r
283           // - findMSBSet(1) => 1\r
284           // - findMSBSet(255) => 8\r
285           public static int findMSBSet(int value) {\r
286             int numDigits = 0;\r
287             while (value != 0) {\r
288               value >>= 1;\r
289               ++numDigits;\r
290             }\r
291             return numDigits;\r
292           }\r
293 \r
294           // Calculate BCH (Bose-Chaudhuri-Hocquenghem) code for "value" using polynomial "poly". The BCH\r
295           // code is used for encoding type information and version information.\r
296           // Example: Calculation of version information of 7.\r
297           // f(x) is created from 7.\r
298           //   - 7 = 000111 in 6 bits\r
299           //   - f(x) = x^2 + x^2 + x^1\r
300           // g(x) is given by the standard (p. 67)\r
301           //   - g(x) = x^12 + x^11 + x^10 + x^9 + x^8 + x^5 + x^2 + 1\r
302           // Multiply f(x) by x^(18 - 6)\r
303           //   - f'(x) = f(x) * x^(18 - 6)\r
304           //   - f'(x) = x^14 + x^13 + x^12\r
305           // Calculate the remainder of f'(x) / g(x)\r
306           //         x^2\r
307           //         __________________________________________________\r
308           //   g(x) )x^14 + x^13 + x^12\r
309           //         x^14 + x^13 + x^12 + x^11 + x^10 + x^7 + x^4 + x^2\r
310           //         --------------------------------------------------\r
311           //                              x^11 + x^10 + x^7 + x^4 + x^2\r
312           //\r
313           // The remainder is x^11 + x^10 + x^7 + x^4 + x^2\r
314           // Encode it in binary: 110010010100\r
315           // The return value is 0xc94 (1100 1001 0100)\r
316           //\r
317           // Since all coefficients in the polynomials are 1 or 0, we can do the calculation by bit\r
318           // operations. We don't care if cofficients are positive or negative.\r
319           public static int calculateBCHCode(int value, int poly) {\r
320             // If poly is "1 1111 0010 0101" (version info poly), msbSetInPoly is 13. We'll subtract 1\r
321             // from 13 to make it 12.\r
322             int msbSetInPoly = findMSBSet(poly);\r
323             value <<= msbSetInPoly - 1;\r
324             // Do the division business using exclusive-or operations.\r
325             while (findMSBSet(value) >= msbSetInPoly) {\r
326               value ^= poly << (findMSBSet(value) - msbSetInPoly);\r
327             }\r
328             // Now the "value" is the remainder (i.e. the BCH code)\r
329             return value;\r
330           }\r
331 \r
332           // Make bit vector of type information. On success, store the result in "bits" and return true.\r
333           // Encode error correction level and mask pattern. See 8.9 of\r
334           // JISX0510:2004 (p.45) for details.\r
335           public static void makeTypeInfoBits(ErrorCorrectionLevel ecLevel, int maskPattern, BitVector bits)\r
336           {\r
337             if (!QRCode.isValidMaskPattern(maskPattern)) {\r
338               throw new WriterException("Invalid mask pattern");\r
339             }\r
340             int typeInfo = (ecLevel.getBits() << 3) | maskPattern;\r
341             bits.appendBits(typeInfo, 5);\r
342 \r
343             int bchCode = calculateBCHCode(typeInfo, TYPE_INFO_POLY);\r
344             bits.appendBits(bchCode, 10);\r
345 \r
346             BitVector maskBits = new BitVector();\r
347             maskBits.appendBits(TYPE_INFO_MASK_PATTERN, 15);\r
348             bits.xor(maskBits);\r
349 \r
350             if (bits.size() != 15) {  // Just in case.\r
351               throw new WriterException("should not happen but we got: " + bits.size());\r
352             }\r
353           }\r
354 \r
355           // Make bit vector of version information. On success, store the result in "bits" and return true.\r
356           // See 8.10 of JISX0510:2004 (p.45) for details.\r
357           public static void makeVersionInfoBits(int version, BitVector bits){\r
358             bits.appendBits(version, 6);\r
359             int bchCode = calculateBCHCode(version, VERSION_INFO_POLY);\r
360             bits.appendBits(bchCode, 12);\r
361 \r
362             if (bits.size() != 18) {  // Just in case.\r
363               throw new WriterException("should not happen but we got: " + bits.size());\r
364             }\r
365           }\r
366 \r
367           // Check if "value" is empty.\r
368           private static bool isEmpty(int value) {\r
369             return value == -1;\r
370           }\r
371 \r
372           // Check if "value" is valid.\r
373           private static bool isValidValue(int value) {\r
374             return (value == -1 ||  // Empty.\r
375                 value == 0 ||  // Light (white).\r
376                 value == 1);  // Dark (black).\r
377           }\r
378 \r
379           private static void embedTimingPatterns(ByteMatrix matrix) {\r
380             // -8 is for skipping position detection patterns (size 7), and two horizontal/vertical\r
381             // separation patterns (size 1). Thus, 8 = 7 + 1.\r
382             for (int i = 8; i < matrix.width() - 8; ++i) {\r
383               int bit = (i + 1) % 2;\r
384               // Horizontal line.\r
385               if (!isValidValue(matrix.get(6, i))) {\r
386                 throw new WriterException();\r
387               }\r
388               if (isEmpty(matrix.get(6, i))) {\r
389                 matrix.set(6, i, bit);\r
390               }\r
391               // Vertical line.\r
392               if (!isValidValue(matrix.get(i, 6))) {\r
393                 throw new WriterException();\r
394               }\r
395               if (isEmpty(matrix.get(i, 6))) {\r
396                 matrix.set(i, 6, bit);\r
397               }\r
398             }\r
399           }\r
400 \r
401           // Embed the lonely dark dot at left bottom corner. JISX0510:2004 (p.46)\r
402           private static void embedDarkDotAtLeftBottomCorner(ByteMatrix matrix){\r
403             if (matrix.get(matrix.height() - 8, 8) == 0) {\r
404               throw new WriterException();\r
405             }\r
406             matrix.set(matrix.height() - 8, 8, 1);\r
407           }\r
408 \r
409           private static void embedHorizontalSeparationPattern(int xStart, int yStart,ByteMatrix matrix) {\r
410             // We know the width and height.\r
411             if (HORIZONTAL_SEPARATION_PATTERN[0].Length != 8 || HORIZONTAL_SEPARATION_PATTERN.Length != 1) {\r
412               throw new WriterException("Bad horizontal separation pattern");\r
413             }\r
414             for (int x = 0; x < 8; ++x) {\r
415               if (!isEmpty(matrix.get(yStart, xStart + x))) {\r
416                 throw new WriterException();\r
417               }\r
418               matrix.set(yStart, xStart + x, HORIZONTAL_SEPARATION_PATTERN[0][x]);\r
419             }\r
420           }\r
421 \r
422           private static void embedVerticalSeparationPattern(int xStart, int yStart,ByteMatrix matrix){\r
423             // We know the width and height.\r
424             if (VERTICAL_SEPARATION_PATTERN[0].Length != 1 || VERTICAL_SEPARATION_PATTERN.Length != 7) {\r
425               throw new WriterException("Bad vertical separation pattern");\r
426             }\r
427             for (int y = 0; y < 7; ++y) {\r
428               if (!isEmpty(matrix.get(yStart + y, xStart))) {\r
429                 throw new WriterException();\r
430               }\r
431               matrix.set(yStart + y, xStart, VERTICAL_SEPARATION_PATTERN[y][0]);\r
432             }\r
433           }\r
434 \r
435           // Note that we cannot unify the function with embedPositionDetectionPattern() despite they are\r
436           // almost identical, since we cannot write a function that takes 2D arrays in different sizes in\r
437           // C/C++. We should live with the fact.\r
438           private static void embedPositionAdjustmentPattern(int xStart, int yStart,ByteMatrix matrix){\r
439             // We know the width and height.\r
440             if (POSITION_ADJUSTMENT_PATTERN[0].Length != 5 || POSITION_ADJUSTMENT_PATTERN.Length != 5) {\r
441               throw new WriterException("Bad position adjustment");\r
442             }\r
443             for (int y = 0; y < 5; ++y) {\r
444               for (int x = 0; x < 5; ++x) {\r
445                 if (!isEmpty(matrix.get(yStart + y, xStart + x))) {\r
446                   throw new WriterException();\r
447                 }\r
448                 matrix.set(yStart + y, xStart + x, POSITION_ADJUSTMENT_PATTERN[y][x]);\r
449               }\r
450             }\r
451           }\r
452 \r
453           private static void embedPositionDetectionPattern(int xStart, int yStart,ByteMatrix matrix){\r
454             // We know the width and height.\r
455             if (POSITION_DETECTION_PATTERN[0].Length != 7 || POSITION_DETECTION_PATTERN.Length != 7) {\r
456               throw new WriterException("Bad position detection pattern");\r
457             }\r
458             for (int y = 0; y < 7; ++y) {\r
459               for (int x = 0; x < 7; ++x) {\r
460                 if (!isEmpty(matrix.get(yStart + y, xStart + x))) {\r
461                   throw new WriterException();\r
462                 }\r
463                 matrix.set(yStart + y, xStart + x, POSITION_DETECTION_PATTERN[y][x]);\r
464               }\r
465             }\r
466           }\r
467 \r
468           // Embed position detection patterns and surrounding vertical/horizontal separators.\r
469           private static void embedPositionDetectionPatternsAndSeparators(ByteMatrix matrix) {\r
470             // Embed three big squares at corners.\r
471             int pdpWidth = POSITION_DETECTION_PATTERN[0].Length;\r
472             // Left top corner.\r
473             embedPositionDetectionPattern(0, 0, matrix);\r
474             // Right top corner.\r
475             embedPositionDetectionPattern(matrix.width() - pdpWidth, 0, matrix);\r
476             // Left bottom corner.\r
477             embedPositionDetectionPattern(0, matrix.width() - pdpWidth, matrix);\r
478 \r
479             // Embed horizontal separation patterns around the squares.\r
480             int hspWidth = HORIZONTAL_SEPARATION_PATTERN[0].Length;\r
481             // Left top corner.\r
482             embedHorizontalSeparationPattern(0, hspWidth - 1, matrix);\r
483             // Right top corner.\r
484             embedHorizontalSeparationPattern(matrix.width() - hspWidth,\r
485                 hspWidth - 1, matrix);\r
486             // Left bottom corner.\r
487             embedHorizontalSeparationPattern(0, matrix.width() - hspWidth, matrix);\r
488 \r
489             // Embed vertical separation patterns around the squares.\r
490             int vspSize = VERTICAL_SEPARATION_PATTERN.Length;\r
491             // Left top corner.\r
492             embedVerticalSeparationPattern(vspSize, 0, matrix);\r
493             // Right top corner.\r
494             embedVerticalSeparationPattern(matrix.height() - vspSize - 1, 0, matrix);\r
495             // Left bottom corner.\r
496             embedVerticalSeparationPattern(vspSize, matrix.height() - vspSize,\r
497                 matrix);\r
498           }\r
499 \r
500           // Embed position adjustment patterns if need be.\r
501           private static void maybeEmbedPositionAdjustmentPatterns(int version, ByteMatrix matrix)\r
502           {\r
503             if (version < 2) {  // The patterns appear if version >= 2\r
504               return;\r
505             }\r
506             int index = version - 1;\r
507             int[] coordinates = POSITION_ADJUSTMENT_PATTERN_COORDINATE_TABLE[index];\r
508             int numCoordinates = POSITION_ADJUSTMENT_PATTERN_COORDINATE_TABLE[index].Length;\r
509             for (int i = 0; i < numCoordinates; ++i) {\r
510               for (int j = 0; j < numCoordinates; ++j) {\r
511                 int y = coordinates[i];\r
512                 int x = coordinates[j];\r
513                 if (x == -1 || y == -1) {\r
514                   continue;\r
515                 }\r
516                 // If the cell is unset, we embed the position adjustment pattern here.\r
517                 if (isEmpty(matrix.get(y, x))) {\r
518                   // -2 is necessary since the x/y coordinates point to the center of the pattern, not the\r
519                   // left top corner.\r
520                   embedPositionAdjustmentPattern(x - 2, y - 2, matrix);\r
521                 }\r
522               }\r
523             }\r
524           }\r
525 \r
526     \r
527     \r
528     }\r
529 \r
530 \r
531 }