New C# port from Suraj Supekar
[zxing.git] / csharp / qrcode / decoder / Decoder.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 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 using GF256 = com.google.zxing.common.reedsolomon.GF256;\r
21 using ReedSolomonDecoder = com.google.zxing.common.reedsolomon.ReedSolomonDecoder;\r
22 using ReedSolomonException = com.google.zxing.common.reedsolomon.ReedSolomonException;\r
23 namespace com.google.zxing.qrcode.decoder\r
24 {\r
25         \r
26         /// <summary> <p>The main class which implements QR Code decoding -- as opposed to locating and extracting\r
27         /// the QR Code from an image.</p>\r
28         /// \r
29         /// </summary>\r
30         /// <author>  Sean Owen\r
31         /// </author>\r
32         /// <author>www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source \r
33         /// </author>\r
34         public sealed class Decoder\r
35         {\r
36                 \r
37                 //UPGRADE_NOTE: Final was removed from the declaration of 'rsDecoder '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"\r
38                 private ReedSolomonDecoder rsDecoder;\r
39                 \r
40                 public Decoder()\r
41                 {\r
42                         rsDecoder = new ReedSolomonDecoder(GF256.QR_CODE_FIELD);\r
43                 }\r
44                 \r
45                 /// <summary> <p>Convenience method that can decode a QR 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 QR Code modules\r
50                 /// </param>\r
51                 /// <returns> text and bytes encoded within the QR Code\r
52                 /// </returns>\r
53                 /// <throws>  ReaderException if the QR 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[i][j])\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 QR Code represented as a {@link BitMatrix}. A 1 or "true" is taken to mean a black module.</p>\r
72                 /// \r
73                 /// </summary>\r
74                 /// <param name="bits">booleans representing white/black QR Code modules\r
75                 /// </param>\r
76                 /// <returns> text and bytes encoded within the QR Code\r
77                 /// </returns>\r
78                 /// <throws>  ReaderException if the QR Code cannot be decoded </throws>\r
79                 public DecoderResult decode(BitMatrix bits)\r
80                 {\r
81                         \r
82                         // Construct a parser and read version, error-correction level\r
83                         BitMatrixParser parser = new BitMatrixParser(bits);\r
84                         Version version = parser.readVersion();\r
85                         ErrorCorrectionLevel ecLevel = parser.readFormatInformation().ErrorCorrectionLevel;\r
86                         \r
87                         // Read codewords\r
88                         sbyte[] codewords = parser.readCodewords();\r
89                         // Separate into data blocks\r
90                         DataBlock[] dataBlocks = DataBlock.getDataBlocks(codewords, version, ecLevel);\r
91                         \r
92                         // Count total number of data bytes\r
93                         int totalBytes = 0;\r
94                         for (int i = 0; i < dataBlocks.Length; i++)\r
95                         {\r
96                                 totalBytes += dataBlocks[i].NumDataCodewords;\r
97                         }\r
98                         sbyte[] resultBytes = new sbyte[totalBytes];\r
99                         int resultOffset = 0;\r
100                         \r
101                         // Error-correct and copy data blocks together into a stream of bytes\r
102                         for (int j = 0; j < dataBlocks.Length; j++)\r
103                         {\r
104                                 DataBlock dataBlock = dataBlocks[j];\r
105                                 sbyte[] codewordBytes = dataBlock.Codewords;\r
106                                 int numDataCodewords = dataBlock.NumDataCodewords;\r
107                                 correctErrors(codewordBytes, numDataCodewords);\r
108                                 for (int i = 0; i < numDataCodewords; i++)\r
109                                 {\r
110                                         resultBytes[resultOffset++] = codewordBytes[i];\r
111                                 }\r
112                         }\r
113                         \r
114                         // Decode the contents of that stream of bytes\r
115                         return DecodedBitStreamParser.decode(resultBytes, version, ecLevel);\r
116                 }\r
117                 \r
118                 /// <summary> <p>Given data and error-correction codewords received, possibly corrupted by errors, attempts to\r
119                 /// correct the errors in-place using Reed-Solomon error correction.</p>\r
120                 /// \r
121                 /// </summary>\r
122                 /// <param name="codewordBytes">data and error correction codewords\r
123                 /// </param>\r
124                 /// <param name="numDataCodewords">number of codewords that are data bytes\r
125                 /// </param>\r
126                 /// <throws>  ReaderException if error correction fails </throws>\r
127                 private void  correctErrors(sbyte[] codewordBytes, int numDataCodewords)\r
128                 {\r
129                         int numCodewords = codewordBytes.Length;\r
130                         // First read into an array of ints\r
131                         int[] codewordsInts = new int[numCodewords];\r
132                         for (int i = 0; i < numCodewords; i++)\r
133                         {\r
134                                 codewordsInts[i] = codewordBytes[i] & 0xFF;\r
135                         }\r
136                         int numECCodewords = codewordBytes.Length - numDataCodewords;\r
137                         try\r
138                         {\r
139                                 rsDecoder.decode(codewordsInts, numECCodewords);\r
140                         }\r
141                         catch (ReedSolomonException rse)\r
142                         {\r
143                                 throw ReaderException.Instance;\r
144                         }\r
145                         // Copy back into array of bytes -- only need to worry about the bytes that were data\r
146                         // We don't care about errors in the error-correction codewords\r
147                         for (int i = 0; i < numDataCodewords; i++)\r
148                         {\r
149                                 codewordBytes[i] = (sbyte) codewordsInts[i];\r
150                         }\r
151                 }\r
152         }\r
153 }