Style changes mostly
[zxing.git] / core / src / com / google / zxing / pdf417 / decoder / Decoder.java
1 /*\r
2  * Copyright 2009 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 \r
17 package com.google.zxing.pdf417.decoder;\r
18 \r
19 import com.google.zxing.ReaderException;\r
20 import com.google.zxing.common.BitMatrix;\r
21 import com.google.zxing.common.DecoderResult;\r
22 //import com.google.zxing.pdf417.reedsolomon.ReedSolomonDecoder;\r
23 \r
24 /**\r
25  * <p>The main class which implements PDF417 Code decoding -- as\r
26  * opposed to locating and extracting the PDF417 Code from an image.</p>\r
27  *\r
28  * @author SITA Lab (kevin.osullivan@sita.aero)\r
29  */\r
30 public final class Decoder {\r
31 \r
32   private static final int MAX_ERRORS = 3;\r
33   private static final int MAX_EC_CODEWORDS = 512;\r
34   //private final ReedSolomonDecoder rsDecoder;\r
35 \r
36   public Decoder() {\r
37     // TODO MGMG\r
38     //rsDecoder = new ReedSolomonDecoder();\r
39   }\r
40 \r
41   /**\r
42    * <p>Convenience method that can decode a PDF417 Code represented as a 2D array of booleans.\r
43    * "true" is taken to mean a black module.</p>\r
44    *\r
45    * @param image booleans representing white/black PDF417 modules\r
46    * @return text and bytes encoded within the PDF417 Code\r
47    * @throws ReaderException if the PDF417 Code cannot be decoded\r
48    */\r
49   public DecoderResult decode(boolean[][] image) throws ReaderException {\r
50     int dimension = image.length;\r
51     BitMatrix bits = new BitMatrix(dimension);\r
52     for (int i = 0; i < dimension; i++) {\r
53       for (int j = 0; j < dimension; j++) {\r
54         if (image[i][j]) {\r
55           bits.set(i, j);\r
56         }\r
57       }\r
58     }\r
59     return decode(bits);\r
60   }\r
61 \r
62   /**\r
63    * <p>Decodes a PDF417 Code represented as a {@link BitMatrix}.\r
64    * A 1 or "true" is taken to mean a black module.</p>\r
65    *\r
66    * @param bits booleans representing white/black PDF417 Code modules\r
67    * @return text and bytes encoded within the PDF417 Code\r
68    * @throws ReaderException if the PDF417 Code cannot be decoded\r
69    */\r
70   public DecoderResult decode(BitMatrix bits) throws ReaderException {\r
71     // Construct a parser to read the data codewords and error-correction level\r
72     BitMatrixParser parser = new BitMatrixParser(bits);\r
73     int[] codewords = parser.readCodewords();\r
74     if (codewords == null || codewords.length == 0) {\r
75       throw ReaderException.getInstance();\r
76     }\r
77 \r
78     int ecLevel = parser.getECLevel();\r
79     int numECCodewords = 1 << (ecLevel + 1);\r
80     int[] erasures = parser.getErasures();\r
81 \r
82     correctErrors(codewords, erasures, numECCodewords);\r
83     verifyCodewordCount(codewords, numECCodewords);\r
84 \r
85     // Decode the codewords\r
86     return DecodedBitStreamParser.decode(codewords);\r
87   }\r
88 \r
89   /**\r
90    * Verify that all is OK with the codeword array.\r
91    *\r
92    * @param codewords\r
93    * @return an index to the first data codeword.\r
94    * @throws ReaderException\r
95    */\r
96   private static int verifyCodewordCount(int[] codewords, int numECCodewords) throws ReaderException {\r
97     if (codewords.length < 4) {\r
98       // Codeword array size should be at least 4 allowing for\r
99       // Count CW, At least one Data CW, Error Correction CW, Error Correction CW\r
100       throw ReaderException.getInstance();\r
101     }\r
102     // The first codeword, the Symbol Length Descriptor, shall always encode the total number of data\r
103     // codewords in the symbol, including the Symbol Length Descriptor itself, data codewords and pad\r
104     // codewords, but excluding the number of error correction codewords.\r
105     int numberOfCodewords = codewords[0];\r
106     if (numberOfCodewords > codewords.length) {\r
107       throw ReaderException.getInstance();\r
108     }\r
109     if (numberOfCodewords == 0) {\r
110       // Reset to the length of the array - 8 (Allow for at least level 3 Error Correction (8 Error Codewords)\r
111       if (numECCodewords < codewords.length) {\r
112         codewords[0] = codewords.length - numECCodewords;\r
113       } else {\r
114         throw ReaderException.getInstance();\r
115       }\r
116     }\r
117     return 1; // Index to first data codeword\r
118   }\r
119 \r
120   /**\r
121    * <p>Given data and error-correction codewords received, possibly corrupted by errors, attempts to\r
122    * correct the errors in-place using Reed-Solomon error correction.</p>\r
123    *\r
124    * @param codewords   data and error correction codewords\r
125    * @throws ReaderException if error correction fails\r
126    */\r
127   private static int correctErrors(int[] codewords, int[] erasures, int numECCodewords) throws ReaderException {\r
128     if ((erasures != null && erasures.length > numECCodewords / 2 + MAX_ERRORS) ||\r
129         (numECCodewords < 0 || numECCodewords > MAX_EC_CODEWORDS)) {\r
130       // Too many errors or EC Codewords is corrupted\r
131       throw ReaderException.getInstance();\r
132     }\r
133     // Try to correct the errors\r
134     int result = 0; // rsDecoder.correctErrors(codewords, numECCodewords);\r
135     if (erasures != null) {\r
136       int numErasures = erasures.length;\r
137       if (result > 0) {\r
138         numErasures -= result;\r
139       }\r
140       if (numErasures > MAX_ERRORS) {\r
141         // Still too many errors\r
142         throw ReaderException.getInstance();\r
143       }\r
144     }\r
145     return result;\r
146         }\r
147 }\r