"Split" ReaderException into subclasses to enable more useful error reporting
[zxing.git] / core / src / com / google / zxing / pdf417 / PDF417Reader.java
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 \r
17 package com.google.zxing.pdf417;\r
18 \r
19 import com.google.zxing.BarcodeFormat;\r
20 import com.google.zxing.BinaryBitmap;\r
21 import com.google.zxing.DecodeHintType;\r
22 import com.google.zxing.FormatException;\r
23 import com.google.zxing.NotFoundException;\r
24 import com.google.zxing.Reader;\r
25 import com.google.zxing.Result;\r
26 import com.google.zxing.ResultPoint;\r
27 import com.google.zxing.common.BitMatrix;\r
28 import com.google.zxing.common.DecoderResult;\r
29 import com.google.zxing.common.DetectorResult;\r
30 import com.google.zxing.pdf417.decoder.Decoder;\r
31 import com.google.zxing.pdf417.detector.Detector;\r
32 \r
33 import java.util.Hashtable;\r
34 \r
35 /**\r
36  * This implementation can detect and decode PDF417 codes in an image.\r
37  *\r
38  * @author SITA Lab (kevin.osullivan@sita.aero)\r
39  */\r
40 public final class PDF417Reader implements Reader {\r
41 \r
42   private static final ResultPoint[] NO_POINTS = new ResultPoint[0];\r
43 \r
44   private final Decoder decoder = new Decoder();\r
45 \r
46   /**\r
47    * Locates and decodes a PDF417 code in an image.\r
48    *\r
49    * @return a String representing the content encoded by the PDF417 code\r
50    * @throws NotFoundException if a PDF417 code cannot be found,\r
51    * @throws FormatException if a PDF417 cannot be decoded\r
52    */\r
53   public Result decode(BinaryBitmap image) throws NotFoundException, FormatException {\r
54     return decode(image, null);\r
55   }\r
56 \r
57   public Result decode(BinaryBitmap image, Hashtable hints)\r
58       throws NotFoundException, FormatException {\r
59     DecoderResult decoderResult;\r
60     ResultPoint[] points;\r
61     if (hints != null && hints.containsKey(DecodeHintType.PURE_BARCODE)) {\r
62       BitMatrix bits = extractPureBits(image);\r
63       decoderResult = decoder.decode(bits);\r
64       points = NO_POINTS;\r
65     } else {\r
66       DetectorResult detectorResult = new Detector(image).detect();\r
67       decoderResult = decoder.decode(detectorResult.getBits());\r
68       points = detectorResult.getPoints();\r
69     }\r
70     return new Result(decoderResult.getText(), decoderResult.getRawBytes(), points,\r
71         BarcodeFormat.PDF417);\r
72   }\r
73 \r
74   public void reset() {\r
75     // do nothing\r
76   }\r
77 \r
78   /**\r
79    * This method detects a barcode in a "pure" image -- that is, pure monochrome image\r
80    * which contains only an unrotated, unskewed, image of a barcode, with some white border\r
81    * around it. This is a specialized method that works exceptionally fast in this special\r
82    * case.\r
83    */\r
84   private static BitMatrix extractPureBits(BinaryBitmap image) throws NotFoundException {\r
85     // Now need to determine module size in pixels\r
86     BitMatrix matrix = image.getBlackMatrix();\r
87     int height = matrix.getHeight();\r
88     int width = matrix.getWidth();\r
89     int minDimension = 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(borderWidth, borderWidth)) {\r
94       borderWidth++;\r
95     }\r
96     if (borderWidth == minDimension) {\r
97       throw NotFoundException.getNotFoundInstance();\r
98     }\r
99 \r
100     // And then keep tracking across the top-left black module to determine module size\r
101     int moduleEnd = borderWidth;\r
102     while (moduleEnd < minDimension && matrix.get(moduleEnd, moduleEnd)) {\r
103       moduleEnd++;\r
104     }\r
105     if (moduleEnd == minDimension) {\r
106       throw NotFoundException.getNotFoundInstance();\r
107     }\r
108 \r
109     int moduleSize = moduleEnd - borderWidth;\r
110 \r
111     // And now find where the rightmost black module on the first row ends\r
112     int rowEndOfSymbol = width - 1;\r
113     while (rowEndOfSymbol >= 0 && !matrix.get(rowEndOfSymbol, borderWidth)) {\r
114       rowEndOfSymbol--;\r
115     }\r
116     if (rowEndOfSymbol < 0) {\r
117       throw NotFoundException.getNotFoundInstance();\r
118     }\r
119     rowEndOfSymbol++;\r
120 \r
121     // Make sure width of barcode is a multiple of module size\r
122     if ((rowEndOfSymbol - borderWidth) % moduleSize != 0) {\r
123       throw NotFoundException.getNotFoundInstance();\r
124     }\r
125     int dimension = (rowEndOfSymbol - borderWidth) / moduleSize;\r
126 \r
127     // Push in the "border" by half the module width so that we start\r
128     // sampling in the middle of the module. Just in case the image is a\r
129     // little off, this will help recover.\r
130     borderWidth += moduleSize >> 1;\r
131 \r
132     int sampleDimension = borderWidth + (dimension - 1) * moduleSize;\r
133     if (sampleDimension >= width || sampleDimension >= height) {\r
134       throw NotFoundException.getNotFoundInstance();\r
135     }\r
136 \r
137     // Now just read off the bits\r
138     BitMatrix bits = new BitMatrix(dimension);\r
139     for (int y = 0; y < dimension; y++) {\r
140       int iOffset = borderWidth + y * moduleSize;\r
141       for (int x = 0; x < dimension; x++) {\r
142         if (matrix.get(borderWidth + x * moduleSize, iOffset)) {\r
143           bits.set(x, y);\r
144         }\r
145       }\r
146     }\r
147     return bits;\r
148   }\r
149 }\r