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