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