Morgan's cosmetic improvement to a translation, and equivalent for other translations...
[zxing.git] / csharp / datamatrix / DataMatrixReader.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 BarcodeFormat = com.google.zxing.BarcodeFormat;\r
18 using DecodeHintType = com.google.zxing.DecodeHintType;\r
19 using BinaryBitmap = com.google.zxing.BinaryBitmap;\r
20 using Reader = com.google.zxing.Reader;\r
21 using ReaderException = com.google.zxing.ReaderException;\r
22 using Result = com.google.zxing.Result;\r
23 using ResultPoint = com.google.zxing.ResultPoint;\r
24 using ResultMetadataType = com.google.zxing.ResultMetadataType;\r
25 using BitMatrix = com.google.zxing.common.BitMatrix;\r
26 using DecoderResult = com.google.zxing.common.DecoderResult;\r
27 using DetectorResult = com.google.zxing.common.DetectorResult;\r
28 using Decoder = com.google.zxing.datamatrix.decoder.Decoder;\r
29 using Detector = com.google.zxing.datamatrix.detector.Detector;\r
30 namespace com.google.zxing.datamatrix\r
31 {\r
32         \r
33         /// <summary> This implementation can detect and decode Data Matrix codes in an image.\r
34         /// \r
35         /// </summary>\r
36         /// <author>  bbrown@google.com (Brian Brown)\r
37         /// </author>\r
38         /// <author>www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source \r
39         /// </author>\r
40         public sealed class DataMatrixReader : Reader\r
41         {\r
42                 \r
43                 //UPGRADE_NOTE: Final was removed from the declaration of 'NO_POINTS '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"\r
44                 private static readonly ResultPoint[] NO_POINTS = new ResultPoint[0];\r
45                 \r
46                 //UPGRADE_NOTE: Final was removed from the declaration of 'decoder '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"\r
47                 private Decoder decoder = new Decoder();\r
48                 \r
49                 /// <summary> Locates and decodes a Data Matrix code in an image.\r
50                 /// \r
51                 /// </summary>\r
52                 /// <returns> a String representing the content encoded by the Data Matrix code\r
53                 /// </returns>\r
54                 /// <throws>  ReaderException if a Data Matrix code cannot be found, or cannot be decoded </throws>\r
55                 public Result decode(BinaryBitmap image)\r
56                 {\r
57                         return decode(image, null);\r
58                 }\r
59                 \r
60                 public Result decode(BinaryBitmap image, System.Collections.Hashtable hints)\r
61                 {\r
62                         DecoderResult decoderResult;\r
63                         ResultPoint[] points;\r
64                         if (hints != null && hints.ContainsKey(DecodeHintType.PURE_BARCODE))\r
65                         {\r
66                                 BitMatrix bits = extractPureBits(image.BlackMatrix);\r
67                                 decoderResult = decoder.decode(bits);\r
68                                 points = NO_POINTS;\r
69                         }\r
70                         else\r
71                         {\r
72                                 DetectorResult detectorResult = new Detector(image.BlackMatrix).detect();\r
73                                 decoderResult = decoder.decode(detectorResult.Bits);\r
74                                 points = detectorResult.Points;\r
75                         }\r
76                         Result result = new Result(decoderResult.Text, decoderResult.RawBytes, points, BarcodeFormat.DATAMATRIX);\r
77                         if (decoderResult.ByteSegments != null)\r
78                         {\r
79                                 result.putMetadata(ResultMetadataType.BYTE_SEGMENTS, decoderResult.ByteSegments);\r
80                         }\r
81                         if (decoderResult.ECLevel != null)\r
82                         {\r
83                                 result.putMetadata(ResultMetadataType.ERROR_CORRECTION_LEVEL, decoderResult.ECLevel.ToString());\r
84                         }\r
85                         return result;\r
86                 }\r
87                 \r
88                 /// <summary> This method detects a Data Matrix code in a "pure" image -- that is, pure monochrome image\r
89                 /// which contains only an unrotated, unskewed, image of a Data Matrix code, with some white border\r
90                 /// around it. This is a specialized method that works exceptionally fast in this special\r
91                 /// case.\r
92                 /// </summary>\r
93                 private static BitMatrix extractPureBits(BitMatrix image)\r
94                 {\r
95                         // Now need to determine module size in pixels\r
96                         \r
97                         int height = image.Height;\r
98                         int width = image.Width;\r
99                         int minDimension = System.Math.Min(height, width);\r
100                         \r
101                         // First, skip white border by tracking diagonally from the top left down and to the right:\r
102                         int borderWidth = 0;\r
103                         while (borderWidth < minDimension && !image.get_Renamed(borderWidth, borderWidth))\r
104                         {\r
105                                 borderWidth++;\r
106                         }\r
107                         if (borderWidth == minDimension)\r
108                         {\r
109                                 throw ReaderException.Instance;\r
110                         }\r
111                         \r
112                         // And then keep tracking across the top-left black module to determine module size\r
113                         int moduleEnd = borderWidth + 1;\r
114                         while (moduleEnd < width && image.get_Renamed(moduleEnd, borderWidth))\r
115                         {\r
116                                 moduleEnd++;\r
117                         }\r
118                         if (moduleEnd == width)\r
119                         {\r
120                                 throw ReaderException.Instance;\r
121                         }\r
122                         \r
123                         int moduleSize = moduleEnd - borderWidth;\r
124                         \r
125                         // And now find where the bottommost black module on the first column ends\r
126                         int columnEndOfSymbol = height - 1;\r
127                         while (columnEndOfSymbol >= 0 && !image.get_Renamed(borderWidth, columnEndOfSymbol))\r
128                         {\r
129                                 columnEndOfSymbol--;\r
130                         }\r
131                         if (columnEndOfSymbol < 0)\r
132                         {\r
133                                 throw ReaderException.Instance;\r
134                         }\r
135                         columnEndOfSymbol++;\r
136                         \r
137                         // Make sure width of barcode is a multiple of module size\r
138                         if ((columnEndOfSymbol - borderWidth) % moduleSize != 0)\r
139                         {\r
140                                 throw ReaderException.Instance;\r
141                         }\r
142                         int dimension = (columnEndOfSymbol - borderWidth) / moduleSize;\r
143                         \r
144                         // Push in the "border" by half the module width so that we start\r
145                         // sampling in the middle of the module. Just in case the image is a\r
146                         // little off, this will help recover.\r
147                         borderWidth += (moduleSize >> 1);\r
148                         \r
149                         int sampleDimension = borderWidth + (dimension - 1) * moduleSize;\r
150                         if (sampleDimension >= width || sampleDimension >= height)\r
151                         {\r
152                                 throw ReaderException.Instance;\r
153                         }\r
154                         \r
155                         // Now just read off the bits\r
156                         BitMatrix bits = new BitMatrix(dimension);\r
157                         for (int i = 0; i < dimension; i++)\r
158                         {\r
159                                 int iOffset = borderWidth + i * moduleSize;\r
160                                 for (int j = 0; j < dimension; j++)\r
161                                 {\r
162                                         if (image.get_Renamed(borderWidth + j * moduleSize, iOffset))\r
163                                         {\r
164                                                 bits.set_Renamed(j, i);\r
165                                         }\r
166                                 }\r
167                         }\r
168                         return bits;\r
169                 }\r
170         }\r
171 }