Committed C# port from Mohamad
[zxing.git] / csharp / qrcode / decoder / Decoder.cs
1 /*\r
2 * Licensed under the Apache License, Version 2.0 (the "License");\r
3 * you may not use this file except in compliance with the License.\r
4 * You may obtain a copy of the License at\r
5 *\r
6 *      http://www.apache.org/licenses/LICENSE-2.0\r
7 *\r
8 * Unless required by applicable law or agreed to in writing, software\r
9 * distributed under the License is distributed on an "AS IS" BASIS,\r
10 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
11 * See the License for the specific language governing permissions and\r
12 * limitations under the License.\r
13 */\r
14 \r
15 using System;\r
16 namespace com.google.zxing.qrcode.decoder\r
17 {\r
18      using com.google.zxing.common;  \r
19     using com.google.zxing.common.reedsolomon;  \r
20 \r
21     public sealed class Decoder\r
22     { \r
23           private ReedSolomonDecoder rsDecoder;\r
24 \r
25           public Decoder() {\r
26             rsDecoder = new ReedSolomonDecoder(GF256.QR_CODE_FIELD);\r
27           }\r
28 \r
29           /**\r
30            * <p>Convenience method that can decode a QR Code represented as a 2D array of booleans.\r
31            * "true" is taken to mean a black module.</p>\r
32            *\r
33            * @param image booleans representing white/black QR Code modules\r
34            * @return text and bytes encoded within the QR Code\r
35            * @throws ReaderException if the QR Code cannot be decoded\r
36            */\r
37           public DecoderResult decode(bool[][] image) {\r
38               try{\r
39                 int dimension = image.Length;\r
40                 BitMatrix bits = new BitMatrix(dimension);\r
41                 for (int i = 0; i < dimension; i++) {\r
42                   for (int j = 0; j < dimension; j++) {\r
43                     if (image[i][j]) {\r
44                       bits.set(i, j);\r
45                     }\r
46                   }\r
47                 }\r
48                 return decode(bits);\r
49               }catch (Exception e){\r
50                 throw  new ReaderException(e.Message);\r
51               }            \r
52           }\r
53 \r
54           /**\r
55            * <p>Decodes a QR Code represented as a {@link BitMatrix}. A 1 or "true" is taken to mean a black module.</p>\r
56            *\r
57            * @param bits booleans representing white/black QR Code modules\r
58            * @return text and bytes encoded within the QR Code\r
59            * @throws ReaderException if the QR Code cannot be decoded\r
60            */\r
61           public DecoderResult decode(BitMatrix bits){\r
62               try{\r
63                 // Construct a parser and read version, error-correction level\r
64                 BitMatrixParser parser = new BitMatrixParser(bits);\r
65                 Version version = parser.readVersion();\r
66                 ErrorCorrectionLevel ecLevel = parser.readFormatInformation().getErrorCorrectionLevel();\r
67 \r
68                 // Read codewords\r
69                 sbyte[] codewords = parser.readCodewords();\r
70                 // Separate into data blocks\r
71                 DataBlock[] dataBlocks = DataBlock.getDataBlocks(codewords, version, ecLevel);\r
72 \r
73                 // Count total number of data bytes\r
74                 int totalBytes = 0;\r
75                 for (int i = 0; i < dataBlocks.Length; i++) {\r
76                   totalBytes += dataBlocks[i].NumDataCodewords;\r
77                 }\r
78                 sbyte[] resultBytes = new sbyte[totalBytes];\r
79                 int resultOffset = 0;\r
80 \r
81                 // Error-correct and copy data blocks together into a stream of bytes\r
82                 for (int j = 0; j < dataBlocks.Length; j++) {\r
83                   DataBlock dataBlock = dataBlocks[j];\r
84                   sbyte[] codewordBytes = dataBlock.Codewords;\r
85                   int numDataCodewords = dataBlock.NumDataCodewords;\r
86                   correctErrors(codewordBytes, numDataCodewords);\r
87                   for (int i = 0; i < numDataCodewords; i++) {\r
88                     resultBytes[resultOffset++] = codewordBytes[i];\r
89                   }\r
90                 }\r
91 \r
92                 // Decode the contents of that stream of bytes\r
93                 string sResult = DecodedBitStreamParser.decode(resultBytes, version);\r
94                 return new DecoderResult(resultBytes, sResult, null);\r
95               }catch(Exception e){\r
96                 throw new ReaderException(e.Message);\r
97               }\r
98             \r
99           }\r
100 \r
101           /**\r
102            * <p>Given data and error-correction codewords received, possibly corrupted by errors, attempts to\r
103            * correct the errors in-place using Reed-Solomon error correction.</p>\r
104            *\r
105            * @param codewordBytes data and error correction codewords\r
106            * @param numDataCodewords number of codewords that are data bytes\r
107            * @throws ReaderException if error correction fails\r
108            */\r
109           private void correctErrors(sbyte[] codewordBytes, int numDataCodewords){\r
110               try\r
111               {\r
112                   int numCodewords = codewordBytes.Length;\r
113                   // First read into an array of ints\r
114                   int[] codewordsInts = new int[numCodewords];\r
115                   for (int i = 0; i < numCodewords; i++)\r
116                   {\r
117                       codewordsInts[i] = codewordBytes[i] & 0xFF;\r
118                   }\r
119                   int numECCodewords = codewordBytes.Length - numDataCodewords;\r
120                   try\r
121                   {\r
122                       rsDecoder.decode(codewordsInts, numECCodewords);\r
123                   }\r
124                   catch (ReedSolomonException rse)\r
125                   {\r
126                       throw new ReaderException(rse.Message);\r
127                   }\r
128                   // Copy back into array of bytes -- only need to worry about the bytes that were data\r
129                   // We don't care about errors in the error-correction codewords\r
130                   for (int i = 0; i < numDataCodewords; i++)\r
131                   {\r
132                       codewordBytes[i] = (sbyte)codewordsInts[i];\r
133                   }\r
134               }\r
135               catch (Exception e) {\r
136                   throw new ReaderException(e.Message);\r
137               }            \r
138           }\r
139     }\r
140 }